diff --git a/src/components/file/DashboardFile/FileModal.tsx b/src/components/file/DashboardFile/FileModal.tsx index e694412e..6eb72072 100644 --- a/src/components/file/DashboardFile/FileModal.tsx +++ b/src/components/file/DashboardFile/FileModal.tsx @@ -34,6 +34,7 @@ import useSWR from 'swr'; import { Response } from '@/lib/api/response'; import { Folder } from '@/lib/db/models/folder'; import { bytes } from '@/lib/bytes'; +import { useSettingsStore } from '@/lib/store/settings'; function ActionButton({ Icon, @@ -67,6 +68,7 @@ export default function FileModal({ reduce?: boolean; }) { const clipboard = useClipboard(); + const warnDeletion = useSettingsStore((state) => state.settings.warnDeletion); const { data: folders } = useSWR>( '/api/user/folders?noincl=true' @@ -145,7 +147,7 @@ export default function FileModal({ <> deleteFile(file, setOpen)} + onClick={() => deleteFile(warnDeletion, file, setOpen)} tooltip='Delete file' color='red' /> diff --git a/src/components/file/actions.tsx b/src/components/file/actions.tsx index 27e4b0e5..d8e7ed94 100644 --- a/src/components/file/actions.tsx +++ b/src/components/file/actions.tsx @@ -2,8 +2,11 @@ import { Response } from '@/lib/api/response'; import type { File } from '@/lib/db/models/file'; import { Folder } from '@/lib/db/models/folder'; import { fetchApi } from '@/lib/fetchApi'; +import { useSettingsStore } from '@/lib/store/settings'; +import { conditionalWarning } from '@/lib/warningModal'; import { Anchor } from '@mantine/core'; import { useClipboard } from '@mantine/hooks'; +import { modals } from '@mantine/modals'; import { notifications, notifications as notifs } from '@mantine/notifications'; import { IconCopy, @@ -45,7 +48,15 @@ export function copyFile(file: File, clipboard: ReturnType) }); } -export async function deleteFile(file: File, setOpen: (open: boolean) => void) { +export async function deleteFile(warnDeletion: boolean, file: File, setOpen: (open: boolean) => void) { + conditionalWarning(warnDeletion, { + confirmLabel: `Delete ${file.name}`, + message: `Are you sure you want to delete ${file.name}? This action cannot be undone.`, + onConfirm: () => handleDeleteFile(file, setOpen), + }); +} + +export async function handleDeleteFile(file: File, setOpen: (open: boolean) => void) { const { error } = await fetchApi(`/api/user/files/${file.id}`, 'DELETE'); if (error) { diff --git a/src/components/pages/files/views/FileTable.tsx b/src/components/pages/files/views/FileTable.tsx index 8680629a..255d9cf2 100644 --- a/src/components/pages/files/views/FileTable.tsx +++ b/src/components/pages/files/views/FileTable.tsx @@ -81,7 +81,10 @@ function SearchFilter({ export default function FileTable({ id }: { id?: string }) { const router = useRouter(); const clipboard = useClipboard(); - const searchThreshold = useSettingsStore((state) => state.settings.searchThreshold); + const [searchThreshold, warnDeletion] = useSettingsStore((state) => [ + state.settings.searchThreshold, + state.settings.warnDeletion, + ]); const [page, setPage] = useState(router.query.page ? parseInt(router.query.page as string) : 1); const [perpage, setPerpage] = useState(20); @@ -321,7 +324,7 @@ export default function FileTable({ id }: { id?: string }) { color='red' onClick={(e) => { e.stopPropagation(); - deleteFile(file, () => {}); + deleteFile(warnDeletion, file, () => {}); }} > diff --git a/src/components/pages/invites/InviteCard.tsx b/src/components/pages/invites/InviteCard.tsx index 3188fe4a..28b6fe8a 100644 --- a/src/components/pages/invites/InviteCard.tsx +++ b/src/components/pages/invites/InviteCard.tsx @@ -4,10 +4,13 @@ import { ActionIcon, Card, Group, Menu, Stack, Text } from '@mantine/core'; import { IconCopy, IconDots, IconTrashFilled } from '@tabler/icons-react'; import { copyInviteUrl, deleteInvite } from './actions'; import { useClipboard } from '@mantine/hooks'; +import { useSettingsStore } from '@/lib/store/settings'; export default function InviteCard({ invite }: { invite: Invite }) { const clipboard = useClipboard(); + const warnDeletion = useSettingsStore((state) => state.settings.warnDeletion); + return ( <> @@ -31,7 +34,7 @@ export default function InviteCard({ invite }: { invite: Invite }) { } color='red' - onClick={() => deleteInvite(invite)} + onClick={() => deleteInvite(warnDeletion, invite)} > Delete diff --git a/src/components/pages/invites/actions.tsx b/src/components/pages/invites/actions.tsx index 74c3aab2..78ce35b3 100644 --- a/src/components/pages/invites/actions.tsx +++ b/src/components/pages/invites/actions.tsx @@ -1,6 +1,7 @@ import { Response } from '@/lib/api/response'; import { Invite } from '@/lib/db/models/invite'; import { fetchApi } from '@/lib/fetchApi'; +import { conditionalWarning } from '@/lib/warningModal'; import { Anchor, Title } from '@mantine/core'; import { useClipboard } from '@mantine/hooks'; import { modals } from '@mantine/modals'; @@ -9,17 +10,11 @@ import { IconCheck, IconCopy, IconTagOff } from '@tabler/icons-react'; import Link from 'next/link'; import { mutate } from 'swr'; -export async function deleteInvite(invite: Invite) { - modals.openConfirmModal({ - title: Delete invite "{invite.code}", - children: `Are you sure you want to delete invite ${invite.code}? This action cannot be undone.`, - labels: { - cancel: 'Cancel', - confirm: 'Delete', - }, - confirmProps: { color: 'red' }, +export async function deleteInvite(warnDeletion: boolean, invite: Invite) { + conditionalWarning(warnDeletion, { + message: `Are you sure you want to delete invite ${invite.code}? This action cannot be undone.`, onConfirm: () => handleDeleteInvite(invite), - onCancel: modals.closeAll, + confirmLabel: `Delete ${invite.code}`, }); } diff --git a/src/components/pages/invites/views/InviteTableView.tsx b/src/components/pages/invites/views/InviteTableView.tsx index c277ee97..67dff991 100644 --- a/src/components/pages/invites/views/InviteTableView.tsx +++ b/src/components/pages/invites/views/InviteTableView.tsx @@ -1,4 +1,3 @@ -import { useConfig } from '@/components/ConfigProvider'; import RelativeDate from '@/components/RelativeDate'; import { Response } from '@/lib/api/response'; import { Invite } from '@/lib/db/models/invite'; @@ -9,10 +8,11 @@ import { DataTable, DataTableSortStatus } from 'mantine-datatable'; import { useEffect, useState } from 'react'; import useSWR from 'swr'; import { copyInviteUrl, deleteInvite } from '../actions'; +import { useSettingsStore } from '@/lib/store/settings'; export default function InviteTableView() { - const config = useConfig(); const clipboard = useClipboard(); + const warnDeletion = useSettingsStore((state) => state.settings.warnDeletion); const { data, isLoading } = useSWR>('/api/auth/invites'); @@ -105,7 +105,7 @@ export default function InviteTableView() { color='red' onClick={(e) => { e.stopPropagation(); - deleteInvite(invite); + deleteInvite(warnDeletion, invite); }} > diff --git a/src/components/pages/settings/parts/SettingsDashboard.tsx b/src/components/pages/settings/parts/SettingsDashboard.tsx index 92431613..2e5b96f5 100644 --- a/src/components/pages/settings/parts/SettingsDashboard.tsx +++ b/src/components/pages/settings/parts/SettingsDashboard.tsx @@ -65,7 +65,7 @@ export default function SettingsDashboard() { /> update('warnDeletion', event.currentTarget.checked)} /> @@ -73,7 +73,7 @@ export default function SettingsDashboard() { state.settings.warnDeletion); + return ( <> @@ -40,7 +42,11 @@ export default function UserCard({ url }: { url: Url }) { } onClick={() => copyUrl(url, config, clipboard)}> Copy - } color='red' onClick={() => deleteUrl(url)}> + } + color='red' + onClick={() => deleteUrl(warnDeletion, url)} + > Delete diff --git a/src/components/pages/urls/actions.tsx b/src/components/pages/urls/actions.tsx index 257d5401..ad3d34d8 100644 --- a/src/components/pages/urls/actions.tsx +++ b/src/components/pages/urls/actions.tsx @@ -3,6 +3,7 @@ import type { SafeConfig } from '@/lib/config/safe'; import { Url } from '@/lib/db/models/url'; import { fetchApi } from '@/lib/fetchApi'; import { formatRootUrl } from '@/lib/url'; +import { conditionalWarning } from '@/lib/warningModal'; import { Anchor, Title } from '@mantine/core'; import { useClipboard } from '@mantine/hooks'; import { modals } from '@mantine/modals'; @@ -11,18 +12,11 @@ import { IconCheck, IconCopy, IconLinkOff } from '@tabler/icons-react'; import Link from 'next/link'; import { mutate } from 'swr'; -export async function deleteUrl(url: Url) { - modals.openConfirmModal({ - centered: true, - title: Delete {url.code ?? url.vanity}?, - children: `Are you sure you want to delete ${url.code ?? url.vanity}? This action cannot be undone.`, - labels: { - cancel: 'Cancel', - confirm: 'Delete', - }, - confirmProps: { color: 'red' }, +export async function deleteUrl(warnDeletion: boolean, url: Url) { + conditionalWarning(warnDeletion, { + message: `Are you sure you want to delete ${url.code ?? url.vanity}? This action cannot be undone.`, onConfirm: () => handleDeleteUrl(url), - onCancel: modals.closeAll, + confirmLabel: `Delete '${url.code ?? url.vanity}'`, }); } diff --git a/src/components/pages/urls/views/UrlTableView.tsx b/src/components/pages/urls/views/UrlTableView.tsx index e6dd2222..bdcc86a6 100644 --- a/src/components/pages/urls/views/UrlTableView.tsx +++ b/src/components/pages/urls/views/UrlTableView.tsx @@ -109,7 +109,10 @@ export default function UrlTableView() { destination: '', } ); - const searchThreshold = useSettingsStore((s) => s.settings.searchThreshold); + const [warnDeletion, searchThreshold] = useSettingsStore((s) => [ + s.settings.warnDeletion, + s.settings.searchThreshold, + ]); const { data, isLoading } = useSWR>( { @@ -259,7 +262,7 @@ export default function UrlTableView() { color='red' onClick={(e) => { e.stopPropagation(); - deleteUrl(url); + deleteUrl(warnDeletion, url); }} > diff --git a/src/lib/warningModal.tsx b/src/lib/warningModal.tsx new file mode 100644 index 00000000..de0278c9 --- /dev/null +++ b/src/lib/warningModal.tsx @@ -0,0 +1,33 @@ +import { Title } from '@mantine/core'; +import { modals } from '@mantine/modals'; + +type WarningModalOptions = { + message: string | React.ReactNode; + confirmLabel: string; + onConfirm: () => void; +}; + +export function openWarningModal(options: WarningModalOptions) { + modals.openConfirmModal({ + title: Are you sure?, + labels: { + cancel: 'Cancel', + confirm: options.confirmLabel, + }, + children: options.message, + confirmProps: { + color: 'red', + }, + onCancel: () => modals.closeAll(), + onConfirm: options.onConfirm, + zIndex: 10320948239487, + }); +} + +export function conditionalWarning(on: boolean, options: WarningModalOptions) { + if (on) { + openWarningModal(options); + } else { + options.onConfirm(); + } +}