update forms

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-05-07 21:02:15 +03:00
co-authored by Copilot
parent dd32658500
commit 38565298fc
32 changed files with 797 additions and 236 deletions
@@ -63,7 +63,7 @@ const DEFAULT_VALUES: PaymentMadeFormValues & { details: Array<{ bill_id?: strin
payment_date: getTodayDate(),
paid_through: "",
notes: "",
details: []
details: [{ amount_paid: 0 }]
}
// ── Mapping helpers ──
@@ -79,14 +79,14 @@ function mapToFormValues(data: unknown): typeof DEFAULT_VALUES {
vendor: toRelation(d.vendor_id, d.vendor?.company_name ?? d.vendor?.name ?? d.vendor_name),
employee: toRelation(d.employee_id, d.employee?.first_name ? `${d.employee.first_name} ${d.employee.last_name ?? ""}`.trim() : d.employee_name),
payment_mode: toRelation(paymentModeId, paymentModeLabel),
payment_for: d.payment_for || "",
payment_for: d.payment_for || "bill",
amount: d.payment_made ? String(d.payment_made) : "",
payment_number: d.payment_number || "",
payment_reference: d.payment_reference || "",
payment_date: d.payment_date || "",
paid_through: d.paid_through || "-",
notes: d.notes || "-",
details: [{ bill_id: d.bill_id, amount_paid: d.amount_paid }],
details: [{ bill_id: d.bill_id, expense_id: d.expense_id, amount_paid: d.amount_paid ?? 0 }],
}
}
@@ -249,6 +249,7 @@ export function PaymentMadeForm({ resourceId, initialData, onSuccess, billId, ex
name="payment_mode"
label="Payment Mode"
placeholder="Select payment mode"
required
queryKey={[PAYMENT_MODE_ROUTES.INDEX]}
listFn={() => api.paymentModes.list()}
mapOption={mapLookupOption}
@@ -1,23 +1,61 @@
import { z } from "zod"
import { PaymentFor } from "@garage/api"
const relationFieldSchema = z
.object({ value: z.string(), label: z.string() })
.nullable()
const requiredRelationFieldSchema = relationFieldSchema.superRefine((value, ctx) => {
if (!value?.value) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "This field is required",
})
}
})
const optionalStringMax255Schema = z.preprocess(
(value) => (value === "" || value == null ? undefined : value),
z.string().max(255, "Must be at most 255 characters").optional(),
)
const detailsItemSchema = z.object({
bill_id: z.union([z.string(), z.number()]).optional().nullable(),
expense_id: z.union([z.string(), z.number()]).optional().nullable(),
amount_paid: z.coerce.number().min(0).optional(),
})
const paymentMadeFormSchema = z.object({
// ── Relations ──
vendor: relationFieldSchema,
employee: relationFieldSchema,
payment_mode: relationFieldSchema,
payment_mode: requiredRelationFieldSchema,
// ── Payment info ──
amount: z.string().min(1, "Amount is required"),
payment_for: z.string().min(1, "Payment for is required"),
payment_number: z.string().optional(),
payment_reference: z.string().optional(),
payment_date: z.string().min(1, "Payment date is required"),
paid_through: z.string().optional(),
amount: z.coerce.number().min(0, "Amount must be 0 or more"),
payment_for: z.enum(PaymentFor),
payment_number: optionalStringMax255Schema,
payment_reference: optionalStringMax255Schema,
payment_date: z.string().min(1, "Payment date is required").date("Enter a valid date"),
paid_through: optionalStringMax255Schema,
notes: z.string().optional(),
details: z.array(detailsItemSchema).min(1, "At least one payment detail is required"),
}).superRefine((values, ctx) => {
const hasVendor = Boolean(values.vendor?.value)
const hasEmployee = Boolean(values.employee?.value)
if (!hasVendor && !hasEmployee) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["vendor"],
message: "Vendor or employee is required",
})
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["employee"],
message: "Vendor or employee is required",
})
}
})
type PaymentMadeFormValues = z.infer<typeof paymentMadeFormSchema>