diff --git a/app/assets/css/variables.css b/app/assets/css/variables.css index e3b3fc5..0bc9256 100644 --- a/app/assets/css/variables.css +++ b/app/assets/css/variables.css @@ -9,5 +9,6 @@ --color-button-warning: #f59e0b; --color-button-danger: #fb3b3b; --color-action-button-text: #fff; + --color-success-text: #4caf50; --color-error-text: #fb3b3b; } \ No newline at end of file diff --git a/app/components/forms/auth/new-password-form.vue b/app/components/forms/auth/new-password-form.vue index bdc3a11..07cb57f 100644 --- a/app/components/forms/auth/new-password-form.vue +++ b/app/components/forms/auth/new-password-form.vue @@ -4,14 +4,14 @@ const props = defineProps<{ email: string }>(); -const {resetPassword} = useAuth(); +const {resetPasswordWithToken} = useAuth(); const password = ref(""); const passwordConfirmation = ref(""); const tokenExpired = ref(false); const handlePasswordReset = () => { try { - resetPassword(password.value, passwordConfirmation.value, props.token, props.email); + resetPasswordWithToken(password.value, passwordConfirmation.value, props.token, props.email); } catch (error: unknown) { if (error instanceof Error && error.message === "TOKEN_EXPIRED") tokenExpired.value = true; diff --git a/app/components/forms/password-reset-form.vue b/app/components/forms/password-reset-form.vue index 8489fd2..5ce5d14 100644 --- a/app/components/forms/password-reset-form.vue +++ b/app/components/forms/password-reset-form.vue @@ -1,18 +1,49 @@ @@ -22,4 +53,12 @@ flex-direction: column; gap: 1rem; } + +.error-message { + color: var(--color-error-text); +} + +.success-message { + color: var(--color-success-text); +} \ No newline at end of file diff --git a/app/components/profile-menu.vue b/app/components/profile-menu.vue index 93f2171..8d43f6f 100644 --- a/app/components/profile-menu.vue +++ b/app/components/profile-menu.vue @@ -26,7 +26,7 @@ onUnmounted(() => document.removeEventListener('click', onClickOutside)) diff --git a/app/composables/useAuth.ts b/app/composables/useAuth.ts index 6c0fd76..0aeb857 100644 --- a/app/composables/useAuth.ts +++ b/app/composables/useAuth.ts @@ -37,12 +37,32 @@ export const useAuth = () => { await navigateTo('/auth/login') } - const resetPassword = async (password: string, passwordConfirmation: string, token: string, email: string) => { + const resetPassword = async (password: string, passwordConfirmation: string, currentPassword: string) => { await $fetch('/sanctum/csrf-cookie', { baseURL: config.public.apiBase, credentials: 'include', }) await $api('/api/reset-password', { + method: 'POST', + body: { + password, + password_confirmation: passwordConfirmation, + current_password: currentPassword + }, + onResponseError: ({response}) => { + const err = new Error(response._data?.message ?? 'Failed to reset password'); + (err as any).errors = response._data?.errors ?? {} + throw err + } + }) + } + + const resetPasswordWithToken = async (password: string, passwordConfirmation: string, token: string, email: string) => { + await $fetch('/sanctum/csrf-cookie', { + baseURL: config.public.apiBase, + credentials: 'include', + }) + await $api('/api/reset-password-token', { method: 'POST', body: { password, @@ -59,6 +79,20 @@ export const useAuth = () => { await navigateTo('/lists') } + const forgotPassword = async (email: string) => { + await $fetch('/sanctum/csrf-cookie', { + baseURL: config.public.apiBase, + credentials: 'include', + }) + await $api('/api/forgot-password', { + method: 'POST', + body: { + email + }, + }) + await navigateTo('/login') + } + const xsrfToken = useCookie('XSRF-TOKEN') const logout = async () => { @@ -77,5 +111,5 @@ export const useAuth = () => { navigateTo('/auth/login') } - return {login, register, resetPassword, logout} + return {login, register, forgotPassword, resetPassword, resetPasswordWithToken, logout} } diff --git a/app/middleware/auth.global.ts b/app/middleware/auth.global.ts index b329c1f..e637b34 100644 --- a/app/middleware/auth.global.ts +++ b/app/middleware/auth.global.ts @@ -2,7 +2,8 @@ export default defineNuxtRouteMiddleware((to) => { const publicRoutes = [ 'auth-login', 'auth-register', - 'auth-reset-password', + 'auth-reset-password-token', + 'auth-forgot-password', 'invitations-token-accept', 'invitations-token-decline', ] diff --git a/app/pages/account.vue b/app/pages/account-settings.vue similarity index 100% rename from app/pages/account.vue rename to app/pages/account-settings.vue diff --git a/app/pages/auth/forgot-password.vue b/app/pages/auth/forgot-password.vue new file mode 100644 index 0000000..1d6b45b --- /dev/null +++ b/app/pages/auth/forgot-password.vue @@ -0,0 +1,35 @@ + + + + + \ No newline at end of file diff --git a/app/pages/auth/login.vue b/app/pages/auth/login.vue index 42ca645..6f612a8 100644 --- a/app/pages/auth/login.vue +++ b/app/pages/auth/login.vue @@ -10,11 +10,16 @@ definePageMeta({

Log in

+ Forgot Your Password?