From f386a055790f08ab84bf94f34bdae2de60317d36 Mon Sep 17 00:00:00 2001 From: Xavier Abad <77491413+xabg2@users.noreply.github.com> Date: Tue, 24 Mar 2026 09:37:46 +0100 Subject: [PATCH 1/3] feat(context): dialogs manager --- .../dialog-manager/DialogManager.context.tsx | 35 +++++++++++++++++++ src/context/dialog-manager/index.ts | 3 ++ src/context/dialog-manager/types/index.ts | 18 ++++++++++ .../dialog-manager/useActionDialog.tsx | 32 +++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 src/context/dialog-manager/DialogManager.context.tsx create mode 100644 src/context/dialog-manager/index.ts create mode 100644 src/context/dialog-manager/types/index.ts create mode 100644 src/context/dialog-manager/useActionDialog.tsx diff --git a/src/context/dialog-manager/DialogManager.context.tsx b/src/context/dialog-manager/DialogManager.context.tsx new file mode 100644 index 0000000..933b884 --- /dev/null +++ b/src/context/dialog-manager/DialogManager.context.tsx @@ -0,0 +1,35 @@ +import { useMemo, useState, useCallback, type ReactNode, type FC } from 'react'; +import type { ActionDialog, ActionDialogState, DialogActionConfig } from './types'; +import { DialogManagerContext } from './useActionDialog'; + +export const DialogManagerProvider: FC<{ children: ReactNode }> = ({ children }) => { + const [actionDialogs, setActionDialogs] = useState>>({}); + + const openDialog = useCallback((dialogKey: ActionDialog, config?: DialogActionConfig) => { + setActionDialogs((prevDialogs) => { + const newDialogs = config?.closeAllDialogsFirst ? {} : { ...prevDialogs }; + newDialogs[dialogKey] = { isOpen: true, key: dialogKey, data: config?.data }; + return newDialogs; + }); + }, []); + + const closeDialog = useCallback((dialogKey: ActionDialog) => { + setActionDialogs((prevDialogs) => { + return { + ...prevDialogs, + [dialogKey]: { ...prevDialogs[dialogKey], isOpen: false, data: null }, + }; + }); + }, []); + + const memoizedValue = useMemo( + () => ({ + actionDialogs, + openDialog, + closeDialog, + }), + [actionDialogs, openDialog, closeDialog], + ); + + return {children}; +}; diff --git a/src/context/dialog-manager/index.ts b/src/context/dialog-manager/index.ts new file mode 100644 index 0000000..0b7f4b2 --- /dev/null +++ b/src/context/dialog-manager/index.ts @@ -0,0 +1,3 @@ +export { DialogManagerProvider } from './DialogManager.context'; +export { ActionDialog, type DialogActionConfig } from './types'; +export { DialogManagerContext, useActionDialog } from './useActionDialog'; diff --git a/src/context/dialog-manager/types/index.ts b/src/context/dialog-manager/types/index.ts new file mode 100644 index 0000000..19fef58 --- /dev/null +++ b/src/context/dialog-manager/types/index.ts @@ -0,0 +1,18 @@ +export enum ActionDialog { + ComposeMessage = 'compose-message', + Settings = 'settings', +} + +export interface ActionDialogState { + isOpen: boolean; + key: ActionDialog; + data?: unknown; +} + +export type DialogActionConfig = { closeAllDialogsFirst?: boolean; data?: unknown }; + +export type ActionDialogContextProps = { + actionDialogs: Partial>; + openDialog: (key: ActionDialog, config?: DialogActionConfig) => void; + closeDialog: (key: ActionDialog, config?: DialogActionConfig) => void; +}; diff --git a/src/context/dialog-manager/useActionDialog.tsx b/src/context/dialog-manager/useActionDialog.tsx new file mode 100644 index 0000000..d6ed875 --- /dev/null +++ b/src/context/dialog-manager/useActionDialog.tsx @@ -0,0 +1,32 @@ +import { createContext, useCallback, useContext } from 'react'; +import type { ActionDialog, ActionDialogContextProps } from './types'; + +export const DialogManagerContext = createContext(undefined); + +export const useActionDialog = () => { + const ctx = useContext(DialogManagerContext); + if (!ctx) { + throw new Error('The context is not initialized. Please it inside the provider'); + } + + const isDialogOpen = useCallback( + (key: ActionDialog) => { + return ctx.actionDialogs[key]?.isOpen || false; + }, + [ctx.actionDialogs], + ); + + const getDialogData = useCallback( + (key: ActionDialog) => { + return ctx.actionDialogs[key]?.data || null; + }, + [ctx.actionDialogs], + ); + + return { + isDialogOpen, + getDialogData, + openDialog: ctx.openDialog, + closeDialog: ctx.closeDialog, + }; +}; From 248769107713f37b41d12e1519c03cee7da7990e Mon Sep 17 00:00:00 2001 From: Xavier Abad <77491413+xabg2@users.noreply.github.com> Date: Tue, 24 Mar 2026 10:23:09 +0100 Subject: [PATCH 2/3] fix: small issues --- src/context/dialog-manager/DialogManager.context.tsx | 2 +- src/context/dialog-manager/types/index.ts | 2 +- src/context/dialog-manager/useActionDialog.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/context/dialog-manager/DialogManager.context.tsx b/src/context/dialog-manager/DialogManager.context.tsx index 933b884..64b386d 100644 --- a/src/context/dialog-manager/DialogManager.context.tsx +++ b/src/context/dialog-manager/DialogManager.context.tsx @@ -17,7 +17,7 @@ export const DialogManagerProvider: FC<{ children: ReactNode }> = ({ children }) setActionDialogs((prevDialogs) => { return { ...prevDialogs, - [dialogKey]: { ...prevDialogs[dialogKey], isOpen: false, data: null }, + [dialogKey]: { ...prevDialogs[dialogKey], key: dialogKey, isOpen: false, data: null }, }; }); }, []); diff --git a/src/context/dialog-manager/types/index.ts b/src/context/dialog-manager/types/index.ts index 19fef58..e65ea9d 100644 --- a/src/context/dialog-manager/types/index.ts +++ b/src/context/dialog-manager/types/index.ts @@ -14,5 +14,5 @@ export type DialogActionConfig = { closeAllDialogsFirst?: boolean; data?: unknow export type ActionDialogContextProps = { actionDialogs: Partial>; openDialog: (key: ActionDialog, config?: DialogActionConfig) => void; - closeDialog: (key: ActionDialog, config?: DialogActionConfig) => void; + closeDialog: (key: ActionDialog) => void; }; diff --git a/src/context/dialog-manager/useActionDialog.tsx b/src/context/dialog-manager/useActionDialog.tsx index d6ed875..391d819 100644 --- a/src/context/dialog-manager/useActionDialog.tsx +++ b/src/context/dialog-manager/useActionDialog.tsx @@ -6,7 +6,7 @@ export const DialogManagerContext = createContext { const ctx = useContext(DialogManagerContext); if (!ctx) { - throw new Error('The context is not initialized. Please it inside the provider'); + throw new Error('The context is not initialized. Please use it inside the provider'); } const isDialogOpen = useCallback( @@ -18,7 +18,7 @@ export const useActionDialog = () => { const getDialogData = useCallback( (key: ActionDialog) => { - return ctx.actionDialogs[key]?.data || null; + return ctx.actionDialogs[key]?.data ?? null; }, [ctx.actionDialogs], ); From e4bc40e37ecb97f6938496b4e5c9520505b5b69e Mon Sep 17 00:00:00 2001 From: Xavier Abad <77491413+xabg2@users.noreply.github.com> Date: Tue, 24 Mar 2026 10:35:00 +0100 Subject: [PATCH 3/3] fix: use nullish for is open dialog --- src/context/dialog-manager/useActionDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/dialog-manager/useActionDialog.tsx b/src/context/dialog-manager/useActionDialog.tsx index 391d819..5f667ff 100644 --- a/src/context/dialog-manager/useActionDialog.tsx +++ b/src/context/dialog-manager/useActionDialog.tsx @@ -11,7 +11,7 @@ export const useActionDialog = () => { const isDialogOpen = useCallback( (key: ActionDialog) => { - return ctx.actionDialogs[key]?.isOpen || false; + return ctx.actionDialogs[key]?.isOpen ?? false; }, [ctx.actionDialogs], );