Spaces:
Sleeping
Sleeping
| import { z } from 'zod'; | |
| // ============================================================================ | |
| // CORE ENTITY INTERFACES | |
| // ============================================================================ | |
| /** | |
| * Asset entity representing basic asset information | |
| */ | |
| export interface Asset { | |
| assetID: number; | |
| assetCode: string; | |
| assetType: string; | |
| brandModel: string; | |
| serialNumber: string; | |
| assetCondition: string; | |
| } | |
| /** | |
| * System Details entity representing technical specifications linked to assets | |
| */ | |
| export interface SystemDetails { | |
| systemDetailsID: number; | |
| assetID: number; | |
| systemModel: string; | |
| processor: string; | |
| installedRAM: string; | |
| graphics: string; | |
| screenResolution: string; | |
| diskModel: string; | |
| diskSize: string; | |
| manufacturer: string; | |
| } | |
| /** | |
| * Asset Assignment entity representing employee assignment tracking | |
| */ | |
| export interface AssetAssignment { | |
| assignmentID: number; | |
| assetID: number; | |
| employeeID: number; | |
| employeeName: string; | |
| assetCode: string; | |
| assignedDate: string; // ISO 8601 format | |
| returnedDate: string | null; // ISO 8601 format | |
| remarks: string; | |
| } | |
| /** | |
| * Asset Item entity representing individual components/items attached to an asset | |
| */ | |
| export interface AssetItem { | |
| itemID: number; | |
| assetID: number; | |
| itemType: string; | |
| itemName: string; | |
| quantity: number; | |
| specifications: string; | |
| serialNumber?: string; | |
| condition: string; | |
| notes?: string; | |
| addedDate: string; // ISO 8601 format | |
| } | |
| // ============================================================================ | |
| // API REQUEST/RESPONSE TYPES | |
| // ============================================================================ | |
| /** | |
| * Request type for creating a new asset (excludes auto-generated ID) | |
| */ | |
| export interface AssetCreateRequest { | |
| assetCode: string; | |
| assetType: string; | |
| brandModel: string; | |
| serialNumber: string; | |
| assetCondition: string; | |
| purchaseDate?: string; | |
| warrantyExpiry?: string; | |
| purchaseCost?: number; | |
| currentValue?: number; | |
| location?: string; | |
| notes?: string; | |
| } | |
| /** | |
| * Request type for updating an existing asset | |
| */ | |
| export interface AssetUpdateRequest { | |
| assetID: number; | |
| assetCode: string; | |
| assetType: string; | |
| brandModel: string; | |
| serialNumber: string; | |
| assetCondition: string; | |
| } | |
| /** | |
| * Request type for creating new system details (excludes auto-generated ID) | |
| */ | |
| export interface SystemDetailsCreateRequest { | |
| assetID: number; | |
| systemModel: string; | |
| processor: string; | |
| installedRAM: string; | |
| graphics: string; | |
| screenResolution: string; | |
| diskModel: string; | |
| diskSize: string; | |
| manufacturer: string; | |
| } | |
| /** | |
| * Request type for updating existing system details | |
| */ | |
| export interface SystemDetailsUpdateRequest { | |
| systemDetailsID: number; | |
| assetID: number; | |
| systemModel: string; | |
| processor: string; | |
| installedRAM: string; | |
| graphics: string; | |
| screenResolution: string; | |
| diskModel: string; | |
| diskSize: string; | |
| manufacturer: string; | |
| } | |
| /** | |
| * Request type for creating a new asset assignment (excludes auto-generated ID) | |
| */ | |
| export interface AssetAssignmentCreateRequest { | |
| assetID: number; | |
| employeeID: number; | |
| employeeName: string; | |
| assetCode: string; | |
| assignedDate: string; // ISO 8601 format | |
| returnedDate: string | null; // ISO 8601 format | |
| remarks: string; | |
| } | |
| /** | |
| * Request type for updating an existing asset assignment | |
| */ | |
| export interface AssetAssignmentUpdateRequest { | |
| assignmentID: number; | |
| assetID: number; | |
| employeeID: number; | |
| employeeName: string; | |
| assetCode: string; | |
| assignedDate: string; // ISO 8601 format | |
| returnedDate: string | null; // ISO 8601 format | |
| remarks: string; | |
| } | |
| /** | |
| * Request type for creating a new asset item (excludes auto-generated ID) | |
| */ | |
| export interface AssetItemCreateRequest { | |
| assetID: number; | |
| itemType: string; | |
| itemName: string; | |
| quantity: number; | |
| specifications: string; | |
| serialNumber?: string; | |
| condition: string; | |
| notes?: string; | |
| addedDate: string; // ISO 8601 format | |
| } | |
| /** | |
| * Request type for updating an existing asset item | |
| */ | |
| export interface AssetItemUpdateRequest { | |
| itemID: number; | |
| assetID: number; | |
| itemType: string; | |
| itemName: string; | |
| quantity: number; | |
| specifications: string; | |
| serialNumber?: string; | |
| condition: string; | |
| notes?: string; | |
| addedDate: string; // ISO 8601 format | |
| } | |
| // ============================================================================ | |
| // ENUM TYPES AND CONSTANTS | |
| // ============================================================================ | |
| /** | |
| * Valid asset condition values | |
| */ | |
| export type AssetCondition = 'Excellent' | 'Good' | 'Fair' | 'Poor'; | |
| /** | |
| * Common asset types | |
| */ | |
| export type AssetType = | |
| | 'Laptop' | |
| | 'Desktop' | |
| | 'Monitor' | |
| | 'Keyboard' | |
| | 'Mouse' | |
| | 'Wired Mouse' | |
| | 'Wireless Mouse' | |
| | 'Laptop Stand' | |
| | 'Extended Screen' | |
| | 'Printer' | |
| | 'Scanner' | |
| | 'Tablet' | |
| | 'Phone' | |
| | 'Other'; | |
| /** | |
| * Asset condition options for dropdowns | |
| */ | |
| export const ASSET_CONDITIONS: AssetCondition[] = ['Excellent', 'Good', 'Fair', 'Poor']; | |
| /** | |
| * Asset type options for dropdowns | |
| */ | |
| export const ASSET_TYPES: AssetType[] = [ | |
| 'Laptop', | |
| 'Desktop', | |
| 'Monitor', | |
| 'Keyboard', | |
| 'Mouse', | |
| 'Wired Mouse', | |
| 'Wireless Mouse', | |
| 'Laptop Stand', | |
| 'Extended Screen', | |
| 'Printer', | |
| 'Scanner', | |
| 'Tablet', | |
| 'Phone', | |
| 'Other' | |
| ]; | |
| /** | |
| * Asset item types | |
| */ | |
| export type AssetItemType = | |
| | 'RAM' | |
| | 'Storage' | |
| | 'Battery' | |
| | 'Charger' | |
| | 'Cable' | |
| | 'Adapter' | |
| | 'Keyboard' | |
| | 'Mouse' | |
| | 'Webcam' | |
| | 'Headset' | |
| | 'Docking Station' | |
| | 'Monitor' | |
| | 'Other'; | |
| /** | |
| * Asset item type options for dropdowns | |
| */ | |
| export const ASSET_ITEM_TYPES: AssetItemType[] = [ | |
| 'RAM', | |
| 'Storage', | |
| 'Battery', | |
| 'Charger', | |
| 'Cable', | |
| 'Adapter', | |
| 'Keyboard', | |
| 'Mouse', | |
| 'Webcam', | |
| 'Headset', | |
| 'Docking Station', | |
| 'Monitor', | |
| 'Other' | |
| ]; | |
| // ============================================================================ | |
| // ZOD VALIDATION SCHEMAS | |
| // ============================================================================ | |
| /** | |
| * Zod schema for Asset validation | |
| */ | |
| export const AssetSchema = z.object({ | |
| assetID: z.number().int().positive().optional(), | |
| assetCode: z.string() | |
| .min(1, 'Asset code is required') | |
| .max(20, 'Asset code must be 20 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Asset code cannot be empty or contain only spaces' | |
| }) | |
| .refine(val => /^[A-Za-z0-9\-_]+$/.test(val.trim()), { | |
| message: 'Asset code can only contain letters, numbers, hyphens, and underscores' | |
| }), | |
| assetType: z.string() | |
| .min(1, 'Asset type is required') | |
| .max(50, 'Asset type must be 50 characters or less') | |
| .refine(val => ASSET_TYPES.includes(val as AssetType), { | |
| message: 'Please select a valid asset type from the list' | |
| }), | |
| brandModel: z.string() | |
| .min(1, 'Brand model is required') | |
| .max(100, 'Brand model must be 100 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Brand model cannot be empty or contain only spaces' | |
| }), | |
| serialNumber: z.string() | |
| .min(1, 'Serial number is required') | |
| .max(50, 'Serial number must be 50 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Serial number cannot be empty or contain only spaces' | |
| }) | |
| .refine(val => /^[A-Za-z0-9\-_]+$/.test(val.trim()), { | |
| message: 'Serial number can only contain letters, numbers, hyphens, and underscores' | |
| }), | |
| assetCondition: z.enum(['Excellent', 'Good', 'Fair', 'Poor'], { | |
| errorMap: () => ({ message: 'Asset condition must be Excellent, Good, Fair, or Poor' }) | |
| }), | |
| }); | |
| /** | |
| * Zod schema for Asset creation (excludes ID) | |
| */ | |
| export const AssetCreateSchema = AssetSchema.omit({ assetID: true }); | |
| /** | |
| * Zod schema for Asset updates (requires ID and assetCode) | |
| */ | |
| export const AssetUpdateSchema = AssetSchema.required({ assetID: true, assetCode: true }); | |
| /** | |
| * Zod schema for System Details validation | |
| */ | |
| export const SystemDetailsSchema = z.object({ | |
| systemDetailsID: z.number().int().positive().optional(), | |
| assetID: z.number().int().positive('Asset ID must be a positive number'), | |
| systemModel: z.string() | |
| .min(1, 'System model is required') | |
| .max(100, 'System model must be 100 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'System model cannot be empty or contain only spaces' | |
| }), | |
| processor: z.string() | |
| .min(1, 'Processor information is required') | |
| .max(100, 'Processor must be 100 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Processor information cannot be empty or contain only spaces' | |
| }), | |
| installedRAM: z.string() | |
| .min(1, 'RAM information is required') | |
| .max(50, 'RAM must be 50 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'RAM information cannot be empty or contain only spaces' | |
| }), | |
| graphics: z.string() | |
| .min(1, 'Graphics information is required') | |
| .max(100, 'Graphics must be 100 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Graphics information cannot be empty or contain only spaces' | |
| }), | |
| screenResolution: z.string() | |
| .min(1, 'Screen resolution is required') | |
| .max(50, 'Screen resolution must be 50 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Screen resolution cannot be empty or contain only spaces' | |
| }) | |
| .refine(val => /^\d+x\d+$/.test(val.trim()) || val === 'custom', { | |
| message: 'Screen resolution must be in format "1920x1080" or select from the dropdown' | |
| }), | |
| diskModel: z.string() | |
| .min(1, 'Disk model is required') | |
| .max(100, 'Disk model must be 100 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Disk model cannot be empty or contain only spaces' | |
| }), | |
| diskSize: z.string() | |
| .min(1, 'Disk size is required') | |
| .max(50, 'Disk size must be 50 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Disk size cannot be empty or contain only spaces' | |
| }), | |
| manufacturer: z.string() | |
| .min(1, 'Manufacturer is required') | |
| .max(100, 'Manufacturer must be 100 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Manufacturer cannot be empty or contain only spaces' | |
| }), | |
| }); | |
| /** | |
| * Zod schema for System Details creation (excludes ID) | |
| */ | |
| export const SystemDetailsCreateSchema = SystemDetailsSchema.omit({ systemDetailsID: true }); | |
| /** | |
| * Zod schema for System Details updates (requires ID) | |
| */ | |
| export const SystemDetailsUpdateSchema = SystemDetailsSchema.required({ systemDetailsID: true }); | |
| /** | |
| * Base Zod schema for Asset Assignment validation (without refinements) | |
| */ | |
| const AssetAssignmentBaseSchema = z.object({ | |
| assignmentID: z.number().int().positive().optional(), | |
| assetID: z.number().int().positive('Asset ID must be a positive number'), | |
| employeeID: z.number().int().positive('Employee ID must be a positive number'), | |
| employeeName: z.string() | |
| .min(1, 'Employee name is required') | |
| .max(100, 'Employee name must be 100 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Employee name cannot be empty or contain only spaces' | |
| }), | |
| assetCode: z.string() | |
| .min(1, 'Asset code is required') | |
| .max(20, 'Asset code must be 20 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Asset code cannot be empty or contain only spaces' | |
| }), | |
| assignedDate: z.string().datetime('Assigned date must be in ISO 8601 format'), | |
| returnedDate: z.string().datetime('Returned date must be in ISO 8601 format').nullable(), | |
| remarks: z.string() | |
| .min(1, 'Remarks are required') | |
| .max(500, 'Remarks must be 500 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Remarks cannot be empty or contain only spaces' | |
| }), | |
| }); | |
| /** | |
| * Zod schema for Asset Assignment validation (with date validation refinement) | |
| */ | |
| export const AssetAssignmentSchema = AssetAssignmentBaseSchema.refine(data => { | |
| // If both dates are provided, returned date must be after assigned date | |
| if (data.returnedDate && data.assignedDate) { | |
| const assignedDate = new Date(data.assignedDate); | |
| const returnedDate = new Date(data.returnedDate); | |
| return returnedDate > assignedDate; | |
| } | |
| return true; | |
| }, { | |
| message: 'Returned date must be after the assigned date', | |
| path: ['returnedDate'] | |
| }); | |
| /** | |
| * Zod schema for Asset Assignment creation (excludes ID) | |
| */ | |
| export const AssetAssignmentCreateSchema = AssetAssignmentBaseSchema.omit({ assignmentID: true }).refine(data => { | |
| // If both dates are provided, returned date must be after assigned date | |
| if (data.returnedDate && data.assignedDate) { | |
| const assignedDate = new Date(data.assignedDate); | |
| const returnedDate = new Date(data.returnedDate); | |
| return returnedDate > assignedDate; | |
| } | |
| return true; | |
| }, { | |
| message: 'Returned date must be after the assigned date', | |
| path: ['returnedDate'] | |
| }); | |
| /** | |
| * Zod schema for Asset Assignment updates (requires ID) | |
| */ | |
| export const AssetAssignmentUpdateSchema = AssetAssignmentBaseSchema.required({ assignmentID: true }).refine(data => { | |
| // If both dates are provided, returned date must be after assigned date | |
| if (data.returnedDate && data.assignedDate) { | |
| const assignedDate = new Date(data.assignedDate); | |
| const returnedDate = new Date(data.returnedDate); | |
| return returnedDate > assignedDate; | |
| } | |
| return true; | |
| }, { | |
| message: 'Returned date must be after the assigned date', | |
| path: ['returnedDate'] | |
| }); | |
| /** | |
| * Zod schema for Asset Assignment form editing (excludes ID for form validation) | |
| * Uses Date objects instead of strings for form compatibility | |
| */ | |
| export const AssetAssignmentFormSchema = z.object({ | |
| assetID: z.number().int().positive('Asset ID must be a positive number'), | |
| employeeID: z.number().int().positive('Employee ID must be a positive number'), | |
| employeeName: z.string() | |
| .min(1, 'Employee name is required') | |
| .max(100, 'Employee name must be 100 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Employee name cannot be empty or contain only spaces' | |
| }), | |
| assetCode: z.string() | |
| .min(1, 'Asset code is required') | |
| .max(20, 'Asset code must be 20 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Asset code cannot be empty or contain only spaces' | |
| }), | |
| assignedDate: z.date({ | |
| required_error: 'Assigned date is required', | |
| invalid_type_error: 'Assigned date must be a valid date' | |
| }), | |
| returnedDate: z.date({ | |
| invalid_type_error: 'Returned date must be a valid date' | |
| }).nullable(), | |
| remarks: z.string() | |
| .min(1, 'Remarks are required') | |
| .max(500, 'Remarks must be 500 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Remarks cannot be empty or contain only spaces' | |
| }), | |
| }).refine(data => { | |
| // If both dates are provided, returned date must be after assigned date | |
| if (data.returnedDate && data.assignedDate) { | |
| return data.returnedDate > data.assignedDate; | |
| } | |
| return true; | |
| }, { | |
| message: 'Returned date must be after the assigned date', | |
| path: ['returnedDate'] | |
| }); | |
| /** | |
| * Zod schema for Asset Item validation | |
| */ | |
| export const AssetItemSchema = z.object({ | |
| itemID: z.number().int().positive().optional(), | |
| assetID: z.number().int().positive('Asset ID must be a positive number'), | |
| itemType: z.string() | |
| .min(1, 'Item type is required') | |
| .max(50, 'Item type must be 50 characters or less'), | |
| itemName: z.string() | |
| .min(1, 'Item name is required') | |
| .max(100, 'Item name must be 100 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Item name cannot be empty or contain only spaces' | |
| }), | |
| quantity: z.number().int().positive('Quantity must be a positive number').min(1, 'Quantity must be at least 1'), | |
| specifications: z.string() | |
| .min(1, 'Specifications are required') | |
| .max(200, 'Specifications must be 200 characters or less') | |
| .refine(val => val.trim().length > 0, { | |
| message: 'Specifications cannot be empty or contain only spaces' | |
| }), | |
| serialNumber: z.string() | |
| .max(50, 'Serial number must be 50 characters or less') | |
| .optional(), | |
| condition: z.enum(['Excellent', 'Good', 'Fair', 'Poor'], { | |
| errorMap: () => ({ message: 'Condition must be Excellent, Good, Fair, or Poor' }) | |
| }), | |
| notes: z.string() | |
| .max(500, 'Notes must be 500 characters or less') | |
| .optional(), | |
| addedDate: z.string().datetime('Added date must be in ISO 8601 format'), | |
| }); | |
| /** | |
| * Zod schema for Asset Item creation (excludes ID) | |
| */ | |
| export const AssetItemCreateSchema = AssetItemSchema.omit({ itemID: true }); | |
| /** | |
| * Zod schema for Asset Item updates (requires ID) | |
| */ | |
| export const AssetItemUpdateSchema = AssetItemSchema.required({ itemID: true }); | |
| // ============================================================================ | |
| // UTILITY TYPES AND INTERFACES | |
| // ============================================================================ | |
| /** | |
| * Generic API response wrapper | |
| */ | |
| export interface AssetManagementApiResponse<T> { | |
| success: boolean; | |
| data?: T; | |
| message?: string; | |
| error?: string; | |
| } | |
| /** | |
| * Extended Asset interface with related data for detailed views | |
| */ | |
| export interface AssetWithDetails extends Asset { | |
| systemDetails?: SystemDetails; | |
| assignments?: AssetAssignment[]; | |
| currentAssignment?: AssetAssignment; | |
| items?: AssetItem[]; | |
| } | |
| /** | |
| * Extended System Details interface with asset information | |
| */ | |
| export interface SystemDetailsWithAsset extends SystemDetails { | |
| asset?: Asset; | |
| } | |
| /** | |
| * Extended Asset Assignment interface with related entity information | |
| */ | |
| export interface AssetAssignmentWithDetails extends AssetAssignment { | |
| asset?: Asset; | |
| employeeEmail?: string; | |
| } | |
| /** | |
| * Filter options for asset listing | |
| */ | |
| export interface AssetFilter { | |
| assetType?: string; | |
| assetCondition?: AssetCondition; | |
| searchTerm?: string; | |
| assignmentStatus?: 'assigned' | 'unassigned' | 'all'; | |
| } | |
| /** | |
| * Sort options for asset listing | |
| */ | |
| export interface AssetSort { | |
| field: keyof Asset; | |
| direction: 'asc' | 'desc'; | |
| } | |
| /** | |
| * Pagination options | |
| */ | |
| export interface PaginationOptions { | |
| page: number; | |
| limit: number; | |
| } | |
| /** | |
| * Paginated response wrapper | |
| */ | |
| export interface PaginatedResponse<T> { | |
| data: T[]; | |
| total: number; | |
| page: number; | |
| limit: number; | |
| totalPages: number; | |
| } | |
| /** | |
| * Bulk import response interface | |
| */ | |
| export interface BulkImportResponse { | |
| success: boolean; | |
| message: string; | |
| results: { | |
| successful: number; | |
| failed: number; | |
| total: number; | |
| errors: ImportError[]; | |
| createdAssets: Asset[]; | |
| }; | |
| } | |
| /** | |
| * Import error interface for bulk operations | |
| */ | |
| export interface ImportError { | |
| index: number; | |
| asset: AssetCreateRequest; | |
| error: string; | |
| field?: string; | |
| } | |
| // ============================================================================ | |
| // TYPE GUARDS AND VALIDATION HELPERS | |
| // ============================================================================ | |
| /** | |
| * Type guard to check if an object is a valid Asset | |
| */ | |
| export function isAsset(obj: any): obj is Asset { | |
| return AssetSchema.safeParse(obj).success; | |
| } | |
| /** | |
| * Type guard to check if an object is a valid SystemDetails | |
| */ | |
| export function isSystemDetails(obj: any): obj is SystemDetails { | |
| return SystemDetailsSchema.safeParse(obj).success; | |
| } | |
| /** | |
| * Type guard to check if an object is a valid AssetAssignment | |
| */ | |
| export function isAssetAssignment(obj: any): obj is AssetAssignment { | |
| return AssetAssignmentSchema.safeParse(obj).success; | |
| } | |
| /** | |
| * Validates and transforms API response data to ensure type safety | |
| */ | |
| export function validateAssetApiResponse(data: any): Asset { | |
| // For API responses, we expect the ID to be present | |
| const schemaWithRequiredId = AssetSchema.required({ assetID: true }); | |
| const result = schemaWithRequiredId.safeParse(data); | |
| if (!result.success) { | |
| console.error('Asset validation failed:', result.error); | |
| throw new Error(`Invalid asset data: ${result.error.message}`); | |
| } | |
| return result.data as Asset; | |
| } | |
| /** | |
| * Validates and transforms System Details API response data | |
| */ | |
| export function validateSystemDetailsApiResponse(data: any): SystemDetails { | |
| // For API responses, we expect the ID to be present | |
| const schemaWithRequiredId = SystemDetailsSchema.required({ systemDetailsID: true }); | |
| const result = schemaWithRequiredId.safeParse(data); | |
| if (!result.success) { | |
| console.error('System Details validation failed:', result.error); | |
| throw new Error(`Invalid system details data: ${result.error.message}`); | |
| } | |
| return result.data as SystemDetails; | |
| } | |
| /** | |
| * Validates and transforms Asset Assignment API response data | |
| */ | |
| export function validateAssetAssignmentApiResponse(data: any): AssetAssignment { | |
| // For API responses, we expect the ID to be present | |
| const result = AssetAssignmentSchema.safeParse(data); | |
| if (!result.success) { | |
| console.error('Asset Assignment validation failed:', result.error); | |
| throw new Error(`Invalid asset assignment data: ${result.error.message}`); | |
| } | |
| return result.data as AssetAssignment; | |
| } | |
| // ============================================================================ | |
| // FORM VALIDATION HELPERS | |
| // ============================================================================ | |
| /** | |
| * Helper to get validation errors for Asset forms | |
| */ | |
| export function getAssetValidationErrors(data: any): Record<string, string> { | |
| const result = AssetSchema.safeParse(data); | |
| if (result.success) return {}; | |
| const errors: Record<string, string> = {}; | |
| result.error.errors.forEach(error => { | |
| const field = error.path.join('.'); | |
| errors[field] = error.message; | |
| }); | |
| return errors; | |
| } | |
| /** | |
| * Helper to get validation errors for System Details forms | |
| */ | |
| export function getSystemDetailsValidationErrors(data: any): Record<string, string> { | |
| const result = SystemDetailsSchema.safeParse(data); | |
| if (result.success) return {}; | |
| const errors: Record<string, string> = {}; | |
| result.error.errors.forEach(error => { | |
| const field = error.path.join('.'); | |
| errors[field] = error.message; | |
| }); | |
| return errors; | |
| } | |
| /** | |
| * Helper to get validation errors for Asset Assignment forms | |
| */ | |
| export function getAssetAssignmentValidationErrors(data: any): Record<string, string> { | |
| const result = AssetAssignmentSchema.safeParse(data); | |
| if (result.success) return {}; | |
| const errors: Record<string, string> = {}; | |
| result.error.errors.forEach(error => { | |
| const field = error.path.join('.'); | |
| errors[field] = error.message; | |
| }); | |
| return errors; | |
| } |