import type { Route } from "./+types/profile"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { ArrowLeft } from "lucide-react"; import { Link, Form, useActionData } from "react-router"; import { db } from "@lib/db"; import { users } from "@lib/db/schema"; import { getCurrentUser } from "@lib/auth-utils"; import Layout from "@/components/layout"; import { eq } from "drizzle-orm"; import { hashPassword, passwordMatches } from "@lib/auth"; import { useState, useEffect } from "react"; export function meta({}: Route.MetaArgs) { return [ { title: "User Profile" }, { name: "description", content: "Manage your account settings" } ]; } export async function loader({ request }: Route.LoaderArgs) { const user = await getCurrentUser(request); if (!user) { throw new Response("Unauthorized", { status: 401 }); } return { user }; } export async function action({ request }: Route.ActionArgs) { const user = await getCurrentUser(request); if (!user) { throw new Response("Unauthorized", { status: 401 }); } const formData = await request.formData(); const intent = formData.get("intent") as string; if (intent === "changePassword") { const currentPassword = formData.get("currentPassword") as string; const newPassword = formData.get("newPassword") as string; const confirmPassword = formData.get("confirmPassword") as string; if (!currentPassword || !newPassword || !confirmPassword) { return { error: "All password fields are required" }; } if (newPassword !== confirmPassword) { return { error: "New passwords do not match" }; } const currentUser = await db.select().from(users).where(eq(users.id, user.id)).get(); if (!currentUser) { return { error: "User not found" }; } const isCurrentPasswordValid = await passwordMatches(currentPassword, currentUser.password); if (!isCurrentPasswordValid) { return { error: "Current password is incorrect" }; } const hashedNewPassword = await hashPassword(newPassword); await db .update(users) .set({ password: hashedNewPassword, updatedAt: new Date() }) .where(eq(users.id, user.id)); return { success: true, message: "Password updated successfully" }; } if (intent === "changeUsername") { const newUsername = formData.get("newUsername") as string; if (!newUsername) { return { error: "Username is required" }; } const existingUser = await db .select() .from(users) .where(eq(users.username, newUsername)) .get(); if (existingUser && existingUser.id !== user.id) { return { error: "Username already exists" }; } await db .update(users) .set({ username: newUsername, updatedAt: new Date() }) .where(eq(users.id, user.id)); const updatedUser = await db.select().from(users).where(eq(users.id, user.id)).get(); return { success: true, message: "Username updated successfully", updatedUser }; } return { error: "Unknown action" }; } export default function UserProfile({ loaderData }: Route.ComponentProps) { const { user } = loaderData; const actionData = useActionData(); const [userName, setUserName] = useState(user.username); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); // 处理动作返回的消息 useEffect(() => { if (actionData?.error) { setError(actionData.error); setSuccess(null); } else if (actionData?.success) { setSuccess(actionData.message); setError(null); // 如果用户名更新了,同步状态 if (actionData.updatedUser?.username) { setUserName(actionData.updatedUser.username); } } }, [actionData]); return ( {/* 头部 */}

User Profile

Manage your account settings

{/* 消息提示 */} {error &&
{error}
} {success && (
{success}
)} {/* 用户信息 */} Account Information Your basic account details
setUserName(e.target.value)} value={userName} className="flex-1" />
{/* 更改密码 */} Change Password Update your account password
); }