Skip to content

Commit

Permalink
feat: add FGR flow
Browse files Browse the repository at this point in the history
Co-Authored-By: Pram Gurusinga <[email protected]>
Co-Authored-By: Joschka <[email protected]>
  • Loading branch information
3 people committed Oct 27, 2023
1 parent cebe985 commit 06ca71f
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 15 deletions.
7 changes: 1 addition & 6 deletions app/models/flows/fluggastrechte/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ import {
YesNoAnswer,
customRequiredErrorMessage,
} from "~/services/validation/YesNoAnswer";

const airportSchema = z
.string()
.trim()
.regex(/^[a-zA-Z]{3}$/, "wrong_airport_format")
.transform((v) => v.toUpperCase());
import { airportSchema } from "~/services/validation/airport";

export const fluggastrechteVorabcheckContext = {
startAirport: airportSchema,
Expand Down
73 changes: 70 additions & 3 deletions app/models/flows/fluggastrechteFormular/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,78 @@
"id": "/fluggastrechte/formular/",
"initial": "start",
"states": {
"start": { "id": "start", "on": { "SUBMIT": "persoenliche-daten" } },
"start": { "on": { "SUBMIT": "dokumente" } },
"dokumente": {
"on": { "SUBMIT": "daten-uebernahme", "BACK": "start" }
},
"daten-uebernahme": {
"on": { "SUBMIT": "zwischenstopps", "BACK": "dokumente" }
},
"zwischenstopps": {
"on": {
"SUBMIT": [
{
"cond": "zwischenstoppsYes",
"target": "zwischenstopps-eingabe"
},
{
"cond": "zwischenstoppsNo",
"target": "flug-details"
}
],
"BACK": "daten-uebernahme"
}
},
"zwischenstopps-eingabe": {
"on": { "SUBMIT": "flug-details", "BACK": "zwischenstopps" }
},
"flug-details": {
"on": {
"SUBMIT": "ankunftszeit",
"BACK": [
{ "target": "zwischenstopps-eingabe", "cond": "zwischenstoppsYes" },
{ "target": "zwischenstopps", "cond": "zwischenstoppsNo" }
]
}
},
"ankunftszeit": {
"on": { "SUBMIT": "anzahl", "BACK": "flug-details" }
},
"anzahl": {
"id": "anzahl",
"on": { "SUBMIT": "persoenliche-daten.name", "BACK": "ankunftszeit" }
},
"persoenliche-daten": {},
"entfernung": {
"id": "entfernung",
"on": {
"SUBMIT": "forderung",
"BACK": "persoenliche-daten.bevollmaechtigte-person"
}
},
"forderung": {
"on": { "SUBMIT": "teilentschaedigung", "BACK": "entfernung" }
},
"teilentschaedigung": {
"on": { "SUBMIT": "nebenforderungen", "BACK": "forderung" }
},
"nebenforderungen": {
"on": { "SUBMIT": "buchungsbestaetigung", "BACK": "teilentschaedigung" }
},
"buchungsbestaetigung": {
"on": { "SUBMIT": "buchungsreferenz", "BACK": "nebenforderungen" }
},
"buchungsreferenz": {
"on": { "SUBMIT": "schriftverkehr", "BACK": "buchungsbestaetigung" }
},
"schriftverkehr": {
"on": { "SUBMIT": "frist", "BACK": "buchungsreferenz" }
},
"frist": {
"on": { "SUBMIT": "versaeumnisurteil", "BACK": "schriftverkehr" }
},
"versaeumnisurteil": {
"id": "versaeumnisurteil",
"on": { "SUBMIT": "anmerkung", "BACK": "#persoenliche-daten" }
"on": { "SUBMIT": "anmerkung", "BACK": "frist" }
},
"anmerkung": {
"on": { "SUBMIT": "ueberpruefung", "BACK": "versaeumnisurteil" }
Expand Down
13 changes: 10 additions & 3 deletions app/models/flows/fluggastrechteFormular/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,26 @@ import {
adresse,
persoenlicheDaten,
namePrivatPerson,
titleSchema,
} from "../persoenlicheDaten/context";
import { airportSchema } from "~/services/validation/airport";
import { inputRequiredSchema } from "~/services/validation/inputRequired";

export const fluggastrechtContext = {
zwischenstopps: YesNoAnswer,
zwischenstoppFlughafen: z.union([airportSchema, z.literal("")]),
ankunftsDatum: inputRequiredSchema, // TODO: validate as German date in the past
ankunftsZeit: inputRequiredSchema,
ankunftsFlugnummer: inputRequiredSchema,
anzahl: z.enum(["1", "2", "3"], customRequiredErrorMessage),
...persoenlicheDaten,
...adresse,
...namePrivatPerson,
titel: titleSchema, //TODO: remove and replace by persoenlicheDaten.title after merge
strasse: inputRequiredSchema, // TODO: replace by adresse.strasseHausnummer after merge
volljaerig: YesNoAnswer,
gesetzlicheVertretung: YesNoAnswer,
entfernung: z.coerce.number().min(1),
teilentschaedigung: YesNoAnswer,
buchungsreferenz: z.string().trim().min(6).max(6),
frist: z.string(), // TODO: validate as German date in the future
versaeumnisurteil: YesNoAnswer,
anmerkung: z.string(),
} as const;
Expand Down
19 changes: 19 additions & 0 deletions app/models/flows/fluggastrechteFormular/guards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { type FluggastrechtContext } from "./context";

type Guard = (context: FluggastrechtContext) => boolean;

function yesNoGuards<Field extends keyof FluggastrechtContext>(
field: Field,
): { [field in Field as `${field}Yes`]: Guard } & {
[field in Field as `${field}No`]: Guard;
} {
//@ts-ignore
return {
[`${field}Yes`]: ((context) => context[field] === "yes") as Guard,
[`${field}No`]: ((context) => context[field] === "no") as Guard,
};
}

export const fluggastrechteGuards = {
...yesNoGuards("zwischenstopps"),
};
7 changes: 4 additions & 3 deletions app/routes/shared/flowSpecifics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { Params } from "@remix-run/react";
import _ from "lodash";
import { fluggastrechtContext } from "~/models/flows/fluggastrechteFormular/context";
import { fluggastrechteVorabcheckContext } from "~/models/flows/fluggastrechte/context";
import { fluggastrechteGuards } from "~/models/flows/fluggastrechteFormular/guards";

export const flowSpecifics = {
"beratungshilfe/vorabcheck": {
Expand Down Expand Up @@ -57,13 +58,13 @@ export const flowSpecifics = {
states: {
"persoenliche-daten": _.merge(_.cloneDeep(persoenlicheDatenFlow), {
states: {
start: { on: { BACK: "#start" } },
"bevollmaechtigte-person": { on: { SUBMIT: "#versaeumnisurteil" } },
anzahl: { on: { BACK: "#anzahl" } },
"bevollmaechtigte-person": { on: { SUBMIT: "#entfernung" } },
},
}),
},
}),
guards: {},
guards: fluggastrechteGuards,
context: fluggastrechtContext,
},
} as const;
Expand Down
7 changes: 7 additions & 0 deletions app/services/validation/airport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { z } from "zod";

export const airportSchema = z
.string()
.trim()
.regex(/^[a-zA-Z]{3}$/, "wrong_airport_format")
.transform((v) => v.toUpperCase());
41 changes: 41 additions & 0 deletions tests/unit/services/validation/airport.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { airportSchema } from "~/services/validation/airport";
import type { SafeParseError } from "zod";

describe("airport validation", () => {
describe("success cases", () => {
const cases = [
{ input: " abc ", expected: "ABC" },
{ input: "Bar", expected: "BAR" },
{ input: " fOo ", expected: "FOO" },
];

test.each(cases)(
"given $input, returns $expected",
({ input, expected }) => {
const actual = airportSchema.safeParse(input);
expect(actual).toEqual({ data: expected, success: true });
},
);
});

describe("failing cases", () => {
const cases = [
{ input: "", errorMessage: "wrong_airport_format" },
{ input: "ab", errorMessage: "wrong_airport_format" },
{ input: "123", errorMessage: "wrong_airport_format" },
{ input: " :) ", errorMessage: "wrong_airport_format" },
{ input: "foobar ", errorMessage: "wrong_airport_format" },
];

test.each(cases)(
"given $input, returns $errorMessage",
({ input, errorMessage }) => {
const actual = airportSchema.safeParse(input);
expect(actual.success).toBe(false);
expect(
(actual as SafeParseError<unknown>).error.issues[0].message,
).toBe(errorMessage);
},
);
});
});

0 comments on commit 06ca71f

Please sign in to comment.