Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions frontend/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"collectionDialog": {
"title": "Add New Collection"
},
"confirmationDialog": {
"title": "Delete Collection",
"warningMessages": "Are you sure you want to delete the collection {{name}}? The action is irreversible and will also delete the associated cards."
},
"editorToolbar": {
"heading1": "Heading 1",
"heading2": "Heading 2",
Expand Down Expand Up @@ -89,6 +93,7 @@
"backToCollection": "Back to Collection",
"cancel": "Cancel",
"close": "Close",
"collectionDeletedDescription": "Collection deleted successfully",
"comingSoon": "Coming soon",
"confirmPassword": "Confirm Password",
"create": "Create",
Expand Down Expand Up @@ -119,6 +124,7 @@
"default": "Something went wrong",
"emailIsRequired": "Email is required",
"errorCreatingAccount": "Error creating account",
"errorDeletingCollection": "Error deleting collection",
"errorLoadingCard": "Error loading card",
"errorSavingCard": "Error saving card",
"invalidCredentials": "Invalid credentials",
Expand Down
6 changes: 6 additions & 0 deletions frontend/public/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"collectionDialog": {
"title": "Agregar Nueva Colección"
},
"confirmationDialog": {
"title": "Eliminar colección",
"warningMessages": "¿Estás seguro de que quieres eliminar la colección {{name}}? Esta acción es irreversible y también eliminará las tarjetas asociadas."
},
"editorToolbar": {
"heading1": "Encabezado 1",
"heading2": "Encabezado 2",
Expand Down Expand Up @@ -89,6 +93,7 @@
"backToCollection": "Volver a la Colección",
"cancel": "Cancelar",
"close": "Cerrar",
"collectionDeletedDescription": "Colección eliminada exitosamente",
"comingSoon": "Próximamente",
"confirmPassword": "Confirmar Contraseña",
"create": "Crear",
Expand Down Expand Up @@ -119,6 +124,7 @@
"default": "Algo salió mal",
"emailIsRequired": "Correo electrónico es requerido",
"errorCreatingAccount": "Error al crear la cuenta",
"errorDeletingCollection": "Error al eliminar la colección",
"errorLoadingCard": "Error al cargar la tarjeta",
"errorSavingCard": "Error al guardar la tarjeta",
"invalidCredentials": "Credenciales inválidas",
Expand Down
6 changes: 6 additions & 0 deletions frontend/public/locales/nl/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"collectionDialog": {
"title": "Nieuwe Collectie Toevoegen"
},
"confirmationDialog": {
"title": "Collectie verwijderen",
"warningMessages": "Weet u zeker dat u de verzameling {{name}} wilt verwijderen? Deze actie is onomkeerbaar en verwijdert ook de bijbehorende kaarten."
},
"editorToolbar": {
"heading1": "Kop 1",
"heading2": "Kop 2",
Expand Down Expand Up @@ -89,6 +93,7 @@
"backToCollection": "Terug naar Collectie",
"cancel": "Annuleren",
"close": "Sluiten",
"collectionDeletedDescription": "Collectie succesvol verwijderd",
"comingSoon": "Binnenkort beschikbaar",
"confirmPassword": "Bevestig Wachtwoord",
"create": "Creëren",
Expand Down Expand Up @@ -119,6 +124,7 @@
"default": "Er is iets misgegaan",
"emailIsRequired": "E-mail is vereist",
"errorCreatingAccount": "Fout bij het aanmaken van account",
"errorDeletingCollection": "Fout bij het verwijderen van de collectie",
"errorLoadingCard": "Fout bij het laden van kaart",
"errorSavingCard": "Fout bij het opslaan van kaart",
"invalidCredentials": "Ongeldige inloggegevens",
Expand Down
78 changes: 78 additions & 0 deletions frontend/src/components/commonUI/ConfirmationDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type React from 'react'
import { useEffect, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
} from '../ui/dialog'
import { BlueButton, RedButton } from './Button'

interface ConfirmationProps {
isOpen: boolean
message: string
onClose: () => void
onConfirm: () => void
}

const ConfirmationDialog: React.FC<ConfirmationProps> = ({
isOpen,
message,
onClose,
onConfirm,
}: ConfirmationProps) => {
const { t } = useTranslation()
const closeButtonRef = useRef<HTMLButtonElement>(null)
const cancelButtonRef = useRef<HTMLButtonElement>(null)

useEffect(() => {
if (isOpen && cancelButtonRef.current) {
setTimeout(() => {
cancelButtonRef.current?.focus()
}, 50)
}
}, [isOpen])

if (!isOpen) return null

return (
<DialogRoot
key="delete-collection-confirmation-dialog"
placement="center"
motionPreset="slide-in-bottom"
open={isOpen}
onOpenChange={(detail) => {
if (!detail.open) {
onClose()
}
}}
>
<DialogContent bg={'bg.50'}>
<DialogHeader>
<DialogTitle color="fg.DEFAULT">{t('components.confirmationDialog.title')}</DialogTitle>
</DialogHeader>
<DialogBody>
<p>{message}</p>
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<BlueButton onClick={onClose} ref={cancelButtonRef} tabIndex={0}>
{t('general.actions.cancel')}
</BlueButton>
</DialogActionTrigger>
<RedButton onClick={onConfirm} colorPalette="red">
{t('general.actions.delete')}
</RedButton>
</DialogFooter>
<DialogCloseTrigger ref={closeButtonRef} />
</DialogContent>
</DialogRoot>
)
}

export default ConfirmationDialog
47 changes: 44 additions & 3 deletions frontend/src/routes/_layout/collections/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import type { Collection } from '@/client/types.gen'
import CollectionDialog from '@/components/collections/CollectionDialog'
import CollectionListItem from '@/components/collections/CollectionListItem'
import AiPromptDialog from '@/components/commonUI/AiPromptDialog'
import ConfirmationDialog from '@/components/commonUI/ConfirmationDialog'
import EmptyState from '@/components/commonUI/EmptyState'
import ErrorState from '@/components/commonUI/ErrorState'
import ListSkeleton from '@/components/commonUI/ListSkeleton'
import ScrollableContainer from '@/components/commonUI/ScrollableContainer'
import SpeedDial, { type SpeedDialActionItem } from '@/components/commonUI/SpeedDial'
import { toaster } from '@/components/ui/toaster'
import {
createCollection,
deleteCollection as deleteCollectionApi,
Expand All @@ -32,6 +34,9 @@ function Collections() {
const [isSpeedDialLoading, setIsSpeedDialLoading] = useState(false)
const [isAiDialogOpen, setIsAiDialogOpen] = useState(false)
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false)
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false)
const [collectionToDelete, setCollectionToDelete] = useState<string | null>(null)
const [collectionNameToDelete, setCollectionNameToDelete] = useState<string>('')

const { data, error, isLoading } = useQuery<Collection[]>({
queryKey: ['collections'],
Expand Down Expand Up @@ -77,12 +82,39 @@ function Collections() {
}
}

const handleDeleteCollection = async (collectionId: string) => {
const openDeleteConfirmation = (collectionId: string, collectionName: string) => {
setCollectionToDelete(collectionId)
setCollectionNameToDelete(collectionName)
setIsDeleteDialogOpen(true)
}

const closeDeleteDialog = () => {
setIsDeleteDialogOpen(false)
setCollectionToDelete(null)
setCollectionNameToDelete('')
}

const handleDeleteCollection = async () => {
if (!collectionToDelete) return

try {
await deleteCollectionApi(collectionId)
await deleteCollectionApi(collectionToDelete)
queryClient.invalidateQueries({ queryKey: ['collections'] })

toaster.create({
title: t('general.actions.collectionDeletedDescription'),
type: 'success',
})
} catch (error) {
console.error(error)
toaster.create({
title: t('general.errors.errorDeletingCollection'),
type: 'error',
})
} finally {
setIsDeleteDialogOpen(false)
setCollectionToDelete(null)
setCollectionNameToDelete('')
}
}

Expand Down Expand Up @@ -124,7 +156,7 @@ function Collections() {
<CollectionListItem
key={collection.id}
collection={collection}
onDelete={handleDeleteCollection}
onDelete={() => openDeleteConfirmation(collection.id, collection.name)}
onRename={renameCollection}
/>
))
Expand All @@ -147,6 +179,15 @@ function Collections() {
title={t('components.AiCollectionDialog.title')}
placeholder={t('components.AiCollectionDialog.placeholder')}
/>

<ConfirmationDialog
isOpen={isDeleteDialogOpen}
message={t('components.confirmationDialog.warningMessages', {
name: collectionNameToDelete,
})}
onClose={closeDeleteDialog}
onConfirm={handleDeleteCollection}
/>
</>
)
}