From 6b1389c066f3c416441ddd008a052172937814f1 Mon Sep 17 00:00:00 2001 From: GaoNeng-wWw Date: Mon, 22 Jul 2024 12:50:52 +0800 Subject: [PATCH 1/3] refactor: login page --- app/(root)/authenticate/layout.tsx | 21 +++- app/(root)/authenticate/login/page.tsx | 77 ++++++++++++++ app/(root)/authenticate/page.tsx | 124 ++++++---------------- app/(root)/authenticate/register/page.tsx | 15 +++ app/(root)/layout.tsx | 2 +- app/layout.tsx | 2 +- app/store.ts | 3 +- 7 files changed, 149 insertions(+), 95 deletions(-) create mode 100644 app/(root)/authenticate/login/page.tsx create mode 100644 app/(root)/authenticate/register/page.tsx diff --git a/app/(root)/authenticate/layout.tsx b/app/(root)/authenticate/layout.tsx index c653baa..3036b01 100644 --- a/app/(root)/authenticate/layout.tsx +++ b/app/(root)/authenticate/layout.tsx @@ -1,4 +1,12 @@ +'use client' import React from "react"; +import {AnimatePresence, motion} from 'framer-motion'; + +const variants = { + hidden: { opacity: 0 }, + enter: { opacity: 1 }, + exit: { opacity: 0 }, +}; export default function AuthenticateLayout({children}: { children: React.ReactNode; @@ -6,7 +14,18 @@ export default function AuthenticateLayout({children}: { return (
- {children} + + + {children} + +
); diff --git a/app/(root)/authenticate/login/page.tsx b/app/(root)/authenticate/login/page.tsx new file mode 100644 index 0000000..e5d12f1 --- /dev/null +++ b/app/(root)/authenticate/login/page.tsx @@ -0,0 +1,77 @@ +'use client'; +import { useState } from "react"; +import { Login } from "../components/login"; +import { useAtom } from "jotai"; +import { accountAtom } from "@/app/store"; +import { Button, Card, CardBody, CardFooter, Checkbox, Input } from "@nextui-org/react"; +import Link from "next/link"; +import IOC from "@/providers"; +import { UserAPI } from "@/interface/userAPI"; +import { Message } from "@/components/message"; +import { SetLoggedInState } from "@/interface/hooks"; +import { useRouter } from "next/navigation"; +export default function LoginPage(){ + const [password, setPassword] = useState(''); + const [account, setAccount] = useAtom(accountAtom); + const [policy, setPolicy] = useState(false); + const [loading, setLoading] = useState(false); + const router = useRouter(); + const login = () => { + setLoading(true); + UserAPI.login(account, password) + .then(( + [state, text] + )=>{ + if (state){ + Message.success('登陆成功'); + SetLoggedInState(true); + router.push('/dashboard') + } else { + Message.success(text); + } + }) + .finally(()=>{ + setLoading(false); + }) + } + return ( +
+ + +
+
+ + +
+ + 点击注册 + +
+
+ + 登录或注册即代表同意服务条款 + +
+
+ + + +
+
+ ) +} \ No newline at end of file diff --git a/app/(root)/authenticate/page.tsx b/app/(root)/authenticate/page.tsx index 84953e9..49788e5 100644 --- a/app/(root)/authenticate/page.tsx +++ b/app/(root)/authenticate/page.tsx @@ -11,7 +11,7 @@ import { Message } from '@/components/message'; import { useRouter } from 'next/navigation'; import { SetLoggedInState } from '@/interface/hooks'; import { UserAPI } from '@/interface/userAPI'; -import { useDebounceFn } from 'ahooks'; +import { useDebounceFn, useUpdateEffect } from 'ahooks'; export type Colors = "default" | "primary" | "secondary" | "success" | "warning" | "danger" | undefined; export type PageType = 'wait-check' | 'login' | 'register' @@ -86,7 +86,15 @@ export default function Page(){ .then((exists:boolean) => exists) .catch(() => false); } - const checkAccountExists = useDebounceFn(()=>{ + + + const onChangeAccount = (account: string) => { + setAccount(account); + setPageType("wait-check"); + } + + const accountCheck = () => { + setLoading(true); if (email){ checkAccountExistsByEmail() .then((exists) => { @@ -94,85 +102,37 @@ export default function Page(){ }) .finally(() => setLoading(false)); } - }, {wait: 1000}) - useEffect(()=>{ - checkAccountExists.run(); - }, [account]); - const invoke = () => { - const checkAccount = () => { - setLoading(true); - if (email){ - checkAccountExistsByEmail() - .then((exists) => { - setShowErr(!exists) - }) - .finally(() => setLoading(false)); - } - if (phone){ - checkAccountExistsByPhone() - .then((exists) => { - if (!exists){ - setPageType('register') - return; - } - setPageType('login') - }) - .finally(()=>{ - setLoading(false); - }) - } - } - const login = () => { - setLoading(true) - UserAPI.login(account, password) - .then((r) => { - const [state, text] = r; - if (state) { - Message.success("登录成功"); - SetLoggedInState(true); - router.push("/dashboard"); - } else { - Message.error(text); - setLoading(false) + if (phone){ + checkAccountExistsByPhone() + .then((exists) => { + if (!exists){ + setPageType('register') + return; } + setPageType('login') + }) + .finally(()=>{ + setLoading(false); }) } - const reg = () => { - setLoading(true) - if (phone){ - IOC.user.createUser({ - phone: account, - password, - username: userName, - code - }) - .then(() => { - Message.success('注册成功, 请登录'); - setPageType('login'); - setPassword(''); - return; - }) - .finally(() => setLoading(false)); - } - } - const obj:Recordvoid> = { - 'login': login, - 'register': reg, - 'wait-check': checkAccount - } - return obj[pageType] } const onEnter = (e:KeyboardEvent) => { if (!disabled && e.code.toLowerCase().includes('enter')){ e.preventDefault(); - invoke()(); + accountCheck() } } - - const onChangeAccount = (account: string) => { - setAccount(account); - setPageType("wait-check"); - } + useEffect(()=>{ + return ()=>{ + router.prefetch('/authenticate/login') + router.prefetch('/authenticate/register') + } + },[]); + useUpdateEffect(()=>{ + if (pageType !== 'wait-check'){ + router.push(`/authenticate/${pageType}`); + } + }, [pageType]); return (
@@ -194,31 +154,13 @@ export default function Page(){ } - { - pageType !== 'wait-check' ? pageType === 'login' ? - : - pageType === 'register' ? - : null : null - } 登录或注册即代表同意服务条款 - diff --git a/app/(root)/authenticate/register/page.tsx b/app/(root)/authenticate/register/page.tsx new file mode 100644 index 0000000..f4980bb --- /dev/null +++ b/app/(root)/authenticate/register/page.tsx @@ -0,0 +1,15 @@ +'use client' + +import { Card, CardBody } from "@nextui-org/react"; + +export default function RegisterPage(){ + return ( + + + +

reg

+
+
+ + ) +} \ No newline at end of file diff --git a/app/(root)/layout.tsx b/app/(root)/layout.tsx index a8b1f5f..9575858 100644 --- a/app/(root)/layout.tsx +++ b/app/(root)/layout.tsx @@ -46,7 +46,7 @@ export default function RootLayout({children,}: { } } } gutter={-15}/> - + {children} diff --git a/app/layout.tsx b/app/layout.tsx index db3bb40..33e6273 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -39,7 +39,7 @@ export default function Root(
- + {children}
diff --git a/app/store.ts b/app/store.ts index d99771a..f742469 100644 --- a/app/store.ts +++ b/app/store.ts @@ -15,4 +15,5 @@ export const profile = atom(null); export const verify = atom(true); export const uploadStack = atom([]); export const currentFolderId = atom('1'); -export const folderId = atom([{id: '1', name: 'root'}]) \ No newline at end of file +export const folderId = atom([{id: '1', name: 'root'}]) +export const accountAtom = atom(''); \ No newline at end of file From 8466d009404124fdd213fb05f159125cbf86da84 Mon Sep 17 00:00:00 2001 From: GaoNeng-wWw Date: Mon, 22 Jul 2024 13:56:36 +0800 Subject: [PATCH 2/3] refactor: register page --- .../authenticate/components/register.tsx | 3 - app/(root)/authenticate/hooks/useRegister.ts | 22 +++ app/(root)/authenticate/hooks/useValide.ts | 14 +- app/(root)/authenticate/layout.tsx | 29 ++-- app/(root)/authenticate/login/page.tsx | 2 +- app/(root)/authenticate/page.tsx | 14 +- app/(root)/authenticate/register/page.tsx | 142 +++++++++++++++++- 7 files changed, 183 insertions(+), 43 deletions(-) create mode 100644 app/(root)/authenticate/hooks/useRegister.ts diff --git a/app/(root)/authenticate/components/register.tsx b/app/(root)/authenticate/components/register.tsx index 35d6e14..5985bd7 100644 --- a/app/(root)/authenticate/components/register.tsx +++ b/app/(root)/authenticate/components/register.tsx @@ -15,7 +15,6 @@ export default function Register({ userName, setCode, setPassword, - setAccount, setConfirmPassword, setUserName }: RegisterProps){ @@ -86,11 +85,9 @@ export interface RegisterProps { password: string; confirmPassword: string; passwordRobustness: boolean[]; - valide: boolean; userName: string; setCode: (val: string) => void; setPassword: (val: string) => void, - setAccount: (val: string) => void, setConfirmPassword: (val: string) => void, setUserName: (val:string) => void; } diff --git a/app/(root)/authenticate/hooks/useRegister.ts b/app/(root)/authenticate/hooks/useRegister.ts new file mode 100644 index 0000000..15ac114 --- /dev/null +++ b/app/(root)/authenticate/hooks/useRegister.ts @@ -0,0 +1,22 @@ +import { useState } from "react" + +export const useRegister = ( +) => { + const [code, setCode] = useState(''); + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [passwordRobustness, setRobustness] = useState([]); + const [userName, setUsername] = useState(''); + return { + code, + setCode, + password, + setPassword, + confirmPassword, + setConfirmPassword, + passwordRobustness, + setRobustness, + userName, + setUsername + } +} \ No newline at end of file diff --git a/app/(root)/authenticate/hooks/useValide.ts b/app/(root)/authenticate/hooks/useValide.ts index b470ebe..1569361 100644 --- a/app/(root)/authenticate/hooks/useValide.ts +++ b/app/(root)/authenticate/hooks/useValide.ts @@ -1,6 +1,7 @@ -import { useEffect, useMemo, useState } from "react" +import { useCallback, useEffect, useMemo, useState } from "react" import { PageType } from "../page"; -import { z,ZodError } from 'zod'; +import { z,ZodError, ZodIssue } from 'zod'; +import { useUpdate, useUpdateEffect } from "ahooks"; const validateEmail = (val: string) => val.match(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,10}$/i); const validatePhone = (val: string) => val.match(/^1[3-9]\d{9}$/i); @@ -42,26 +43,25 @@ export const useValide = ( props: Partial, ) => { const [valide, setValide] = useState(false); - const [errors, setErrors] = useState(); + const [errors, setErrors] = useState(); const valideData = ()=>{ if (pageType !== 'register'){ const schemaValideRes = schema[pageType].safeParse(props); if (!schemaValideRes.success){ - setErrors(schemaValideRes.error) + setErrors(schemaValideRes.error.errors) } setValide(schemaValideRes.success); return; } if (pageType === 'register'){ - console.log(props.password, props.confirmPassword) const schemaRes = schema['register'].safeParse(props) setValide(schemaRes.success && (props.password === props.confirmPassword)); if (!schemaRes.success){ - setErrors(schemaRes.error) + setErrors(schemaRes.error.errors) } return; } - } + }; return { valide,errors, setValide,setErrors, diff --git a/app/(root)/authenticate/layout.tsx b/app/(root)/authenticate/layout.tsx index 3036b01..2322c40 100644 --- a/app/(root)/authenticate/layout.tsx +++ b/app/(root)/authenticate/layout.tsx @@ -1,31 +1,20 @@ 'use client' import React from "react"; -import {AnimatePresence, motion} from 'framer-motion'; - -const variants = { - hidden: { opacity: 0 }, - enter: { opacity: 1 }, - exit: { opacity: 0 }, -}; +import { useMount } from "ahooks"; +import { useRouter } from "next/navigation"; export default function AuthenticateLayout({children}: { children: React.ReactNode; }) { + const router = useRouter(); + useMount(()=>{ + router.prefetch('/authenticate/login') + router.prefetch('/authenticate/register') + }) return (
-
- - - {children} - - +
+ {children}
); diff --git a/app/(root)/authenticate/login/page.tsx b/app/(root)/authenticate/login/page.tsx index e5d12f1..509cdfa 100644 --- a/app/(root)/authenticate/login/page.tsx +++ b/app/(root)/authenticate/login/page.tsx @@ -36,7 +36,7 @@ export default function LoginPage(){ } return (
- +
diff --git a/app/(root)/authenticate/page.tsx b/app/(root)/authenticate/page.tsx index 49788e5..ae0159f 100644 --- a/app/(root)/authenticate/page.tsx +++ b/app/(root)/authenticate/page.tsx @@ -11,13 +11,15 @@ import { Message } from '@/components/message'; import { useRouter } from 'next/navigation'; import { SetLoggedInState } from '@/interface/hooks'; import { UserAPI } from '@/interface/userAPI'; -import { useDebounceFn, useUpdateEffect } from 'ahooks'; +import { useDebounceFn, useMount, useUpdateEffect } from 'ahooks'; +import { accountAtom } from '@/app/store'; +import { useAtom } from 'jotai'; export type Colors = "default" | "primary" | "secondary" | "success" | "warning" | "danger" | undefined; export type PageType = 'wait-check' | 'login' | 'register' export default function Page(){ - const [account, setAccount] = useState('') + const [account, setAccount] = useAtom(accountAtom) const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [accountExists, setAccountExists] = useState(false); @@ -122,12 +124,6 @@ export default function Page(){ accountCheck() } } - useEffect(()=>{ - return ()=>{ - router.prefetch('/authenticate/login') - router.prefetch('/authenticate/register') - } - },[]); useUpdateEffect(()=>{ if (pageType !== 'wait-check'){ router.push(`/authenticate/${pageType}`); @@ -135,7 +131,7 @@ export default function Page(){ }, [pageType]); return ( - +
diff --git a/app/(root)/authenticate/register/page.tsx b/app/(root)/authenticate/register/page.tsx index f4980bb..7a3290c 100644 --- a/app/(root)/authenticate/register/page.tsx +++ b/app/(root)/authenticate/register/page.tsx @@ -1,14 +1,150 @@ 'use client' -import { Card, CardBody } from "@nextui-org/react"; +import { accountAtom } from "@/app/store"; +import { Button, Card, CardBody, CardFooter, CardHeader, Checkbox, Input, Link } from "@nextui-org/react"; +import { useAtom } from "jotai"; +import Register from "../components/register"; +import { useEffect, useMemo, useState } from "react"; +import { useRegister } from "../hooks/useRegister"; +import { useMount, useUpdateEffect } from "ahooks"; +import { useButton } from "../hooks/useButton"; +import { useValide } from "../hooks/useValide"; +import { IoChevronBackSharp } from "react-icons/io5"; +import IOC from "@/providers"; +import { Message } from "@/components/message"; +import { useRouter } from "next/navigation"; + +const isEmail = (val: string): boolean => /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/gim.test(val); +const isPhone = (val: string): boolean => /^[0-9]{7,32}$/gim.test(val); export default function RegisterPage(){ + const [account, setAccount] = useAtom(accountAtom); + + const { + code, + password, + confirmPassword, + passwordRobustness, + userName, + setCode, + setPassword, + setConfirmPassword, + setUsername, + setRobustness, + } = useRegister(); + const [policy, setPolicy] = useState(false); + const accountType = useMemo(() => isPhone(account) ? 'phone' : isEmail(account) ? 'email' : '', [account]); + const [loading, setLoading] = useState(false); + const router = useRouter(); + const {valide, valideData, errors} = useValide('register', { + password, + confirmPassword, + checkCode: code, + passwordRobustness, + pageType: 'register', + isEmail: accountType === 'email', + isPhone: accountType === 'phone', + account, + accountExists: false, + userName, + policyState: policy + }) + useEffect(()=>{ + valideData() + }, [account, policy, password, confirmPassword, code, userName, passwordRobustness]); + const {buttonMessage, color, disabled} = useButton({ + pageType: 'register', + valide, + }) + const fns = useMemo(() => { + return [ + (val: string) => val.length > 5, + (val: string) => /[A-Z]/.test(val), + (val: string) => /[a-z]/.test(val), + (val: string) => /[0-9]/.test(val), + (val: string) => /\W/.test(val), + (val: string) => val.length < 20 + ] + }, []) + useMount(()=>{ + setRobustness( + Array.from({length: fns.length}, ()=>false) + ) + }) + useUpdateEffect(()=>{ + setRobustness( + [...fns.map(fn => fn(password))] + ) + },[password,fns, setRobustness]) + + const reg = () => { + if (errors && errors.length){ + const [err] = errors; + Message.error(err.message); + return; + } + IOC.user.createUser({ + username: userName, + phone: account, + password, + code + }) + .then(({data}) => data) + .then(() => { + Message.success('注册成功, 请登录'); + router.replace('/authenticate/login'); + setPassword(''); + }) + .finally(() => setLoading(false)); + } + return ( - + + +
+ + + +
+
-

reg

+
+ + + + 登录或注册即代表同意服务条款 + +
+ + +
) From 6f801875563e5ee1d1ce4746b57ea409df83c262 Mon Sep 17 00:00:00 2001 From: GaoNeng-wWw Date: Mon, 22 Jul 2024 14:05:41 +0800 Subject: [PATCH 3/3] refactor: clean authenticate --- app/(root)/authenticate/page.tsx | 69 ++++---------------------------- 1 file changed, 7 insertions(+), 62 deletions(-) diff --git a/app/(root)/authenticate/page.tsx b/app/(root)/authenticate/page.tsx index ae0159f..95c1c7d 100644 --- a/app/(root)/authenticate/page.tsx +++ b/app/(root)/authenticate/page.tsx @@ -1,17 +1,12 @@ 'use client' import { Button, Card, CardBody, CardFooter, Checkbox, Input } from '@nextui-org/react'; -import { KeyboardEvent, useEffect, useMemo, useState} from 'react'; +import { KeyboardEvent, useEffect, useState} from 'react'; import { useAccountDiscriminator, useValide } from './hooks/useValide'; import { useButton } from './hooks/useButton'; import IOC from '@/providers'; -import { Login } from './components/login'; -import Register from './components/register'; -import { Message } from '@/components/message'; import { useRouter } from 'next/navigation'; -import { SetLoggedInState } from '@/interface/hooks'; -import { UserAPI } from '@/interface/userAPI'; -import { useDebounceFn, useMount, useUpdateEffect } from 'ahooks'; +import { useUpdateEffect } from 'ahooks'; import { accountAtom } from '@/app/store'; import { useAtom } from 'jotai'; @@ -20,64 +15,16 @@ export type PageType = 'wait-check' | 'login' | 'register' export default function Page(){ const [account, setAccount] = useAtom(accountAtom) - const [password, setPassword] = useState(''); - const [confirmPassword, setConfirmPassword] = useState(''); - const [accountExists, setAccountExists] = useState(false); - const [code, setCode] = useState(''); - const [passwordRobustness, setPasswordRobustness] = useState(new Array(6).fill(false)); - const [userName, setUserName] = useState(''); - const [pageType, setPageType] = useState('wait-check'); const [policy, setPolicy] = useState(false); const [showErr, setShowErr] = useState(false); const {phone, email} = useAccountDiscriminator(account) - const {valide, errors, valideData} = useValide(pageType, { - account, - policyState: policy, - password, - confirmPassword, - checkCode: code, - userName, - passwordRobustness, - isPhone: phone, - isEmail: email, - }); + const {valide, valideData} = useValide(pageType, { account, policyState: policy, isPhone: phone, isEmail: email }); const {color, disabled, loading, setLoading, buttonMessage} = useButton({pageType, valide }); const router = useRouter(); - const fns = useMemo(() => { - return [ - (val: string) => val.length > 5, - (val: string) => /[A-Z]/.test(val), - (val: string) => /[a-z]/.test(val), - (val: string) => /[0-9]/.test(val), - (val: string) => /\W/.test(val), - (val: string) => val.length < 20 - ] - }, []) - useEffect(()=>{ - if (pageType !== 'wait-check' && account.length === 0){ - setPageType('wait-check'); - } - }, [pageType, account]) useEffect(()=>{ valideData() - }, [ - account, - policy, - password, - confirmPassword, - code, - userName, - passwordRobustness, - phone, - email, - pageType - ]); - useEffect(()=>{ - setPasswordRobustness( - [...fns.map(fn => fn(password))] - ) - }, [password, fns]) + }, [ account, policy, phone, email, pageType ]); const checkAccountExistsByEmail = () => { return IOC.user.checkEmail(account) .then((exists:boolean) => exists) @@ -88,8 +35,6 @@ export default function Page(){ .then((exists:boolean) => exists) .catch(() => false); } - - const onChangeAccount = (account: string) => { setAccount(account); setPageType("wait-check"); @@ -136,8 +81,8 @@ export default function Page(){
}
- + 登录或注册即代表同意服务条款