diff --git a/components/account/AccountLoginInner.vue b/components/account/AccountLoginInner.vue index 98e285c4..29adbf2a 100644 --- a/components/account/AccountLoginInner.vue +++ b/components/account/AccountLoginInner.vue @@ -21,13 +21,13 @@ const { t } = useI18n(); const schema = z.object({ username: z .string({ - required_error: t('account.login.email.error'), + required_error: t('account.email.error'), }) .email(), password: z .string({ - required_error: t('account.login.password.errorGeneral'), + required_error: t('account.password.errorGeneral'), }), }); export type LoginData = z.infer; @@ -43,17 +43,17 @@ const login = async (loginData: LoginData) => { :schema="schema" :field-config="{ username: { - label: $t('account.login.email.label'), + label: $t('account.email.label'), inputProps: { type: 'email', - placeholder: $t('account.login.email.placeholder'), + placeholder: $t('account.email.placeholder'), }, }, password: { - label: $t('account.login.password.label'), + label: $t('account.password.label'), inputProps: { type: 'password', - placeholder: $t('account.login.password.placeholder'), + placeholder: $t('account.password.placeholder'), }, }, }" @@ -61,8 +61,8 @@ const login = async (loginData: LoginData) => { >
- - {{ $t('account.login.password.forgotten') }} + + {{ $t('account.password.forgotten') }} diff --git a/components/account/AccountRecover.vue b/components/account/AccountRecover.vue new file mode 100644 index 00000000..01d2f5a5 --- /dev/null +++ b/components/account/AccountRecover.vue @@ -0,0 +1,34 @@ + + + diff --git a/components/account/AccountRecoverInner.vue b/components/account/AccountRecoverInner.vue new file mode 100644 index 00000000..da270159 --- /dev/null +++ b/components/account/AccountRecoverInner.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/ui/alert/index.ts b/components/ui/alert/index.ts index c52f5dcd..fb84e765 100644 --- a/components/ui/alert/index.ts +++ b/components/ui/alert/index.ts @@ -11,6 +11,7 @@ export const alertVariants = cva( variant: { default: 'bg-white text-gray-950', destructive: 'border-red-500/50 text-red-500', + successful: 'border-green-500/50 text-green-500', }, }, defaultVariants: { diff --git a/docs/features/account-management.md b/docs/features/account-management.md new file mode 100644 index 00000000..4b096156 --- /dev/null +++ b/docs/features/account-management.md @@ -0,0 +1,83 @@ +# Account management + +## Account Recovery + +The **Account Recovery** page provides users with a secure way to initiate a password reset via email. When a user submits an email address: + +- If the email is **registered**, a recovery link is sent and a generic success message is displayed. +- If the email is **not registered**, a generic success message is still displayed to prevent account enumeration. + +### Component Structure + +This page is composed of layered components: + +1. **`pages/account/recover.vue`** – wraps the recovery component in a responsive layout. + +2. **`components/account/AccountRecover.vue`** – manages the logic, loading state, and message display. + +3. **`components/account/AccountRecoverInner.vue`** – provides the form UI and emits the form submission event. Customizable via **named slots**. + +--- + +### Named Slots + +The `AccountRecoverInner.vue` component exposes several named slots for UI customization: + +| Slot Name | Description | +|-------------------|--------------------------------------------------------------| +| `wrapper` | Wraps the component, including form and messages | +| `success-message` | Overrides the default success alert | +| `alert-icon` | Overrides the default success alert icon | +| `header` | Overrides the default heading | +| `info-text` | Overrides the informational text displayed below the heading | +| `form` | Wraps the form | +| `buttons` | Wraps the buttons | +| `back-button` | Overrides the back to login button | +| `submit-button` | Overrides the submit button | + +--- + +### Props + +`AccountRecoverInner.vue` accepts two optional props: + +| Prop Name | Type | Description | +|----------------------|-----------|---------------------------------------------| +| `isLoading` | `boolean` | Controls a loading spinner on submit button | +| `showSuccessMessage` | `boolean` | Controls whether the success message shows | + +--- + +### Events + +| Event Name | Payload | Description | +|------------|-----------------------|----------------------------------| +| `recover` | `{ email: string }` | Emitted when form is submitted | + +--- + +### Usage Example: Custom Header & Message + +```vue + + + + + +``` + +### Technical Notes + +This component uses the `resetPassword` method from the `useCustomerPassword` composable under the hood. + +You can learn more about the `useCustomerPassword` composable in the Shopware Frontends documentation: [Shopware Frontends – useCustomerPassword](https://frontends.shopware.com/packages/composables/useCustomerPassword.html) + diff --git a/i18n/locales/de-DE/account.json b/i18n/locales/de-DE/account.json index cfb12b95..23e827ff 100644 --- a/i18n/locales/de-DE/account.json +++ b/i18n/locales/de-DE/account.json @@ -13,19 +13,25 @@ "register": "Registrieren", "logout": "Abmelden" }, - "login": { - "email": { - "label": "Ihre E-Mail-Adresse", - "placeholder": "E-Mail-Adresse", - "error": "Bitte geben Sie eine valide E-Mail-Adresse ein" - }, - "password": { - "label": "Ihr Passwort", - "placeholder": "••••••••", - "forgotten": "Passwort vergessen", - "errorGeneral": "Bitte geben Sie ein Password ein", - "errorLength": "Ihr Passwort muss mind. {length} Zeichen lang sein" - } + "email": { + "label": "Ihre E-Mail-Adresse", + "placeholder": "E-Mail-Adresse", + "error": "Bitte geben Sie eine valide E-Mail-Adresse ein" + }, + "password": { + "label": "Ihr Passwort", + "placeholder": "••••••••", + "forgotten": "Passwort vergessen", + "errorGeneral": "Bitte geben Sie ein Passwort ein", + "errorLength": "Ihr Passwort muss mind. {length} Zeichen lang sein" + }, + "recover": { + "header": "Passwort-Wiederherstellung", + "information": "Wir senden Ihnen eine Bestätigungs-E-Mail. Klicken Sie auf den darin enthaltenen Link, um Ihr Passwort zu ändern.", + "submitButton": "E-Mail anfordern", + "backButton": "Zurück zum Login", + "successHeader": "E-Mail gesendet", + "successMessage": "Eine Bestätigungs-E-Mail mit einem Link zum Zurücksetzen des Passworts wurde versandt, wenn die angegebene E-Mail-Adresse registriert ist." }, "customer": { "accountType": "Accounttyp", @@ -87,4 +93,4 @@ } } } -} \ No newline at end of file +} diff --git a/i18n/locales/en-GB/account.json b/i18n/locales/en-GB/account.json index 2f5f4db8..5315c8db 100644 --- a/i18n/locales/en-GB/account.json +++ b/i18n/locales/en-GB/account.json @@ -13,19 +13,25 @@ "register": "Sign up", "logout": "Logout" }, - "login": { - "email": { - "label": "Your Email Address", - "placeholder": "Email address", - "error": "Please enter a valid email address" - }, - "password": { - "label": "Your Password", - "placeholder": "••••••••", - "forgotten": "Password forgotten", - "errorGeneral": "Please enter a password", - "errorLength": "Your password must be at least {length} characters long" - } + "email": { + "label": "Your Email Address", + "placeholder": "Email address", + "error": "Please enter a valid email address" + }, + "password": { + "label": "Your Password", + "placeholder": "••••••••", + "forgotten": "Password forgotten", + "errorGeneral": "Please enter a password", + "errorLength": "Your password must be at least {length} characters long" + }, + "recover": { + "header": "Password recovery", + "information": "We will send you a confirmation email. Click the link in that email in order to change your password.", + "submitButton": "Request email", + "backButton": "Back to login", + "successHeader": "Email sent", + "successMessage": "A confirmation email with a password reset link has been sent if the email address provided is registered." }, "customer": { "accountType": "Account type", diff --git a/pages/account/recover.vue b/pages/account/recover.vue new file mode 100644 index 00000000..d41990ce --- /dev/null +++ b/pages/account/recover.vue @@ -0,0 +1,7 @@ + diff --git a/stories/Alert.story.vue b/stories/Alert.story.vue index a297f079..d0cafcef 100644 --- a/stories/Alert.story.vue +++ b/stories/Alert.story.vue @@ -1,6 +1,6 @@