The two apps had drifted into unrelated themes. The portal's carried a full
type scale, radius scale, shadow ramp and component defaults; the backoffice's
had none of them — 55 lines defining two colour ramps and little else. With
nothing to inherit, its 23 features each invented their own sizing, which is
the real source of the inconsistency the UI reads with.
Promote the portal's structure to `libs/shared` as `baseTheme`, and reduce both
themes to what they should differ on: brand. The backoffice keeps #1e40af and
the portal keeps Coastal Modern — a distinct accent tells an officer which of
the two systems they are in, and the ramps are not interchangeable in contrast.
Both export names are preserved, so no consumer import changes.
Two properties are deliberately held back rather than shared:
- `colors.gray`: the portal's blue-tinted neutrals retint every dimmed label,
neutral badge and table border. The backoffice adopts them as its own
reviewed change, not as a side effect of sharing a base.
- `primaryShade.dark`: moves every filled control in dark mode; waits until
dark mode is verified end to end.
Also fixes a live bug: PageLoader coloured its primary label `navy.9`, which is
defined in neither theme. Mantine drops unresolved colour keys silently, so the
label in a component used by 20 files had been rendering an inherited colour.
Adds a visual-regression harness to make all of this reviewable. It runs
against a static gallery route rather than real pages, so it needs no API,
database or auth — a theme diff cannot be masked by a migration or an expired
token. The portal is the control group: it is pixel-identical across all four
light/dark × desktop/tablet baselines, which is what makes the refactor
provably lossless.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Implement DocumentRequirementsTab for managing document upload requirements.
- Create FieldEditorDrawer and SectionEditorDrawer for editing fields and sections in the form schema.
- Develop FormSchemaTab to handle sections and fields for a license type's form schema.
- Introduce CertificateRequirementsPage to serve as the main interface for configuring license type requirements.
- Add hooks for requirement actions to streamline mutation handling and notifications.
- Implement condition handling for fields and sections to manage visibility based on user input.
- Create schema-paths configuration to facilitate condition target collection.
- Refactor ExamStageActions component to handle eligibility payment and retake exam actions.
- Update MyApplicationsPage to use new retakeExam mutation instead of requestExamPayment.
- Modify licensing API to include retakeExam mutation for handling exam fee requests for failed candidates.
- Adjust mock data to reflect new application statuses and ensure consistency in eligibility and exam payment states.
- Update licensing helpers to include new status labels and colors for eligibility payment states.
- Revise licensing types to replace ELIGIBILITY_APPROVED with ELIGIBILITY_PAYMENT_PENDING and ELIGIBILITY_PAID for clarity in application status flow.
- Split MedicalVerificationPage into MedicalVerificationPage and SeaServiceVerificationPage for better separation of concerns.
- Update navigation to include separate entries for Sea Service Verification and Medical Verification.
- Enhance sea service columns to display additional vessel information and days served.
- Add translations for new and updated labels in both English and Amharic.
- Introduce seaServiceDays helper function to calculate days served based on engagement and discharge dates.
- Remove deprecated MedicalCertificatePage from the portal.
- Update routing to direct to the new sea service and medical pages.
- Remove SeamanBookApplicationPage from router and redirect to Seaman Book page.
- Add new API endpoints for managing seafarer documents, including listing, reviewing, and issuing documents.
- Introduce new SeafarerDocumentQueuePage and SeafarerDocumentReviewPage components for document management.
- Update licensing types to accommodate optional applicationId and documentId in ApplicationPayment.
- Remove unused claimSeafarerRegistration mutation and related constants.
- Update seafarer registration status labels and types to remove 'UNDER_REVIEW'.
- Create new constants and types for seafarer documents, including status labels and colors.
- Implement document payment initiation and confirmation functionalities.
- Enhance UI components for better user experience in document management.
- Implemented SeafarerRegistrationPage component with five-step registration process.
- Added API endpoints for seafarer registration including start, save, and submit functionalities.
- Created necessary types and constants for seafarer registration.
- Updated router to include new registration paths and permissions.
- Integrated profile defaults to pre-fill registration fields where applicable.
- Added validation and error handling for registration steps.
- Enhanced document upload functionality specific to seafarer registration.
- Updated imports for better readability in LicenseApplicationPage.
- Introduced legacy profile sources for backward compatibility in LicenseApplicationPage.
- Enhanced user profile handling by utilizing accountUser in LicenseApplicationPage.
- Improved application state management in LicenseApplicationPage to include accountUser.
- Refactored RequireSeafarerProfile to check for existing applications and handle navigation accordingly.
- Cleaned up navigation items in PortalLayout for better readability and maintainability.
body had its own 40px padding + max-width:800px for the on-screen preview
tab, which stacked with @page's own margin once actual printing kicked in
— the preview tab never shows @page at all, so it looked like one
continuous page while the real printed output wasted ~150px+ of page
height per side and was capped to 800px wide regardless of the physical
page width. In @media print specifically: padding:0, max-width:none —
@page's margin is the only inset that should apply once printing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Footer was just the last thing in document flow, so on a short paper it
landed mid-page instead of at the bottom. position:fixed in @media print
(the standard trick for a repeating page footer) plus a matching @page
bottom margin so it never overlaps the last question's text.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Matches the new backend rule. Field caps at 100 and shows a hint the
moment Percentage is selected, instead of letting you type 150 and only
finding out later.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Create a CHOICE question and the options fields were hidden behind a
'save first' message — had to save, then reopen via Edit, to actually add
options. Added an inline options editor (local state, same bilingual
fields/correct-checkbox as the existing edit-mode one) directly in the
create form. On submit: create the question, then immediately call
setOptions with the drafted options using the new question's id — one
action from the user's point of view, two API calls under the hood.
Edit mode is unchanged, still uses the existing QuestionOptionsEditor
against the real question id.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two follow-ups on the dropdown-actions pass:
- All four action menus (exams, results, questions, candidates panel) now
trigger off a plain three-dot icon button instead of a text 'Actions'
button with a chevron.
- Exam status change no longer lists all six statuses flat in the dropdown
(bad UX, looked like six always-visible options). 'Status' is now one
menu item that opens a small picker modal (current status + a Select +
Update) rather than the full edit form.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same treatment as the questions table, applied consistently: exams list,
exam results list, and the exam-detail candidates panel all now show a
single Actions button opening a dropdown instead of a row of inline
buttons/icons. Also fixes the exams list's action column header, which was
rendering the literal untranslated key ('exam.columns.actions') — missing
a fallback string, same pattern already used elsewhere in this file.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Matches the exams table's action pattern — a single Actions button opening
a menu, instead of a row of inline buttons/icons that got crowded once a
question had submit/approve/reject/retire/edit/delete all applicable at
once.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>