nuxt-users 1.38.0 → 1.40.0

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 (94) hide show
  1. package/README.md +13 -1
  2. package/dist/cli.mjs +57 -27
  3. package/dist/module.d.mts +2 -2
  4. package/dist/module.d.ts +2 -2
  5. package/dist/module.json +4 -1
  6. package/dist/module.mjs +29 -7
  7. package/dist/runtime/assets/nuxt-users.css +1 -1
  8. package/dist/runtime/components/NUsersEmailConfirmation.d.vue.ts +5 -3
  9. package/dist/runtime/components/NUsersEmailConfirmation.vue +22 -15
  10. package/dist/runtime/components/NUsersEmailConfirmation.vue.d.ts +5 -3
  11. package/dist/runtime/components/NUsersGoogleLoginButton.d.vue.ts +4 -2
  12. package/dist/runtime/components/NUsersGoogleLoginButton.vue +5 -2
  13. package/dist/runtime/components/NUsersGoogleLoginButton.vue.d.ts +4 -2
  14. package/dist/runtime/components/NUsersList.vue +25 -11
  15. package/dist/runtime/components/NUsersLoginForm.d.vue.ts +13 -2
  16. package/dist/runtime/components/NUsersLoginForm.vue +35 -13
  17. package/dist/runtime/components/NUsersLoginForm.vue.d.ts +13 -2
  18. package/dist/runtime/components/NUsersLogoutLink.d.vue.ts +3 -4
  19. package/dist/runtime/components/NUsersLogoutLink.vue +8 -5
  20. package/dist/runtime/components/NUsersLogoutLink.vue.d.ts +3 -4
  21. package/dist/runtime/components/NUsersPasswordStrengthIndicator.d.vue.ts +6 -0
  22. package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue +17 -9
  23. package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue.d.ts +6 -0
  24. package/dist/runtime/components/NUsersProfileInfo.d.vue.ts +13 -1
  25. package/dist/runtime/components/NUsersProfileInfo.vue +23 -9
  26. package/dist/runtime/components/NUsersProfileInfo.vue.d.ts +13 -1
  27. package/dist/runtime/components/NUsersRegisterForm.d.vue.ts +26 -11
  28. package/dist/runtime/components/NUsersRegisterForm.vue +34 -16
  29. package/dist/runtime/components/NUsersRegisterForm.vue.d.ts +26 -11
  30. package/dist/runtime/components/NUsersResetPasswordForm.d.vue.ts +11 -2
  31. package/dist/runtime/components/NUsersResetPasswordForm.vue +25 -12
  32. package/dist/runtime/components/NUsersResetPasswordForm.vue.d.ts +11 -2
  33. package/dist/runtime/components/NUsersUserCard.d.vue.ts +2 -0
  34. package/dist/runtime/components/NUsersUserCard.vue +8 -4
  35. package/dist/runtime/components/NUsersUserCard.vue.d.ts +2 -0
  36. package/dist/runtime/components/NUsersUserForm.d.vue.ts +2 -2
  37. package/dist/runtime/components/NUsersUserForm.vue +5 -4
  38. package/dist/runtime/components/NUsersUserForm.vue.d.ts +2 -2
  39. package/dist/runtime/composables/useAuthentication.js +14 -0
  40. package/dist/runtime/composables/useNuxtUsersLocale.d.ts +15 -0
  41. package/dist/runtime/composables/useNuxtUsersLocale.js +27 -0
  42. package/dist/runtime/composables/usePasswordValidation.d.ts +1 -1
  43. package/dist/runtime/composables/usePublicPaths.js +2 -1
  44. package/dist/runtime/locales/en.d.ts +2 -0
  45. package/dist/runtime/locales/en.js +130 -0
  46. package/dist/runtime/locales/hu.d.ts +3 -0
  47. package/dist/runtime/locales/hu.js +188 -0
  48. package/dist/runtime/locales/index.d.ts +5 -0
  49. package/dist/runtime/locales/index.js +8 -0
  50. package/dist/runtime/server/api/nuxt-users/[id].delete.js +1 -1
  51. package/dist/runtime/server/api/nuxt-users/[id].get.js +1 -1
  52. package/dist/runtime/server/api/nuxt-users/[id].patch.js +1 -1
  53. package/dist/runtime/server/api/nuxt-users/auth/google/callback.get.js +1 -1
  54. package/dist/runtime/server/api/nuxt-users/auth/google/redirect.get.js +1 -1
  55. package/dist/runtime/server/api/nuxt-users/confirm-email.get.js +3 -3
  56. package/dist/runtime/server/api/nuxt-users/inactive.get.js +1 -2
  57. package/dist/runtime/server/api/nuxt-users/index.get.js +1 -2
  58. package/dist/runtime/server/api/nuxt-users/index.post.js +1 -1
  59. package/dist/runtime/server/api/nuxt-users/me.get.js +20 -13
  60. package/dist/runtime/server/api/nuxt-users/me.patch.js +1 -1
  61. package/dist/runtime/server/api/nuxt-users/password/forgot.post.js +2 -1
  62. package/dist/runtime/server/api/nuxt-users/password/index.patch.js +1 -1
  63. package/dist/runtime/server/api/nuxt-users/password/reset.post.d.ts +1 -1
  64. package/dist/runtime/server/api/nuxt-users/password/reset.post.js +4 -2
  65. package/dist/runtime/server/api/nuxt-users/session/index.delete.js +1 -1
  66. package/dist/runtime/server/api/nuxt-users/session/index.post.js +5 -3
  67. package/dist/runtime/server/composables/useServerAuth.js +1 -1
  68. package/dist/runtime/server/internal/index.d.ts +1 -7
  69. package/dist/runtime/server/internal/index.js +23 -7
  70. package/dist/runtime/server/middleware/authorization.server.js +22 -5
  71. package/dist/runtime/server/tasks/cleanup-tokens.d.ts +1 -1
  72. package/dist/runtime/server/utils/add-indexes.d.ts +3 -0
  73. package/dist/runtime/server/utils/add-indexes.js +17 -0
  74. package/dist/runtime/server/utils/google-oauth.js +2 -1
  75. package/dist/runtime/server/utils/index.d.ts +2 -2
  76. package/dist/runtime/server/utils/index.js +2 -2
  77. package/dist/runtime/server/utils/migrate.d.ts +6 -0
  78. package/dist/runtime/server/utils/migrate.js +10 -1
  79. package/dist/runtime/utils/deep-merge.d.ts +8 -0
  80. package/dist/runtime/utils/deep-merge.js +17 -0
  81. package/dist/runtime/utils/locale.d.ts +14 -0
  82. package/dist/runtime/utils/locale.js +38 -0
  83. package/dist/shared/{nuxt-users.BnOQs2LI.mjs → nuxt-users.DfZ7bc_P.mjs} +16 -8
  84. package/dist/shared/{nuxt-users.SXaMnaEL.d.mts → nuxt-users.XW6DYM7t.d.mts} +46 -2
  85. package/dist/shared/{nuxt-users.SXaMnaEL.d.ts → nuxt-users.XW6DYM7t.d.ts} +46 -2
  86. package/dist/utils.d.mts +4 -1
  87. package/dist/utils.d.ts +4 -1
  88. package/dist/utils.mjs +4 -1
  89. package/package.json +11 -6
  90. package/scripts/check-locale-consistency.ts +156 -0
  91. package/scripts/check-peer-dependencies.js +5 -5
  92. package/scripts/check-translations.ts +255 -0
  93. package/scripts/post-build.js +1 -1
  94. package/scripts/test-nuxt3.sh +78 -0
@@ -3,6 +3,21 @@ interface Props {
3
3
  apiEndpoint?: string;
4
4
  redirectTo?: string;
5
5
  loginLink?: string;
6
+ title?: string;
7
+ subtitle?: string;
8
+ nameLabel?: string;
9
+ namePlaceholder?: string;
10
+ emailLabel?: string;
11
+ emailPlaceholder?: string;
12
+ passwordLabel?: string;
13
+ passwordPlaceholder?: string;
14
+ confirmPasswordLabel?: string;
15
+ confirmPasswordPlaceholder?: string;
16
+ passwordMismatchError?: string;
17
+ submitLabel?: string;
18
+ submittingLabel?: string;
19
+ alreadyHaveAccountText?: string;
20
+ signInLinkText?: string;
6
21
  }
7
22
  interface RegistrationFormData {
8
23
  email: string;
@@ -10,9 +25,9 @@ interface RegistrationFormData {
10
25
  password: string;
11
26
  confirmPassword: string;
12
27
  }
13
- declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_17: {}, __VLS_19: {}, __VLS_21: {}, __VLS_23: {
28
+ declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_16: {}, __VLS_18: {}, __VLS_20: {}, __VLS_22: {
14
29
  message: string;
15
- }, __VLS_25: {
30
+ }, __VLS_24: {
16
31
  error: string;
17
32
  };
18
33
  type __VLS_Slots = {} & {
@@ -26,30 +41,30 @@ type __VLS_Slots = {} & {
26
41
  } & {
27
42
  'password-strength'?: (props: typeof __VLS_9) => any;
28
43
  } & {
29
- 'confirm-password-field'?: (props: typeof __VLS_17) => any;
44
+ 'confirm-password-field'?: (props: typeof __VLS_16) => any;
30
45
  } & {
31
- 'submit-button'?: (props: typeof __VLS_19) => any;
46
+ 'submit-button'?: (props: typeof __VLS_18) => any;
32
47
  } & {
33
- footer?: (props: typeof __VLS_21) => any;
48
+ footer?: (props: typeof __VLS_20) => any;
34
49
  } & {
35
- 'success-message'?: (props: typeof __VLS_23) => any;
50
+ 'success-message'?: (props: typeof __VLS_22) => any;
36
51
  } & {
37
- 'error-message'?: (props: typeof __VLS_25) => any;
52
+ 'error-message'?: (props: typeof __VLS_24) => any;
38
53
  };
39
54
  declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
55
+ error: (error: string) => any;
56
+ submit: (data: RegistrationFormData) => any;
40
57
  success: (data: {
41
58
  user: Omit<UserWithoutPassword, "active">;
42
59
  message: string;
43
60
  }) => any;
44
- error: (error: string) => any;
45
- submit: (data: RegistrationFormData) => any;
46
61
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
62
+ onError?: ((error: string) => any) | undefined;
63
+ onSubmit?: ((data: RegistrationFormData) => any) | undefined;
47
64
  onSuccess?: ((data: {
48
65
  user: Omit<UserWithoutPassword, "active">;
49
66
  message: string;
50
67
  }) => any) | undefined;
51
- onError?: ((error: string) => any) | undefined;
52
- onSubmit?: ((data: RegistrationFormData) => any) | undefined;
53
68
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
54
69
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
55
70
  declare const _default: typeof __VLS_export;
@@ -3,12 +3,29 @@ import { ref, computed, watch } from "vue";
3
3
  import { navigateTo } from "#app";
4
4
  import { useRuntimeConfig } from "#imports";
5
5
  import { validatePassword } from "nuxt-users/utils";
6
+ import { useNuxtUsersLocale } from "../composables/useNuxtUsersLocale";
6
7
  const { public: { nuxtUsers } } = useRuntimeConfig();
7
8
  const { passwordValidation } = nuxtUsers;
9
+ const { t } = useNuxtUsersLocale();
8
10
  const props = defineProps({
9
11
  apiEndpoint: { type: String, required: false },
10
12
  redirectTo: { type: String, required: false },
11
- loginLink: { type: String, required: false }
13
+ loginLink: { type: String, required: false },
14
+ title: { type: String, required: false },
15
+ subtitle: { type: String, required: false },
16
+ nameLabel: { type: String, required: false },
17
+ namePlaceholder: { type: String, required: false },
18
+ emailLabel: { type: String, required: false },
19
+ emailPlaceholder: { type: String, required: false },
20
+ passwordLabel: { type: String, required: false },
21
+ passwordPlaceholder: { type: String, required: false },
22
+ confirmPasswordLabel: { type: String, required: false },
23
+ confirmPasswordPlaceholder: { type: String, required: false },
24
+ passwordMismatchError: { type: String, required: false },
25
+ submitLabel: { type: String, required: false },
26
+ submittingLabel: { type: String, required: false },
27
+ alreadyHaveAccountText: { type: String, required: false },
28
+ signInLinkText: { type: String, required: false }
12
29
  });
13
30
  const emit = defineEmits(["success", "error", "submit"]);
14
31
  const apiEndpoint = computed(() => props.apiEndpoint || `${nuxtUsers?.apiBasePath}/register`);
@@ -25,7 +42,8 @@ const formData = ref({
25
42
  watch(() => formData.value.password, (newPassword) => {
26
43
  if (newPassword) {
27
44
  passwordValidationResult.value = validatePassword(newPassword, passwordValidation);
28
- } else {
45
+ }
46
+ if (!newPassword) {
29
47
  passwordValidationResult.value = null;
30
48
  }
31
49
  }, { immediate: true });
@@ -83,10 +101,10 @@ const handleSubmit = async () => {
83
101
  <slot name="header">
84
102
  <div class="n-users-register-header">
85
103
  <h2 class="n-users-register-title">
86
- Create Account
104
+ {{ props.title || t("register.title") }}
87
105
  </h2>
88
106
  <p class="n-users-register-subtitle">
89
- Sign up for a new account
107
+ {{ props.subtitle || t("register.subtitle") }}
90
108
  </p>
91
109
  </div>
92
110
  </slot>
@@ -94,13 +112,13 @@ const handleSubmit = async () => {
94
112
  <!-- Name field -->
95
113
  <slot name="name-field">
96
114
  <div class="n-users-form-group">
97
- <label for="name">Full Name</label>
115
+ <label for="name">{{ props.nameLabel || t("register.nameLabel") }}</label>
98
116
  <input
99
117
  id="name"
100
118
  v-model="formData.name"
101
119
  type="text"
102
120
  name="name"
103
- placeholder="Enter your full name"
121
+ :placeholder="props.namePlaceholder || t('register.namePlaceholder')"
104
122
  required
105
123
  >
106
124
  </div>
@@ -109,13 +127,13 @@ const handleSubmit = async () => {
109
127
  <!-- Email field -->
110
128
  <slot name="email-field">
111
129
  <div class="n-users-form-group">
112
- <label for="email">Email</label>
130
+ <label for="email">{{ props.emailLabel || t("common.email") }}</label>
113
131
  <input
114
132
  id="email"
115
133
  v-model="formData.email"
116
134
  type="email"
117
135
  name="email"
118
- placeholder="Enter your email"
136
+ :placeholder="props.emailPlaceholder || t('register.emailPlaceholder')"
119
137
  required
120
138
  >
121
139
  </div>
@@ -124,13 +142,13 @@ const handleSubmit = async () => {
124
142
  <!-- Password field -->
125
143
  <slot name="password-field">
126
144
  <div class="n-users-form-group">
127
- <label for="password">Password</label>
145
+ <label for="password">{{ props.passwordLabel || t("register.passwordLabel") }}</label>
128
146
  <input
129
147
  id="password"
130
148
  v-model="formData.password"
131
149
  type="password"
132
150
  name="password"
133
- placeholder="Enter your password"
151
+ :placeholder="props.passwordPlaceholder || t('register.passwordPlaceholder')"
134
152
  required
135
153
  :minlength="passwordValidation.minLength"
136
154
  >
@@ -151,13 +169,13 @@ const handleSubmit = async () => {
151
169
  <!-- Confirm Password field -->
152
170
  <slot name="confirm-password-field">
153
171
  <div class="n-users-form-group">
154
- <label for="confirmPassword">Confirm Password</label>
172
+ <label for="confirmPassword">{{ props.confirmPasswordLabel || t("register.confirmPasswordLabel") }}</label>
155
173
  <input
156
174
  id="confirmPassword"
157
175
  v-model="formData.confirmPassword"
158
176
  type="password"
159
177
  name="confirmPassword"
160
- placeholder="Confirm your password"
178
+ :placeholder="props.confirmPasswordPlaceholder || t('register.confirmPasswordPlaceholder')"
161
179
  required
162
180
  :class="{ 'n-users-input-error': !passwordsMatch }"
163
181
  >
@@ -165,7 +183,7 @@ const handleSubmit = async () => {
165
183
  v-if="!passwordsMatch && formData.confirmPassword"
166
184
  class="n-users-error-text"
167
185
  >
168
- Passwords do not match
186
+ {{ props.passwordMismatchError || t("register.passwordMismatch") }}
169
187
  </small>
170
188
  </div>
171
189
  </slot>
@@ -180,7 +198,7 @@ const handleSubmit = async () => {
180
198
  v-if="isLoading"
181
199
  class="n-users-loading-spinner"
182
200
  />
183
- {{ isLoading ? "Creating Account..." : "Create Account" }}
201
+ {{ isLoading ? props.submittingLabel || t("register.submitting") : props.submitLabel || t("register.submit") }}
184
202
  </button>
185
203
  </slot>
186
204
 
@@ -188,12 +206,12 @@ const handleSubmit = async () => {
188
206
  <slot name="footer">
189
207
  <div class="n-users-register-footer">
190
208
  <p class="n-users-login-link">
191
- Already have an account?
209
+ {{ props.alreadyHaveAccountText || t("register.alreadyHaveAccount") }}
192
210
  <a
193
211
  :href="loginLink || '/login'"
194
212
  class="n-users-link"
195
213
  >
196
- Sign in here
214
+ {{ props.signInLinkText || t("register.signInLink") }}
197
215
  </a>
198
216
  </p>
199
217
  </div>
@@ -3,6 +3,21 @@ interface Props {
3
3
  apiEndpoint?: string;
4
4
  redirectTo?: string;
5
5
  loginLink?: string;
6
+ title?: string;
7
+ subtitle?: string;
8
+ nameLabel?: string;
9
+ namePlaceholder?: string;
10
+ emailLabel?: string;
11
+ emailPlaceholder?: string;
12
+ passwordLabel?: string;
13
+ passwordPlaceholder?: string;
14
+ confirmPasswordLabel?: string;
15
+ confirmPasswordPlaceholder?: string;
16
+ passwordMismatchError?: string;
17
+ submitLabel?: string;
18
+ submittingLabel?: string;
19
+ alreadyHaveAccountText?: string;
20
+ signInLinkText?: string;
6
21
  }
7
22
  interface RegistrationFormData {
8
23
  email: string;
@@ -10,9 +25,9 @@ interface RegistrationFormData {
10
25
  password: string;
11
26
  confirmPassword: string;
12
27
  }
13
- declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_17: {}, __VLS_19: {}, __VLS_21: {}, __VLS_23: {
28
+ declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {}, __VLS_7: {}, __VLS_9: {}, __VLS_16: {}, __VLS_18: {}, __VLS_20: {}, __VLS_22: {
14
29
  message: string;
15
- }, __VLS_25: {
30
+ }, __VLS_24: {
16
31
  error: string;
17
32
  };
18
33
  type __VLS_Slots = {} & {
@@ -26,30 +41,30 @@ type __VLS_Slots = {} & {
26
41
  } & {
27
42
  'password-strength'?: (props: typeof __VLS_9) => any;
28
43
  } & {
29
- 'confirm-password-field'?: (props: typeof __VLS_17) => any;
44
+ 'confirm-password-field'?: (props: typeof __VLS_16) => any;
30
45
  } & {
31
- 'submit-button'?: (props: typeof __VLS_19) => any;
46
+ 'submit-button'?: (props: typeof __VLS_18) => any;
32
47
  } & {
33
- footer?: (props: typeof __VLS_21) => any;
48
+ footer?: (props: typeof __VLS_20) => any;
34
49
  } & {
35
- 'success-message'?: (props: typeof __VLS_23) => any;
50
+ 'success-message'?: (props: typeof __VLS_22) => any;
36
51
  } & {
37
- 'error-message'?: (props: typeof __VLS_25) => any;
52
+ 'error-message'?: (props: typeof __VLS_24) => any;
38
53
  };
39
54
  declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
55
+ error: (error: string) => any;
56
+ submit: (data: RegistrationFormData) => any;
40
57
  success: (data: {
41
58
  user: Omit<UserWithoutPassword, "active">;
42
59
  message: string;
43
60
  }) => any;
44
- error: (error: string) => any;
45
- submit: (data: RegistrationFormData) => any;
46
61
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
62
+ onError?: ((error: string) => any) | undefined;
63
+ onSubmit?: ((data: RegistrationFormData) => any) | undefined;
47
64
  onSuccess?: ((data: {
48
65
  user: Omit<UserWithoutPassword, "active">;
49
66
  message: string;
50
67
  }) => any) | undefined;
51
- onError?: ((error: string) => any) | undefined;
52
- onSubmit?: ((data: RegistrationFormData) => any) | undefined;
53
68
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
54
69
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
55
70
  declare const _default: typeof __VLS_export;
@@ -2,15 +2,24 @@ interface Props {
2
2
  updatePasswordEndpoint?: string;
3
3
  resetPasswordEndpoint?: string;
4
4
  redirectTo?: string;
5
+ titleReset?: string;
6
+ titleChange?: string;
7
+ currentPasswordLabel?: string;
8
+ newPasswordLabel?: string;
9
+ confirmPasswordLabel?: string;
10
+ submitResetLabel?: string;
11
+ submitUpdateLabel?: string;
12
+ submittingResetLabel?: string;
13
+ submittingUpdateLabel?: string;
5
14
  }
6
15
  declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
7
- success: (user: UserWithoutPassword) => any;
8
16
  error: (error: string) => any;
17
+ success: (user: UserWithoutPassword) => any;
9
18
  "password-error": (error: string) => any;
10
19
  "password-updated": () => any;
11
20
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
12
- onSuccess?: ((user: UserWithoutPassword) => any) | undefined;
13
21
  onError?: ((error: string) => any) | undefined;
22
+ onSuccess?: ((user: UserWithoutPassword) => any) | undefined;
14
23
  "onPassword-error"?: ((error: string) => any) | undefined;
15
24
  "onPassword-updated"?: (() => any) | undefined;
16
25
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -3,12 +3,23 @@ import { ref, watch, computed } from "vue";
3
3
  import { usePasswordValidation } from "../composables/usePasswordValidation";
4
4
  import { useRuntimeConfig, useRoute, useRouter } from "#imports";
5
5
  import NUsersPasswordStrengthIndicator from "./NUsersPasswordStrengthIndicator.vue";
6
+ import { useNuxtUsersLocale } from "../composables/useNuxtUsersLocale";
7
+ const { t } = useNuxtUsersLocale();
6
8
  const { public: { nuxtUsers } } = useRuntimeConfig();
7
9
  const moduleOptions = nuxtUsers;
8
10
  const props = defineProps({
9
11
  updatePasswordEndpoint: { type: String, required: false },
10
12
  resetPasswordEndpoint: { type: String, required: false },
11
- redirectTo: { type: String, required: false }
13
+ redirectTo: { type: String, required: false },
14
+ titleReset: { type: String, required: false },
15
+ titleChange: { type: String, required: false },
16
+ currentPasswordLabel: { type: String, required: false },
17
+ newPasswordLabel: { type: String, required: false },
18
+ confirmPasswordLabel: { type: String, required: false },
19
+ submitResetLabel: { type: String, required: false },
20
+ submitUpdateLabel: { type: String, required: false },
21
+ submittingResetLabel: { type: String, required: false },
22
+ submittingUpdateLabel: { type: String, required: false }
12
23
  });
13
24
  const emit = defineEmits(["success", "error", "password-error", "password-updated"]);
14
25
  const route = useRoute();
@@ -30,7 +41,8 @@ const passwordValidation = usePasswordValidation(moduleOptions);
30
41
  watch(() => passwordForm.value.newPassword, (newPassword) => {
31
42
  if (newPassword) {
32
43
  passwordValidation.validate(newPassword);
33
- } else {
44
+ }
45
+ if (!newPassword) {
34
46
  passwordValidation.clearValidation();
35
47
  }
36
48
  });
@@ -101,7 +113,8 @@ const resetPassword = async () => {
101
113
  const handleSubmit = () => {
102
114
  if (isPasswordReset.value) {
103
115
  resetPassword();
104
- } else {
116
+ }
117
+ if (!isPasswordReset.value) {
105
118
  updatePassword();
106
119
  }
107
120
  };
@@ -110,15 +123,15 @@ const handleSubmit = () => {
110
123
  <template>
111
124
  <div class="n-users-reset-password-container n-users-section">
112
125
  <h2 class="n-users-section-header">
113
- {{ isPasswordReset ? "Reset Password" : "Change Password" }}
126
+ {{ isPasswordReset ? props.titleReset || t("resetPassword.titleReset") : props.titleChange || t("resetPassword.titleChange") }}
114
127
  </h2>
115
128
 
116
129
  <div
117
130
  v-if="isPasswordReset"
118
131
  class="n-users-info-message"
119
132
  >
120
- <p>You are resetting your password using a secure link.</p>
121
- <p><strong>Email:</strong> {{ resetEmail }}</p>
133
+ <p>{{ t("resetPassword.secureResetInfo") }}</p>
134
+ <p><strong>{{ t("common.email") }}:</strong> {{ resetEmail }}</p>
122
135
  </div>
123
136
 
124
137
  <form @submit.prevent="handleSubmit">
@@ -130,7 +143,7 @@ const handleSubmit = () => {
130
143
  <label
131
144
  for="currentPassword"
132
145
  class="n-users-form-label"
133
- >Current Password</label>
146
+ >{{ props.currentPasswordLabel || t("resetPassword.currentPasswordLabel") }}</label>
134
147
  <input
135
148
  id="currentPassword"
136
149
  v-model="passwordForm.currentPassword"
@@ -145,7 +158,7 @@ const handleSubmit = () => {
145
158
  <label
146
159
  for="newPassword"
147
160
  class="n-users-form-label"
148
- >{{ isPasswordReset ? "New Password" : "New Password" }}</label>
161
+ >{{ props.newPasswordLabel || t("resetPassword.newPasswordLabel") }}</label>
149
162
  <input
150
163
  id="newPassword"
151
164
  v-model="passwordForm.newPassword"
@@ -175,7 +188,7 @@ const handleSubmit = () => {
175
188
  <label
176
189
  for="newPasswordConfirmation"
177
190
  class="n-users-form-label"
178
- >Confirm {{ isPasswordReset ? "New Password" : "New Password" }}</label>
191
+ >{{ props.confirmPasswordLabel || t("resetPassword.confirmPasswordLabel") }}</label>
179
192
  <input
180
193
  id="newPasswordConfirmation"
181
194
  v-model="passwordForm.newPasswordConfirmation"
@@ -206,10 +219,10 @@ const handleSubmit = () => {
206
219
  :disabled="isPasswordLoading"
207
220
  >
208
221
  <span v-if="isPasswordLoading">
209
- {{ isPasswordReset ? "Resetting..." : "Updating..." }}
222
+ {{ isPasswordReset ? props.submittingResetLabel || t("resetPassword.submittingReset") : props.submittingUpdateLabel || t("resetPassword.submittingUpdate") }}
210
223
  </span>
211
- <span v-else>
212
- {{ isPasswordReset ? "Reset Password" : "Update Password" }}
224
+ <span v-if="!isPasswordLoading">
225
+ {{ isPasswordReset ? props.submitResetLabel || t("resetPassword.submitReset") : props.submitUpdateLabel || t("resetPassword.submitUpdate") }}
213
226
  </span>
214
227
  </button>
215
228
  </form>
@@ -2,15 +2,24 @@ interface Props {
2
2
  updatePasswordEndpoint?: string;
3
3
  resetPasswordEndpoint?: string;
4
4
  redirectTo?: string;
5
+ titleReset?: string;
6
+ titleChange?: string;
7
+ currentPasswordLabel?: string;
8
+ newPasswordLabel?: string;
9
+ confirmPasswordLabel?: string;
10
+ submitResetLabel?: string;
11
+ submitUpdateLabel?: string;
12
+ submittingResetLabel?: string;
13
+ submittingUpdateLabel?: string;
5
14
  }
6
15
  declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
7
- success: (user: UserWithoutPassword) => any;
8
16
  error: (error: string) => any;
17
+ success: (user: UserWithoutPassword) => any;
9
18
  "password-error": (error: string) => any;
10
19
  "password-updated": () => any;
11
20
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
12
- onSuccess?: ((user: UserWithoutPassword) => any) | undefined;
13
21
  onError?: ((error: string) => any) | undefined;
22
+ onSuccess?: ((user: UserWithoutPassword) => any) | undefined;
14
23
  "onPassword-error"?: ((error: string) => any) | undefined;
15
24
  "onPassword-updated"?: (() => any) | undefined;
16
25
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -4,6 +4,8 @@ interface Props {
4
4
  index: number;
5
5
  displayFields?: string[];
6
6
  fieldLabels?: Record<string, string>;
7
+ editButtonText?: string;
8
+ deleteButtonText?: string;
7
9
  }
8
10
  declare var __VLS_1: {
9
11
  user: any;
@@ -3,11 +3,15 @@ import { computed, onMounted, ref } from "vue";
3
3
  import { useAuthentication } from "../composables/useAuthentication";
4
4
  import { useRuntimeConfig } from "#imports";
5
5
  import { defaultDisplayFields, defaultFieldLabels } from "nuxt-users/utils";
6
+ import { useNuxtUsersLocale } from "../composables/useNuxtUsersLocale";
7
+ const { t } = useNuxtUsersLocale();
6
8
  const props = defineProps({
7
9
  user: { type: null, required: true },
8
10
  index: { type: Number, required: true },
9
11
  displayFields: { type: Array, required: false, default: () => defaultDisplayFields },
10
- fieldLabels: { type: Object, required: false, default: () => defaultFieldLabels }
12
+ fieldLabels: { type: Object, required: false, default: () => defaultFieldLabels },
13
+ editButtonText: { type: String, required: false },
14
+ deleteButtonText: { type: String, required: false }
11
15
  });
12
16
  const emit = defineEmits(["delete", "editClick"]);
13
17
  const { public: { nuxtUsers } } = useRuntimeConfig();
@@ -43,7 +47,7 @@ const editUser = async (user) => {
43
47
  emit("editClick", user);
44
48
  };
45
49
  const deleteUser = async (user) => {
46
- if (!confirm(`Are you sure you want to delete user ${user.name}?`)) {
50
+ if (!confirm(t("userCard.deleteConfirm", [user.name]))) {
47
51
  return;
48
52
  }
49
53
  try {
@@ -86,7 +90,7 @@ const deleteUser = async (user) => {
86
90
  class="n-users-edit-btn"
87
91
  @click="editUser(user)"
88
92
  >
89
- Edit
93
+ {{ props.editButtonText || t("userCard.editButton") }}
90
94
  </button>
91
95
  </slot>
92
96
  <slot
@@ -100,7 +104,7 @@ const deleteUser = async (user) => {
100
104
  class="n-users-delete-btn"
101
105
  @click="deleteUser(user)"
102
106
  >
103
- Delete
107
+ {{ props.deleteButtonText || t("userCard.deleteButton") }}
104
108
  </button>
105
109
  </slot>
106
110
  </div>
@@ -4,6 +4,8 @@ interface Props {
4
4
  index: number;
5
5
  displayFields?: string[];
6
6
  fieldLabels?: Record<string, string>;
7
+ editButtonText?: string;
8
+ deleteButtonText?: string;
7
9
  }
8
10
  declare var __VLS_1: {
9
11
  user: any;
@@ -4,12 +4,12 @@ interface Props {
4
4
  }
5
5
  declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
6
6
  error: (error: unknown) => any;
7
- cancel: () => any;
8
7
  submit: (userData: User) => any;
8
+ cancel: () => any;
9
9
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
10
10
  onError?: ((error: unknown) => any) | undefined;
11
- onCancel?: (() => any) | undefined;
12
11
  onSubmit?: ((userData: User) => any) | undefined;
12
+ onCancel?: (() => any) | undefined;
13
13
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
14
  declare const _default: typeof __VLS_export;
15
15
  export default _default;
@@ -26,16 +26,16 @@ watch(() => props.user, (newUser) => {
26
26
  }
27
27
  });
28
28
  watch(() => formData.value.name, (name) => {
29
+ nameError.value = "";
29
30
  if (!name || name.trim().length < 3) {
30
31
  nameError.value = "Name must be at least 3 characters long";
31
- } else {
32
- nameError.value = "";
33
32
  }
34
33
  });
35
34
  watch(() => formData.value.password, (newPassword) => {
36
35
  if (newPassword) {
37
36
  passwordValidation.validate(newPassword);
38
- } else {
37
+ }
38
+ if (!newPassword) {
39
39
  passwordValidation.clearValidation();
40
40
  }
41
41
  });
@@ -58,7 +58,8 @@ const handleSubmit = async () => {
58
58
  method: "PATCH",
59
59
  body: userData
60
60
  });
61
- } else {
61
+ }
62
+ if (!isEditMode.value) {
62
63
  await $fetch(nuxtUsers.apiBasePath, {
63
64
  method: "POST",
64
65
  body: userData
@@ -4,12 +4,12 @@ interface Props {
4
4
  }
5
5
  declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
6
6
  error: (error: unknown) => any;
7
- cancel: () => any;
8
7
  submit: (userData: User) => any;
8
+ cancel: () => any;
9
9
  }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
10
10
  onError?: ((error: unknown) => any) | undefined;
11
- onCancel?: (() => any) | undefined;
12
11
  onSubmit?: ((userData: User) => any) | undefined;
12
+ onCancel?: (() => any) | undefined;
13
13
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
14
  declare const _default: typeof __VLS_export;
15
15
  export default _default;
@@ -45,6 +45,11 @@ export const useAuthentication = () => {
45
45
  lazy: false
46
46
  });
47
47
  if (error.value) {
48
+ const statusCode = error.value.statusCode || error.value.status;
49
+ if (statusCode === 401) {
50
+ user.value = null;
51
+ return null;
52
+ }
48
53
  throw new Error(error.value.message || "Failed to fetch user");
49
54
  }
50
55
  userData = data.value?.user || null;
@@ -74,6 +79,15 @@ export const useAuthentication = () => {
74
79
  }
75
80
  return userData;
76
81
  } catch (error) {
82
+ const statusCode = error?.statusCode || error?.status || error?.response?.status;
83
+ if (statusCode === 401) {
84
+ user.value = null;
85
+ if (import.meta.client) {
86
+ localStorage.removeItem("user");
87
+ sessionStorage.removeItem("user");
88
+ }
89
+ return null;
90
+ }
77
91
  console.error("Failed to fetch user:", error);
78
92
  user.value = null;
79
93
  if (import.meta.client) {
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Composable for accessing nuxt-users localized messages
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * const { t } = useNuxtUsersLocale()
7
+ * const title = t('login.title') // 'Welcome Back'
8
+ * const message = t('userCard.deleteConfirm', ['John']) // 'Are you sure you want to delete user John?'
9
+ * ```
10
+ */
11
+ export declare const useNuxtUsersLocale: () => {
12
+ t: (key: string, params?: (string | number)[]) => string;
13
+ currentLocale: import("vue").ComputedRef<string>;
14
+ fallbackLocale: import("vue").ComputedRef<string>;
15
+ };
@@ -0,0 +1,27 @@
1
+ import { computed } from "vue";
2
+ import { useRuntimeConfig } from "#app";
3
+ import { getTranslation } from "../utils/locale.js";
4
+ export const useNuxtUsersLocale = () => {
5
+ const { public: { nuxtUsers } } = useRuntimeConfig();
6
+ const moduleOptions = nuxtUsers;
7
+ const currentLocale = computed(() => {
8
+ return moduleOptions.locale?.default || "en";
9
+ });
10
+ const fallbackLocale = computed(() => {
11
+ return moduleOptions.locale?.fallbackLocale || "en";
12
+ });
13
+ const t = (key, params) => {
14
+ return getTranslation(
15
+ key,
16
+ currentLocale.value,
17
+ moduleOptions.locale?.texts,
18
+ fallbackLocale.value,
19
+ params
20
+ );
21
+ };
22
+ return {
23
+ t,
24
+ currentLocale,
25
+ fallbackLocale
26
+ };
27
+ };
@@ -25,7 +25,7 @@ export declare const usePasswordValidation: (moduleOptions?: RuntimeModuleOption
25
25
  isValid: import("vue").ComputedRef<boolean>;
26
26
  errors: import("vue").ComputedRef<string[]>;
27
27
  hints: import("vue").ComputedRef<string[]>;
28
- strength: import("vue").ComputedRef<"strong" | "weak" | "medium">;
28
+ strength: import("vue").ComputedRef<"weak" | "medium" | "strong">;
29
29
  score: import("vue").ComputedRef<number>;
30
30
  strengthColor: import("vue").ComputedRef<string>;
31
31
  strengthText: import("vue").ComputedRef<string>;