phase 2 and 3
This commit is contained in:
+237
@@ -0,0 +1,237 @@
|
||||
import { z } from "zod";
|
||||
|
||||
// ---- shared --------------------------------------------------------------
|
||||
|
||||
const NonEmpty = z.string().trim().min(1, "Required").max(200);
|
||||
const Code = z.string().trim().min(1).max(64).regex(/^[A-Za-z0-9._\-/]+$/, "Use letters, digits, . _ - /");
|
||||
const OptionalText = z
|
||||
.string()
|
||||
.trim()
|
||||
.max(5000)
|
||||
.transform((v) => (v.length === 0 ? null : v))
|
||||
.nullable()
|
||||
.optional();
|
||||
const JsonString = z
|
||||
.string()
|
||||
.max(10_000)
|
||||
.refine(
|
||||
(s) => {
|
||||
if (s.length === 0) return true;
|
||||
try {
|
||||
JSON.parse(s);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{ message: "Must be valid JSON" },
|
||||
)
|
||||
.transform((s) => (s.length === 0 ? null : s))
|
||||
.nullable()
|
||||
.optional();
|
||||
|
||||
const Pin = z.string().regex(/^\d{4}$/, "PIN must be exactly 4 digits");
|
||||
|
||||
// ---- users ---------------------------------------------------------------
|
||||
|
||||
export const CreateAdminSchema = z.object({
|
||||
role: z.literal("admin"),
|
||||
name: NonEmpty,
|
||||
email: z.string().email().max(200),
|
||||
password: z.string().min(8).max(200),
|
||||
});
|
||||
|
||||
export const CreateOperatorSchema = z.object({
|
||||
role: z.literal("operator"),
|
||||
name: NonEmpty,
|
||||
pin: Pin,
|
||||
});
|
||||
|
||||
export const CreateUserSchema = z.discriminatedUnion("role", [
|
||||
CreateAdminSchema,
|
||||
CreateOperatorSchema,
|
||||
]);
|
||||
|
||||
export const UpdateUserSchema = z
|
||||
.object({
|
||||
name: NonEmpty.optional(),
|
||||
active: z.boolean().optional(),
|
||||
email: z.string().email().max(200).optional(),
|
||||
password: z.string().min(8).max(200).optional(),
|
||||
pin: Pin.optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
// ---- machines ------------------------------------------------------------
|
||||
|
||||
export const MachineKinds = [
|
||||
"NCT_PUNCH",
|
||||
"PRESS_BRAKE",
|
||||
"RIVET",
|
||||
"WELD",
|
||||
"LASER",
|
||||
"SHEAR",
|
||||
"ASSEMBLY",
|
||||
"OTHER",
|
||||
] as const;
|
||||
|
||||
export const CreateMachineSchema = z.object({
|
||||
name: NonEmpty,
|
||||
kind: z.enum(MachineKinds),
|
||||
location: OptionalText,
|
||||
notes: OptionalText,
|
||||
});
|
||||
|
||||
export const UpdateMachineSchema = z
|
||||
.object({
|
||||
name: NonEmpty.optional(),
|
||||
kind: z.enum(MachineKinds).optional(),
|
||||
location: OptionalText,
|
||||
notes: OptionalText,
|
||||
active: z.boolean().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
// ---- operation templates -------------------------------------------------
|
||||
|
||||
export const CreateTemplateSchema = z.object({
|
||||
name: NonEmpty,
|
||||
machineId: z.string().min(1).nullable().optional(),
|
||||
defaultSettings: JsonString,
|
||||
defaultInstructions: OptionalText,
|
||||
qcRequired: z.boolean().default(false),
|
||||
});
|
||||
|
||||
export const UpdateTemplateSchema = z
|
||||
.object({
|
||||
name: NonEmpty.optional(),
|
||||
machineId: z.string().min(1).nullable().optional(),
|
||||
defaultSettings: JsonString,
|
||||
defaultInstructions: OptionalText,
|
||||
qcRequired: z.boolean().optional(),
|
||||
active: z.boolean().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
// ---- projects ------------------------------------------------------------
|
||||
|
||||
export const ProjectStatuses = ["planning", "in_progress", "completed", "cancelled"] as const;
|
||||
|
||||
export const CreateProjectSchema = z.object({
|
||||
code: Code,
|
||||
name: NonEmpty,
|
||||
customerCode: z
|
||||
.string()
|
||||
.trim()
|
||||
.max(64)
|
||||
.transform((v) => (v.length === 0 ? null : v))
|
||||
.nullable()
|
||||
.optional(),
|
||||
dueDate: z.coerce.date().nullable().optional(),
|
||||
notes: OptionalText,
|
||||
});
|
||||
|
||||
export const UpdateProjectSchema = z
|
||||
.object({
|
||||
code: Code.optional(),
|
||||
name: NonEmpty.optional(),
|
||||
customerCode: z
|
||||
.string()
|
||||
.trim()
|
||||
.max(64)
|
||||
.transform((v) => (v.length === 0 ? null : v))
|
||||
.nullable()
|
||||
.optional(),
|
||||
dueDate: z.coerce.date().nullable().optional(),
|
||||
status: z.enum(ProjectStatuses).optional(),
|
||||
notes: OptionalText,
|
||||
})
|
||||
.strict();
|
||||
|
||||
// ---- assemblies / parts --------------------------------------------------
|
||||
|
||||
export const CreateAssemblySchema = z.object({
|
||||
code: Code,
|
||||
name: NonEmpty,
|
||||
qty: z.coerce.number().int().positive().max(100000).default(1),
|
||||
notes: OptionalText,
|
||||
});
|
||||
|
||||
export const UpdateAssemblySchema = z
|
||||
.object({
|
||||
code: Code.optional(),
|
||||
name: NonEmpty.optional(),
|
||||
qty: z.coerce.number().int().positive().max(100000).optional(),
|
||||
notes: OptionalText,
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const CreatePartSchema = z.object({
|
||||
code: Code,
|
||||
name: NonEmpty,
|
||||
material: z
|
||||
.string()
|
||||
.trim()
|
||||
.max(120)
|
||||
.transform((v) => (v.length === 0 ? null : v))
|
||||
.nullable()
|
||||
.optional(),
|
||||
qty: z.coerce.number().int().positive().max(100000).default(1),
|
||||
notes: OptionalText,
|
||||
});
|
||||
|
||||
export const UpdatePartSchema = z
|
||||
.object({
|
||||
code: Code.optional(),
|
||||
name: NonEmpty.optional(),
|
||||
material: z
|
||||
.string()
|
||||
.trim()
|
||||
.max(120)
|
||||
.transform((v) => (v.length === 0 ? null : v))
|
||||
.nullable()
|
||||
.optional(),
|
||||
qty: z.coerce.number().int().positive().max(100000).optional(),
|
||||
notes: OptionalText,
|
||||
stepFileId: z.string().min(1).nullable().optional(),
|
||||
drawingFileId: z.string().min(1).nullable().optional(),
|
||||
cutFileId: z.string().min(1).nullable().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
// ---- operations ---------------------------------------------------------
|
||||
|
||||
export const OperationStatuses = ["pending", "in_progress", "completed"] as const;
|
||||
|
||||
export const CreateOperationSchema = z.object({
|
||||
templateId: z.string().min(1).nullable().optional(),
|
||||
name: NonEmpty,
|
||||
machineId: z.string().min(1).nullable().optional(),
|
||||
settings: JsonString,
|
||||
materialNotes: OptionalText,
|
||||
instructions: OptionalText,
|
||||
qcRequired: z.boolean().default(false),
|
||||
plannedMinutes: z.coerce.number().int().positive().max(100000).nullable().optional(),
|
||||
plannedUnits: z.coerce.number().int().positive().max(100000).nullable().optional(),
|
||||
sequence: z.coerce.number().int().positive().max(10000).optional(),
|
||||
});
|
||||
|
||||
export const UpdateOperationSchema = z
|
||||
.object({
|
||||
templateId: z.string().min(1).nullable().optional(),
|
||||
name: NonEmpty.optional(),
|
||||
machineId: z.string().min(1).nullable().optional(),
|
||||
settings: JsonString,
|
||||
materialNotes: OptionalText,
|
||||
instructions: OptionalText,
|
||||
qcRequired: z.boolean().optional(),
|
||||
plannedMinutes: z.coerce.number().int().positive().max(100000).nullable().optional(),
|
||||
plannedUnits: z.coerce.number().int().positive().max(100000).nullable().optional(),
|
||||
sequence: z.coerce.number().int().positive().max(10000).optional(),
|
||||
status: z.enum(OperationStatuses).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const ReorderOperationsSchema = z.object({
|
||||
order: z.array(z.string().min(1)).min(1),
|
||||
});
|
||||
Reference in New Issue
Block a user