Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 4x 4x 3x 3x 3x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x 2x 2x 5x 5x 5x 5x 5x 5x 5x 7x 7x 7x 7x 3x 3x 3x 3x 3x 3x 1x 1x 1x | export const dynamic = "force-dynamic";
import { NextRequest, NextResponse } from 'next/server';
import {
withAdmin,
withErrorHandling,
successResponse,
createdResponse,
ApiError,
ApiSuccessResponse,
ApiErrorResponse } from "@/lib/api";
import { prisma } from "@/lib/prisma";
import { z } from "zod";
import { invalidatePattern } from "@/lib/core";
// Validation schema for creating a category
const createCategorySchema = z.object({
title: z.string().min(1, "Title is required"),
slug: z.string().min(1, "Slug is required"),
imageUrl: z.string().url().optional().nullable(),
description: z.string().optional().nullable(),
parentId: z
.union([z.string(), z.number()])
.transform((val) => (typeof val === "string" ? parseInt(val) : val))
.optional()
.nullable() });
type Category = {
id: number;
title: string;
slug: string;
imageUrl: string | null;
description: string | null;
parentId: number | null;
children?: unknown[];
_count?: { products: number };
};
/**
* GET /api/admin/categories
* Get all categories with hierarchy and product counts
* Public endpoint - no authentication required
*/
async function handleGet(): Promise<NextResponse<ApiSuccessResponse<Category[]> | ApiErrorResponse>> {
const categories = await prisma.category.findMany({
include: {
children: true,
_count: { select: { products: true } } },
orderBy: { title: "asc" } });
return successResponse(categories);
}
/**
* POST /api/admin/categories
* Create new category
* Admin only endpoint
*/
async function handlePost(
request: NextRequest
): Promise<NextResponse<ApiSuccessResponse<Category> | ApiErrorResponse>> {
const body = await request.json();
// Validate request body
const validation = createCategorySchema.safeParse(body);
if (!validation.success) {
throw ApiError.validation("Validation failed", validation.error.flatten().fieldErrors);
}
const { title, slug, imageUrl, description, parentId } = validation.data;
const category = await prisma.category.create({
data: {
title,
slug,
imageUrl: imageUrl || null,
description: description || null,
parentId: parentId || null },
include: { children: true } });
// Invalidate all categories cache entries
await invalidatePattern("categories:*");
return createdResponse(category);
}
export const GET = withErrorHandling(handleGet);
export const POST = withErrorHandling(withAdmin(handlePost));
|