From c629f0dcf8ad52934ed8980f1f6ad6b57d7ae92f Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Wed, 23 Apr 2025 12:32:27 +0300 Subject: [PATCH] feat: form hook --- bun.lock | 3 ++ package.json | 1 + src/components/ui/Button.module.scss | 2 +- src/components/ui/Button.tsx | 4 +- src/components/ui/Input.tsx | 30 ++++++-------- src/pages/login.dto.ts | 4 ++ src/pages/login.tsx | 59 ++++++++++++++++++---------- 7 files changed, 62 insertions(+), 41 deletions(-) create mode 100644 src/pages/login.dto.ts diff --git a/bun.lock b/bun.lock index e8e6326..a99175a 100644 --- a/bun.lock +++ b/bun.lock @@ -14,6 +14,7 @@ "preact-iso": "^2.9.1", "primelocale": "^2.1.2", "primereact": "^10.9.4", + "react-hook-form": "^7.56.1", "tailwind-merge": "^3.0.2", "tailwind-variants": "^1.0.0", "tailwindcss": "^4.0.17", @@ -612,6 +613,8 @@ "react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="], + "react-hook-form": ["react-hook-form@7.56.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-qWAVokhSpshhcEuQDSANHx3jiAEFzu2HAaaQIzi/r9FNPm1ioAvuJSD4EuZzWd7Al7nTRKcKPnBKO7sRn+zavQ=="], + "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], diff --git a/package.json b/package.json index bd41b7b..6966121 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "preact-iso": "^2.9.1", "primelocale": "^2.1.2", "primereact": "^10.9.4", + "react-hook-form": "^7.56.1", "tailwind-merge": "^3.0.2", "tailwind-variants": "^1.0.0", "tailwindcss": "^4.0.17" diff --git a/src/components/ui/Button.module.scss b/src/components/ui/Button.module.scss index cce2982..7c42059 100644 --- a/src/components/ui/Button.module.scss +++ b/src/components/ui/Button.module.scss @@ -1,5 +1,5 @@ @reference '../../index.scss'; .button { - @apply rounded-4xl px-4 py-3 text-xl text-black shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] transition-colors hover:cursor-pointer; + @apply rounded-4xl px-4 py-3 text-xl text-black shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] transition-colors hover:cursor-pointer focus:outline-1; } diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx index 207430f..3ab1198 100644 --- a/src/components/ui/Button.tsx +++ b/src/components/ui/Button.tsx @@ -16,6 +16,7 @@ interface ButtonProps { color?: "primary" | "secondary" | "red"; onClick?: () => void; className?: string; + type?: "button" | "submit"; } const Button: FunctionComponent = ({ @@ -23,9 +24,10 @@ const Button: FunctionComponent = ({ onClick = () => {}, color = "primary", className = "", + type = "button", }) => { return ( - ); diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx index ffe4f7c..21f33cc 100644 --- a/src/components/ui/Input.tsx +++ b/src/components/ui/Input.tsx @@ -1,5 +1,5 @@ import { cn } from "@/utils/class-merge"; -import { FunctionComponent, Ref } from "preact"; +import { forwardRef, HTMLProps, useEffect } from "preact/compat"; import { tv } from "tailwind-variants"; import classes from "./Input.module.scss"; @@ -20,29 +20,19 @@ const input = tv({ }, }); -interface InputProps { - isPassword?: boolean; - placeholder?: string; +interface InputProps extends HTMLProps { textAlign?: "center" | "left"; error?: string; - textRef?: Ref | null; } -const Input: FunctionComponent = ({ - isPassword = false, - placeholder = "", - textAlign, - error = "", - textRef = null, -}: InputProps) => { +const Input = forwardRef((props, ref) => { + const { textAlign, error, type = "text", ...rest } = props; + useEffect(() => { + console.log(`error: ${error}`); + }, [error]); return (
- +

= ({

); -}; +}); + +Input.displayName = "AHInput"; export default Input; diff --git a/src/pages/login.dto.ts b/src/pages/login.dto.ts new file mode 100644 index 0000000..54769df --- /dev/null +++ b/src/pages/login.dto.ts @@ -0,0 +1,4 @@ +export interface ILoginForm { + login: string; + password: string; +} diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 9515e8f..18319a1 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -6,7 +6,9 @@ import { useAppContext } from "@/providers/AuthProvider"; import { FunctionComponent } from "preact"; import { useLocation } from "preact-iso"; import "preact/debug"; -import { useRef, useState } from "preact/hooks"; +import { useState } from "preact/hooks"; +import { Controller, SubmitHandler, useForm } from "react-hook-form"; +import { ILoginForm } from "./login.dto"; import classes from "./login.module.scss"; const testUser = { @@ -16,37 +18,54 @@ const testUser = { const LoginPage: FunctionComponent = () => { const { isLoggedIn } = useAppContext(); const { route } = useLocation(); - const loginRef = useRef(null); - const passwordRef = useRef(null); - const [loginError, setLoginError] = useState(""); const [passwordError, setPasswordError] = useState(""); - const login = async () => { - if (!loginRef.current || !passwordRef.current) return; - setLoginError(""); - setPasswordError(""); - if (!loginRef.current.value.length || !passwordRef.current.value.length) { - if (!loginRef.current.value.length) setLoginError("Введите логин"); - if (!passwordRef.current.value.length) setPasswordError("Введите пароль"); - return; - } - if (loginRef.current.value !== testUser.login || passwordRef.current.value !== testUser.password) { - setLoginError("Неправильный логин или пароль"); + const login: SubmitHandler = async (data) => { + console.log(data); + if (data.login !== testUser.login || data.password !== testUser.password) { + setError("login", { message: "Неверный" }); //TODO: не показывает ошибку return; } isLoggedIn.value = true; localStorage.setItem("loggedIn", "true"); route("/profile/tasks", true); }; + const { control, handleSubmit, formState, setError } = useForm({ + defaultValues: { + login: "", + password: "", + }, + mode: "onChange", + }); if (isLoggedIn.value) route("/profile/tasks", true); return !isLoggedIn.value ? (

Антихвост

- - - +
login(data))}> + ( + + )} + /> + ( + + )} + /> + +
) : (