Add custom commission types
This commit is contained in:
43
src/app/(admin)/commissions/custom-cards/[id]/page.tsx
Normal file
43
src/app/(admin)/commissions/custom-cards/[id]/page.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import { listCommissionCustomCardImages } from "@/actions/commissions/customCards/images";
|
||||
import EditCustomCardForm from "@/components/commissions/customCards/EditCustomCardForm";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
export default async function CommissionCustomCardEditPage({
|
||||
params,
|
||||
}: {
|
||||
params: { id: string };
|
||||
}) {
|
||||
const { id } = await params;
|
||||
|
||||
const [card, options, extras, images] = await Promise.all([
|
||||
prisma.commissionCustomCard.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
options: { orderBy: { sortIndex: "asc" } },
|
||||
extras: { orderBy: { sortIndex: "asc" } },
|
||||
},
|
||||
}),
|
||||
prisma.commissionOption.findMany({ orderBy: [{ sortIndex: "asc" }, { name: "asc" }] }),
|
||||
prisma.commissionExtra.findMany({ orderBy: [{ sortIndex: "asc" }, { name: "asc" }] }),
|
||||
listCommissionCustomCardImages(),
|
||||
]);
|
||||
|
||||
if (!card) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex gap-4 justify-between pb-8">
|
||||
<h1 className="text-2xl font-bold mb-4">Edit Custom Commission Card</h1>
|
||||
</div>
|
||||
<EditCustomCardForm
|
||||
card={card}
|
||||
allOptions={options}
|
||||
allExtras={extras}
|
||||
images={images}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
20
src/app/(admin)/commissions/custom-cards/new/page.tsx
Normal file
20
src/app/(admin)/commissions/custom-cards/new/page.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { listCommissionCustomCardImages } from "@/actions/commissions/customCards/images";
|
||||
import NewCustomCardForm from "@/components/commissions/customCards/NewCustomCardForm";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export default async function CommissionCustomCardsNewPage() {
|
||||
const [options, extras, images] = await Promise.all([
|
||||
prisma.commissionOption.findMany({ orderBy: [{ sortIndex: "asc" }, { name: "asc" }] }),
|
||||
prisma.commissionExtra.findMany({ orderBy: [{ sortIndex: "asc" }, { name: "asc" }] }),
|
||||
listCommissionCustomCardImages(),
|
||||
]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex gap-4 justify-between pb-8">
|
||||
<h1 className="text-2xl font-bold mb-4">New Custom Commission Card</h1>
|
||||
</div>
|
||||
<NewCustomCardForm options={options} extras={extras} images={images} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
34
src/app/(admin)/commissions/custom-cards/page.tsx
Normal file
34
src/app/(admin)/commissions/custom-cards/page.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import ListCustomCards from "@/components/commissions/customCards/ListCustomCards";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { PlusCircleIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default async function CommissionCustomCardsPage() {
|
||||
const cards = await prisma.commissionCustomCard.findMany({
|
||||
include: {
|
||||
options: { include: { option: true }, orderBy: { sortIndex: "asc" } },
|
||||
extras: { include: { extra: true }, orderBy: { sortIndex: "asc" } },
|
||||
},
|
||||
orderBy: [{ sortIndex: "asc" }, { name: "asc" }],
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex gap-4 justify-between pb-8">
|
||||
<h1 className="text-2xl font-bold mb-4">Custom Commission Cards</h1>
|
||||
<Link
|
||||
href="/commissions/custom-cards/new"
|
||||
className="flex gap-2 items-center cursor-pointer bg-primary hover:bg-primary/90 text-primary-foreground px-4 py-2 rounded"
|
||||
>
|
||||
<PlusCircleIcon className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all text-primary-foreground" />
|
||||
Add new Card
|
||||
</Link>
|
||||
</div>
|
||||
{cards && cards.length > 0 ? (
|
||||
<ListCustomCards cards={cards} />
|
||||
) : (
|
||||
<p className="text-muted-foreground italic">No custom cards found.</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -7,6 +7,7 @@ import { z } from "zod/v4";
|
||||
|
||||
const payloadSchema = z.object({
|
||||
typeId: z.string().min(1).optional().nullable(),
|
||||
customCardId: z.string().min(1).optional().nullable(),
|
||||
optionId: z.string().min(1).optional().nullable(),
|
||||
extraIds: z.array(z.string().min(1)).default([]),
|
||||
|
||||
@ -14,6 +15,23 @@ const payloadSchema = z.object({
|
||||
customerEmail: z.string().email().max(320),
|
||||
customerSocials: z.string().max(2000).optional().nullable(),
|
||||
message: z.string().min(1).max(20_000),
|
||||
}).superRefine((data, ctx) => {
|
||||
const hasType = Boolean(data.typeId);
|
||||
const hasCustom = Boolean(data.customCardId);
|
||||
if (!hasType && !hasCustom) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ["typeId"],
|
||||
message: "Missing commission type or custom card",
|
||||
});
|
||||
}
|
||||
if (hasType && hasCustom) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ["typeId"],
|
||||
message: "Only one of typeId or customCardId is allowed",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function safeJsonParse(input: string) {
|
||||
@ -83,6 +101,7 @@ export async function POST(request: Request) {
|
||||
message: payload.data.message,
|
||||
|
||||
typeId: payload.data.typeId ?? null,
|
||||
customCardId: payload.data.customCardId ?? null,
|
||||
optionId: payload.data.optionId ?? null,
|
||||
|
||||
ipAddress,
|
||||
|
||||
Reference in New Issue
Block a user