import { useMutation } from "@tanstack/react-query"; import { Download, KeyRound, User } from "lucide-react"; import { useState } from "react"; import { useNavigate } from "react-router"; import { toast } from "sonner"; import { Button } from "~/client/components/ui/button"; import { Card, CardContent, CardDescription, CardTitle } from "~/client/components/ui/card"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "~/client/components/ui/dialog"; import { Input } from "~/client/components/ui/input"; import { Label } from "~/client/components/ui/label"; import { appContext } from "~/context"; import type { Route } from "./+types/settings"; import { changePasswordMutation, downloadResticPasswordMutation, logoutMutation, } from "~/client/api-client/@tanstack/react-query.gen"; export const handle = { breadcrumb: () => [{ label: "Settings" }], }; export function meta(_: Route.MetaArgs) { return [ { title: "Zerobyte - Settings" }, { name: "description", content: "Manage your account settings and preferences.", }, ]; } export async function clientLoader({ context }: Route.LoaderArgs) { const ctx = context.get(appContext); return ctx; } export default function Settings({ loaderData }: Route.ComponentProps) { const [currentPassword, setCurrentPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); const [downloadDialogOpen, setDownloadDialogOpen] = useState(false); const [downloadPassword, setDownloadPassword] = useState(""); const navigate = useNavigate(); const logout = useMutation({ ...logoutMutation(), onSuccess: () => { navigate("/login", { replace: true }); }, }); const changePassword = useMutation({ ...changePasswordMutation(), onSuccess: (data) => { if (data.success) { toast.success("Password changed successfully. You will be logged out."); setTimeout(() => { logout.mutate({}); }, 1500); } else { toast.error("Failed to change password", { description: data.message }); } }, onError: (error) => { toast.error("Failed to change password", { description: error.message }); }, }); const downloadResticPassword = useMutation({ ...downloadResticPasswordMutation(), onSuccess: (data) => { const blob = new Blob([data], { type: "text/plain" }); const url = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "restic.pass"; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); toast.success("Restic password file downloaded successfully"); setDownloadDialogOpen(false); setDownloadPassword(""); }, onError: (error) => { toast.error("Failed to download Restic password", { description: error.message }); }, }); const handleChangePassword = (e: React.FormEvent) => { e.preventDefault(); if (newPassword !== confirmPassword) { toast.error("Passwords do not match"); return; } if (newPassword.length < 8) { toast.error("Password must be at least 8 characters long"); return; } changePassword.mutate({ body: { currentPassword, newPassword, }, }); }; const handleDownloadResticPassword = (e: React.FormEvent) => { e.preventDefault(); if (!downloadPassword) { toast.error("Password is required"); return; } downloadResticPassword.mutate({ body: { password: downloadPassword, }, }); }; return (
Account Information Your account details
Change Password Update your password to keep your account secure
setCurrentPassword(e.target.value)} className="max-w-md" required />
setNewPassword(e.target.value)} className="max-w-md" required minLength={8} />

Must be at least 8 characters long

setConfirmPassword(e.target.value)} className="max-w-md" required minLength={8} />
Backup Recovery Key Download your Restic password file for disaster recovery

This file contains the encryption password used by Restic to secure your backups. Store it in a safe place (like a password manager or encrypted storage). If you lose access to this server, you'll need this file to recover your backup data.

Download Restic Password For security reasons, please enter your account password to download the Restic password file.
setDownloadPassword(e.target.value)} placeholder="Enter your password" required autoFocus />
); }