feat(services): customer-linked services CRUD module
Same pattern as customers. Each service belongs to one customer (FK), has unit price (TRY), billing period (monthly/yearly/onetime), and recurring flag. - lib/validation/services.ts: Zod schema with TRY price coercion (accepts comma decimal), enum billing period, recurring boolean coercion. - lib/appwrite/service-actions.ts: createServiceAction, updateServiceAction, deleteServiceAction. Same tenant guard, audit log, team-scoped row perms. - lib/appwrite/service-queries.ts: listServices, listServicesByCustomer. - lib/format.ts: formatTRY (Intl.NumberFormat tr-TR), formatDate/DateTime, BILLING_PERIOD_LABEL mapping (Aylık/Yıllık/Tek seferlik). - /services page (server): joins services with customer names via in-memory map. - ServicesClient: TanStack table with global filter (name/customer/desc), Repeat icon next to recurring badges, formatted TRY column. - ServiceFormSheet: customer dropdown (disabled if no customers exist), unit price + billing period + recurring switch. - DeleteServiceDialog: same destructive confirmation pattern. Empty state on /services CTA's user back to add a customer first if none exist.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const serviceSchema = z.object({
|
||||
customerId: z.string().min(1, "Müşteri seçin."),
|
||||
name: z.string().trim().min(1, "Hizmet adı zorunlu.").max(255),
|
||||
description: z
|
||||
.string()
|
||||
.trim()
|
||||
.max(2000)
|
||||
.optional()
|
||||
.transform((v) => (v ? v : undefined)),
|
||||
unitPrice: z
|
||||
.union([z.number(), z.string()])
|
||||
.transform((v) => (typeof v === "string" ? Number(v.replace(",", ".")) : v))
|
||||
.pipe(z.number().nonnegative("Negatif olamaz.")),
|
||||
recurring: z
|
||||
.union([z.boolean(), z.literal("on"), z.literal(""), z.undefined()])
|
||||
.transform((v) => v === true || v === "on")
|
||||
.optional(),
|
||||
billingPeriod: z.enum(["monthly", "yearly", "onetime"]).optional().default("onetime"),
|
||||
});
|
||||
|
||||
export type ServiceInput = z.infer<typeof serviceSchema>;
|
||||
Reference in New Issue
Block a user