@bagelink/auth 1.12.3 → 1.12.5

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 (37) hide show
  1. package/dist/index.cjs +2 -1183
  2. package/dist/index.d.ts +0 -9
  3. package/dist/index.mjs +3 -1184
  4. package/dist/routes.d.ts +0 -36
  5. package/package.json +1 -1
  6. package/src/index.ts +0 -13
  7. package/src/routes.ts +0 -96
  8. package/dist/Callback-BHqVaZZm.cjs +0 -4
  9. package/dist/Callback-C-XghN_z.js +0 -4
  10. package/dist/ForgotPasswordPage-BV9tyhHl.cjs +0 -4
  11. package/dist/ForgotPasswordPage-DvttMGb0.js +0 -4
  12. package/dist/LoginPage-hv1wc54S.cjs +0 -4
  13. package/dist/LoginPage-klj1NV4J.js +0 -4
  14. package/dist/ResetPasswordPage-COPrJmW8.cjs +0 -4
  15. package/dist/ResetPasswordPage-nvQ4uupb.js +0 -4
  16. package/dist/SignupPage-m36w9PLJ.cjs +0 -4
  17. package/dist/SignupPage-oUFYApYW.js +0 -4
  18. package/dist/components/auth/ForgotPasswordForm.vue.d.ts +0 -23
  19. package/dist/components/auth/LoginForm.vue.d.ts +0 -58
  20. package/dist/components/auth/ResetPasswordForm.vue.d.ts +0 -28
  21. package/dist/components/auth/SignupForm.vue.d.ts +0 -34
  22. package/dist/components/index.d.ts +0 -4
  23. package/dist/pages/Callback.vue.d.ts +0 -2
  24. package/dist/pages/ForgotPasswordPage.vue.d.ts +0 -13
  25. package/dist/pages/LoginPage.vue.d.ts +0 -38
  26. package/dist/pages/ResetPasswordPage.vue.d.ts +0 -13
  27. package/dist/pages/SignupPage.vue.d.ts +0 -16
  28. package/src/components/auth/ForgotPasswordForm.vue +0 -97
  29. package/src/components/auth/LoginForm.vue +0 -258
  30. package/src/components/auth/ResetPasswordForm.vue +0 -156
  31. package/src/components/auth/SignupForm.vue +0 -231
  32. package/src/components/index.ts +0 -5
  33. package/src/pages/Callback.vue +0 -196
  34. package/src/pages/ForgotPasswordPage.vue +0 -42
  35. package/src/pages/LoginPage.vue +0 -68
  36. package/src/pages/ResetPasswordPage.vue +0 -47
  37. package/src/pages/SignupPage.vue +0 -46
@@ -1,258 +0,0 @@
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: false,
47
- google: false,
48
- microsoft: false,
49
- apple: false,
50
- okta: false,
51
- facebook: false,
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',
94
- emailLabel: 'Email',
95
- passwordLabel: 'Password',
96
- forgotPassword: 'Forgot Password',
97
- loginButton: 'Login',
98
- signupButton: 'Create Account',
99
- orText: 'or',
100
- githubButton: 'Continue with GitHub',
101
- googleButton: 'Continue with Google',
102
- microsoftButton: 'Continue with Microsoft',
103
- appleButton: 'Continue with Apple',
104
- oktaButton: 'Continue with Okta',
105
- facebookButton: 'Continue 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 class="h-20px pt-075">
252
- <p v-if="error" class="txt-center color-red txt-12">
253
- {{ error }}
254
- </p>
255
- </div>
256
- </div>
257
- </form>
258
- </template>
@@ -1,156 +0,0 @@
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
141
- v-model="newPassword" class="mb-05" :label="texts.newPasswordLabel"
142
- autocomplete="new-password"
143
- />
144
- <PasswordInput v-model="confirmPassword" :label="texts.confirmPasswordLabel" autocomplete="new-password" />
145
- <Btn type="submit" class="w-100 mt-2" :value="texts.submitButton" />
146
- <Btn
147
- thin flat class="txt-12 mt-075 underline block" :value="texts.backToLogin"
148
- @click="$emit('switchForm', 'login')"
149
- />
150
- <div class="h-20px pt-075">
151
- <p v-if="error" class="txt-center color-red txt-12">
152
- {{ error }}
153
- </p>
154
- </div>
155
- </form>
156
- </template>
@@ -1,231 +0,0 @@
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 SignupTexts {
7
- title?: string
8
- firstNameLabel?: string
9
- lastNameLabel?: string
10
- emailLabel?: string
11
- passwordLabel?: string
12
- confirmPasswordLabel?: string
13
- signupButton?: string
14
- alreadyHaveAccount?: string
15
- // Validation errors
16
- emailRequiredError?: string
17
- emailInvalidError?: string
18
- passwordRequiredError?: string
19
- passwordTooShortError?: string
20
- passwordMismatchError?: string
21
- firstNameRequiredError?: string
22
- lastNameRequiredError?: string
23
- }
24
-
25
- interface Props {
26
- showNames?: boolean
27
- useHebrewDefaults?: boolean
28
- errorState?: 'normal' | 'email-required' | 'email-invalid' | 'password-short' | 'password-mismatch' | 'name-required' | 'server-error'
29
- texts?: Partial<SignupTexts>
30
- }
31
-
32
- const props = withDefaults(defineProps<Props>(), {
33
- showNames: true,
34
- useHebrewDefaults: false,
35
- errorState: 'normal',
36
- texts: () => ({})
37
- })
38
-
39
- defineEmits<{
40
- switchForm: [form: string]
41
- }>()
42
-
43
- const { signup, login } = useAuth()
44
-
45
- // Internal error for actual validation
46
- const internalError = ref<string>('')
47
-
48
- // Use computed for error that reacts to errorState changes
49
- const error = computed(() => {
50
- if (props.errorState !== 'normal') {
51
- return getDevError()
52
- }
53
- return internalError.value
54
- })
55
-
56
- const form = ref({
57
- email: '',
58
- password: '',
59
- confirmPassword: '',
60
- first_name: '',
61
- last_name: '',
62
- })
63
-
64
- // Text configuration with conditional defaults
65
- const texts = computed(() => {
66
- const hebrewDefaults = {
67
- title: 'יצירת חשבון',
68
- firstNameLabel: 'שם פרטי',
69
- lastNameLabel: 'שם משפחה',
70
- emailLabel: 'איימיל',
71
- passwordLabel: 'סיסמה',
72
- confirmPasswordLabel: 'אימות סיסמה',
73
- signupButton: 'יצירת חשבון',
74
- alreadyHaveAccount: 'יש לך כבר חשבון?',
75
- // Validation errors
76
- emailRequiredError: 'איימיל נדרש',
77
- emailInvalidError: 'יש להזין כתובת איימיל תקינה',
78
- passwordRequiredError: 'סיסמה נדרשת',
79
- passwordTooShortError: 'הסיסמה חייבת להיות לפחות 8 תווים',
80
- passwordMismatchError: 'הסיסמאות לא תואמות',
81
- firstNameRequiredError: 'שם פרטי נדרש',
82
- lastNameRequiredError: 'שם משפחה נדרש'
83
- }
84
-
85
- const englishDefaults = {
86
- title: 'Create Account',
87
- firstNameLabel: 'First Name',
88
- lastNameLabel: 'Last Name',
89
- emailLabel: 'Email',
90
- passwordLabel: 'Password',
91
- confirmPasswordLabel: 'Confirm Password',
92
- signupButton: 'Create Account',
93
- alreadyHaveAccount: 'Already have an account?',
94
- // Validation errors
95
- emailRequiredError: 'Email is required',
96
- emailInvalidError: 'Please enter a valid email address',
97
- passwordRequiredError: 'Password is required',
98
- passwordTooShortError: 'Password must be at least 8 characters',
99
- passwordMismatchError: 'Passwords do not match',
100
- firstNameRequiredError: 'First name is required',
101
- lastNameRequiredError: 'Last name is required'
102
- }
103
-
104
- const defaults = props.useHebrewDefaults ? hebrewDefaults : englishDefaults
105
-
106
- return {
107
- title: props.texts.title || defaults.title,
108
- firstNameLabel: props.texts.firstNameLabel || defaults.firstNameLabel,
109
- lastNameLabel: props.texts.lastNameLabel || defaults.lastNameLabel,
110
- emailLabel: props.texts.emailLabel || defaults.emailLabel,
111
- passwordLabel: props.texts.passwordLabel || defaults.passwordLabel,
112
- confirmPasswordLabel: props.texts.confirmPasswordLabel || defaults.confirmPasswordLabel,
113
- signupButton: props.texts.signupButton || defaults.signupButton,
114
- alreadyHaveAccount: props.texts.alreadyHaveAccount || defaults.alreadyHaveAccount,
115
- // Validation errors
116
- emailRequiredError: props.texts.emailRequiredError || defaults.emailRequiredError,
117
- emailInvalidError: props.texts.emailInvalidError || defaults.emailInvalidError,
118
- passwordRequiredError: props.texts.passwordRequiredError || defaults.passwordRequiredError,
119
- passwordTooShortError: props.texts.passwordTooShortError || defaults.passwordTooShortError,
120
- passwordMismatchError: props.texts.passwordMismatchError || defaults.passwordMismatchError,
121
- firstNameRequiredError: props.texts.firstNameRequiredError || defaults.firstNameRequiredError,
122
- lastNameRequiredError: props.texts.lastNameRequiredError || defaults.lastNameRequiredError
123
- }
124
- })
125
-
126
- const textDirection = computed(() => ({ 'auth-rtl': props.useHebrewDefaults }))
127
-
128
- function getDevError() {
129
- switch (props.errorState) {
130
- case 'email-required': return texts.value.emailRequiredError
131
- case 'email-invalid': return texts.value.emailInvalidError
132
- case 'password-short': return texts.value.passwordTooShortError
133
- case 'password-mismatch': return texts.value.passwordMismatchError
134
- case 'name-required': return props.showNames ? texts.value.firstNameRequiredError : null
135
- case 'server-error': return props.useHebrewDefaults ? 'כתובת האימייל כבר קיימת או שגיאת שרת' : 'Email already exists or server error'
136
- default: return null
137
- }
138
- }
139
-
140
- function validateForm() {
141
- // Email validation
142
- if (!form.value.email.trim()) {
143
- return texts.value.emailRequiredError
144
- }
145
- const emailRegex = /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/
146
- if (!emailRegex.test(form.value.email)) {
147
- return texts.value.emailInvalidError
148
- }
149
-
150
- // Password validation
151
- if (!form.value.password) {
152
- return texts.value.passwordRequiredError
153
- }
154
- if (form.value.password.length < 8) {
155
- return texts.value.passwordTooShortError
156
- }
157
- if (form.value.password !== form.value.confirmPassword) {
158
- return texts.value.passwordMismatchError
159
- }
160
-
161
- // Name validation (only if names are shown)
162
- if (props.showNames) {
163
- if (!form.value.first_name.trim()) {
164
- return texts.value.firstNameRequiredError
165
- }
166
- if (!form.value.last_name.trim()) {
167
- return texts.value.lastNameRequiredError
168
- }
169
- }
170
-
171
- return null
172
- }
173
-
174
- async function handleSignup() {
175
- // Don't process if we're showing a development error
176
- if (props.errorState !== 'normal') {
177
- return
178
- }
179
-
180
- // Clear previous errors
181
- internalError.value = ''
182
-
183
- // Validate form first
184
- const validationError = validateForm()
185
- if (validationError) {
186
- internalError.value = validationError
187
- return
188
- }
189
- const { message, success } = await signup(form.value).catch((error) => {
190
- console.error(error)
191
- // Handle specific server errors
192
- const errorMessage = error.response?.data?.detail as string
193
- if (errorMessage?.toLowerCase().includes('email')) {
194
- return { success: false, message: 'Email already exists or invalid' }
195
- }
196
- if (errorMessage?.toLowerCase().includes('password')) {
197
- return { success: false, message: 'Password does not meet requirements' }
198
- }
199
- return { success: false, message: errorMessage || 'Registration failed. Please try again.' }
200
- })
201
- if (!success) {
202
- internalError.value = message as string
203
- return
204
- }
205
- await login({ email: form.value.email, password: form.value.password })
206
- }
207
- </script>
208
-
209
- <template>
210
- <form :class="textDirection" @submit.prevent="handleSignup">
211
- <h1 class="txt20 bold txt-center mb-1">
212
- {{ texts.title }}
213
- </h1>
214
-
215
- <TextInput v-if="props.showNames" v-model="form.first_name" :label="texts.firstNameLabel" />
216
- <TextInput v-if="props.showNames" v-model="form.last_name" :label="texts.lastNameLabel" />
217
- <TextInput v-model="form.email" type="email" :label="texts.emailLabel" autocomplete="username" />
218
- <PasswordInput v-model="form.password" class="mb-05" :label="texts.passwordLabel" />
219
- <PasswordInput v-model="form.confirmPassword" :label="texts.confirmPasswordLabel" />
220
- <Btn class="w-100 mt-2" :value="texts.signupButton" type="submit" />
221
- <Btn
222
- thin flat class="txt-12 mt-075 underline block" :value="texts.alreadyHaveAccount"
223
- @click="$emit('switchForm', 'login')"
224
- />
225
- <div class="h-20px pt-075">
226
- <p v-if="error" class="txt-center color-red txt-12">
227
- {{ error }}
228
- </p>
229
- </div>
230
- </form>
231
- </template>
@@ -1,5 +0,0 @@
1
- // Export form components
2
- export { default as ForgotPasswordForm } from './auth/ForgotPasswordForm.vue'
3
- export { default as LoginForm } from './auth/LoginForm.vue'
4
- export { default as ResetPasswordForm } from './auth/ResetPasswordForm.vue'
5
- export { default as SignupForm } from './auth/SignupForm.vue'