feat(03-02): server actions + getAllServices query for service catalog
- Create src/app/admin/catalog/actions.ts with createService, updateService, toggleServiceActive - Each action includes requireAdmin() guard via getServerSession - Zod validation: name (min 1), unit_price (coerce.number min 0.01) - Add getAllServices() to src/lib/admin-queries.ts ordered by name - Import service_catalog and ServiceCatalog types in admin-queries.ts
This commit is contained in:
@@ -0,0 +1,64 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import { db } from "@/db";
|
||||||
|
import { service_catalog } from "@/db/schema";
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { getServerSession } from "next-auth";
|
||||||
|
import { authOptions } from "@/lib/auth";
|
||||||
|
|
||||||
|
const serviceSchema = z.object({
|
||||||
|
name: z.string().min(1, "Nome richiesto"),
|
||||||
|
description: z.string().optional(),
|
||||||
|
unit_price: z.coerce.number().min(0.01, "Prezzo deve essere maggiore di 0"),
|
||||||
|
});
|
||||||
|
|
||||||
|
async function requireAdmin() {
|
||||||
|
const session = await getServerSession(authOptions);
|
||||||
|
if (!session) throw new Error("Non autorizzato");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createService(formData: FormData) {
|
||||||
|
await requireAdmin();
|
||||||
|
const parsed = serviceSchema.safeParse({
|
||||||
|
name: formData.get("name"),
|
||||||
|
description: formData.get("description") ?? "",
|
||||||
|
unit_price: formData.get("unit_price"),
|
||||||
|
});
|
||||||
|
if (!parsed.success) throw new Error(parsed.error.issues[0].message);
|
||||||
|
await db.insert(service_catalog).values({
|
||||||
|
name: parsed.data.name,
|
||||||
|
description: parsed.data.description ?? null,
|
||||||
|
unit_price: parsed.data.unit_price.toFixed(2),
|
||||||
|
});
|
||||||
|
revalidatePath("/admin/catalog");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateService(serviceId: string, formData: FormData) {
|
||||||
|
await requireAdmin();
|
||||||
|
const parsed = serviceSchema.safeParse({
|
||||||
|
name: formData.get("name"),
|
||||||
|
description: formData.get("description") ?? "",
|
||||||
|
unit_price: formData.get("unit_price"),
|
||||||
|
});
|
||||||
|
if (!parsed.success) throw new Error(parsed.error.issues[0].message);
|
||||||
|
await db
|
||||||
|
.update(service_catalog)
|
||||||
|
.set({
|
||||||
|
name: parsed.data.name,
|
||||||
|
description: parsed.data.description ?? null,
|
||||||
|
unit_price: parsed.data.unit_price.toFixed(2),
|
||||||
|
})
|
||||||
|
.where(eq(service_catalog.id, serviceId));
|
||||||
|
revalidatePath("/admin/catalog");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function toggleServiceActive(serviceId: string, active: boolean) {
|
||||||
|
await requireAdmin();
|
||||||
|
await db
|
||||||
|
.update(service_catalog)
|
||||||
|
.set({ active })
|
||||||
|
.where(eq(service_catalog.id, serviceId));
|
||||||
|
revalidatePath("/admin/catalog");
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
documents,
|
documents,
|
||||||
notes,
|
notes,
|
||||||
time_entries,
|
time_entries,
|
||||||
|
service_catalog,
|
||||||
} from "@/db/schema";
|
} from "@/db/schema";
|
||||||
import { eq, inArray, asc, isNull, sql } from "drizzle-orm";
|
import { eq, inArray, asc, isNull, sql } from "drizzle-orm";
|
||||||
import type {
|
import type {
|
||||||
@@ -20,6 +21,7 @@ import type {
|
|||||||
Document,
|
Document,
|
||||||
Note,
|
Note,
|
||||||
Comment,
|
Comment,
|
||||||
|
ServiceCatalog,
|
||||||
} from "@/db/schema";
|
} from "@/db/schema";
|
||||||
|
|
||||||
export type ClientWithPayments = {
|
export type ClientWithPayments = {
|
||||||
@@ -188,4 +190,11 @@ export async function getClientFullDetail(id: string): Promise<ClientFullDetail
|
|||||||
notes: notesRows,
|
notes: notesRows,
|
||||||
comments: commentsRows,
|
comments: commentsRows,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAllServices(): Promise<ServiceCatalog[]> {
|
||||||
|
return db
|
||||||
|
.select()
|
||||||
|
.from(service_catalog)
|
||||||
|
.orderBy(asc(service_catalog.name));
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user