Skip to content

Commit f6ff9a6

Browse files
committed
update account theme
1 parent 6f588c5 commit f6ff9a6

11 files changed

Lines changed: 248 additions & 31 deletions

File tree

locales/de-DE.arb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@
152152
"@backToApplication": {
153153
"description": "Zurück zur Anwendung Button Text"
154154
},
155+
"backToAccount": "Zurück zum Konto",
156+
"@backToAccount": {
157+
"description": "Zurück zum Konto Button-Text in der Kontokonsole"
158+
},
155159
"doContinue": "Weiter",
156160
"@doContinue": {
157161
"description": "Weiter Button Text"

locales/en-US.arb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@
152152
"@backToApplication": {
153153
"description": "Back to application button text"
154154
},
155+
"backToAccount": "Back to Account",
156+
"@backToAccount": {
157+
"description": "Back to account button text in account console"
158+
},
155159
"doContinue": "Continue",
156160
"@doContinue": {
157161
"description": "Continue button text"

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"license": "MPL-2",
2222
"keywords": [],
2323
"dependencies": {
24-
"@helpwave/hightide": "0.6.16",
24+
"@helpwave/hightide": "^0.8.1",
2525
"@keycloakify/email-native": "~260007.0.0",
2626
"keycloakify": "^11.14.2",
2727
"lucide-react": "^0.563.0",

src/account/KcPage.tsx

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Suspense } from 'react'
22
import type { KcContext } from './KcContext'
33
import { AccountPageLayout } from './components/AccountPageLayout'
44
import AccountSettings from './pages/AccountSettings'
5+
import AccountPassword from './pages/AccountPassword'
56

67
export default function KcPage(props: { kcContext: KcContext }) {
78
const { kcContext } = props
@@ -19,22 +20,17 @@ export default function KcPage(props: { kcContext: KcContext }) {
1920
)
2021
}
2122

23+
if (kcContext.pageId === 'password.ftl') {
24+
return (
25+
<AccountPageLayout kcContext={kcContext}>
26+
<AccountPassword kcContext={kcContext} />
27+
</AccountPageLayout>
28+
)
29+
}
30+
2231
return (
2332
<AccountPageLayout kcContext={kcContext}>
2433
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
25-
<p>
26-
{kcContext.pageId === 'password.ftl'
27-
? 'Use the link below to update your password.'
28-
: 'Use the link below to return to your account.'}
29-
</p>
30-
{kcContext.pageId === 'password.ftl' && (
31-
<a
32-
href={kcContext.url.passwordUrl}
33-
className="text-[var(--hw-color-primary-600)] underline"
34-
>
35-
Update Password
36-
</a>
37-
)}
3834
<a
3935
href={kcContext.url.accountUrl}
4036
className="text-[var(--hw-color-primary-600)] underline"

src/account/components/AccountPageLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function AccountPageLayout({ kcContext, children }: AccountPageLayoutProp
3535
</div>
3636

3737
<div className="flex flex-col items-center justify-center flex-1 w-[360px] max-w-[360px] mx-auto py-8 px-4 md:w-full md:max-w-[360px] md:py-6 md:px-4 sm:w-full sm:max-w-full sm:py-4 sm:px-2">
38-
<Branding />
38+
<Branding animate="none" />
3939

4040
<div className="w-full max-w-full mt-8 box-border [&_form]:w-full [&_form]:max-w-full [&_form]:box-border [&_>*]:w-full [&_>*]:max-w-full [&_>*]:box-border [&_input]:w-full [&_input]:max-w-full [&_input]:box-border [&_button]:w-full [&_button]:max-w-full [&_button]:box-border">
4141
{children}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import type { Meta, StoryObj } from '@storybook/react-vite'
2+
import { createKcPageStory } from '../KcPageStory'
3+
4+
const { KcPageStory } = createKcPageStory({ pageId: 'password.ftl' })
5+
6+
const meta = {
7+
title: 'account/password.ftl',
8+
component: KcPageStory
9+
} satisfies Meta<typeof KcPageStory>
10+
11+
export default meta
12+
13+
type Story = StoryObj<typeof meta>
14+
15+
export const Default: Story = {
16+
render: () => <KcPageStory />
17+
}
18+
19+
export const WithCurrentPassword: Story = {
20+
render: () => (
21+
<KcPageStory
22+
kcContext={{
23+
password: {
24+
passwordSet: true
25+
},
26+
account: {
27+
username: 'user',
28+
email: 'user@example.com',
29+
firstName: 'Test',
30+
lastName: 'User'
31+
}
32+
}}
33+
/>
34+
)
35+
}
36+
37+
export const WithMessage: Story = {
38+
render: () => (
39+
<KcPageStory
40+
kcContext={{
41+
account: {
42+
username: 'user',
43+
email: 'user@example.com',
44+
firstName: 'Test',
45+
lastName: 'User'
46+
},
47+
message: {
48+
type: 'error',
49+
summary: 'Invalid password.'
50+
}
51+
}}
52+
/>
53+
)
54+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { useState } from 'react'
2+
import { Button, Input, FormFieldLayout } from '@helpwave/hightide'
3+
import type { KcContext } from '../KcContext'
4+
import { useTranslation } from '../../i18n/useTranslation'
5+
import { useTranslatedFieldError } from '../../login/utils/translateFieldError'
6+
7+
type AccountPasswordProps = {
8+
kcContext: Extract<KcContext, { pageId: 'password.ftl' }>,
9+
}
10+
11+
export default function AccountPassword({ kcContext }: AccountPasswordProps) {
12+
const t = useTranslation()
13+
const translateError = useTranslatedFieldError()
14+
const { url, password, account, stateChecker, messagesPerField, message } = kcContext
15+
16+
const [currentPassword, setCurrentPassword] = useState('')
17+
const [newPassword, setNewPassword] = useState('')
18+
const [newPasswordConfirm, setNewPasswordConfirm] = useState('')
19+
20+
const passwordError = messagesPerField.existsError('password')
21+
? messagesPerField.get('password')
22+
: undefined
23+
const newPasswordError = messagesPerField.existsError('password-new')
24+
? messagesPerField.get('password-new')
25+
: undefined
26+
const passwordConfirmError = messagesPerField.existsError('password-confirm')
27+
? messagesPerField.get('password-confirm')
28+
: undefined
29+
30+
return (
31+
<div className="flex flex-col gap-8">
32+
{message && (
33+
<div
34+
role="alert"
35+
style={{
36+
padding: '1rem',
37+
borderRadius: '0.5rem',
38+
backgroundColor:
39+
message.type === 'error'
40+
? 'var(--hw-color-negative-50)'
41+
: 'var(--hw-color-positive-50)',
42+
color:
43+
message.type === 'error'
44+
? 'var(--hw-color-negative-900)'
45+
: 'var(--hw-color-positive-900)',
46+
marginBottom: '0.5rem'
47+
}}
48+
>
49+
{message.summary}
50+
</div>
51+
)}
52+
53+
<section className="flex flex-col gap-4">
54+
<h2 className="text-lg font-bold text-[var(--hw-color-neutral-700)]">
55+
{t('passwordSectionTitle')}
56+
</h2>
57+
<form
58+
action={url.passwordUrl}
59+
method="post"
60+
className="flex flex-col gap-4"
61+
>
62+
<input type="hidden" name="stateChecker" value={stateChecker} />
63+
<input
64+
type="hidden"
65+
name="username"
66+
value={account.username ?? ''}
67+
autoComplete="username"
68+
readOnly
69+
/>
70+
71+
{password.passwordSet && (
72+
<div>
73+
<FormFieldLayout
74+
label={t('password')}
75+
invalidDescription={translateError(passwordError)}
76+
>
77+
{({ id, ariaAttributes }) => (
78+
<Input
79+
id={id}
80+
name="password"
81+
type="password"
82+
value={currentPassword}
83+
onChange={(e) => setCurrentPassword(e.target.value)}
84+
autoComplete="current-password"
85+
{...ariaAttributes}
86+
/>
87+
)}
88+
</FormFieldLayout>
89+
</div>
90+
)}
91+
92+
<div>
93+
<FormFieldLayout
94+
label={t('passwordNew')}
95+
invalidDescription={translateError(newPasswordError)}
96+
required
97+
>
98+
{({ id, ariaAttributes }) => (
99+
<Input
100+
id={id}
101+
name="password-new"
102+
type="password"
103+
value={newPassword}
104+
onChange={(e) => setNewPassword(e.target.value)}
105+
autoComplete="new-password"
106+
required
107+
{...ariaAttributes}
108+
/>
109+
)}
110+
</FormFieldLayout>
111+
</div>
112+
113+
<div>
114+
<FormFieldLayout
115+
label={t('passwordConfirm')}
116+
invalidDescription={translateError(passwordConfirmError)}
117+
required
118+
>
119+
{({ id, ariaAttributes }) => (
120+
<Input
121+
id={id}
122+
name="password-confirm"
123+
type="password"
124+
value={newPasswordConfirm}
125+
onChange={(e) => setNewPasswordConfirm(e.target.value)}
126+
autoComplete="new-password"
127+
required
128+
{...ariaAttributes}
129+
/>
130+
)}
131+
</FormFieldLayout>
132+
</div>
133+
134+
<div className="flex flex-col gap-2">
135+
<Button type="submit" name="submitAction" value="Save" color="primary">
136+
{t('doSave')}
137+
</Button>
138+
<Button
139+
type="button"
140+
color="neutral"
141+
onClick={() => {
142+
window.location.href = url.accountUrl
143+
}}
144+
>
145+
{t('backToAccount')}
146+
</Button>
147+
</div>
148+
</form>
149+
</section>
150+
</div>
151+
)
152+
}

src/account/pages/AccountSettings.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ export default function AccountSettings({ kcContext }: AccountSettingsProps) {
4343
message.type === 'error'
4444
? 'var(--hw-color-negative-50)'
4545
: message.type === 'warning'
46-
? 'var(--hw-color-warning-50)'
47-
: 'var(--hw-color-positive-50)',
46+
? 'var(--hw-color-warning-50)'
47+
: 'var(--hw-color-positive-50)',
4848
color:
4949
message.type === 'error'
5050
? 'var(--hw-color-negative-900)'
5151
: message.type === 'warning'
52-
? 'var(--hw-color-warning-900)'
53-
: 'var(--hw-color-positive-900)',
52+
? 'var(--hw-color-warning-900)'
53+
: 'var(--hw-color-positive-900)',
5454
marginBottom: '0.5rem'
5555
}}
5656
>
@@ -59,7 +59,7 @@ export default function AccountSettings({ kcContext }: AccountSettingsProps) {
5959
)}
6060

6161
<section className="flex flex-col gap-3">
62-
<h2 className="text-sm font-medium text-[var(--hw-color-neutral-700)]">
62+
<h2 className="text-lg font-bold text-[var(--hw-color-neutral-700)]">
6363
{t('accountSectionProfile')}
6464
</h2>
6565
<div className="flex items-center gap-3 flex-wrap">
@@ -80,7 +80,7 @@ export default function AccountSettings({ kcContext }: AccountSettingsProps) {
8080
<hr className="border-[var(--hw-color-neutral-200)]" />
8181

8282
<section className="flex flex-col gap-4">
83-
<h2 className="text-sm font-medium text-[var(--hw-color-neutral-700)]">
83+
<h2 className="text-lg font-bold text-[var(--hw-color-neutral-700)]">
8484
{t('personalInfoTitle')}
8585
</h2>
8686
<form
@@ -184,7 +184,7 @@ export default function AccountSettings({ kcContext }: AccountSettingsProps) {
184184
<hr className="border-[var(--hw-color-neutral-200)]" />
185185

186186
<section className="flex flex-col gap-3">
187-
<h2 className="text-sm font-medium text-[var(--hw-color-neutral-700)]">
187+
<h2 className="text-lg font-bold text-[var(--hw-color-neutral-700)]">
188188
{t('passwordSectionTitle')}
189189
</h2>
190190
<Button
@@ -201,7 +201,7 @@ export default function AccountSettings({ kcContext }: AccountSettingsProps) {
201201
<hr className="border-[var(--hw-color-neutral-200)]" />
202202

203203
<section className="flex flex-col gap-2">
204-
<h2 className="text-sm font-medium text-[var(--hw-color-neutral-700)]">
204+
<h2 className="text-lg font-bold text-[var(--hw-color-neutral-700)]">
205205
{t('profilePicture')}
206206
</h2>
207207
<p className="text-sm text-[var(--hw-color-neutral-600)]">

src/i18n/translations.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type HelpwaveIdTranslationEntries = {
1313
'acceptTerms': string,
1414
'accountSectionProfile': string,
1515
'accountStatusActive': string,
16+
'backToAccount': string,
1617
'backToApplication': string,
1718
'backToLogin': string,
1819
'deleteAccountConfirm': string,
@@ -101,6 +102,7 @@ export const helpwaveIdTranslation: Translation<HelpwaveIdTranslationLocales, Pa
101102
'acceptTerms': `Ich akzeptiere die Allgemeinen Geschäftsbedingungen`,
102103
'accountSectionProfile': `Profil`,
103104
'accountStatusActive': `Aktiv`,
105+
'backToAccount': `Zurück zum Konto`,
104106
'backToApplication': `Zurück zur Anwendung`,
105107
'backToLogin': `Zurück zur Anmeldung`,
106108
'deleteAccountConfirm': `Möchten Sie Ihr Konto wirklich löschen?`,
@@ -192,6 +194,7 @@ export const helpwaveIdTranslation: Translation<HelpwaveIdTranslationLocales, Pa
192194
'acceptTerms': `I accept the terms and conditions`,
193195
'accountSectionProfile': `Profile`,
194196
'accountStatusActive': `Active`,
197+
'backToAccount': `Back to Account`,
195198
'backToApplication': `Back to Application`,
196199
'backToLogin': `Back to Login`,
197200
'deleteAccountConfirm': `Are you sure you want to delete your account?`,

0 commit comments

Comments
 (0)