From f9f26d43d5c51627f8e3979091cebf41c1630edc Mon Sep 17 00:00:00 2001 From: Jonas Hungershausen Date: Wed, 23 Oct 2024 20:40:26 +0200 Subject: [PATCH] fix: short-circuit code login on two step card --- .../api-report/elements-react.api.json | 10 ++-- .../api-report/elements-react.api.md | 6 ++- .../src/components/card/card-two-step.tsx | 52 +++++++++++++++---- .../components/card/card-two-step.utils.ts | 1 - .../src/components/form/form.tsx | 7 ++- .../default/components/card/auth-methods.tsx | 5 +- .../src/theme/default/utils/form.ts | 7 +++ 7 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 packages/elements-react/src/theme/default/utils/form.ts diff --git a/packages/elements-react/api-report/elements-react.api.json b/packages/elements-react/api-report/elements-react.api.json index df74e3f7d..2e319f1a2 100644 --- a/packages/elements-react/api-report/elements-react.api.json +++ b/packages/elements-react/api-report/elements-react.api.json @@ -1662,7 +1662,7 @@ "excerptTokens": [ { "kind": "Content", - "text": "declare function OryForm({ children }: " + "text": "declare function OryForm({ children, onAfterSubmit }: " }, { "kind": "Reference", @@ -1696,7 +1696,7 @@ "overloadIndex": 1, "parameters": [ { - "parameterName": "{ children }", + "parameterName": "{ children, onAfterSubmit }", "parameterTypeTokenRange": { "startIndex": 1, "endIndex": 2 @@ -1989,6 +1989,10 @@ "text": "PropsWithChildren", "canonicalReference": "@types/react!React.PropsWithChildren:type" }, + { + "kind": "Content", + "text": "<{\n onAfterSubmit?: (method: string | number | boolean | undefined) => void;\n}>" + }, { "kind": "Content", "text": ";" @@ -1999,7 +2003,7 @@ "name": "OryFormProps", "typeTokenRange": { "startIndex": 1, - "endIndex": 2 + "endIndex": 3 } }, { diff --git a/packages/elements-react/api-report/elements-react.api.md b/packages/elements-react/api-report/elements-react.api.md index 1cde0266b..19091e175 100644 --- a/packages/elements-react/api-report/elements-react.api.md +++ b/packages/elements-react/api-report/elements-react.api.md @@ -191,7 +191,7 @@ export type OryFlowComponents = { export type OryFlowContainer = LoginFlowContainer | RegistrationFlowContainer | RecoveryFlowContainer | VerificationFlowContainer | SettingsFlowContainer; // @public (undocumented) -export function OryForm({ children }: OryFormProps): string | react_jsx_runtime.JSX.Element; +export function OryForm({ children, onAfterSubmit }: OryFormProps): string | react_jsx_runtime.JSX.Element; // @public export function OryFormGroupDivider(): react_jsx_runtime.JSX.Element | null; @@ -221,7 +221,9 @@ export type OryFormOidcRootProps = PropsWithChildren<{ }>; // @public (undocumented) -export type OryFormProps = PropsWithChildren; +export type OryFormProps = PropsWithChildren<{ + onAfterSubmit?: (method: string | number | boolean | undefined) => void; +}>; // @public (undocumented) export type OryFormRootProps = ComponentPropsWithoutRef<"form"> & { diff --git a/packages/elements-react/src/components/card/card-two-step.tsx b/packages/elements-react/src/components/card/card-two-step.tsx index 9dba5661f..434453f91 100644 --- a/packages/elements-react/src/components/card/card-two-step.tsx +++ b/packages/elements-react/src/components/card/card-two-step.tsx @@ -8,6 +8,7 @@ import { UiNodeInputAttributes, } from "@ory/client-fetch" import { useState } from "react" +import { useFormContext } from "react-hook-form" import { OryCard, OryCardContent, OryCardFooter } from "." import { useComponents, useNodeSorter, useOryFlow } from "../../context" import { useNodesGroups } from "../../util/ui" @@ -15,12 +16,13 @@ import { OryForm } from "../form/form" import { OryCardValidationMessages } from "../form/messages" import { Node } from "../form/nodes/node" import { OryFormSocialButtonsForm } from "../form/social" -import { OryCardHeader } from "./header" import { filterZeroStepGroups, getFinalNodes, isChoosingMethod, } from "./card-two-step.utils" +import { OryCardHeader } from "./header" +import { isGroupImmediateSubmit } from "../../theme/default/utils/form" enum ProcessStep { ProvideIdentifier, @@ -39,7 +41,7 @@ export function OryTwoStepCard() { const [selectedGroup, setSelectedGroup] = useState< UiNodeGroupEnum | undefined >() - const { Form, Card } = useComponents() + const { Form } = useComponents() const { flowType } = useOryFlow() const nodeSorter = useNodeSorter() @@ -80,7 +82,13 @@ export function OryTwoStepCard() { {step === ProcessStep.ProvideIdentifier && hasOidc && ( )} - + + isGroupImmediateSubmit(method + "") + ? setSelectedGroup(method as UiNodeGroupEnum) + : undefined + } + > {step === ProcessStep.ProvideIdentifier && zeroStepGroups @@ -91,13 +99,10 @@ export function OryTwoStepCard() { {flowType === FlowType.Login && ( )} - {options.map((option) => ( - setSelectedGroup(option)} - /> - ))} + )} {step === ProcessStep.ExecuteAuthMethod && ( @@ -116,6 +121,33 @@ export function OryTwoStepCard() { ) } +type AuthMethodListProps = { + options: UiNodeGroupEnum[] + setSelectedGroup: (group: UiNodeGroupEnum) => void +} + +function AuthMethodList({ options, setSelectedGroup }: AuthMethodListProps) { + const { Card } = useComponents() + const { setValue } = useFormContext() + + const handleClick = (group: UiNodeGroupEnum) => { + if (isGroupImmediateSubmit(group)) { + // If the method is "immediate submit" (e.g. the method's submit button should be triggered immediately) + // then the methid needs to be added to the form data. + setValue("method", group) + } else { + setSelectedGroup(group) + } + } + return options.map((option) => ( + handleClick(option)} + /> + )) +} + type BackButtonProps = { onClick?: () => void href?: string diff --git a/packages/elements-react/src/components/card/card-two-step.utils.ts b/packages/elements-react/src/components/card/card-two-step.utils.ts index 71c4671d5..5cbf6dde9 100644 --- a/packages/elements-react/src/components/card/card-two-step.utils.ts +++ b/packages/elements-react/src/components/card/card-two-step.utils.ts @@ -4,7 +4,6 @@ import { UiNode, UiNodeGroupEnum } from "@ory/client-fetch" export function isChoosingMethod(uiNodes: UiNode[]): boolean { - console.log(uiNodes) return ( uiNodes.some( (node) => diff --git a/packages/elements-react/src/components/form/form.tsx b/packages/elements-react/src/components/form/form.tsx index 2400f8f27..2ff964b1d 100644 --- a/packages/elements-react/src/components/form/form.tsx +++ b/packages/elements-react/src/components/form/form.tsx @@ -182,9 +182,11 @@ type DeepPartialTwoLevels = { export type OryFlowComponentOverrides = DeepPartialTwoLevels -export type OryFormProps = PropsWithChildren +export type OryFormProps = PropsWithChildren<{ + onAfterSubmit?: (method: string | number | boolean | undefined) => void +}> -export function OryForm({ children }: OryFormProps) { +export function OryForm({ children, onAfterSubmit }: OryFormProps) { const { Form } = useComponents() const flowContainer = useOryFlow() const methods = useForm({ @@ -272,6 +274,7 @@ export function OryForm({ children }: OryFormProps) { }) break } + onAfterSubmit?.(data.method) } const hasMethods = diff --git a/packages/elements-react/src/theme/default/components/card/auth-methods.tsx b/packages/elements-react/src/theme/default/components/card/auth-methods.tsx index 8fd938262..5ccb3493d 100644 --- a/packages/elements-react/src/theme/default/components/card/auth-methods.tsx +++ b/packages/elements-react/src/theme/default/components/card/auth-methods.tsx @@ -3,11 +3,11 @@ import { useIntl } from "react-intl" import { OryCardAuthMethodListItemProps } from "@ory/elements-react" - import code from "../../assets/icons/code.svg" import passkey from "../../assets/icons/passkey.svg" import password from "../../assets/icons/password.svg" import webauthn from "../../assets/icons/webauthn.svg" +import { isGroupImmediateSubmit } from "../../utils/form" const iconsMap: Record = { code, @@ -27,8 +27,9 @@ export function DefaultAuthMethodListItem({ return (