Fix backend bulk delete, separate password page, remove admin dummy data, swap dashboard rows
This commit is contained in:
115
src/app/dashboard/settings/password/page.tsx
Normal file
115
src/app/dashboard/settings/password/page.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
"use client";
|
||||
|
||||
import { fetchWithAuth } from "@/lib/apiClient";
|
||||
import { useState } from "react";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Lock } from "lucide-react";
|
||||
|
||||
export default function PasswordPage() {
|
||||
const [currentPassword, setCurrentPassword] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
const [passwordSaving, setPasswordSaving] = useState(false);
|
||||
|
||||
const handleChangePassword = async () => {
|
||||
if (newPassword !== confirmPassword) {
|
||||
alert("New passwords do not match.");
|
||||
return;
|
||||
}
|
||||
setPasswordSaving(true);
|
||||
try {
|
||||
const res = await fetchWithAuth("/api/auth/change-password", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
current_password: currentPassword,
|
||||
new_password: newPassword,
|
||||
}),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
alert(data.message || "Password updated successfully!");
|
||||
setCurrentPassword("");
|
||||
setNewPassword("");
|
||||
setConfirmPassword("");
|
||||
} else {
|
||||
alert("Failed to change password: " + (data.detail || "Unknown error"));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
alert("Network error. Could not change password.");
|
||||
} finally {
|
||||
setPasswordSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-8 space-y-8 animate-in fade-in zoom-in-95 origin-top duration-500 max-w-3xl mx-auto">
|
||||
<div className="flex flex-col md:flex-row md:items-end justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-1">
|
||||
<span className="p-2.5 rounded-xl bg-purple-50 dark:bg-[var(--cyan-ai-10)] border border-purple-300/60 dark:border-[var(--cyan-ai-20)]">
|
||||
<Lock className="text-purple-600 dark:text-[var(--cyan-ai)]" size={28} />
|
||||
</span>
|
||||
Change Password
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Update your account password securely.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card className="border-border bg-background shadow-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Change Password</CardTitle>
|
||||
<CardDescription>Update your account password</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-bold">Current Password</label>
|
||||
<input
|
||||
type="password"
|
||||
value={currentPassword}
|
||||
onChange={(e) => setCurrentPassword(e.target.value)}
|
||||
className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]"
|
||||
placeholder="Enter current password"
|
||||
/>
|
||||
</div>
|
||||
<div className="hidden md:block"></div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-bold">New Password</label>
|
||||
<input
|
||||
type="password"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]"
|
||||
placeholder="Enter new password"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-bold">Confirm New Password</label>
|
||||
<input
|
||||
type="password"
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]"
|
||||
placeholder="Confirm new password"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-2 border-t border-border mt-6">
|
||||
<Button
|
||||
className="bg-foreground text-background hover:bg-foreground/90 font-bold px-6 rounded-xl"
|
||||
onClick={handleChangePassword}
|
||||
disabled={passwordSaving || !currentPassword || !newPassword || !confirmPassword}
|
||||
>
|
||||
{passwordSaving ? "Updating..." : "Update Password"}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user