Skip to content

Commit

Permalink
feat: render profile nodes, saner js setup
Browse files Browse the repository at this point in the history
  • Loading branch information
hperl committed Feb 6, 2024
1 parent 674aa19 commit d8e7451
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 51 deletions.
13 changes: 7 additions & 6 deletions src/react-components/ory/sections/passkey-settings-section.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { JSX } from "react"

import { SettingsFlow } from "@ory/client"
import { gridStyle } from "../../../theme"
import { FilterFlowNodes } from "../helpers/filter-flow-nodes"
import { hasPasskey } from "../helpers/utils"
import { gridStyle } from "../../../theme"

export interface PasskeySettingsProps {
flow: SettingsFlow
Expand All @@ -14,18 +14,19 @@ export const PasskeySettingsSection = ({
}: PasskeySettingsProps): JSX.Element | null => {
const filter = {
nodes: flow.ui.nodes,
groups: ["passkey", "webauthn"],
groups: "passkey",
withoutDefaultGroup: true,
}

return hasPasskey(flow.ui.nodes) ? (
<div>
<div className={gridStyle({ gap: 32 })}>
<FilterFlowNodes
filter={{ ...filter, attributes: "submit,button" }}
buttonOverrideProps={{ fullWidth: false }}
filter={{ ...filter, excludeAttributes: "onclick,button" }}
/>

<FilterFlowNodes
filter={{ ...filter, excludeAttributes: "submit,button" }}
filter={{ ...filter, attributes: "onclick,button" }}
buttonOverrideProps={{ fullWidth: false }}
/>
</div>
) : null
Expand Down
54 changes: 41 additions & 13 deletions src/react-components/ory/sections/passwordless-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import { hasPasskey, hasWebauthn } from "../helpers/utils"
export const PasswordlessSection = (
flow: SelfServiceFlow,
): JSX.Element | null => {
return hasWebauthn(flow.ui.nodes) || hasPasskey(flow.ui.nodes) ? (
return hasWebauthn(flow.ui.nodes) ? (
<div className={gridStyle({ gap: 32 })}>
<div className={gridStyle({ gap: 16 })}>
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
// we will also map default fields here but not oidc and password fields
groups: ["webauthn", "passkey"],
groups: ["webauthn"],
withoutDefaultAttributes: true,
excludeAttributes: ["hidden", "button", "submit"], // the form will take care of hidden fields
}}
Expand All @@ -24,7 +24,7 @@ export const PasswordlessSection = (
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
groups: ["webauthn", "passkey"],
groups: ["webauthn"],
withoutDefaultAttributes: true,
attributes: ["button", "submit"],
}}
Expand All @@ -33,24 +33,52 @@ export const PasswordlessSection = (
) : null
}

export const PasswordlessLoginSection = (
flow: SelfServiceFlow,
): JSX.Element | null => {
if (hasPasskey(flow.ui.nodes)) {
return (
<div className={gridStyle({ gap: 32 })}>
export const PasskeySection = (flow: SelfServiceFlow): JSX.Element | null => {
return hasPasskey(flow.ui.nodes) ? (
<div className={gridStyle({ gap: 32 })}>
<div className={gridStyle({ gap: 16 })}>
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
groups: ["webauthn", "passkey"],
// we will also map default fields here but not oidc and password fields
groups: ["passkey"],
withoutDefaultAttributes: true,
attributes: ["button", "submit"],
excludeAttributes: ["hidden", "button", "submit"], // the form will take care of hidden fields
}}
/>
</div>
)
}
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
groups: ["passkey"],
withoutDefaultAttributes: true,
attributes: ["button", "submit"],
}}
/>
</div>
) : null
}

export const PasskeyLoginSection = (
flow: SelfServiceFlow,
): JSX.Element | null => {
return hasPasskey(flow.ui.nodes) ? (
<div className={gridStyle({ gap: 32 })}>
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
groups: ["passkey"],
withoutDefaultAttributes: true,
attributes: ["button", "submit"],
}}
/>
</div>
) : null
}

export const PasswordlessLoginSection = (
flow: SelfServiceFlow,
): JSX.Element | null => {
if (hasWebauthn(flow.ui.nodes)) {
return (
<div className={gridStyle({ gap: 32 })}>
Expand Down
53 changes: 29 additions & 24 deletions src/react-components/ory/sections/profile-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import { JSX } from "react"
import { SettingsFlow } from "@ory/client"
import { gridStyle } from "../../../theme"
import { FilterFlowNodes } from "../helpers/filter-flow-nodes"
import {SelfServiceFlow} from "../helpers/types";
import {hasPasskey, hasPassword, hasProfile, hasWebauthn} from "../helpers/utils";
import { SelfServiceFlow } from "../helpers/types"
import {
hasPasskey,
hasPassword,
hasProfile,
hasWebauthn,
} from "../helpers/utils"

export interface ProfileSettingsProps {
flow: SettingsFlow
Expand All @@ -28,26 +33,26 @@ export const ProfileSettingsSection = ({
}

export const ProfileRegistrationSection = (
flow: SelfServiceFlow,
flow: SelfServiceFlow,
): JSX.Element | null => {
return hasProfile(flow.ui.nodes) ? (
<div className={gridStyle({ gap: 32 })}>
<div className={gridStyle({ gap: 16 })}>
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
groups: ["profile"],
excludeAttributes: "submit",
}}
/>
</div>
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
groups: ["profile"],
attributes: "submit",
}}
/>
</div>
) : null
}
return hasProfile(flow.ui.nodes) ? (
<div className={gridStyle({ gap: 32 })}>
<div className={gridStyle({ gap: 16 })}>
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
groups: ["profile"],
excludeAttributes: "submit",
}}
/>
</div>
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
groups: ["profile"],
attributes: "submit",
}}
/>
</div>
) : null
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ export const WebAuthnSettingsSection = ({
return hasWebauthn(flow.ui.nodes) ? (
<div className={gridStyle({ gap: 32 })}>
<FilterFlowNodes
filter={{ ...filter, excludeAttributes: "submit,button" }}
filter={{ ...filter, excludeAttributes: "onclick,button" }}
/>
<FilterFlowNodes
filter={{ ...filter, attributes: "submit,button" }}
filter={{ ...filter, attributes: "onclick,button" }}
buttonOverrideProps={{ fullWidth: false }}
/>
</div>
Expand Down
44 changes: 38 additions & 6 deletions src/react-components/ory/user-auth-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import { LoggedInInfo } from "./sections/logged-info"
import { LoginSection } from "./sections/login-section"
import { OIDCSection } from "./sections/oidc-section"
import {
PasskeyLoginSection,
PasskeySection,
PasswordlessLoginSection,
PasswordlessSection,
} from "./sections/passwordless-section"
Expand Down Expand Up @@ -200,7 +202,8 @@ export const UserAuthCard = ({
let $flow: JSX.Element | null = null
let $oidc: JSX.Element | null = null
let $code: JSX.Element | null = null
let $passwordless: JSX.Element | null = null
let $passwordlessWebauthn: JSX.Element | null = null
let $passkey: JSX.Element | null = null
let $profile: JSX.Element | null = null
let message: MessageSectionProps | null = null

Expand All @@ -217,7 +220,13 @@ export const UserAuthCard = ({
// passwordless can be shown if the user is not logged in (e.g. exclude 2FA screen) or if the flow is a registration flow.
// we want the login section to handle passwordless as well when we have a 2FA screen.
const canShowPasswordless = () =>
!!$passwordless &&
!!$passwordlessWebauthn &&
(!isLoggedIn(flow as LoginFlow) || flowType === "registration")

// passkey can be shown if the user is not logged in (e.g. exclude 2FA screen) or if the flow is a registration flow.
// we want the login section to handle passwordless as well when we have a 2FA screen.
const canShowPasskey = () =>
!!$passkey &&
(!isLoggedIn(flow as LoginFlow) || flowType === "registration")

const canShowProfile = () => !!$profile && flowType === "registration"
Expand Down Expand Up @@ -257,7 +266,7 @@ export const UserAuthCard = ({
<FilterFlowNodes
filter={{
nodes: flow.ui.nodes,
groups: ["passkey", "webauthn"],
groups: ["passkey"],
withoutDefaultGroup: true,
}}
/>
Expand Down Expand Up @@ -344,7 +353,8 @@ export const UserAuthCard = ({

switch (flowType) {
case "login":
$passwordless = PasswordlessLoginSection(flow)
$passwordlessWebauthn = PasswordlessLoginSection(flow)
$passkey = PasskeyLoginSection(flow)
$oidc = OIDCSection(flow)
$code = AuthCodeSection({ nodes: flow.ui.nodes })

Expand Down Expand Up @@ -382,7 +392,8 @@ export const UserAuthCard = ({
}
break
case "registration":
$passwordless = PasswordlessSection(flow)
$passwordlessWebauthn = PasswordlessSection(flow)
$passkey = PasskeySection(flow)
$profile = ProfileRegistrationSection(flow)
$oidc = OIDCSection(flow)
$code = AuthCodeSection({ nodes: flow.ui.nodes })
Expand Down Expand Up @@ -518,6 +529,25 @@ export const UserAuthCard = ({
</>
)}

{canShowPasskey() && (
<>
<Divider />
<UserAuthForm
flow={flow}
submitOnEnter={true}
onSubmit={onSubmit}
data-testid={"passkey-flow"}
formFilterOverride={{
nodes: flow.ui.nodes,
groups: ["default", "passkey"],
attributes: "hidden",
}}
>
{$passkey}
</UserAuthForm>
</>
)}

{canShowPasswordless() && (
<>
<Divider />
Expand All @@ -528,13 +558,15 @@ export const UserAuthCard = ({
data-testid={"passwordless-flow"}
formFilterOverride={{
nodes: flow.ui.nodes,
groups: ["default", "webauthn"],
attributes: "hidden",
}}
>
{$passwordless}
{$passwordlessWebauthn}
</UserAuthForm>
</>
)}

{message && MessageSection(message)}
</div>
</Card>
Expand Down

0 comments on commit d8e7451

Please sign in to comment.