diff --git a/package-lock.json b/package-lock.json index 56d44cd..bccb22c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "@headlessui/react": "^2.1.2", + "@hookform/resolvers": "^3.9.0", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -20,11 +21,13 @@ "iconsax-react": "^0.0.8", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-hook-form": "^7.52.2", "react-otp-input": "^3.1.1", "react-router-dom": "^6.26.0", "react-scripts": "5.0.1", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "yup": "^1.4.0" }, "devDependencies": { "tailwindcss": "^3.4.7" @@ -2622,6 +2625,15 @@ "react-dom": "^18" } }, + "node_modules/@hookform/resolvers": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.0.tgz", + "integrity": "sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==", + "license": "MIT", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -15767,6 +15779,12 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "license": "MIT" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -16160,6 +16178,22 @@ "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", "license": "MIT" }, + "node_modules/react-hook-form": { + "version": "7.52.2", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.2.tgz", + "integrity": "sha512-pqfPEbERnxxiNMPd0bzmt1tuaPcVccywFDpyk2uV5xCIBphHV5T8SVnX9/o3kplPE1zzKt77+YIoq+EMwJp56A==", + "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-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -18254,6 +18288,12 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "license": "MIT" }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", + "license": "MIT" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -18290,6 +18330,12 @@ "node": ">=0.6" } }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "license": "MIT" + }, "node_modules/tough-cookie": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", @@ -19784,6 +19830,30 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yup": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz", + "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==", + "license": "MIT", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index ba45ed4..0b91c64 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@headlessui/react": "^2.1.2", + "@hookform/resolvers": "^3.9.0", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -15,11 +16,13 @@ "iconsax-react": "^0.0.8", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-hook-form": "^7.52.2", "react-otp-input": "^3.1.1", "react-router-dom": "^6.26.0", "react-scripts": "5.0.1", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "yup": "^1.4.0" }, "scripts": { "start": "react-scripts start", diff --git a/src/components/common/error.tsx b/src/components/common/error.tsx new file mode 100644 index 0000000..46332f7 --- /dev/null +++ b/src/components/common/error.tsx @@ -0,0 +1,17 @@ + +import { FC } from "react"; + +type Props = { + message: any; + show: any; +}; + +export const ErrorComponent: FC = ({ message, show }) => { + return ( + show && ( +

+ * {message} +

+ ) + ); +}; diff --git a/src/components/common/input.tsx b/src/components/common/input.tsx index 4eb4d48..cc2bc7a 100644 --- a/src/components/common/input.tsx +++ b/src/components/common/input.tsx @@ -6,22 +6,21 @@ type Props = { style?: string, type?: React.HTMLInputTypeAttribute, placeholder: string, - icon?: React.ReactNode + icon?: React.ReactNode, + other?: any } -export const Input: FC = ({ placeholder, type = "text", icon }) => { +export const Input: FC = ({ placeholder, type = "text", icon, other }) => { const [hidden, setHidden] = useState(false) const handleHidden = () => setHidden(prev => !prev) return ( -
{type === "password" ? !hidden ? : : icon}
-
- ) } \ No newline at end of file diff --git a/src/components/forms/login-form.tsx b/src/components/forms/login-form.tsx index 738ad46..e51898c 100644 --- a/src/components/forms/login-form.tsx +++ b/src/components/forms/login-form.tsx @@ -1,9 +1,25 @@ import { Link } from "react-router-dom" import { Input } from "../common/input" +import { Button } from "@headlessui/react" +import { Controller, SubmitHandler, useForm } from "react-hook-form" +import { LoginFormInterface } from "../../types" +import { loginSchema } from "../../schema" +import { ErrorComponent } from "../common/error" +import { yupResolver } from '@hookform/resolvers/yup' export const LoginForm = () => { + const { + handleSubmit, + formState: { errors }, + control, + } = useForm({ + resolver: yupResolver(loginSchema) + }) + const handleLoginSubmit: SubmitHandler = async (data) => { + console.log("data=>", data) + } return ( -
logo
@@ -17,15 +33,25 @@ export const LoginForm = () => {
- - + ( + <> + + + + )} /> + ( + <> + + + + )} />

فراموشی رمز عبور

- +

ورود با رمز یکبار مصرف

- + ) } \ No newline at end of file diff --git a/src/schema/index.ts b/src/schema/index.ts new file mode 100644 index 0000000..8cdf516 --- /dev/null +++ b/src/schema/index.ts @@ -0,0 +1,12 @@ +import * as yup from 'yup' + +export const loginSchema = yup.object({ + phoneNumber: yup.string() + .required("وارد کردن شماره تماس الزامی میباشد") + .min(11, "شماره تماس نمیتوند کمتر از 11 رقم باشد") + .max(11, "شماره تماس نمیتواند بیشتر از 11 رقم باشد") + .matches(/^[0-9]{11}$/, "شماره تماس نامعتبر"), + password: yup.string() + .required("وارد کردن رمزعبور الزامی میباشد") + .min(8, "رمزعبور نمیتواند کمتر از 8 کاراکتر باشد") +}) \ No newline at end of file diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..cb9cfe5 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,4 @@ +export interface LoginFormInterface { + phoneNumber: string, + password: string +} \ No newline at end of file