diff --git a/apps/backoffice/src/app/features/certificate-requirements/components/ConditionBuilder.tsx b/apps/backoffice/src/app/features/certificate-requirements/components/ConditionBuilder.tsx index b1192fca2..7c016bd76 100644 --- a/apps/backoffice/src/app/features/certificate-requirements/components/ConditionBuilder.tsx +++ b/apps/backoffice/src/app/features/certificate-requirements/components/ConditionBuilder.tsx @@ -198,7 +198,7 @@ function ConditionArmFields({ fz="xs" px={6} py={2} - bg="var(--mantine-color-gray-1)" + bg="var(--mantine-color-default-hover)" style={{ borderRadius: 4, cursor: 'pointer' }} onClick={() => setInValues((value.in ?? []).filter((_, idx) => idx !== i).map(String))} title={t('certReq.condition.removeValue', 'Click to remove')} diff --git a/apps/backoffice/src/app/features/certificate-requirements/components/DocumentRequirementsTab.tsx b/apps/backoffice/src/app/features/certificate-requirements/components/DocumentRequirementsTab.tsx index 05680009d..033795186 100644 --- a/apps/backoffice/src/app/features/certificate-requirements/components/DocumentRequirementsTab.tsx +++ b/apps/backoffice/src/app/features/certificate-requirements/components/DocumentRequirementsTab.tsx @@ -127,7 +127,7 @@ export function DocumentRequirementsTab({ licenseType }: { licenseType: LicenseT ) : ( {rows.map((req) => ( - +
diff --git a/apps/backoffice/src/app/features/certificate-requirements/components/FormSchemaTab.tsx b/apps/backoffice/src/app/features/certificate-requirements/components/FormSchemaTab.tsx index ddeb712f1..f103b43d4 100644 --- a/apps/backoffice/src/app/features/certificate-requirements/components/FormSchemaTab.tsx +++ b/apps/backoffice/src/app/features/certificate-requirements/components/FormSchemaTab.tsx @@ -209,7 +209,7 @@ export function FormSchemaTab({ licenseType }: { licenseType: LicenseType }) { - +
{localized(section.title) || section.key} @@ -237,7 +237,7 @@ export function FormSchemaTab({ licenseType }: { licenseType: LicenseType }) { {section.fields.map((field, fIndex) => ( - +
diff --git a/apps/backoffice/src/app/features/license-review/pages/LicenseReviewPage/index.tsx b/apps/backoffice/src/app/features/license-review/pages/LicenseReviewPage/index.tsx index 1977689ae..3c5b8f2f1 100644 --- a/apps/backoffice/src/app/features/license-review/pages/LicenseReviewPage/index.tsx +++ b/apps/backoffice/src/app/features/license-review/pages/LicenseReviewPage/index.tsx @@ -1214,18 +1214,6 @@ export function LicenseReviewPage() { - {status === "INSPECTION_FAILED" && ( - } - > - {t( - "review.inspectionFailedBlocked", - "Approval is unavailable because the inspection failed. Schedule a re-inspection, request corrections, or reject the application.", - )} - - )} {inspections.length === 0 ? ( @@ -1281,6 +1269,18 @@ export function LicenseReviewPage() { + {/* Page-level, not inside the inspection tab: a license type + configured without an inspection detail section must still show + why approval is blocked if it ever lands here. */} + {status === "INSPECTION_FAILED" && ( + }> + {t( + "review.inspectionFailedBlocked", + "Approval is unavailable because the inspection failed. Schedule a re-inspection, request corrections, or reject the application.", + )} + + )} + {status === "PAYMENT_PENDING" && ( 0; - const hasDocRemarks = Object.keys(flaggedDocuments).length > 0; + const hasStaffRemarks = roundRemarks.some((r) => r.targetType === "STAFF"); + // Nothing at all came back for this round (a detail response that predates + // the remarks, say) — lock nothing rather than freeze the whole application + // with no way forward. Any remark present means the round is itemised, so + // only what the officer flagged opens: a documents-only round leaves every + // form section frozen, and a sections-only round leaves every document as + // filed. + const roundIsItemised = isAdjusting && roundRemarks.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]; + roundIsItemised && !flaggedSections[sectionKey]; + const staffLocked = roundIsItemised && !hasStaffRemarks; // Sections that share a group collapse onto one step, so the stepper stays // short instead of showing a page per section. @@ -862,7 +866,7 @@ export function LicenseApplicationPage() { complete )} - {!readOnly && ( + {!readOnly && !staffLocked && (
- {!readOnly && ( + {!readOnly && !staffLocked && (
@@ -937,7 +941,7 @@ export function LicenseApplicationPage() { ownerType="APPLICATION" ownerId={appId} flagged={flaggedDocuments} - restrictToFlagged={isAdjusting && hasDocRemarks} + restrictToFlagged={roundIsItemised} readOnly={readOnly} onUploaded={() => { refetchAttachments(); diff --git a/libs/api/src/lib/features/seafarer-registration/seafarer-registration-api.ts b/libs/api/src/lib/features/seafarer-registration/seafarer-registration-api.ts index 4b42681eb..87f5fef15 100644 --- a/libs/api/src/lib/features/seafarer-registration/seafarer-registration-api.ts +++ b/libs/api/src/lib/features/seafarer-registration/seafarer-registration-api.ts @@ -10,9 +10,17 @@ const TAG = 'SeafarerRegistration' as const; const LIST = { type: TAG, id: 'LIST' } as const; const item = (id: string) => ({ type: TAG, id }) as const; +export type SeafarerRegistrationSortField = + | 'submittedAt' + | 'registrationNumber' + | 'lastName' + | 'status'; + export interface SeafarerRegistrationListFilter { status?: SeafarerRegistrationStatus; search?: string; + sortBy?: SeafarerRegistrationSortField; + sortDir?: 'ASC' | 'DESC'; take?: number; skip?: number; }