diff --git a/src/app/[locale]/pages/refferals/page.tsx b/src/app/[locale]/pages/refferals/page.tsx index 2f30864..7cc1a5f 100644 --- a/src/app/[locale]/pages/refferals/page.tsx +++ b/src/app/[locale]/pages/refferals/page.tsx @@ -16,7 +16,7 @@ export default function Page() { ...}> - + {/* */} diff --git a/src/app/actions/companyActions.ts b/src/app/actions/companyActions.ts new file mode 100644 index 0000000..d83f3cd --- /dev/null +++ b/src/app/actions/companyActions.ts @@ -0,0 +1,180 @@ +'use server' + +import { API_BASE_URL, getSignupFormSchema } from '@/app/actions/definitions'; +import { createSession } from '@/app/actions/session'; +import { redirect } from 'next/navigation'; + +export type CompanyUserRegistrationFormState = { + previousState: { + fullName: string; + email: string; + password: string; + confirm_password: string; + phone: string; + }, + error: Record | null +} | undefined; + +export async function companyUserRegistration( + state: CompanyUserRegistrationFormState | undefined, + formData: FormData, +): Promise { + const fullName = formData.get('fullName') as string || ''; + const email = formData.get('email') as string || ''; + const password = formData.get('password') as string || ''; + const confirm_password = formData.get('confirm_password') as string || ''; + const phone = formData.get('phone') as string || ''; + + const SignupFormSchema = await getSignupFormSchema('b2c'); + + const dataToValidate = { + fullName, + email, + phone: phone.replace(/[-\(\)\s]/g, ''), + password, + confirm_password, + agree: 'on' + }; + + const validatedFields = SignupFormSchema.safeParse(dataToValidate); + + console.log(`try to register company users ${email}`); + + if (!validatedFields.success) { + const errors: Record = {} + JSON.parse(validatedFields.error.message).forEach((obj: { + message: string, + path: string + }) => { + if (errors[obj.path[0]]) { + errors[obj.path[0]] = `${errors[obj.path[0]]}&${obj.message}`; + } else { + errors[obj.path[0]] = obj.message; + } + }); + + console.log(errors); + + return { + previousState: { + fullName, + email, + password, + confirm_password, + phone + }, + error: errors + }; + } + + return { + previousState: { + fullName, + email, + password, + confirm_password, + phone + }, + error: null + }; + + try { + const { fullName, email, password, phone } = validatedFields.data; + const response = await fetch(`${API_BASE_URL}/api/v1/data`, { + method: 'POST', + body: JSON.stringify({ + version: 1, + msg_id: 20002, + message_body: { + fullName: fullName, + email, + phone: phone, + password + } + }), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + } + }); + + if (response.ok) { + let parsed = await response.json() as { + message_desc: string, + message_body: { token: string }, + message_code: number + }; + + if (parsed.message_code === 0) { + console.log(`registration - ${email}`); + console.log({ + fullName: fullName, + email, + phone: phone, + password + }); + await createSession(parsed.message_body.token, email as string); + } else { + throw parsed; + } + } else { + throw (`${response.status}`); + } + + } catch (error: unknown) { + const errors: Record = {}; + if (error) { + const typedError = error as any; + + switch (typedError.message_code) { + case 1: + errors['server'] = 'email-or-already-registered' + break; + + case 2: + if (typedError.message_body?.fieldErrors) { + typedError.message_body?.fieldErrors?.forEach((obj: { + code: string, + field: string + }) => { + if (errors[obj.field]) { + errors[obj.field] = `${errors[obj.field]}&${obj.code.replaceAll('.', '-')}`; + } else { + errors[obj.field] = obj.code.replaceAll('.', '-'); + } + }); + + } else { + errors['server'] = 'unknown-error' + } + break; + + default: + errors['server'] = 'request-ended-with-an-error' + break; + } + + return { + previousState: { + fullName, + email, + password, + confirm_password, + phone + }, + error: errors + }; + } + + return { + previousState: { + fullName, + email, + password, + confirm_password, + phone + }, + error: errors + }; + } +} \ No newline at end of file diff --git a/src/app/actions/definitions.ts b/src/app/actions/definitions.ts index 51e9662..94e7913 100644 --- a/src/app/actions/definitions.ts +++ b/src/app/actions/definitions.ts @@ -45,7 +45,7 @@ async function loadConfigFromBackend(accountType?: 'b2b' | 'b2c'): Promise return await response.json(); } catch (error) { //сейчас выполняем это пока бека нету - console.error('Using default validation config:', error); + /* console.error('Using default validation config:', error); */ return defaultConfig; } } diff --git a/src/app/lib/validation-config-parser.ts b/src/app/lib/validation-config-parser.ts index d3a3825..a2cb322 100644 --- a/src/app/lib/validation-config-parser.ts +++ b/src/app/lib/validation-config-parser.ts @@ -97,10 +97,13 @@ export function createValidationSchema(config: ValidationConfig, accountType?: ' // phone if (config.phone) { + console.log('validate phone'); + let phoneSchema = z.string(); // Минимальная длина if (config.phone.minSize) { + console.log(config.phone.minSize.value); phoneSchema = phoneSchema.min(config.phone.minSize.value, { error: config.phone.minSize.message }); diff --git a/src/app/lib/validation-config.json b/src/app/lib/validation-config.json index 816625b..97abe6c 100644 --- a/src/app/lib/validation-config.json +++ b/src/app/lib/validation-config.json @@ -80,7 +80,7 @@ "message": "register-error-phone-max" }, "minSize": { - "value": 2, + "value": 12, "message": "register-error-phone-min" }, "allowedSymbols": { diff --git a/src/app/ui/settings/company-users-setting-panel.tsx b/src/app/ui/settings/company-users-setting-panel.tsx index 074a030..e9d7197 100644 --- a/src/app/ui/settings/company-users-setting-panel.tsx +++ b/src/app/ui/settings/company-users-setting-panel.tsx @@ -1,20 +1,18 @@ 'use client' +import styles from '@/app/styles/module/login.module.scss'; import { useTranslations } from 'next-intl'; -import { useActionState, useEffect } from 'react'; +import { useActionState, useEffect, useRef, useState, ChangeEvent } from 'react'; import { getUserData } from '@/app/actions/action'; import { useQuery } from '@tanstack/react-query'; +import { companyUserRegistration } from '@/app/actions/companyActions'; +import { CompanyUserRegistrationFormState } from '@/app/actions/companyActions'; +import { SignupFormSchema } from '@/app/actions/definitions'; +import * as z from 'zod'; +import PhoneInput from '@/app/ui/inputs/phone-input'; +import { IconEye } from '@/app/ui/icons/icons'; export function CompanyUsersSettingPanel() { - const t = useTranslations('Global'); - - const [errorMessage, formAction, isPending] = useActionState( - (state: void | undefined, formData: FormData) => { - console.log(formData); - }, - undefined - ); - const { data: userData, isLoading, @@ -31,42 +29,269 @@ export function CompanyUsersSettingPanel() { return null } + const [state, formAction, isPending] = useActionState( + companyUserRegistration, + undefined + ); + + const t = useTranslations('Login-register-form'); + const [showPassword, setShowPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = useState(false); + const [formState, setFormState] = useState(undefined); + const passwordRef = useRef(null); + + useEffect(() => { + if (state) { + setFormState(state); + } + + }, [state]) + + function validateField( + fieldName: string, + value: string, + ) { + switch (fieldName) { + case 'confirm_password': + const baseSchema = SignupFormSchema.shape.confirm_password; + const baseResult = baseSchema.safeParse(value); + + if (!baseResult.success) { + return baseResult; + } + + const currentPassword = passwordRef.current?.value || ''; + if (value !== currentPassword) { + return { + success: false, + error: new z.ZodError([ + { + code: z.ZodIssueCode.custom, + message: 'repeat-password', + path: ['confirm_password'] + } + ]) + }; + } + + return { success: true, data: value }; + + case 'email': + case 'fullName': + case 'phone': + case 'password': + case 'companyName': + case 'agree': + const schema = SignupFormSchema.shape[fieldName]; + if (fieldName === 'phone') { + console.log(schema.safeParse(value.replace(/[-\(\)\s]/g, ''))); + return schema.safeParse(value.replace(/[-\(\)\s]/g, '')); + } + if (fieldName === 'companyName') { + return { success: true, data: value }; + } + return schema.safeParse(value); + + default: + throw new Error(`Unknown field: ${fieldName}`); + } + } + + function onChangeHandler(e: ChangeEvent): void { + const fieldName = e.target.name; + if (fieldName !== 'phone') { + e.target.value = e.target.value.replace(/([^a-zA-Zа-яёА-ЯЁ0-9@.!#$%&"'*+/=?^_{|}~\-\s])/g, ''); + } + const validatedField = validateField(fieldName, e.target.value); + + if (validatedField.success) { + setFormState(prevState => { + if (!prevState?.error || !prevState?.error[fieldName]) { + return prevState; + } + + const { [fieldName]: _, ...newError } = prevState.error; + + return { + ...prevState, + error: newError + }; + }); + } + } + + function showPassowrd(target: 'password' | 'confirm-password') { + if (target === 'password') { + setShowPassword(!showPassword); + } else { + setShowConfirmPassword(!showConfirmPassword); + } + } + return (

Добавление пользователей

-
-
-