Files
fiberops-web/app/(app)/profile/page.tsx

148 lines
5.0 KiB
TypeScript

"use client";
import { useState } from "react";
import { useMutation } from "@tanstack/react-query";
import { useAuthStore } from "@/lib/auth-store";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card";
import { Button } from "@/components/ui/Button";
import { Input } from "@/components/ui/Input";
import { User, Lock } from "lucide-react";
import api from "@/lib/api";
import { toast } from "sonner";
export default function ProfilePage() {
const user = useAuthStore((s) => s.user);
const [infoForm, setInfoForm] = useState({
firstName: (user as any)?.firstName ?? user?.name?.split(" ")[0] ?? "",
lastName: (user as any)?.lastName ?? user?.name?.split(" ").slice(1).join(" ") ?? "",
email: user?.email ?? "",
});
const [pwForm, setPwForm] = useState({
currentPassword: "",
newPassword: "",
confirmPassword: "",
});
const updateInfo = useMutation({
mutationFn: async () => {
await api.patch("/api/v1/auth/me", {
firstName: infoForm.firstName,
lastName: infoForm.lastName,
email: infoForm.email,
});
},
onSuccess: () => toast.success("Profile updated!"),
onError: (e: any) => toast.error(e.response?.data?.message ?? "Failed to update profile"),
});
const resetPassword = useMutation({
mutationFn: async () => {
if (pwForm.newPassword !== pwForm.confirmPassword) {
throw new Error("Passwords do not match");
}
await api.post("/api/v1/auth/change-password", {
currentPassword: pwForm.currentPassword,
newPassword: pwForm.newPassword,
});
},
onSuccess: () => {
toast.success("Password changed successfully!");
setPwForm({ currentPassword: "", newPassword: "", confirmPassword: "" });
},
onError: (e: any) => toast.error(e.response?.data?.message ?? e.message ?? "Failed to change password"),
});
return (
<div className="space-y-6 max-w-xl">
<div>
<h1 className="text-2xl font-bold text-gray-900">My Profile</h1>
<p className="text-sm text-gray-500 mt-1">Manage your account settings</p>
</div>
{/* Profile Info */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<User className="h-4 w-4 text-blue-600" />
Personal Information
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-3">
<Input
label="First Name"
value={infoForm.firstName}
onChange={e => setInfoForm(f => ({ ...f, firstName: e.target.value }))}
/>
<Input
label="Last Name"
value={infoForm.lastName}
onChange={e => setInfoForm(f => ({ ...f, lastName: e.target.value }))}
/>
</div>
<Input
label="Email"
type="email"
value={infoForm.email}
onChange={e => setInfoForm(f => ({ ...f, email: e.target.value }))}
/>
<div className="flex justify-end">
<Button
onClick={() => updateInfo.mutate()}
isLoading={updateInfo.isPending}
disabled={!infoForm.firstName || !infoForm.email}
>
Save Changes
</Button>
</div>
</CardContent>
</Card>
{/* Change Password */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Lock className="h-4 w-4 text-blue-600" />
Change Password
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<Input
label="Current Password"
type="password"
value={pwForm.currentPassword}
onChange={e => setPwForm(f => ({ ...f, currentPassword: e.target.value }))}
/>
<Input
label="New Password"
type="password"
value={pwForm.newPassword}
onChange={e => setPwForm(f => ({ ...f, newPassword: e.target.value }))}
hint="Minimum 8 characters"
/>
<Input
label="Confirm New Password"
type="password"
value={pwForm.confirmPassword}
onChange={e => setPwForm(f => ({ ...f, confirmPassword: e.target.value }))}
/>
{pwForm.newPassword && pwForm.confirmPassword && pwForm.newPassword !== pwForm.confirmPassword && (
<p className="text-xs text-red-500">Passwords do not match</p>
)}
<div className="flex justify-end">
<Button
onClick={() => resetPassword.mutate()}
isLoading={resetPassword.isPending}
disabled={!pwForm.currentPassword || !pwForm.newPassword || !pwForm.confirmPassword || pwForm.newPassword !== pwForm.confirmPassword}
>
Change Password
</Button>
</div>
</CardContent>
</Card>
</div>
);
}