mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-09-08 06:35:44 +00:00
feat: add INSPECTION_FAILED state, enforce inspection scheduling locks, and improve adjustment round UI for section locking and remark labeling
This commit is contained in:
@@ -322,24 +322,44 @@ export function LicenseApplicationPage() {
|
||||
const isAdjusting = application?.status === "RESUBMIT_REQUIRED";
|
||||
const openRemarks = detail?.openRemarks ?? [];
|
||||
|
||||
// The whole round's remarks, resolved or not — the server's section lock
|
||||
// (`assertSectionUnlocked`) ignores `isResolved`, and this page bulk-resolves
|
||||
// remarks right before resubmitting, so `openRemarks` would re-freeze a
|
||||
// section the moment the applicant ticked it off.
|
||||
const roundRemarks = useMemo(
|
||||
() =>
|
||||
(detail?.remarks ?? []).filter(
|
||||
(r) => r.roundNumber === detail?.application?.adjustmentRound,
|
||||
),
|
||||
[detail?.remarks, detail?.application?.adjustmentRound],
|
||||
);
|
||||
|
||||
const flaggedSections = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
openRemarks
|
||||
roundRemarks
|
||||
.filter((r) => r.targetType === "FORM_SECTION")
|
||||
.map((r) => [r.targetKey, r.remark]),
|
||||
),
|
||||
[openRemarks],
|
||||
[roundRemarks],
|
||||
);
|
||||
const flaggedDocuments = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
openRemarks
|
||||
roundRemarks
|
||||
.filter((r) => r.targetType === "DOCUMENT")
|
||||
.map((r) => [r.targetKey, r.remark]),
|
||||
),
|
||||
[openRemarks],
|
||||
[roundRemarks],
|
||||
);
|
||||
const hasSectionRemarks = Object.keys(flaggedSections).length > 0;
|
||||
const hasDocRemarks = Object.keys(flaggedDocuments).length > 0;
|
||||
|
||||
// A round that flagged no form sections carries no section locks — mirror of
|
||||
// the server's fallback, without which a documents-only correction round
|
||||
// froze every field and the applicant could not edit anything at all.
|
||||
const isSectionLocked = (sectionKey: string) =>
|
||||
isAdjusting && hasSectionRemarks && !flaggedSections[sectionKey];
|
||||
|
||||
// Sections that share a group collapse onto one step, so the stepper stays
|
||||
// short instead of showing a page per section.
|
||||
@@ -383,6 +403,24 @@ export function LicenseApplicationPage() {
|
||||
// to the summary first.
|
||||
const showSummary = application.status !== "DRAFT" && viewingSummary;
|
||||
|
||||
// The applicant reads "Vessel Particulars", not "vesselParticulars" — and a
|
||||
// staff remark is keyed by a uuid, which reads as nothing at all.
|
||||
function remarkLabel(remark: (typeof openRemarks)[number]): string {
|
||||
if (remark.targetType === "FORM_SECTION") {
|
||||
const section = config?.licenseType.formSchema.sections.find(
|
||||
(s) => s.key === remark.targetKey,
|
||||
);
|
||||
return section ? localized(section.title) : remark.targetKey;
|
||||
}
|
||||
if (remark.targetType === "DOCUMENT") {
|
||||
const requirement = config?.documentRequirements.find(
|
||||
(r) => r.key === remark.targetKey,
|
||||
);
|
||||
return requirement ? localized(requirement.name) : remark.targetKey;
|
||||
}
|
||||
return t("licenseApplication.staffMember", "Staff member");
|
||||
}
|
||||
|
||||
// Vessel Information and Current Ownership are separate form sections, so
|
||||
// ConfigDrivenSection (one instance per section) can't fill both itself —
|
||||
// it reports the pick up here and this fans it out across every section.
|
||||
@@ -400,7 +438,7 @@ export function LicenseApplicationPage() {
|
||||
async function saveSection(sectionKey: string) {
|
||||
// During an adjustment round only flagged sections are editable, so don't
|
||||
// even attempt a write the server would reject.
|
||||
if (isAdjusting && !flaggedSections[sectionKey]) return;
|
||||
if (isSectionLocked(sectionKey)) return;
|
||||
const values = { ...(draft[sectionKey] ?? {}) };
|
||||
// The picker works in alpha-2 codes (CountrySelect); the backend, like
|
||||
// the profile Address endpoint, stores the full country name.
|
||||
@@ -679,7 +717,7 @@ export function LicenseApplicationPage() {
|
||||
<Stack gap={4}>
|
||||
{openRemarks.map((remark) => (
|
||||
<Text size="sm" key={remark.id}>
|
||||
<b>{remark.targetKey}</b>: {remark.remark}
|
||||
<b>{remarkLabel(remark)}</b>: {remark.remark}
|
||||
</Text>
|
||||
))}
|
||||
<Text size="xs" c="dimmed" mt={4}>
|
||||
@@ -741,7 +779,7 @@ export function LicenseApplicationPage() {
|
||||
{currentStep?.kind === "sections" && (
|
||||
<Stack gap="lg">
|
||||
{currentStep.sections.map((section, index) => {
|
||||
const locked = isAdjusting && !flaggedSections[section.key];
|
||||
const locked = isSectionLocked(section.key);
|
||||
return (
|
||||
<div key={section.key}>
|
||||
{index > 0 && <Divider mb="lg" />}
|
||||
@@ -899,7 +937,7 @@ export function LicenseApplicationPage() {
|
||||
ownerType="APPLICATION"
|
||||
ownerId={appId}
|
||||
flagged={flaggedDocuments}
|
||||
restrictToFlagged={isAdjusting}
|
||||
restrictToFlagged={isAdjusting && hasDocRemarks}
|
||||
readOnly={readOnly}
|
||||
onUploaded={() => {
|
||||
refetchAttachments();
|
||||
@@ -922,7 +960,10 @@ export function LicenseApplicationPage() {
|
||||
formData={draft}
|
||||
errors={fieldErrors}
|
||||
vessels={vessels}
|
||||
disabled={readOnly}
|
||||
// Same lock as the earlier steps — without it this step
|
||||
// looked editable during an adjustment round while
|
||||
// saveSection silently dropped the changes.
|
||||
disabled={readOnly || isSectionLocked(section.key)}
|
||||
onChange={(key, value) => {
|
||||
setDraft((prev) => ({
|
||||
...prev,
|
||||
|
||||
@@ -242,6 +242,7 @@ export const am: Translations = {
|
||||
RESUBMIT_REQUIRED: 'እንደገና ማስገባት ያስፈልጋል',
|
||||
INSPECTION_PENDING: 'ቁጥጥር በመጠባበቅ ላይ',
|
||||
INSPECTION_COMPLETED: 'ቁጥጥር ተጠናቋል',
|
||||
INSPECTION_FAILED: 'ቁጥጥር አልተሳካም',
|
||||
APPROVED: 'ጸድቋል',
|
||||
REJECTED: 'ውድቅ ተደርጓል',
|
||||
ON_HOLD: 'ላይ ቆሟል',
|
||||
|
||||
@@ -242,6 +242,7 @@ export const en = {
|
||||
RESUBMIT_REQUIRED: 'Resubmit Required',
|
||||
INSPECTION_PENDING: 'Inspection Pending',
|
||||
INSPECTION_COMPLETED: 'Inspection Completed',
|
||||
INSPECTION_FAILED: 'Inspection Failed',
|
||||
APPROVED: 'Approved',
|
||||
REJECTED: 'Rejected',
|
||||
ON_HOLD: 'On Hold',
|
||||
|
||||
Reference in New Issue
Block a user