2026-01-10 15:12:51 +07:00
|
|
|
|
import * as z from 'zod';
|
2026-01-10 15:44:37 +07:00
|
|
|
|
//@ts-ignore
|
|
|
|
|
|
import validator from 'validator';
|
2026-01-10 15:12:51 +07:00
|
|
|
|
|
|
|
|
|
|
interface FieldConfig {
|
|
|
|
|
|
maxSize?: { value: number; message: string };
|
|
|
|
|
|
minSize?: { value: number; message: string };
|
|
|
|
|
|
allowedSymbols?: { value: string; message: string };
|
|
|
|
|
|
optional?: { value: boolean };
|
|
|
|
|
|
requiredDigit?: { value: boolean; message: string };
|
|
|
|
|
|
requiredLetter?: { value: boolean; message: string };
|
|
|
|
|
|
caseType?: { value: 'LOWER' | 'UPPER' | 'ANY'; message: string };
|
|
|
|
|
|
emailValidation?: { value: boolean; message: string };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface ValidationConfig {
|
|
|
|
|
|
[key: string]: FieldConfig;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-10 15:44:37 +07:00
|
|
|
|
/* const EMAIL_REGEX = /^([a-z0-9.\-_]+|[а-яё0-9.\-_]+)@(([a-z0-9.\-]+)\.([a-z]{2,})|([a-z0-9.\-]+)\.([а-яё]{2,})|([а-яё0-9.\-]+)\.([a-z]{2,})|([а-яё0-9.\-]+)\.([а-яё]{2,}))$/i; */
|
2026-01-10 15:12:51 +07:00
|
|
|
|
|
2026-01-29 21:34:02 +07:00
|
|
|
|
export function createValidationSchema(config: ValidationConfig, accountType?: 'b2b' | 'b2c') {
|
2026-01-10 15:12:51 +07:00
|
|
|
|
const schema: Record<string, any> = {};
|
|
|
|
|
|
|
|
|
|
|
|
// fullName
|
|
|
|
|
|
if (config.fullName) {
|
|
|
|
|
|
schema.fullName = z
|
|
|
|
|
|
.string()
|
|
|
|
|
|
.min(config.fullName.minSize?.value || 1, {
|
|
|
|
|
|
error: config.fullName.minSize?.message || 'register-error-name-min'
|
|
|
|
|
|
})
|
|
|
|
|
|
.max(config.fullName.maxSize?.value || 100, {
|
|
|
|
|
|
error: config.fullName.maxSize?.message || 'register-error-name-max'
|
|
|
|
|
|
})
|
|
|
|
|
|
.regex(new RegExp(config.fullName.allowedSymbols?.value || '.*'), {
|
|
|
|
|
|
message: config.fullName.allowedSymbols?.message || 'register-error-name-not-allowed-symbols'
|
|
|
|
|
|
})
|
|
|
|
|
|
.trim();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-29 14:34:04 +07:00
|
|
|
|
// fullName
|
2026-01-29 21:34:02 +07:00
|
|
|
|
if (config.companyName && accountType !== 'b2c') {
|
2026-01-29 14:34:04 +07:00
|
|
|
|
schema.companyName = z
|
|
|
|
|
|
.string()
|
|
|
|
|
|
.trim()
|
|
|
|
|
|
.min(config.companyName.minSize?.value || 1, {
|
|
|
|
|
|
error: config.companyName.minSize?.message || 'register-error-company-name-min'
|
|
|
|
|
|
})
|
|
|
|
|
|
.max(config.companyName.maxSize?.value || 100, {
|
|
|
|
|
|
error: config.companyName.maxSize?.message || 'register-error-company-name-max'
|
|
|
|
|
|
})
|
|
|
|
|
|
.regex(new RegExp(config.companyName.allowedSymbols?.value || '.*'), {
|
|
|
|
|
|
message: config.companyName.allowedSymbols?.message || 'register-error-company-name-not-allowed-symbols'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-10 15:12:51 +07:00
|
|
|
|
// email
|
|
|
|
|
|
if (config.email) {
|
|
|
|
|
|
let emailSchema = z
|
|
|
|
|
|
.string()
|
|
|
|
|
|
.min(config.email.minSize?.value || 1, {
|
|
|
|
|
|
error: config.email.minSize?.message || 'register-error-email-min'
|
|
|
|
|
|
})
|
|
|
|
|
|
.max(config.email.maxSize?.value || 254, {
|
|
|
|
|
|
error: config.email.maxSize?.message || 'register-error-email-max'
|
|
|
|
|
|
})
|
|
|
|
|
|
.trim();
|
|
|
|
|
|
|
|
|
|
|
|
// Проверка на нижний регистр
|
|
|
|
|
|
if (config.email.caseType?.value === 'LOWER') {
|
|
|
|
|
|
emailSchema = emailSchema.refine(
|
|
|
|
|
|
(value) => value === value.toLowerCase(),
|
|
|
|
|
|
{ message: config.email.caseType?.message || 'register-error-email-no-uppercase' }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Проверка допустимых символов (опционально, если указано)
|
|
|
|
|
|
if (config.email.allowedSymbols?.value) {
|
|
|
|
|
|
emailSchema = emailSchema.regex(
|
|
|
|
|
|
new RegExp(config.email.allowedSymbols.value),
|
|
|
|
|
|
{ message: config.email.allowedSymbols.message }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (config.email.emailValidation?.value) {
|
|
|
|
|
|
emailSchema = emailSchema.refine(
|
2026-01-10 15:44:37 +07:00
|
|
|
|
(value) => validator.isEmail(value, {
|
|
|
|
|
|
allow_utf8_local_part: true,
|
|
|
|
|
|
require_tld: true,
|
|
|
|
|
|
}),
|
|
|
|
|
|
{ message: config.email.emailValidation.message }
|
2026-01-10 15:12:51 +07:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
schema.email = emailSchema;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// phone
|
|
|
|
|
|
if (config.phone) {
|
|
|
|
|
|
let phoneSchema = z.string();
|
|
|
|
|
|
|
|
|
|
|
|
// Минимальная длина
|
|
|
|
|
|
if (config.phone.minSize) {
|
|
|
|
|
|
phoneSchema = phoneSchema.min(config.phone.minSize.value, {
|
|
|
|
|
|
error: config.phone.minSize.message
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Максимальная длина
|
|
|
|
|
|
if (config.phone.maxSize) {
|
|
|
|
|
|
phoneSchema = phoneSchema.max(config.phone.maxSize.value, {
|
|
|
|
|
|
error: config.phone.maxSize.message
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Допустимые символы
|
|
|
|
|
|
if (config.phone.allowedSymbols) {
|
|
|
|
|
|
phoneSchema = phoneSchema.regex(
|
|
|
|
|
|
new RegExp(config.phone.allowedSymbols.value),
|
|
|
|
|
|
{ message: config.phone.allowedSymbols.message }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
schema.phone = phoneSchema;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// password
|
|
|
|
|
|
if (config.password) {
|
|
|
|
|
|
let passwordSchema = z
|
|
|
|
|
|
.string()
|
|
|
|
|
|
.min(config.password.minSize?.value || 8, {
|
|
|
|
|
|
error: config.password.minSize?.message || 'register-error-password-symbols'
|
|
|
|
|
|
})
|
|
|
|
|
|
.max(config.password.maxSize?.value || 124, {
|
|
|
|
|
|
error: config.password.maxSize?.message || 'register-error-max-password'
|
|
|
|
|
|
})
|
|
|
|
|
|
.trim();
|
|
|
|
|
|
|
|
|
|
|
|
// Проверка допустимых символов
|
|
|
|
|
|
if (config.password.allowedSymbols?.value) {
|
|
|
|
|
|
passwordSchema = passwordSchema.regex(
|
|
|
|
|
|
new RegExp(config.password.allowedSymbols.value),
|
|
|
|
|
|
{ message: config.password.allowedSymbols.message }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Проверка наличия цифры
|
|
|
|
|
|
if (config.password.requiredDigit?.value) {
|
|
|
|
|
|
passwordSchema = passwordSchema.regex(
|
|
|
|
|
|
/[0-9]/,
|
|
|
|
|
|
{ message: config.password.requiredDigit.message }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Проверка наличия буквы
|
|
|
|
|
|
if (config.password.requiredLetter?.value) {
|
|
|
|
|
|
passwordSchema = passwordSchema.regex(
|
|
|
|
|
|
/[a-zA-Zа-яёА-ЯЁ]/,
|
|
|
|
|
|
{ message: config.password.requiredLetter.message }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
schema.password = passwordSchema;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-29 14:34:04 +07:00
|
|
|
|
// companyName (опциональное поле), надо будет удалить потом
|
|
|
|
|
|
/* if (config.companyName) {
|
2026-01-10 15:12:51 +07:00
|
|
|
|
let companySchema = z.string();
|
|
|
|
|
|
|
|
|
|
|
|
// Если поле опциональное, добавляем .optional().nullable()
|
|
|
|
|
|
if (config.companyName.optional?.value) {
|
|
|
|
|
|
companySchema = companySchema
|
|
|
|
|
|
.optional()
|
|
|
|
|
|
.nullable()
|
|
|
|
|
|
.transform((val) => (val === null || val === undefined ? '' : val))
|
|
|
|
|
|
.refine(
|
|
|
|
|
|
(value) => {
|
|
|
|
|
|
// Для пустого значения пропускаем проверки
|
|
|
|
|
|
if (!value || value.trim().length === 0) return true;
|
|
|
|
|
|
|
|
|
|
|
|
// Проверка минимальной длины
|
|
|
|
|
|
const minLength = config.companyName?.minSize?.value || 2;
|
|
|
|
|
|
return value.trim().length >= minLength;
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
message: config.companyName.minSize?.message || 'register-error-company-name-min'
|
|
|
|
|
|
}
|
|
|
|
|
|
) as unknown as z.ZodString;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Если поле обязательное
|
|
|
|
|
|
if (config.companyName.minSize) {
|
|
|
|
|
|
companySchema = companySchema.min(config.companyName.minSize.value, {
|
|
|
|
|
|
error: config.companyName.minSize.message
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Максимальная длина (применяется всегда)
|
|
|
|
|
|
if (config.companyName.maxSize) {
|
|
|
|
|
|
companySchema = companySchema.refine(
|
|
|
|
|
|
(value) => {
|
|
|
|
|
|
if (config.companyName?.optional?.value && (!value || value.trim().length === 0)) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
const maxLength = config.companyName?.maxSize?.value || 200;
|
|
|
|
|
|
return (value || '').trim().length <= maxLength;
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
message: config.companyName.maxSize.message
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Допустимые символы
|
|
|
|
|
|
if (config.companyName.allowedSymbols?.value) {
|
|
|
|
|
|
companySchema = companySchema.refine(
|
|
|
|
|
|
(value) => {
|
|
|
|
|
|
if (config.companyName?.optional?.value && (!value || value.trim().length === 0)) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
const regex = new RegExp(config.companyName.allowedSymbols!.value);
|
|
|
|
|
|
return regex.test(value || '');
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
message: config.companyName.allowedSymbols.message
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
companySchema = companySchema.transform((val) => val?.trim() || '') as unknown as z.ZodString;
|
|
|
|
|
|
|
|
|
|
|
|
schema.companyName = companySchema;
|
2026-01-29 14:34:04 +07:00
|
|
|
|
} */
|
2026-01-10 15:12:51 +07:00
|
|
|
|
|
|
|
|
|
|
// Дополнительные поля для формы регистрации
|
|
|
|
|
|
schema.confirm_password = z.string();
|
|
|
|
|
|
schema.agree = z.string().min(2, { error: 'register-error-agree' });
|
|
|
|
|
|
|
|
|
|
|
|
return z
|
|
|
|
|
|
.object(schema)
|
|
|
|
|
|
.refine((data) => data.password === data.confirm_password, {
|
|
|
|
|
|
message: 'repeat-password',
|
|
|
|
|
|
path: ['confirm_password'],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|