@@ -0,0 +1,15 @@ +const Sentry = { + init: jest.fn(), + captureException: jest.fn(), + captureMessage: jest.fn(), + withScope: jest.fn((callback) => { + callback({ + setExtra: jest.fn(), + setTag: jest.fn(), + setUser: jest.fn(), + }); + }), +}; + + +export default Sentry; @@ -0,0 +1,25 @@ +const mockRouter = { + push: jest.fn(() => Promise.resolve()), + replace: jest.fn(() => Promise.resolve()), + reload: jest.fn(), + back: jest.fn(), + prefetch: jest.fn(() => Promise.resolve()), + beforePopState: jest.fn(), + events: { + on: jest.fn(), + off: jest.fn(), + emit: jest.fn(), + }, + query: {}, + asPath: '', + pathname: '', + route: '', +} + +const useRouter = jest.fn(() => mockRouter) + +export { useRouter } + +export const setRouter = (overrides: Partial) => { + Object.assign(mockRouter, overrides) +} @@ -0,0 +1,30 @@ +import { jest } from '@jest/globals' + +const mockUseSession = jest.fn() +const mockSignIn = jest.fn() +const mockSignOut = jest.fn() +const mockGetSession = jest.fn() + +const mockSession = { + user: { + name: 'Test User', + email: 'test@example.com', + image: 'https://example.com/test.jpg', + }, + expires: '1', +} + +export const useSession = () => { + return { data: mockSession, status: 'authenticated' } +} + +export const signIn = mockSignIn +export const signOut = mockSignOut +export const getSession = mockGetSession + +export default { + useSession, + signIn, + signOut, + getSession, +} @@ -0,0 +1,3 @@ +const ReactComponent = 'div' + +export default ReactComponent \ No newline at end of file @@ -0,0 +1,27 @@ +import { Modal, usePlatesStore } from '#/features/modals/model' +import { useEffect } from 'react' +import { jestRender } from './render' + +const ModalTester = ({ id, onModal }: { id: string; onModal: (modal: Modal) => void }) => { + const { getModal } = usePlatesStore() + + useEffect(() => { + const modal = getModal(id) + onModal(modal) + }, [id, onModal]) + + return null +} + +export async function getModalTest(id: string): Promise { + return await new Promise((resolve) => { + jestRender( + { + resolve(m) + }} + /> + ) + }) +} @@ -0,0 +1,9 @@ +import { store } from '#/app/store/store' +import { render } from '@testing-library/react' +import { Provider } from 'react-redux' + +export function jestRender(component: React.ReactElement) { + return render({component}) +} + + @@ -0,0 +1,28 @@ +//@ts-nocheck +export function windowMock() { + let originalLocation = window.location // Сохраняем оригинальный window.location + + beforeEach(() => { + // Удаляем оригинальный window.location + delete window.location + + // Мокируем window.location + window.location = { + href: '', + assign: jest.fn(), + replace: jest.fn(), + reload: jest.fn(), + protocol: 'http:', + host: 'localhost', + pathname: '/', + search: '', + hash: '', + ...originalLocation, // Сохраняем оригинальные методы + } + }) + afterEach(() => { + // Возвращаем оригинальный window.location + // @ts-ignore + window.location = originalLocation + }) +} @@ -490,3 +490,21 @@ button { opacity: 0; transition: opacity 400ms; } + + +.fade-enter{ + opacity: 0; +} +.fade-exit{ + opacity: 1; +} +.fade-enter-active{ + opacity: 1; +} +.fade-exit-active{ + opacity: 0; +} +.fade-enter-active, +.fade-exit-active{ + transition: opacity 500ms; +} \ No newline at end of file @@ -0,0 +1,6 @@ + + + + \ No newline at end of file @@ -150,7 +150,7 @@ background-color: rgba(0, 0, 0, 0.7); border-radius: 15px; padding: 20px; - z-index: 10000; + z-index: 1000; &:hover { outline: 4px solid #8280ff66; outline-offset: -3px; @@ -148,7 +148,7 @@ background-color: rgba(0, 0, 0, 0.7); border-radius: 15px; padding: 20px; - z-index: 10000; + z-index: 1000; &:hover { outline: 4px solid #8280ff66; outline-offset: -3px; @@ -1,19 +1,8 @@ -import axios from 'axios' +import { api } from '#/shared/api' -import { API_URL } from '#/shared/lib/constants' - -export const changePassword = async (email: string, password: string, newPassword: string, token?: string) => { - return await axios.patch( - API_URL + `/auth/business-host/account/change-pass/${email}`, - { - password_1: password, - password_2: newPassword, - }, - { - headers: { - Authorization: `Bearer ${token}`, - }, - validateStatus: (status) => status < 500 - } - ) +export const changePassword = async (email: string, password_1: string, password_2: string) => { + return await api.patch<{ detail: string }>(`/auth/business-host/account/change-pass/${email}`, { + password_1, + password_2, + }) } @@ -4,6 +4,7 @@ import { useState } from 'react' import { getModalById, PLATE_CHANGE_PASSWORD } from '#/features/modals' import { useShowDataStore } from '#/shared/lib/hooks/use-show-data' import { useForm } from 'react-hook-form' +import { makePrivateRequest } from '#/shared/api' interface ChangePasswordForm { password: string @@ -23,34 +24,27 @@ export const useChangePassword = () => { setValue, } = useForm() const { showMessage } = useShowDataStore() - const { data: session } = useSession() const [passwordShowed, setPasswordShowed] = useState(false) - const onSubmit = handleSubmit(async (data, event) => { - if (!session) return + const onSubmit = handleSubmit( + makePrivateRequest(async ({ password, newPassword }) => { + if (password !== newPassword) { + showMessage('Пароли не совпадают') + setError('password', { message: 'Пароли не совпадают' }) + return setError('newPassword', { message: 'Пароли не совпадают' }) + } - if (data.password !== data.newPassword) { - showMessage('Пароли не совпадают!', 'error') - setError('password', { message: 'Пароли не совпадают' }) - return setError('newPassword', { message: 'Пароли не совпадают' }) - } + const { data, status } = await changePassword(modal.getStoreProperty('email')!, password, newPassword) - const { data: res, status } = await changePassword( - modal.getStoreProperty('email')!, - data.password, - data.newPassword, - session.access - ) + if (status !== 200) return showMessage(data.detail) - if (status == 200) { showMessage('Пароль изменен успешно!', 'success') + modal.setState(false) - return - } - showMessage((res as { detail: string }).detail) - reset() - }) + reset() + }) + ) return { onSubmit, register, watch, reset, errors, trigger, setValue, passwordShowed, setPasswordShowed } } @@ -0,0 +1,100 @@ +import '@testing-library/jest-dom' +import { act, fireEvent, screen, waitFor } from '@testing-library/react' +import { jestRender } from '#/../jest/utils/render' +import { windowMock } from '#/../jest/utils/window-mock' +import { ChangePasswordPlate } from './change-password' +import { PLATE_CHANGE_PASSWORD } from '#/features/modals' +import { getModalTest } from '#/../jest/utils/modal-tester' +import { api } from '#/shared/api/instance' + +jest.mock('next/router') +jest.mock('@sentry/nextjs') + +jest.mock('#/shared/api/instance') + +const showMessageMock = jest.fn() +const useSessionMock = jest.fn() + +jest.mock('next-auth/react', () => { + return { + useSession: () => useSessionMock(), + } +}) + +jest.mock('#/shared/lib/hooks/use-show-data', () => { + return { + useShowDataStore: jest.fn(() => { + return { + showMessage: showMessageMock, + } + }), + } +}) + +useSessionMock.mockReturnValue({ + data: { + access: 'something access', + }, +}) + +windowMock() + +describe('chage-password', () => { + it('successfully change password', async () => { + jestRender() + + const modal = await getModalTest(PLATE_CHANGE_PASSWORD) + + act(() => { + modal.setState(true, { + email: 'aleksander.freelancer@gmail.com', + }) + }) + ;(api.patch as jest.Mock).mockResolvedValue({ + status: 200, + data: { detail: 'Host password has been updated' }, + }) + + const password = screen.getByPlaceholderText('Пароль') + const newPassword = screen.getByPlaceholderText('Повторить пароль') + const button = screen.getByText('Сменить пароль') + + fireEvent.change(password, { target: { value: 'h7O5vF$M' } }) + fireEvent.change(newPassword, { target: { value: 'h7O5vF$M' } }) + + act(() => { + fireEvent.click(button) + }) + + await waitFor(() => { + expect(showMessageMock).toHaveBeenCalledWith('Пароль изменен успешно!', 'success') + }) + }) + + it('not equal passwords', async () => { + jestRender() + + const modal = await getModalTest(PLATE_CHANGE_PASSWORD) + + act(() => { + modal.setState(true, { + email: 'aleksander.freelancer@gmail.com', + }) + }) + + const password = screen.getByPlaceholderText('Пароль') + const newPassword = screen.getByPlaceholderText('Повторить пароль') + const button = screen.getByText('Сменить пароль') + + fireEvent.change(password, { target: { value: 'h7O5vF$M' } }) + fireEvent.change(newPassword, { target: { value: 'h7O5vF$Md' } }) + + act(() => { + fireEvent.click(button) + }) + + await waitFor(() => { + expect(showMessageMock).toHaveBeenCalledWith('Пароли не совпадают') + }) + }) +}) @@ -1,6 +1,5 @@ import { getModalById, PLATE_CHANGE_PASSWORD, PlateTemplate } from '#/features/modals' import styles from './change-password.module.scss' -import React, { useEffect } from 'react' import { CommonButton } from '#/shared/ui/button' import { CommonInput } from '#/shared/ui/common-input' import { useChangePassword } from '../lib/use-change-password' @@ -9,30 +8,19 @@ import ClosedEyeSvg from '#/assets/svg/closed-eye.svg?react' export const ChangePasswordPlate = () => { const modal = getModalById(PLATE_CHANGE_PASSWORD) - const { onSubmit, register, errors, reset, trigger, watch, setValue, passwordShowed, setPasswordShowed } = useChangePassword() + + const { onSubmit, register, errors, reset, trigger, passwordShowed, setPasswordShowed } = useChangePassword() return ( - { - reset() - }} - > -
+ reset()}> + trigger()} onSubmit={onSubmit}>

Смена пароля

{ - setValue('password', e.target.value) - trigger('password') - }} label='Новый пароль' variant='outline' placeholder='Пароль' @@ -48,18 +36,12 @@ export const ChangePasswordPlate = () => { )} } - // onInput={() => trigger('password')} /> { - setValue('newPassword', e.target.value) - trigger('newPassword') - }} label='Повторить пароль' variant='outline' placeholder='Повторить пароль' @@ -74,21 +56,13 @@ export const ChangePasswordPlate = () => { } error={errors.newPassword} - // onInput={() => trigger('password')} />
Сменить пароль - { - modal.setState(false) - reset() - }} - type='button' - > + modal.setState(false)} type='button'> Отмена
@@ -0,0 +1,17 @@ +import { api } from '#/shared/api' + +interface SendReport { + errorMessage: string + email: string + file?: File +} + +export async function sendReport({errorMessage, email, file}: SendReport) { + let formData = new FormData() + + formData.append('report_text', `${email}: ${errorMessage}`) + if (file) { + formData.append('images', file) + } + return await api.post('/reports/', formData) +} @@ -0,0 +1 @@ +export * from './error-report.api' \ No newline at end of file @@ -0,0 +1,64 @@ +import { useAppSelector } from '#/app/store/store' +import { API_URL } from '#/shared/lib/constants' +import axios from 'axios' +import { useSession } from 'next-auth/react' +import React, { ChangeEvent } from 'react' +import { sendReport } from '../api' +import { makePrivateRequest } from '#/shared/api' +import { useShowDataStore } from '#/shared/lib/hooks/use-show-data' + +export const useErrorReport = () => { + + const { showMessage } = useShowDataStore() + const [errorMessage, setErrorMessage] = React.useState('') + + const [error, setError] = React.useState(false) + + const [isSend, setIsSend] = React.useState(false) + + const [file, setFile] = React.useState() + + const { data: session } = useSession() + + const email = useAppSelector((state) => state.user.email) + + const handleFileChange = (e: ChangeEvent) => { + if (e.target.files) { + if (4500000 > e.target.files[0].size) setFile(e.target.files[0]) + } + } + + const sendError = makePrivateRequest(async () => { + if (errorMessage.trim() === '') { + showMessage("Поле не должно быть пустым.") + setError(true) + setTimeout(() => setError(false), 3000) + return + } + + try { + const { status } = await sendReport({ errorMessage, email, file }) + + if (status === 201) { + setErrorMessage('') + setIsSend(true) + setTimeout(() => { + setIsSend(false) + }, 4000) + } + } catch (err) { + setError(true) + setTimeout(() => setError(false), 3000) + } + }) + + return { + isSend, + setErrorMessage, + handleFileChange, + file, + setFile, + sendError, + error, + } +} @@ -0,0 +1,78 @@ +.container { + width: 589px; + height: auto; + background-color: var(--background-color-additional); + padding: 32px; + border-radius: 20px; + + box-shadow: rgba(0, 0, 0, 0.2) 0px 8px 10px -5px, rgba(0, 0, 0, 0.14) 0px 16px 24px 2px, rgba(0, 0, 0, 0.12) 0px 6px 30px 5px; + + &_sended { + display: flex; + gap: 16px; + flex-direction: column; + width: 300px; + text-align: center; + } + + &__buttons { + display: flex; + justify-content: flex-end; + flex-direction: row; + align-items: flex-end; + margin-top: 12px; + gap: 8px; + } + + &__close { + transform: rotate(45deg); + margin-left: 8px; + color: var(--new-ui-gray-color); + } +} + +.text { + color: #868686; + font-size: 17px; + line-height: 1.5; + + &_accent { + color: #22b47f; + font-size: 23px; + } + + &_heading { + font-size: 21px; + font-weight: 500; + } + + &_file { + font-size: 15px; + } +} + +.textarea { + position: relative; + margin: 20px 0px 9.6px 0px; + + &__button { + position: absolute; + padding: 0; + bottom: 16px; + left: 8px; + background-color: transparent; + box-shadow: none; + margin: 0; + rotate: 30deg; + + &:hover { + background-color: transparent; + box-shadow: none; + } + } + + &__file { + display: flex; + align-items: center; + } +} @@ -0,0 +1,92 @@ +import '@testing-library/jest-dom' +import { act, fireEvent, screen, waitFor } from '@testing-library/react' +import { jestRender } from '#/../jest/utils/render' +import { windowMock } from '#/../jest/utils/window-mock' +import { ERROR_REPORT, PLATE_CHANGE_PASSWORD } from '#/features/modals' +import { getModalTest } from '#/../jest/utils/modal-tester' +import { api } from '#/shared/api/instance' +import { ErrorReportPlate } from './error-report' +import axios from 'axios' +import { sendReport } from '../api' + +jest.mock('next/router') +jest.mock('@sentry/nextjs') + +jest.mock('../api') + +const showMessageMock = jest.fn() +const useSessionMock = jest.fn() + +jest.mock('next-auth/react', () => { + return { + useSession: () => useSessionMock(), + } +}) + +jest.mock('#/shared/lib/hooks/use-show-data', () => { + return { + useShowDataStore: jest.fn(() => { + return { + showMessage: showMessageMock, + } + }), + } +}) + +useSessionMock.mockReturnValue({ + data: { + access: 'something access', + }, +}) + +windowMock() + +describe('error-report', () => { + it('successfully show modal', async () => { + jestRender() + + const modal = await getModalTest(ERROR_REPORT) + + act(() => { + modal.setState(true) + }) + ;(sendReport as jest.Mock).mockResolvedValue({ + status: 201, + data: { detail: 'error report sent' }, + }) + + const textarea = screen.getByPlaceholderText('Опишите детально возникшую проблему') + const button = screen.getByText('Отправить') + + fireEvent.change(textarea, { target: { value: 'О нет все пропало' } }) + + act(() => { + fireEvent.click(button) + }) + + await waitFor(() => { + expect(sendReport).toHaveBeenCalledWith({ errorMessage: 'О нет все пропало', email: '' }) + }) + }) + + it('empty textarea', async () => { + jestRender() + + const modal = await getModalTest(ERROR_REPORT) + + act(() => { + modal.setState(true) + }) + + const textarea = screen.getByPlaceholderText('Опишите детально возникшую проблему') + const button = screen.getByText('Отправить') + + act(() => { + fireEvent.click(button) + }) + + await waitFor(() => { + expect(showMessageMock).toHaveBeenCalledWith("Поле не должно быть пустым.") + }) + }) +}) @@ -0,0 +1,73 @@ +import * as React from 'react' +import AttachSvg from '#/assets/svg/attach.svg?react' +import PlusSvg from '#/assets/svg/plus.svg?react' +import { ERROR_REPORT, getModalById, PlateTemplate } from '#/features/modals' + +import styles from './error-report.module.scss' +import { c } from '#/shared' +import { CommonTextArea } from '#/shared/ui/common-textarea' +import { CommonButton } from '#/shared/ui/button' +import { useErrorReport } from '../model/use-error-report' + +export const ErrorReportPlate = () => { + const modal = getModalById(ERROR_REPORT) + + const { error, isSend, setErrorMessage, handleFileChange, file, setFile, sendError } = useErrorReport() + + return ( + + {isSend ? ( +
+

Спасибо!

+

Ваше сообщение направлено нашим специалистам. Ответ придет на почту, указанную при регистрации

+
+ ) : ( +
e.stopPropagation()}> +

Сообщить об ошибке

+ setErrorMessage(evt.target.value)} + buttomSlot={ + <> + + + } + /> + {file && ( +
+

Добавлено 1 изображение: {file.name}

+ + +
+ )} + +
+ modal.setState(false)}> + Отмена + + + Отправить + +
+
+ )} +
+ ) +} @@ -0,0 +1 @@ +export * from './error-report' \ No newline at end of file @@ -0,0 +1 @@ +export * from './ui' \ No newline at end of file @@ -1,2 +1,3 @@ export const PLATE_CHANGE_PASSWORD = 'plate-change-password' export const RESEND_INVATION_PASSWORD = 'resend-invation-password' +export const ERROR_REPORT = 'error-report' @@ -1,4 +1,3 @@ -'use client' import { useEffect } from 'react' import { c } from '#/shared' import { usePlatesStore } from '../model' @@ -44,8 +43,6 @@ export default function PlatesTemplate({ const modal = getModal(id) - const { theme } = useThemeAndDevice() - useEffect(() => setModal(id), []) return ( @@ -28,13 +28,18 @@ .area { width: 100%; resize: none; - // height: 28px; border-radius: 0px; - overflow-y: hidden; + overflow-y: auto; + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; padding: 0px; font-size: 16px; max-height: 82px; + &::-webkit-scrollbar { + display: none; /* Chrome, Brave, Edge */ + } + &::placeholder { font-size: 16px; } @@ -56,7 +61,3 @@ width: 1px; margin: 0px 8px; } - -// theme === 'dark' -// ? '#40404E' -// : '#EBEFF5', @@ -0,0 +1,127 @@ +import '@testing-library/jest-dom' +import { act, fireEvent, screen, waitFor } from '@testing-library/react' +import { jestRender } from '#/../jest/utils/render' +import { windowMock } from '#/../jest/utils/window-mock' +import { ModelInput } from './model-input' + +jest.mock('next/router') +jest.mock('@sentry/nextjs') + +windowMock() + +const defaultProps = { + image: null, + loading: false, + desktop: true, + unpinImage: jest.fn(), + sendMessage: jest.fn().mockReturnValue(true), + imageLoad: jest.fn(), + styles: 'chats' as const, + input_types: [{ type: 'text', required: true, versions: ['v1'] }], + viewMobileSettings: jest.fn(), + currentVersion: 'v1', + blocked: false, +} + +describe('renders textarea with correct placeholder', () => { + it('successfully show modal', async () => { + jestRender() + const textarea = screen.getByPlaceholderText('Ваше сообщение') + expect(textarea).toBeInTheDocument() + }) + + it('updates textarea value on user input', () => { + jestRender() + const textarea = screen.getByPlaceholderText('Ваше сообщение') as HTMLTextAreaElement + + fireEvent.change(textarea, { target: { value: 'Test input' } }) + expect(textarea.value).toBe('Test input') + }) + + it('adjusts height on input', () => { + jestRender() + const textarea = screen.getByPlaceholderText('Ваше сообщение') as HTMLTextAreaElement + + Object.defineProperty(textarea, 'scrollHeight', { configurable: true, value: 80 }) + + fireEvent.input(textarea) + expect(textarea.style.height).toBe('80px') + }) + + it('textarea is disabled when disabled is true', () => { + const props = { ...defaultProps, blocked: true } + jestRender() + const textarea = screen.getByPlaceholderText('Ввод текста недоступен для этой модели') as HTMLTextAreaElement + expect(textarea).toBeDisabled() + }) + + it('calls sendMessage on Enter and clears textarea on success', () => { + const sendMessageMock = jest.fn().mockReturnValue(true) + const props = { ...defaultProps, sendMessage: sendMessageMock } + jestRender() + + const textarea = screen.getByPlaceholderText('Ваше сообщение') as HTMLTextAreaElement + + fireEvent.change(textarea, { target: { value: 'Test message' } }) + fireEvent.keyDown(textarea, { key: 'Enter', shiftKey: false }) + + expect(sendMessageMock).toHaveBeenCalledWith('Test message', ['text']) + expect(textarea.value).toBe('') + }) + + it('does not call sendMessage on Shift+Enter', () => { + const sendMessageMock = jest.fn() + const props = { ...defaultProps, sendMessage: sendMessageMock } + jestRender() + + const textarea = screen.getByPlaceholderText('Ваше сообщение') as HTMLTextAreaElement + + fireEvent.change(textarea, { target: { value: 'Should not send' } }) + fireEvent.keyDown(textarea, { key: 'Enter', shiftKey: true }) + + expect(sendMessageMock).not.toHaveBeenCalled() + }) + + it('sets initial value from resendValue', () => { + const props = { ...defaultProps, resendValue: 'Previous message' } + jestRender() + + const textarea = screen.getByDisplayValue('Previous message') as HTMLTextAreaElement + expect(textarea).toBeInTheDocument() + }) + + it('disables textarea if input_types does not include supported text type', async () => { + const props = { + ...defaultProps, + input_types: [{ type: 'image', required: true, versions: ['v1'] }], // no 'text' type + } + + jestRender() + await waitFor(() => { + const textarea = screen.getByPlaceholderText('Ввод текста недоступен для этой модели') as HTMLTextAreaElement + expect(textarea).toBeDisabled() + }) + }) + + it('enables textarea if text input type is supported for currentVersion', async () => { + const props = { + ...defaultProps, + input_types: [{ type: 'text', required: true, versions: ['v1'] }], + currentVersion: 'v1', + } + + jestRender() + await waitFor(() => { + const textarea = screen.getByPlaceholderText('Ваше сообщение') as HTMLTextAreaElement + expect(textarea).not.toBeDisabled() + }) + }) + + it('updates value on change and does not break', () => { + jestRender() + const textarea = screen.getByPlaceholderText('Ваше сообщение') as HTMLTextAreaElement + + fireEvent.change(textarea, { target: { value: 'Side effect test' } }) + expect(textarea.value).toBe('Side effect test') + }) +}) @@ -1,6 +1,6 @@ import { RegisterOptions } from 'react-hook-form/dist/types/validator' -export const companyNameOptions: RegisterOptions = { +export const companyNameOptions = { required: { value: true, message: 'Поле "Наименование организации" обязательно к заполнению', @@ -11,7 +11,7 @@ export const companyNameOptions: RegisterOptions = { }, } -export const innOptions: RegisterOptions = { +export const innOptions = { required: { value: true, message: 'Поле "ИНН" обязательно к заполнению', @@ -23,7 +23,7 @@ export const innOptions: RegisterOptions = { validate: (value: any) => value.length === 10 || 'ИНН должен быть длиной 10 цифр', } -export const ogrnOptions: RegisterOptions = { +export const ogrnOptions = { required: { value: true, message: 'Поле "ОГРН" обязательно к заполнению', @@ -6,7 +6,7 @@ import { innOptions, ogrnOptions } from '../../lib/constatnts-step-legal-informa const validateInnForIP = (value: any) => value.length === 12 || 'ИНН для ИП должен быть длиной 12 цифр' const validateOgrnForIp = (value: any) => value.length === 15 || 'ОГРН для ИП должен быть длиной 15 цифр' -export const useCheckTypeCompany = (company?: string): [{ inn: RegisterOptions; ogrn: RegisterOptions }, boolean] => { +export const useCheckTypeCompany = (company?: string): [{ inn: any; ogrn: any }, boolean] => { const [rulesData, setRulesData] = useState({ inn: innOptions, ogrn: ogrnOptions }) const [isIP, setIsIP] = useState(false) @@ -27,7 +27,7 @@ export const useCheckTypeCompany = (company?: string): [{ inn: RegisterOptions; ...prev, inn: { ...innOptions, validate: validateInnForIP }, ogrn: { ...ogrnOptions, validate: validateOgrnForIp }, - } + } as any }) }, [company]) @@ -1,4 +1,3 @@ -// @ts-nocheck import React, { useState } from 'react' import { useForm } from 'react-hook-form' import { SubmitErrorHandler } from 'react-hook-form/dist/types/form' @@ -1,11 +1,12 @@ .container { padding-bottom: 0; + background-color: #373737; } .modal { min-width: 450px; width: 100%; - padding-top: 35px; + padding-top: 35px; &__buttons { display: flex; @@ -3,15 +3,20 @@ import { useThemeAndDevice } from '#/shared/lib/hooks' import { Button } from '@mui/material' import { signIn } from 'next-auth/react' import Image from 'next/image' -import React from 'react' +import React, { useState } from 'react' interface YandexAuthButtonProps {} export const YandexAuthButton = ({}: YandexAuthButtonProps) => { const { theme } = useThemeAndDevice() + const [hovered, setHovered] = useState(false) + return (