From 21c4bd97e649503bb8bc2bbaa5b729e321d377f3 Mon Sep 17 00:00:00 2001 From: yassinedorbozgithub Date: Sun, 26 Jan 2025 09:15:07 +0100 Subject: [PATCH] fix(frontend): introduce state mode feature --- frontend/public/locales/en/translation.json | 3 +- frontend/public/locales/fr/translation.json | 3 +- .../app-components/dialogs/DeleteDialog.tsx | 57 ++++++++----------- .../src/app-components/dialogs/MoveDialog.tsx | 42 +++++++------- .../components/visual-editor/v2/Diagrams.tsx | 17 ++---- frontend/src/hooks/useDialog.tsx | 30 ++++++---- 6 files changed, 74 insertions(+), 78 deletions(-) diff --git a/frontend/public/locales/en/translation.json b/frontend/public/locales/en/translation.json index a65a18bc..f090d8af 100644 --- a/frontend/public/locales/en/translation.json +++ b/frontend/public/locales/en/translation.json @@ -43,8 +43,9 @@ "account_update_success": "Account has been updated successfully", "account_disabled": "Your account has been either disabled or is pending confirmation.", "success_invitation_sent": "Invitation to join has been successfully sent.", - "item_delete_confirm": "Are you sure you want to delete this item?", + "item_delete_confirm": "Are you sure you want to delete this {{0}} item?", "items_delete_confirm": "Are you sure you want to delete those {{0}} selected items?", + "selected": "selected", "item_delete_success": "Item has been deleted successfully", "success_save": "Changes has been saved!", "no_result_found": "No result found", diff --git a/frontend/public/locales/fr/translation.json b/frontend/public/locales/fr/translation.json index 53b421dc..75bba807 100644 --- a/frontend/public/locales/fr/translation.json +++ b/frontend/public/locales/fr/translation.json @@ -43,8 +43,9 @@ "account_update_success": "Le compte a été mis à jour avec succès", "account_disabled": "Votre compte a été désactivé ou est en attente de confirmation.", "success_invitation_sent": "L'invitation a été envoyée avec succès.", - "item_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer cet élément?", + "item_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer cet élément {{0}}?", "items_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer ces {{0}} éléments sélectionnés?", + "selected": "sélectionné", "item_delete_success": "L'élément a été supprimé avec succès", "success_save": "Les modifications ont été enregistrées!", "no_result_found": "Aucun résultat trouvé", diff --git a/frontend/src/app-components/dialogs/DeleteDialog.tsx b/frontend/src/app-components/dialogs/DeleteDialog.tsx index 1c410719..fae0592f 100644 --- a/frontend/src/app-components/dialogs/DeleteDialog.tsx +++ b/frontend/src/app-components/dialogs/DeleteDialog.tsx @@ -26,40 +26,30 @@ import { IEntityMapTypes } from "@/types/base.types"; export type DeleteDialogProps = DialogControl; export const DeleteDialog = ({ - open, - closeDialog: closeFunction, - datum, data: ids, - callback, entity = EntityType.ATTACHMENT, - setData, onDeleteError = () => {}, onDeleteSuccess = () => {}, + ...rest }: DeleteDialogProps & { entity?: keyof IEntityMapTypes; onDeleteError?: (error: Error) => void; onDeleteSuccess?: (data?: unknown) => void; }) => { const { t } = useTranslate(); - const getItemsFromData = (data: unknown) => (Array.isArray(data) ? data : []); - const hasMultipleItems = (data: unknown): boolean => - getItemsFromData(data).length > 1; - const onSuccess = (data: unknown) => { - setData?.(undefined); - onDeleteSuccess(data); + const options = { + onError: onDeleteError, + onSuccess: (data: unknown) => { + rest.setData?.(undefined); + onDeleteSuccess(data); + }, }; - const { mutateAsync: deleteOne } = useDelete(entity, { - onError: onDeleteError, - onSuccess, - }); - const { mutateAsync: deleteMany } = useDeleteMany(entity, { - onError: onDeleteError, - onSuccess, - }); + const { mutateAsync: deleteOne } = useDelete(entity, options); + const { mutateAsync: deleteMany } = useDeleteMany(entity, options); return ( - - {t("title.warning")} + + {t("title.warning")} @@ -68,12 +58,15 @@ export const DeleteDialog = ({ {t( - `${ - hasMultipleItems(ids) - ? "message.items_delete_confirm" - : "message.item_delete_confirm" - }`, - { "0": getItemsFromData(ids).length.toString() }, + `message.item${ + (ids?.length || 0) > 1 ? "s" : "" + }_delete_confirm`, + { + "0": + ids?.length === 1 + ? t("message.selected") + : ids?.length.toString(), + }, )} @@ -84,19 +77,19 @@ export const DeleteDialog = ({ color="error" variant="contained" onClick={async () => { - if (callback) { - callback(ids); + if (rest.callback) { + rest.callback(ids); } else if (Array.isArray(ids)) { await deleteMany(ids); - } else if (datum) { - await deleteOne(datum); + } else if (rest.datum) { + await deleteOne(rest.datum); } }} autoFocus > {t("button.yes")} - diff --git a/frontend/src/app-components/dialogs/MoveDialog.tsx b/frontend/src/app-components/dialogs/MoveDialog.tsx index e2340de2..71f8cd37 100644 --- a/frontend/src/app-components/dialogs/MoveDialog.tsx +++ b/frontend/src/app-components/dialogs/MoveDialog.tsx @@ -15,55 +15,51 @@ import { MenuItem, Select, } from "@mui/material"; -import { FC, useState } from "react"; import { DialogTitle } from "@/app-components/dialogs/DialogTitle"; import { DialogControl } from "@/hooks/useDialog"; import { useTranslate } from "@/hooks/useTranslate"; import { ICategory } from "@/types/category.types"; -export interface MoveDialogProps - extends Omit, "callback"> { +export interface MoveDialogProps + extends Omit, "callback"> { categories: ICategory[]; - callback?: (newCategoryId?: string) => Promise; - openDialog: (data?: string) => void; + callback?: (selectedCategoryId?: T, ids?: T[]) => Promise; } -export const MoveDialog: FC = ({ - open, - callback, - closeDialog, - categories, -}: MoveDialogProps) => { +export const MoveDialog = ({ + data: ids, + datum: selectedCategoryId, + ...rest +}: MoveDialogProps) => { const { t } = useTranslate(); - const [selectedCategoryId, setSelectedCategoryId] = useState(""); const handleMove = async () => { - if (selectedCategoryId && callback) { - await callback(selectedCategoryId); - closeDialog(); + if (selectedCategoryId && rest.callback) { + await rest.callback(selectedCategoryId, ids); + rest.closeDialog(); } }; return ( - - + + {t("message.select_category")} @@ -78,7 +74,7 @@ export const MoveDialog: FC = ({ > {t("button.move")} - diff --git a/frontend/src/components/visual-editor/v2/Diagrams.tsx b/frontend/src/components/visual-editor/v2/Diagrams.tsx index 921b5f47..8123ae73 100644 --- a/frontend/src/components/visual-editor/v2/Diagrams.tsx +++ b/frontend/src/components/visual-editor/v2/Diagrams.tsx @@ -75,7 +75,7 @@ const Diagrams = () => { const [canvas, setCanvas] = useState(); const [selectedBlockId, setSelectedBlockId] = useState(); const deleteDialogCtl = useDialog(false); - const moveDialogCtl = useDialog(false); + const moveDialogCtl = useDialog(false, "datumAndData"); const addCategoryDialogCtl = useDialog(false); const { mutateAsync: updateBlocks } = useUpdateMany(EntityType.BLOCK); const { @@ -203,8 +203,7 @@ const Diagrams = () => { setter: setSelectedBlockId, updateFn: updateBlock, onRemoveNode: (ids, next) => { - deleteDialogCtl.setData?.(ids); - deleteDialogCtl.openDialog(); + deleteDialogCtl.openDialog(ids); deleteCallbackRef.current = next; }, onDbClickNode: (event, id) => { @@ -446,8 +445,7 @@ const Diagrams = () => { }); engine?.repaintCanvas(); }; - deleteDialogCtl.setData?.(ids); - deleteDialogCtl.openDialog(); + deleteDialogCtl.openDialog(ids); } }; const handleMoveButton = () => { @@ -455,8 +453,7 @@ const Diagrams = () => { const ids = selectedEntities?.map((model) => model.getID()); if (ids && selectedEntities) { - moveDialogCtl.setData?.(ids); - moveDialogCtl.openDialog(); + moveDialogCtl.openDialog(ids); } }; const onDelete = async (ids: string[]) => { @@ -473,14 +470,12 @@ const Diagrams = () => { cleanupAfterDeletion(); }; - const onMove = async (newCategoryId?: string) => { + const onMove = async (newCategoryId?: string, ids?: string[]) => { if (!newCategoryId) { return; } - const ids = moveDialogCtl?.data; - - if (ids?.length && Array.isArray(ids)) { + if (Array.isArray(ids) && ids?.length) { await updateBlocks({ ids, payload: { category: newCategoryId } }); queryClient.invalidateQueries({ diff --git a/frontend/src/hooks/useDialog.tsx b/frontend/src/hooks/useDialog.tsx index 13b03d3f..cac256c0 100644 --- a/frontend/src/hooks/useDialog.tsx +++ b/frontend/src/hooks/useDialog.tsx @@ -15,24 +15,33 @@ type TCloseDialog = ( reason?: "backdropClick" | "escapeKeyDown", ) => void; type TFnVoid = (data?: T) => void; - +type TStatesMode = "datumOrData" | "datumAndData"; export type DialogControl = DialogProps & { data?: T[]; datum?: T; setData?: TFnVoid; + setDatum?: TFnVoid; callback?: (data?: T | T[]) => Promise; - openDialog: TFnVoid; + openDialog: TFnVoid; closeDialog: TCloseDialog; }; -export const useDialog = (initialState: boolean): DialogControl => { +export const useDialog = ( + initialState: boolean, + statesMode: TStatesMode = "datumOrData", +): DialogControl => { const [open, setOpen] = useState(initialState); - const [data, setData] = useState(undefined); - const [datum, setDatum] = useState(undefined); - const openDialog: TFnVoid = (datum) => { - setDatum(datum); - if (datum) { - setData(undefined); + const [data, setData] = useState(); + const [datum, setDatum] = useState(); + const openDialog: TFnVoid = (value) => { + if (statesMode === "datumOrData") { + if (value) { + setData(Array.isArray(value) ? value : undefined); + setDatum(Array.isArray(value) ? undefined : value); + } + } else if (statesMode === "datumAndData") { + setData(Array.isArray(value) ? value : data); + setDatum(Array.isArray(value) ? datum : value); } setOpen(true); }; @@ -47,6 +56,7 @@ export const useDialog = (initialState: boolean): DialogControl => { data, datum, setData, + setDatum, openDialog, closeDialog, }; @@ -54,6 +64,6 @@ export const useDialog = (initialState: boolean): DialogControl => { export const getDisplayDialogs = ({ open, - closeDialog, datum, + closeDialog, }: DialogControl): DialogControlProps => ({ open, datum, closeDialog });