Skip to content

Commit 583c343

Browse files
committed
add alertbox
1 parent 8c71eda commit 583c343

32 files changed

Lines changed: 254 additions & 452 deletions

docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ services:
1414
retries: 5
1515

1616
keycloak:
17-
image: quay.io/keycloak/keycloak:26.0
17+
image: quay.io/keycloak/keycloak:26.5
1818
command: start-dev --import-realm
1919
environment:
2020
KEYCLOAK_ADMIN: admin
@@ -30,7 +30,7 @@ services:
3030
ports:
3131
- "8080:8080"
3232
volumes:
33-
- ./dist_keycloak/keycloak-theme-for-kc-all-other-versions.jar:/opt/keycloak/providers/helpwave-id-theme.jar:ro
33+
- ./dist_keycloak/keycloak-theme-for-kc-26.2-and-above.jar:/opt/keycloak/providers/helpwave-id-theme.jar:ro
3434
depends_on:
3535
postgres:
3636
condition: service_healthy

locales/de-DE.arb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@
116116
"@doSave": {
117117
"description": "Speichern Button Text"
118118
},
119+
"doUpdate": "Aktualisieren",
120+
"@doUpdate": {
121+
"description": "Aktualisieren Button Text für Passwortformular"
122+
},
119123
"updatePassword": "Passwort ändern",
120124
"@updatePassword": {
121125
"description": "Passwort ändern Button Text"
@@ -343,5 +347,29 @@
343347
"errorAccountTemporarilyDisabled": "Konto ist vorübergehend deaktiviert. Wenden Sie sich an Ihren Administrator oder versuchen Sie es später erneut.",
344348
"@errorAccountTemporarilyDisabled": {
345349
"description": "Konto deaktiviert Fehler"
350+
},
351+
"errorIncorrectCurrentPassword": "Falsches aktuelles Passwort",
352+
"@errorIncorrectCurrentPassword": {
353+
"description": "Aktuelles Passwort-Feldfehler im Konto"
354+
},
355+
"errorInvalidExistingPassword": "Ungültiges bestehendes Passwort",
356+
"@errorInvalidExistingPassword": {
357+
"description": "Bestehendes Passwort ungültig im Konto"
358+
},
359+
"errorPleaseSpecifyPassword": "Bitte geben Sie ein Passwort an",
360+
"@errorPleaseSpecifyPassword": {
361+
"description": "Passwort-Pflichtfeld Validierungsmeldung"
362+
},
363+
"successPasswordChanged": "Passwort erfolgreich geändert",
364+
"@successPasswordChanged": {
365+
"description": "Passwort-Änderung Erfolgsmeldung"
366+
},
367+
"successMobileAuthenticatorConfigured": "Mobiler Authentifikator konfiguriert",
368+
"@successMobileAuthenticatorConfigured": {
369+
"description": "TOTP/Authentifikator Erfolgsmeldung"
370+
},
371+
"successAccountUpdated": "Ihr Konto wurde aktualisiert",
372+
"@successAccountUpdated": {
373+
"description": "Konto-Aktualisierung Erfolgsmeldung"
346374
}
347375
}

locales/en-US.arb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@
116116
"@doSave": {
117117
"description": "Save button text"
118118
},
119+
"doUpdate": "Update",
120+
"@doUpdate": {
121+
"description": "Update button text for password form"
122+
},
119123
"updatePassword": "Update Password",
120124
"@updatePassword": {
121125
"description": "Update password button text"
@@ -343,5 +347,29 @@
343347
"errorAccountTemporarilyDisabled": "Account is temporarily disabled. Contact your administrator or try again later.",
344348
"@errorAccountTemporarilyDisabled": {
345349
"description": "Account disabled error"
350+
},
351+
"errorIncorrectCurrentPassword": "Incorrect current password",
352+
"@errorIncorrectCurrentPassword": {
353+
"description": "Current password field error on account"
354+
},
355+
"errorInvalidExistingPassword": "Invalid existing password",
356+
"@errorInvalidExistingPassword": {
357+
"description": "Existing password invalid on account"
358+
},
359+
"errorPleaseSpecifyPassword": "Please specify password",
360+
"@errorPleaseSpecifyPassword": {
361+
"description": "Password required validation message"
362+
},
363+
"successPasswordChanged": "Password successfully changed",
364+
"@successPasswordChanged": {
365+
"description": "Password change success message"
366+
},
367+
"successMobileAuthenticatorConfigured": "Mobile authenticator configured",
368+
"@successMobileAuthenticatorConfigured": {
369+
"description": "TOTP/authenticator success message"
370+
},
371+
"successAccountUpdated": "Your account has been updated",
372+
"@successAccountUpdated": {
373+
"description": "Account update success message"
346374
}
347375
}

src/account/components/AccountPageLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function AccountPageLayout({ kcContext, children }: AccountPageLayoutProp
4040
<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">
4141
<Branding animate="none" />
4242

43-
<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">
43+
<div className="w-full max-w-full 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">
4444
{children}
4545
</div>
4646
</div>

src/account/pages/AccountPassword.tsx

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { useState } from 'react'
2-
import { ArrowLeft, Save } from 'lucide-react'
2+
import { ArrowLeft, Shield } from 'lucide-react'
33
import { Button, Input, FormFieldLayout } from '@helpwave/hightide'
44
import type { KcContext } from '../KcContext'
55
import { useTranslation } from '../../i18n/useTranslation'
66
import { useTranslatedFieldError } from '../../login/utils/translateFieldError'
7+
import { AlertBox } from '../../login/components/AlertBox'
78

89
type AccountPasswordProps = {
910
kcContext: Extract<KcContext, { pageId: 'password.ftl' }>,
@@ -30,26 +31,7 @@ export default function AccountPassword({ kcContext }: AccountPasswordProps) {
3031

3132
return (
3233
<div className="flex flex-col gap-8">
33-
{message && (
34-
<div
35-
role="alert"
36-
style={{
37-
padding: '1rem',
38-
borderRadius: '0.5rem',
39-
backgroundColor:
40-
message.type === 'error'
41-
? 'var(--hw-color-negative-50)'
42-
: 'var(--hw-color-positive-50)',
43-
color:
44-
message.type === 'error'
45-
? 'var(--hw-color-negative-900)'
46-
: 'var(--hw-color-positive-900)',
47-
marginBottom: '0.5rem'
48-
}}
49-
>
50-
{message.summary}
51-
</div>
52-
)}
34+
{message && <AlertBox message={message} className="mb-2" />}
5335

5436
<section className="flex flex-col gap-4">
5537
<h2 className="text-lg font-bold text-[var(--hw-color-neutral-700)]">
@@ -137,8 +119,8 @@ export default function AccountPassword({ kcContext }: AccountPasswordProps) {
137119

138120
<div className="flex flex-col gap-2">
139121
<Button type="submit" name="submitAction" value="Save" color="primary">
140-
<Save className="w-4 h-4" />
141-
{t('doSave')}
122+
<Shield className="w-4 h-4" />
123+
{t('doUpdate')}
142124
</Button>
143125
<Button
144126
type="button"

src/account/pages/AccountSettings.tsx

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Avatar, Button, Chip, Input, FormFieldLayout } from '@helpwave/hightide
44
import type { KcContext } from '../KcContext'
55
import { useTranslation } from '../../i18n/useTranslation'
66
import { useTranslatedFieldError } from '../../login/utils/translateFieldError'
7+
import { AlertBox } from '../../login/components/AlertBox'
78

89
type AccountSettingsProps = {
910
kcContext: Extract<KcContext, { pageId: 'account.ftl' }>,
@@ -34,30 +35,7 @@ export default function AccountSettings({ kcContext }: AccountSettingsProps) {
3435

3536
return (
3637
<div className="flex flex-col gap-8">
37-
{message && (
38-
<div
39-
role="alert"
40-
style={{
41-
padding: '1rem',
42-
borderRadius: '0.5rem',
43-
backgroundColor:
44-
message.type === 'error'
45-
? 'var(--hw-color-negative-50)'
46-
: message.type === 'warning'
47-
? 'var(--hw-color-warning-50)'
48-
: 'var(--hw-color-positive-50)',
49-
color:
50-
message.type === 'error'
51-
? 'var(--hw-color-negative-900)'
52-
: message.type === 'warning'
53-
? 'var(--hw-color-warning-900)'
54-
: 'var(--hw-color-positive-900)',
55-
marginBottom: '0.5rem'
56-
}}
57-
>
58-
{message.summary}
59-
</div>
60-
)}
38+
{message && <AlertBox message={message} className="mb-2" />}
6139

6240
<section className="flex flex-col gap-3">
6341
<h2 className="text-lg font-bold text-[var(--hw-color-neutral-700)]">

src/i18n/translations.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,22 @@ export type HelpwaveIdTranslationEntries = {
3434
'doRestart': string,
3535
'doSave': string,
3636
'doSubmit': string,
37+
'doUpdate': string,
3738
'email': string,
3839
'emailVerificationBody': string,
3940
'emailVerificationBody1': string,
4041
'errorAccountTemporarilyDisabled': string,
42+
'errorIncorrectCurrentPassword': string,
4143
'errorInvalidCode': string,
4244
'errorInvalidEmail': string,
45+
'errorInvalidExistingPassword': string,
4346
'errorInvalidPassword': string,
4447
'errorInvalidRecoveryCode': string,
4548
'errorInvalidUserCode': string,
4649
'errorInvalidUsername': string,
4750
'errorInvalidUsernameOrPassword': string,
4851
'errorPasswordMismatch': string,
52+
'errorPleaseSpecifyPassword': string,
4953
'firstName': string,
5054
'forgotPassword': string,
5155
'frontchannelLogoutMessage': string,
@@ -85,6 +89,9 @@ export type HelpwaveIdTranslationEntries = {
8589
'samlPostFormMessage': string,
8690
'selectAuthenticatorTitle': string,
8791
'selectOrganizationTitle': string,
92+
'successAccountUpdated': string,
93+
'successMobileAuthenticatorConfigured': string,
94+
'successPasswordChanged': string,
8895
'termsText': string,
8996
'updatePassword': string,
9097
'userCode': string,
@@ -123,18 +130,22 @@ export const helpwaveIdTranslation: Translation<HelpwaveIdTranslationLocales, Pa
123130
'doRestart': `Neu starten`,
124131
'doSave': `Speichern`,
125132
'doSubmit': `Absenden`,
133+
'doUpdate': `Aktualisieren`,
126134
'email': `E-Mail`,
127135
'emailVerificationBody': `Bitte überprüfen Sie Ihre E-Mail für einen Bestätigungslink.`,
128136
'emailVerificationBody1': `Bitte überprüfen Sie Ihre E-Mail für einen Bestätigungslink.`,
129137
'errorAccountTemporarilyDisabled': `Konto ist vorübergehend deaktiviert. Wenden Sie sich an Ihren Administrator oder versuchen Sie es später erneut.`,
138+
'errorIncorrectCurrentPassword': `Falsches aktuelles Passwort`,
130139
'errorInvalidCode': `Ungültiger Code`,
131140
'errorInvalidEmail': `Ungültige E-Mail`,
141+
'errorInvalidExistingPassword': `Ungültiges bestehendes Passwort`,
132142
'errorInvalidPassword': `Ungültiges Passwort`,
133143
'errorInvalidRecoveryCode': `Ungültiger Wiederherstellungscode`,
134144
'errorInvalidUserCode': `Ungültiger Benutzercode`,
135145
'errorInvalidUsername': `Ungültiger Benutzername`,
136146
'errorInvalidUsernameOrPassword': `Ungültiger Benutzername oder Passwort`,
137147
'errorPasswordMismatch': `Passwörter stimmen nicht überein`,
148+
'errorPleaseSpecifyPassword': `Bitte geben Sie ein Passwort an`,
138149
'firstName': `Vorname`,
139150
'forgotPassword': `Passwort vergessen?`,
140151
'frontchannelLogoutMessage': `Abmelden...`,
@@ -179,6 +190,9 @@ export const helpwaveIdTranslation: Translation<HelpwaveIdTranslationLocales, Pa
179190
'samlPostFormMessage': `Weiterleitung zum Identitätsanbieter...`,
180191
'selectAuthenticatorTitle': `Authentifikator auswählen`,
181192
'selectOrganizationTitle': `Organisation auswählen`,
193+
'successAccountUpdated': `Ihr Konto wurde aktualisiert`,
194+
'successMobileAuthenticatorConfigured': `Mobiler Authentifikator konfiguriert`,
195+
'successPasswordChanged': `Passwort erfolgreich geändert`,
182196
'termsText': `Allgemeine Geschäftsbedingungen Text`,
183197
'updatePassword': `Passwort ändern`,
184198
'userCode': `Benutzercode`,
@@ -215,18 +229,22 @@ export const helpwaveIdTranslation: Translation<HelpwaveIdTranslationLocales, Pa
215229
'doRestart': `Restart`,
216230
'doSave': `Save`,
217231
'doSubmit': `Submit`,
232+
'doUpdate': `Update`,
218233
'email': `Email`,
219234
'emailVerificationBody': `Please check your email for a verification link.`,
220235
'emailVerificationBody1': `Please check your email for a verification link.`,
221236
'errorAccountTemporarilyDisabled': `Account is temporarily disabled. Contact your administrator or try again later.`,
237+
'errorIncorrectCurrentPassword': `Incorrect current password`,
222238
'errorInvalidCode': `Invalid code`,
223239
'errorInvalidEmail': `Invalid email`,
240+
'errorInvalidExistingPassword': `Invalid existing password`,
224241
'errorInvalidPassword': `Invalid password`,
225242
'errorInvalidRecoveryCode': `Invalid recovery code`,
226243
'errorInvalidUserCode': `Invalid user code`,
227244
'errorInvalidUsername': `Invalid username`,
228245
'errorInvalidUsernameOrPassword': `Invalid username or password`,
229246
'errorPasswordMismatch': `Passwords do not match`,
247+
'errorPleaseSpecifyPassword': `Please specify password`,
230248
'firstName': `First name`,
231249
'forgotPassword': `Forgot Password?`,
232250
'frontchannelLogoutMessage': `Logging out...`,
@@ -271,6 +289,9 @@ export const helpwaveIdTranslation: Translation<HelpwaveIdTranslationLocales, Pa
271289
'samlPostFormMessage': `Redirecting to identity provider...`,
272290
'selectAuthenticatorTitle': `Select Authenticator`,
273291
'selectOrganizationTitle': `Select Organization`,
292+
'successAccountUpdated': `Your account has been updated`,
293+
'successMobileAuthenticatorConfigured': `Mobile authenticator configured`,
294+
'successPasswordChanged': `Password successfully changed`,
274295
'termsText': `Terms and conditions text`,
275296
'updatePassword': `Update Password`,
276297
'userCode': `User Code`,

src/login/components/AlertBox.tsx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { useTranslation } from '../../i18n/useTranslation'
2+
import {
3+
translateFieldError,
4+
getMessageKey,
5+
SENTIMENT_BY_KEY,
6+
type MessageSentiment
7+
} from '../utils/translateFieldError'
8+
9+
type MessageType = 'error' | 'warning' | 'success' | 'info'
10+
11+
type AlertBoxProps = {
12+
message: { type: MessageType, summary: string },
13+
className?: string,
14+
}
15+
16+
const borderColorBySentiment: Record<MessageSentiment, string> = {
17+
negative: 'var(--hw-color-negative-500)',
18+
neutral: 'var(--hw-color-warning-500)',
19+
positive: 'var(--hw-color-positive-500)'
20+
}
21+
22+
const bgColorBySentiment: Record<MessageSentiment, string> = {
23+
negative: 'var(--hw-color-negative-50)',
24+
neutral: 'var(--hw-color-warning-50)',
25+
positive: 'var(--hw-color-positive-50)'
26+
}
27+
28+
const textColorBySentiment: Record<MessageSentiment, string> = {
29+
negative: 'var(--hw-color-negative-900)',
30+
neutral: 'var(--hw-color-warning-900)',
31+
positive: 'var(--hw-color-positive-900)'
32+
}
33+
34+
function sentimentFromMessage(
35+
type: MessageType,
36+
summary: string
37+
): MessageSentiment {
38+
const key = getMessageKey(summary)
39+
if (key && SENTIMENT_BY_KEY[key]) return SENTIMENT_BY_KEY[key]
40+
if (type === 'error') return 'negative'
41+
if (type === 'warning' || type === 'info') return 'neutral'
42+
return 'positive'
43+
}
44+
45+
const positiveGlowStyle = {
46+
boxShadow:
47+
'0 0 0 1px var(--hw-color-positive-500), 0 0 24px 4px var(--hw-color-positive-500)'
48+
}
49+
50+
export function AlertBox({ message, className = '' }: AlertBoxProps) {
51+
const t = useTranslation()
52+
const translatedSummary =
53+
translateFieldError(message.summary, t as (key: string) => string) ?? message.summary
54+
const sentiment = sentimentFromMessage(message.type, message.summary)
55+
const borderColor = borderColorBySentiment[sentiment]
56+
const bgColor = bgColorBySentiment[sentiment]
57+
const textColor = textColorBySentiment[sentiment]
58+
const isPositive = sentiment === 'positive'
59+
60+
return (
61+
<div
62+
role="alert"
63+
className={`rounded-lg p-4 mb-4 border-2 backdrop-blur-md text-center ${className}`}
64+
style={{
65+
borderColor,
66+
backgroundColor: `color-mix(in srgb, ${bgColor} 85%, transparent)`,
67+
color: textColor,
68+
...(isPositive ? positiveGlowStyle : {})
69+
}}
70+
>
71+
<p className="m-0 block w-full break-words">{translatedSummary}</p>
72+
</div>
73+
)
74+
}

src/login/components/Branding.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ type BrandingProps = {
66

77
export function Branding({ animate = 'loading' }: BrandingProps) {
88
return (
9-
<div className="flex flex-col items-center mb-8 sm:mb-8">
9+
<div className="flex flex-col items-center mb-4">
1010
<HelpwaveLogo animate={animate} height={96} width={96} animationDuration={5} />
11-
<div className="font-space text-4xl -translate-y-6 font-bold">
11+
<div className="font-space text-4xl -translate-y-6 font-extrabold">
1212
helpwave id
1313
</div>
1414
</div>

src/login/components/Footer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export function Footer() {
55

66
return (
77
<div
8-
className="text-center text-sm mt-8 pt-4"
8+
className="text-center text-sm pt-4"
99
>
1010
<div className="mb-2">
1111
<a

0 commit comments

Comments
 (0)