This commit is contained in:
Estifo77
2026-08-19 10:23:57 +03:00
parent c377ddf74a
commit 0832e5d339
2 changed files with 36 additions and 29 deletions

View File

@@ -26,12 +26,8 @@ export const SEAFARER_PROFILE_REQUIREMENT: ProfileRequirement = {
"primaryPhoneNumber",
"email",
],
// Translation key, not literal text — `ProfileRequirementGate` runs it
// through `t()` at render time (it can't be translated here: this object
// is built at module scope, before any component or `useTranslation` call
// exists). Reuses `profileGate.seafarerReason`, the same sentence already
// shown by the seafarer-redirect toast below.
reason: 'profileGate.seafarerReason',
reason:
"Seafarer registration is built from your profile — these details fill it in for you.",
};
const REGISTRATION_TYPE_KEY = "SEAFARER_REGISTRATION";
@@ -70,32 +66,41 @@ export function RequireSeafarerProfile({
if (!gated) return <>{children}</>;
if (isLoading) {
return <PageLoader label={t('profileGate.checkingProfile')} height={350} />;
return (
<Center h={200}>
<Loader />
</Center>
);
}
// Already registered: the number is permanent and the server now refuses a
// second registration outright (409 seafarer_already_registered). Sending
// them on beats opening a wizard whose first act — creating the draft — is
// the call that fails. Checked after the loading guard so an unresolved
// profile is never read as "not registered".
if (profile?.seafarerNumber) {
return <Navigate to="/seaman-book" replace />;
// The number is permanent and the server refuses a second registration.
// Keep the registration tab useful by opening the completed application in
// its read-only summary instead.
if (registered) {
if (loadingApplications) {
return (
<Center h={200}>
<Loader />
</Center>
);
}
const registration = applications?.items.find(
(application) => application.licenseType?.key === REGISTRATION_TYPE_KEY,
);
if (registration) {
return (
<Navigate
to={`/licensing/${REGISTRATION_TYPE_KEY}/applications/${registration.id}`}
replace
/>
);
}
}
// A failed lookup must not lock anyone out — the server still refuses the
// application for a profile it can't fill in from.
// A failed lookup must not lock anyone out — an unreadable profile says
// nothing about whether this applicant is already registered, and the
// server refuses a duplicate registration regardless.
if (error) return <>{children}</>;
if (gaps.length === 0) return <>{children}</>;
// Gaps while a save is still landing are not an answer yet. Saving a
// profile tab invalidates this query and the applicant may already be
// headed back here in the same tick — deciding on the pre-save cache would
// bounce them off the screen they just finished.
if (isFetching) {
return <PageLoader label={t('profileGate.checkingProfile')} height={350} />;
}
const target = PROFILE_FIELD_SECTION[gaps[0]];
return <Navigate to={`/profile#${target}`} replace />;
}
return <>{children}</>;
}

View File

@@ -286,9 +286,11 @@ export const am: Translations = {
addDetails: 'እነዚህን መረጃዎች ጨምር',
viewProfile: 'ሙሉ መገለጫ ይመልከቱ',
seafarerReason: 'የባህረኞች ምዝገባ የሚዘጋጀው ከመገለጫዎ ነው — እነዚህ መረጃዎች ራሱ ይሞላሉ።',
checkingProfile: 'የባህረኛ መገለጫ በመፈተሽ ላይ…',
seafarerBanner:
'የባህረኛ ምዝገባ እነዚህን መረጃዎች ይጠይቃል፤ ከጸደቀ በኋላም መገለጫዎን ያዘምናል። እዚህ አስቀድመው ቢሞሏቸው እዚያ እንደገና መተየብ አይኖርብዎትም።',
},
profileSections: {
personal: 'የግል መረጃ',