fix: component and state separated, fixed #240
This commit is contained in:
parent
afb3d6ee87
commit
5d5c437089
|
|
@ -1,4 +1,4 @@
|
|||
import { Fragment, useEffect, useMemo, useState } from "react"
|
||||
import { FC, Fragment, useEffect, useMemo, useState } from "react"
|
||||
import { getPageVisibility } from "~/lib/page-helpers"
|
||||
import { useDate } from "~/hooks/useDate"
|
||||
import { TabItem, Tabs } from "../ui/Tabs"
|
||||
|
|
@ -25,6 +25,7 @@ import { Tooltip } from "../ui/Tooltip"
|
|||
import { APP_NAME } from "~/lib/env"
|
||||
import { Trans, useTranslation } from "next-i18next"
|
||||
import { readFiles } from "~/lib/read-files"
|
||||
import { useGetState } from "~/hooks/useGetState"
|
||||
|
||||
export const PagesManager: React.FC<{
|
||||
isPost: boolean
|
||||
|
|
@ -40,38 +41,9 @@ export const PagesManager: React.FC<{
|
|||
[router.query.visibility],
|
||||
)
|
||||
|
||||
const deletePage = useDeletePage()
|
||||
const createOrUpdatePage = useCreateOrUpdatePage()
|
||||
const [convertToastId, setConvertToastId] = useState("")
|
||||
const [deleteToastId, setDeleteToastId] = useState("")
|
||||
const { t } = useTranslation(["dashboard", "site"])
|
||||
const date = useDate()
|
||||
|
||||
useEffect(() => {
|
||||
if (deletePage.isSuccess) {
|
||||
toast.success(t("Deleted!"), {
|
||||
id: deleteToastId,
|
||||
})
|
||||
}
|
||||
}, [deletePage.isSuccess, deleteToastId, t])
|
||||
|
||||
useEffect(() => {
|
||||
if (createOrUpdatePage.isSuccess) {
|
||||
toast.success(t("Converted!"), {
|
||||
id: convertToastId,
|
||||
})
|
||||
} else if (createOrUpdatePage.isError) {
|
||||
toast.error(t("Failed to convert."), {
|
||||
id: convertToastId,
|
||||
})
|
||||
}
|
||||
}, [
|
||||
createOrUpdatePage.isSuccess,
|
||||
createOrUpdatePage.isError,
|
||||
convertToastId,
|
||||
t,
|
||||
])
|
||||
|
||||
const pages = useGetPagesBySite({
|
||||
type: isPost ? "post" : "page",
|
||||
site: subdomain!,
|
||||
|
|
@ -125,91 +97,6 @@ export const PagesManager: React.FC<{
|
|||
}
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
const getPageMenuItems = (page: Note) => {
|
||||
const isCrossbell = !page.applications?.includes("xlog")
|
||||
return [
|
||||
{
|
||||
text: "Edit",
|
||||
icon: <span className="i-mingcute:edit-line inline-block"></span>,
|
||||
onClick() {
|
||||
router.push(getPageEditLink(page))
|
||||
},
|
||||
},
|
||||
{
|
||||
text:
|
||||
"Convert to " +
|
||||
(isCrossbell
|
||||
? `${APP_NAME} ${isPost ? "Post" : "Page"}`
|
||||
: isPost
|
||||
? "Page"
|
||||
: "Post"),
|
||||
icon: <span className="i-mingcute:transfer-3-line inline-block"></span>,
|
||||
onClick() {
|
||||
const toastId = toast.loading("Converting...")
|
||||
if (isCrossbell) {
|
||||
setConvertToastId(toastId)
|
||||
createOrUpdatePage.mutate({
|
||||
published: true,
|
||||
pageId: page.id,
|
||||
siteId: subdomain,
|
||||
tags: page.tags
|
||||
?.filter((tag) => tag !== "post" && tag !== "page")
|
||||
?.join(", "),
|
||||
isPost: isPost,
|
||||
applications: page.applications,
|
||||
})
|
||||
} else {
|
||||
if (!page.metadata) {
|
||||
const data = getStorage(`draft-${subdomain}-${page.id}`)
|
||||
data.isPost = !isPost
|
||||
setStorage(`draft-${subdomain}-${page.id}`, data)
|
||||
queryClient.invalidateQueries(["getPagesBySite", subdomain])
|
||||
queryClient.invalidateQueries(["getPage", page.id])
|
||||
toast.success("Converted!", {
|
||||
id: toastId,
|
||||
})
|
||||
} else {
|
||||
setConvertToastId(toastId)
|
||||
createOrUpdatePage.mutate({
|
||||
published: true,
|
||||
pageId: page.id,
|
||||
siteId: subdomain,
|
||||
tags: page.tags
|
||||
?.filter((tag) => tag !== "post" && tag !== "page")
|
||||
?.join(", "),
|
||||
isPost: !isPost,
|
||||
applications: page.applications,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
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,
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const importFile = () => {
|
||||
const input = document.createElement("input")
|
||||
|
|
@ -380,27 +267,8 @@ export const PagesManager: React.FC<{
|
|||
<i className="i-mingcute:more-1-line text-2xl" />
|
||||
</button>
|
||||
</Menu.Button>
|
||||
<Menu.Items className="text-sm absolute z-20 right-0 bg-white shadow-modal rounded-lg overflow-hidden py-2 w-64">
|
||||
{getPageMenuItems(page).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()
|
||||
}}
|
||||
>
|
||||
<span className="inline-flex">
|
||||
{item.icon}
|
||||
</span>
|
||||
<span>{t(item.text)}</span>
|
||||
</button>
|
||||
</Menu.Item>
|
||||
)
|
||||
})}
|
||||
</Menu.Items>
|
||||
|
||||
<MenuItems isPost={isPost} page={page} />
|
||||
</>
|
||||
)}
|
||||
</Menu>
|
||||
|
|
@ -435,3 +303,169 @@ export const PagesManager: React.FC<{
|
|||
</DashboardMain>
|
||||
)
|
||||
}
|
||||
|
||||
const usePageEditLink = (page: { id: string }, isPost: boolean) => {
|
||||
const router = useRouter()
|
||||
const subdomain = router.query.subdomain as string
|
||||
|
||||
return `/dashboard/${subdomain}/editor?id=${page.id}&type=${
|
||||
isPost ? "post" : "page"
|
||||
}`
|
||||
}
|
||||
|
||||
const usePageMenuItems = ({
|
||||
page,
|
||||
isPost,
|
||||
}: {
|
||||
page: Note
|
||||
isPost: boolean
|
||||
}) => {
|
||||
const isCrossbell = !page.applications?.includes("xlog")
|
||||
const router = useRouter()
|
||||
const createOrUpdatePage = useCreateOrUpdatePage()
|
||||
|
||||
const editLink = usePageEditLink(page, isPost)
|
||||
const subdomain = router.query.subdomain as string
|
||||
const queryClient = useQueryClient()
|
||||
const deletePage = useDeletePage()
|
||||
|
||||
const [convertToastId, setConvertToastId] = useState("")
|
||||
const [deleteToastId, setDeleteToastId] = useState("")
|
||||
|
||||
const getDeleteToastId = useGetState(deleteToastId)
|
||||
const getCurrentToastId = useGetState(convertToastId)
|
||||
const { t } = useTranslation(["dashboard", "site"])
|
||||
|
||||
useEffect(() => {
|
||||
if (deletePage.isSuccess) {
|
||||
toast.success(t("Deleted!"), {
|
||||
id: getDeleteToastId(),
|
||||
})
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [deletePage.isSuccess])
|
||||
|
||||
useEffect(() => {
|
||||
if (createOrUpdatePage.isSuccess) {
|
||||
toast.success(t("Converted!"), {
|
||||
id: getCurrentToastId(),
|
||||
})
|
||||
} else if (createOrUpdatePage.isError) {
|
||||
toast.error(t("Failed to convert."), {
|
||||
id: getCurrentToastId(),
|
||||
})
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [createOrUpdatePage.isSuccess, createOrUpdatePage.isError])
|
||||
|
||||
return [
|
||||
{
|
||||
text: "Edit",
|
||||
icon: <span className="i-mingcute:edit-line inline-block"></span>,
|
||||
onClick() {
|
||||
router.push(editLink)
|
||||
},
|
||||
},
|
||||
{
|
||||
text:
|
||||
"Convert to " +
|
||||
(isCrossbell
|
||||
? `${APP_NAME} ${isPost ? "Post" : "Page"}`
|
||||
: isPost
|
||||
? "Page"
|
||||
: "Post"),
|
||||
icon: <span className="i-mingcute:transfer-3-line inline-block"></span>,
|
||||
onClick() {
|
||||
const toastId = toast.loading("Converting...")
|
||||
if (isCrossbell) {
|
||||
setConvertToastId(toastId)
|
||||
createOrUpdatePage.mutate({
|
||||
published: true,
|
||||
pageId: page.id,
|
||||
siteId: subdomain,
|
||||
tags: page.tags
|
||||
?.filter((tag) => tag !== "post" && tag !== "page")
|
||||
?.join(", "),
|
||||
isPost: isPost,
|
||||
applications: page.applications,
|
||||
})
|
||||
} else {
|
||||
if (!page.metadata) {
|
||||
const data = getStorage(`draft-${subdomain}-${page.id}`)
|
||||
data.isPost = !isPost
|
||||
setStorage(`draft-${subdomain}-${page.id}`, data)
|
||||
queryClient.invalidateQueries(["getPagesBySite", subdomain])
|
||||
queryClient.invalidateQueries(["getPage", page.id])
|
||||
toast.success("Converted!", {
|
||||
id: toastId,
|
||||
})
|
||||
} else {
|
||||
setConvertToastId(toastId)
|
||||
createOrUpdatePage.mutate({
|
||||
published: true,
|
||||
pageId: page.id,
|
||||
siteId: subdomain,
|
||||
tags: page.tags
|
||||
?.filter((tag) => tag !== "post" && tag !== "page")
|
||||
?.join(", "),
|
||||
isPost: !isPost,
|
||||
applications: page.applications,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
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,
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const MenuItems: FC<{
|
||||
isPost: boolean
|
||||
page: Note
|
||||
}> = ({ isPost, page }) => {
|
||||
const { t } = useTranslation(["dashboard", "site"])
|
||||
return (
|
||||
<Menu.Items className="text-sm absolute z-20 right-0 bg-white shadow-modal rounded-lg overflow-hidden py-2 w-64">
|
||||
{usePageMenuItems({ page, isPost }).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()
|
||||
}}
|
||||
>
|
||||
<span className="inline-flex">{item.icon}</span>
|
||||
<span>{t(item.text)}</span>
|
||||
</button>
|
||||
</Menu.Item>
|
||||
)
|
||||
})}
|
||||
</Menu.Items>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
import { useEffect, useRef } from "react"
|
||||
|
||||
export const useGetState = (state: any) => {
|
||||
const ref = useRef(state)
|
||||
|
||||
useEffect(() => void (ref.current = state), [state])
|
||||
return () => ref.current
|
||||
}
|
||||
Loading…
Reference in New Issue