From 9fe43393d032fa3a6f2b1c2a927f669a15ebb1df Mon Sep 17 00:00:00 2001 From: "Ben Scholzen (DASPRiD)" Date: Thu, 25 Apr 2024 14:34:20 +0200 Subject: [PATCH] feat(skeleton): replace dialog controller component with hook --- .../DialogController/DialogController.tsx | 48 ------------------- .../src/components/DialogController/index.ts | 1 - .../base/src/hooks/useDialogController.tsx | 47 ++++++++++++++++++ .../pages/ArticlesPage/ArticleFormDialog.tsx | 10 ++-- .../pages/ArticlesPage/ArticleListItem.tsx | 25 ++++++---- .../src/pages/ArticlesPage/ArticlesPage.tsx | 18 +++++-- .../ArticlesPage/CreateArticleFormDialog.tsx | 10 ++-- .../ArticlesPage/EditArticleFormDialog.tsx | 10 ++-- skeleton/package.json | 4 +- 9 files changed, 95 insertions(+), 78 deletions(-) delete mode 100644 skeleton/base/src/components/DialogController/DialogController.tsx delete mode 100644 skeleton/base/src/components/DialogController/index.ts create mode 100644 skeleton/base/src/hooks/useDialogController.tsx diff --git a/skeleton/base/src/components/DialogController/DialogController.tsx b/skeleton/base/src/components/DialogController/DialogController.tsx deleted file mode 100644 index 8844c9b..0000000 --- a/skeleton/base/src/components/DialogController/DialogController.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import type { TransitionProps } from "@mui/material/transitions"; -import { type ReactNode, useState } from "react"; - -type RenderControllerProps = { - onClick: () => void; -}; - -export type RenderDialogProps = { - open: boolean; - onClose: () => void; - TransitionProps: TransitionProps; -}; - -type Props = { - controller: (props: RenderControllerProps) => ReactNode; - dialog: (props: RenderDialogProps) => ReactNode; -}; - -const DialogController = ({ controller, dialog }: Props): ReactNode => { - const [open, setOpen] = useState(false); - const [mounted, setMounted] = useState(false); - - return ( - <> - {controller({ - onClick: () => { - setOpen(true); - setMounted(true); - }, - })} - - {mounted && - dialog({ - open, - onClose: () => { - setOpen(false); - }, - TransitionProps: { - onExited: () => { - setMounted(false); - }, - }, - })} - - ); -}; - -export default DialogController; diff --git a/skeleton/base/src/components/DialogController/index.ts b/skeleton/base/src/components/DialogController/index.ts deleted file mode 100644 index c54ce23..0000000 --- a/skeleton/base/src/components/DialogController/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default, type RenderDialogProps } from "./DialogController.tsx"; diff --git a/skeleton/base/src/hooks/useDialogController.tsx b/skeleton/base/src/hooks/useDialogController.tsx new file mode 100644 index 0000000..e921114 --- /dev/null +++ b/skeleton/base/src/hooks/useDialogController.tsx @@ -0,0 +1,47 @@ +import type { TransitionProps } from "@mui/material/transitions"; +import { useCallback, useMemo, useState } from "react"; + +export type ControlledDialogProps = { + open: boolean; + onClose: () => void; + TransitionProps: TransitionProps; +}; + +type DialogController = { + open: () => void; + mount: boolean; + dialogProps: ControlledDialogProps; +}; + +const useDialogController = (): DialogController => { + const [open, setOpen] = useState(false); + const [mounted, setMounted] = useState(false); + + const handleOpen = useCallback(() => { + setMounted(true); + setOpen(true); + }, []); + + const onClose = useCallback(() => { + setOpen(false); + }, []); + + return useMemo( + () => ({ + open: handleOpen, + mount: mounted, + dialogProps: { + open, + onClose, + TransitionProps: { + onExited: () => { + setMounted(false); + }, + }, + }, + }), + [open, handleOpen, onClose, mounted], + ); +}; + +export default useDialogController; diff --git a/skeleton/base/src/pages/ArticlesPage/ArticleFormDialog.tsx b/skeleton/base/src/pages/ArticlesPage/ArticleFormDialog.tsx index 1ddf881..1ac8671 100644 --- a/skeleton/base/src/pages/ArticlesPage/ArticleFormDialog.tsx +++ b/skeleton/base/src/pages/ArticlesPage/ArticleFormDialog.tsx @@ -1,4 +1,3 @@ -import type { RenderDialogProps } from "@/components/DialogController/index.ts"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Stack } from "@mui/material"; import { RhfTextField } from "mui-rhf-integration"; @@ -6,6 +5,7 @@ import type { ReactNode } from "react"; import { useEffect } from "react"; import { type DefaultValues, useForm } from "react-hook-form"; import { z } from "zod"; +import type { ControlledDialogProps } from "@/hooks/useDialogController.tsx"; const schema = z.object({ title: z.string().trim().min(1), @@ -20,10 +20,10 @@ type Props = { title: string; defaultValues?: DefaultValues; onSubmit: (values: TransformedValues) => Promise; - DialogProps: RenderDialogProps; + dialogProps: ControlledDialogProps; }; -const ArticleFormDialog = ({ title, defaultValues, onSubmit, DialogProps }: Props): ReactNode => { +const ArticleFormDialog = ({ title, defaultValues, onSubmit, dialogProps }: Props): ReactNode => { const form = useForm({ resolver: zodResolver(schema), defaultValues, @@ -35,7 +35,7 @@ const ArticleFormDialog = ({ title, defaultValues, onSubmit, DialogProps }: Prop return ( - diff --git a/skeleton/base/src/pages/ArticlesPage/ArticleListItem.tsx b/skeleton/base/src/pages/ArticlesPage/ArticleListItem.tsx index 68860d0..794efda 100644 --- a/skeleton/base/src/pages/ArticlesPage/ArticleListItem.tsx +++ b/skeleton/base/src/pages/ArticlesPage/ArticleListItem.tsx @@ -1,5 +1,4 @@ import ConfirmDialog from "@/components/ConfirmDialog/index.ts"; -import DialogController from "@/components/DialogController/index.ts"; import { useDeleteArticleMutation } from "@/mutations/article.ts"; import EditArticleFormDialog from "@/pages/ArticlesPage/EditArticleFormDialog.tsx"; import type { ListArticle } from "@/queries/article.ts"; @@ -9,6 +8,7 @@ import { bindMenu, bindTrigger, usePopupState } from "material-ui-popup-state/ho import { useSnackbar } from "notistack"; import type { ReactNode } from "react"; import { useConfirm } from "react-confirm-hook"; +import useDialogController from "@/hooks/useDialogController.js"; type Props = { article: ListArticle; @@ -22,6 +22,7 @@ const ArticleListItem = ({ article }: Props): ReactNode => { const deleteMutation = useDeleteArticleMutation(); const { enqueueSnackbar } = useSnackbar(); const confirm = useConfirm(ConfirmDialog); + const editDialogController = useDialogController(); const handleDelete = () => { confirm({ @@ -48,19 +49,27 @@ const ArticleListItem = ({ article }: Props): ReactNode => { - Edit} - dialog={(props) => ( - - )} - /> - + { + editDialogController.open(); + popupState.close(); + }} + > + Edit + Delete } > {article.title} + + {editDialogController.mount && ( + + )} ); }; diff --git a/skeleton/base/src/pages/ArticlesPage/ArticlesPage.tsx b/skeleton/base/src/pages/ArticlesPage/ArticlesPage.tsx index b93e2f5..e093240 100644 --- a/skeleton/base/src/pages/ArticlesPage/ArticlesPage.tsx +++ b/skeleton/base/src/pages/ArticlesPage/ArticlesPage.tsx @@ -6,6 +6,7 @@ import type { ReactNode } from "react"; import { useState } from "react"; import ArticleListItem from "./ArticleListItem.tsx"; import CreateArticleFormDialog from "./CreateArticleFormDialog.tsx"; +import useDialogController from "@/hooks/useDialogController.js"; type PaginationButtonProps = { label: string; @@ -85,16 +86,25 @@ const ArticleList = (): ReactNode => { }; const ArticlesPage = (): ReactNode => { + const createDialogController = useDialogController(); + return ( Articles - } - dialog={(props) => } - /> + + + {createDialogController.mount && ( + + )} diff --git a/skeleton/base/src/pages/ArticlesPage/CreateArticleFormDialog.tsx b/skeleton/base/src/pages/ArticlesPage/CreateArticleFormDialog.tsx index 46ebbb1..9dddec1 100644 --- a/skeleton/base/src/pages/ArticlesPage/CreateArticleFormDialog.tsx +++ b/skeleton/base/src/pages/ArticlesPage/CreateArticleFormDialog.tsx @@ -1,14 +1,14 @@ -import type { RenderDialogProps } from "@/components/DialogController/index.ts"; import { useCreateWorldMutation } from "@/mutations/article.ts"; import { useSnackbar } from "notistack"; import type { ReactNode } from "react"; import ArticleFormDialog, { type ArticleFormValues } from "./ArticleFormDialog.tsx"; +import type { ControlledDialogProps } from "@/hooks/useDialogController.tsx"; type Props = { - DialogProps: RenderDialogProps; + dialogProps: ControlledDialogProps; }; -const CreateArticleFormDialog = ({ DialogProps }: Props): ReactNode => { +const CreateArticleFormDialog = ({ dialogProps }: Props): ReactNode => { const { enqueueSnackbar } = useSnackbar(); const createMutation = useCreateWorldMutation(); @@ -23,14 +23,14 @@ const CreateArticleFormDialog = ({ DialogProps }: Props): ReactNode => { } enqueueSnackbar("Article has been created", { variant: "success" }); - DialogProps.onClose(); + dialogProps.onClose(); }; return ( ); }; diff --git a/skeleton/base/src/pages/ArticlesPage/EditArticleFormDialog.tsx b/skeleton/base/src/pages/ArticlesPage/EditArticleFormDialog.tsx index 2d5950d..f7fc47f 100644 --- a/skeleton/base/src/pages/ArticlesPage/EditArticleFormDialog.tsx +++ b/skeleton/base/src/pages/ArticlesPage/EditArticleFormDialog.tsx @@ -1,4 +1,3 @@ -import type { RenderDialogProps } from "@/components/DialogController/index.ts"; import { useUpdateArticleMutation } from "@/mutations/article.ts"; import { useArticleQuery } from "@/queries/article.ts"; import { Backdrop, CircularProgress } from "@mui/material"; @@ -6,13 +5,14 @@ import { useSnackbar } from "notistack"; import { useEffect } from "react"; import type { ReactNode } from "react"; import ArticleFormDialog, { type ArticleFormValues } from "./ArticleFormDialog.tsx"; +import type { ControlledDialogProps } from "@/hooks/useDialogController.tsx"; type Props = { articleId: string; - DialogProps: RenderDialogProps; + dialogProps: ControlledDialogProps; }; -const EditArticleFormDialog = ({ articleId, DialogProps }: Props): ReactNode => { +const EditArticleFormDialog = ({ articleId, dialogProps }: Props): ReactNode => { const { enqueueSnackbar } = useSnackbar(); const articleQuery = useArticleQuery(articleId); const updateMutation = useUpdateArticleMutation(); @@ -29,7 +29,7 @@ const EditArticleFormDialog = ({ articleId, DialogProps }: Props): ReactNode => } enqueueSnackbar("Article has been updated", { variant: "success" }); - DialogProps.onClose(); + dialogProps.onClose(); }; useEffect(() => { @@ -60,7 +60,7 @@ const EditArticleFormDialog = ({ articleId, DialogProps }: Props): ReactNode => content: article.content, }} onSubmit={handleSubmit} - DialogProps={DialogProps} + DialogProps={dialogProps} /> ); }; diff --git a/skeleton/package.json b/skeleton/package.json index c289776..f92b96a 100644 --- a/skeleton/package.json +++ b/skeleton/package.json @@ -28,9 +28,9 @@ "@mui/material": "^5.15.10", "@tanstack/react-query": "^5.20.5", "caught-object-report-json": "^7.1.7", - "jsonapi-zod-query": "^1.2.3", + "jsonapi-zod-query": "^1.5.0", "material-ui-popup-state": "^5.0.10", - "mui-rhf-integration": "^3.4.0", + "mui-rhf-integration": "^4.0.3", "notistack": "^3.0.1", "react": "^18.2.0", "react-confirm-hook": "^1.0.4",