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.
The verify step now returns an encrypted verificationToken alongside the
readable identity. After the existing signup succeeds, the page posts it to
POST /profiles/me/fayda, which marks the phone verified when it is the one
Fayda vouched for and fills the still-empty profile fields. Best-effort: the
account already works if the call fails, and the token can be presented again.
When the server confirms the phone, the page goes straight to the portal
instead of /otp-verify — Fayda already verified that exact number with its own
OTP, and asking for a second one on the same number is theatre. An applicant
who edited the prefilled number still gets the normal OTP step.
The registrations table mirrored the server's old attendance deny-list —
ABSENT/WITHDRAWN/DISQUALIFIED — so the default REGISTERED fell through and
"Take exam" appeared before any invigilator had confirmed the candidate was
there. It is an allow-list now, PRESENT and LATE only, matching
ExamAttemptService.MAY_SIT.
A blocked candidate gets a reason rather than an empty cell: "Awaiting
attendance" with a tooltip while nobody has called the register, "Not sitting"
once attendance was taken and they are not. useExamAttempt does the same for
the direct-link path, and translates attendance_not_confirmed /
candidate_not_present instead of showing a raw error key on a Start button
that cannot work. The server refuses either way — this only makes the refusal
legible.
ScheduleExamModal no longer promises an admission number: scheduling makes a
sitting available, and the candidate registers for it themselves.