feat: delete confirmation

This commit is contained in:
DIYgod 2023-04-28 23:52:34 +01:00
parent b9b99be994
commit b1a880cd34
No known key found for this signature in database
4 changed files with 140 additions and 92 deletions

View File

@ -1,6 +1,6 @@
import { useTranslation } from "next-i18next"
import { useRouter } from "next/router"
import React from "react"
import React, { useState } from "react"
import toast from "react-hot-toast"
import type { Note, Notes } from "unidata.js"
@ -12,6 +12,8 @@ import { APP_NAME } from "~/lib/env"
import { delStorage, getStorage, setStorage } from "~/lib/storage"
import { useCreateOrUpdatePage, useDeletePage } from "~/queries/page"
import { DeleteConfirmationModal } from "./DeleteConfirmationModal"
export const PagesManagerBatchSelectActionTab: React.FC<{
isPost: boolean
isNotxLogContent: boolean
@ -136,61 +138,77 @@ export const PagesManagerBatchSelectActionTab: React.FC<{
{
text: "Delete",
onClick: async () => {
// Start message
const toastId = toast.loading("Deleting...")
// Find all selected
const selectedPages: Note[] = []
pages.data?.pages.map((page) =>
page.list?.map((page) => {
if (batchSelected.includes(page.id)) {
selectedPages.push(page)
}
}),
)
// Delete all // TODO: use multicall to optimize
try {
await Promise.all(
selectedPages.map((page) => {
if (!page.metadata) {
// Is draft
delStorage(`draft-${subdomain}-${page.id}`)
} else {
// Is Note
return deletePage.mutateAsync({
site: subdomain,
id: page.id,
})
}
}),
)
toast.success(t("Deleted!"), {
id: toastId,
})
} catch (e) {
toast.error(t("Fail to Deleted."), {
// It should be "Failed to delete.", but the translation key is that so :shrug:
id: toastId,
})
}
// Refresh site data
await Promise.all([
queryClient.refetchQueries(["getPagesBySite", subdomain]),
...selectedPages.map((page) =>
queryClient.refetchQueries(["getPage", page.id]),
),
])
// Unselect all
setBatchSelected([])
setDeleteConfirmModalOpen(true)
},
},
]
return <Tabs items={tabItems} />
const [deleteConfirmModalOpen, setDeleteConfirmModalOpen] =
useState<boolean>(false)
const onDelete = async () => {
// Start message
const toastId = toast.loading("Deleting...")
// Find all selected
const selectedPages: Note[] = []
pages.data?.pages.map((page) =>
page.list?.map((page) => {
if (batchSelected.includes(page.id)) {
selectedPages.push(page)
}
}),
)
// Delete all // TODO: use multicall to optimize
try {
await Promise.all(
selectedPages.map((page) => {
if (!page.metadata) {
// Is draft
delStorage(`draft-${subdomain}-${page.id}`)
} else {
// Is Note
return deletePage.mutateAsync({
site: subdomain,
id: page.id,
})
}
}),
)
toast.success(t("Deleted!"), {
id: toastId,
})
} catch (e) {
toast.error(t("Fail to Deleted."), {
// It should be "Failed to delete.", but the translation key is that so :shrug:
id: toastId,
})
}
// Refresh site data
await Promise.all([
queryClient.refetchQueries(["getPagesBySite", subdomain]),
...selectedPages.map((page) =>
queryClient.refetchQueries(["getPage", page.id]),
),
])
// Unselect all
setBatchSelected([])
}
return (
<>
<Tabs items={tabItems} />
<DeleteConfirmationModal
open={deleteConfirmModalOpen}
setOpen={setDeleteConfirmModalOpen}
onConfirm={onDelete}
isPost={isPost}
/>
</>
)
}
export default PagesManagerBatchSelectActionTab

View File

@ -14,6 +14,8 @@ import { delStorage, getStorage, setStorage } from "~/lib/storage"
import { useCreateOrUpdatePage, useDeletePage } from "~/queries/page"
import { useGetSite } from "~/queries/site"
import { DeleteConfirmationModal } from "./DeleteConfirmationModal"
const usePageEditLink = (page: { id: string }, isPost: boolean) => {
const router = useRouter()
const subdomain = router.query.subdomain as string
@ -167,24 +169,7 @@ export const PagesManagerMenu: FC<{
text: "Delete",
icon: <span className="i-mingcute:delete-2-line inline-block"></span>,
onClick() {
if (!page.metadata) {
const toastId = toast.loading("Deleting...")
delStorage(`draft-${subdomain}-${page.id}`)
Promise.all([
queryClient.refetchQueries(["getPagesBySite", subdomain]),
queryClient.refetchQueries(["getPage", page.id]),
]).then(() => {
toast.success("Deleted!", {
id: toastId,
})
})
} else {
setDeleteToastId(toast.loading("Deleting..."))
deletePage.mutate({
site: subdomain,
id: page.id,
})
}
setDeleteConfirmModalOpen(true)
},
},
]
@ -199,26 +184,57 @@ export const PagesManagerMenu: FC<{
}
}, [])
const [deleteConfirmModalOpen, setDeleteConfirmModalOpen] =
useState<boolean>(false)
const onDelete = () => {
if (!page.metadata) {
const toastId = toast.loading("Deleting...")
delStorage(`draft-${subdomain}-${page.id}`)
Promise.all([
queryClient.refetchQueries(["getPagesBySite", subdomain]),
queryClient.refetchQueries(["getPage", page.id]),
]).then(() => {
toast.success("Deleted!", {
id: toastId,
})
})
} else {
setDeleteToastId(toast.loading("Deleting..."))
deletePage.mutate({
site: subdomain,
id: page.id,
})
}
}
return (
<Menu.Items className="text-sm absolute z-20 right-0 bg-white shadow-modal rounded-lg overflow-hidden py-2 w-64 ring-1 ring-border">
{items.map((item) => {
return (
<Menu.Item key={item.text}>
<button
type="button"
className="h-10 flex w-full space-x-2 items-center px-3 hover:bg-gray-100"
onClick={(e) => {
e.preventDefault()
item.onClick()
onClose()
}}
>
<span className="inline-flex">{item.icon}</span>
<span>{t(item.text)}</span>
</button>
</Menu.Item>
)
})}
</Menu.Items>
<>
<Menu.Items className="text-sm absolute z-20 right-0 bg-white shadow-modal rounded-lg overflow-hidden py-2 w-64 ring-1 ring-border">
{items.map((item) => {
return (
<Menu.Item key={item.text}>
<button
type="button"
className="h-10 flex w-full space-x-2 items-center px-3 hover:bg-gray-100"
onClick={(e) => {
e.preventDefault()
item.onClick()
onClose()
}}
>
<span className="inline-flex">{item.icon}</span>
<span>{t(item.text)}</span>
</button>
</Menu.Item>
)
})}
</Menu.Items>
<DeleteConfirmationModal
open={deleteConfirmModalOpen}
setOpen={setDeleteConfirmModalOpen}
onConfirm={onDelete}
isPost={isPost}
/>
</>
)
}

View File

@ -3,6 +3,7 @@ import { useEffect, useRef, useState } from "react"
import useOnClickOutside from "use-onclickoutside"
import { Button, ButtonGroup } from "../ui/Button"
import { DeleteConfirmationModal } from "./DeleteConfirmationModal"
export const PublishButton: React.FC<{
save: (published: boolean) => void
@ -10,7 +11,8 @@ export const PublishButton: React.FC<{
isSaving: boolean
isDisabled: boolean
twitterShareUrl?: string
}> = ({ save, published, isSaving, isDisabled, twitterShareUrl }) => {
isPost: boolean
}> = ({ save, published, isSaving, isDisabled, twitterShareUrl, isPost }) => {
const [showDropdown, setShowDropdown] = useState(false)
const dropdownRef = useRef<HTMLDivElement | null>(null)
const triggerRef = useRef<HTMLButtonElement | null>(null)
@ -27,6 +29,9 @@ export const PublishButton: React.FC<{
}
}, [isSaving])
const [deleteConfirmModalOpen, setDeleteConfirmModalOpen] =
useState<boolean>(false)
return (
<div className="relative">
<ButtonGroup>
@ -69,7 +74,7 @@ export const PublishButton: React.FC<{
</button>
<button
className="flex w-full h-8 hover:bg-zinc-100 items-center px-5"
onClick={() => save(false)}
onClick={() => setDeleteConfirmModalOpen(true)}
>
<i className="i-mingcute:delete-2-line mr-1"></i>
{t("Delete")}
@ -79,6 +84,14 @@ export const PublishButton: React.FC<{
</div>
</div>
)}
<DeleteConfirmationModal
open={deleteConfirmModalOpen}
setOpen={setDeleteConfirmModalOpen}
onConfirm={() => {
save(false)
}}
isPost={isPost}
/>
</div>
)
}

View File

@ -563,6 +563,7 @@ export default function SubdomainEditor() {
visibility !== PageVisibilityEnum.Modified &&
visibility !== PageVisibilityEnum.Draft
}
isPost={isPost}
/>
</div>
)}