import { useState } from "react"; import { useMutation, useQuery } from "@tanstack/react-query"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { FolderOpen, HardDrive, Trash2 } from "lucide-react"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { useToast } from "@/hooks/use-toast"; import { FolderBrowserModal } from "./folder-browser-modal"; export function BackupDestinationManager() { const { toast } = useToast(); const [path, setPath] = useState(""); const [deleteId, setDeleteId] = useState(null); const [browserOpen, setBrowserOpen] = useState(false); // ============================== // Queries // ============================== const { data: destinations = [] } = useQuery({ queryKey: ["/db/destination"], queryFn: async () => { const res = await apiRequest( "GET", "/api/database-management/destination" ); return res.json(); }, }); const { data: usbSettingData } = useQuery({ queryKey: ["/db/usb-backup-setting"], queryFn: async () => { const res = await apiRequest("GET", "/api/database-management/usb-backup-setting"); return res.json(); }, }); const usbBackupEnabled = usbSettingData?.usbBackupEnabled ?? false; const usbToggleMutation = useMutation({ mutationFn: async (enabled: boolean) => { const res = await apiRequest("PUT", "/api/database-management/usb-backup-setting", { usbBackupEnabled: enabled, }); return res.json(); }, onSuccess: (data) => { queryClient.setQueryData(["/db/usb-backup-setting"], data); toast({ title: "Setting Saved", description: `USB backup ${data.usbBackupEnabled ? "enabled" : "disabled"}.`, }); }, onError: () => { toast({ title: "Error", description: "Failed to update USB backup setting.", variant: "destructive", }); }, }); // ============================== // Mutations // ============================== const saveMutation = useMutation({ mutationFn: async () => { const res = await apiRequest( "POST", "/api/database-management/destination", { path } ); if (!res.ok) throw new Error((await res.json()).error); }, onSuccess: () => { toast({ title: "Backup destination saved" }); setPath(""); queryClient.invalidateQueries({ queryKey: ["/db/destination"] }); }, }); const deleteMutation = useMutation({ mutationFn: async (id: number) => { await apiRequest("DELETE", `/api/database-management/destination/${id}`); }, onSuccess: () => { toast({ title: "Backup destination deleted" }); queryClient.invalidateQueries({ queryKey: ["/db/destination"] }); setDeleteId(null); }, }); const backupNowMutation = useMutation({ mutationFn: async () => { const res = await apiRequest("POST", "/api/database-management/backup-path"); if (!res.ok) throw new Error((await res.json()).error || "Backup failed"); return res.json(); }, onSuccess: (data) => { toast({ title: "Backup complete", description: `Saved: ${data.filename}` }); queryClient.invalidateQueries({ queryKey: ["/db/status"] }); }, onError: (err: any) => { toast({ title: "Backup failed", description: err.message, variant: "destructive" }); }, }); // ============================== // Folder browser // ============================== const handleFolderSelect = (selectedPath: string) => { setPath(selectedPath); }; // ============================== // UI // ============================== return ( External Backup Destination
usbToggleMutation.mutate(checked)} disabled={usbToggleMutation.isPending} /> (daily at 9 PM → saves to the "USB Backup" folder on your drive)

Enter the root path of your USB drive below. The app will automatically back up to the{" "} USB Backup folder inside it every night at 9 PM when the toggle is on.

setPath(e.target.value)} />
setBrowserOpen(false)} onSelect={handleFolderSelect} />
{destinations.map((d: any) => (
{d.path}
))}
{/* Confirm delete dialog */} Delete backup destination? This will remove the destination and stop automatic backups. setDeleteId(null)}> Cancel deleteId && deleteMutation.mutate(deleteId)} > Delete
); }