Skip to content

Commit

Permalink
refactor(playground): extract texts from pages, set autoComplete fiel…
Browse files Browse the repository at this point in the history
…ds, add forget password link etc
  • Loading branch information
matej21 committed May 29, 2024
1 parent 1226811 commit 64957d8
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 37 deletions.
66 changes: 40 additions & 26 deletions packages/playground/admin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,51 @@ import { ToastContent, Toaster, useShowToast } from './lib/components/ui/toast'
import { Loader } from './lib/components/ui/loader'
import { Overlay } from './lib/components/ui/overlay'
import { useEffect } from 'react'
import { dict } from './lib/dict'

const errorHandler = createErrorHandler((dom, react, onRecoverableError) => createRoot(dom, { onRecoverableError }).render(react))

const rootEl = document.body.appendChild(document.createElement('div'))

const Idps = {
google: 'Login with Google',
}

const hasTokenFromEnv = import.meta.env.VITE_CONTEMBER_ADMIN_SESSION_TOKEN !== '__SESSION_TOKEN__'
const appUrl = '/app'

const Login = () => {
const showToast = useShowToast()
return <>
<IDP
onInitError={error => showToast(<ToastContent>Failed to initialize IdP login: {error}</ToastContent>, { type: 'error' })}
onResponseError={error => showToast(<ToastContent>Failed to process IdP response: {error}</ToastContent>, { type: 'error' })}
onInitError={error => showToast(<ToastContent>{dict.tenant.login.idpInitError} {error}</ToastContent>, { type: 'error' })}
onResponseError={error => showToast(<ToastContent>{dict.tenant.login.idpResponseError} {error}</ToastContent>, { type: 'error' })}
>

<Card className="w-96 relative">
<CardHeader>
<CardTitle className="text-2xl">Login</CardTitle>
<CardTitle className="text-2xl">{dict.tenant.login.title}</CardTitle>
<CardDescription>
Enter your email below to login to your account
{dict.tenant.login.description}
</CardDescription>
</CardHeader>
<CardContent>
{hasTokenFromEnv && <AnchorButton href={appUrl} size="lg" className="w-full" variant="destructive">
Continue as default user
</AnchorButton>}
<LoginForm>
<form className="grid gap-4">
<LoginFormFields />
</form>
</LoginForm>

<IDPInitTrigger identityProvider="google">
<Button variant="outline" className="w-full">
Login with Google
</Button>
</IDPInitTrigger>
{Object.entries(Idps).map(([idp, label]) => (
<IDPInitTrigger key={idp} identityProvider={idp}>
<Button variant="outline" className="w-full">
{label}
</Button>
</IDPInitTrigger>
))}
</CardContent>
<IDPState state={['processing_init', 'processing_response', 'success']}>
<Loader />
Expand All @@ -60,8 +73,8 @@ const LoggedIn = () => {
const identity = useIdentity()
useEffect(() => {
setTimeout(() => {
window.location.href = '/app/'
}, 2000)
window.location.href = appUrl
}, 500)
}, [])

return (
Expand Down Expand Up @@ -111,9 +124,9 @@ const PasswordResetRequestPage = () => {
return (
<Card className="w-96">
<CardHeader>
<CardTitle className="text-2xl">Password reset request</CardTitle>
<CardTitle className="text-2xl">{dict.tenant.passwordResetRequest.title}</CardTitle>
<CardDescription>
Enter your email below to reset your password
{dict.tenant.passwordResetRequest.description}
</CardDescription>
</CardHeader>
<CardContent>
Expand All @@ -126,7 +139,7 @@ const PasswordResetRequestPage = () => {
<CardFooter>
<Link to="index">
<AnchorButton variant="link" className="ml-auto">
Back to login
{dict.tenant.login.backToLogin}
</AnchorButton>
</Link>
</CardFooter>
Expand All @@ -142,14 +155,16 @@ const PasswordResetPage = () => {
return (
<Card className="w-96">
<CardHeader>
<CardTitle className="text-2xl">Password reset</CardTitle>
<CardTitle className="text-2xl">{dict.tenant.passwordReset.title}</CardTitle>
<CardDescription>
Enter new password
{dict.tenant.passwordReset.description}
</CardDescription>
</CardHeader>
<CardContent>
<PasswordResetForm onSuccess={() => {
showToast(<ToastContent>Password has been reset</ToastContent>, { type: 'success' })
showToast(<ToastContent>
Password has been reset
</ToastContent>, { type: 'success' })
redirect('index')
}} token={token}>
<form>
Expand All @@ -160,7 +175,7 @@ const PasswordResetPage = () => {
<CardFooter>
<Link to="index">
<AnchorButton variant="link" className="ml-auto">
Back to login
{dict.tenant.login.backToLogin}
</AnchorButton>
</Link>
</CardFooter>
Expand All @@ -171,26 +186,26 @@ const PasswordResetPage = () => {
const PasswordResetRequestSuccessPage = () => (
<Card className="w-96">
<CardHeader>
<CardTitle className="text-2xl">Password reset request</CardTitle>
<CardTitle className="text-2xl">{dict.tenant.passwordResetRequest.title}</CardTitle>
<CardDescription>
Password reset link has been sent
{dict.tenant.passwordResetRequest.description}
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex flex-col items-center justify-center gap-4">
<MailIcon className="text-gray-300 w-16 h-16" />
<div className="text-center">
Please check you mailbox for instructions on how to reset your password.
An email with password reset instructions has been sent to your email address.
</div>
<div className="text-center text-gray-500">
Or <Link to="passwordReset"><a className="underline">entry password reset code</a></Link> directly.
<Link to="passwordReset"><a className="underline">{dict.tenant.passwordResetRequest.entryCode}</a></Link>
</div>
</div>
</CardContent>
<CardFooter>
<Link to="index">
<AnchorButton variant="link" className="ml-auto">
Back to login
{dict.tenant.login.backToLogin}
</AnchorButton>
</Link>
</CardFooter>
Expand All @@ -204,7 +219,8 @@ const Layout = ({ children }: { children?: React.ReactNode }) => (
</div>
<div className="bg-gray-700 text-white p-4 flex items-center justify-center">
<div className="w-full max-w-md">
<div className="text-center text-2xl"></div>
<div className="text-center text-2xl">Welcome to your app</div>
<p className="mt-8 text-center text-gray-300">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec auctor, sem eget ultricies ultricies, sapien urna tristique eros, ac tincidunt felis lacus nec nunc.</p>
</div>
</div>
</div>
Expand All @@ -225,8 +241,6 @@ errorHandler(onRecoverableError => createRoot(rootEl, { onRecoverableError }).re
resetRequest: PasswordResetRequestPage,
resetRequestSuccess: PasswordResetRequestSuccessPage,
passwordReset: PasswordResetPage,
passwordResetSuccess: <div>password reset success</div>,

}}
/>
</Toaster>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ export const ChangeMyPasswordFormFields = () => {
/>
<TenantFormField
form={form} messages={dict.tenant.changePassword.errorMessages} field="currentPassword"
type="password" required autoFocus
type="password" required autoFocus autoComplete="current-password"
>
{dict.tenant.changePassword.currentPassword}
</TenantFormField>
<TenantFormField
form={form} messages={dict.tenant.changePassword.errorMessages} field="newPassword"
type="password" required
type="password" required autoComplete="new-password"
>
{dict.tenant.changePassword.newPassword}
</TenantFormField>
<TenantFormField
form={form} messages={dict.tenant.changePassword.errorMessages} field="passwordConfirmation"
type="password" required
type="password" required autoComplete="new-password"
>
{dict.tenant.changePassword.confirmPassword}
</TenantFormField>
Expand Down
12 changes: 9 additions & 3 deletions packages/playground/admin/lib/components/tenant/loginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Button } from '../ui/button'
import { Loader } from '../ui/loader'
import { TenantFormError, TenantFormField } from './common'
import { dict } from '../../dict'
import { Link } from '@contember/interface'

export const LoginFormFields = () => {
const form = useLoginForm()
Expand All @@ -17,21 +18,26 @@ export const LoginFormFields = () => {

<TenantFormField
form={form} messages={dict.tenant.login.errorMessages} field="email"
type="email" required autoFocus={form.state === 'initial'} readOnly={form.state === 'otp-required'} placeholder="[email protected]"
type="email" required autoFocus={form.state === 'initial'} readOnly={form.state === 'otp-required'} placeholder="[email protected]" autoComplete="email"
>
{dict.tenant.login.email}
</TenantFormField>

<TenantFormField
form={form} messages={dict.tenant.login.errorMessages} field="password"
form={form} messages={dict.tenant.login.errorMessages} field="password" autoComplete="current-password"
type="password" required readOnly={form.state === 'otp-required'}
>
{dict.tenant.login.password}
<Link to="resetRequest">
<a className="float-end underline text-gray-600 text-sm font-normal">
{dict.tenant.login.forgotPassword}
</a>
</Link>
</TenantFormField>

{(form.state === 'otp-required' || fieldErrors.includes('otpToken')) && (
<TenantFormField
form={form} messages={dict.tenant.login.errorMessages} field="otpToken"
form={form} messages={dict.tenant.login.errorMessages} field="otpToken" autoComplete="one-time-code"
type="text" required autoFocus maxLength={6}
>
{dict.tenant.login.otpToken}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PasswordResetFormErrorCode, usePasswordResetForm } from '@contember/react-identity'
import { usePasswordResetForm } from '@contember/react-identity'
import { Button } from '../ui/button'
import { Loader } from '../ui/loader'
import { TenantFormError, TenantFormField } from './common'
Expand All @@ -17,21 +17,21 @@ export const PasswordResetFormFields = ({ hasToken }: { hasToken?: boolean }) =>

<TenantFormField
form={form} messages={dict.tenant.passwordReset.errorMessages} field="token"
type="text" required readOnly={hasToken}
type="text" required readOnly={hasToken} autoComplete="off"
>
{dict.tenant.passwordReset.token}
</TenantFormField>

<TenantFormField
form={form} messages={dict.tenant.passwordReset.errorMessages} field="password"
type="password" required autoFocus
type="password" required autoFocus autoComplete="new-password"
>
{dict.tenant.passwordReset.password}
</TenantFormField>

<TenantFormField
form={form} messages={dict.tenant.passwordReset.errorMessages} field="passwordConfirmation"
type="password" required
type="password" required autoComplete="new-password"
>
{dict.tenant.passwordReset.passwordConfirmation}
</TenantFormField>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const PasswordResetRequestFormFields = () => {

<TenantFormField
form={form} messages={dict.tenant.passwordResetRequest.errorMessages} field="email"
type="email" required autoFocus
type="email" required autoFocus autoComplete="email"
>
{dict.tenant.passwordResetRequest.email}
</TenantFormField>
Expand Down
14 changes: 14 additions & 0 deletions packages/playground/admin/lib/dict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ export const dict = {
email: 'Email',
password: 'Password',
otpToken: 'OTP token',
forgotPassword: 'Forgot password?',
login: 'Login',
errorMessages: {
'FIELD_REQUIRED': 'This field is required',
Expand All @@ -205,6 +206,11 @@ export const dict = {
'UNKNOWN_EMAIL': 'Unknown email',
'OTP_REQUIRED': undefined,
} satisfies Record<LoginFormErrorCode, string | undefined>,
idpInitError: 'Failed to initialize IdP login:',
idpResponseError: 'Failed to process IdP response:',
title: 'Login',
description: 'Enter your email below to login to your account',
backToLogin: 'Back to login',
},
personList: {
email: 'Email',
Expand Down Expand Up @@ -268,6 +274,9 @@ export const dict = {
'TOKEN_NOT_FOUND': 'Token not found',
'TOKEN_USED': 'Token already used',
} satisfies Record<PasswordResetFormErrorCode, string>,
title: 'Reset password',
description: 'Enter new password below',
success: 'Password has been reset',
},
passwordResetRequest: {
email: 'Email',
Expand All @@ -278,6 +287,11 @@ export const dict = {
'UNKNOWN_ERROR': 'Something went wrong. Please try again later',
'PERSON_NOT_FOUND': 'Unknown email',
} satisfies Record<PasswordResetRequestFormErrorCode, string>,
title: 'Reset password',
description: 'Enter your email below to reset your password',
success: 'Password reset link has been sent',
checkMail: 'Please check your mailbox for instructions on how to reset your password.',
entryCode: 'Or enter the reset code directly.',
},
updateProjectMember: {
updateSuccess: 'Roles updated',
Expand Down

0 comments on commit 64957d8

Please sign in to comment.