@revenexx/cover 0.1.0 → 0.1.1
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/app/app.config.ts +1 -1
- package/app/components/account/address/AccountAddressCard.vue +69 -88
- package/app/components/auth/AuthRegisterPanel.vue +122 -194
- package/app/formkit.config.ts +21 -0
- package/app/interfaces/auth.ts +0 -2
- package/app/interfaces/validation.ts +1 -1
- package/app/validations/formValidationConfig.ts +0 -30
- package/nuxt.config.ts +0 -3
- package/package.json +2 -2
- package/server/api/account/orders.get.ts +6 -5
- package/server/api/account/profile.get.ts +3 -3
- package/server/api/account/profile.put.ts +6 -4
- package/server/api/auth/login.post.ts +2 -5
- package/server/api/auth/recovery.post.ts +5 -13
- package/server/api/auth/recovery.put.ts +5 -14
- package/server/api/auth/register.post.ts +21 -44
- package/server/api/orders/index.post.ts +28 -24
- package/server/api/payment/methods.post.ts +5 -4
- package/server/api/shipping/rates.post.ts +6 -4
- package/server/interfaces/auth.ts +1 -1
- package/server/services/ApiAccountService.ts +44 -0
- package/server/services/ApiAuthService.ts +15 -14
- package/server/services/ApiCartService.ts +45 -27
- package/server/services/ApiMarketService.ts +3 -5
- package/server/utils/accountService.ts +4 -5
- package/server/utils/authService.ts +0 -3
- package/server/utils/liveCatalog.ts +22 -13
- package/server/utils/liveInventories.ts +4 -4
- package/server/utils/liveOrders.ts +5 -3
- package/server/utils/livePrices.ts +10 -9
- package/server/utils/revenexxSdk.ts +162 -0
- package/app/validations/companyName.ts +0 -18
- package/app/validations/maxLength.ts +0 -12
- package/app/validations/optionalCompanyName.ts +0 -23
- package/app/validations/phoneNumber.ts +0 -19
- package/app/validations/termsRequired.ts +0 -4
- package/app/validations/zipCode.ts +0 -15
- package/server/services/SdkAccountService.ts +0 -56
- package/server/services/SdkAuthService.ts +0 -83
- package/server/utils/revenexxApi.ts +0 -136
- package/server/utils/shopSdk.ts +0 -88
package/app/app.config.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { DEFAULT_ICON_WEIGHT, nuxtUiIcons } from "./config/icons";
|
|
|
4
4
|
* Layer defaults for the BFF service registry. Every server data domain is
|
|
5
5
|
* resolved through a registry key — `mock` serves the bundled demo data.
|
|
6
6
|
* Consuming apps override individual keys in their own app.config.ts to
|
|
7
|
-
* switch a domain to a live implementation (e.g. accountService: "
|
|
7
|
+
* switch a domain to a live implementation (e.g. accountService: "api").
|
|
8
8
|
*
|
|
9
9
|
* `ui.icons` maps Nuxt UI's built-in icons to Solar in the default weight;
|
|
10
10
|
* the theme store re-applies them with the active theme's weight at runtime.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { AccountAddress, AccountAddressFormState } from "../../../interfaces/account/address-list";
|
|
3
|
+
import { COUNTRIES } from "../../../config/countries";
|
|
3
4
|
|
|
4
5
|
const { icon } = useIcons();
|
|
5
6
|
|
|
@@ -23,7 +24,6 @@ const emit = defineEmits<{
|
|
|
23
24
|
}>();
|
|
24
25
|
|
|
25
26
|
const { t } = useI18n();
|
|
26
|
-
const { validate: validateAddress } = useFormValidation<AccountAddressFormState>("accountAddress");
|
|
27
27
|
|
|
28
28
|
const confirmDeleteOpen = ref(false);
|
|
29
29
|
|
|
@@ -120,116 +120,97 @@ function confirmDelete() {
|
|
|
120
120
|
<div>{{ address.country }}</div>
|
|
121
121
|
</address>
|
|
122
122
|
|
|
123
|
-
<
|
|
123
|
+
<FormKit
|
|
124
124
|
v-else
|
|
125
|
-
|
|
126
|
-
:
|
|
127
|
-
class="space-y-4"
|
|
125
|
+
type="form"
|
|
126
|
+
:actions="false"
|
|
128
127
|
@submit="emit('submit')"
|
|
129
128
|
>
|
|
130
129
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
131
|
-
<
|
|
130
|
+
<FormKit
|
|
131
|
+
v-model="formState.label"
|
|
132
|
+
type="text"
|
|
132
133
|
:label="t('addresses.fields.label')"
|
|
133
134
|
name="label"
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
</UFormField>
|
|
141
|
-
<UFormField
|
|
135
|
+
validation="required|length:2,200"
|
|
136
|
+
outer-class="sm:col-span-2"
|
|
137
|
+
/>
|
|
138
|
+
<FormKit
|
|
139
|
+
v-model="formState.company"
|
|
140
|
+
type="text"
|
|
142
141
|
:label="t('addresses.fields.company')"
|
|
143
142
|
name="company"
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
<UFormField
|
|
143
|
+
validation="companyName"
|
|
144
|
+
:validation-messages="{ companyName: t('validation.invalidCompanyName') }"
|
|
145
|
+
autocomplete="organization"
|
|
146
|
+
outer-class="sm:col-span-2"
|
|
147
|
+
/>
|
|
148
|
+
<FormKit
|
|
149
|
+
v-model="formState.firstName"
|
|
150
|
+
type="text"
|
|
153
151
|
:label="t('addresses.fields.firstName')"
|
|
154
152
|
name="firstName"
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
</UFormField>
|
|
162
|
-
<UFormField
|
|
153
|
+
validation="required|length:2,100"
|
|
154
|
+
autocomplete="given-name"
|
|
155
|
+
/>
|
|
156
|
+
<FormKit
|
|
157
|
+
v-model="formState.lastName"
|
|
158
|
+
type="text"
|
|
163
159
|
:label="t('addresses.fields.lastName')"
|
|
164
160
|
name="lastName"
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
</UFormField>
|
|
172
|
-
<UFormField
|
|
161
|
+
validation="required|length:2,100"
|
|
162
|
+
autocomplete="family-name"
|
|
163
|
+
/>
|
|
164
|
+
<FormKit
|
|
165
|
+
v-model="formState.street"
|
|
166
|
+
type="text"
|
|
173
167
|
:label="t('addresses.fields.street')"
|
|
174
168
|
name="street"
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
</UFormField>
|
|
182
|
-
<UFormField
|
|
169
|
+
validation="required|length:2,200"
|
|
170
|
+
autocomplete="street-address"
|
|
171
|
+
/>
|
|
172
|
+
<FormKit
|
|
173
|
+
v-model="formState.streetNumber"
|
|
174
|
+
type="text"
|
|
183
175
|
:label="t('addresses.fields.streetNumber')"
|
|
184
176
|
name="streetNumber"
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
</UFormField>
|
|
191
|
-
<UFormField
|
|
177
|
+
validation="required"
|
|
178
|
+
/>
|
|
179
|
+
<FormKit
|
|
180
|
+
v-model="formState.zip"
|
|
181
|
+
type="text"
|
|
192
182
|
:label="t('addresses.fields.zip')"
|
|
193
183
|
name="zip"
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
<UFormField
|
|
184
|
+
validation="required|zip"
|
|
185
|
+
:validation-messages="{ zip: t('validation.invalidZipCode') }"
|
|
186
|
+
autocomplete="postal-code"
|
|
187
|
+
/>
|
|
188
|
+
<FormKit
|
|
189
|
+
v-model="formState.city"
|
|
190
|
+
type="text"
|
|
202
191
|
:label="t('addresses.fields.city')"
|
|
203
192
|
name="city"
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
</UFormField>
|
|
211
|
-
<UFormField
|
|
193
|
+
validation="required|length:2,100"
|
|
194
|
+
autocomplete="address-level2"
|
|
195
|
+
/>
|
|
196
|
+
<FormKit
|
|
197
|
+
v-model="formState.country"
|
|
198
|
+
type="select"
|
|
212
199
|
:label="t('addresses.fields.country')"
|
|
213
200
|
name="country"
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
<UFormField
|
|
201
|
+
validation="required"
|
|
202
|
+
:options="COUNTRIES"
|
|
203
|
+
outer-class="sm:col-span-2"
|
|
204
|
+
/>
|
|
205
|
+
<FormKit
|
|
206
|
+
v-model="formState.type"
|
|
207
|
+
type="select"
|
|
222
208
|
:label="t('addresses.fields.type')"
|
|
223
209
|
name="type"
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
:items="typeOptions"
|
|
229
|
-
value-key="value"
|
|
230
|
-
class="w-full"
|
|
231
|
-
/>
|
|
232
|
-
</UFormField>
|
|
210
|
+
validation="required"
|
|
211
|
+
:options="typeOptions"
|
|
212
|
+
outer-class="sm:col-span-2"
|
|
213
|
+
/>
|
|
233
214
|
<div class="sm:col-span-2">
|
|
234
215
|
<UCheckbox
|
|
235
216
|
:model-value="formState.isDefault"
|
|
@@ -256,7 +237,7 @@ function confirmDelete() {
|
|
|
256
237
|
:label="t('addresses.actions.save')"
|
|
257
238
|
/>
|
|
258
239
|
</div>
|
|
259
|
-
</
|
|
240
|
+
</FormKit>
|
|
260
241
|
</UCard>
|
|
261
242
|
|
|
262
243
|
<UModal
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { COUNTRIES } from "../../config/countries";
|
|
3
|
-
import { required } from "../../validations/required";
|
|
4
|
-
import { zipCode } from "../../validations/zipCode";
|
|
5
|
-
import type { FormError } from "@nuxt/ui";
|
|
6
|
-
|
|
7
3
|
import type { RegisterFormState, RegistrationMode, RegistrationProfile } from "../../interfaces/auth";
|
|
8
4
|
|
|
9
5
|
/**
|
|
@@ -47,36 +43,13 @@ const modes: { value: RegistrationMode; icon: string }[] = [
|
|
|
47
43
|
{ value: "existing", icon: "key" },
|
|
48
44
|
];
|
|
49
45
|
|
|
50
|
-
const salutationItems = computed(() =>
|
|
51
|
-
|
|
46
|
+
const salutationItems = computed(() => [
|
|
47
|
+
{ value: "", label: "—" },
|
|
48
|
+
...(["mr", "ms", "none"] as const).map(value => ({
|
|
52
49
|
value,
|
|
53
50
|
label: t(`auth.register.fields2.salutations.${value}`),
|
|
54
|
-
}))
|
|
55
|
-
|
|
56
|
-
const countryItems = COUNTRIES;
|
|
57
|
-
|
|
58
|
-
/* ---- validation: static base + mode-dependent fields ------------------- */
|
|
59
|
-
const { validate: validateBase } = useFormValidation<RegisterFormState>("register");
|
|
60
|
-
|
|
61
|
-
function validate(formState: RegisterFormState): FormError[] {
|
|
62
|
-
const errors = validateBase(formState);
|
|
63
|
-
const push = (name: string, key: string | null) => {
|
|
64
|
-
if (key !== null) {
|
|
65
|
-
errors.push({ name, message: t(key) });
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
if (formState.mode === "new") {
|
|
69
|
-
push("street", required(formState.street));
|
|
70
|
-
push("streetNumber", required(formState.streetNumber));
|
|
71
|
-
push("zip", required(formState.zip) ?? zipCode(formState.zip));
|
|
72
|
-
push("city", required(formState.city));
|
|
73
|
-
push("country", required(formState.country));
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
push("customerNumber", required(formState.customerNumber));
|
|
77
|
-
}
|
|
78
|
-
return errors;
|
|
79
|
-
}
|
|
51
|
+
})),
|
|
52
|
+
]);
|
|
80
53
|
|
|
81
54
|
function buildProfile(): RegistrationProfile {
|
|
82
55
|
return {
|
|
@@ -164,9 +137,9 @@ async function onSubmit(): Promise<void> {
|
|
|
164
137
|
</div>
|
|
165
138
|
</fieldset>
|
|
166
139
|
|
|
167
|
-
<
|
|
168
|
-
|
|
169
|
-
:
|
|
140
|
+
<FormKit
|
|
141
|
+
type="form"
|
|
142
|
+
:actions="false"
|
|
170
143
|
class="space-y-7 pt-7"
|
|
171
144
|
@submit="onSubmit"
|
|
172
145
|
>
|
|
@@ -175,46 +148,38 @@ async function onSubmit(): Promise<void> {
|
|
|
175
148
|
<h3 class="text-xs font-semibold uppercase tracking-wide text-muted">
|
|
176
149
|
{{ t('auth.register.sections.company') }}
|
|
177
150
|
</h3>
|
|
178
|
-
<
|
|
151
|
+
<FormKit
|
|
152
|
+
v-model="state.company"
|
|
153
|
+
type="text"
|
|
179
154
|
:label="t('auth.register.fields.company')"
|
|
180
155
|
name="company"
|
|
181
|
-
required
|
|
182
|
-
:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
autocomplete="organization"
|
|
187
|
-
class="w-full"
|
|
188
|
-
/>
|
|
189
|
-
</UFormField>
|
|
156
|
+
validation="required|companyName"
|
|
157
|
+
:validation-messages="{ companyName: t('validation.invalidCompanyName') }"
|
|
158
|
+
:help="t('auth.register.companyRequiredHint')"
|
|
159
|
+
autocomplete="organization"
|
|
160
|
+
/>
|
|
190
161
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
191
|
-
<
|
|
162
|
+
<FormKit
|
|
192
163
|
v-if="state.mode === 'existing'"
|
|
164
|
+
v-model="state.customerNumber"
|
|
165
|
+
type="text"
|
|
193
166
|
:label="t('auth.register.fields2.customerNumber')"
|
|
194
167
|
name="customerNumber"
|
|
195
|
-
required
|
|
196
|
-
:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
/>
|
|
202
|
-
</UFormField>
|
|
203
|
-
<UFormField
|
|
168
|
+
validation="required"
|
|
169
|
+
:help="t('auth.register.fields2.customerNumberHint')"
|
|
170
|
+
/>
|
|
171
|
+
<FormKit
|
|
172
|
+
v-model="state.vatId"
|
|
173
|
+
type="text"
|
|
204
174
|
:label="t('auth.register.fields2.vatId')"
|
|
205
175
|
name="vatId"
|
|
206
|
-
:
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
v-model="state.vatId"
|
|
210
|
-
class="w-full"
|
|
211
|
-
placeholder="DE123456789"
|
|
212
|
-
/>
|
|
213
|
-
</UFormField>
|
|
176
|
+
:help="t('auth.register.fields2.vatIdHint')"
|
|
177
|
+
placeholder="DE123456789"
|
|
178
|
+
/>
|
|
214
179
|
</div>
|
|
215
180
|
</section>
|
|
216
181
|
|
|
217
|
-
<!-- Billing address (new customers) -->
|
|
182
|
+
<!-- Billing address (new customers only) -->
|
|
218
183
|
<section
|
|
219
184
|
v-if="state.mode === 'new'"
|
|
220
185
|
class="space-y-4"
|
|
@@ -223,66 +188,52 @@ async function onSubmit(): Promise<void> {
|
|
|
223
188
|
{{ t('auth.register.sections.address') }}
|
|
224
189
|
</h3>
|
|
225
190
|
<div class="grid grid-cols-3 gap-4">
|
|
226
|
-
<
|
|
191
|
+
<FormKit
|
|
192
|
+
v-model="state.street"
|
|
193
|
+
type="text"
|
|
227
194
|
:label="t('auth.register.fields2.street')"
|
|
228
195
|
name="street"
|
|
229
|
-
required
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
/>
|
|
237
|
-
</UFormField>
|
|
238
|
-
<UFormField
|
|
196
|
+
validation="required"
|
|
197
|
+
autocomplete="address-line1"
|
|
198
|
+
outer-class="col-span-2"
|
|
199
|
+
/>
|
|
200
|
+
<FormKit
|
|
201
|
+
v-model="state.streetNumber"
|
|
202
|
+
type="text"
|
|
239
203
|
:label="t('auth.register.fields2.streetNumber')"
|
|
240
204
|
name="streetNumber"
|
|
241
|
-
required
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
v-model="state.streetNumber"
|
|
245
|
-
autocomplete="address-line2"
|
|
246
|
-
class="w-full"
|
|
247
|
-
/>
|
|
248
|
-
</UFormField>
|
|
205
|
+
validation="required"
|
|
206
|
+
autocomplete="address-line2"
|
|
207
|
+
/>
|
|
249
208
|
</div>
|
|
250
209
|
<div class="grid grid-cols-3 gap-4">
|
|
251
|
-
<
|
|
210
|
+
<FormKit
|
|
211
|
+
v-model="state.zip"
|
|
212
|
+
type="text"
|
|
252
213
|
:label="t('auth.register.fields2.zip')"
|
|
253
214
|
name="zip"
|
|
254
|
-
required
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
</UFormField>
|
|
262
|
-
<UFormField
|
|
215
|
+
validation="required|zip"
|
|
216
|
+
:validation-messages="{ zip: t('validation.invalidZipCode') }"
|
|
217
|
+
autocomplete="postal-code"
|
|
218
|
+
/>
|
|
219
|
+
<FormKit
|
|
220
|
+
v-model="state.city"
|
|
221
|
+
type="text"
|
|
263
222
|
:label="t('auth.register.fields2.city')"
|
|
264
223
|
name="city"
|
|
265
|
-
required
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
v-model="state.city"
|
|
270
|
-
autocomplete="address-level2"
|
|
271
|
-
class="w-full"
|
|
272
|
-
/>
|
|
273
|
-
</UFormField>
|
|
224
|
+
validation="required"
|
|
225
|
+
autocomplete="address-level2"
|
|
226
|
+
outer-class="col-span-2"
|
|
227
|
+
/>
|
|
274
228
|
</div>
|
|
275
|
-
<
|
|
229
|
+
<FormKit
|
|
230
|
+
v-model="state.country"
|
|
231
|
+
type="select"
|
|
276
232
|
:label="t('auth.register.fields2.country')"
|
|
277
233
|
name="country"
|
|
278
|
-
required
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
v-model="state.country"
|
|
282
|
-
:items="countryItems"
|
|
283
|
-
class="w-full"
|
|
284
|
-
/>
|
|
285
|
-
</UFormField>
|
|
234
|
+
validation="required"
|
|
235
|
+
:options="COUNTRIES"
|
|
236
|
+
/>
|
|
286
237
|
</section>
|
|
287
238
|
|
|
288
239
|
<!-- Contact person -->
|
|
@@ -291,63 +242,47 @@ async function onSubmit(): Promise<void> {
|
|
|
291
242
|
{{ t('auth.register.sections.contact') }}
|
|
292
243
|
</h3>
|
|
293
244
|
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
|
294
|
-
<
|
|
245
|
+
<FormKit
|
|
246
|
+
v-model="state.salutation"
|
|
247
|
+
type="select"
|
|
295
248
|
:label="t('auth.register.fields2.salutation')"
|
|
296
249
|
name="salutation"
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
/>
|
|
303
|
-
</UFormField>
|
|
304
|
-
<UFormField
|
|
250
|
+
:options="salutationItems"
|
|
251
|
+
/>
|
|
252
|
+
<FormKit
|
|
253
|
+
v-model="state.firstName"
|
|
254
|
+
type="text"
|
|
305
255
|
:label="t('auth.register.fields.firstName')"
|
|
306
256
|
name="firstName"
|
|
307
|
-
required
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
/>
|
|
314
|
-
</UFormField>
|
|
315
|
-
<UFormField
|
|
257
|
+
validation="required"
|
|
258
|
+
autocomplete="given-name"
|
|
259
|
+
/>
|
|
260
|
+
<FormKit
|
|
261
|
+
v-model="state.lastName"
|
|
262
|
+
type="text"
|
|
316
263
|
:label="t('auth.register.fields.lastName')"
|
|
317
264
|
name="lastName"
|
|
318
|
-
required
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
v-model="state.lastName"
|
|
322
|
-
autocomplete="family-name"
|
|
323
|
-
class="w-full"
|
|
324
|
-
/>
|
|
325
|
-
</UFormField>
|
|
265
|
+
validation="required"
|
|
266
|
+
autocomplete="family-name"
|
|
267
|
+
/>
|
|
326
268
|
</div>
|
|
327
269
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
328
|
-
<
|
|
270
|
+
<FormKit
|
|
271
|
+
v-model="state.jobTitle"
|
|
272
|
+
type="text"
|
|
329
273
|
:label="t('auth.register.fields2.jobTitle')"
|
|
330
274
|
name="jobTitle"
|
|
331
|
-
:
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
/>
|
|
338
|
-
</UFormField>
|
|
339
|
-
<UFormField
|
|
275
|
+
:help="t('auth.register.fields2.jobTitleHint')"
|
|
276
|
+
autocomplete="organization-title"
|
|
277
|
+
/>
|
|
278
|
+
<FormKit
|
|
279
|
+
v-model="state.phone"
|
|
280
|
+
type="tel"
|
|
340
281
|
:label="t('auth.register.fields2.phone')"
|
|
341
282
|
name="phone"
|
|
342
|
-
:
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
v-model="state.phone"
|
|
346
|
-
type="tel"
|
|
347
|
-
autocomplete="tel"
|
|
348
|
-
class="w-full"
|
|
349
|
-
/>
|
|
350
|
-
</UFormField>
|
|
283
|
+
:help="t('auth.register.fields2.phoneHint')"
|
|
284
|
+
autocomplete="tel"
|
|
285
|
+
/>
|
|
351
286
|
</div>
|
|
352
287
|
</section>
|
|
353
288
|
|
|
@@ -356,53 +291,46 @@ async function onSubmit(): Promise<void> {
|
|
|
356
291
|
<h3 class="text-xs font-semibold uppercase tracking-wide text-muted">
|
|
357
292
|
{{ t('auth.register.sections.account') }}
|
|
358
293
|
</h3>
|
|
359
|
-
<
|
|
294
|
+
<FormKit
|
|
295
|
+
v-model="state.email"
|
|
296
|
+
type="email"
|
|
360
297
|
:label="t('auth.register.fields.email')"
|
|
361
298
|
name="email"
|
|
362
|
-
required
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
type="email"
|
|
367
|
-
autocomplete="email"
|
|
368
|
-
class="w-full"
|
|
369
|
-
:placeholder="t('auth.register.fields.emailPlaceholder')"
|
|
370
|
-
/>
|
|
371
|
-
</UFormField>
|
|
299
|
+
validation="required|email"
|
|
300
|
+
autocomplete="email"
|
|
301
|
+
:placeholder="t('auth.register.fields.emailPlaceholder')"
|
|
302
|
+
/>
|
|
372
303
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
373
|
-
<
|
|
304
|
+
<FormKit
|
|
305
|
+
v-model="state.password"
|
|
306
|
+
type="password"
|
|
374
307
|
:label="t('auth.register.fields.password')"
|
|
375
308
|
name="password"
|
|
376
|
-
required
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
/>
|
|
384
|
-
</UFormField>
|
|
385
|
-
<UFormField
|
|
309
|
+
validation="required|length:8"
|
|
310
|
+
autocomplete="new-password"
|
|
311
|
+
:placeholder="t('auth.register.fields.passwordPlaceholder')"
|
|
312
|
+
/>
|
|
313
|
+
<FormKit
|
|
314
|
+
v-model="state.passwordConfirm"
|
|
315
|
+
type="password"
|
|
386
316
|
:label="t('auth.register.fields.passwordConfirm')"
|
|
387
317
|
name="passwordConfirm"
|
|
388
|
-
required
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
autocomplete="new-password"
|
|
393
|
-
:placeholder="t('auth.register.fields.passwordConfirmPlaceholder')"
|
|
394
|
-
/>
|
|
395
|
-
</UFormField>
|
|
318
|
+
validation="required|confirm:password"
|
|
319
|
+
autocomplete="new-password"
|
|
320
|
+
:placeholder="t('auth.register.fields.passwordConfirmPlaceholder')"
|
|
321
|
+
/>
|
|
396
322
|
</div>
|
|
397
323
|
</section>
|
|
398
324
|
|
|
399
|
-
<
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
325
|
+
<FormKit
|
|
326
|
+
v-model="state.acceptTerms"
|
|
327
|
+
type="checkbox"
|
|
328
|
+
:label="t('auth.register.fields.acceptTerms')"
|
|
329
|
+
name="acceptTerms"
|
|
330
|
+
validation="accepted"
|
|
331
|
+
:validation-messages="{ accepted: t('validation.termsRequired') }"
|
|
332
|
+
:help="t('auth.register.fields.acceptTermsDescription')"
|
|
333
|
+
/>
|
|
406
334
|
|
|
407
335
|
<UAlert
|
|
408
336
|
color="info"
|
|
@@ -426,6 +354,6 @@ async function onSubmit(): Promise<void> {
|
|
|
426
354
|
:loading="loading"
|
|
427
355
|
:label="t('auth.register.submit')"
|
|
428
356
|
/>
|
|
429
|
-
</
|
|
357
|
+
</FormKit>
|
|
430
358
|
</div>
|
|
431
359
|
</template>
|
package/app/formkit.config.ts
CHANGED
|
@@ -21,6 +21,27 @@ export default defineFormKitConfig({
|
|
|
21
21
|
props: ["minDays", "maxDays", "disableWeekends"],
|
|
22
22
|
}),
|
|
23
23
|
},
|
|
24
|
+
rules: {
|
|
25
|
+
zip(node) {
|
|
26
|
+
const v = String(node.value ?? "").trim();
|
|
27
|
+
if (!/^\d{3,5}$/.test(v)) return false;
|
|
28
|
+
if (/^0+$/.test(v) || v === "99999") return false;
|
|
29
|
+
return true;
|
|
30
|
+
},
|
|
31
|
+
// Optional company name: empty is always valid; when filled, enforce
|
|
32
|
+
// length (3–64) and restrict to allowed characters.
|
|
33
|
+
companyName(node) {
|
|
34
|
+
const v = String(node.value ?? "").trim();
|
|
35
|
+
if (v === "") return true;
|
|
36
|
+
if (v.length < 3 || v.length > 64) return false;
|
|
37
|
+
return /^[a-zA-Z0-9äöüÄÖÜß\s.,'-]+$/.test(v);
|
|
38
|
+
},
|
|
39
|
+
phoneNumber(node) {
|
|
40
|
+
const v = String(node.value ?? "").trim();
|
|
41
|
+
if (v === "") return true;
|
|
42
|
+
return /^[+\d]?(?:[\d\s\-.()]*)$/.test(v);
|
|
43
|
+
},
|
|
44
|
+
},
|
|
24
45
|
config: {
|
|
25
46
|
classes: generateClasses({
|
|
26
47
|
global: {
|
package/app/interfaces/auth.ts
CHANGED
|
@@ -52,8 +52,6 @@ export interface LoginInput {
|
|
|
52
52
|
export interface StoredSession {
|
|
53
53
|
id: string;
|
|
54
54
|
expire: string;
|
|
55
|
-
/** Set for SDK sessions — carries the platform session for server calls. */
|
|
56
|
-
fallbackCookie?: string;
|
|
57
55
|
/** Set for mock sessions — references the signed-in demo persona. */
|
|
58
56
|
personaId?: string;
|
|
59
57
|
/** Set for public-API sessions — the platform user behind the session. */
|