Skip to content

Commit 02c5e9e

Browse files
committed
feat: login page
Signed-off-by: Innei <[email protected]>
1 parent 9ad87c3 commit 02c5e9e

File tree

10 files changed

+114
-11
lines changed

10 files changed

+114
-11
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"@tanstack/react-query-devtools": "4.29.14",
5454
"@tanstack/react-query-persist-client": "4.29.14",
5555
"@uidotdev/usehooks": "2.0.1",
56+
"@vercel/analytics": "1.0.1",
5657
"axios": "1.4.0",
5758
"clsx": "1.2.1",
5859
"daisyui": "3.1.1",

pnpm-lock.yaml

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/@login/page.tsx

-3
This file was deleted.

src/app/layout.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import '../styles/index.css'
22

33
import { dehydrate } from '@tanstack/react-query'
4+
import { Analytics } from '@vercel/analytics/react'
45
import { ToastContainer } from 'react-toastify'
56

67
import { ClerkProvider } from '@clerk/nextjs'
@@ -95,6 +96,7 @@ export default async function RootLayout(props: Props) {
9596
<ToastContainer />
9697
</body>
9798
</html>
99+
<Analytics />
98100
</ClerkProvider>
99101
)
100102
}

src/app/login/page.tsx

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use client'
2+
3+
import { useState } from 'react'
4+
import { useRouter } from 'next/navigation'
5+
6+
import { login } from '~/atoms/owner'
7+
import { MotionButtonBase } from '~/components/ui/button'
8+
import { Routes } from '~/lib/route-builder'
9+
10+
export default () => {
11+
const [username, setUsername] = useState('')
12+
const [password, setPassword] = useState('')
13+
const router = useRouter()
14+
15+
const handleLogin = (e: any) => {
16+
e.preventDefault()
17+
login(username, password).then(() => {
18+
router.push(Routes.Home)
19+
})
20+
}
21+
return (
22+
<div className="flex min-h-[calc(100vh-7rem)] center">
23+
<form className="flex flex-col space-y-5" onSubmit={handleLogin}>
24+
<input
25+
autoFocus
26+
value={username}
27+
onChange={(e) => setUsername(e.target.value)}
28+
type="text"
29+
placeholder="Username"
30+
className="input w-full max-w-xs"
31+
/>
32+
<input
33+
value={password}
34+
onChange={(e) => setPassword(e.target.value)}
35+
type="password"
36+
placeholder="Password"
37+
className="input w-full max-w-xs"
38+
/>
39+
40+
<div className="flex center">
41+
<MotionButtonBase
42+
disabled={!username || !password}
43+
className="btn-primary btn text-white"
44+
onClick={handleLogin}
45+
>
46+
Login
47+
</MotionButtonBase>
48+
</div>
49+
</form>
50+
</div>
51+
)
52+
}

src/atoms/owner.ts

+24-3
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,43 @@ const ownerAtom = atom((get) => {
1111
})
1212
const tokenAtom = atom(null as string | null)
1313

14-
export const login = async () => {
14+
export const login = async (username?: string, password?: string) => {
15+
if (username && password) {
16+
const user = await apiClient.user.login(username, password).catch((err) => {
17+
console.error(err)
18+
toast('再试试哦', 'error')
19+
return null
20+
})
21+
if (user) {
22+
const token = user.token
23+
setToken(token)
24+
jotaiStore.set(tokenAtom, token)
25+
26+
toast(`欢迎回来,${jotaiStore.get(ownerAtom)?.name}`, 'success')
27+
}
28+
29+
return Promise.resolve()
30+
}
31+
1532
const token = getToken()
1633
if (!token) {
1734
return
1835
}
36+
const outdateToast = () => toast('登录身份过期了,再登录一下吧!', 'warning')
1937
const validated = await apiClient.user
2038
.checkTokenValid(token)
2139
.then((res) => !!res.ok)
2240

2341
.catch(() => {
2442
removeToken()
25-
toast('登录身份过期了,再登录一下吧!', 'warning')
43+
outdateToast()
2644
return false
2745
})
2846

29-
if (!validated) return
47+
if (!validated) {
48+
outdateToast()
49+
return
50+
}
3051

3152
apiClient.user.proxy.login.put<{ token: string }>().then((res) => {
3253
jotaiStore.set(tokenAtom, res.token)

src/components/layout/header/internal/AnimatedLogo.tsx

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
'use client'
22

33
import { AnimatePresence, motion } from 'framer-motion'
4+
import { useRouter } from 'next/navigation'
45

56
import { useViewport } from '~/atoms'
7+
import { useSingleAndDoubleClick } from '~/hooks/common/use-single-double-click'
8+
import { Routes } from '~/lib/route-builder'
69

710
import { useHeaderMetaShouldShow } from './hooks'
811
import { Logo } from './Logo'
912

13+
const TapableLogo = () => {
14+
const router = useRouter()
15+
const fn = useSingleAndDoubleClick(
16+
() => {
17+
router.push(Routes.Home)
18+
},
19+
() => {
20+
router.push(Routes.Login)
21+
},
22+
)
23+
return <Logo onClick={fn} className="cursor-pointer" />
24+
}
1025
export const AnimatedLogo = () => {
1126
const shouldShowMeta = useHeaderMetaShouldShow()
1227

1328
const isDesktop = useViewport(($) => $.lg && $.w !== 0)
1429

15-
if (isDesktop) return <Logo />
30+
if (isDesktop) return <TapableLogo />
1631

1732
return (
1833
<AnimatePresence>
@@ -23,7 +38,7 @@ export const AnimatedLogo = () => {
2338
exit={{ opacity: 0 }}
2439
className="scale-75"
2540
>
26-
<Logo />
41+
<TapableLogo />
2742
</motion.div>
2843
)}
2944
</AnimatePresence>

src/components/layout/header/internal/Logo.tsx

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
export const Logo = () => {
1+
import type { SVGProps } from 'react'
2+
3+
import { clsxm } from '~/utils/helper'
4+
5+
export const Logo = (props: SVGProps<SVGSVGElement>) => {
26
return (
37
<svg
4-
className="inline-block h-[4.5rem] p-3"
58
viewBox="0 0 220 220"
69
version="1.1"
710
xmlns="http://www.w3.org/2000/svg"
11+
{...props}
12+
className={clsxm('inline-block h-[4.5rem] p-3', props.className)}
813
>
914
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
1015
<g id="forest-black" transform="translate(25.000000, 25.000000)">

src/lib/route-builder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export enum Routes {
2-
Home = '/home',
2+
Home = '/',
33
Posts = '/posts',
44
Post = '/posts/',
55
Notes = '/notes',

src/styles/toastify.css

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
right: 12px;
77
width: 300px;
88
}
9+
.Toastify__toast-icon {
10+
display: none;
11+
}
912
.Toastify__toast-container {
1013
width: 100%;
1114
}

0 commit comments

Comments
 (0)