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.
- package/README.md +13 -1
- package/dist/cli.mjs +57 -27
- package/dist/module.d.mts +2 -2
- package/dist/module.d.ts +2 -2
- package/dist/module.json +4 -1
- package/dist/module.mjs +29 -7
- package/dist/runtime/assets/nuxt-users.css +1 -1
- package/dist/runtime/components/NUsersEmailConfirmation.d.vue.ts +5 -3
- package/dist/runtime/components/NUsersEmailConfirmation.vue +22 -15
- package/dist/runtime/components/NUsersEmailConfirmation.vue.d.ts +5 -3
- package/dist/runtime/components/NUsersGoogleLoginButton.d.vue.ts +4 -2
- package/dist/runtime/components/NUsersGoogleLoginButton.vue +5 -2
- package/dist/runtime/components/NUsersGoogleLoginButton.vue.d.ts +4 -2
- package/dist/runtime/components/NUsersList.vue +25 -11
- package/dist/runtime/components/NUsersLoginForm.d.vue.ts +13 -2
- package/dist/runtime/components/NUsersLoginForm.vue +35 -13
- package/dist/runtime/components/NUsersLoginForm.vue.d.ts +13 -2
- package/dist/runtime/components/NUsersLogoutLink.d.vue.ts +3 -4
- package/dist/runtime/components/NUsersLogoutLink.vue +8 -5
- package/dist/runtime/components/NUsersLogoutLink.vue.d.ts +3 -4
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.d.vue.ts +6 -0
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue +17 -9
- package/dist/runtime/components/NUsersPasswordStrengthIndicator.vue.d.ts +6 -0
- package/dist/runtime/components/NUsersProfileInfo.d.vue.ts +13 -1
- package/dist/runtime/components/NUsersProfileInfo.vue +23 -9
- package/dist/runtime/components/NUsersProfileInfo.vue.d.ts +13 -1
- package/dist/runtime/components/NUsersRegisterForm.d.vue.ts +26 -11
- package/dist/runtime/components/NUsersRegisterForm.vue +34 -16
- package/dist/runtime/components/NUsersRegisterForm.vue.d.ts +26 -11
- package/dist/runtime/components/NUsersResetPasswordForm.d.vue.ts +11 -2
- package/dist/runtime/components/NUsersResetPasswordForm.vue +25 -12
- package/dist/runtime/components/NUsersResetPasswordForm.vue.d.ts +11 -2
- package/dist/runtime/components/NUsersUserCard.d.vue.ts +2 -0
- package/dist/runtime/components/NUsersUserCard.vue +8 -4
- package/dist/runtime/components/NUsersUserCard.vue.d.ts +2 -0
- package/dist/runtime/components/NUsersUserForm.d.vue.ts +2 -2
- package/dist/runtime/components/NUsersUserForm.vue +5 -4
- package/dist/runtime/components/NUsersUserForm.vue.d.ts +2 -2
- package/dist/runtime/composables/useAuthentication.js +14 -0
- package/dist/runtime/composables/useNuxtUsersLocale.d.ts +15 -0
- package/dist/runtime/composables/useNuxtUsersLocale.js +27 -0
- package/dist/runtime/composables/usePasswordValidation.d.ts +1 -1
- package/dist/runtime/composables/usePublicPaths.js +2 -1
- package/dist/runtime/locales/en.d.ts +2 -0
- package/dist/runtime/locales/en.js +130 -0
- package/dist/runtime/locales/hu.d.ts +3 -0
- package/dist/runtime/locales/hu.js +188 -0
- package/dist/runtime/locales/index.d.ts +5 -0
- package/dist/runtime/locales/index.js +8 -0
- package/dist/runtime/server/api/nuxt-users/[id].delete.js +1 -1
- package/dist/runtime/server/api/nuxt-users/[id].get.js +1 -1
- package/dist/runtime/server/api/nuxt-users/[id].patch.js +1 -1
- package/dist/runtime/server/api/nuxt-users/auth/google/callback.get.js +1 -1
- package/dist/runtime/server/api/nuxt-users/auth/google/redirect.get.js +1 -1
- package/dist/runtime/server/api/nuxt-users/confirm-email.get.js +3 -3
- package/dist/runtime/server/api/nuxt-users/inactive.get.js +1 -2
- package/dist/runtime/server/api/nuxt-users/index.get.js +1 -2
- package/dist/runtime/server/api/nuxt-users/index.post.js +1 -1
- package/dist/runtime/server/api/nuxt-users/me.get.js +20 -13
- package/dist/runtime/server/api/nuxt-users/me.patch.js +1 -1
- package/dist/runtime/server/api/nuxt-users/password/forgot.post.js +2 -1
- package/dist/runtime/server/api/nuxt-users/password/index.patch.js +1 -1
- package/dist/runtime/server/api/nuxt-users/password/reset.post.d.ts +1 -1
- package/dist/runtime/server/api/nuxt-users/password/reset.post.js +4 -2
- package/dist/runtime/server/api/nuxt-users/session/index.delete.js +1 -1
- package/dist/runtime/server/api/nuxt-users/session/index.post.js +5 -3
- package/dist/runtime/server/composables/useServerAuth.js +1 -1
- package/dist/runtime/server/internal/index.d.ts +1 -7
- package/dist/runtime/server/internal/index.js +23 -7
- package/dist/runtime/server/middleware/authorization.server.js +22 -5
- package/dist/runtime/server/tasks/cleanup-tokens.d.ts +1 -1
- package/dist/runtime/server/utils/add-indexes.d.ts +3 -0
- package/dist/runtime/server/utils/add-indexes.js +17 -0
- package/dist/runtime/server/utils/google-oauth.js +2 -1
- package/dist/runtime/server/utils/index.d.ts +2 -2
- package/dist/runtime/server/utils/index.js +2 -2
- package/dist/runtime/server/utils/migrate.d.ts +6 -0
- package/dist/runtime/server/utils/migrate.js +10 -1
- package/dist/runtime/utils/deep-merge.d.ts +8 -0
- package/dist/runtime/utils/deep-merge.js +17 -0
- package/dist/runtime/utils/locale.d.ts +14 -0
- package/dist/runtime/utils/locale.js +38 -0
- package/dist/shared/{nuxt-users.BnOQs2LI.mjs → nuxt-users.DfZ7bc_P.mjs} +16 -8
- package/dist/shared/{nuxt-users.SXaMnaEL.d.mts → nuxt-users.XW6DYM7t.d.mts} +46 -2
- package/dist/shared/{nuxt-users.SXaMnaEL.d.ts → nuxt-users.XW6DYM7t.d.ts} +46 -2
- package/dist/utils.d.mts +4 -1
- package/dist/utils.d.ts +4 -1
- package/dist/utils.mjs +4 -1
- package/package.json +11 -6
- package/scripts/check-locale-consistency.ts +156 -0
- package/scripts/check-peer-dependencies.js +5 -5
- package/scripts/check-translations.ts +255 -0
- package/scripts/post-build.js +1 -1
- 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: {},
|
|
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
|
-
},
|
|
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
|
|
44
|
+
'confirm-password-field'?: (props: typeof __VLS_16) => any;
|
|
30
45
|
} & {
|
|
31
|
-
'submit-button'?: (props: typeof
|
|
46
|
+
'submit-button'?: (props: typeof __VLS_18) => any;
|
|
32
47
|
} & {
|
|
33
|
-
footer?: (props: typeof
|
|
48
|
+
footer?: (props: typeof __VLS_20) => any;
|
|
34
49
|
} & {
|
|
35
|
-
'success-message'?: (props: typeof
|
|
50
|
+
'success-message'?: (props: typeof __VLS_22) => any;
|
|
36
51
|
} & {
|
|
37
|
-
'error-message'?: (props: typeof
|
|
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
|
-
}
|
|
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
|
-
|
|
104
|
+
{{ props.title || t("register.title") }}
|
|
87
105
|
</h2>
|
|
88
106
|
<p class="n-users-register-subtitle">
|
|
89
|
-
|
|
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">
|
|
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="
|
|
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">
|
|
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="
|
|
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">
|
|
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="
|
|
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">
|
|
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="
|
|
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
|
-
|
|
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 ?
|
|
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
|
-
|
|
209
|
+
{{ props.alreadyHaveAccountText || t("register.alreadyHaveAccount") }}
|
|
192
210
|
<a
|
|
193
211
|
:href="loginLink || '/login'"
|
|
194
212
|
class="n-users-link"
|
|
195
213
|
>
|
|
196
|
-
|
|
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: {},
|
|
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
|
-
},
|
|
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
|
|
44
|
+
'confirm-password-field'?: (props: typeof __VLS_16) => any;
|
|
30
45
|
} & {
|
|
31
|
-
'submit-button'?: (props: typeof
|
|
46
|
+
'submit-button'?: (props: typeof __VLS_18) => any;
|
|
32
47
|
} & {
|
|
33
|
-
footer?: (props: typeof
|
|
48
|
+
footer?: (props: typeof __VLS_20) => any;
|
|
34
49
|
} & {
|
|
35
|
-
'success-message'?: (props: typeof
|
|
50
|
+
'success-message'?: (props: typeof __VLS_22) => any;
|
|
36
51
|
} & {
|
|
37
|
-
'error-message'?: (props: typeof
|
|
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
|
-
}
|
|
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
|
-
}
|
|
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 ?
|
|
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>
|
|
121
|
-
<p><strong>
|
|
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
|
-
>
|
|
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
|
-
>{{
|
|
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
|
-
>
|
|
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 ? "
|
|
222
|
+
{{ isPasswordReset ? props.submittingResetLabel || t("resetPassword.submittingReset") : props.submittingUpdateLabel || t("resetPassword.submittingUpdate") }}
|
|
210
223
|
</span>
|
|
211
|
-
<span v-
|
|
212
|
-
{{ isPasswordReset ?
|
|
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>;
|
|
@@ -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(
|
|
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
|
-
|
|
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
|
-
|
|
107
|
+
{{ props.deleteButtonText || t("userCard.deleteButton") }}
|
|
104
108
|
</button>
|
|
105
109
|
</slot>
|
|
106
110
|
</div>
|
|
@@ -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
|
-
}
|
|
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
|
-
}
|
|
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<"
|
|
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>;
|