@bagelink/auth 1.6.53 → 1.6.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +284 -219
  2. package/dist/Callback-BHqVaZZm.cjs +4 -0
  3. package/dist/Callback-C-XghN_z.js +4 -0
  4. package/dist/ForgotPasswordPage-BV9tyhHl.cjs +4 -0
  5. package/dist/ForgotPasswordPage-DvttMGb0.js +4 -0
  6. package/dist/LoginPage-hv1wc54S.cjs +4 -0
  7. package/dist/LoginPage-klj1NV4J.js +4 -0
  8. package/dist/ResetPasswordPage-COPrJmW8.cjs +4 -0
  9. package/dist/ResetPasswordPage-nvQ4uupb.js +4 -0
  10. package/dist/SignupPage-m36w9PLJ.cjs +4 -0
  11. package/dist/SignupPage-oUFYApYW.js +4 -0
  12. package/dist/api.d.ts +115 -0
  13. package/dist/components/auth/ForgotPasswordForm.vue.d.ts +23 -0
  14. package/dist/components/auth/LoginForm.vue.d.ts +58 -0
  15. package/dist/components/auth/ResetPasswordForm.vue.d.ts +28 -0
  16. package/dist/components/auth/SignupForm.vue.d.ts +34 -0
  17. package/dist/components/index.d.ts +4 -0
  18. package/dist/constants.d.ts +34 -0
  19. package/dist/index.cjs +1227 -30
  20. package/dist/index.d.ts +16 -631
  21. package/dist/index.mjs +1242 -24
  22. package/dist/pages/Callback.vue.d.ts +2 -0
  23. package/dist/pages/ForgotPasswordPage.vue.d.ts +13 -0
  24. package/dist/pages/LoginPage.vue.d.ts +38 -0
  25. package/dist/pages/ResetPasswordPage.vue.d.ts +13 -0
  26. package/dist/pages/SignupPage.vue.d.ts +16 -0
  27. package/dist/routes.d.ts +49 -0
  28. package/dist/sso.d.ts +145 -0
  29. package/dist/types/index.d.ts +41 -0
  30. package/dist/types.d.ts +254 -0
  31. package/dist/useAuth.d.ts +112 -0
  32. package/dist/utils.d.ts +11 -0
  33. package/package.json +11 -13
  34. package/src/components/auth/ForgotPasswordForm.vue +97 -0
  35. package/src/components/auth/LoginForm.vue +257 -0
  36. package/src/components/auth/ResetPasswordForm.vue +146 -0
  37. package/src/components/auth/SignupForm.vue +224 -0
  38. package/src/components/index.ts +5 -0
  39. package/src/constants.ts +10 -0
  40. package/src/index.ts +26 -1
  41. package/src/pages/Callback.vue +183 -0
  42. package/src/pages/ForgotPasswordPage.vue +42 -0
  43. package/src/pages/LoginPage.vue +68 -0
  44. package/src/pages/ResetPasswordPage.vue +47 -0
  45. package/src/pages/SignupPage.vue +46 -0
  46. package/src/routes.ts +122 -0
  47. package/src/types/index.ts +45 -0
  48. package/dist/index.d.cts +0 -631
  49. package/dist/index.d.mts +0 -631
@@ -0,0 +1,11 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import { AuthEventMap, AuthState } from './types';
3
+ export declare function createAxiosInstance(baseURL: string): AxiosInstance;
4
+ export declare class EventEmitter {
5
+ private listeners;
6
+ on<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
7
+ off<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
8
+ emit<K extends AuthState>(event: K): void;
9
+ removeAllListeners<K extends AuthState>(event?: K): void;
10
+ }
11
+ export declare function queryParams(): Record<string, string>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/auth",
3
3
  "type": "module",
4
- "version": "1.6.53",
4
+ "version": "1.6.57",
5
5
  "description": "Bagelink auth package",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
@@ -40,23 +40,21 @@
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "^24.0.0",
43
+ "@vitejs/plugin-vue": "^5.0.0",
43
44
  "typescript": "^5.8.3",
44
- "unbuild": "^3.5.0",
45
- "@typescript-eslint/eslint-plugin": "^8.34.0",
46
- "@typescript-eslint/parser": "^8.34.0",
47
- "eslint": "^9.28.0",
48
- "rimraf": "^6.0.1",
49
- "tsup": "^8.5.0"
45
+ "vite": "^5.0.0",
46
+ "vite-plugin-dts": "^4.0.0",
47
+ "vite-tsconfig-paths": "^5.0.0",
48
+ "vue": "^3.5.16",
49
+ "vue-router": "^4.6.3",
50
+ "vue-tsc": "^2.0.0"
50
51
  },
51
52
  "peerDependencies": {
52
53
  "vue": "^3.0.0"
53
54
  },
54
55
  "scripts": {
55
- "dev": "unbuild --stub",
56
- "build": "unbuild",
57
- "start": "tsx src/index.ts",
58
- "watch": "tsx watch src/index.ts",
59
- "lint": "eslint . --ext .ts",
60
- "clean": "rimraf dist"
56
+ "dev": "vite build --watch",
57
+ "build": "vite build",
58
+ "typecheck": "vue-tsc --noEmit"
61
59
  }
62
60
  }
@@ -0,0 +1,97 @@
1
+ <script lang="ts" setup>
2
+ import { useAuth } from '@bagelink/auth'
3
+ import { Btn, Icon, TextInput } from '@bagelink/vue'
4
+ import { computed, ref } from 'vue'
5
+
6
+ export interface ForgotPasswordTexts {
7
+ title?: string
8
+ emailLabel?: string
9
+ submitButton?: string
10
+ backToLogin?: string
11
+ emailSentTitle?: string
12
+ emailSentMessage?: string
13
+ }
14
+
15
+ interface Props {
16
+ emailSent?: boolean
17
+ useHebrewDefaults?: boolean
18
+ texts?: Partial<ForgotPasswordTexts>
19
+ }
20
+
21
+ const props = withDefaults(defineProps<Props>(), {
22
+ emailSent: false,
23
+ useHebrewDefaults: false,
24
+ texts: () => ({})
25
+ })
26
+
27
+ defineEmits<{
28
+ switchForm: [form: string]
29
+ }>()
30
+
31
+ const { forgotPassword } = useAuth()
32
+
33
+ const email = ref<string>('')
34
+ const internalEmailSent = ref(false)
35
+
36
+ const showEmailSent = computed(() => props.emailSent || internalEmailSent.value)
37
+
38
+ // Text configuration with conditional defaults
39
+ const texts = computed(() => {
40
+ const hebrewDefaults = {
41
+ title: 'שכחתם סיסמה',
42
+ emailLabel: 'איימיל',
43
+ submitButton: 'שליחת איימיל איפוס',
44
+ backToLogin: 'חזרה להתחברות',
45
+ emailSentTitle: 'איימיל נשלח!',
46
+ emailSentMessage: 'יש לבדוק את תיבת הדואר שלכם לקישור איפוס הסיסמה'
47
+ }
48
+
49
+ const englishDefaults = {
50
+ title: 'Forgot Password',
51
+ emailLabel: 'Email',
52
+ submitButton: 'Send Reset Email',
53
+ backToLogin: 'Back to Login',
54
+ emailSentTitle: 'Email Sent!',
55
+ emailSentMessage: 'Check your inbox for a password reset link'
56
+ }
57
+
58
+ const defaults = props.useHebrewDefaults ? hebrewDefaults : englishDefaults
59
+
60
+ return {
61
+ title: props.texts?.title ?? defaults.title,
62
+ emailLabel: props.texts?.emailLabel ?? defaults.emailLabel,
63
+ submitButton: props.texts?.submitButton ?? defaults.submitButton,
64
+ backToLogin: props.texts?.backToLogin ?? defaults.backToLogin,
65
+ emailSentTitle: props.texts?.emailSentTitle ?? defaults.emailSentTitle,
66
+ emailSentMessage: props.texts?.emailSentMessage ?? defaults.emailSentMessage
67
+ }
68
+ })
69
+
70
+ const textDirection = computed(() => ({ 'auth-rtl': props.useHebrewDefaults }))
71
+
72
+ async function handleRecoverPassword() {
73
+ await forgotPassword(email.value)
74
+ internalEmailSent.value = true
75
+ }
76
+ </script>
77
+
78
+ <template>
79
+ <div v-if="showEmailSent" class="txt-center" :class="[textDirection]">
80
+ <Icon name="email" size="4" class="opacity-3 mb-1" />
81
+ <h1 class="txt20 bold mb-1">
82
+ {{ texts.emailSentTitle }}
83
+ </h1>
84
+ <p class="txt-center opacity-7">
85
+ {{ texts.emailSentMessage }}
86
+ </p>
87
+ <Btn thin flat class="txt-12 mt-2 underline" :value="texts.backToLogin" @click="$emit('switchForm', 'login')" />
88
+ </div>
89
+ <form v-else :class="textDirection" @submit.prevent="handleRecoverPassword">
90
+ <h1 class="txt20 bold txt-center mb-1">
91
+ {{ texts.title }}
92
+ </h1>
93
+ <TextInput v-model="email" :label="texts.emailLabel" autocomplete="email" type="email" />
94
+ <Btn type="submit" class="w-100 mt-05" :value="texts.submitButton" />
95
+ <Btn thin flat class="txt-12 mt-075 underline block" :value="texts.backToLogin" @click="$emit('switchForm', 'login')" />
96
+ </form>
97
+ </template>
@@ -0,0 +1,257 @@
1
+ <script lang="ts" setup>
2
+ import { useAuth } from '@bagelink/auth'
3
+ import { Btn, PasswordInput, TextInput } from '@bagelink/vue'
4
+ import { computed, ref } from 'vue'
5
+
6
+ export interface LoginTexts {
7
+ title?: string
8
+ emailLabel?: string
9
+ passwordLabel?: string
10
+ forgotPassword?: string
11
+ loginButton?: string
12
+ signupButton?: string
13
+ orText?: string
14
+ githubButton?: string
15
+ googleButton?: string
16
+ microsoftButton?: string
17
+ appleButton?: string
18
+ oktaButton?: string
19
+ facebookButton?: string
20
+ }
21
+
22
+ interface Props {
23
+ hideRegularLogin?: boolean
24
+ showForgotPassword?: boolean
25
+ showSignupButton?: boolean
26
+ github?: boolean
27
+ google?: boolean
28
+ microsoft?: boolean
29
+ apple?: boolean
30
+ okta?: boolean
31
+ facebook?: boolean
32
+ ssoOutline?: boolean
33
+ ssoShowValue?: boolean
34
+ ssoSize?: 'xs' | 's' | 'm' | 'l' | 'xl' | 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large'
35
+ ssoAlign?: boolean
36
+ ssoBrandBackground?: boolean
37
+ useHebrewDefaults?: boolean
38
+ errorState?: 'normal' | 'email-required' | 'email-invalid' | 'password-required' | 'invalid-credentials' | 'server-error'
39
+ texts?: Partial<LoginTexts>
40
+ }
41
+
42
+ const props = withDefaults(defineProps<Props>(), {
43
+ hideRegularLogin: false,
44
+ showForgotPassword: true,
45
+ showSignupButton: true,
46
+ github: true,
47
+ google: true,
48
+ microsoft: true,
49
+ apple: true,
50
+ okta: true,
51
+ facebook: true,
52
+ ssoOutline: true,
53
+ ssoShowValue: true,
54
+ ssoSize: undefined,
55
+ ssoAlign: false,
56
+ ssoBrandBackground: true,
57
+ useHebrewDefaults: false,
58
+ errorState: 'normal',
59
+ texts: () => ({})
60
+ })
61
+
62
+ defineEmits<{
63
+ switchForm: [form: string]
64
+ }>()
65
+
66
+ const { login, sso } = useAuth()
67
+ const form = ref({
68
+ email: '',
69
+ password: '',
70
+ })
71
+
72
+ const internalError = ref<string>('')
73
+
74
+ // Text configuration with conditional defaults
75
+ const texts = computed(() => {
76
+ const hebrewDefaults = {
77
+ title: 'התחברות',
78
+ emailLabel: 'אימייל',
79
+ passwordLabel: 'סיסמה',
80
+ forgotPassword: 'שכחתם סיסמה?',
81
+ loginButton: 'התחברות',
82
+ signupButton: 'יצירת חשבון',
83
+ orText: 'או',
84
+ githubButton: 'התחברות עם GitHub',
85
+ googleButton: 'התחברות עם Google',
86
+ microsoftButton: 'התחברות עם Microsoft',
87
+ appleButton: 'התחברות עם Apple',
88
+ oktaButton: 'התחברות עם Okta',
89
+ facebookButton: 'התחברות עם Facebook'
90
+ }
91
+
92
+ const englishDefaults = {
93
+ title: 'Login In',
94
+ emailLabel: 'Email',
95
+ passwordLabel: 'Password',
96
+ forgotPassword: 'Forgot Password?',
97
+ loginButton: 'Login In',
98
+ signupButton: 'Create Account',
99
+ orText: 'or',
100
+ githubButton: 'Login with GitHub',
101
+ googleButton: 'Login with Google',
102
+ microsoftButton: 'Login with Microsoft',
103
+ appleButton: 'Login with Apple',
104
+ oktaButton: 'Login with Okta',
105
+ facebookButton: 'Login with Facebook'
106
+ }
107
+
108
+ const defaults = props.useHebrewDefaults ? hebrewDefaults : englishDefaults
109
+
110
+ return {
111
+ title: props.texts?.title ?? defaults.title,
112
+ emailLabel: props.texts?.emailLabel ?? defaults.emailLabel,
113
+ passwordLabel: props.texts?.passwordLabel ?? defaults.passwordLabel,
114
+ forgotPassword: props.texts?.forgotPassword ?? defaults.forgotPassword,
115
+ loginButton: props.texts?.loginButton ?? defaults.loginButton,
116
+ signupButton: props.texts?.signupButton ?? defaults.signupButton,
117
+ orText: props.texts?.orText ?? defaults.orText,
118
+ githubButton: props.texts?.githubButton ?? defaults.githubButton,
119
+ googleButton: props.texts?.googleButton ?? defaults.googleButton,
120
+ microsoftButton: props.texts?.microsoftButton ?? defaults.microsoftButton,
121
+ appleButton: props.texts?.appleButton ?? defaults.appleButton,
122
+ oktaButton: props.texts?.oktaButton ?? defaults.oktaButton,
123
+ facebookButton: props.texts?.facebookButton ?? defaults.facebookButton
124
+ }
125
+ })
126
+
127
+ const showAnySso = computed(() => props.github || props.google || props.microsoft
128
+ || props.apple || props.okta || props.facebook
129
+ )
130
+
131
+ const textDirection = computed(() => ({ 'auth-rtl': props.useHebrewDefaults }))
132
+
133
+ const error = computed(() => getDevError() || internalError.value)
134
+
135
+ function getDevError() {
136
+ switch (props.errorState) {
137
+ case 'email-required': return props.useHebrewDefaults ? 'איימיל נדרש' : 'Email is required'
138
+ case 'email-invalid': return props.useHebrewDefaults ? 'יש להזין כתובת איימיל תקינה' : 'Please enter a valid email address'
139
+ case 'password-required': return props.useHebrewDefaults ? 'סיסמה נדרשת' : 'Password is required'
140
+ case 'invalid-credentials': return props.useHebrewDefaults ? 'איימיל או סיסמה לא נכונים' : 'Invalid email or password'
141
+ case 'server-error': return props.useHebrewDefaults ? 'ההתחברות נכשלה. אנא נסה שוב.' : 'Login failed. Please try again.'
142
+ default: return null
143
+ }
144
+ }
145
+
146
+ async function handleLogin() {
147
+ // Clear any previous internal errors
148
+ internalError.value = ''
149
+
150
+ // Development error states don't need actual form submission
151
+ if (props.errorState !== 'normal') {
152
+ return
153
+ }
154
+
155
+ const { message } = await login(form.value)
156
+ internalError.value = message as string
157
+ }
158
+ </script>
159
+
160
+ <template>
161
+ <form :class="textDirection" @submit.prevent="handleLogin">
162
+ <h1 class="txt20 bold txt-center mb-1">
163
+ {{ texts.title }}
164
+ </h1>
165
+
166
+ <!-- Regular Login Form - Hidden when hideRegularLogin is true -->
167
+ <template v-if="!props.hideRegularLogin">
168
+ <TextInput v-model="form.email" type="email" :label="texts.emailLabel" autocomplete="email" />
169
+ <PasswordInput v-model="form.password" :label="texts.passwordLabel" />
170
+
171
+ <Btn
172
+ v-if="props.showForgotPassword" thin flat class="txt-12 mt-075 underline block"
173
+ :value="texts.forgotPassword" @click="$emit('switchForm', 'forgot-password')"
174
+ />
175
+ <Btn type="submit" class="w-100 mt-1" :value="texts.loginButton" />
176
+ <Btn
177
+ v-if="props.showSignupButton" outline color="primary" class="w-100 mt-05" :value="texts.signupButton"
178
+ @click="$emit('switchForm', 'signup')"
179
+ />
180
+ </template>
181
+
182
+ <!-- SSO Section -->
183
+ <div v-if="showAnySso">
184
+ <div v-if="!props.hideRegularLogin" class="flex gap-1 opacity-6">
185
+ <div class="line" />
186
+ <p class="txt-center my-05">
187
+ {{ texts.orText }}
188
+ </p>
189
+ <div class="line" />
190
+ </div>
191
+
192
+ <div
193
+ class="gap-05"
194
+ :class="{ 'grid grid-wrap-1': props.ssoShowValue, 'flex justify-content-center gap-05 flex-wrap': !props.ssoShowValue }"
195
+ >
196
+ <Btn
197
+ v-if="props.github" v-tooltip="!props.ssoShowValue ? texts.githubButton : undefined"
198
+ :outline="props.ssoOutline" :full-width="props.ssoAlign"
199
+ :align-txt="props.ssoAlign ? 'start' : undefined"
200
+ :style="props.ssoOutline ? 'color: #24292F;' : `color: #FFFFFF; ${props.ssoBrandBackground ? 'background: #24292F;' : ''}`"
201
+ icon="github" :class="{ 'px-075': props.ssoAlign ? 'px-075' : '' }"
202
+ :value="props.ssoShowValue ? texts.githubButton : undefined" :size="props.ssoSize"
203
+ @click="sso.github.redirect()"
204
+ />
205
+ <Btn
206
+ v-if="props.google" v-tooltip="!props.ssoShowValue ? texts.googleButton : undefined"
207
+ :outline="props.ssoOutline" :full-width="props.ssoAlign"
208
+ :align-txt="props.ssoAlign ? 'start' : undefined"
209
+ :style="props.ssoOutline ? 'color: #DB4437;' : `color: #FFFFFF; ${props.ssoBrandBackground ? 'background: #DB4437;' : ''}`"
210
+ icon="google" :class="{ 'px-075': props.ssoAlign ? 'px-075' : '' }"
211
+ :value="props.ssoShowValue ? texts.googleButton : undefined" :size="props.ssoSize"
212
+ @click="sso.google.redirect()"
213
+ />
214
+ <Btn
215
+ v-if="props.microsoft" v-tooltip="!props.ssoShowValue ? texts.microsoftButton : undefined"
216
+ :outline="props.ssoOutline" :full-width="props.ssoAlign"
217
+ :align-txt="props.ssoAlign ? 'start' : undefined"
218
+ :style="props.ssoOutline ? 'color: #2F2FEE;' : `color: #FFFFFF; ${props.ssoBrandBackground ? 'background: #2F2FEE;' : ''}`"
219
+ icon="microsoft" :class="{ 'px-075': props.ssoAlign ? 'px-075' : '' }"
220
+ :value="props.ssoShowValue ? texts.microsoftButton : undefined" :size="props.ssoSize"
221
+ @click="sso.microsoft.redirect()"
222
+ />
223
+ <Btn
224
+ v-if="props.apple" v-tooltip="!props.ssoShowValue ? texts.appleButton : undefined"
225
+ :outline="props.ssoOutline" :full-width="props.ssoAlign"
226
+ :align-txt="props.ssoAlign ? 'start' : undefined"
227
+ :style="props.ssoOutline ? 'color: #000000;' : `color: #FFFFFF; ${props.ssoBrandBackground ? 'background: #000000;' : ''}`"
228
+ icon="apple" :class="{ 'px-075': props.ssoAlign ? 'px-075' : '' }"
229
+ :value="props.ssoShowValue ? texts.appleButton : undefined" :size="props.ssoSize"
230
+ @click="sso.apple.redirect()"
231
+ />
232
+ <Btn
233
+ v-if="props.okta" v-tooltip="!props.ssoShowValue ? texts.oktaButton : undefined"
234
+ :outline="props.ssoOutline" :full-width="props.ssoAlign"
235
+ :align-txt="props.ssoAlign ? 'start' : undefined"
236
+ :style="props.ssoOutline ? 'color: #FFB600;' : `color: #FFFFFF; ${props.ssoBrandBackground ? 'background: #FFB600;' : ''}`"
237
+ icon="sun" :class="{ 'px-075': props.ssoAlign ? 'px-075' : '' }"
238
+ :value="props.ssoShowValue ? texts.oktaButton : undefined" :size="props.ssoSize"
239
+ @click="sso.okta.redirect()"
240
+ />
241
+ <Btn
242
+ v-if="props.facebook" v-tooltip="!props.ssoShowValue ? texts.facebookButton : undefined"
243
+ :outline="props.ssoOutline" :full-width="props.ssoAlign"
244
+ :align-txt="props.ssoAlign ? 'start' : undefined"
245
+ :style="props.ssoOutline ? 'color: #1877F3;' : `color: #FFFFFF; ${props.ssoBrandBackground ? 'background: #1877F3;' : ''}`"
246
+ icon="facebook" :class="{ 'px-075': props.ssoAlign ? 'px-075' : '' }"
247
+ :value="props.ssoShowValue ? texts.facebookButton : undefined" :size="props.ssoSize"
248
+ @click="sso.facebook.redirect()"
249
+ />
250
+ </div>
251
+ </div>
252
+
253
+ <p v-if="error" class="txt-center color-red txt-12 mt-1">
254
+ {{ error }}
255
+ </p>
256
+ </form>
257
+ </template>
@@ -0,0 +1,146 @@
1
+ <script lang="ts" setup>
2
+ import { useAuth } from '@bagelink/auth'
3
+ import { Btn, Icon, PasswordInput } from '@bagelink/vue'
4
+ import { computed, ref } from 'vue'
5
+
6
+ export interface ResetPasswordTexts {
7
+ title?: string
8
+ invalidLinkTitle?: string
9
+ invalidLinkMessage?: string
10
+ newPasswordLabel?: string
11
+ confirmPasswordLabel?: string
12
+ submitButton?: string
13
+ backToLogin?: string
14
+ passwordMismatchError?: string
15
+ invalidTokenError?: string
16
+ successTitle?: string
17
+ successMessage?: string
18
+ goToLogin?: string
19
+ }
20
+
21
+ interface Props {
22
+ token?: string
23
+ showSuccess?: boolean
24
+ useHebrewDefaults?: boolean
25
+ texts?: Partial<ResetPasswordTexts>
26
+ }
27
+
28
+ const props = withDefaults(defineProps<Props>(), {
29
+ useHebrewDefaults: false
30
+ })
31
+ defineEmits<{
32
+ switchForm: [form: string]
33
+ }>()
34
+
35
+ const { resetPassword } = useAuth()
36
+
37
+ const error = ref<string>('')
38
+ const internalSuccess = ref<boolean>(false)
39
+ const newPassword = ref<string>('')
40
+ const confirmPassword = ref<string>('')
41
+
42
+ const isValidToken = computed(() => !!props.token)
43
+ const isSuccess = computed(() => props.showSuccess || internalSuccess.value)
44
+
45
+ // Text configuration with conditional defaults
46
+ const texts = computed(() => {
47
+ const hebrewDefaults = {
48
+ title: 'איפוס סיסמה',
49
+ invalidLinkTitle: 'קישור לא תקין',
50
+ invalidLinkMessage: 'קישור איפוס הסיסמה לא תקין או פג תוקף',
51
+ newPasswordLabel: 'סיסמה חדשה',
52
+ confirmPasswordLabel: 'אימות סיסמה',
53
+ submitButton: 'איפוס סיסמה',
54
+ backToLogin: 'חזרה להתחברות',
55
+ passwordMismatchError: 'הסיסמאות לא תואמות',
56
+ invalidTokenError: 'אסימון לא תקין',
57
+ successTitle: 'הסיסמה אופסה בהצלחה!',
58
+ successMessage: 'הסיסמה שלכם אופסה. כעת תוכלו להתחברות עם הסיסמה החדשה.',
59
+ goToLogin: 'מעבר להתחברות'
60
+ }
61
+
62
+ const englishDefaults = {
63
+ title: 'Reset Password',
64
+ invalidLinkTitle: 'Invalid Link',
65
+ invalidLinkMessage: 'This reset link is invalid or has expired',
66
+ newPasswordLabel: 'New Password',
67
+ confirmPasswordLabel: 'Confirm Password',
68
+ submitButton: 'Reset Password',
69
+ backToLogin: 'Back to Login',
70
+ passwordMismatchError: 'Passwords do not match',
71
+ invalidTokenError: 'Invalid token',
72
+ successTitle: 'Password Reset Successfully!',
73
+ successMessage: 'Your password has been reset. You can now log in with your new password.',
74
+ goToLogin: 'Go to Login'
75
+ }
76
+
77
+ const defaults = props.useHebrewDefaults ? hebrewDefaults : englishDefaults
78
+
79
+ return {
80
+ title: props.texts?.title ?? defaults.title,
81
+ invalidLinkTitle: props.texts?.invalidLinkTitle ?? defaults.invalidLinkTitle,
82
+ invalidLinkMessage: props.texts?.invalidLinkMessage ?? defaults.invalidLinkMessage,
83
+ newPasswordLabel: props.texts?.newPasswordLabel ?? defaults.newPasswordLabel,
84
+ confirmPasswordLabel: props.texts?.confirmPasswordLabel ?? defaults.confirmPasswordLabel,
85
+ submitButton: props.texts?.submitButton ?? defaults.submitButton,
86
+ backToLogin: props.texts?.backToLogin ?? defaults.backToLogin,
87
+ passwordMismatchError: props.texts?.passwordMismatchError ?? defaults.passwordMismatchError,
88
+ invalidTokenError: props.texts?.invalidTokenError ?? defaults.invalidTokenError,
89
+ successTitle: props.texts?.successTitle ?? defaults.successTitle,
90
+ successMessage: props.texts?.successMessage ?? defaults.successMessage,
91
+ goToLogin: props.texts?.goToLogin ?? defaults.goToLogin
92
+ }
93
+ })
94
+
95
+ const textDirection = computed(() => ({ 'auth-rtl': props.useHebrewDefaults }))
96
+
97
+ async function handleResetPassword() {
98
+ if (newPassword.value !== confirmPassword.value) {
99
+ error.value = texts.value.passwordMismatchError
100
+ return
101
+ }
102
+ if (!props.token) {
103
+ error.value = texts.value.invalidTokenError
104
+ return
105
+ }
106
+ try {
107
+ await resetPassword(props.token, newPassword.value)
108
+ internalSuccess.value = true
109
+ error.value = ''
110
+ } catch (err: unknown) {
111
+ error.value = err instanceof Error ? err.message : 'Reset failed'
112
+ }
113
+ }
114
+ </script>
115
+
116
+ <template>
117
+ <div v-if="!isValidToken" class="txt-center" :class="textDirection">
118
+ <h1 class="txt20 bold mb-1">
119
+ {{ texts.invalidLinkTitle }}
120
+ </h1>
121
+ <p class="opacity-7 mb-2">
122
+ {{ texts.invalidLinkMessage }}
123
+ </p>
124
+ <Btn :value="texts.backToLogin" @click="$emit('switchForm', 'login')" />
125
+ </div>
126
+ <div v-else-if="isSuccess" class="txt-center" :class="textDirection">
127
+ <Icon name="check_circle" size="4" class="txt-green mb-1" />
128
+ <h1 class="txt20 bold mb-1">
129
+ {{ texts.successTitle }}
130
+ </h1>
131
+ <p class="opacity-7 mb-2">
132
+ {{ texts.successMessage }}
133
+ </p>
134
+ <Btn :value="texts.goToLogin" @click="$emit('switchForm', 'login')" />
135
+ </div>
136
+ <form v-else :class="textDirection" @submit.prevent="handleResetPassword">
137
+ <h1 class="txt20 bold txt-center mb-1">
138
+ {{ texts.title }}
139
+ </h1>
140
+ <PasswordInput v-model="newPassword" class="mb-05" :label="texts.newPasswordLabel" autocomplete="new-password" />
141
+ <PasswordInput v-model="confirmPassword" :label="texts.confirmPasswordLabel" autocomplete="new-password" />
142
+ <Btn type="submit" class="w-100 mt-2" :value="texts.submitButton" />
143
+ <Btn thin flat class="txt-12 mt-075 underline block" :value="texts.backToLogin" @click="$emit('switchForm', 'login')" />
144
+ <p v-if="error" class="txt-center color-red txt-12 mt-1" v-text="error" />
145
+ </form>
146
+ </template>