Skip to content

feat(account): add forgot password page #147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 41 commits into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
2b7260a
[POND-1] add first components
aheartforspinach Feb 26, 2025
1eb5691
[POND-1] add wishlist icon in header
aheartforspinach Feb 26, 2025
a72d0b7
[POND-1] add shadcn
aheartforspinach Feb 26, 2025
075d749
[POND-1] push broken stuff
aheartforspinach Feb 27, 2025
9610f87
[POND-1] fix import topic
aheartforspinach Feb 28, 2025
110fa93
[POND-1] add inner and outer
aheartforspinach Mar 7, 2025
3d08d23
[POND-5] add button componentm extract login
aheartforspinach Mar 7, 2025
c42f5d1
[POND-5] add login form
aheartforspinach Mar 10, 2025
1720218
[POND-5] remove dark variables, replace zinc with gray
aheartforspinach Mar 10, 2025
20fd016
[POND-5] hunt error
aheartforspinach Mar 10, 2025
4ab1f7e
[POND-5] fix issue
aheartforspinach Mar 10, 2025
325841a
[POND-5] add auto animate
aheartforspinach Mar 10, 2025
41dbea8
[POND-5] fix issues
aheartforspinach Mar 10, 2025
9f1cd39
[POND-5] add password forgotten link
aheartforspinach Mar 10, 2025
9c247bd
fix typo
aheartforspinach Mar 27, 2025
3c705bd
install ducktory
aheartforspinach Mar 27, 2025
6fba4a6
add ducktory
aheartforspinach Apr 1, 2025
3d3366c
add more stories
aheartforspinach Apr 1, 2025
1825783
fix accordion
aheartforspinach Apr 1, 2025
ca3f38e
update branch
aheartforspinach Apr 1, 2025
484853d
adjust loogin
aheartforspinach Apr 1, 2025
8ae730a
remove return
aheartforspinach Apr 1, 2025
a392ee6
revert change
aheartforspinach Apr 1, 2025
c9394dc
delete unneeded stuff
aheartforspinach Apr 2, 2025
89d952f
use formatLink
aheartforspinach Apr 4, 2025
9d15c28
Merge remote-tracking branch 'origin/release/v0.2' into feature/POND-…
aheartforspinach Apr 4, 2025
b4431f4
fix localepath
aheartforspinach Apr 7, 2025
92d4e5d
[POND-10]: add recover password page
MorennMcFly Apr 16, 2025
9df1023
[POND-10]: add documentation
MorennMcFly Apr 16, 2025
63b6495
Merge branch 'release/v0.2' into feature/POND-10-forgot-password
MorennMcFly Apr 16, 2025
51fc324
Apply suggestions from code review
MorennMcFly Apr 17, 2025
8a17584
[POND-10]: add paragraphs and a slot in template, update docs
MorennMcFly Apr 17, 2025
649e0ef
[POND-10]: update docs
MorennMcFly Apr 17, 2025
9659066
Merge branch 'refs/heads/release/v0.2' into feature/POND-10-forgot-pa…
MorennMcFly May 8, 2025
1fb156d
[POND-10]: make email and password snippets more generic
MorennMcFly May 8, 2025
d8e26bd
Merge branch 'refs/heads/release/v0.2' into feature/POND-10-forgot-pa…
MorennMcFly May 16, 2025
ad10e7c
[POND-11]: fix indentation
MorennMcFly May 16, 2025
8ad4f72
Merge branch 'release/v0.2' into feature/POND-10-forgot-password
MorennMcFly Jun 12, 2025
cb446e1
[POND-10]: resolve docs conflicts
MorennMcFly Jun 12, 2025
afc8343
[POND-10]: close login dialog on navigation to recover page
MorennMcFly Jun 12, 2025
ef5e1c6
Merge branch 'release/v0.2' into feature/POND-10-forgot-password
MorennMcFly Jun 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions components/account/AccountLoginInner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ const emits = defineEmits<{
login: [loginData: LoginData];
}>();

const closeDialog = inject('closeDialog');

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<typeof schema>;
Expand All @@ -44,26 +46,30 @@ 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'),
},
},
}"
@submit="login"
>
<div class="mt-0! grid">
<slot name="password-forgotten">
<NuxtLinkLocale to="/account/todo" class="mb-6 justify-self-start py-2 text-sm underline underline-offset-4">
{{ $t('account.login.password.forgotten') }}
<NuxtLinkLocale
to="/account/recover"
class="mb-6 justify-self-start py-2 text-sm underline underline-offset-4"
@click="closeDialog?.()"
>
{{ $t('account.password.forgotten') }}
</NuxtLinkLocale>
</slot>

Expand Down
34 changes: 34 additions & 0 deletions components/account/AccountRecover.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script setup lang="ts">
import type { RecoverData } from './AccountRecoverInner.vue';

const isLoading = ref(false);
const showSuccessMessage = ref(false);

const customerStore = useCustomerStore();
const { getStorefrontUrl } = useInternationalization();

const recover = async (recoverData: RecoverData) => {
isLoading.value = true;

try {
await customerStore.resetPassword({
...recoverData,
storefrontUrl: getStorefrontUrl(),
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
// catch but do nothing
} finally {
showSuccessMessage.value = true;
isLoading.value = false;
}
};
</script>

<template>
<AccountRecoverInner
:is-loading="isLoading"
:show-success-message="showSuccessMessage"
@recover="(recoverData: RecoverData) => recover(recoverData)"
/>
</template>
98 changes: 98 additions & 0 deletions components/account/AccountRecoverInner.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script setup lang="ts">
import * as z from 'zod';
const { t } = useI18n();

withDefaults(
defineProps<{
isLoading?: boolean;
showSuccessMessage?: boolean;
}>(),
{
isLoading: false,
showSuccessMessage: false,
},
);

const emits = defineEmits<{
recover: [recoverData: RecoverData];
}>();

const schema = z.object({
email: z
.string({
required_error: t('account.email.error'),
})
.email(),
});

export type RecoverData = z.infer<typeof schema>;

const recover = (recoverData: RecoverData) => {
emits('recover', recoverData);
};
</script>

<template>
<slot name="wrapper">
<div v-auto-animate>
<slot name="success-message">
<template v-if="showSuccessMessage">
<UiAlert variant="successful" class="mb-4 flex gap-4">
<slot name="alert-icon">
<Icon name="mdi:check" class="size-4 shrink-0" />
</slot>

<div>
<UiAlertTitle>{{ $t('account.recover.successHeader') }}</UiAlertTitle>
<UiAlertDescription>
{{ $t('account.recover.successMessage') }}
</UiAlertDescription>
</div>
</UiAlert>
</template>
</slot>

<slot name="header">
<h1 class="text-lg font-semibold">{{ $t('account.recover.header') }}</h1>
<hr>
</slot>

<slot name="info-text">
<p class="pb-4 pt-2 text-sm">{{ $t('account.recover.information') }}</p>
</slot>

<slot name="form">
<UiAutoForm
class="space-y-6"
:schema="schema"
:field-config="{
email: {
label: $t('account.email.label'),
inputProps: {
type: 'email',
placeholder: $t('account.email.placeholder'),
},
}
}"
@submit="recover"
>
<slot name="buttons">
<div class="flex flex-wrap gap-4">
<slot name="back-button">
<UiButton variant="outline" class="w-fit grow sm:grow-0">
<NuxtLinkLocale to="/account/login">{{ $t('account.recover.backButton') }}</NuxtLinkLocale>
</UiButton>
</slot>

<slot name="submit-button">
<UiButton type="submit" :is-loading="isLoading" class="min-w-52 grow">
{{ $t('account.recover.submitButton') }}
</UiButton>
</slot>
</div>
</slot>
</UiAutoForm>
</slot>
</div>
</slot>
</template>
8 changes: 7 additions & 1 deletion components/layout/header/LayoutHeaderAccountInner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ defineEmits<{
}>();

const { formatLink } = useInternationalization();

const dialogOpen = ref(true);

Comment on lines +17 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Dialog is pre-opened (ref(true)); likely should default to closed

Initializing the dialog as open (true) will pop the login modal the very first time a guest opens the account menu—probably not the intended UX. Start with false and let the trigger handle opening.

-const dialogOpen = ref(true);
+const dialogOpen = ref(false);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const dialogOpen = ref(true);
- const dialogOpen = ref(true);
+ const dialogOpen = ref(false);
🤖 Prompt for AI Agents
In components/layout/header/LayoutHeaderAccountInner.vue at lines 17 to 18, the
dialogOpen ref is initialized to true, causing the dialog to be open by default.
Change the initialization of dialogOpen to false so the dialog starts closed and
only opens when triggered by user interaction.

provide('closeDialog', () => {
dialogOpen.value = false;
});
</script>

<template>
Expand Down Expand Up @@ -104,7 +110,7 @@ const { formatLink } = useInternationalization();
<!-- guest view -->
<template v-else>
<slot name="guest">
<UiDialog>
<UiDialog v-model:open="dialogOpen">
<UiDialogTrigger class="w-full">
<slot name="action-login">
<UiDropdownMenuItem class="cursor-pointer" @select.prevent="">
Expand Down
1 change: 1 addition & 0 deletions components/ui/alert/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default defineConfig({
items: [
{ text: 'CMS System', link: '/how-to/cms-system' },
{ text: 'Error Handling', link: '/how-to/error-handling'},
{ text: 'Account Management', link: '/how-to/account-management'},
],
},
],
Expand Down
90 changes: 0 additions & 90 deletions docs/features/account-management.md

This file was deleted.

Loading