Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
574e4b7
move BankNameBadge to its own file and hide for now
Spencer6497 May 8, 2026
83be418
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 8, 2026
5ccb6b0
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 8, 2026
92c15b4
make TextInput potentially controlled, fix useEffect in IbanInput
Spencer6497 May 11, 2026
46775f5
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 11, 2026
396e263
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 11, 2026
f8e7d00
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 11, 2026
721597f
add tests
Spencer6497 May 12, 2026
583e9ea
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 12, 2026
2a9e9ac
add clarifying comment to controlled prop, comment out bank name badg…
Spencer6497 May 12, 2026
d8f5e54
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 12, 2026
20af6b4
add accessibility features
Spencer6497 May 12, 2026
724ff2a
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 12, 2026
26687b2
extract controlled field logic to discrete hook
Spencer6497 May 12, 2026
e49d951
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 12, 2026
0c4b5ca
move ControlledFieldConfig to pageSchema
Spencer6497 May 12, 2026
42c952f
add and simplify tests
Spencer6497 May 12, 2026
2c90f7d
optional chain possibly-undefined function calls
Spencer6497 May 12, 2026
0dd0b90
misc renames
Spencer6497 May 13, 2026
eabccc0
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 13, 2026
5af47e8
cache call to fetchBanks()
Spencer6497 May 13, 2026
cfba95c
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 13, 2026
9823ffb
simplify IbanInput interface
Spencer6497 May 13, 2026
3028082
simplify testing apparatus, split handleFieldValueChange function to …
Spencer6497 May 13, 2026
d8d0664
add discrete function type definition
Spencer6497 May 13, 2026
fab1cc0
Merge branch 'main' into iban-bank-name-refactor-RAST-477
Spencer6497 May 13, 2026
6e410e8
refactor(TextInput): fix value during load page
aaschlote May 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions app/components/formElements/SchemaComponents.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { type SchemaObject } from "~/domains/userData";
import { type StrapiFormComponent } from "~/services/cms/models/formElements/StrapiFormComponent";
import { getNestedSchema } from "../formElements/schemaToForm/getNestedSchema";
import {
Expand Down Expand Up @@ -28,22 +27,23 @@ import {
isZodNumber,
renderZodNumber,
} from "~/components/formElements/schemaToForm/renderZodNumber";
import { type ArrayPage, type PageConfig } from "~/domains/pageSchemas";

type Props = {
pageSchema: SchemaObject;
pageConfig?: ArrayPage | PageConfig;
formComponents?: StrapiFormComponent[];
className?: string;
readOnlyFieldNames: string[];
};

export const SchemaComponents = ({
pageSchema,
pageConfig,
formComponents,
className,
readOnlyFieldNames,
}: Props) => {
const sortedFieldsSchema = sortSchemaByFormComponents(
pageSchema,
pageConfig?.pageSchema ?? {},
formComponents,
);

Expand Down Expand Up @@ -73,6 +73,7 @@ export const SchemaComponents = ({
return renderSpecialMetaDescriptions(
fieldName,
description,
pageConfig,
matchingElement,
);
}
Expand Down
13 changes: 8 additions & 5 deletions app/components/formElements/ValidatedFormFlow.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ValidatedForm } from "@rvf/react-router";
import { useLocation } from "react-router";
import { getPageSchema } from "~/domains/pageSchemas";
import { getPageConfigOrArrayPageByPathname } from "~/domains/pageSchemas";
import type { UserData } from "~/domains/userData";
import type { StrapiFormComponent } from "~/services/cms/models/formElements/StrapiFormComponent";
import { buildStepSchemaWithPageSchema } from "~/services/validation/stepValidator/buildStepSchemaWithPageSchema";
Expand All @@ -24,8 +24,11 @@ function ValidatedFlowForm({
buttonNavigationProps: { back, next },
}: Readonly<ValidatedFlowFormProps>) {
const { pathname } = useLocation();
const pageSchema = getPageSchema(pathname);
const formSchema = buildStepSchemaWithPageSchema(pathname, pageSchema);
const pageConfig = getPageConfigOrArrayPageByPathname(pathname);
const formSchema = buildStepSchemaWithPageSchema(
pathname,
pageConfig?.pageSchema,
);
const readOnlyFieldNames = getReadOnlyFieldNames(pathname, stepData);

return (
Expand All @@ -41,9 +44,9 @@ function ValidatedFlowForm({
<>
<CsrfInput />
<div className="flex flex-col">
{pageSchema && (
{pageConfig && (
<SchemaComponents
pageSchema={pageSchema}
pageConfig={pageConfig}
formComponents={formElements}
className="mb-kern-space-x-large"
readOnlyFieldNames={readOnlyFieldNames}
Expand Down
64 changes: 38 additions & 26 deletions app/components/formElements/__test__/SchemaComponents.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe("SchemaComponents", () => {
props: Readonly<Parameters<typeof SchemaComponents>[0]>,
) {
const form = useForm({
schema: z.object(props.pageSchema),
schema: z.object(props.pageConfig?.pageSchema),
defaultValues: {},
});

Expand All @@ -47,7 +47,7 @@ describe("SchemaComponents", () => {
const pageSchema = { field1: z.string() };
const { getByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={[]}
/>,
);
Expand All @@ -58,7 +58,7 @@ describe("SchemaComponents", () => {
it("should render textarea", () => {
const { getByRole } = render(
<WrappedSchemaComponents
pageSchema={{ field1: z.string() }}
pageConfig={{ pageSchema: { field1: z.string() } }}
readOnlyFieldNames={[]}
formComponents={[
{
Expand All @@ -78,7 +78,7 @@ describe("SchemaComponents", () => {
const pageSchema = { field1: z.enum(["option1", "option2"]) };
const { getAllByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={[]}
/>,
);
Expand All @@ -96,7 +96,7 @@ describe("SchemaComponents", () => {
};
const { getAllByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={[]}
/>,
);
Expand All @@ -111,7 +111,7 @@ describe("SchemaComponents", () => {
const pageSchema = { [fieldName]: z.enum(["option1"]) };
const { getByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={[]}
formComponents={[
{
Expand Down Expand Up @@ -148,7 +148,7 @@ describe("SchemaComponents", () => {
const pageSchema = { [fieldName]: checkedRequired };
const { getByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={[]}
formComponents={[
{
Expand All @@ -173,7 +173,7 @@ describe("SchemaComponents", () => {
const pageSchema = { field: exclusiveCheckboxesSchema(["option", "none"]) };
const { getAllByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={[]}
formComponents={[
{
Expand Down Expand Up @@ -203,12 +203,14 @@ describe("SchemaComponents", () => {
const { getByRole, getAllByRole } = render(
<WrappedSchemaComponents
readOnlyFieldNames={[]}
pageSchema={{
field1: z
.string()
.min(1)
.transform((val) => val.toUpperCase()),
field2: z.enum(["option1", "option2"]),
pageConfig={{
pageSchema: {
field1: z
.string()
.min(1)
.transform((val) => val.toUpperCase()),
field2: z.enum(["option1", "option2"]),
},
}}
/>,
);
Expand All @@ -226,7 +228,7 @@ describe("SchemaComponents", () => {
it("should attach correct labels to inputs", () => {
const { getByRole, getByLabelText, getByText } = render(
<WrappedSchemaComponents
pageSchema={{ field1: z.string() }}
pageConfig={{ pageSchema: { field1: z.string() } }}
readOnlyFieldNames={[]}
formComponents={[
{
Expand Down Expand Up @@ -264,7 +266,7 @@ describe("SchemaComponents", () => {

const { getByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={[]}
formComponents={[]}
/>,
Expand All @@ -277,7 +279,7 @@ describe("SchemaComponents", () => {
const pageSchema = { [fieldName]: createNumberIncrementSchema(-2, 18) };
const { getByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={[]}
formComponents={[
{
Expand Down Expand Up @@ -336,7 +338,7 @@ describe("SchemaComponents", () => {
const { getAllByRole, getByText } = render(
<WrappedSchemaComponents
readOnlyFieldNames={[]}
pageSchema={mockPageSchema}
pageConfig={{ pageSchema: mockPageSchema }}
formComponents={mockFormComponentsWithFieldSet}
/>,
);
Expand All @@ -351,7 +353,7 @@ describe("SchemaComponents", () => {
const pageSchema = { field1: z.string(), field2: z.string() };
const { getAllByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={["field1"]}
/>,
);
Expand All @@ -371,17 +373,27 @@ describe("SchemaComponents", () => {
const pageSchema = {
field1: ibanSchema,
};
const { getByRole } = render(
const { getByLabelText } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{
pageSchema,
}}
readOnlyFieldNames={[]}
formComponents={[
{
name: "field1",
label: "label",
errorMessages: undefined,
type: "text",
width: "10",
id: 76,
__component: "form-elements.input",
},
]}
/>,
);
const ibanInput = getByRole("textbox");
const ibanInput = getByLabelText("label");
expect(ibanInput).toHaveAttribute("name", "field1");
expect(ibanInput.getAttribute("aria-describedby")).toContain(
"bank-name-badge",
);
});

it("should render a telephone input when the schema is phoneNumberSchema", () => {
Expand All @@ -390,7 +402,7 @@ describe("SchemaComponents", () => {
};
const { getByRole } = render(
<WrappedSchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
readOnlyFieldNames={[]}
/>,
);
Expand Down
28 changes: 16 additions & 12 deletions app/components/formElements/__test__/ValidatedFlowForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { checkedRequired } from "~/services/validation/checkedCheckbox";
import { configureZod } from "~/services/validation/configureZod";
import { createDateSchema } from "~/services/validation/dateString";
import { integerSchema } from "~/services/validation/integer";
import { getPageSchema } from "~/domains/pageSchemas";
import { getPageConfigOrArrayPageByPathname } from "~/domains/pageSchemas";
import { stringRequiredSchema } from "~/services/validation/stringRequired";
import { timeSchema } from "~/services/validation/time";
import { YesNoAnswer } from "~/services/validation/YesNoAnswer";
Expand All @@ -38,8 +38,10 @@ vi.mock("~/services/params", () => ({

vi.mock("~/domains/pageSchemas");

const mockGetPageSchema = (pageSchema: SchemaObject | undefined) => {
vi.mocked(getPageSchema).mockReturnValue(pageSchema);
const mockGetPageConfigOrArrayPageByPathname = (
pageSchema: SchemaObject | undefined,
) => {
vi.mocked(getPageConfigOrArrayPageByPathname).mockReturnValue({ pageSchema });
};

vi.spyOn(parsePathname, "parsePathname").mockResolvedValue({
Expand All @@ -54,14 +56,14 @@ describe("ValidatedFlowForm", () => {
});

it("should render", () => {
mockGetPageSchema(undefined);
mockGetPageConfigOrArrayPageByPathname(undefined);
const { getByText } = renderValidatedFlowForm([]);
expect(getByText("NEXT")).toBeInTheDocument();
});

describe("Input Component", () => {
beforeAll(() => {
mockGetPageSchema({ inputName: integerSchema });
mockGetPageConfigOrArrayPageByPathname({ inputName: integerSchema });
});
const { component, expectInputErrorToExist } = getStrapiInputComponent({
code: "invalidInteger",
Expand Down Expand Up @@ -108,7 +110,7 @@ describe("ValidatedFlowForm", () => {

describe("Date Input Component", () => {
beforeAll(() => {
mockGetPageSchema({ inputName: createDateSchema() });
mockGetPageConfigOrArrayPageByPathname({ inputName: createDateSchema() });
});
const { component, expectInputErrorToExist } = getStrapiInputComponent(
{
Expand Down Expand Up @@ -158,7 +160,7 @@ describe("ValidatedFlowForm", () => {

describe("Time Input Component", () => {
beforeAll(() => {
mockGetPageSchema({ inputName: timeSchema });
mockGetPageConfigOrArrayPageByPathname({ inputName: timeSchema });
});
const { component, expectInputErrorToExist } = getStrapiInputComponent(
{
Expand Down Expand Up @@ -208,7 +210,9 @@ describe("ValidatedFlowForm", () => {

describe("Textarea Component", () => {
beforeAll(() => {
mockGetPageSchema({ myTextarea: stringRequiredSchema });
mockGetPageConfigOrArrayPageByPathname({
myTextarea: stringRequiredSchema,
});
});
const { component, expectTextareaErrorToExist } =
getStrapiTextareaComponent({
Expand Down Expand Up @@ -253,7 +257,7 @@ describe("ValidatedFlowForm", () => {

describe("Select Component (Radio)", () => {
beforeAll(() => {
mockGetPageSchema({ mySelect: YesNoAnswer });
mockGetPageConfigOrArrayPageByPathname({ mySelect: YesNoAnswer });
});
const { component, expectSelectErrorToExist } = getStrapiSelectComponent({
code: "required",
Expand Down Expand Up @@ -298,7 +302,7 @@ describe("ValidatedFlowForm", () => {

describe("Dropdown Component", () => {
beforeAll(() => {
mockGetPageSchema({
mockGetPageConfigOrArrayPageByPathname({
myDropdown: z.enum(["option1", "option2", "option3"]),
});
});
Expand Down Expand Up @@ -338,7 +342,7 @@ describe("ValidatedFlowForm", () => {

describe("Checkbox Component", () => {
beforeAll(() => {
mockGetPageSchema({
mockGetPageConfigOrArrayPageByPathname({
checkbox1: checkedRequired,
checkbox2: checkedRequired,
});
Expand Down Expand Up @@ -402,7 +406,7 @@ describe("ValidatedFlowForm", () => {

describe("TileGroup Component", () => {
beforeAll(() => {
mockGetPageSchema({
mockGetPageConfigOrArrayPageByPathname({
myTileGroup: z.enum(["firstTile", "secondTile"]),
});
});
Expand Down
2 changes: 1 addition & 1 deletion app/components/formElements/inputs/fieldset/Fieldset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const Fieldset = ({
)}
<div className="kern-fieldset__body">
<SchemaComponents
pageSchema={pageSchema}
pageConfig={{ pageSchema }}
formComponents={formComponents}
className={classNames("pt-16", { "md:pl-32": image })}
readOnlyFieldNames={readOnlyFieldNames}
Expand Down
19 changes: 19 additions & 0 deletions app/components/formElements/inputs/iban/BankNameBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Icon } from "~/components/common/Icon";

export const BankNameBadge = ({
bankNameBadgeId,
bankName,
}: {
bankNameBadgeId: string;
bankName?: string;
}) => {
return bankName ? (
<output
id={bankNameBadgeId}
className="kern-badge kern-badge-info border-2 border-kern-feedback-info bg-kern-feedback-info-background min-w-fit w-min"
>
<Icon name="info" className="fill-kern-feedback-info" />
<span className="kern-label kern-label--small">{bankName}</span>
</output>
) : null;
};
Loading
Loading