@greatapps/common 1.1.32 → 1.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/account/AccountModals.mjs +18 -0
- package/dist/components/account/AccountModals.mjs.map +1 -0
- package/dist/components/account/ConfigurationsMyAccountModal.mjs +26 -15
- package/dist/components/account/ConfigurationsMyAccountModal.mjs.map +1 -1
- package/dist/components/account/ConfirmDeleteAccountModal.mjs +45 -0
- package/dist/components/account/ConfirmDeleteAccountModal.mjs.map +1 -0
- package/dist/components/account/DeleteAccountModal.mjs +123 -0
- package/dist/components/account/DeleteAccountModal.mjs.map +1 -0
- package/dist/components/account/IsntPossibleDeleteAccountModal.mjs +42 -0
- package/dist/components/account/IsntPossibleDeleteAccountModal.mjs.map +1 -0
- package/dist/components/layouts/AppMobileNavBar.mjs +55 -0
- package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -0
- package/dist/components/layouts/AppNavBar.mjs +77 -0
- package/dist/components/layouts/AppNavBar.mjs.map +1 -0
- package/dist/components/modals/ModalManager.mjs +19 -0
- package/dist/components/modals/ModalManager.mjs.map +1 -0
- package/dist/components/modals/Modals.mjs +20 -0
- package/dist/components/modals/Modals.mjs.map +1 -0
- package/dist/index.mjs +14 -2
- package/dist/index.mjs.map +1 -1
- package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs +2 -2
- package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs.map +1 -1
- package/dist/store/useAccountModals.mjs +18 -0
- package/dist/store/useAccountModals.mjs.map +1 -0
- package/dist/store/useModalManager.mjs +75 -0
- package/dist/store/useModalManager.mjs.map +1 -0
- package/package.json +1 -1
- package/src/components/account/AccountModals.tsx +17 -0
- package/src/components/account/ConfigurationsMyAccountModal.tsx +29 -26
- package/src/components/account/ConfirmDeleteAccountModal.tsx +55 -0
- package/src/components/account/DeleteAccountModal.tsx +130 -0
- package/src/components/account/IsntPossibleDeleteAccountModal.tsx +49 -0
- package/src/components/layouts/AppMobileNavBar.tsx +73 -0
- package/src/components/layouts/AppNavBar.tsx +90 -0
- package/src/components/modals/ModalManager.tsx +29 -0
- package/src/components/modals/Modals.tsx +29 -0
- package/src/index.ts +13 -2
- package/src/modules/whitelabel/actions/find-whitelabel.action.ts +1 -1
- package/src/store/useAccountModals.ts +57 -0
- package/src/store/useModalManager.ts +104 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import Image from 'next/image';
|
|
5
|
+
import { ProfilePopover } from './ProfilePopover';
|
|
6
|
+
import { useAccountModals } from '../../store/useAccountModals';
|
|
7
|
+
import type { ProfileMenuItem } from './ProfilePopover';
|
|
8
|
+
|
|
9
|
+
export interface AppMobileNavBarProps {
|
|
10
|
+
appIconActive?: boolean;
|
|
11
|
+
/** Shows the colored indicator bar below the app icon */
|
|
12
|
+
appIconIndicator?: boolean;
|
|
13
|
+
/** Shows the gray indicator bar below the GreatApps logo */
|
|
14
|
+
logoIndicator?: boolean;
|
|
15
|
+
/** Extra slot rendered after the app icon (e.g. project selector) */
|
|
16
|
+
extraLeftSlot?: ReactNode;
|
|
17
|
+
/** Required: the right-side action element (toggle button, sheet button, etc.) */
|
|
18
|
+
rightActionSlot: ReactNode;
|
|
19
|
+
menuItems?: ProfileMenuItem[];
|
|
20
|
+
onCreditsClick?: () => void;
|
|
21
|
+
logoutOverlay?: ReactNode;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function AppMobileNavBar({
|
|
25
|
+
appIconActive = false,
|
|
26
|
+
appIconIndicator = false,
|
|
27
|
+
logoIndicator = false,
|
|
28
|
+
extraLeftSlot,
|
|
29
|
+
rightActionSlot,
|
|
30
|
+
menuItems = [],
|
|
31
|
+
onCreditsClick,
|
|
32
|
+
logoutOverlay,
|
|
33
|
+
}: AppMobileNavBarProps) {
|
|
34
|
+
const { openConfigurations } = useAccountModals();
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div className="fixed top-0 left-0 right-0 flex md:hidden items-center justify-between p-4 bg-white z-50 border-b border-gray-200">
|
|
38
|
+
<div className="flex items-center gap-1.5">
|
|
39
|
+
<div className="relative size-10 flex items-center justify-center">
|
|
40
|
+
<Image src="/icons/great-icon.svg" alt="GreatApps" width={28} height={28} />
|
|
41
|
+
{logoIndicator && (
|
|
42
|
+
<div className="absolute bottom-[-17px] left-1/2 -translate-x-1/2 w-5 h-[3px] bg-gray-950 rounded-t-xl" />
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
<div className="relative">
|
|
46
|
+
<div
|
|
47
|
+
className={`size-10 flex items-center justify-center rounded-lg transition-colors duration-300 ${
|
|
48
|
+
appIconActive ? 'bg-pages-300' : 'bg-pages-50'
|
|
49
|
+
}`}
|
|
50
|
+
>
|
|
51
|
+
<Image src="/icons/icon-navbar.svg" alt="GreatPages" width={24} height={24} />
|
|
52
|
+
</div>
|
|
53
|
+
{appIconIndicator && (
|
|
54
|
+
<div className="absolute -bottom-[17px] left-1/2 -translate-x-1/2 w-5 h-[3px] bg-pages-300 rounded-t-xl" />
|
|
55
|
+
)}
|
|
56
|
+
</div>
|
|
57
|
+
{extraLeftSlot}
|
|
58
|
+
</div>
|
|
59
|
+
<div className="flex items-center gap-1.5">
|
|
60
|
+
<ProfilePopover
|
|
61
|
+
side="bottom"
|
|
62
|
+
align="end"
|
|
63
|
+
contentClassName=""
|
|
64
|
+
onEditProfile={() => openConfigurations()}
|
|
65
|
+
onCreditsClick={onCreditsClick}
|
|
66
|
+
menuItems={menuItems}
|
|
67
|
+
logoutOverlay={logoutOverlay}
|
|
68
|
+
/>
|
|
69
|
+
{rightActionSlot}
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import Image from 'next/image';
|
|
5
|
+
import { useRouter } from 'next/navigation';
|
|
6
|
+
import { NavBar } from './NavBar';
|
|
7
|
+
import { ProfilePopover } from './ProfilePopover';
|
|
8
|
+
import { NotificationsPopover } from './NotificationsPopover';
|
|
9
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';
|
|
10
|
+
import { useAccountModals } from '../../store/useAccountModals';
|
|
11
|
+
import type { ProfileMenuItem } from './ProfilePopover';
|
|
12
|
+
import type { NotificationData } from './NotificationsPopover';
|
|
13
|
+
|
|
14
|
+
export interface AppNavBarProps {
|
|
15
|
+
onLogoClick?: () => void;
|
|
16
|
+
logoIndicatorClassName?: string;
|
|
17
|
+
appIconHref?: string;
|
|
18
|
+
appIconActive?: boolean;
|
|
19
|
+
/** Controls the left-side indicator bar on the app icon (opacity transition) */
|
|
20
|
+
appIconIndicator?: boolean;
|
|
21
|
+
showExpandButton?: boolean;
|
|
22
|
+
onExpandClick?: () => void;
|
|
23
|
+
menuItems?: ProfileMenuItem[];
|
|
24
|
+
onCreditsClick?: () => void;
|
|
25
|
+
notifications?: NotificationData[];
|
|
26
|
+
onNotificationsViewAll?: () => void;
|
|
27
|
+
logoutOverlay?: ReactNode;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function AppNavBar({
|
|
31
|
+
onLogoClick,
|
|
32
|
+
logoIndicatorClassName,
|
|
33
|
+
appIconHref = '/',
|
|
34
|
+
appIconActive = false,
|
|
35
|
+
appIconIndicator = false,
|
|
36
|
+
showExpandButton = false,
|
|
37
|
+
onExpandClick,
|
|
38
|
+
menuItems = [],
|
|
39
|
+
onCreditsClick,
|
|
40
|
+
notifications,
|
|
41
|
+
onNotificationsViewAll,
|
|
42
|
+
logoutOverlay,
|
|
43
|
+
}: AppNavBarProps) {
|
|
44
|
+
const router = useRouter();
|
|
45
|
+
const { openConfigurations } = useAccountModals();
|
|
46
|
+
|
|
47
|
+
const handleLogoClick = onLogoClick ?? (() => router.push('/'));
|
|
48
|
+
const handleAppIconClick = () => router.push(appIconHref);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<NavBar
|
|
52
|
+
onLogoClick={handleLogoClick}
|
|
53
|
+
logoIndicatorClassName={logoIndicatorClassName}
|
|
54
|
+
showExpandButton={showExpandButton}
|
|
55
|
+
onExpandClick={onExpandClick}
|
|
56
|
+
appIconSlot={
|
|
57
|
+
<div className="relative">
|
|
58
|
+
<Tooltip>
|
|
59
|
+
<TooltipTrigger asChild onClick={handleAppIconClick}>
|
|
60
|
+
<div
|
|
61
|
+
className={`size-10 flex items-center justify-center rounded-lg hover:bg-pages-100 cursor-pointer transition-colors duration-300 ${
|
|
62
|
+
appIconActive ? 'bg-pages-300' : 'bg-pages-50'
|
|
63
|
+
}`}
|
|
64
|
+
>
|
|
65
|
+
<Image src="/icons/icon-navbar.svg" alt="GreatPages" width={24} height={24} />
|
|
66
|
+
</div>
|
|
67
|
+
</TooltipTrigger>
|
|
68
|
+
<TooltipContent side="right">GreatPages</TooltipContent>
|
|
69
|
+
</Tooltip>
|
|
70
|
+
<div
|
|
71
|
+
className={`absolute -left-4 top-1/2 -translate-y-1/2 w-[3px] h-5 bg-pages-300 rounded-r-xl transition-opacity duration-300 ${
|
|
72
|
+
appIconIndicator ? 'opacity-100' : 'opacity-0'
|
|
73
|
+
}`}
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
}
|
|
77
|
+
>
|
|
78
|
+
<NotificationsPopover
|
|
79
|
+
notifications={notifications}
|
|
80
|
+
onViewAll={onNotificationsViewAll}
|
|
81
|
+
/>
|
|
82
|
+
<ProfilePopover
|
|
83
|
+
onEditProfile={() => openConfigurations()}
|
|
84
|
+
onCreditsClick={onCreditsClick}
|
|
85
|
+
menuItems={menuItems}
|
|
86
|
+
logoutOverlay={logoutOverlay}
|
|
87
|
+
/>
|
|
88
|
+
</NavBar>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ComponentType } from 'react';
|
|
4
|
+
import { useModalManager } from '../../store/useModalManager';
|
|
5
|
+
|
|
6
|
+
interface ModalManagerProps {
|
|
7
|
+
registry: Record<string, ComponentType>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function ModalManager({ registry }: ModalManagerProps) {
|
|
11
|
+
const { modalStack } = useModalManager();
|
|
12
|
+
|
|
13
|
+
if (modalStack.length === 0) return null;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
{modalStack.map((modal) => {
|
|
18
|
+
const ModalComponent = registry[modal.key];
|
|
19
|
+
|
|
20
|
+
if (!ModalComponent) {
|
|
21
|
+
console.warn(`Modal "${modal.key}" not found in registry`);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return <ModalComponent key={modal.key} />;
|
|
26
|
+
})}
|
|
27
|
+
</>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ComponentType, useEffect } from 'react';
|
|
4
|
+
import AccountModals from '../account/AccountModals';
|
|
5
|
+
import { ModalManager } from './ModalManager';
|
|
6
|
+
import { useAccountModals } from '../../store/useAccountModals';
|
|
7
|
+
import type { ComboboxOption } from '../ui/form/ComboboxField';
|
|
8
|
+
|
|
9
|
+
interface ModalsProps {
|
|
10
|
+
registry: Record<string, ComponentType>;
|
|
11
|
+
hasActiveSubscription?: boolean;
|
|
12
|
+
currencies?: ComboboxOption[];
|
|
13
|
+
onGoToSubscription?: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function Modals({ registry, hasActiveSubscription, currencies, onGoToSubscription }: ModalsProps) {
|
|
17
|
+
const { updateConfig } = useAccountModals();
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
updateConfig({ hasActiveSubscription, currencies, onGoToSubscription });
|
|
21
|
+
}, [hasActiveSubscription, currencies, onGoToSubscription, updateConfig]);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<AccountModals />
|
|
26
|
+
<ModalManager registry={registry} />
|
|
27
|
+
</>
|
|
28
|
+
);
|
|
29
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -38,6 +38,10 @@ export { parseSchema, parseResult } from './infra/utils/parser';
|
|
|
38
38
|
export { MainLayout, MainLayoutContent, MainLayoutSpacer, MainLayoutMain } from './components/layouts/MainLayout';
|
|
39
39
|
export { NavBar } from './components/layouts/NavBar';
|
|
40
40
|
export type { NavBarProps } from './components/layouts/NavBar';
|
|
41
|
+
export { AppNavBar } from './components/layouts/AppNavBar';
|
|
42
|
+
export type { AppNavBarProps } from './components/layouts/AppNavBar';
|
|
43
|
+
export { AppMobileNavBar } from './components/layouts/AppMobileNavBar';
|
|
44
|
+
export type { AppMobileNavBarProps } from './components/layouts/AppMobileNavBar';
|
|
41
45
|
export { SideBarNavigation } from './components/layouts/SideBarNavigation';
|
|
42
46
|
export { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';
|
|
43
47
|
export { NotificationItem } from './components/layouts/NotificationItem';
|
|
@@ -96,6 +100,8 @@ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './comp
|
|
|
96
100
|
|
|
97
101
|
// Store
|
|
98
102
|
export { useMdSidebarStore } from './store/useMdSidebarStore';
|
|
103
|
+
export { useModalManager } from './store/useModalManager';
|
|
104
|
+
export type { ModalData } from './store/useModalManager';
|
|
99
105
|
|
|
100
106
|
// Enums
|
|
101
107
|
export { AccountSectionType } from './enums/AccountSectionType';
|
|
@@ -145,8 +151,13 @@ export type {
|
|
|
145
151
|
ContactResetResult,
|
|
146
152
|
} from './modules/accounts/types';
|
|
147
153
|
|
|
148
|
-
|
|
149
|
-
export {
|
|
154
|
+
export { default as AccountModals } from './components/account/AccountModals';
|
|
155
|
+
export { useAccountModals } from './store/useAccountModals';
|
|
156
|
+
export type { AccountModalsConfig } from './store/useAccountModals';
|
|
157
|
+
|
|
158
|
+
export { ModalManager } from './components/modals/ModalManager';
|
|
159
|
+
export { Modals } from './components/modals/Modals';
|
|
160
|
+
|
|
150
161
|
export { default as TwoFactorAuthModal } from './components/account/TwoFactorAuthModal';
|
|
151
162
|
export { default as DisableTwoFactorAuthModal } from './components/account/DisableTwoFactorAuthModal';
|
|
152
163
|
export { default as ConfirmGlobalPreferencesModal } from './components/account/ConfirmGlobalPreferencesModal';
|
|
@@ -4,7 +4,7 @@ import { whitelabelService } from "../services/whitelabel.service";
|
|
|
4
4
|
import { ApiError } from "../../../infra/api/types";
|
|
5
5
|
import { cache } from "react";
|
|
6
6
|
|
|
7
|
-
export const
|
|
7
|
+
export const findWhitelabel = cache(async () => {
|
|
8
8
|
const headersList = await headers();
|
|
9
9
|
const host = headersList.get('host');
|
|
10
10
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { create } from 'zustand';
|
|
4
|
+
import type { ComboboxOption } from '../components/ui/form/ComboboxField';
|
|
5
|
+
import type { AccountSectionType } from '../enums/AccountSectionType';
|
|
6
|
+
|
|
7
|
+
type AccountModalType =
|
|
8
|
+
| 'configurations'
|
|
9
|
+
| 'deleteAccount'
|
|
10
|
+
| 'isntPossibleDelete'
|
|
11
|
+
| 'confirmDelete';
|
|
12
|
+
|
|
13
|
+
export interface AccountModalsConfig {
|
|
14
|
+
hasActiveSubscription?: boolean;
|
|
15
|
+
currencies?: ComboboxOption[];
|
|
16
|
+
onGoToSubscription?: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface AccountModalsState {
|
|
20
|
+
activeModal: AccountModalType | null;
|
|
21
|
+
config: AccountModalsConfig;
|
|
22
|
+
initialSection?: AccountSectionType;
|
|
23
|
+
pagesCount: number;
|
|
24
|
+
|
|
25
|
+
/** Called by <AccountModals> to keep app-level config in sync */
|
|
26
|
+
updateConfig: (config: AccountModalsConfig) => void;
|
|
27
|
+
|
|
28
|
+
openConfigurations: (initialSection?: AccountSectionType) => void;
|
|
29
|
+
openDeleteAccount: (pagesCount?: number) => void;
|
|
30
|
+
openIsntPossibleDelete: () => void;
|
|
31
|
+
openConfirmDelete: (pagesCount?: number) => void;
|
|
32
|
+
close: () => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const useAccountModals = create<AccountModalsState>((set) => ({
|
|
36
|
+
activeModal: null,
|
|
37
|
+
config: {},
|
|
38
|
+
initialSection: undefined,
|
|
39
|
+
pagesCount: 0,
|
|
40
|
+
|
|
41
|
+
updateConfig: (config) => set({ config }),
|
|
42
|
+
|
|
43
|
+
openConfigurations: (initialSection) =>
|
|
44
|
+
set({ activeModal: 'configurations', initialSection }),
|
|
45
|
+
|
|
46
|
+
openDeleteAccount: (pagesCount = 0) =>
|
|
47
|
+
set({ activeModal: 'deleteAccount', pagesCount }),
|
|
48
|
+
|
|
49
|
+
openIsntPossibleDelete: () =>
|
|
50
|
+
set({ activeModal: 'isntPossibleDelete' }),
|
|
51
|
+
|
|
52
|
+
openConfirmDelete: (pagesCount = 0) =>
|
|
53
|
+
set({ activeModal: 'confirmDelete', pagesCount }),
|
|
54
|
+
|
|
55
|
+
close: () =>
|
|
56
|
+
set({ activeModal: null, initialSection: undefined }),
|
|
57
|
+
}));
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { create } from 'zustand';
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
+
export type ModalData = Record<string, any>;
|
|
7
|
+
|
|
8
|
+
interface ModalStackItem {
|
|
9
|
+
key: string;
|
|
10
|
+
data: ModalData;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ModalState {
|
|
14
|
+
modalStack: ModalStackItem[];
|
|
15
|
+
activeModal: string | null;
|
|
16
|
+
modalData: ModalData;
|
|
17
|
+
openModal: (key: string, data?: ModalData) => void;
|
|
18
|
+
/** Closes the top modal in the stack */
|
|
19
|
+
closeModal: () => void;
|
|
20
|
+
/** Closes a specific modal by key */
|
|
21
|
+
closeModalByKey: (key: string) => void;
|
|
22
|
+
updateModalData: (data: ModalData) => void;
|
|
23
|
+
isModalOpen: (key: string) => boolean;
|
|
24
|
+
getModalData: (key: string) => ModalData;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const useModalManager = create<ModalState>((set, get) => ({
|
|
28
|
+
modalStack: [],
|
|
29
|
+
activeModal: null,
|
|
30
|
+
modalData: {},
|
|
31
|
+
|
|
32
|
+
openModal: (key, data = {}) => {
|
|
33
|
+
set((state) => {
|
|
34
|
+
const existingIndex = state.modalStack.findIndex((item) => item.key === key);
|
|
35
|
+
if (existingIndex !== -1) {
|
|
36
|
+
const newStack = [...state.modalStack];
|
|
37
|
+
newStack[existingIndex] = { key, data };
|
|
38
|
+
return {
|
|
39
|
+
modalStack: newStack,
|
|
40
|
+
activeModal: newStack[newStack.length - 1]?.key ?? null,
|
|
41
|
+
modalData: newStack[newStack.length - 1]?.data ?? {},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const newStack = [...state.modalStack, { key, data }];
|
|
46
|
+
return {
|
|
47
|
+
modalStack: newStack,
|
|
48
|
+
activeModal: key,
|
|
49
|
+
modalData: data,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
closeModal: () => {
|
|
55
|
+
set((state) => {
|
|
56
|
+
const newStack = state.modalStack.slice(0, -1);
|
|
57
|
+
const topModal = newStack[newStack.length - 1];
|
|
58
|
+
return {
|
|
59
|
+
modalStack: newStack,
|
|
60
|
+
activeModal: topModal?.key ?? null,
|
|
61
|
+
modalData: topModal?.data ?? {},
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
closeModalByKey: (key: string) => {
|
|
67
|
+
set((state) => {
|
|
68
|
+
const newStack = state.modalStack.filter((item) => item.key !== key);
|
|
69
|
+
const topModal = newStack[newStack.length - 1];
|
|
70
|
+
return {
|
|
71
|
+
modalStack: newStack,
|
|
72
|
+
activeModal: topModal?.key ?? null,
|
|
73
|
+
modalData: topModal?.data ?? {},
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
updateModalData: (data) => {
|
|
79
|
+
set((state) => {
|
|
80
|
+
if (state.modalStack.length === 0) return state;
|
|
81
|
+
|
|
82
|
+
const newStack = [...state.modalStack];
|
|
83
|
+
const lastIndex = newStack.length - 1;
|
|
84
|
+
newStack[lastIndex] = {
|
|
85
|
+
...newStack[lastIndex],
|
|
86
|
+
data: { ...newStack[lastIndex].data, ...data },
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
modalStack: newStack,
|
|
91
|
+
modalData: newStack[lastIndex].data,
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
isModalOpen: (key: string) => {
|
|
97
|
+
return get().modalStack.some((item) => item.key === key);
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
getModalData: (key: string) => {
|
|
101
|
+
const item = get().modalStack.find((item) => item.key === key);
|
|
102
|
+
return item?.data ?? {};
|
|
103
|
+
},
|
|
104
|
+
}));
|