import type { SeafarerRegistrationAnswers, SeafarerRegistrationStatus, } from './seafarer-registration.types'; /** * Option lists and labels shared by the portal wizard and the backoffice * review screen. Values are the server's enum members. */ export const GENDER_OPTIONS = [ { value: 'MALE', label: 'Male' }, { value: 'FEMALE', label: 'Female' }, ]; export const MARITAL_STATUS_OPTIONS = [ { value: 'SINGLE', label: 'Single' }, { value: 'MARRIED', label: 'Married' }, { value: 'DIVORCED', label: 'Divorced' }, { value: 'WIDOWED', label: 'Widowed' }, ]; export const DEPARTMENT_OPTIONS = [ { value: 'DECK', label: 'Deck' }, { value: 'ENGINE', label: 'Engine' }, { value: 'CATERING', label: 'Catering' }, ]; export const HAIR_COLOR_OPTIONS = [ { value: 'BLACK', label: 'Black' }, { value: 'BROWN', label: 'Brown' }, { value: 'BLONDE', label: 'Blonde' }, { value: 'RED', label: 'Red' }, { value: 'GREY', label: 'Grey' }, { value: 'WHITE', label: 'White' }, { value: 'BALD', label: 'Bald' }, { value: 'OTHER', label: 'Other' }, ]; export const EYE_COLOR_OPTIONS = [ { value: 'BROWN', label: 'Brown' }, { value: 'BLACK', label: 'Black' }, { value: 'BLUE', label: 'Blue' }, { value: 'GREEN', label: 'Green' }, { value: 'HAZEL', label: 'Hazel' }, { value: 'GREY', label: 'Grey' }, { value: 'OTHER', label: 'Other' }, ]; export const BLOOD_TYPE_OPTIONS = [ { value: 'A_POSITIVE', label: 'A+' }, { value: 'A_NEGATIVE', label: 'A−' }, { value: 'B_POSITIVE', label: 'B+' }, { value: 'B_NEGATIVE', label: 'B−' }, { value: 'AB_POSITIVE', label: 'AB+' }, { value: 'AB_NEGATIVE', label: 'AB−' }, { value: 'O_POSITIVE', label: 'O+' }, { value: 'O_NEGATIVE', label: 'O−' }, { value: 'UNKNOWN', label: 'Unknown' }, ]; /** Same plausibility bounds the API enforces (PHYSICAL_BOUNDS). */ export const PHYSICAL_BOUNDS = { heightCm: { min: 100, max: 250 }, weightKg: { min: 30, max: 250 }, } as const; /** Upload slots, keyed as the API's submission check expects them. */ export const SEAFARER_REGISTRATION_DOCUMENTS: { key: string; name: string; description?: string; /** `'passport'`: required only once a passport number is declared. */ required: boolean | 'passport'; accept?: string; }[] = [ { key: 'photo', name: 'Passport-size Photograph', description: 'Recent colour photograph with a plain background.', required: true, accept: 'image/jpeg,image/png', }, { key: 'nationalId', name: 'National ID (Fayda) or Kebele ID', required: true }, { key: 'passport', name: 'Passport Copy', required: 'passport' }, { key: 'graduation', name: 'Educational Certificate', required: false }, { key: 'medical_certificate', name: 'Medical Certificate', description: 'Your STCW medical fitness certificate. Must match the certificate details entered above.', required: true, }, { key: 'basic_training_evidence', name: 'Basic Training Evidence', description: 'One file containing evidence of all five basic training competencies: Personal Survival Techniques (PST), Fire Prevention and Fire Fighting (FPFF), Elementary First Aid (EFA), Personal Safety and Social Responsibility (PSSR), and Security Awareness.', required: true, }, ]; export const SEAFARER_REGISTRATION_STATUS_LABELS: Record = { DRAFT: 'Draft', SUBMITTED: 'Submitted', UNDER_REVIEW: 'Under Review', RESUBMIT_REQUIRED: 'Corrections Requested', APPROVED: 'Approved', REJECTED: 'Rejected', }; export const SEAFARER_REGISTRATION_STATUS_COLORS: Record = { DRAFT: 'gray', SUBMITTED: 'blue', UNDER_REVIEW: 'indigo', RESUBMIT_REQUIRED: 'orange', APPROVED: 'teal', REJECTED: 'red', }; /** Human label for each answer — the review table and the summary both use it. */ export const SEAFARER_REGISTRATION_FIELD_LABELS: Record = { firstName: 'First Name', middleName: 'Middle Name', lastName: 'Last Name', gender: 'Gender', dateOfBirth: 'Date of Birth', maritalStatus: 'Marital Status', nationality: 'Nationality', nationalIdNumber: 'National ID (Fayda) Number', placeOfBirth: 'Place of Birth', passportNumber: 'Passport Number', passportExpiry: 'Passport Expiry Date', department: 'Department', locationId: 'Location', permanentAddress: 'Permanent Address', currentAddress: 'Current Address', emergencyContactName: 'Full Name', emergencyContactRelationship: 'Relationship', emergencyContactPhone: 'Phone Number', hairColor: 'Hair Colour', eyeColor: 'Eye Colour', heightCm: 'Height (cm)', weightKg: 'Weight (kg)', bloodType: 'Blood Type', medicalCertificateNumber: 'Certificate Number', medicalIssuerName: 'Issuing Clinic or Practitioner', medicalIssueDate: 'Issue Date', declarationAccepted: 'Declaration', }; /** * The answers grouped the way the wizard asks them — the summary on the * portal and the review screen in the backoffice render the same sections. */ export const SEAFARER_REGISTRATION_SECTIONS: { key: string; title: string; fields: (keyof SeafarerRegistrationAnswers)[]; }[] = [ { key: 'identityDetails', title: 'Identity Details', fields: ['firstName', 'middleName', 'lastName', 'gender', 'dateOfBirth', 'maritalStatus', 'nationality', 'nationalIdNumber'], }, { key: 'identity', title: 'Identity', fields: ['placeOfBirth', 'passportNumber', 'passportExpiry', 'department'], }, { key: 'address', title: 'Address', fields: ['locationId', 'permanentAddress', 'currentAddress'], }, { key: 'physicalCharacteristics', title: 'Physical Characteristics', fields: ['hairColor', 'eyeColor', 'heightCm', 'weightKg', 'bloodType'], }, { key: 'medicalCertificate', title: 'Medical Certificate', fields: ['medicalCertificateNumber', 'medicalIssuerName', 'medicalIssueDate'], }, { key: 'emergencyContact', title: 'Emergency Contact', fields: ['emergencyContactName', 'emergencyContactRelationship', 'emergencyContactPhone'], }, ]; const OPTION_LABELS: Partial> = { gender: GENDER_OPTIONS, maritalStatus: MARITAL_STATUS_OPTIONS, department: DEPARTMENT_OPTIONS, hairColor: HAIR_COLOR_OPTIONS, eyeColor: EYE_COLOR_OPTIONS, bloodType: BLOOD_TYPE_OPTIONS, }; /** Display value for one answer: option label for enums, "—" when blank. */ export function displaySeafarerAnswer( field: keyof SeafarerRegistrationAnswers, value: unknown, ): string { if (value === null || value === undefined || value === '') return '—'; if (typeof value === 'boolean') return value ? 'Yes' : 'No'; const options = OPTION_LABELS[field]; if (options) return options.find((o) => o.value === value)?.label ?? String(value); return String(value); }