mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-05-11 06:11:15 +00:00
Init
This commit is contained in:
3
src/app/api/auth/[...nextauth]/route.ts
Normal file
3
src/app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { handlers } from "@/lib/auth";
|
||||
|
||||
export const { GET, POST } = handlers;
|
||||
52
src/app/api/catalog/filaments/route.ts
Normal file
52
src/app/api/catalog/filaments/route.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import type { CatalogBrand, CatalogResponse } from "@/types/catalog.types";
|
||||
import { fetchFilaments } from "@/lib/catalog/shopify";
|
||||
import { deduplicateItems } from "@/lib/catalog/cache";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const { searchParams } = req.nextUrl;
|
||||
const brandFilter = searchParams.get("brand")?.toLowerCase();
|
||||
const search = searchParams.get("search")?.toLowerCase();
|
||||
|
||||
try {
|
||||
let items = deduplicateItems(await fetchFilaments());
|
||||
|
||||
// Build brand summary from unfiltered data
|
||||
const brandMap = new Map<string, number>();
|
||||
for (const p of items) {
|
||||
brandMap.set(p.brand, (brandMap.get(p.brand) ?? 0) + 1);
|
||||
}
|
||||
|
||||
if (brandFilter) {
|
||||
items = items.filter((p) => p.brand.toLowerCase() === brandFilter);
|
||||
}
|
||||
|
||||
if (search) {
|
||||
items = items.filter(
|
||||
(p) =>
|
||||
p.name.toLowerCase().includes(search) ||
|
||||
p.brand.toLowerCase().includes(search) ||
|
||||
(p.color && p.color.toLowerCase().includes(search)) ||
|
||||
(p.material && p.material.toLowerCase().includes(search)),
|
||||
);
|
||||
}
|
||||
|
||||
const brands: CatalogBrand[] = Array.from(brandMap.entries())
|
||||
.map(([name, count]) => ({
|
||||
id: name.toLowerCase().replace(/[^a-z0-9]/g, "_"),
|
||||
name,
|
||||
type: "filament" as const,
|
||||
itemCount: count,
|
||||
}))
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
const response: CatalogResponse = { items, brands };
|
||||
return NextResponse.json(response);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch filament catalog:", error);
|
||||
return NextResponse.json(
|
||||
{ items: [], brands: [], error: "Failed to fetch filament data" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
||||
47
src/app/api/catalog/paints/route.ts
Normal file
47
src/app/api/catalog/paints/route.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import type { CatalogBrand, CatalogItem, CatalogResponse } from "@/types/catalog.types";
|
||||
|
||||
// Static import — bundled at build time from the generated JSON
|
||||
import paintsData from "@/data/catalog/paints.json";
|
||||
|
||||
const allPaints = paintsData as CatalogItem[];
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const { searchParams } = req.nextUrl;
|
||||
const brandFilter = searchParams.get("brand")?.toLowerCase();
|
||||
const search = searchParams.get("search")?.toLowerCase();
|
||||
|
||||
let items = allPaints;
|
||||
|
||||
if (brandFilter) {
|
||||
items = items.filter((p) => p.brand.toLowerCase() === brandFilter);
|
||||
}
|
||||
|
||||
if (search) {
|
||||
items = items.filter(
|
||||
(p) =>
|
||||
p.name.toLowerCase().includes(search) ||
|
||||
p.brand.toLowerCase().includes(search) ||
|
||||
(p.line && p.line.toLowerCase().includes(search)) ||
|
||||
(p.productCode && p.productCode.toLowerCase().includes(search)),
|
||||
);
|
||||
}
|
||||
|
||||
// Build brand summary from the FULL dataset (not filtered)
|
||||
const brandMap = new Map<string, number>();
|
||||
for (const p of allPaints) {
|
||||
brandMap.set(p.brand, (brandMap.get(p.brand) ?? 0) + 1);
|
||||
}
|
||||
|
||||
const brands: CatalogBrand[] = Array.from(brandMap.entries())
|
||||
.map(([name, count]) => ({
|
||||
id: name.toLowerCase().replace(/[^a-z0-9]/g, "_"),
|
||||
name,
|
||||
type: "paint" as const,
|
||||
itemCount: count,
|
||||
}))
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
const response: CatalogResponse = { items, brands };
|
||||
return NextResponse.json(response);
|
||||
}
|
||||
52
src/app/api/catalog/resins/route.ts
Normal file
52
src/app/api/catalog/resins/route.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import type { CatalogBrand, CatalogResponse } from "@/types/catalog.types";
|
||||
import { fetchResins } from "@/lib/catalog/shopify";
|
||||
import { deduplicateItems } from "@/lib/catalog/cache";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const { searchParams } = req.nextUrl;
|
||||
const brandFilter = searchParams.get("brand")?.toLowerCase();
|
||||
const search = searchParams.get("search")?.toLowerCase();
|
||||
|
||||
try {
|
||||
let items = deduplicateItems(await fetchResins());
|
||||
|
||||
// Build brand summary from unfiltered data
|
||||
const brandMap = new Map<string, number>();
|
||||
for (const p of items) {
|
||||
brandMap.set(p.brand, (brandMap.get(p.brand) ?? 0) + 1);
|
||||
}
|
||||
|
||||
if (brandFilter) {
|
||||
items = items.filter((p) => p.brand.toLowerCase() === brandFilter);
|
||||
}
|
||||
|
||||
if (search) {
|
||||
items = items.filter(
|
||||
(p) =>
|
||||
p.name.toLowerCase().includes(search) ||
|
||||
p.brand.toLowerCase().includes(search) ||
|
||||
(p.color && p.color.toLowerCase().includes(search)) ||
|
||||
(p.resinType && p.resinType.toLowerCase().includes(search)),
|
||||
);
|
||||
}
|
||||
|
||||
const brands: CatalogBrand[] = Array.from(brandMap.entries())
|
||||
.map(([name, count]) => ({
|
||||
id: name.toLowerCase().replace(/[^a-z0-9]/g, "_"),
|
||||
name,
|
||||
type: "resin" as const,
|
||||
itemCount: count,
|
||||
}))
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
const response: CatalogResponse = { items, brands };
|
||||
return NextResponse.json(response);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch resin catalog:", error);
|
||||
return NextResponse.json(
|
||||
{ items: [], brands: [], error: "Failed to fetch resin data" },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
}
|
||||
27
src/app/api/health/route.ts
Normal file
27
src/app/api/health/route.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
await prisma.$queryRaw`SELECT 1`;
|
||||
return NextResponse.json(
|
||||
{
|
||||
status: "healthy",
|
||||
timestamp: new Date().toISOString(),
|
||||
database: "connected",
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
} catch {
|
||||
return NextResponse.json(
|
||||
{
|
||||
status: "unhealthy",
|
||||
timestamp: new Date().toISOString(),
|
||||
database: "disconnected",
|
||||
},
|
||||
{ status: 503 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user