Skip to content

Commit

Permalink
feat: add user logout card (#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
hperl authored Mar 9, 2023
1 parent 336e7e0 commit f2b9d51
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 15 deletions.
6 changes: 6 additions & 0 deletions src/markup-components/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ import {
UserAuthForm as userAuthForm,
UserAuthFormProps,
UserConsentCard as userConsentCard,
UserLogoutCard as userLogoutCard,
UserConsentCardProps,
UserErrorCard as userErrorCard,
UserErrorCardProps,
UserSettingsCard as userSettingsCard,
UserSettingsCardProps,
WebAuthnSettingsProps,
WebAuthnSettingsSection as webAuthnSettingsSection,
UserLogoutCardProps,
} from "../react-components"
import { CodeBoxProps } from "../react-components/codebox"
import { ComponentWrapper } from "./component-wrapper"
Expand Down Expand Up @@ -162,6 +164,9 @@ export const LookupSecretSettingsSection = (
export const UserConsentCard = (props: UserConsentCardProps) =>
ComponentWrapper(userConsentCard(props))

export const UserLogoutCard = (props: UserLogoutCardProps) =>
ComponentWrapper(userLogoutCard(props))

export type {
ButtonLinkProps,
ButtonProps,
Expand All @@ -187,6 +192,7 @@ export type {
UserAuthCardProps,
UserAuthFormProps,
UserConsentCardProps,
UserLogoutCardProps,
UserErrorCardProps,
UserSettingsCardProps,
UserSettingsFlowType,
Expand Down
2 changes: 1 addition & 1 deletion src/react-components/checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const Checkbox = ({
dataTestid,
...props
}: CheckboxProps): JSX.Element => {
const id = Math.random().toString(36).substring(2)
const id = props.id ?? Math.random().toString(36).substring(2)
return (
<div
data-testid={dataTestid}
Expand Down
1 change: 1 addition & 0 deletions src/react-components/ory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ export * from "./user-auth-card"
export * from "./user-error-card"
export * from "./user-settings-card"
export * from "./user-consent-card"
export * from "./user-logout-card"
11 changes: 1 addition & 10 deletions src/react-components/ory/user-consent-card.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import { OAuth2ConsentRequest } from "@ory/client"
import {
AuthPage,
loginFixture,
recoveryFixture,
registrationFixture,
twoFactorLoginFixture,
verificationFixture,
} from "@ory/elements-test"
import { expect, test } from "@playwright/experimental-ct-react"
import { ComponentProps } from "react"
import { test } from "@playwright/experimental-ct-react"
import { ConsentPage } from "../../test/ConsentPage"
import { UserConsentCard } from "./user-consent-card"

Expand Down
13 changes: 9 additions & 4 deletions src/react-components/ory/user-consent-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ export const UserConsentCard = ({
</div>
<div className={gridStyle({ gap: 4 })}>
{requested_scope.map((scope) => (
<Checkbox label={scope} value={scope} name="grant_scope" />
<Checkbox
key={scope}
label={scope}
value={scope}
name="grant_scope"
/>
))}
</div>
<div className={gridStyle({ gap: 4 })}>
Expand All @@ -65,20 +70,20 @@ export const UserConsentCard = ({
</div>
<div className={gridStyle({ direction: "row" })}>
{client?.policy_uri && (
<a href={client.policy_uri} target="_blank">
<a href={client.policy_uri} target="_blank" rel="noreferrer">
<Typography size="xsmall">Privacy Policy</Typography>
</a>
)}
{client?.tos_uri && (
<a href={client.tos_uri} target="_blank">
<a href={client.tos_uri} target="_blank" rel="noreferrer">
<Typography size="xsmall">Terms of Service</Typography>
</a>
)}
</div>
<Divider />
<div className={gridStyle({ gap: 8 })}>
<Checkbox
label="Remember my decision"
label="remember my decision"
id="remember"
name="remember"
/>
Expand Down
43 changes: 43 additions & 0 deletions src/react-components/ory/user-logout-card.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect, test } from "@playwright/experimental-ct-react"
import { Locator, Request } from "@playwright/test"
import { UserLogoutCard } from "./user-logout-card"

let component: Locator

test.beforeEach(async ({ mount }) => {
component = await mount(
<UserLogoutCard
csrfToken="CSRF token"
action="https://example.com/logout"
challenge="logout challenge"
/>,
)
})

async function submitForm(buttonText: RegExp): Promise<Request> {
const requestPromise = component
.page()
.waitForRequest("https://example.com/logout")
await component.locator("button", { hasText: buttonText }).click()
return requestPromise
}

test("submits when user clicks 'Yes'", async () => {
const request = await submitForm(/yes/i)

expect(request.method()).toBe("POST")
const data = request.postDataJSON()
expect(data).toHaveProperty("_csrf", "CSRF token")
expect(data).toHaveProperty("challenge", "logout challenge")
expect(data).toHaveProperty("submit", "Yes")
})

test("submits when user clicks 'No'", async () => {
const request = await submitForm(/no/i)

expect(request.method()).toBe("POST")
const data = request.postDataJSON()
expect(data).toHaveProperty("_csrf", "CSRF token")
expect(data).toHaveProperty("challenge", "logout challenge")
expect(data).toHaveProperty("submit", "No")
})
60 changes: 60 additions & 0 deletions src/react-components/ory/user-logout-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { gridStyle } from "../../theme"
import { Button } from "../button"
import { Card } from "../card"
import { Typography } from "../typography"

export type UserLogoutCardProps = {
csrfToken: string
challenge: string
action: string
className?: string
cardImage?: string | React.ReactElement
}

export const UserLogoutCard = ({
csrfToken,
challenge,
action,
className,
cardImage,
}: UserLogoutCardProps) => {
return (
<Card
className={className}
heading={
<div style={{ textAlign: "center" }}>
<Typography>Do you wish to log out?</Typography>
</div>
}
image={cardImage}
>
<form action={action} method="post">
<input type="hidden" name="_csrf" value={csrfToken} />
<input type="hidden" name="challenge" value={challenge} />
<div className={gridStyle({ gap: 16 })}>
<div
className={gridStyle({ direction: "row" })}
style={{ justifyContent: "space-between", alignItems: "center" }}
>
<Button
type="submit"
id="reject"
value="No"
name="submit"
variant="error"
header="No"
/>
<Button
type="submit"
id="accept"
value="Yes"
name="submit"
variant="semibold"
header="Yes"
/>
</div>
</div>
</form>
</Card>
)
}
22 changes: 22 additions & 0 deletions src/stories/Ory/Logout.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentProps } from "react"
import { ComponentMeta, Story } from "@storybook/react"

import { Container } from "../storyhelper"
import { UserLogoutCard } from "../../react-components"
import logo from "../assets/logo.svg"

export default {
title: "Ory/UserLogoutCard",
component: UserLogoutCard,
} as ComponentMeta<typeof UserLogoutCard>

const Template: Story<ComponentProps<typeof UserLogoutCard>> = (args) => (
<Container>
<UserLogoutCard {...args} />
</Container>
)

export const LogoutCard = Template.bind({})
LogoutCard.args = {
cardImage: logo,
}

0 comments on commit f2b9d51

Please sign in to comment.