The COC detail page read the application status alone, so a candidate who had
registered, been marked present, sat the paper and had a PASSED mark published
still appeared to be awaiting an exam — and the officer was offered "Schedule
exam" and "Record exam result" for work already done.
ExamStatePanel reads GET /exams/applications/:id/state, which the server
derives from the registration, the attempt and the published mark. Session,
date and admission number while the exam is ahead; score, outcome and whether
the exam engine or an examiner produced the mark once it is settled. Polled,
because attendance is recorded and papers are marked while the officer has the
page open. Same derivation the applicant's portal reads, so the two cannot
disagree.
The eligible-exams query, the scheduling mutation and the outcome mutation are
gone from the RTK layer along with the endpoints behind them.
Four screens were telling the applicant things that were not true, and two
back-office actions were writing state nobody should be able to write by hand.
The exam form is a stepper. Basic Info and Settings each answer only for their
own fields, and a third step reviews the whole thing before anything is sent —
"Create Exam" exists on that step alone, so there is no path from an earlier
one into the API. Clicking it from Basic Info used to report the Settings
fields as missing: a correct error the user could not act on, since that step
had not been shown yet. The rules move to ./validation, which is what the
per-step check and the final whole-payload check both read, so the two cannot
drift apart. Back keeps everything entered — state lives in the component.
The portal derives the examination stage from the records rather than from the
application status alone. Registering, attendance and the sitting itself all
happen on the registration and the attempt, and the portal read none of them —
which is how an application still said "Awaiting Exam Date" after the back
office had already evaluated the paper. examStageFor() names what the records
add up to: eligible to register, registered, attendance confirmed, sitting,
under evaluation, passed, failed. Both the applications list and the
certificates page use it, and both poll the registrations they read it from,
because attendance is recorded by an invigilator while the candidate is
watching the screen.
EXAM_PAID is no longer a waiting state. Nobody assigns a date: the fee having
cleared is exactly what makes the candidate eligible to pick a published
sitting, so that row now offers Register rather than a disabled button.
Schedule Exam and Record Exam Outcome are gone from the COC queue — actions,
modals, RTK endpoints and strings. Their server endpoints are gone too, so
this is not a hidden button over a live route.
- Implemented MySignaturePad component for officers to draw and upload their signatures.
- Added signature API endpoints for managing officer signatures in the backoffice.
- Created SignaturePad component for seafarers to manage their specimen signatures.
- Updated ProfilePage to include signature tabs for both officers and seafarers.
- Added translations for signature-related terms in English and Amharic.
- Introduced RankTier options for seafarer registration.
- Added tests for canvas-point utility to ensure accurate pointer mapping on signature pad.
Resolves conflicts:
- LicenseReviewPage: dropped a duplicated schedule-issuance ActionIcon,
keeping the Tooltip-wrapped one and adding scheduledPeriod (required
by the scheduleIssuance mutation) to it.
- portal i18n (en.ts/am.ts): both sides added distinct keys under
licensing.card (reportDamaged/reissueFailed vs status/statusReason) —
kept both, additive.
- licensing.helpers.ts: kept sectionAppliesToKind (this branch) and
switched to the centralized BASE_API_URL import from
base-api/base-query-with-reauth (WorkflowChange), dropping the local
duplicate constant.
- Introduced new pickup appointment functionalities in the licensing API, including scheduling, rescheduling, and managing pickup offices.
- Added UI components for the pickup desk, allowing officers to check in, issue documents, and manage no-show appointments.
- Implemented a new page for managing pickup offices with CRUD operations.
- Enhanced internationalization support for new pickup-related terms and messages.
- Updated licensing types to include new application kinds and issuance periods.
- Created a read-only panel for displaying scheduled pickup appointments in the licensing component.
refactor(i18n): remove 'assignReviewer' translation key from Amharic and English locales
refactor(nav-config): clean up navigation configuration by removing redundant items
refactor(licensing-api): remove assignReviewer mutation from licensing API
feat(package): add build script for parallel building of portal and backoffice