diff --git a/src/app/page.tsx b/src/app/page.tsx index e815517..a4488fc 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,6 +7,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { CamoufoxConfigDialog } from "@/components/camoufox-config-dialog"; import { ChangeVersionDialog } from "@/components/change-version-dialog"; import { CreateProfileDialog } from "@/components/create-profile-dialog"; +import { DeleteConfirmationDialog } from "@/components/delete-confirmation-dialog"; import { GroupAssignmentDialog } from "@/components/group-assignment-dialog"; import { GroupBadges } from "@/components/group-badges"; import { GroupManagementDialog } from "@/components/group-management-dialog"; @@ -77,6 +78,9 @@ export default function Home() { const [areGroupsLoading, setGroupsLoading] = useState(true); const [currentPermissionType, setCurrentPermissionType] = useState("microphone"); + const [showBulkDeleteConfirmation, setShowBulkDeleteConfirmation] = + useState(false); + const [isBulkDeleting, setIsBulkDeleting] = useState(false); const { isMicrophoneAccessGranted, isCameraAccessGranted, isInitialized } = usePermissions(); @@ -595,17 +599,27 @@ export default function Home() { setGroupAssignmentDialogOpen(true); }, []); - const handleBulkDelete = useCallback(async () => { + const handleBulkDelete = useCallback(() => { + if (selectedProfiles.length === 0) return; + setShowBulkDeleteConfirmation(true); + }, [selectedProfiles]); + + const confirmBulkDelete = useCallback(async () => { if (selectedProfiles.length === 0) return; + setIsBulkDeleting(true); try { await invoke("delete_selected_profiles", { profileNames: selectedProfiles, }); await loadProfiles(); setSelectedProfiles([]); + setShowBulkDeleteConfirmation(false); } catch (error) { console.error("Failed to delete selected profiles:", error); + setError(`Failed to delete selected profiles: ${JSON.stringify(error)}`); + } finally { + setIsBulkDeleting(false); } }, [selectedProfiles, loadProfiles]); @@ -827,6 +841,16 @@ export default function Home() { selectedProfiles={selectedProfilesForGroup} onAssignmentComplete={handleGroupAssignmentComplete} /> + + setShowBulkDeleteConfirmation(false)} + onConfirm={confirmBulkDelete} + title="Delete Selected Profiles" + description={`This action cannot be undone. This will permanently delete ${selectedProfiles.length} profile${selectedProfiles.length !== 1 ? "s" : ""} and all associated data.`} + confirmButtonText={`Delete ${selectedProfiles.length} Profile${selectedProfiles.length !== 1 ? "s" : ""}`} + isLoading={isBulkDeleting} + /> ); } diff --git a/src/components/delete-confirmation-dialog.tsx b/src/components/delete-confirmation-dialog.tsx new file mode 100644 index 0000000..f90552b --- /dev/null +++ b/src/components/delete-confirmation-dialog.tsx @@ -0,0 +1,58 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; + +interface DeleteConfirmationDialogProps { + isOpen: boolean; + onClose: () => void; + onConfirm: () => void | Promise; + title: string; + description: string; + confirmButtonText?: string; + isLoading?: boolean; +} + +export function DeleteConfirmationDialog({ + isOpen, + onClose, + onConfirm, + title, + description, + confirmButtonText = "Delete", + isLoading = false, +}: DeleteConfirmationDialogProps) { + const handleConfirm = async () => { + await onConfirm(); + }; + + return ( + + + + {title} + {description} + + + + + + + + ); +} diff --git a/src/components/home-header.tsx b/src/components/home-header.tsx index 286f5e6..3a448a5 100644 --- a/src/components/home-header.tsx +++ b/src/components/home-header.tsx @@ -16,7 +16,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; type Props = { selectedProfiles: string[]; onBulkGroupAssignment: () => void; - onBulkDelete: () => Promise; + onBulkDelete: () => void; onSettingsDialogOpen: (open: boolean) => void; onProxyManagementDialogOpen: (open: boolean) => void; onGroupManagementDialogOpen: (open: boolean) => void; @@ -57,7 +57,7 @@ const HomeHeader = ({ - - - - + setProfileToDelete(null)} + onConfirm={handleDelete} + title="Delete Profile" + description={`This action cannot be undone. This will permanently delete the profile "${profileToDelete?.name}" and all its associated data.`} + confirmButtonText="Delete Profile" + isLoading={isDeleting} + /> ); }