diff --git a/eslint.config.mjs b/eslint.config.mjs index 7f86eca..c765879 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -11,6 +11,11 @@ const compat = new FlatCompat({ const eslintConfig = [ ...compat.extends('next/core-web-vitals', 'next/typescript'), + { + rules: { + "@typescript-eslint/no-unused-vars": "off", + }, + }, ]; export default eslintConfig; diff --git a/package-lock.json b/package-lock.json index df7ece4..a98e970 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,14 @@ "name": "fire-exam", "version": "0.1.0", "dependencies": { + "@hookform/resolvers": "^5.1.1", "next": "15.3.2", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-hook-form": "^7.57.0", "react-hot-toast": "^2.5.2", - "swiper": "^11.2.8" + "swiper": "^11.2.8", + "zod": "^3.25.56" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -203,6 +206,18 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@hookform/resolvers": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.1.1.tgz", + "integrity": "sha512-J/NVING3LMAEvexJkyTLjruSm7aOFx7QX21pzkiJfMoNG0wl5aFEjLTl7ay7IQb9EWY6AkrBy7tHL2Alijpdcg==", + "license": "MIT", + "dependencies": { + "@standard-schema/utils": "^0.3.0" + }, + "peerDependencies": { + "react-hook-form": "^7.55.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -884,6 +899,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -4768,6 +4789,22 @@ "react": "^19.1.0" } }, + "node_modules/react-hook-form": { + "version": "7.57.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.57.0.tgz", + "integrity": "sha512-RbEks3+cbvTP84l/VXGUZ+JMrKOS8ykQCRYdm5aYsxnDquL0vspsyNhGRO7pcH6hsZqWlPOjLye7rJqdtdAmlg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, "node_modules/react-hot-toast": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.5.2.tgz", @@ -5998,6 +6035,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.25.56", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.56.tgz", + "integrity": "sha512-rd6eEF3BTNvQnR2e2wwolfTmUTnp70aUTqr0oaGbHifzC3BKJsoV+Gat8vxUMR1hwOKBs6El+qWehrHbCpW6SQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index b7dc14a..895cbf8 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,14 @@ "prepare": "husky" }, "dependencies": { + "@hookform/resolvers": "^5.1.1", "next": "15.3.2", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-hook-form": "^7.57.0", "react-hot-toast": "^2.5.2", - "swiper": "^11.2.8" + "swiper": "^11.2.8", + "zod": "^3.25.56" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/public/svg/email-icon.svg b/public/svg/email-icon.svg new file mode 100644 index 0000000..622dddd --- /dev/null +++ b/public/svg/email-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/shared/ui/advanced-phone-input/advanced-phone-input.tsx b/src/shared/ui/advanced-phone-input/advanced-phone-input.tsx index 179f8d1..1db9c5e 100644 --- a/src/shared/ui/advanced-phone-input/advanced-phone-input.tsx +++ b/src/shared/ui/advanced-phone-input/advanced-phone-input.tsx @@ -1,5 +1,5 @@ import s from './advancedPhoneInput.module.scss'; -import { DetailedHTMLProps, InputHTMLAttributes } from 'react'; +import { DetailedHTMLProps, forwardRef, InputHTMLAttributes, Ref } from 'react'; import { clsx } from 'clsx'; import { Button, Input } from '@shared/ui'; @@ -11,17 +11,20 @@ type AdvancedPhoneInputProps = { text: string; } & DetailedHTMLProps, HTMLInputElement>; -export default function AdvancedPhoneInput({ - containerClassName, - inputClassName, - buttonClassName, - onClick, - text, - ...props -}: AdvancedPhoneInputProps) { +const AdvancedPhoneInput = forwardRef(function AdvancedPhoneInput( + { + containerClassName, + inputClassName, + buttonClassName, + onClick, + text, + ...props + }: AdvancedPhoneInputProps, + ref: Ref, +) { return (
- +
); -} +}); + +export default AdvancedPhoneInput; diff --git a/src/shared/ui/input/input.tsx b/src/shared/ui/input/input.tsx index 8f1beb2..3f9d697 100644 --- a/src/shared/ui/input/input.tsx +++ b/src/shared/ui/input/input.tsx @@ -2,7 +2,7 @@ import s from './input.module.scss'; -import { DetailedHTMLProps, InputHTMLAttributes } from 'react'; +import { DetailedHTMLProps, forwardRef, InputHTMLAttributes, Ref } from 'react'; import { clsx } from 'clsx'; type InputProps = { @@ -12,15 +12,14 @@ type InputProps = { variant?: 'default' | 'ghost'; } & DetailedHTMLProps, HTMLInputElement>; -const Input = ({ - className, - fullWidth = false, - variant = 'default', - ...props -}: InputProps) => { +const Input = forwardRef(function Input( + { className, fullWidth = false, variant = 'default', ...props }: InputProps, + ref: Ref, +) { return ( ); -}; +}); export default Input; diff --git a/src/shared/ui/text-area/text-area.tsx b/src/shared/ui/text-area/text-area.tsx index ce89539..1513a2f 100644 --- a/src/shared/ui/text-area/text-area.tsx +++ b/src/shared/ui/text-area/text-area.tsx @@ -1,5 +1,11 @@ import s from './text-area.module.scss'; -import { DetailedHTMLProps, ReactNode, TextareaHTMLAttributes } from 'react'; +import { + DetailedHTMLProps, + forwardRef, + ReactNode, + Ref, + TextareaHTMLAttributes, +} from 'react'; import { clsx } from 'clsx'; type TextAreaProps = { @@ -12,21 +18,27 @@ type TextAreaProps = { HTMLTextAreaElement >; -export default function TextArea({ - className, - children, - variant = 'default', - fullWidth = false, - ...props -}: TextAreaProps) { +const TextArea = forwardRef(function TextArea( + { + className, + children, + variant = 'default', + fullWidth = false, + ...props + }: TextAreaProps, + ref: Ref, +) { return (
); -} +}); + +export default TextArea; diff --git a/src/views/home/ui/contacts/contacts.module.scss b/src/views/home/ui/contacts/contacts.module.scss index e25a581..17c2c02 100644 --- a/src/views/home/ui/contacts/contacts.module.scss +++ b/src/views/home/ui/contacts/contacts.module.scss @@ -236,6 +236,11 @@ margin-left: rem(42px); } + a:hover { + color: #163055; + text-decoration: underline; + } + .Icon { position: absolute; top: 0; diff --git a/src/views/home/ui/contacts/contacts.tsx b/src/views/home/ui/contacts/contacts.tsx index 3bbc273..d244574 100644 --- a/src/views/home/ui/contacts/contacts.tsx +++ b/src/views/home/ui/contacts/contacts.tsx @@ -53,11 +53,11 @@ export default function Contacts() {

- +7 (988) 400 93 93 + +7 (988) 400-93-93

- office@firecheck.ru + spo-71@yandex.ru

diff --git a/src/views/home/ui/footer/footer.tsx b/src/views/home/ui/footer/footer.tsx index d4de59d..f10b6ae 100644 --- a/src/views/home/ui/footer/footer.tsx +++ b/src/views/home/ui/footer/footer.tsx @@ -10,9 +10,23 @@ export default function Footer() {
- - - + + + + + + + + +

Политика конфиденциальности

diff --git a/src/views/home/ui/home.tsx b/src/views/home/ui/home.tsx index f5ac30d..71b993e 100644 --- a/src/views/home/ui/home.tsx +++ b/src/views/home/ui/home.tsx @@ -10,7 +10,7 @@ export default function HomePage() { <>
- + {/**/}