Skip to content

Commit 67ac97c

Browse files
Refactor vessel error handling and input identifiers for improved usability
1 parent dd7f289 commit 67ac97c

8 files changed

Lines changed: 84 additions & 81 deletions

app/.server/directLanding.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,16 @@ const transformError = (
171171
},
172172
};
173173
} else if (errorKey === "vessel.vesselName") {
174+
// FI0-11239: DAC_Error_Focus_Usability_02 (AAA)
175+
const vesselNameErrorKey = errorKey.replaceAll(".", "-");
174176
// FIO-10474: Handle vessel errors separately without date-related params
175177
return {
176-
[errorKey]: {
178+
[vesselNameErrorKey]: {
177179
key: errors[errorKey],
178180
},
179181
};
180182
} else if (errorKey.includes("exportWeight")) {
181-
const index: number = parseInt(errorKey.split(".")[1]);
183+
const index: number = Number.parseInt(errorKey.split(".")[1]);
182184
const product = products.items[index].product;
183185

184186
return {

app/.server/manualEntryLanding.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ const onAddLandingResponse = async (
204204
case 200:
205205
case 204:
206206
return await response.json();
207-
case 400:
207+
case 400: {
208208
const errorsResponse = await response.json();
209209
const products: ProductLanded[] = errorsResponse?.items ?? [];
210210
const product: string =
@@ -228,7 +228,7 @@ const onAddLandingResponse = async (
228228
}
229229

230230
return {
231-
key: error,
231+
key: error === "vessel.vesselName" ? error.replaceAll(".", "-") : error,
232232
message: getErrorMessage(messageKey),
233233
...(messageKey === "error.dateLanded.date.max" && {
234234
value: { dynamicValue: getEnv().LANDING_LIMIT_DAYS_FUTURE },
@@ -242,6 +242,7 @@ const onAddLandingResponse = async (
242242
};
243243
}),
244244
};
245+
}
245246
case 403:
246247
return {
247248
unauthorised: true,

app/helpers/lookupErrorText.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ export const getTransformedError = (errors: IError[], vesselInput?: string): IEr
471471
// Vessel fallback: if error is 'ccAddLandingVesselNameUnpopulatedError' but vessel field is not empty, show 'ccAddLandingSelectVesselListNullError'
472472
let errorMessage = error.message;
473473
if (
474-
errorKey === "vessel.vesselName" &&
474+
errorKey === "vessel-vesselName" &&
475475
error.message === "ccAddLandingVesselNameUnpopulatedError" &&
476476
vesselInput !== undefined &&
477477
vesselInput.trim() !== ""

app/routes/create-catch-certificate.$documentNumber.add-landings.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ const hasMaxLandingExceeded = (errors: any, maxLandingExceeded: boolean) => {
112112
};
113113
}
114114
};
115-
const getVesselClassName = (errors: any) => errors["vessel.vesselName"] ?? "";
115+
const getVesselClassName = (errors: any) => errors["vessel-vesselName"] ?? "";
116116

117117
const intialProcessedValues = (
118118
values: Pick<AddLandingsType, "gearCategory" | "availableGearTypes" | "gearType" | "selectedRfmo">
@@ -397,7 +397,7 @@ const AddLandings = () => {
397397
"eez.2",
398398
"eez.3",
399399
"eez.4",
400-
"vessel.vesselName",
400+
"vessel-vesselName",
401401
"exportWeight",
402402
"gearCategory",
403403
"gearType",
@@ -602,11 +602,11 @@ const AddLandings = () => {
602602
rfmos={rfmos}
603603
/>
604604
<AutocompleteFormField
605-
id="vessel.vesselName"
605+
id="vessel-vesselName"
606606
name="vessel"
607607
errorMessageText={
608-
errors["vessel.vesselName"]?.message
609-
? t(errors["vessel.vesselName"].message, { ns: "errorsText" })
608+
errors["vessel-vesselName"]?.message
609+
? t(errors["vessel-vesselName"].message, { ns: "errorsText" })
610610
: ""
611611
}
612612
defaultValue={values.vessel ?? selectedVessel ?? ""}
@@ -626,7 +626,7 @@ const AddLandings = () => {
626626
labelText={t("ccAddLandingVesselNameLabel", { ns: "directLandings" })}
627627
hintText={t("ccAddLandingVesselNameHint", { ns: "directLandings" })}
628628
containerClassName={
629-
isEmpty(errors["vessel.vesselName"])
629+
isEmpty(errors["vessel-vesselName"])
630630
? "govuk-form-group govuk-!-width-one-half"
631631
: "govuk-form-group govuk-!-width-one-half govuk-form-group--error"
632632
}
@@ -635,9 +635,9 @@ const AddLandings = () => {
635635
selectClassName: vesselClassName,
636636
}}
637637
inputProps={{
638-
id: "vessel.vesselName",
638+
id: "vessel-vesselName",
639639
className: vesselClassName,
640-
"aria-describedby": "vessel.vesselName-hint",
640+
"aria-describedby": "vessel-vesselName-hint",
641641
}}
642642
onChange={enableChange ? handleVesselChange : undefined}
643643
onSelected={handleVesselSelected}

app/routes/create-catch-certificate.$documentNumber.direct-landing.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ const DirectLanding = () => {
160160

161161
// vessel input
162162
const getVesselErrorText = () => {
163-
const vesselNameError = errors?.["vessel.vesselName"]?.message ?? "";
163+
const vesselNameError = errors?.["vessel-vesselName"]?.message ?? "";
164164
const vesselIsListedError = errors?.["vessel.isListed"]?.message ?? "";
165165
const error = vesselNameError || vesselIsListedError;
166166
return isEmpty(error) ? "" : t(error, { ns: "errorsText" });
@@ -292,10 +292,10 @@ const DirectLanding = () => {
292292
const faoValue = normalize(faoArea) ?? normalize(directLandings?.faoArea) ?? "FAO27";
293293
const { "vessel.isListed": isListedError, ...restErrors } = errors;
294294
const errorsForSummary =
295-
isListedError && !restErrors["vessel.vesselName"]
295+
isListedError && !restErrors["vessel-vesselName"]
296296
? {
297297
...restErrors,
298-
"vessel.vesselName": { ...isListedError, fieldId: "vessel.vesselName-error", key: "vessel.vesselName" },
298+
"vessel-vesselName": { ...isListedError, fieldId: "vessel-vesselName-error", key: "vessel-vesselName" },
299299
}
300300
: restErrors;
301301

@@ -317,7 +317,7 @@ const DirectLanding = () => {
317317
"eez.2",
318318
"eez.3",
319319
"eez.4",
320-
"vessel.vesselName",
320+
"vessel-vesselName",
321321
"gearCategory",
322322
"gearType",
323323
"weight",
@@ -425,7 +425,7 @@ const DirectLanding = () => {
425425
rfmoHelpSectionContentTwoLink={t("ccRfmoHelpSectionContentTwoLink")}
426426
/>
427427
<AutocompleteFormField
428-
id="vessel.vesselName"
428+
id="vessel-vesselName"
429429
name="vessel"
430430
errorMessageText={getVesselErrorText()}
431431
defaultValue={values?.vessels ?? vesselSelected ?? ""}
@@ -445,16 +445,16 @@ const DirectLanding = () => {
445445
}}
446446
containerClassName={classNames("govuk-form-group", "govuk-!-width-one-half", {
447447
"govuk-form-group--error":
448-
!isEmpty(errors["vessel.vesselName"]) || !isEmpty(errors["vessel.isListed"]),
448+
!isEmpty(errors["vessel-vesselName"]) || !isEmpty(errors["vessel.isListed"]),
449449
})}
450450
selectProps={{
451451
selectClassName: classNames("govuk-select", {
452-
"govuk-select--error": !isEmpty(errors["vessel.vesselName"]) || !isEmpty(errors["vessel.isListed"]),
452+
"govuk-select--error": !isEmpty(errors["vessel-vesselName"]) || !isEmpty(errors["vessel.isListed"]),
453453
}),
454454
}}
455455
inputProps={{
456456
className: classNames("govuk-input", {
457-
"govuk-input--error": !isEmpty(errors["vessel.vesselName"]) || !isEmpty(errors["vessel.isListed"]),
457+
"govuk-input--error": !isEmpty(errors["vessel-vesselName"]) || !isEmpty(errors["vessel.isListed"]),
458458
}),
459459
}}
460460
onChange={enableChange ? handleVesselChange : undefined}

tests/cypress/integration/helpers/lookupErrorText.spec.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ describe("lookupErrorText helpers", () => {
1414
message: "ccAddLandingForProductError",
1515
},
1616
{
17-
key: "vessel.vesselName",
17+
key: "vessel-vesselName",
1818
message: "ccAddVesselFormVesselNameError",
1919
},
2020
];
@@ -28,39 +28,39 @@ describe("lookupErrorText helpers", () => {
2828
value: undefined,
2929
fieldId: "product-error",
3030
},
31-
"vessel.vesselName": {
32-
key: "vessel.vesselName",
31+
"vessel-vesselName": {
32+
key: "vessel-vesselName",
3333
message: "ccAddVesselFormVesselNameError",
3434
value: undefined,
35-
fieldId: "vessel.vesselName-error",
35+
fieldId: "vessel-vesselName-error",
3636
},
3737
});
3838
});
3939

4040
it("should show 'select from list' error when vessel input is non-empty but vessel is not found", () => {
4141
const errors: IError[] = [
4242
{
43-
key: "vessel.vesselName",
43+
key: "vessel-vesselName",
4444
message: "ccAddLandingVesselNameUnpopulatedError",
4545
},
4646
];
4747

4848
const result = getTransformedError(errors, "INVALID123");
4949

50-
expect(result["vessel.vesselName"].message).to.equal("ccAddLandingSelectVesselListNullError");
50+
expect(result["vessel-vesselName"].message).to.equal("ccAddLandingSelectVesselListNullError");
5151
});
5252

5353
it("should keep 'unpopulated' error when vessel input is empty", () => {
5454
const errors: IError[] = [
5555
{
56-
key: "vessel.vesselName",
56+
key: "vessel-vesselName",
5757
message: "ccAddLandingVesselNameUnpopulatedError",
5858
},
5959
];
6060

6161
const result = getTransformedError(errors, "");
6262

63-
expect(result["vessel.vesselName"].message).to.equal("ccAddLandingVesselNameUnpopulatedError");
63+
expect(result["vessel-vesselName"].message).to.equal("ccAddLandingVesselNameUnpopulatedError");
6464
});
6565

6666
it("should include error values when provided", () => {
@@ -91,10 +91,10 @@ describe("lookupErrorText helpers", () => {
9191
describe("displayErrorMessagesInOrder", () => {
9292
it("should return errors in the specified order", () => {
9393
const errors: IErrorsTransformed = {
94-
"vessel.vesselName": {
95-
key: "vessel.vesselName",
94+
"vessel-vesselName": {
95+
key: "vessel-vesselName",
9696
message: "ccAddVesselFormVesselNameError",
97-
fieldId: "vessel.vesselName-error",
97+
fieldId: "vessel-vesselName-error",
9898
},
9999
product: {
100100
key: "product",
@@ -108,14 +108,14 @@ describe("lookupErrorText helpers", () => {
108108
},
109109
};
110110

111-
const errorKeysInOrder = ["product", "dateLanded", "vessel.vesselName"];
111+
const errorKeysInOrder = ["product", "dateLanded", "vessel-vesselName"];
112112

113113
const result = displayErrorMessagesInOrder(errors, errorKeysInOrder);
114114

115115
expect(result).to.have.length(3);
116116
expect(result[0].key).to.equal("product");
117117
expect(result[1].key).to.equal("dateLanded");
118-
expect(result[2].key).to.equal("vessel.vesselName");
118+
expect(result[2].key).to.equal("vessel-vesselName");
119119
});
120120

121121
it("should handle errors with the same prefix (e.g., multiple products)", () => {
@@ -276,7 +276,7 @@ describe("lookupErrorText helpers", () => {
276276
"eez.2",
277277
"eez.3",
278278
"eez.4",
279-
"vessel.vesselName",
279+
"vessel-vesselName",
280280
"exportWeight",
281281
"gearCategory",
282282
"gearType",

tests/cypress/integration/routes/addLandings.spec.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const verifyLandingFormIsReset = (isProductEmpty: boolean) => {
2121
cy.get("#dateLanded").should("have.value", "");
2222
cy.get("#select-faoArea").should("have.value", "FAO27");
2323
cy.get("#highSeasArea").should("not.be.checked");
24-
cy.get(String.raw`#vessel\.vesselName`).should("have.value", "");
24+
cy.get(String.raw`#vessel-vesselName`).should("have.value", "");
2525
cy.get("#weight").should("have.value", "");
2626
cy.get("select#gearCategory option:selected").should("have.value", "");
2727
cy.get("select#gearType option:selected").should("have.value", "");
@@ -55,8 +55,8 @@ const populateLandingForm = () => {
5555
//High Seas Area
5656
cy.get("#highSeasArea").check();
5757
// vessel
58-
cy.get(String.raw`#vessel\.vesselName`).invoke("val", "CARINA (BF803)");
59-
cy.get(String.raw`#vessel\.vesselName`)
58+
cy.get(String.raw`#vessel-vesselName`).invoke("val", "CARINA (BF803)");
59+
cy.get(String.raw`#vessel-vesselName`)
6060
.should("have.prop", "value")
6161
.and("not.be.empty");
6262
// weight
@@ -484,7 +484,7 @@ describe("Manual landing page: post-action behaviour", () => {
484484
cy.get("#dateLanded").should("not.have.value", "");
485485
cy.get("#dateLanded").should("not.have.value", "");
486486
cy.get("#select-faoArea").should("have.value", "FAO27");
487-
cy.get(String.raw`#vessel\.vesselName`).should("not.have.value", "");
487+
cy.get(String.raw`#vessel-vesselName`).should("not.have.value", "");
488488
cy.get("#weight").should("not.have.value", "");
489489
cy.get("select#gearCategory option:selected").should("not.have.value", "");
490490
cy.get("select#gearType option:selected").should("not.have.value", "");
@@ -516,7 +516,7 @@ describe("Manual landing page: post-action behaviour", () => {
516516
cy.get("#dateLanded").should("not.have.value", "");
517517
cy.get("#dateLanded").should("not.have.value", "");
518518
cy.get("#select-faoArea").should("have.value", "FAO27");
519-
cy.get(String.raw`#vessel\.vesselName`).should("not.have.value", "");
519+
cy.get(String.raw`#vessel-vesselName`).should("not.have.value", "");
520520
cy.get("#weight").should("not.have.value", "");
521521
cy.get("select#gearCategory option:selected").should("not.have.value", "");
522522
cy.get("select#gearType option:selected").should("not.have.value", "");
@@ -540,7 +540,7 @@ describe("Manual landing page: post-action behaviour", () => {
540540
cy.get("#dateLanded").should("not.have.value", "");
541541
cy.get("#dateLanded").should("not.have.value", "");
542542
cy.get("#select-faoArea").should("have.value", "FAO27");
543-
cy.get(String.raw`#vessel\.vesselName`).should("not.have.value", "");
543+
cy.get(String.raw`#vessel-vesselName`).should("not.have.value", "");
544544
cy.get("#weight").should("not.have.value", "");
545545
cy.get("select#gearCategory option:selected").should("not.have.value", "");
546546
cy.get("select#gearType option:selected").should("not.have.value", "");
@@ -564,7 +564,7 @@ describe("Manual landing page: post-action behaviour", () => {
564564
cy.get("#dateLanded").should("not.have.value", "");
565565
cy.get("#dateLanded").should("not.have.value", "");
566566
cy.get("#select-faoArea").should("have.value", "FAO27");
567-
cy.get(String.raw`#vessel\.vesselName`).should("not.have.value", "");
567+
cy.get(String.raw`#vessel-vesselName`).should("not.have.value", "");
568568
cy.get("#weight").should("not.have.value", "");
569569
cy.get("select#gearCategory option:selected").should("not.have.value", "");
570570
cy.get("select#gearType option:selected").should("not.have.value", "");
@@ -1169,15 +1169,15 @@ describe("Manual landing page: Date Landed and Vessel validation", () => {
11691169
});
11701170

11711171
it("should not allow vessel selection until Date Landed is valid", () => {
1172-
cy.get(String.raw`#vessel\.vesselName`).type("SHOULDNOTWORK", { force: true });
1173-
cy.get(String.raw`#vessel\.vesselName`).should("have.value", "");
1172+
cy.get(String.raw`#vessel-vesselName`).type("SHOULDNOTWORK", { force: true });
1173+
cy.get(String.raw`#vessel-vesselName`).should("have.value", "");
11741174
cy.get("#dateLanded").type("12");
11751175
cy.get("#dateLanded-month").type("05");
1176-
cy.get(String.raw`#vessel\.vesselName`).type("SHOULDNOTWORK", { force: true });
1177-
cy.get(String.raw`#vessel\.vesselName`).should("have.value", "");
1176+
cy.get(String.raw`#vessel-vesselName`).type("SHOULDNOTWORK", { force: true });
1177+
cy.get(String.raw`#vessel-vesselName`).should("have.value", "");
11781178
const today = new Date();
11791179
cy.get("#dateLanded-year").type(today.getFullYear().toString());
1180-
cy.get(String.raw`#vessel\.vesselName`).type("SHOULDWORK", { force: true });
1180+
cy.get(String.raw`#vessel-vesselName`).type("SHOULDWORK", { force: true });
11811181
});
11821182

11831183
it("should clear vessel input if Date Landed is changed to invalid", () => {

0 commit comments

Comments
 (0)