From 5193e17a1d009ba7d18df60b00a6518ba1f37586 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Thu, 20 Mar 2025 15:58:48 -0600 Subject: [PATCH] update confirm modal logic --- .../ui/modal/ConfirmModal.stories.tsx | 35 +++++++++++ .../BusterNotifications/useConfirmModal.ts | 58 ++++++++++++------- .../DashboardViewDashboardController.tsx | 2 +- 3 files changed, 72 insertions(+), 23 deletions(-) diff --git a/web/src/components/ui/modal/ConfirmModal.stories.tsx b/web/src/components/ui/modal/ConfirmModal.stories.tsx index 263abb85d..308e23295 100644 --- a/web/src/components/ui/modal/ConfirmModal.stories.tsx +++ b/web/src/components/ui/modal/ConfirmModal.stories.tsx @@ -55,3 +55,38 @@ export const Default: Story = { ); } }; + +export const Sequential: Story = { + render: () => { + const { openConfirmModal } = useBusterNotifications(); + + const handleSequentialModals = async () => { + await openConfirmModal({ + title: 'First Modal', + content: 'This is the first modal in the sequence.', + onOk: fn(), + onCancel: fn() + }); + + await new Promise((resolve) => setTimeout(resolve, 100)); + + await openConfirmModal({ + title: 'Second Modal', + content: 'Here comes the second modal!', + onOk: fn(), + onCancel: fn() + }); + + await new Promise((resolve) => setTimeout(resolve, 100)); + + await openConfirmModal({ + title: 'Final Modal', + content: 'This is the last modal in our sequence.', + onOk: fn(), + onCancel: fn() + }); + }; + + return ; + } +}; diff --git a/web/src/context/BusterNotifications/useConfirmModal.ts b/web/src/context/BusterNotifications/useConfirmModal.ts index 0cce1b0dd..7e7d08593 100644 --- a/web/src/context/BusterNotifications/useConfirmModal.ts +++ b/web/src/context/BusterNotifications/useConfirmModal.ts @@ -1,5 +1,5 @@ import { ConfirmModalProps, ConfirmProps } from '@/components/ui/modal/ConfirmModal'; -import { useState, useRef } from 'react'; +import { useState, useRef, useMemo } from 'react'; const defaultConfirmModalProps: ConfirmProps = { title: '', @@ -8,19 +8,22 @@ const defaultConfirmModalProps: ConfirmProps = { onCancel: async () => {} }; +interface QueuedModal extends ConfirmProps { + resolve: (value: void) => void; + reject: (reason?: any) => void; + onClose: () => void; +} + export const useOpenConfirmModal = () => { - const [open, setOpen] = useState(false); - const confirmModalPropsRef = useRef(defaultConfirmModalProps); - const resolveRef = useRef<((value: void) => void) | null>(null); - const rejectRef = useRef<((reason?: any) => void) | null>(null); + const [modalQueue, setModalQueue] = useState([]); + const currentModal = modalQueue[0]; // Get the first modal in the queue const openConfirmModal = (props: ConfirmProps): Promise => { return new Promise((resolve, reject) => { - resolveRef.current = resolve; - rejectRef.current = reject; - - confirmModalPropsRef.current = { + const newModal: QueuedModal = { ...props, + resolve, + reject, onOk: async () => { try { await props.onOk(); @@ -28,7 +31,8 @@ export const useOpenConfirmModal = () => { } catch (error) { reject(error); } finally { - setOpen(false); + // Remove the current modal from the queue + setModalQueue((prev) => prev.slice(1)); } }, onCancel: async () => { @@ -38,24 +42,34 @@ export const useOpenConfirmModal = () => { } catch (error) { reject(error); } finally { - setOpen(false); + // Remove the current modal from the queue + setModalQueue((prev) => prev.slice(1)); } + }, + onClose: () => { + resolve(); + setModalQueue((prev) => prev.slice(1)); } }; - setOpen(true); + setModalQueue((prev) => [...prev, newModal]); }); }; - const onCloseConfirmModal = () => { - setOpen(false); - }; + const confirmModalProps: ConfirmModalProps = useMemo(() => { + return currentModal + ? { + ...currentModal, + open: true + } + : { + ...defaultConfirmModalProps, + open: false, + onClose: () => {} + }; + }, [currentModal]); - const confirmModalProps: ConfirmModalProps = { - ...confirmModalPropsRef.current, - open, - onClose: onCloseConfirmModal - }; - - return { openConfirmModal, confirmModalProps }; + return useMemo(() => { + return { openConfirmModal, confirmModalProps }; + }, [openConfirmModal, confirmModalProps]); }; diff --git a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx index 5923096e6..a1f97530d 100644 --- a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx +++ b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx @@ -1,7 +1,7 @@ 'use client'; import { DashboardViewProps } from '../config'; -import React, { useState } from 'react'; +import React from 'react'; import { useMemoizedFn } from '@/hooks'; import { DashboardEditTitles } from './DashboardEditTitle'; import { DashboardContentController } from './DashboardContentController';