diff --git a/packages/elements-react/src/context/form-state.test.ts b/packages/elements-react/src/context/form-state.test.ts index 876d4ce4..19ace8ac 100644 --- a/packages/elements-react/src/context/form-state.test.ts +++ b/packages/elements-react/src/context/form-state.test.ts @@ -96,6 +96,62 @@ test(`should parse state from flow on "action_flow_update" provide_identifier`, expect(state).toEqual({ current: "provide_identifier" }) }) +test(`should parse state from flow on "action_flow_update" provide_identifier`, () => { + const { result } = renderHook(() => useFormStateReducer(init)) + const [, dispatch] = result.current + + const mockFlow = { + flowType: FlowType.Login, + flow: { + active: "", + ui: { + nodes: [ + { + attributes: { + autocomplete: "new-password", + disabled: false, + name: "password", + node_type: "input", + required: true, + type: "password", + }, + group: "password", + messages: [ + { + context: { + actual_length: 2, + min_length: 8, + }, + id: 4000032, + text: "The password must be at least 8 characters long, but got 2.", + type: "error", + }, + ], + meta: { + label: { + id: 1070001, + text: "Password", + type: "info", + }, + }, + type: "input", + }, + ], + }, // Assuming nodes structure + }, + } as unknown as OryFlowContainer + + act(() => { + dispatch({ + type: "action_flow_update", + flow: mockFlow, + }) + }) + + const [state] = result.current + expect(state).toEqual({ current: "method_active", method: "password" }) +}) + test(`should parse state from flow on "action_flow_update" when choosing method on registration`, () => { const { result } = renderHook(() => useFormStateReducer(init)) const [, dispatch] = result.current diff --git a/packages/elements-react/src/context/form-state.ts b/packages/elements-react/src/context/form-state.ts index 44257277..71f8f677 100644 --- a/packages/elements-react/src/context/form-state.ts +++ b/packages/elements-react/src/context/form-state.ts @@ -1,7 +1,7 @@ // Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { FlowType, UiNodeGroupEnum } from "@ory/client-fetch" +import { FlowType, UiNode, UiNodeGroupEnum } from "@ory/client-fetch" import { useReducer } from "react" import { isChoosingMethod } from "../components/card/card-two-step.utils" import { OryFlowContainer } from "../util" @@ -23,20 +23,28 @@ export type FormStateAction = method: UiNodeGroupEnum } +function findMethodWithMessage(nodes?: UiNode[]) { + return nodes?.find((node) => node.messages?.length > 0) +} + function parseStateFromFlow(flow: OryFlowContainer): FormState { switch (flow.flowType) { case FlowType.Registration: - case FlowType.Login: + case FlowType.Login: { + const methodWithMessage = findMethodWithMessage(flow.flow.ui.nodes) if (flow.flow.active == "link_recovery") { return { current: "method_active", method: "link" } } else if (flow.flow.active == "code_recovery") { return { current: "method_active", method: "code" } + } else if (methodWithMessage) { + return { current: "method_active", method: methodWithMessage.group } } else if (isChoosingMethod(flow.flow.ui.nodes)) { return { current: "select_method" } } else if (flow.flow.active) { return { current: "method_active", method: flow.flow.active } } return { current: "provide_identifier" } + } case FlowType.Recovery: case FlowType.Verification: // The API does not provide types for the active field of the recovery flow