diff --git a/apps/server/src/routes/_protected.tsx b/apps/server/src/routes/_protected.tsx new file mode 100644 index 0000000..c6a71fd --- /dev/null +++ b/apps/server/src/routes/_protected.tsx @@ -0,0 +1,17 @@ +import { createFileRoute, Outlet, redirect } from '@tanstack/react-router' +import { getSession } from '@/server/auth/functions' + +export const Route = createFileRoute('/_protected' as never)({ + beforeLoad: async () => { + const session = await getSession() + if (!session) { + throw redirect({ to: '/login' as never }) + } + return { user: session.user, session: session.session } + }, + component: ProtectedLayout, +}) + +function ProtectedLayout() { + return +} diff --git a/apps/server/src/routes/login.tsx b/apps/server/src/routes/login.tsx new file mode 100644 index 0000000..3772083 --- /dev/null +++ b/apps/server/src/routes/login.tsx @@ -0,0 +1,105 @@ +import { createFileRoute, Link, redirect, useRouter } from '@tanstack/react-router' +import { useState } from 'react' +import { authClient } from '@/server/auth/client' +import { getSession } from '@/server/auth/functions' + +export const Route = createFileRoute('/login' as never)({ + beforeLoad: async () => { + const session = await getSession() + if (session) { + throw redirect({ to: '/' as never }) + } + }, + component: LoginPage, +}) + +function LoginPage() { + const router = useRouter() + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [error, setError] = useState('') + const [loading, setLoading] = useState(false) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setError('') + setLoading(true) + + const { error: signInError } = await authClient.signIn.email({ + email, + password, + }) + + if (signInError) { + setError(signInError.message ?? '登录失败,请重试') + setLoading(false) + return + } + + router.navigate({ to: '/' as never }) + } + + return ( +
+
+
+

Kairos

+

登录你的人生操作系统

+
+ +
+
+
+ + setEmail(e.target.value)} + className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400" + placeholder="your@email.com" + disabled={loading} + /> +
+ +
+ + setPassword(e.target.value)} + className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400" + placeholder="••••••••" + disabled={loading} + /> +
+ + {error &&

{error}

} + + +
+ +

+ 还没有账号?{' '} + + 注册 + +

+
+
+
+ ) +} diff --git a/apps/server/src/routes/signup.tsx b/apps/server/src/routes/signup.tsx new file mode 100644 index 0000000..0b0e708 --- /dev/null +++ b/apps/server/src/routes/signup.tsx @@ -0,0 +1,151 @@ +import { createFileRoute, Link, redirect, useRouter } from '@tanstack/react-router' +import { useState } from 'react' +import { authClient } from '@/server/auth/client' +import { getSession } from '@/server/auth/functions' + +export const Route = createFileRoute('/signup' as never)({ + beforeLoad: async () => { + const session = await getSession() + if (session) { + throw redirect({ to: '/' as never }) + } + }, + component: SignupPage, +}) + +function SignupPage() { + const router = useRouter() + const [name, setName] = useState('') + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [confirmPassword, setConfirmPassword] = useState('') + const [error, setError] = useState('') + const [loading, setLoading] = useState(false) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setError('') + + if (password !== confirmPassword) { + setError('两次输入的密码不一致') + return + } + + if (password.length < 8) { + setError('密码至少需要 8 个字符') + return + } + + setLoading(true) + + const { error: signUpError } = await authClient.signUp.email({ + name, + email, + password, + }) + + if (signUpError) { + setError(signUpError.message ?? '注册失败,请重试') + setLoading(false) + return + } + + router.navigate({ to: '/' as never }) + } + + return ( +
+
+
+

Kairos

+

创建你的账号

+
+ +
+
+
+ + setName(e.target.value)} + className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400" + placeholder="你的名字" + disabled={loading} + /> +
+ +
+ + setEmail(e.target.value)} + className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400" + placeholder="your@email.com" + disabled={loading} + /> +
+ +
+ + setPassword(e.target.value)} + className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400" + placeholder="至少 8 个字符" + disabled={loading} + /> +
+ +
+ + setConfirmPassword(e.target.value)} + className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400" + placeholder="再次输入密码" + disabled={loading} + /> +
+ + {error &&

{error}

} + + +
+ +

+ 已有账号?{' '} + + 登录 + +

+
+
+
+ ) +}