From 5893de6e4de1d61e8f157800507bf863a940adae Mon Sep 17 00:00:00 2001 From: antoncoding Date: Thu, 13 Nov 2025 12:02:53 -0300 Subject: [PATCH 01/11] refactor: modal usages --- .../components/DepositToVaultModal.tsx | 2 +- .../components/VaultDepositProcessModal.tsx | 2 +- .../components/VaultInitializationModal.tsx | 16 +- .../components/deployment/DeploymentModal.tsx | 10 +- .../[marketid]/components/CampaignModal.tsx | 2 +- .../components/BlacklistConfirmationModal.tsx | 17 ++- .../components/MarketSettingsModal.tsx | 10 +- app/positions/components/RebalanceModal.tsx | 22 +-- .../components/RebalanceProcessModal.tsx | 2 +- .../components/agent/SetupAgentModal.tsx | 10 +- app/positions/components/onboarding/Modal.tsx | 12 +- docs/Styling.md | 139 ++++++++++++++++++ src/components/AgentSetupProcessModal.tsx | 2 +- .../Borrow/AddCollateralAndBorrow.tsx | 10 +- src/components/BorrowModal.tsx | 2 +- src/components/BorrowProcessModal.tsx | 2 +- src/components/RepayProcessModal.tsx | 2 +- src/components/RiskNotificationModal.tsx | 11 +- src/components/SupplyModalV2.tsx | 2 +- src/components/SupplyProcessModal.tsx | 2 +- src/components/WrapProcessModal.tsx | 2 +- src/components/common/MarketDetailsBlock.tsx | 2 +- .../common/MarketSelectionModal.tsx | 8 +- .../SuppliedAssetFilterCompactSwitch.tsx | 12 +- .../settings/BlacklistedMarketsModal.tsx | 17 +-- .../settings/TrustedVaultsModal.tsx | 13 +- 26 files changed, 237 insertions(+), 94 deletions(-) diff --git a/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx b/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx index f6a1ddaf..0e587bff 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx @@ -63,7 +63,7 @@ export function DepositToVaultModal({ return ( <>
diff --git a/app/autovault/[chainId]/[vaultAddress]/components/VaultDepositProcessModal.tsx b/app/autovault/[chainId]/[vaultAddress]/components/VaultDepositProcessModal.tsx index 08d955e3..74a7ced7 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/VaultDepositProcessModal.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/VaultDepositProcessModal.tsx @@ -83,7 +83,7 @@ export function VaultDepositProcessModal({ initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} - className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4" + className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4 font-zen" > - -
-

{stepTitle}

-

- {stepIndex < 3 - ? 'Complete these steps to activate your vault.' - : 'Optionally choose an agent now, or configure later in settings.'} -

-
+ + {stepTitle} + + {stepIndex < 3 + ? 'Complete these steps to activate your vault' + : 'Optionally choose an agent now, or configure later in settings'} + diff --git a/app/autovault/components/deployment/DeploymentModal.tsx b/app/autovault/components/deployment/DeploymentModal.tsx index 721547f4..7bf0441b 100644 --- a/app/autovault/components/deployment/DeploymentModal.tsx +++ b/app/autovault/components/deployment/DeploymentModal.tsx @@ -66,10 +66,12 @@ function DeploymentModalContent({ isOpen, onClose, existingVaults }: DeploymentM }} > - -
-

Deploy Autovault

-

Choose the token and network for your autovault

+ +
+ Deploy Autovault + + Choose the token and network for your autovault +
+ + ``` -**Key Standards:** -- **Header**: `px-10 pt-6` for spacing -- **Title**: `text-lg font-normal text-primary` - never use bold/semibold -- **Description**: `text-sm font-normal text-secondary` -- **Body**: `px-6 pb-6 pt-2` for consistent padding -- **Font**: Always include `font-zen` class -- **Gap**: `gap-5` between sections in body +**With Icon Support:** + +```tsx +import { TokenIcon } from '@/components/TokenIcon'; + + + + } + /> + {/* content */} + +``` + +**With Actions in Header:** + +```tsx + + Refresh + + } +/> +``` + +**Auto-Applied Standards:** +- **Spacing**: Automatically applied based on variant +- **Typography**: `font-zen` and text sizes handled automatically +- **Z-Index**: Managed through named layers (base, selection, settings, process) +- **No hardcoded styles**: Everything configured through props ### Compact Modal Pattern Use this pattern for filters, confirmations, and quick actions: ```tsx - - - - Modal Title - - Brief description - - - - - {/* Modal content */} - + + + + + {/* Modal content - tighter spacing applied automatically */} + + + + + + + +``` + +**Auto-Applied Differences from Standard:** +- **Smaller padding**: `px-6 pt-4` vs `px-10 pt-6` +- **Smaller title**: `text-base` vs `text-lg` +- **Tighter spacing**: `gap-4` vs `gap-5` + +### Z-Index Management + +Our Modal component manages z-index automatically through named layers. This prevents conflicts when multiple modals are open: + +```tsx +// Z-Index Layers (from lowest to highest): +zIndex="base" // z-50 - Standard modals (Supply, Borrow, Campaign) +zIndex="process" // z-1100 - Process/transaction modals +zIndex="selection" // z-2200 - Market/item selection modals +zIndex="settings" // z-2300 - Settings modals (HIGHEST - always on top) +``` + +**Usage Example:** - - {/* Footer buttons */} - - +```tsx +// Settings modal (should be on top of everything) + + + {/* ... */} + + +// Market selection modal (opened from settings) + + + {/* ... */} + + +// Base modal (standard use case) + + + {/* ... */} ``` -**Key Differences from Standard:** -- **Header**: `px-6 pt-4` (smaller padding) -- **Title**: `text-base` (smaller size) -- **Body**: `px-6 pb-4 pt-2` and `gap-4` (tighter spacing) +**Custom Z-Index (if needed):** + +```tsx + + {/* Very rare - only use if you have a specific need */} + +``` ### Typography Rules -**IMPORTANT**: Never use bold or semibold font weights in modal headers. +Typography is automatically handled by our Modal components. You don't need to specify font weights or sizes manually - just use the title/description props. + +**IMPORTANT**: Never manually add bold or semibold font weights in modal content. ```tsx -// ✅ Correct -Settings +// ✅ Correct - let the component handle typography + -// ❌ Incorrect -Settings -Settings +// ❌ Incorrect - don't override with manual styles +Settings} /> ``` Use color and size to create hierarchy, not font weight: - **Primary text**: `text-primary` - **Secondary text**: `text-secondary` -- **Title size**: `text-lg` (standard) or `text-base` (compact) -- **Description size**: `text-sm` +- **Title size**: Automatically set based on variant +- **Description size**: Automatically set to `text-sm` ### Section Headers in Modal Body diff --git a/src/components/SupplyModalV2.tsx b/src/components/SupplyModalV2.tsx index c8e3a9fb..a2e17fa9 100644 --- a/src/components/SupplyModalV2.tsx +++ b/src/components/SupplyModalV2.tsx @@ -6,7 +6,6 @@ import { MarketDetailsBlock } from './common/MarketDetailsBlock'; import { SupplyModalContent } from './SupplyModalContent'; import { TokenIcon } from './TokenIcon'; import { WithdrawModalContent } from './WithdrawModalContent'; - type SupplyModalV2Props = { market: Market; position?: MarketPosition | null; diff --git a/src/components/common/Modal/Modal.tsx b/src/components/common/Modal/Modal.tsx new file mode 100644 index 00000000..dcb555a0 --- /dev/null +++ b/src/components/common/Modal/Modal.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { Modal as HeroModal, ModalContent } from '@heroui/react'; + +export type ModalVariant = 'standard' | 'compact' | 'custom'; +export type ModalZIndex = 'base' | 'process' | 'selection' | 'settings' | 'custom'; + +type ModalProps = { + isOpen: boolean; + onClose: () => void; + onOpenChange?: () => void; + children: React.ReactNode; + variant?: ModalVariant; + zIndex?: ModalZIndex; + customZIndex?: number; + size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | 'full'; + isDismissable?: boolean; + hideCloseButton?: boolean; + scrollBehavior?: 'inside' | 'outside' | 'normal'; + backdrop?: 'transparent' | 'opaque' | 'blur'; + className?: string; +}; + +const Z_INDEX_MAP: Record = { + base: { wrapper: 'z-50', backdrop: 'z-[45]' }, + process: { wrapper: 'z-[1100]', backdrop: 'z-[1090]' }, + selection: { wrapper: 'z-[2200]', backdrop: 'z-[2190]' }, + settings: { wrapper: 'z-[2300]', backdrop: 'z-[2290]' }, + custom: { wrapper: '', backdrop: '' }, +}; + +export function Modal({ + isOpen, + onClose, + onOpenChange, + children, + variant = 'standard', + zIndex = 'base', + customZIndex, + size = 'xl', + isDismissable = true, + hideCloseButton = false, + scrollBehavior = 'inside', + backdrop = 'blur', + className = '', +}: ModalProps) { + const zIndexClasses = customZIndex + ? { wrapper: `z-[${customZIndex}]`, backdrop: `z-[${customZIndex - 10}]` } + : Z_INDEX_MAP[zIndex]; + + return ( + + + {(closeModal) => ( + <> + {typeof children === 'function' ? children(closeModal) : children} + + )} + + + ); +} diff --git a/src/components/common/Modal/ModalBody.tsx b/src/components/common/Modal/ModalBody.tsx new file mode 100644 index 00000000..6f91157d --- /dev/null +++ b/src/components/common/Modal/ModalBody.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { ModalBody as HeroModalBody } from '@heroui/react'; + +export type ModalBodyVariant = 'standard' | 'compact'; + +type ModalBodyProps = { + children: React.ReactNode; + variant?: ModalBodyVariant; + className?: string; +}; + +export function ModalBody({ + children, + variant = 'standard', + className = '', +}: ModalBodyProps) { + const isStandard = variant === 'standard'; + const paddingClass = isStandard ? 'px-6 pb-6 pt-2' : 'px-6 pb-4 pt-2'; + const gapClass = isStandard ? 'gap-5' : 'gap-4'; + + return ( + + {children} + + ); +} diff --git a/src/components/common/Modal/ModalFooter.tsx b/src/components/common/Modal/ModalFooter.tsx new file mode 100644 index 00000000..5eb6a309 --- /dev/null +++ b/src/components/common/Modal/ModalFooter.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { ModalFooter as HeroModalFooter } from '@heroui/react'; + +type ModalFooterProps = { + children: React.ReactNode; + className?: string; +}; + +export function ModalFooter({ children, className = '' }: ModalFooterProps) { + return ( + + {children} + + ); +} diff --git a/src/components/common/Modal/ModalHeader.tsx b/src/components/common/Modal/ModalHeader.tsx new file mode 100644 index 00000000..f1f5206c --- /dev/null +++ b/src/components/common/Modal/ModalHeader.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { ModalHeader as HeroModalHeader } from '@heroui/react'; + +export type ModalHeaderVariant = 'standard' | 'compact'; + +type ModalHeaderProps = { + title: string | React.ReactNode; + description?: string | React.ReactNode; + icon?: React.ReactNode; + variant?: ModalHeaderVariant; + children?: React.ReactNode; + className?: string; + actions?: React.ReactNode; +}; + +export function ModalHeader({ + title, + description, + icon, + variant = 'standard', + children, + className = '', + actions, +}: ModalHeaderProps) { + const isStandard = variant === 'standard'; + const paddingClass = isStandard ? 'px-10 pt-6' : 'px-6 pt-4'; + const titleSizeClass = isStandard ? 'text-lg' : 'text-base'; + + // If children are provided, use them directly (for custom layouts) + if (children) { + return ( + + {children} + + ); + } + + // Standard layout with title, description, and optional icon + return ( + +
+
+ {icon &&
{icon}
} + + {title} + +
+ {description && ( + + {description} + + )} +
+ {actions &&
{actions}
} +
+ ); +} diff --git a/src/components/common/Modal/index.ts b/src/components/common/Modal/index.ts new file mode 100644 index 00000000..6b77694b --- /dev/null +++ b/src/components/common/Modal/index.ts @@ -0,0 +1,10 @@ +export { Modal } from './Modal'; +export type { ModalVariant, ModalZIndex } from './Modal'; + +export { ModalHeader } from './ModalHeader'; +export type { ModalHeaderVariant } from './ModalHeader'; + +export { ModalBody } from './ModalBody'; +export type { ModalBodyVariant } from './ModalBody'; + +export { ModalFooter } from './ModalFooter'; From 558be9c1a98df91f5c606607514b9509d0509449 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Thu, 13 Nov 2025 14:51:15 -0300 Subject: [PATCH 03/11] misc: apply modal changes --- .../components/DepositToVaultModal.tsx | 157 ++++++++---------- .../components/VaultDepositProcessModal.tsx | 100 +++++------ .../components/VaultInitializationModal.tsx | 56 +++---- .../components/VaultSettingsModal.tsx | 153 ++++++----------- .../components/deployment/DeploymentModal.tsx | 43 ++--- .../[marketid]/components/CampaignModal.tsx | 46 ++--- .../components/BlacklistConfirmationModal.tsx | 51 +++--- .../components/MarketSettingsModal.tsx | 51 +++--- app/positions/components/PositionsContent.tsx | 2 +- app/positions/components/RebalanceModal.tsx | 103 ++++++------ .../components/RebalanceProcessModal.tsx | 80 +++++---- .../components/agent/SetupAgentModal.tsx | 66 ++------ .../components/onboarding/OnboardingModal.tsx | 47 ++---- src/components/AgentSetupProcessModal.tsx | 99 +++++------ src/components/BorrowModal.tsx | 156 ++++++++--------- src/components/BorrowProcessModal.tsx | 107 +++++------- src/components/RepayProcessModal.tsx | 117 +++++-------- src/components/RiskNotificationModal.tsx | 56 +++---- src/components/SupplyModalV2.tsx | 151 ++++++++--------- src/components/SupplyProcessModal.tsx | 127 ++++++-------- src/components/WrapProcessModal.tsx | 105 +++++------- .../common/MarketSelectionModal.tsx | 38 ++--- src/components/common/Modal/Modal.tsx | 37 +++-- src/components/common/Modal/ModalHeader.tsx | 76 +++++++-- src/components/common/Modal/index.ts | 2 +- .../SuppliedAssetFilterCompactSwitch.tsx | 54 +++--- .../settings/BlacklistedMarketsModal.tsx | 45 +++-- .../settings/TrustedVaultsModal.tsx | 54 +++--- 28 files changed, 948 insertions(+), 1231 deletions(-) diff --git a/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx b/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx index 0e587bff..fa5cb9b1 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx @@ -1,8 +1,8 @@ import React from 'react'; -import { Cross1Icon } from '@radix-ui/react-icons'; import { Address } from 'viem'; import { useAccount } from 'wagmi'; import { Button } from '@/components/common'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import Input from '@/components/Input/Input'; import AccountConnect from '@/components/layout/header/AccountConnect'; import { TokenIcon } from '@/components/TokenIcon'; @@ -62,98 +62,79 @@ export function DepositToVaultModal({ return ( <> -
-
-
- - -
-
-
- - Deposit {assetSymbol} -
- Deposit to {vaultName} -
+ + + } + onClose={onClose} + /> + + {!isConnected ? ( +
+
+ ) : ( +
+
+
+ Deposit amount +

+ Balance: {formatBalance(tokenBalance ?? BigInt(0), assetDecimals)} {assetSymbol} +

+
- {!isConnected ? ( -
- -
- ) : ( - <> - {/* Deposit Input Section */} -
-
-
- Deposit amount -

- Balance: {formatBalance(tokenBalance ?? BigInt(0), assetDecimals)}{' '} - {assetSymbol} +

+
+ + {inputError && ( +

+ {inputError}

-
- -
-
- - {inputError && ( -

- {inputError} -

- )} -
- - {!permit2Authorized || (!usePermit2Setting && !isApproved) ? ( - - ) : ( - - )} -
+ )}
+ + {!permit2Authorized || (!usePermit2Setting && !isApproved) ? ( + + ) : ( + + )}
- - )} -
-
-
+
+
+ )} + + {showProcessModal && ( - - - - -
-

Deposit {assetSymbol}

-

- Depositing {formattedAmount} {assetSymbol} to {vaultName} -

- - {/* Steps */} -
- {steps.map((step) => { - const status = getStepStatus(step.key); - return ( -
-
- {status === 'done' ? ( - - ) : status === 'current' ? ( - - ) : ( - - )} -
-
-
{step.label}
-
{step.detail}
-
-
- ); - })} + + } + onClose={onClose} + /> + + {steps.map((step) => { + const status = getStepStatus(step.key); + return ( +
+
+ {status === 'done' ? ( + + ) : status === 'current' ? ( + + ) : ( + + )} +
+
+
{step.label}
+
{step.detail}
+
-
- - - + ); + })} + + ); } diff --git a/app/autovault/[chainId]/[vaultAddress]/components/VaultInitializationModal.tsx b/app/autovault/[chainId]/[vaultAddress]/components/VaultInitializationModal.tsx index aa85fd40..98e4c555 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/VaultInitializationModal.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/VaultInitializationModal.tsx @@ -1,9 +1,10 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; -import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader } from '@heroui/react'; +import { FiZap } from 'react-icons/fi'; import { Address, zeroAddress } from 'viem'; import { Button } from '@/components/common'; import { AddressDisplay } from '@/components/common/AddressDisplay'; import { AllocatorCard } from '@/components/common/AllocatorCard'; +import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; import { Spinner } from '@/components/common/Spinner'; import { useDeployMorphoMarketV1Adapter } from '@/hooks/useDeployMorphoMarketV1Adapter'; import { useVaultV2 } from '@/hooks/useVaultV2'; @@ -397,22 +398,19 @@ export function VaultInitializationModal({ onClose={onClose} size="lg" scrollBehavior="inside" - classNames={{ - base: 'bg-background dark:border border-gray-700 font-zen', - body: 'py-6', - }} + className="bg-background dark:border border-gray-700" > - - - {stepTitle} - - {stepIndex < 3 - ? 'Complete these steps to activate your vault' - : 'Optionally choose an agent now, or configure later in settings'} - - - - + } + onClose={onClose} + /> + {currentStep === 'deploy' && ( )} - - - - {showBackButton && ( - - )} - {renderCta()} - -
- -
-
+ + + {showBackButton && ( + + )} + {renderCta()} + +
+ +
); } diff --git a/app/autovault/[chainId]/[vaultAddress]/components/VaultSettingsModal.tsx b/app/autovault/[chainId]/[vaultAddress]/components/VaultSettingsModal.tsx index 0da90183..3d068f84 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/VaultSettingsModal.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/VaultSettingsModal.tsx @@ -1,8 +1,8 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { ReloadIcon } from '@radix-ui/react-icons'; -import { createPortal } from 'react-dom'; -import { LuX } from 'react-icons/lu'; +import { FiSettings } from 'react-icons/fi'; import { Address } from 'viem'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { VaultV2Cap } from '@/data-sources/morpho-api/v2-vaults'; import { CapData } from '@/hooks/useVaultV2Data'; import { SupportedNetworks } from '@/utils/networks'; @@ -68,52 +68,13 @@ export function VaultSettingsModal({ isRefreshing = false, }: VaultSettingsModalProps) { const [activeTab, setActiveTab] = useState(initialTab); - const [mounted, setMounted] = useState(false); - const wasOpenRef = useRef(false); - // Reset to initial tab when modal opens useEffect(() => { - const wasOpen = wasOpenRef.current; - - if (isOpen && !wasOpen) { + if (isOpen) { setActiveTab(initialTab); } - - wasOpenRef.current = isOpen; }, [initialTab, isOpen]); - // Handle mounting - useEffect(() => { - setMounted(true); - }, []); - - // Prevent body scroll when modal is open - useEffect(() => { - if (!isOpen) return; - const originalOverflow = document.body.style.overflow; - document.body.style.overflow = 'hidden'; - return () => { - document.body.style.overflow = originalOverflow; - }; - }, [isOpen]); - - // Handle ESC key - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if (event.key === 'Escape' && isOpen) { - onClose(); - } - }; - - if (isOpen) { - window.addEventListener('keydown', handleKeyDown); - } - - return () => { - window.removeEventListener('keydown', handleKeyDown); - }; - }, [isOpen, onClose]); - const handleTabChange = useCallback((tab: SettingsTab) => { setActiveTab(tab); }, []); @@ -163,75 +124,67 @@ export function VaultSettingsModal({ } }; - if (!mounted || !isOpen) { + if (!isOpen) { return null; } - return createPortal( -
-
event.stopPropagation()} - > -
- {/* Header */} -
-

Vault Settings

-
- {onRefresh && ( + } + onClose={onClose} + auxiliaryAction={ + onRefresh + ? { + icon: ( + + ), + onClick: () => { + if (!isRefreshing) { + onRefresh(); + } + }, + ariaLabel: 'Refresh vault data', + } + : undefined + } + /> + +
+
+
+ {TABS.map((tab) => ( - )} - + ))}
- {/* Content */} -
- {/* Sidebar */} - - - {/* Tab Content */} -
-
{renderActiveTab()}
-
+
+
{renderActiveTab()}
-
-
, - document.body, + + ); } diff --git a/app/autovault/components/deployment/DeploymentModal.tsx b/app/autovault/components/deployment/DeploymentModal.tsx index 7bf0441b..ef6e68ca 100644 --- a/app/autovault/components/deployment/DeploymentModal.tsx +++ b/app/autovault/components/deployment/DeploymentModal.tsx @@ -1,7 +1,8 @@ import { useEffect, useMemo, useState } from 'react'; -import { Checkbox, Modal, ModalContent, ModalHeader } from '@heroui/react'; -import { RxCross2 } from 'react-icons/rx'; +import { Checkbox } from '@heroui/react'; +import { FaCube } from 'react-icons/fa'; import { Button } from '@/components/common'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { Spinner } from '@/components/common/Spinner'; import { useMarkets } from '@/contexts/MarketsContext'; import { UserVaultV2 } from '@/data-sources/subgraph/v2-vaults'; @@ -57,28 +58,18 @@ function DeploymentModalContent({ isOpen, onClose, existingVaults }: DeploymentM onClose={onClose} size="2xl" scrollBehavior="inside" - classNames={{ - base: 'bg-background dark:border border-gray-700', - body: 'py-6', - closeButton: 'hidden', - wrapper: 'z-50', - backdrop: 'z-[45] bg-black/50', - }} + backdrop="blur" + className="bg-background dark:border border-gray-700" > - - -
- Deploy Autovault - - Choose the token and network for your autovault - -
- -
- -
+ } + onClose={onClose} + /> + + +
@@ -92,7 +83,7 @@ function DeploymentModalContent({ isOpen, onClose, existingVaults }: DeploymentM
{selectedTokenAndNetwork && ( -
+
You can configure the vault to have caps, automation agents and more after you deploy the vault.
)} @@ -102,7 +93,7 @@ function DeploymentModalContent({ isOpen, onClose, existingVaults }: DeploymentM @@ -145,7 +136,7 @@ function DeploymentModalContent({ isOpen, onClose, existingVaults }: DeploymentM
- + ); } diff --git a/app/market/[chainId]/[marketid]/components/CampaignModal.tsx b/app/market/[chainId]/[marketid]/components/CampaignModal.tsx index 477aa632..85c108bb 100644 --- a/app/market/[chainId]/[marketid]/components/CampaignModal.tsx +++ b/app/market/[chainId]/[marketid]/components/CampaignModal.tsx @@ -1,9 +1,10 @@ 'use client'; -import { Cross1Icon, ExternalLinkIcon } from '@radix-ui/react-icons'; +import { ExternalLinkIcon } from '@radix-ui/react-icons'; import Image from 'next/image'; import Link from 'next/link'; import { Button } from '@/components/common/Button'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { getMerklCampaignURL } from '@/utils/external'; import { SimplifiedCampaign } from '@/utils/merklTypes'; @@ -81,35 +82,18 @@ export function CampaignModal({ isOpen, onClose, campaigns }: CampaignModalProps if (!isOpen) return null; return ( -
-
-
- - -
-
-
- Active Reward Campaigns -
-
-
- -
- {campaigns.map((campaign) => ( - - ))} -
-
-
-
+ + } + onClose={onClose} + /> + + {campaigns.map((campaign) => ( + + ))} + + ); } diff --git a/app/markets/components/BlacklistConfirmationModal.tsx b/app/markets/components/BlacklistConfirmationModal.tsx index 4be6e62a..59823abc 100644 --- a/app/markets/components/BlacklistConfirmationModal.tsx +++ b/app/markets/components/BlacklistConfirmationModal.tsx @@ -1,9 +1,9 @@ 'use client'; import React from 'react'; -import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; import { IoWarningOutline } from 'react-icons/io5'; import { Button } from '@/components/common'; +import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; import { MarketIdentity } from '@/components/MarketIdentity'; import { Market } from '@/utils/types'; @@ -30,26 +30,18 @@ export function BlacklistConfirmationModal({ return ( - - -
- - Blacklist Market -
- - Confirm removal of this market from your view - -
- + } + title="Blacklist Market" + description="Confirm removal of this market from your view" + className="border-b border-primary/10" + onClose={onClose} + /> +
@@ -64,17 +56,16 @@ export function BlacklistConfirmationModal({ blacklisted markets later in Settings.

-
- - - - - - +
+
+ + + +
); } diff --git a/app/markets/components/MarketSettingsModal.tsx b/app/markets/components/MarketSettingsModal.tsx index c8f19073..f0caafe3 100644 --- a/app/markets/components/MarketSettingsModal.tsx +++ b/app/markets/components/MarketSettingsModal.tsx @@ -1,15 +1,9 @@ import React from 'react'; -import { - Modal, - ModalContent, - ModalHeader, - ModalBody, - ModalFooter, - Input, - Divider, -} from '@heroui/react'; +import { Input, Divider } from '@heroui/react'; +import { FiSliders } from 'react-icons/fi'; import { Button } from '@/components/common'; import { IconSwitch } from '@/components/common/IconSwitch'; +import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; import { TrustedByCell } from '@/components/vaults/TrustedVaultBadges'; import { defaultTrustedVaults, type TrustedVault } from '@/constants/vaults/known_vaults'; import { useMarkets } from '@/hooks/useMarkets'; @@ -92,20 +86,20 @@ export default function MarketSettingsModal({ - - {(onClose) => ( - <> - - Market Preferences - - Fine-tune filter thresholds, pagination, and column visibility - - - + {(onClose) => ( + <> + } + onClose={onClose} + /> +

Filter Thresholds

@@ -263,15 +257,14 @@ export default function MarketSettingsModal({

-
- - - - - )} - + + + + + + )} ); } diff --git a/app/positions/components/PositionsContent.tsx b/app/positions/components/PositionsContent.tsx index 2d742fef..52a2cd4a 100644 --- a/app/positions/components/PositionsContent.tsx +++ b/app/positions/components/PositionsContent.tsx @@ -18,7 +18,7 @@ import { SupplyModalV2 } from '@/components/SupplyModalV2'; import { useMarkets } from '@/hooks/useMarkets'; import useUserPositionsSummaryData from '@/hooks/useUserPositionsSummaryData'; import { MarketPosition } from '@/utils/types'; -import { OnboardingModal } from './onboarding/Modal'; +import { OnboardingModal } from './onboarding/OnboardingModal'; import { PositionsSummaryTable } from './PositionsSummaryTable'; export default function Positions() { diff --git a/app/positions/components/RebalanceModal.tsx b/app/positions/components/RebalanceModal.tsx index 0bf1e01b..9fe42376 100644 --- a/app/positions/components/RebalanceModal.tsx +++ b/app/positions/components/RebalanceModal.tsx @@ -1,10 +1,11 @@ import React, { useState, useMemo, useCallback } from 'react'; -import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@heroui/react'; import { ReloadIcon } from '@radix-ui/react-icons'; import { parseUnits, formatUnits } from 'viem'; import { Button } from '@/components/common'; import { MarketSelectionModal } from '@/components/common/MarketSelectionModal'; +import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; import { Spinner } from '@/components/common/Spinner'; +import { TokenIcon } from '@/components/TokenIcon'; import { useLocalStorage } from '@/hooks/useLocalStorage'; import { useMarketNetwork } from '@/hooks/useMarketNetwork'; import { useMarkets } from '@/hooks/useMarkets'; @@ -283,36 +284,43 @@ export function RebalanceModal({ onClose={onClose} isDismissable={false} size="4xl" - classNames={{ - base: 'p-4 rounded-sm', - wrapper: 'z-[2000]', - backdrop: 'z-[1990]', - }} + customZIndex={2000} > - - -
-
- - Rebalance {groupedPosition.loanAsset ?? 'Unknown'} Position - - {isRefetching && } -
- - Click on your existing position to rebalance {groupedPosition.loanAsset} to a new market. You can batch actions. + + + Rebalance {groupedPosition.loanAsset ?? 'Unknown'} Position + {isRefetching && }
- -
- + } + description={`Click on your existing position to rebalance ${ + groupedPosition.loanAssetSymbol ?? groupedPosition.loanAsset ?? 'this token' + } to a new market. You can batch actions.`} + mainIcon={ + + } + onClose={onClose} + auxiliaryAction={{ + icon: ( + + ), + onClick: () => { + if (!isRefetching) { + handleManualRefresh(); + } + }, + ariaLabel: 'Refresh position data', + }} + /> + - - - - - -
+ + + + + {showProcessModal && ( -
- - -
- Rebalancing {tokenSymbol} Positions -
- -
- {steps - .filter((step) => step.key !== 'idle') - .map((step, index) => ( -
-
- {getStepStatus(step.key as RebalanceStepType) === 'done' && ( - - )} - {getStepStatus(step.key as RebalanceStepType) === 'current' && ( -
- )} - {getStepStatus(step.key as RebalanceStepType) === 'undone' && ( + + } + onClose={onClose} + /> + + {steps + .filter((step) => step.key !== 'idle') + .map((step) => { + const status = getStepStatus(step.key as RebalanceStepType); + return ( +
+
+ {status === 'done' ? ( + + ) : status === 'current' ? ( +
+ ) : ( )}
-
-
{step.label}
- {currentStep === step.key && step.detail && ( -
- {step.detail} -
+
+
{step.label}
+ {status === 'current' && step.detail && ( +
{step.detail}
)}
- {index < steps.length - 2 &&
}
- ))} -
-
-
+ ); + })} +
+
); } diff --git a/app/positions/components/agent/SetupAgentModal.tsx b/app/positions/components/agent/SetupAgentModal.tsx index f9acffbe..8347889b 100644 --- a/app/positions/components/agent/SetupAgentModal.tsx +++ b/app/positions/components/agent/SetupAgentModal.tsx @@ -1,7 +1,8 @@ import { useState } from 'react'; -import { Modal, ModalContent, ModalHeader } from '@heroui/react'; import { motion, AnimatePresence } from 'framer-motion'; +import { FaRobot } from 'react-icons/fa'; import { Address } from 'viem'; +import { Modal, ModalBody, ModalFooter, ModalHeader } from '@/components/common/Modal'; import { useMarkets } from '@/contexts/MarketsContext'; import { MarketCap } from '@/hooks/useAuthorizeAgent'; import useUserPositions from '@/hooks/useUserPositions'; @@ -136,44 +137,17 @@ export function SetupAgentModal({ isOpen={isOpen} onClose={handleClose} size="2xl" - classNames={{ - base: 'bg-background text-foreground dark:border border-gray-700', - header: 'border-b border-divider', - body: 'p-4', - closeButton: 'hover:bg-default-100', - }} - motionProps={{ - variants: { - enter: { - y: 0, - opacity: 1, - transition: { - duration: 0.3, - ease: 'easeOut', - }, - }, - exit: { - y: -20, - opacity: 0, - transition: { - duration: 0.2, - ease: 'easeIn', - }, - }, - }, - }} - closeButton={false} + className="bg-background text-foreground dark:border border-gray-700" > - - -
- {SETUP_STEPS[currentStepIndex].title} - - {SETUP_STEPS[currentStepIndex].description} - -
-
- + } + onClose={handleClose} + /> + +
- {/* Step Content */} {currentStep === SetupStep.Main && !hasSetupAgent && ( )} {currentStep === SetupStep.Main && hasSetupAgent && ( - + )} {currentStep === SetupStep.Setup && (
+
- {/* Footer with Step Indicator */} -
- -
-
+ + + ); } diff --git a/app/positions/components/onboarding/OnboardingModal.tsx b/app/positions/components/onboarding/OnboardingModal.tsx index b07b0066..64c4f67b 100644 --- a/app/positions/components/onboarding/OnboardingModal.tsx +++ b/app/positions/components/onboarding/OnboardingModal.tsx @@ -1,6 +1,6 @@ -import { Modal, ModalContent, ModalHeader, Button } from '@heroui/react'; import { motion, AnimatePresence } from 'framer-motion'; -import { RxCross2 } from 'react-icons/rx'; +import { FaCompass } from 'react-icons/fa'; +import { Modal, ModalBody, ModalFooter, ModalHeader } from '@/components/common/Modal'; import { AssetSelection } from './AssetSelection'; import { MarketSelectionOnboarding } from './MarketSelectionOnboarding'; import { useOnboarding } from './OnboardingContext'; @@ -54,32 +54,18 @@ export function OnboardingModal({ isOpen, onClose }: { isOpen: boolean; onClose: onClose={onClose} size="3xl" scrollBehavior="inside" - classNames={{ - base: 'bg-surface', - body: 'py-6', - closeButton: 'hidden', - wrapper: 'z-50', // Higher than header - backdrop: 'z-[45] bg-black/50', // Between header and modal - }} + backdrop="blur" + className="bg-surface" > - - {/* Header */} - -
- - {ONBOARDING_STEPS[currentStepIndex].title} - - - {ONBOARDING_STEPS[currentStepIndex].description} - -
- -
+ } + onClose={onClose} + /> - {/* Content */} -
+ +
+
- {/* Footer with Step Indicator */} -
- -
- + + + ); } diff --git a/src/components/AgentSetupProcessModal.tsx b/src/components/AgentSetupProcessModal.tsx index c2ed13d3..722b7b07 100644 --- a/src/components/AgentSetupProcessModal.tsx +++ b/src/components/AgentSetupProcessModal.tsx @@ -1,7 +1,6 @@ import React from 'react'; -import { Cross1Icon } from '@radix-ui/react-icons'; -import { motion, AnimatePresence } from 'framer-motion'; -import { FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { FaCheckCircle, FaCircle, FaRobot } from 'react-icons/fa'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { AuthorizeAgentStep } from '@/hooks/useAuthorizeAgent'; type AgentSetupModalProps = { @@ -41,64 +40,42 @@ export function AgentSetupProcessModal({ }; return ( - - - - - -
-

Setup Monarch Agent

-

Setup Rebalance market caps

- - {/* Steps */} -
- {steps.map((step) => { - const status = getStepStatus(step.key); - return ( -
-
- {status === 'done' ? ( - - ) : status === 'current' ? ( - - ) : ( - - )} -
-
-
{step.label}
-
{step.detail}
-
-
- ); - })} + + } + onClose={onClose} + /> + + {steps.map((step) => { + const status = getStepStatus(step.key); + return ( +
+
+ {status === 'done' ? ( + + ) : status === 'current' ? ( + + ) : ( + + )} +
+
+
{step.label}
+
{step.detail}
+
-
- - - + ); + })} + + ); } diff --git a/src/components/BorrowModal.tsx b/src/components/BorrowModal.tsx index 5656f979..acf317e7 100644 --- a/src/components/BorrowModal.tsx +++ b/src/components/BorrowModal.tsx @@ -1,7 +1,8 @@ import React, { useState } from 'react'; -import { Cross1Icon } from '@radix-ui/react-icons'; import { FaArrowRightArrowLeft } from 'react-icons/fa6'; import { useAccount, useBalance } from 'wagmi'; +import { Button } from '@/components/common/Button'; +import { Modal, ModalHeader, ModalBody } from '@/components/common/Modal'; import { Market, MarketPosition } from '@/utils/types'; import { AddCollateralAndBorrow } from './Borrow/AddCollateralAndBorrow'; import { WithdrawCollateralAndRepay } from './Borrow/WithdrawCollateralAndRepay'; @@ -49,90 +50,77 @@ export function BorrowModal({ position && (BigInt(position.state.borrowAssets) > 0n || BigInt(position.state.collateral) > 0n); - return ( -
-
-
- - -
-
-
-
- -
- -
-
-
-
- {market.loanAsset.symbol} - / {market.collateralAsset.symbol} -
- - {mode === 'borrow' ? 'Borrow against collateral' : 'Repay borrowed assets'} - -
-
-
- - {hasPosition && ( - - )} -
- - {mode === 'borrow' ? ( - - ) : ( - - )} -
+ const mainIcon = ( +
+ +
+
); + + return ( + + + {market.loanAsset.symbol} + / {market.collateralAsset.symbol} +
+ } + description={mode === 'borrow' ? 'Borrow against collateral' : 'Repay borrowed assets'} + actions={ + hasPosition ? ( + + ) : undefined + } + /> + + {mode === 'borrow' ? ( + + ) : ( + + )} + + + ); } diff --git a/src/components/BorrowProcessModal.tsx b/src/components/BorrowProcessModal.tsx index 2fc939dd..3568fb54 100644 --- a/src/components/BorrowProcessModal.tsx +++ b/src/components/BorrowProcessModal.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; -import { Cross1Icon } from '@radix-ui/react-icons'; -import { motion, AnimatePresence } from 'framer-motion'; import { FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { FiArrowDownCircle } from 'react-icons/fi'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { BorrowStepType } from '@/hooks/useBorrowTransaction'; import { Market } from '@/utils/types'; import { MarketInfoBlock } from './common/MarketInfoBlock'; @@ -103,69 +103,46 @@ export function BorrowProcessModal({ }; return ( - - - - + + } + onClose={onClose} + /> + + -
-

Borrow {borrow.market.loanAsset.symbol}

-

Using {tokenSymbol} as collateral

- - {/* Market details */} -
- -
- - {/* Steps */} -
- {steps.map((step) => { - const status = getStepStatus(step.key); - return ( -
-
- {status === 'done' ? ( - - ) : status === 'current' ? ( - - ) : ( - - )} -
-
-
{step.label}
-
{step.detail}
-
-
- ); - })} -
-
-
-
-
+
+ {steps.map((step) => { + const status = getStepStatus(step.key); + return ( +
+
+ {status === 'done' ? ( + + ) : status === 'current' ? ( + + ) : ( + + )} +
+
+
{step.label}
+
{step.detail}
+
+
+ ); + })} +
+ + ); } diff --git a/src/components/RepayProcessModal.tsx b/src/components/RepayProcessModal.tsx index 97bae100..c2159139 100644 --- a/src/components/RepayProcessModal.tsx +++ b/src/components/RepayProcessModal.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; -import { Cross1Icon } from '@radix-ui/react-icons'; -import { motion, AnimatePresence } from 'framer-motion'; import { FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { FiRepeat } from 'react-icons/fi'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { Market } from '@/utils/types'; import { MarketInfoBlock } from './common/MarketInfoBlock'; @@ -74,75 +74,50 @@ export function RepayProcessModal({ }; return ( - - - - + + 0n ? 'Withdraw & Repay' : 'Repay'} ${tokenSymbol}`} + description={ + withdrawAmount > 0n + ? 'Withdrawing collateral and repaying loan' + : 'Repaying loan to market' + } + mainIcon={} + onClose={onClose} + /> + + -
-

- {withdrawAmount > 0n ? 'Withdraw & Repay' : 'Repay'} {tokenSymbol} -

-

- {withdrawAmount > 0n - ? 'Withdrawing collateral and repaying loan' - : 'Repaying loan to market'} -

- - {/* Market details */} -
- -
- - {/* Steps */} -
- {steps.map((step) => { - const status = getStepStatus(step.key); - return ( -
-
- {status === 'done' ? ( - - ) : status === 'current' ? ( - - ) : ( - - )} -
-
-
{step.label}
-
{step.detail}
-
-
- ); - })} -
-
-
-
-
+
+ {steps.map((step) => { + const status = getStepStatus(step.key); + return ( +
+
+ {status === 'done' ? ( + + ) : status === 'current' ? ( + + ) : ( + + )} +
+
+
{step.label}
+
{step.detail}
+
+
+ ); + })} +
+ + ); } diff --git a/src/components/RiskNotificationModal.tsx b/src/components/RiskNotificationModal.tsx index bfb66e32..484ab62e 100644 --- a/src/components/RiskNotificationModal.tsx +++ b/src/components/RiskNotificationModal.tsx @@ -1,17 +1,11 @@ 'use client'; import { useState, useEffect } from 'react'; -import { - Modal, - ModalContent, - ModalHeader, - ModalBody, - ModalFooter, - Button, - Checkbox, -} from '@heroui/react'; +import { Button, Checkbox } from '@heroui/react'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; +import { IoWarningOutline } from 'react-icons/io5'; +import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; export default function RiskNotificationModal() { const [isOpen, setIsOpen] = useState(false); @@ -37,15 +31,20 @@ export default function RiskNotificationModal() { } return ( - {}} hideCloseButton size="3xl" scrollBehavior="inside"> - - - Welcome to Monarch - - Important information before you begin - - - + setIsOpen(false)} + size="3xl" + scrollBehavior="inside" + className="max-h-[90vh]" + > + } + onClose={() => setIsOpen(false)} + /> +

Monarch enables direct lending to the Morpho Blue protocol. Before proceeding, it's important to understand the key aspects of this approach. For a comprehensive overview, @@ -86,17 +85,16 @@ export default function RiskNotificationModal() {

- - - - - + + + + ); } diff --git a/src/components/SupplyModalV2.tsx b/src/components/SupplyModalV2.tsx index a2e17fa9..6e1555c1 100644 --- a/src/components/SupplyModalV2.tsx +++ b/src/components/SupplyModalV2.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; -import { Cross1Icon } from '@radix-ui/react-icons'; import { FaArrowRightArrowLeft } from 'react-icons/fa6'; +import { Button } from '@/components/common/Button'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { Market, MarketPosition } from '@/utils/types'; import { MarketDetailsBlock } from './common/MarketDetailsBlock'; import { SupplyModalContent } from './SupplyModalContent'; @@ -30,87 +31,75 @@ export function SupplyModalV2({ const hasPosition = position && BigInt(position.state.supplyAssets) > 0n; return ( -
-
-
- + + } + onClose={onClose} + actions={ + hasPosition ? ( + + ) : undefined + } + /> + + -
-
-
- - - {mode === 'supply' ? 'Supply' : 'Withdraw'} {market.loanAsset.symbol} - -
- - {mode === 'supply' ? 'Supply to earn interest' : 'Withdraw your supplied assets'} - -
- - {hasPosition && ( - - )} -
- - {/* Market Details Block - includes position overview and collapsible details */} -
- -
- - {mode === 'supply' ? ( - {})} - onAmountChange={setSupplyPreviewAmount} - /> - ) : ( - {})} - onAmountChange={setWithdrawPreviewAmount} - /> - )} -
-
-
+ {mode === 'supply' ? ( + {})} + onAmountChange={setSupplyPreviewAmount} + /> + ) : ( + {})} + onAmountChange={setWithdrawPreviewAmount} + /> + )} + + ); } diff --git a/src/components/SupplyProcessModal.tsx b/src/components/SupplyProcessModal.tsx index cfdb19d4..ee2b22a2 100644 --- a/src/components/SupplyProcessModal.tsx +++ b/src/components/SupplyProcessModal.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; -import { Cross1Icon } from '@radix-ui/react-icons'; -import { motion, AnimatePresence } from 'framer-motion'; import { FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { FiUpload } from 'react-icons/fi'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { Market } from '@/utils/types'; import { MarketInfoBlock } from './common/MarketInfoBlock'; @@ -89,79 +89,56 @@ export function SupplyProcessModal({ const isMultiMarket = supplies.length > 1; return ( - - - - + + } + onClose={onClose} + /> + +
+ {supplies.map((supply) => ( + + ))} +
-
-

Supply {tokenSymbol}

-

- {isMultiMarket ? `Supplying to ${supplies.length} markets` : 'Supplying to market'} -

- - {/* Market details */} -
- {supplies.map((supply) => { - return ( - - ); - })} -
- - {/* Steps */} -
- {steps.map((step) => { - const status = getStepStatus(step.key); - return ( -
-
- {status === 'done' ? ( - - ) : status === 'current' ? ( - - ) : ( - - )} -
-
-
{step.label}
-
{step.detail}
-
-
- ); - })} -
-
-
-
-
+
+ {steps.map((step) => { + const status = getStepStatus(step.key); + return ( +
+
+ {status === 'done' ? ( + + ) : status === 'current' ? ( + + ) : ( + + )} +
+
+
{step.label}
+
{step.detail}
+
+
+ ); + })} +
+ + ); } diff --git a/src/components/WrapProcessModal.tsx b/src/components/WrapProcessModal.tsx index da13cc21..6a6a7b31 100644 --- a/src/components/WrapProcessModal.tsx +++ b/src/components/WrapProcessModal.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; -import { Cross1Icon } from '@radix-ui/react-icons'; import { motion, AnimatePresence } from 'framer-motion'; -import { FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { FaArrowRightArrowLeft, FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { WrapStep } from '@/hooks/useWrapLegacyMorpho'; import { formatBalance } from '@/utils/balance'; @@ -33,65 +33,48 @@ export function WrapProcessModal({ ); return ( -
- -
- - -
+ + } + onClose={onClose} + /> + + + {steps.map((step, index) => { + const isActive = currentStep === step.key; + const isPassed = steps.findIndex((s) => s.key === currentStep) > index; -
- - {steps.map((step, index) => { - const isActive = currentStep === step.key; - const isPassed = steps.findIndex((s) => s.key === currentStep) > index; - - return ( - -
- {isPassed ? ( - - ) : ( - - )} -
-
-

{step.label}

-

{step.detail}

-
-
- ); - })} -
-
-
-
+ return ( + +
+ {isPassed ? ( + + ) : ( + + )} +
+
+

{step.label}

+

{step.detail}

+
+
+ ); + })} + + + ); } diff --git a/src/components/common/MarketSelectionModal.tsx b/src/components/common/MarketSelectionModal.tsx index 357cae20..b6489ef4 100644 --- a/src/components/common/MarketSelectionModal.tsx +++ b/src/components/common/MarketSelectionModal.tsx @@ -1,8 +1,9 @@ import { useState, useMemo } from 'react'; -import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader } from '@heroui/react'; +import { FiSearch } from 'react-icons/fi'; import { Address } from 'viem'; import { Button } from '@/components/common/Button'; import { MarketsTableWithSameLoanAsset } from '@/components/common/MarketsTableWithSameLoanAsset'; +import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; import { Spinner } from '@/components/common/Spinner'; import { useMarkets } from '@/hooks/useMarkets'; import { SupportedNetworks } from '@/utils/networks'; @@ -106,23 +107,17 @@ export function MarketSelectionModal({ onClose={onClose} size="4xl" scrollBehavior="inside" - classNames={{ - wrapper: 'z-[2200] max-h-[80%] overflow-y-auto', - backdrop: 'z-[2190] bg-black/60', - base: 'rounded-sm bg-surface', - header: 'px-6 pt-6 pb-2', - body: 'px-6 pb-2', - footer: 'px-6 pt-2 pb-6', - }} + zIndex="selection" + backdrop="blur" + className="max-h-[80%] overflow-y-auto" > - - <> - - {title} - {description} - - - + } + onClose={onClose} + /> + {marketsLoading ? (
@@ -145,9 +140,8 @@ export function MarketSelectionModal({ showSelectColumn={multiSelect} /> )} - - - + + {multiSelect ? ( <>

@@ -174,9 +168,7 @@ export function MarketSelectionModal({

)} - - -
+ ); } diff --git a/src/components/common/Modal/Modal.tsx b/src/components/common/Modal/Modal.tsx index dcb555a0..d55f7d33 100644 --- a/src/components/common/Modal/Modal.tsx +++ b/src/components/common/Modal/Modal.tsx @@ -1,4 +1,6 @@ -import React from 'react'; +'use client'; + +import React, { useEffect, useState } from 'react'; import { Modal as HeroModal, ModalContent } from '@heroui/react'; export type ModalVariant = 'standard' | 'compact' | 'custom'; @@ -8,8 +10,7 @@ type ModalProps = { isOpen: boolean; onClose: () => void; onOpenChange?: () => void; - children: React.ReactNode; - variant?: ModalVariant; + children: React.ReactNode | ((onClose: () => void) => React.ReactNode); zIndex?: ModalZIndex; customZIndex?: number; size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | 'full'; @@ -21,10 +22,10 @@ type ModalProps = { }; const Z_INDEX_MAP: Record = { - base: { wrapper: 'z-50', backdrop: 'z-[45]' }, - process: { wrapper: 'z-[1100]', backdrop: 'z-[1090]' }, - selection: { wrapper: 'z-[2200]', backdrop: 'z-[2190]' }, - settings: { wrapper: 'z-[2300]', backdrop: 'z-[2290]' }, + base: { wrapper: 'z-[2000]', backdrop: 'z-[1990]' }, + process: { wrapper: 'z-[2600]', backdrop: 'z-[2590]' }, + selection: { wrapper: 'z-[3000]', backdrop: 'z-[2990]' }, + settings: { wrapper: 'z-[3200]', backdrop: 'z-[3190]' }, custom: { wrapper: '', backdrop: '' }, }; @@ -33,19 +34,27 @@ export function Modal({ onClose, onOpenChange, children, - variant = 'standard', zIndex = 'base', customZIndex, size = 'xl', isDismissable = true, - hideCloseButton = false, + hideCloseButton = true, scrollBehavior = 'inside', backdrop = 'blur', className = '', }: ModalProps) { + const [portalContainer, setPortalContainer] = useState(null); + useEffect(() => { + setPortalContainer(document.body); + }, []); + const zIndexClasses = customZIndex ? { wrapper: `z-[${customZIndex}]`, backdrop: `z-[${customZIndex - 10}]` } : Z_INDEX_MAP[zIndex]; + const backdropStyle = + backdrop === 'transparent' + ? 'bg-transparent' + : 'bg-black/70 backdrop-blur-md'; return ( - + {(closeModal) => ( <> {typeof children === 'function' ? children(closeModal) : children} diff --git a/src/components/common/Modal/ModalHeader.tsx b/src/components/common/Modal/ModalHeader.tsx index f1f5206c..7ec4c24d 100644 --- a/src/components/common/Modal/ModalHeader.tsx +++ b/src/components/common/Modal/ModalHeader.tsx @@ -1,30 +1,50 @@ import React from 'react'; import { ModalHeader as HeroModalHeader } from '@heroui/react'; +import { Cross1Icon } from '@radix-ui/react-icons'; export type ModalHeaderVariant = 'standard' | 'compact'; +export type ModalHeaderAction = { + icon: React.ReactNode; + onClick: () => void; + ariaLabel: string; +}; + type ModalHeaderProps = { title: string | React.ReactNode; description?: string | React.ReactNode; - icon?: React.ReactNode; + mainIcon?: React.ReactNode; variant?: ModalHeaderVariant; children?: React.ReactNode; className?: string; actions?: React.ReactNode; + onClose?: () => void; + showCloseButton?: boolean; + closeButtonAriaLabel?: string; + auxiliaryAction?: ModalHeaderAction; }; export function ModalHeader({ title, description, - icon, + mainIcon, variant = 'standard', children, className = '', actions, + onClose, + showCloseButton = true, + closeButtonAriaLabel = 'Close modal', + auxiliaryAction, }: ModalHeaderProps) { const isStandard = variant === 'standard'; - const paddingClass = isStandard ? 'px-10 pt-6' : 'px-6 pt-4'; - const titleSizeClass = isStandard ? 'text-lg' : 'text-base'; + const paddingClass = isStandard ? 'px-6 pt-6 pb-4' : 'px-5 pt-4 pb-3'; + const titleSizeClass = isStandard ? 'text-2xl' : 'text-lg'; + const descriptionSizeClass = isStandard ? 'text-sm' : 'text-xs'; + const showCloseIcon = Boolean(onClose) && showCloseButton; + const topRightControls = Boolean(actions || auxiliaryAction || showCloseIcon); + const iconButtonBaseClass = + 'flex h-8 w-8 items-center justify-center rounded-full text-secondary transition hover:text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/70'; // If children are provided, use them directly (for custom layouts) if (children) { @@ -37,21 +57,45 @@ export function ModalHeader({ // Standard layout with title, description, and optional icon return ( - -
-
- {icon &&
{icon}
} - - {title} - + +
+
+
+ {mainIcon &&
{mainIcon}
} + {title} +
+ {description && ( + + {description} + + )}
- {description && ( - - {description} - + {topRightControls && ( +
+ {actions &&
{actions}
} + {auxiliaryAction && ( + + )} + {showCloseIcon && ( + + )} +
)}
- {actions &&
{actions}
}
); } diff --git a/src/components/common/Modal/index.ts b/src/components/common/Modal/index.ts index 6b77694b..d03656b3 100644 --- a/src/components/common/Modal/index.ts +++ b/src/components/common/Modal/index.ts @@ -2,7 +2,7 @@ export { Modal } from './Modal'; export type { ModalVariant, ModalZIndex } from './Modal'; export { ModalHeader } from './ModalHeader'; -export type { ModalHeaderVariant } from './ModalHeader'; +export type { ModalHeaderVariant, ModalHeaderAction } from './ModalHeader'; export { ModalBody } from './ModalBody'; export type { ModalBodyVariant } from './ModalBody'; diff --git a/src/components/common/SuppliedAssetFilterCompactSwitch.tsx b/src/components/common/SuppliedAssetFilterCompactSwitch.tsx index a0fc568c..63a27ea8 100644 --- a/src/components/common/SuppliedAssetFilterCompactSwitch.tsx +++ b/src/components/common/SuppliedAssetFilterCompactSwitch.tsx @@ -1,11 +1,12 @@ 'use client'; import { useMemo } from 'react'; -import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, Divider, Tooltip, useDisclosure } from '@heroui/react'; +import { Divider, Tooltip, useDisclosure } from '@heroui/react'; import { FiFilter } from 'react-icons/fi'; import { Button } from '@/components/common/Button'; import { FilterRow, FilterSection } from '@/components/common/FilterComponents'; import { IconSwitch } from '@/components/common/IconSwitch'; +import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; import { TooltipContent } from '@/components/TooltipContent'; import { MONARCH_PRIMARY } from '@/constants/chartColors'; import { formatReadable } from '@/utils/balance'; @@ -103,23 +104,23 @@ export function SuppliedAssetFilterCompactSwitch({ - - {(close) => ( - <> - - Filters - - Quickly toggle the visibility filters that power the markets table - - - + {(close) => ( + <> + } + onClose={close} + /> + - - - - - - - )} - + + + + + + + )}
); diff --git a/src/components/settings/BlacklistedMarketsModal.tsx b/src/components/settings/BlacklistedMarketsModal.tsx index c7d82b7d..0474b181 100644 --- a/src/components/settings/BlacklistedMarketsModal.tsx +++ b/src/components/settings/BlacklistedMarketsModal.tsx @@ -1,10 +1,11 @@ 'use client'; import React, { useMemo } from 'react'; -import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Divider } from '@heroui/react'; +import { Divider } from '@heroui/react'; import { FiPlus, FiX } from 'react-icons/fi'; import { IoWarningOutline } from 'react-icons/io5'; import { Button } from '@/components/common'; +import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; import { MarketIdentity, MarketIdentityMode, MarketIdentityFocus } from '@/components/MarketIdentity'; import { useMarkets } from '@/contexts/MarketsContext'; import type { Market } from '@/utils/types'; @@ -85,24 +86,21 @@ export function BlacklistedMarketsModal({ isOpen, onOpenChange }: BlacklistedMar - - {(onClose) => ( - <> - - Manage Blacklisted Markets - - Block specific markets from appearing in your view - - - + {(onClose) => ( + <> + } + onClose={onClose} + /> + {/* Info Section */}
@@ -266,15 +264,14 @@ export function BlacklistedMarketsModal({ isOpen, onOpenChange }: BlacklistedMar )}
- - - - - - )} - + + + + + + )} ); } diff --git a/src/components/settings/TrustedVaultsModal.tsx b/src/components/settings/TrustedVaultsModal.tsx index 101928fc..18ebb8f0 100644 --- a/src/components/settings/TrustedVaultsModal.tsx +++ b/src/components/settings/TrustedVaultsModal.tsx @@ -1,21 +1,13 @@ 'use client'; import React, { useMemo, useState } from 'react'; -import { - Modal, - ModalContent, - ModalHeader, - ModalBody, - ModalFooter, - Divider, - Input, - Spinner, -} from '@heroui/react'; +import { Divider, Input, Spinner } from '@heroui/react'; import { FiChevronDown, FiChevronUp } from 'react-icons/fi'; import { GoShield, GoShieldCheck } from 'react-icons/go'; import { IoWarningOutline } from 'react-icons/io5'; import { Button } from '@/components/common'; import { IconSwitch } from '@/components/common/IconSwitch'; +import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; import { NetworkIcon } from '@/components/common/NetworkIcon'; import { VaultIdentity } from '@/components/vaults/VaultIdentity'; import { @@ -156,24 +148,21 @@ export default function TrustedVaultsModal({ - - {(onClose) => ( - <> - - Manage Trusted Vaults - - Select which vaults you trust to filter markets based on vault participation - - - + {(onClose) => ( + <> + } + onClose={onClose} + /> + {/* Info Section */}
@@ -313,15 +302,14 @@ export default function TrustedVaultsModal({ ) )}
- - - - - - )} - + + + + + + )} ); } From 5caf24b96629afff281e1f6e556f03c45a4c8d89 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Thu, 13 Nov 2025 15:45:35 -0300 Subject: [PATCH 04/11] chore: apply markets --- src/components/SupplyModalV2.tsx | 12 +- src/components/common/Modal/ModalBody.tsx | 5 +- src/components/common/Modal/ModalHeader.tsx | 75 ++++---- .../SuppliedAssetFilterCompactSwitch.tsx | 4 +- .../settings/BlacklistedMarketsModal.tsx | 16 +- src/components/settings/CustomRpcSettings.tsx | 174 ++++++++---------- .../settings/TrustedVaultsModal.tsx | 2 +- 7 files changed, 130 insertions(+), 158 deletions(-) diff --git a/src/components/SupplyModalV2.tsx b/src/components/SupplyModalV2.tsx index 6e1555c1..3ec0b188 100644 --- a/src/components/SupplyModalV2.tsx +++ b/src/components/SupplyModalV2.tsx @@ -1,6 +1,5 @@ import React, { useState } from 'react'; import { FaArrowRightArrowLeft } from 'react-icons/fa6'; -import { Button } from '@/components/common/Button'; import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { Market, MarketPosition } from '@/utils/types'; import { MarketDetailsBlock } from './common/MarketDetailsBlock'; @@ -55,15 +54,14 @@ export function SupplyModalV2({ onClose={onClose} actions={ hasPosition ? ( - + ) : undefined } /> diff --git a/src/components/common/Modal/ModalBody.tsx b/src/components/common/Modal/ModalBody.tsx index 6f91157d..a9558b51 100644 --- a/src/components/common/Modal/ModalBody.tsx +++ b/src/components/common/Modal/ModalBody.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { ModalBody as HeroModalBody } from '@heroui/react'; +import { twMerge } from 'tailwind-merge'; export type ModalBodyVariant = 'standard' | 'compact'; @@ -19,7 +20,9 @@ export function ModalBody({ const gapClass = isStandard ? 'gap-5' : 'gap-4'; return ( - + {children} ); diff --git a/src/components/common/Modal/ModalHeader.tsx b/src/components/common/Modal/ModalHeader.tsx index 7ec4c24d..d74035f1 100644 --- a/src/components/common/Modal/ModalHeader.tsx +++ b/src/components/common/Modal/ModalHeader.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { ModalHeader as HeroModalHeader } from '@heroui/react'; import { Cross1Icon } from '@radix-ui/react-icons'; +import { twMerge } from 'tailwind-merge'; export type ModalHeaderVariant = 'standard' | 'compact'; @@ -43,13 +44,17 @@ export function ModalHeader({ const descriptionSizeClass = isStandard ? 'text-sm' : 'text-xs'; const showCloseIcon = Boolean(onClose) && showCloseButton; const topRightControls = Boolean(actions || auxiliaryAction || showCloseIcon); + const controlPositionClass = isStandard ? 'top-6 right-6' : 'top-4 right-4'; + const contentRightPadding = topRightControls ? (isStandard ? 'pr-14' : 'pr-10') : ''; const iconButtonBaseClass = 'flex h-8 w-8 items-center justify-center rounded-full text-secondary transition hover:text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/70'; // If children are provided, use them directly (for custom layouts) if (children) { return ( - + {children} ); @@ -57,45 +62,43 @@ export function ModalHeader({ // Standard layout with title, description, and optional icon return ( - -
-
-
- {mainIcon &&
{mainIcon}
} - {title} -
- {description && ( - - {description} - - )} + +
+
+ {mainIcon &&
{mainIcon}
} + {title}
- {topRightControls && ( -
- {actions &&
{actions}
} - {auxiliaryAction && ( - - )} - {showCloseIcon && ( - - )} + {description && ( +
+ {description}
)}
+ {topRightControls && ( +
+ {actions &&
{actions}
} + {auxiliaryAction && ( + + )} + {showCloseIcon && ( + + )} +
+ )} ); } diff --git a/src/components/common/SuppliedAssetFilterCompactSwitch.tsx b/src/components/common/SuppliedAssetFilterCompactSwitch.tsx index 63a27ea8..5899e91e 100644 --- a/src/components/common/SuppliedAssetFilterCompactSwitch.tsx +++ b/src/components/common/SuppliedAssetFilterCompactSwitch.tsx @@ -107,9 +107,7 @@ export function SuppliedAssetFilterCompactSwitch({ onClose={onOpenChange} size="md" backdrop="opaque" - variant="compact" - customZIndex={3600} - className="rounded-lg" + // customZIndex={6000} > {(close) => ( <> diff --git a/src/components/settings/BlacklistedMarketsModal.tsx b/src/components/settings/BlacklistedMarketsModal.tsx index 0474b181..a4867e7e 100644 --- a/src/components/settings/BlacklistedMarketsModal.tsx +++ b/src/components/settings/BlacklistedMarketsModal.tsx @@ -3,7 +3,7 @@ import React, { useMemo } from 'react'; import { Divider } from '@heroui/react'; import { FiPlus, FiX } from 'react-icons/fi'; -import { IoWarningOutline } from 'react-icons/io5'; +import { MdBlockFlipped } from "react-icons/md"; import { Button } from '@/components/common'; import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; import { MarketIdentity, MarketIdentityMode, MarketIdentityFocus } from '@/components/MarketIdentity'; @@ -97,21 +97,11 @@ export function BlacklistedMarketsModal({ isOpen, onOpenChange }: BlacklistedMar } + mainIcon={} onClose={onClose} /> - {/* Info Section */} -
-
- -

- Some markets are blacklisted by default due to security concerns or issues. - These cannot be removed from the blacklist. -

-
-
- + {/* Blacklisted Markets Section */} {blacklistedMarkets.length > 0 && ( <> diff --git a/src/components/settings/CustomRpcSettings.tsx b/src/components/settings/CustomRpcSettings.tsx index 3f8c0841..213f4e3f 100644 --- a/src/components/settings/CustomRpcSettings.tsx +++ b/src/components/settings/CustomRpcSettings.tsx @@ -1,12 +1,12 @@ 'use client'; import { useState } from 'react'; -import { Cross1Icon } from '@radix-ui/react-icons'; import Image from 'next/image'; import { Button } from '@/components/common/Button'; import { Spinner } from '@/components/common/Spinner'; import { useStyledToast } from '@/hooks/useStyledToast'; import { SupportedNetworks, networks } from '@/utils/networks'; +import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { useCustomRpcContext } from '../providers/CustomRpcProvider'; // Helper function to get expected chain ID for each network @@ -175,50 +175,32 @@ function RpcModal({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) setError(''); }; - if (!isOpen) return null; - return ( -
-
-
- - -
-
-

Configure RPC Endpoints

-

- Set custom RPC URLs for blockchain networks -

-
- - -
- - {/* Network List */} -
- {networks.map((network) => { - const chainId = network.network; - const isCustom = isUsingCustomRpc(chainId); - const isSelected = selectedNetwork === chainId; - - return ( - ); })} -
+
+ + {selectedNetwork && ( +
+
+
+ n.network === selectedNetwork)?.logo || ''} + alt={networks.find((n) => n.network === selectedNetwork)?.name || ''} + width={20} + height={20} + className="rounded-full" + /> + + Configure {networks.find((n) => n.network === selectedNetwork)?.name} RPC + +
- {/* Edit Area */} - {selectedNetwork && ( -
-
-
- n.network === selectedNetwork)?.logo || ''} - alt={networks.find((n) => n.network === selectedNetwork)?.name || ''} - width={20} - height={20} - className="rounded-full" +
+
+ handleInputChange(e.target.value)} + className={`bg-hovered h-10 w-full truncate rounded p-2 pr-16 text-sm focus:border-primary focus:outline-none ${ + error ? 'border border-red-500 focus:border-red-500' : '' + }`} /> - - Configure {networks.find((n) => n.network === selectedNetwork)?.name} RPC - +
+ {error &&

{error}

} +
-
-
- handleInputChange(e.target.value)} - className={`bg-hovered h-10 w-full truncate rounded p-2 pr-16 text-sm focus:border-primary focus:outline-none ${ - error ? 'border border-red-500 focus:border-red-500' : '' - }`} - /> - -
- {error &&

{error}

} + {isUsingCustomRpc(selectedNetwork) && ( +
+
- - {isUsingCustomRpc(selectedNetwork) && ( -
- -
- )} -
+ )}
- )} -
-
-
+
+ )} + + ); } diff --git a/src/components/settings/TrustedVaultsModal.tsx b/src/components/settings/TrustedVaultsModal.tsx index 18ebb8f0..85bf8016 100644 --- a/src/components/settings/TrustedVaultsModal.tsx +++ b/src/components/settings/TrustedVaultsModal.tsx @@ -176,7 +176,7 @@ export default function TrustedVaultsModal({
{/* Search and Actions */} -
+
Date: Thu, 13 Nov 2025 16:04:46 -0300 Subject: [PATCH 05/11] chore: fix lint --- .../components/RebalanceProcessModal.tsx | 3 ++- .../components/onboarding/OnboardingModal.tsx | 6 +++--- app/settings/page.tsx | 2 +- .../common/MarketsTableWithSameLoanAsset.tsx | 16 +++++++++++++--- src/components/common/Modal/Modal.tsx | 7 ++----- src/components/common/Modal/ModalHeader.tsx | 10 ++++++---- .../settings/BlacklistedMarketsModal.tsx | 6 +++--- src/components/settings/CustomRpcSettings.tsx | 2 +- src/components/settings/TrustedVaultsModal.tsx | 4 ++-- src/hooks/useRebalance.ts | 14 +++++++++----- 10 files changed, 42 insertions(+), 28 deletions(-) diff --git a/app/positions/components/RebalanceProcessModal.tsx b/app/positions/components/RebalanceProcessModal.tsx index 629fa442..b58ce408 100644 --- a/app/positions/components/RebalanceProcessModal.tsx +++ b/app/positions/components/RebalanceProcessModal.tsx @@ -1,5 +1,6 @@ import React, { useMemo } from 'react'; -import { FaArrowRightArrowLeft, FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { FaArrowRightArrowLeft } from 'react-icons/fa6'; import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { RebalanceStepType } from '@/hooks/useRebalance'; diff --git a/app/positions/components/onboarding/OnboardingModal.tsx b/app/positions/components/onboarding/OnboardingModal.tsx index 64c4f67b..7e5f994b 100644 --- a/app/positions/components/onboarding/OnboardingModal.tsx +++ b/app/positions/components/onboarding/OnboardingModal.tsx @@ -64,12 +64,12 @@ export function OnboardingModal({ isOpen, onClose }: { isOpen: boolean; onClose: onClose={onClose} /> - -
+ +
-
+

Settings

diff --git a/src/components/common/MarketsTableWithSameLoanAsset.tsx b/src/components/common/MarketsTableWithSameLoanAsset.tsx index ac97f038..de2b7a05 100644 --- a/src/components/common/MarketsTableWithSameLoanAsset.tsx +++ b/src/components/common/MarketsTableWithSameLoanAsset.tsx @@ -31,6 +31,16 @@ import { MarketIdBadge } from '../MarketIdBadge'; import { MarketIdentity, MarketIdentityMode, MarketIdentityFocus } from '../MarketIdentity'; import { MarketIndicators } from '../MarketIndicators'; +const ZERO_DISPLAY_THRESHOLD = 1e-6; + +function formatAmountDisplay(value: bigint | string, decimals: number) { + const numericValue = formatBalance(value, decimals); + if (!Number.isFinite(numericValue) || Math.abs(numericValue) < ZERO_DISPLAY_THRESHOLD) { + return '-'; + } + return formatReadable(numericValue); +} + export type MarketWithSelection = { market: Market; isSelected: boolean; @@ -480,21 +490,21 @@ function MarketRow({ {columnVisibility.totalSupply && (

- {formatReadable(formatBalance(market.state.supplyAssets, market.loanAsset.decimals))} + {formatAmountDisplay(market.state.supplyAssets, market.loanAsset.decimals)}

)} {columnVisibility.totalBorrow && (

- {formatReadable(formatBalance(market.state.borrowAssets, market.loanAsset.decimals))} + {formatAmountDisplay(market.state.borrowAssets, market.loanAsset.decimals)}

)} {columnVisibility.liquidity && (

- {formatReadable(formatBalance(market.state.liquidityAssets, market.loanAsset.decimals))} + {formatAmountDisplay(market.state.liquidityAssets, market.loanAsset.decimals)}

)} diff --git a/src/components/common/Modal/Modal.tsx b/src/components/common/Modal/Modal.tsx index d55f7d33..63dfe983 100644 --- a/src/components/common/Modal/Modal.tsx +++ b/src/components/common/Modal/Modal.tsx @@ -76,11 +76,8 @@ export function Modal({ - {(closeModal) => ( - <> - {typeof children === 'function' ? children(closeModal) : children} - - )} + {async (closeModal) => + typeof children === 'function' ? children(closeModal) : children} ); diff --git a/src/components/common/Modal/ModalHeader.tsx b/src/components/common/Modal/ModalHeader.tsx index d74035f1..23415597 100644 --- a/src/components/common/Modal/ModalHeader.tsx +++ b/src/components/common/Modal/ModalHeader.tsx @@ -46,6 +46,8 @@ export function ModalHeader({ const topRightControls = Boolean(actions || auxiliaryAction || showCloseIcon); const controlPositionClass = isStandard ? 'top-6 right-6' : 'top-4 right-4'; const contentRightPadding = topRightControls ? (isStandard ? 'pr-14' : 'pr-10') : ''; + const handleAuxiliaryClick = auxiliaryAction?.onClick; + const handleClose = onClose; const iconButtonBaseClass = 'flex h-8 w-8 items-center justify-center rounded-full text-secondary transition hover:text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/70'; @@ -77,20 +79,20 @@ export function ModalHeader({ {topRightControls && (
{actions &&
{actions}
} - {auxiliaryAction && ( + {auxiliaryAction && handleAuxiliaryClick && ( )} - {showCloseIcon && ( + {showCloseIcon && handleClose && ( +
); diff --git a/src/components/settings/TrustedVaultsModal.tsx b/src/components/settings/TrustedVaultsModal.tsx index 62e81cfb..271f1645 100644 --- a/src/components/settings/TrustedVaultsModal.tsx +++ b/src/components/settings/TrustedVaultsModal.tsx @@ -19,7 +19,7 @@ import { useAllMorphoVaults } from '@/hooks/useAllMorphoVaults'; type TrustedVaultsModalProps = { isOpen: boolean; - onOpenChange: () => void; + onOpenChange: (isOpen: boolean) => void; userTrustedVaults: TrustedVault[]; setUserTrustedVaults: React.Dispatch>; }; @@ -147,8 +147,8 @@ export default function TrustedVaultsModal({ return ( onOpenChange(true)} + onClose={() => onOpenChange(false)} backdrop="blur" size="3xl" zIndex="settings" From 6a8362e1be13652531a25582b9879add50f6d5f6 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Thu, 13 Nov 2025 16:51:53 -0300 Subject: [PATCH 07/11] chore: lint --- app/positions/components/RebalanceModal.tsx | 1 - .../components/RebalanceProcessModal.tsx | 5 ++-- docs/Styling.md | 25 ++++++++----------- src/components/BorrowModal.tsx | 4 +-- src/components/SupplyModalV2.tsx | 4 +-- src/components/WrapProcessModal.tsx | 5 ++-- src/components/common/Modal/Modal.tsx | 6 +---- .../SuppliedAssetFilterCompactSwitch.tsx | 1 - 8 files changed, 21 insertions(+), 30 deletions(-) diff --git a/app/positions/components/RebalanceModal.tsx b/app/positions/components/RebalanceModal.tsx index 9fe42376..15656bbe 100644 --- a/app/positions/components/RebalanceModal.tsx +++ b/app/positions/components/RebalanceModal.tsx @@ -284,7 +284,6 @@ export function RebalanceModal({ onClose={onClose} isDismissable={false} size="4xl" - customZIndex={2000} > } + mainIcon={} onClose={onClose} /> diff --git a/docs/Styling.md b/docs/Styling.md index ec67922b..6eefe0aa 100644 --- a/docs/Styling.md +++ b/docs/Styling.md @@ -5,12 +5,12 @@ Use these shared components instead of raw HTML elements: - `Button`: Import from `@/components/common/Button` for all clickable actions -- `Modal`: For all modal dialogs +- `Modal`: For **all** modal dialogs (always import from `@/components/common/Modal`) - `Card`: For contained content sections ## Modal Guidelines -**IMPORTANT**: Always use our custom Modal components from `@/components/common/Modal` instead of directly using HeroUI modals. This ensures consistent styling, proper z-index management, and automatic font-zen application. +**IMPORTANT**: Always use our custom Modal components from `@/components/common/Modal`. Never import HeroUI modals directly. The shared wrapper applies Monarch typography, corner radius, background, blur, and z-index rules automatically. All modals MUST follow consistent styling standards for typography, spacing, and structure. There are two modal patterns based on use case. @@ -27,7 +27,7 @@ All modals MUST follow consistent styling standards for typography, spacing, and ### Using Our Modal Components -Import from our custom components: +Import the primitives from our shared entry point (and nowhere else): ```tsx import { Modal, ModalHeader, ModalBody, ModalFooter } from '@/components/common/Modal'; @@ -100,10 +100,12 @@ import { TokenIcon } from '@/components/TokenIcon'; ``` **Auto-Applied Standards:** -- **Spacing**: Automatically applied based on variant -- **Typography**: `font-zen` and text sizes handled automatically -- **Z-Index**: Managed through named layers (base, selection, settings, process) -- **No hardcoded styles**: Everything configured through props +- **Spacing**: Automatically applied based on variant (no extra padding needed) +- **Typography**: `font-zen` and text scales handled for you +- **Icon + actions slots**: Header provides `mainIcon`, `actions`, and an always-on close button +- **Z-Index**: Managed through named layers (base, process, selection, settings) +- **Backdrops**: Unified blur/opacity, so you get consistent overlays everywhere +- **Portal**: All modals render to `document.body` to avoid stacking bugs ### Compact Modal Pattern @@ -173,19 +175,12 @@ zIndex="settings" // z-2300 - Settings modals (HIGHEST - always on top) ``` -**Custom Z-Index (if needed):** - -```tsx - - {/* Very rare - only use if you have a specific need */} - -``` ### Typography Rules Typography is automatically handled by our Modal components. You don't need to specify font weights or sizes manually - just use the title/description props. -**IMPORTANT**: Never manually add bold or semibold font weights in modal content. +**IMPORTANT**: Never manually add bold or semibold font weights in modal headings/labels; rely on the shared components. ```tsx // ✅ Correct - let the component handle typography diff --git a/src/components/BorrowModal.tsx b/src/components/BorrowModal.tsx index acf317e7..f416bd06 100644 --- a/src/components/BorrowModal.tsx +++ b/src/components/BorrowModal.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { FaArrowRightArrowLeft } from 'react-icons/fa6'; +import { LuArrowRightLeft } from "react-icons/lu"; import { useAccount, useBalance } from 'wagmi'; import { Button } from '@/components/common/Button'; import { Modal, ModalHeader, ModalBody } from '@/components/common/Modal'; @@ -91,7 +91,7 @@ export function BorrowModal({ onPress={() => setMode(mode === 'borrow' ? 'repay' : 'borrow')} className="flex items-center gap-1.5" > - + {mode === 'borrow' ? 'Repay' : 'Borrow'} ) : undefined diff --git a/src/components/SupplyModalV2.tsx b/src/components/SupplyModalV2.tsx index 3ec0b188..954907ad 100644 --- a/src/components/SupplyModalV2.tsx +++ b/src/components/SupplyModalV2.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { FaArrowRightArrowLeft } from 'react-icons/fa6'; +import { LuArrowRightLeft } from "react-icons/lu"; import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { Market, MarketPosition } from '@/utils/types'; import { MarketDetailsBlock } from './common/MarketDetailsBlock'; @@ -59,7 +59,7 @@ export function SupplyModalV2({ onClick={() => setMode(mode === 'supply' ? 'withdraw' : 'supply')} className="flex items-center gap-1 text-sm font-medium text-primary transition hover:text-white" > - + {mode === 'supply' ? 'Withdraw' : 'Supply'} ) : undefined diff --git a/src/components/WrapProcessModal.tsx b/src/components/WrapProcessModal.tsx index 6a6a7b31..16aef987 100644 --- a/src/components/WrapProcessModal.tsx +++ b/src/components/WrapProcessModal.tsx @@ -1,6 +1,7 @@ import React, { useMemo } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; -import { FaArrowRightArrowLeft, FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { FaCheckCircle, FaCircle } from 'react-icons/fa'; +import { LuArrowRightLeft } from "react-icons/lu"; import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; import { WrapStep } from '@/hooks/useWrapLegacyMorpho'; import { formatBalance } from '@/utils/balance'; @@ -37,7 +38,7 @@ export function WrapProcessModal({ } + mainIcon={} onClose={onClose} /> diff --git a/src/components/common/Modal/Modal.tsx b/src/components/common/Modal/Modal.tsx index 858092e0..d6cabcd5 100644 --- a/src/components/common/Modal/Modal.tsx +++ b/src/components/common/Modal/Modal.tsx @@ -12,7 +12,6 @@ type ModalProps = { onOpenChange?: () => void; children: React.ReactNode | ((onClose: () => void) => React.ReactNode); zIndex?: ModalZIndex; - customZIndex?: number; size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | 'full'; isDismissable?: boolean; hideCloseButton?: boolean; @@ -35,7 +34,6 @@ export function Modal({ onOpenChange, children, zIndex = 'base', - customZIndex, size = 'xl', isDismissable = true, hideCloseButton = true, @@ -48,9 +46,7 @@ export function Modal({ setPortalContainer(document.body); }, []); - const zIndexClasses = customZIndex - ? { wrapper: `z-[${customZIndex}]`, backdrop: `z-[${customZIndex - 10}]` } - : Z_INDEX_MAP[zIndex]; + const zIndexClasses = Z_INDEX_MAP[zIndex]; const backdropStyle = backdrop === 'transparent' ? 'bg-transparent' diff --git a/src/components/common/SuppliedAssetFilterCompactSwitch.tsx b/src/components/common/SuppliedAssetFilterCompactSwitch.tsx index 5899e91e..d70168f5 100644 --- a/src/components/common/SuppliedAssetFilterCompactSwitch.tsx +++ b/src/components/common/SuppliedAssetFilterCompactSwitch.tsx @@ -107,7 +107,6 @@ export function SuppliedAssetFilterCompactSwitch({ onClose={onOpenChange} size="md" backdrop="opaque" - // customZIndex={6000} > {(close) => ( <> From 41624b34a8d89cc35d8bbe80107c2893856d8c32 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Thu, 13 Nov 2025 16:58:15 -0300 Subject: [PATCH 08/11] chore: remove agnet modals --- app/positions/components/agent/Main.tsx | 169 ------ app/positions/components/agent/SetupAgent.tsx | 516 ------------------ .../components/agent/SetupAgentModal.tsx | 193 ------- app/positions/components/agent/Success.tsx | 41 -- app/positions/components/agent/Welcome.tsx | 36 -- 5 files changed, 955 deletions(-) delete mode 100644 app/positions/components/agent/Main.tsx delete mode 100644 app/positions/components/agent/SetupAgent.tsx delete mode 100644 app/positions/components/agent/SetupAgentModal.tsx delete mode 100644 app/positions/components/agent/Success.tsx delete mode 100644 app/positions/components/agent/Welcome.tsx diff --git a/app/positions/components/agent/Main.tsx b/app/positions/components/agent/Main.tsx deleted file mode 100644 index 02203e8b..00000000 --- a/app/positions/components/agent/Main.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import { Tooltip } from '@heroui/react'; -import { motion } from 'framer-motion'; -import Image from 'next/image'; -import Link from 'next/link'; -import { GrStatusGood } from 'react-icons/gr'; -import { Button } from '@/components/common'; -import { TokenIcon } from '@/components/TokenIcon'; -import { TooltipContent } from '@/components/TooltipContent'; -import { useMarkets } from '@/contexts/MarketsContext'; -import { getExplorerURL } from '@/utils/external'; -import { findAgent } from '@/utils/monarch-agent'; -import { getNetworkName } from '@/utils/networks'; -import { UserRebalancerInfo } from '@/utils/types'; - -const img = require('../../../../src/imgs/agent/agent-detailed.png') as string; - -type MainProps = { - onNext: () => void; - userRebalancerInfos: UserRebalancerInfo[]; -}; - -export function Main({ onNext, userRebalancerInfos }: MainProps) { - const { markets } = useMarkets(); - - const activeAgentInfos = userRebalancerInfos - .map((info) => ({ - info, - agent: findAgent(info.rebalancer), - })) - .filter((item) => item.agent !== undefined); - - if (activeAgentInfos.length === 0) { - return ( -
-

No active agent found for the configured networks.

- -
- ); - } - - return ( -
- - Monarch Agent - - - {activeAgentInfos.map(({ info, agent }) => { - if (!agent) return null; - - const networkName = getNetworkName(info.network); - - const authorizedMarkets = markets.filter( - (market) => - market.morphoBlue.chain.id === info.network && - info.marketCaps.some( - (cap) => cap.marketId.toLowerCase() === market.uniqueKey.toLowerCase(), - ), - ); - - const loanAssetGroups = authorizedMarkets.reduce( - (acc, market) => { - const address = market.loanAsset.address.toLowerCase(); - if (!acc[address]) { - acc[address] = { - address, - chainId: market.morphoBlue.chain.id, - markets: [], - symbol: market.loanAsset.symbol, - }; - } - acc[address].markets.push(market); - return acc; - }, - {} as Record< - string, - { address: string; chainId: number; symbol: string; markets: typeof authorizedMarkets } - >, - ); - - const explorerUrl = getExplorerURL(agent.address, info.network); - - return ( -
-
-
-

{agent.name}

- - {networkName} - - - {agent.address.slice(0, 6) + '...' + agent.address.slice(-4)} - -
- } - title="Agent Active" - detail={`Agent is active on ${networkName}`} - /> - } - > -
-
- Active -
- -
- -
-
-

Strategy

-

{agent.strategyDescription}

-
- -
-

Monitoring Positions

-
- {Object.values(loanAssetGroups).map( - ({ address, chainId, markets: marketsForLoanAsset, symbol }) => { - return ( -
- - - {symbol ?? 'Unknown'} ({marketsForLoanAsset.length}) - -
- ); - }, - )} - {Object.values(loanAssetGroups).length === 0 && ( -

- No markets currently configured for this agent. -

- )} -
-
-
-
- ); - })} - - -
- ); -} diff --git a/app/positions/components/agent/SetupAgent.tsx b/app/positions/components/agent/SetupAgent.tsx deleted file mode 100644 index be40210f..00000000 --- a/app/positions/components/agent/SetupAgent.tsx +++ /dev/null @@ -1,516 +0,0 @@ -import { useState, useMemo, useCallback, useEffect } from 'react'; -import { - Checkbox, - Dropdown, - DropdownTrigger, - DropdownMenu, - DropdownItem, - SharedSelection, -} from '@heroui/react'; -import { ChevronDownIcon, ChevronUpIcon } from '@radix-ui/react-icons'; -import { motion, AnimatePresence } from 'framer-motion'; -import Image from 'next/image'; -import { formatUnits, maxUint256 } from 'viem'; -import { AgentSetupProcessModal } from '@/components/AgentSetupProcessModal'; -import { Button } from '@/components/common/Button'; -import { MarketInfoBlockCompact } from '@/components/common/MarketInfoBlock'; -import { TokenIcon } from '@/components/TokenIcon'; -import { MarketCap, useAuthorizeAgent } from '@/hooks/useAuthorizeAgent'; -import { findAgent, KnownAgents } from '@/utils/monarch-agent'; -import { - getNetworkName, - getNetworkImg, - SupportedNetworks, - isAgentAvailable, -} from '@/utils/networks'; -import { Market, MarketPosition, UserRebalancerInfo } from '@/utils/types'; - -type MarketGroup = { - network: SupportedNetworks; - loanAsset: { - address: string; - symbol: string; - }; - - // setup already: this includes markets that have been authorized for agent - authorizedMarkets: Market[]; - // have not setup yet, but currently acitve so should be consider priority - activeMarkets: Market[]; - historicalMarkets: Market[]; - otherMarkets: Market[]; -}; - -type SetupAgentProps = { - positions: MarketPosition[]; - allMarkets: Market[]; - userRebalancerInfos: UserRebalancerInfo[]; - pendingCaps: MarketCap[]; - addToPendingCaps: (market: Market, cap: bigint) => void; - removeFromPendingCaps: (market: Market) => void; - onBack: () => void; - onNext: () => void; - account?: string; -}; - -// Helper component for market rows -function MarketRow({ - market, - isSelected, - onToggle, - isDisabled, -}: { - market: Market; - isSelected: boolean; - onToggle: (selected: boolean) => void; - isDisabled: boolean; -}) { - return ( -
-
- !isDisabled && onToggle(selected)} - size="sm" - color="primary" - className="mr-0" - isDisabled={isDisabled} - /> - -
-
- ); -} - -export function SetupAgent({ - positions, - allMarkets, - userRebalancerInfos, - pendingCaps, - addToPendingCaps, - removeFromPendingCaps, - onBack, - onNext, -}: SetupAgentProps) { - const [hasPreselected, setHasPreselected] = useState(false); - const [expandedGroups, setExpandedGroups] = useState([]); - const [showAllMarkets, setShowAllMarkets] = useState(false); - const [showProcessModal, setShowProcessModal] = useState(false); - - const defaultNetwork = useMemo(() => { - const networks = Array.from(new Set(positions.map((p) => p.market.morphoBlue.chain.id))) - .filter(isAgentAvailable) - .sort(); - return networks[0] ?? SupportedNetworks.Base; - }, [positions]); - - const [targetNetwork, setTargetNetwork] = useState(defaultNetwork); - - const currentUserRebalancerInfo = useMemo(() => { - return userRebalancerInfos.find((info) => info.network === targetNetwork); - }, [userRebalancerInfos, targetNetwork]); - - const availableNetworks = useMemo(() => { - const networkSet = new Set(); - positions.forEach((p) => { - if (isAgentAvailable(p.market.morphoBlue.chain.id)) { - networkSet.add(p.market.morphoBlue.chain.id); - } - }); - userRebalancerInfos.forEach((info) => { - if (isAgentAvailable(info.network)) { - networkSet.add(info.network); - } - }); - return Array.from(networkSet).sort(); - }, [positions, userRebalancerInfos]); - - useEffect(() => { - if (!availableNetworks.includes(targetNetwork)) { - setTargetNetwork(availableNetworks[0] ?? defaultNetwork); - setHasPreselected(false); - } - }, [availableNetworks, targetNetwork, defaultNetwork]); - - const isInPending = (market: Market) => - pendingCaps.some((cap) => cap.market.uniqueKey === market.uniqueKey && cap.amount > 0); - - const isInPendingRemove = (market: Market) => - pendingCaps.some( - (cap) => cap.market.uniqueKey === market.uniqueKey && cap.amount === BigInt(0), - ); - - const groupedMarkets = useMemo(() => { - const groups: Record = {}; - const activeLoanAssets = new Set(); - - positions.forEach((position) => { - if (BigInt(position.state.supplyShares) > 0) { - activeLoanAssets.add(position.market.loanAsset.address.toLowerCase()); - } - }); - - allMarkets.forEach((market) => { - if (market.morphoBlue.chain.id !== targetNetwork) return; - - const loanAssetKey = market.loanAsset.address.toLowerCase(); - - if (!activeLoanAssets.has(loanAssetKey)) return; - - if (!groups[loanAssetKey]) { - groups[loanAssetKey] = { - network: market.morphoBlue.chain.id, - loanAsset: market.loanAsset, - authorizedMarkets: [], - activeMarkets: [], - historicalMarkets: [], - otherMarkets: [], - }; - } - - const authorized = currentUserRebalancerInfo?.marketCaps.find( - (c) => c.marketId.toLowerCase() === market.uniqueKey.toLowerCase(), - )?.cap; - - if (authorized) { - groups[loanAssetKey].authorizedMarkets.push(market); - return; - } - - const position = positions.find((p) => p.market.uniqueKey === market.uniqueKey); - if (position) { - const supply = parseFloat( - formatUnits(BigInt(position.state.supplyAssets), position.market.loanAsset.decimals), - ); - if (supply > 0) { - groups[loanAssetKey].activeMarkets.push(market); - } else { - groups[loanAssetKey].historicalMarkets.push(market); - } - } else { - groups[loanAssetKey].otherMarkets.push(market); - } - }); - - return Object.values(groups).sort((a, b) => { - return a.loanAsset.symbol.localeCompare(b.loanAsset.symbol); - }); - }, [allMarkets, positions, currentUserRebalancerInfo, targetNetwork]); - - useEffect(() => { - let mounted = true; - if (!hasPreselected && groupedMarkets.length > 0 && targetNetwork) { - groupedMarkets.forEach((group) => { - group.activeMarkets.forEach((market) => { - if (!isInPending(market) && !isInPendingRemove(market)) { - addToPendingCaps(market, maxUint256); - } - }); - }); - if (mounted) { - setHasPreselected(true); - } - } - - return () => { - mounted = false; - }; - }, [ - hasPreselected, - groupedMarkets, - isInPending, - isInPendingRemove, - addToPendingCaps, - targetNetwork, - ]); - - const toggleGroup = (key: string) => { - setExpandedGroups((prev) => - prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key], - ); - }; - - const hasSetupAgent = - !!currentUserRebalancerInfo && findAgent(currentUserRebalancerInfo.rebalancer) !== undefined; - - const agent = useMemo(() => { - return currentUserRebalancerInfo - ? findAgent(currentUserRebalancerInfo.rebalancer) - : findAgent(KnownAgents.MAX_APY ?? ''); - }, [currentUserRebalancerInfo]); - - const { executeBatchSetupAgent, currentStep } = useAuthorizeAgent( - KnownAgents.MAX_APY, - pendingCaps.filter((cap) => cap.market.morphoBlue.chain.id === targetNetwork), - targetNetwork, - onNext, - ); - - const handleExecute = useCallback(() => { - setShowProcessModal(true); - void executeBatchSetupAgent(() => setShowProcessModal(false)); - }, [executeBatchSetupAgent]); - - const handleNetworkChange = (keys: SharedSelection) => { - const selectedKey = Array.from(keys)[0]; - const newNetwork = Number(selectedKey) as SupportedNetworks; - if (newNetwork !== targetNetwork) { - setTargetNetwork(newNetwork); - setHasPreselected(false); - setExpandedGroups([]); - } - }; - - return ( -
- {!hasSetupAgent && agent && ( -
-

{agent.name}

-

{agent.strategyDescription}

-
- )} -
- - The agent can only reallocate funds among approved markets for the selected network. - - {availableNetworks.length > 1 && ( - - - - - - {availableNetworks.map((networkId) => ( - -
- {getNetworkName(networkId) - {getNetworkName(networkId) ?? `Network ${networkId}`} -
-
- ))} -
-
- )} -
- -
- {groupedMarkets.length === 0 && ( -

- No active supplied markets found for {getNetworkName(targetNetwork)}. -

- )} - {groupedMarkets.map((group) => { - const groupKey = `${group.loanAsset.address}-${group.network}`; - const isExpanded = expandedGroups.includes(groupKey); - - const numMarketsToAdd = [ - ...group.activeMarkets, - ...group.historicalMarkets, - ...group.otherMarkets, - ].filter(isInPending).length; - - const numMarketsToRemove = group.authorizedMarkets.filter(isInPendingRemove).length; - - return ( -
- {showProcessModal && ( - setShowProcessModal(false)} - /> - )} - - - - - {isExpanded && ( - -
- {group.authorizedMarkets.length > 0 && ( -
-

Authorized

- {group.authorizedMarkets.map((market) => ( - - selected - ? removeFromPendingCaps(market) - : addToPendingCaps(market, BigInt(0)) - } - isDisabled={false} - /> - ))} -
- )} - - {group.activeMarkets.length > 0 && ( -
-

Active Markets

- {group.activeMarkets.map((market) => ( - - selected - ? addToPendingCaps(market, maxUint256) - : removeFromPendingCaps(market) - } - isDisabled={false} - /> - ))} -
- )} - - {group.historicalMarkets.length > 0 && ( -
-

Previously Used

- {group.historicalMarkets.map((market) => ( - - selected - ? addToPendingCaps(market, maxUint256) - : removeFromPendingCaps(market) - } - isDisabled={false} - /> - ))} -
- )} - - {group.otherMarkets.length > 0 && !showAllMarkets && ( - - )} - - {showAllMarkets && group.otherMarkets.length > 0 && ( -
-

Other Available

- {group.otherMarkets.map((market) => ( - - selected - ? addToPendingCaps(market, maxUint256) - : removeFromPendingCaps(market) - } - isDisabled={false} - /> - ))} -
- )} -
-
- )} -
-
- ); - })} -
- -
- - -
-
- ); -} diff --git a/app/positions/components/agent/SetupAgentModal.tsx b/app/positions/components/agent/SetupAgentModal.tsx deleted file mode 100644 index 8347889b..00000000 --- a/app/positions/components/agent/SetupAgentModal.tsx +++ /dev/null @@ -1,193 +0,0 @@ -import { useState } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { FaRobot } from 'react-icons/fa'; -import { Address } from 'viem'; -import { Modal, ModalBody, ModalFooter, ModalHeader } from '@/components/common/Modal'; -import { useMarkets } from '@/contexts/MarketsContext'; -import { MarketCap } from '@/hooks/useAuthorizeAgent'; -import useUserPositions from '@/hooks/useUserPositions'; -import { findAgent } from '@/utils/monarch-agent'; -import { isAgentAvailable } from '@/utils/networks'; -import { Market, UserRebalancerInfo } from '@/utils/types'; -import { Main as MainContent } from './Main'; -import { SetupAgent } from './SetupAgent'; -import { Success as SuccessContent } from './Success'; -import { Welcome as WelcomeContent } from './Welcome'; - -export enum SetupStep { - Main = 'main', - Setup = 'setup', - Success = 'success', -} - -const SETUP_STEPS = [ - { - id: SetupStep.Main, - title: 'Welcome to Monarch Agent', - description: 'Bee-bee-bee, Monarch Agent is here!', - }, - { - id: SetupStep.Setup, - title: 'Setup Markets', - description: 'Choose which markets you want Monarch Agent to monitor', - }, - { - id: SetupStep.Success, - title: 'Setup Complete', - description: 'Your Monarch Agent is ready to go', - }, -] as const; - -function StepIndicator({ currentStep }: { currentStep: SetupStep }) { - return ( -
- {SETUP_STEPS.map((step, index) => { - const isCurrent = step.id === currentStep; - const isPast = SETUP_STEPS.findIndex((s) => s.id === currentStep) > index; - - return ( -
-
-
- ); - })} -
- ); -} - -type SetupAgentModalProps = { - account?: Address; - isOpen: boolean; - onClose: () => void; - userRebalancerInfos: UserRebalancerInfo[]; -}; - -export function SetupAgentModal({ - account, - isOpen, - onClose, - userRebalancerInfos, -}: SetupAgentModalProps) { - const [currentStep, setCurrentStep] = useState(SetupStep.Main); - const [pendingCaps, setPendingCaps] = useState([]); - - const { data: positions } = useUserPositions(account, true); - - // Use computed markets based on user setting - const { allMarkets } = useMarkets(); - - const currentStepIndex = SETUP_STEPS.findIndex((s) => s.id === currentStep); - - const handleNext = () => { - setCurrentStep((prev) => { - const currentIndex = SETUP_STEPS.findIndex((step) => step.id === prev); - const nextStep = SETUP_STEPS[currentIndex + 1]; - return nextStep?.id || prev; - }); - }; - - const handleBack = () => { - setCurrentStep((prev) => { - const currentIndex = SETUP_STEPS.findIndex((step) => step.id === prev); - const prevStep = SETUP_STEPS[currentIndex - 1]; - return prevStep?.id || prev; - }); - }; - - const handleReset = () => { - setCurrentStep(SetupStep.Main); - }; - - const handleClose = () => { - onClose(); - // Reset step after modal is closed - setTimeout(() => { - setCurrentStep(SetupStep.Main); - }, 300); - }; - - const addToPendingCaps = (market: Market, cap: bigint) => { - setPendingCaps((prev) => [ - ...prev, - { - market, - amount: cap, - }, - ]); - }; - - const removeFromPendingCaps = (market: Market) => { - setPendingCaps((prev) => prev.filter((cap) => cap.market.uniqueKey !== market.uniqueKey)); - }; - - const hasSetupAgent = userRebalancerInfos.some( - (info) => findAgent(info.rebalancer) !== undefined, - ); - - return ( - - } - onClose={handleClose} - /> - - -
- - - {currentStep === SetupStep.Main && !hasSetupAgent && ( - - )} - {currentStep === SetupStep.Main && hasSetupAgent && ( - - )} - {currentStep === SetupStep.Setup && ( - isAgentAvailable(m.morphoBlue.chain.id))} - userRebalancerInfos={userRebalancerInfos} - pendingCaps={pendingCaps} - addToPendingCaps={addToPendingCaps} - removeFromPendingCaps={removeFromPendingCaps} - onNext={handleNext} - onBack={handleBack} - account={account} - /> - )} - {currentStep === SetupStep.Success && ( - - )} - - -
-
- - - - -
- ); -} diff --git a/app/positions/components/agent/Success.tsx b/app/positions/components/agent/Success.tsx deleted file mode 100644 index b5d85279..00000000 --- a/app/positions/components/agent/Success.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { motion } from 'framer-motion'; -import Image from 'next/image'; -import { Button } from '@/components/common'; - -const img = require('../../../../src/imgs/agent/agent.png') as string; - -type SuccessProps = { - onClose: () => void; - onDone: () => void; -}; - -export function Success({ onClose, onDone }: SuccessProps) { - const handleDone = () => { - onDone(); - onClose(); - }; - - return ( -
- - Success - - -
-

Setup Complete!

-

- Your Monarch Agent is now ready to manage your positions. You can always update your - settings later. -

-
- - -
- ); -} diff --git a/app/positions/components/agent/Welcome.tsx b/app/positions/components/agent/Welcome.tsx deleted file mode 100644 index 534e4be0..00000000 --- a/app/positions/components/agent/Welcome.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { motion } from 'framer-motion'; -import Image from 'next/image'; -import { Button } from '@/components/common'; - -const img = require('../../../../src/imgs/agent/agent-detailed.png') as string; - -type WelcomeProps = { - onNext: () => void; -}; - -export function Welcome({ onNext }: WelcomeProps) { - return ( -
- - Monarch Agent - - -
-

Automate Your Position Management

-

- Monarch Agent is a smart automation tool that helps you manage your positions across - different markets. It can automatically reallocate your assets to optimize your returns - while maintaining your risk preferences. -

-
- - -
- ); -} From 26c80a34955848f1a37377e57c4362c5706bdb40 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Thu, 13 Nov 2025 17:37:14 -0300 Subject: [PATCH 09/11] chore: review fixes --- .../components/DepositToVaultModal.tsx | 10 ++- .../components/VaultDepositProcessModal.tsx | 10 ++- .../[marketid]/components/CampaignModal.tsx | 10 ++- .../components/BlacklistConfirmationModal.tsx | 12 +-- .../components/MarketActionsDropdown.tsx | 2 +- .../components/MarketSettingsModal.tsx | 3 +- app/markets/components/markets.tsx | 2 +- app/positions/components/PositionsContent.tsx | 12 +-- .../components/PositionsSummaryTable.tsx | 2 +- app/positions/components/RebalanceModal.tsx | 14 ++-- .../components/RebalanceProcessModal.tsx | 8 +- .../components/onboarding/OnboardingModal.tsx | 8 +- app/rewards/components/RewardContent.tsx | 2 +- app/settings/page.tsx | 2 +- src/components/AgentSetupProcessModal.tsx | 81 ------------------- src/components/BorrowModal.tsx | 8 +- src/components/BorrowProcessModal.tsx | 10 ++- src/components/RepayProcessModal.tsx | 10 ++- src/components/RiskNotificationModal.tsx | 2 +- src/components/SupplyModalV2.tsx | 12 +-- src/components/SupplyProcessModal.tsx | 10 ++- src/components/WrapProcessModal.tsx | 7 +- .../common/MarketSelectionModal.tsx | 16 ++-- .../common/MarketsTableWithSameLoanAsset.tsx | 2 +- src/components/common/Modal/Modal.tsx | 11 ++- .../SuppliedAssetFilterCompactSwitch.tsx | 2 +- .../settings/BlacklistedMarketsModal.tsx | 3 +- src/components/settings/CustomRpcSettings.tsx | 9 ++- .../settings/TrustedVaultsModal.tsx | 3 +- 29 files changed, 123 insertions(+), 160 deletions(-) delete mode 100644 src/components/AgentSetupProcessModal.tsx diff --git a/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx b/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx index 5ddaab88..d52dfd59 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/DepositToVaultModal.tsx @@ -64,7 +64,15 @@ export function DepositToVaultModal({ return ( <> - + { + if (!open) onClose(); + }} + size="lg" + scrollBehavior="inside" + backdrop="blur" + > + { + if (!open) onClose(); + }} + size="lg" + isDismissable={false} + backdrop="blur" + > + { + if (!open) onClose(); + }} + size="2xl" + scrollBehavior="inside" + backdrop="blur" + > void; + onOpenChange: (open: boolean) => void; onConfirm: () => void; market: Market | null; }; export function BlacklistConfirmationModal({ isOpen, - onClose, + onOpenChange, onConfirm, market, }: BlacklistConfirmationModalProps) { @@ -24,13 +24,13 @@ export function BlacklistConfirmationModal({ const handleConfirm = () => { onConfirm(); - onClose(); + onOpenChange(false); }; return ( onOpenChange(false)} />
@@ -59,7 +59,7 @@ export function BlacklistConfirmationModal({
-
diff --git a/app/rewards/components/RewardContent.tsx b/app/rewards/components/RewardContent.tsx index f25802f9..fc713f2b 100644 --- a/app/rewards/components/RewardContent.tsx +++ b/app/rewards/components/RewardContent.tsx @@ -294,7 +294,7 @@ export default function Rewards() { setShowProcessModal(false)} + onOpenChange={setShowProcessModal} /> )}
diff --git a/app/settings/page.tsx b/app/settings/page.tsx index 9f392184..099f6137 100644 --- a/app/settings/page.tsx +++ b/app/settings/page.tsx @@ -257,7 +257,7 @@ export default function SettingsPage() { {/* Blacklisted Markets Modal */} setIsBlacklistedMarketsModalOpen(!isBlacklistedMarketsModalOpen)} + onOpenChange={setIsBlacklistedMarketsModalOpen} />
); diff --git a/src/components/AgentSetupProcessModal.tsx b/src/components/AgentSetupProcessModal.tsx deleted file mode 100644 index 722b7b07..00000000 --- a/src/components/AgentSetupProcessModal.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react'; -import { FaCheckCircle, FaCircle, FaRobot } from 'react-icons/fa'; -import { Modal, ModalBody, ModalHeader } from '@/components/common/Modal'; -import { AuthorizeAgentStep } from '@/hooks/useAuthorizeAgent'; - -type AgentSetupModalProps = { - currentStep: AuthorizeAgentStep; - onClose: () => void; -}; - -const steps = [ - { - key: AuthorizeAgentStep.Authorize, - label: 'Authorize Monarch Agent', - detail: - 'Sign a signature to authorize the Monarch Agent contract to reallocate your positions.', - }, - { - key: AuthorizeAgentStep.Execute, - label: 'Execute Transaction', - detail: 'Confirm transaction in wallet to complete the setup', - }, -]; - -export function AgentSetupProcessModal({ - currentStep, - onClose, -}: AgentSetupModalProps): JSX.Element { - const getStepStatus = (stepKey: string) => { - const currentIndex = steps.findIndex((step) => step.key === currentStep); - const stepIndex = steps.findIndex((step) => step.key === stepKey); - - if (stepIndex < currentIndex) { - return 'done'; - } - if (stepKey === currentStep) { - return 'current'; - } - return 'undone'; - }; - - return ( - - } - onClose={onClose} - /> - - {steps.map((step) => { - const status = getStepStatus(step.key); - return ( -
-
- {status === 'done' ? ( - - ) : status === 'current' ? ( - - ) : ( - - )} -
-
-
{step.label}
-
{step.detail}
-
-
- ); - })} -
-
- ); -} diff --git a/src/components/BorrowModal.tsx b/src/components/BorrowModal.tsx index f416bd06..cec97ed3 100644 --- a/src/components/BorrowModal.tsx +++ b/src/components/BorrowModal.tsx @@ -10,7 +10,7 @@ import { TokenIcon } from './TokenIcon'; type BorrowModalProps = { market: Market; - onClose: () => void; + onOpenChange: (open: boolean) => void; oraclePrice: bigint; refetch?: () => void; isRefreshing?: boolean; @@ -19,7 +19,7 @@ type BorrowModalProps = { export function BorrowModal({ market, - onClose, + onOpenChange, oraclePrice, refetch, isRefreshing = false, @@ -72,10 +72,10 @@ export function BorrowModal({ ); return ( - + onOpenChange(false)} title={
{market.loanAsset.symbol} diff --git a/src/components/BorrowProcessModal.tsx b/src/components/BorrowProcessModal.tsx index 3568fb54..45778992 100644 --- a/src/components/BorrowProcessModal.tsx +++ b/src/components/BorrowProcessModal.tsx @@ -103,7 +103,15 @@ export function BorrowProcessModal({ }; return ( - + { + if (!open) onClose(); + }} + size="lg" + isDismissable={false} + backdrop="blur" + > + { + if (!open) onClose(); + }} + size="lg" + isDismissable={false} + backdrop="blur" + > 0n ? 'Withdraw & Repay' : 'Repay'} ${tokenSymbol}`} description={ diff --git a/src/components/RiskNotificationModal.tsx b/src/components/RiskNotificationModal.tsx index 484ab62e..be2fa7aa 100644 --- a/src/components/RiskNotificationModal.tsx +++ b/src/components/RiskNotificationModal.tsx @@ -33,7 +33,7 @@ export default function RiskNotificationModal() { return ( setIsOpen(false)} + onOpenChange={setIsOpen} size="3xl" scrollBehavior="inside" className="max-h-[90vh]" diff --git a/src/components/SupplyModalV2.tsx b/src/components/SupplyModalV2.tsx index 954907ad..b84f2367 100644 --- a/src/components/SupplyModalV2.tsx +++ b/src/components/SupplyModalV2.tsx @@ -9,7 +9,7 @@ import { WithdrawModalContent } from './WithdrawModalContent'; type SupplyModalV2Props = { market: Market; position?: MarketPosition | null; - onClose: () => void; + onOpenChange: (open: boolean) => void; refetch?: () => void; isMarketPage?: boolean; defaultMode?: 'supply' | 'withdraw'; @@ -18,7 +18,7 @@ type SupplyModalV2Props = { export function SupplyModalV2({ market, position, - onClose, + onOpenChange, refetch, isMarketPage, defaultMode = 'supply', @@ -32,7 +32,7 @@ export function SupplyModalV2({ return ( } - onClose={onClose} + onClose={() => onOpenChange(false)} actions={ hasPosition ? (
diff --git a/src/components/common/MarketsTableWithSameLoanAsset.tsx b/src/components/common/MarketsTableWithSameLoanAsset.tsx index 4356b5de..ac4f2380 100644 --- a/src/components/common/MarketsTableWithSameLoanAsset.tsx +++ b/src/components/common/MarketsTableWithSameLoanAsset.tsx @@ -1044,7 +1044,7 @@ export function MarketsTableWithSameLoanAsset({ {showSettingsModal && ( setShowSettingsModal(false)} + onOpenChange={setShowSettingsModal} usdFilters={usdFilters} setUsdFilters={setUsdFilters} entriesPerPage={entriesPerPage} diff --git a/src/components/common/Modal/Modal.tsx b/src/components/common/Modal/Modal.tsx index d6cabcd5..d7ca8152 100644 --- a/src/components/common/Modal/Modal.tsx +++ b/src/components/common/Modal/Modal.tsx @@ -8,8 +8,7 @@ export type ModalZIndex = 'base' | 'process' | 'selection' | 'settings' | 'custo type ModalProps = { isOpen: boolean; - onClose: () => void; - onOpenChange?: () => void; + onOpenChange: (open: boolean) => void; children: React.ReactNode | ((onClose: () => void) => React.ReactNode); zIndex?: ModalZIndex; size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | 'full'; @@ -30,7 +29,6 @@ const Z_INDEX_MAP: Record = export function Modal({ isOpen, - onClose, onOpenChange, children, zIndex = 'base', @@ -50,12 +48,13 @@ export function Modal({ const backdropStyle = backdrop === 'transparent' ? 'bg-transparent' - : 'bg-black/70 backdrop-blur-md'; + : backdrop === 'opaque' + ? 'bg-black/70' + : 'bg-black/70 backdrop-blur-md'; return ( - {(closeModal) => + {async (closeModal) => typeof children === 'function' ? children(closeModal) : children} diff --git a/src/components/common/SuppliedAssetFilterCompactSwitch.tsx b/src/components/common/SuppliedAssetFilterCompactSwitch.tsx index d70168f5..2cbd9531 100644 --- a/src/components/common/SuppliedAssetFilterCompactSwitch.tsx +++ b/src/components/common/SuppliedAssetFilterCompactSwitch.tsx @@ -104,9 +104,9 @@ export function SuppliedAssetFilterCompactSwitch({ {(close) => ( <> diff --git a/src/components/settings/BlacklistedMarketsModal.tsx b/src/components/settings/BlacklistedMarketsModal.tsx index 6d47fd29..d64c3e6f 100644 --- a/src/components/settings/BlacklistedMarketsModal.tsx +++ b/src/components/settings/BlacklistedMarketsModal.tsx @@ -12,7 +12,7 @@ import type { Market } from '@/utils/types'; type BlacklistedMarketsModalProps = { isOpen: boolean; - onOpenChange: () => void; + onOpenChange: (opened: boolean) => void; }; const ITEMS_PER_PAGE = 20; @@ -86,7 +86,6 @@ export function BlacklistedMarketsModal({ isOpen, onOpenChange }: BlacklistedMar void }) } return ( - + { + if (!open) handleClose(); + }} + size="2xl" + scrollBehavior="inside" + > onOpenChange(true)} - onClose={() => onOpenChange(false)} + onOpenChange={onOpenChange} backdrop="blur" size="3xl" zIndex="settings" From b9f0c28b45cbfbcaaa24e23953ac1e8f1d4e2823 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Thu, 13 Nov 2025 18:13:50 -0300 Subject: [PATCH 10/11] chore: fixing modals --- .../components/VaultInitializationModal.tsx | 12 ++++++------ .../components/VaultSettingsModal.tsx | 8 ++++---- .../components/settings/AddMarketCapModal.tsx | 6 +++--- .../components/settings/EditCaps.tsx | 2 +- .../[chainId]/[vaultAddress]/content.tsx | 4 ++-- app/autovault/components/AutovaultContent.tsx | 2 +- .../components/deployment/DeploymentModal.tsx | 15 ++++++++------- app/market/[chainId]/[marketid]/content.tsx | 4 ++-- src/components/common/Modal/Modal.tsx | 4 +--- 9 files changed, 28 insertions(+), 29 deletions(-) diff --git a/app/autovault/[chainId]/[vaultAddress]/components/VaultInitializationModal.tsx b/app/autovault/[chainId]/[vaultAddress]/components/VaultInitializationModal.tsx index b4961512..fdd076c5 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/VaultInitializationModal.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/VaultInitializationModal.tsx @@ -197,7 +197,7 @@ function AgentSelectionStep({ export function VaultInitializationModal({ isOpen, - onClose, + onOpenChange, vaultAddress, marketAdapter, // address of MorphoMakretV1Aapater marketAdapterLoading, // @@ -209,7 +209,7 @@ export function VaultInitializationModal({ marketAdapter: Address; marketAdapterLoading: boolean; refetchMarketAdapter: () => void; - onClose: () => void; + onOpenChange: (open: boolean) => void; vaultAddress: Address; chainId: SupportedNetworks; onAdapterConfigured: () => void; @@ -263,14 +263,14 @@ export function VaultInitializationModal({ return; } onAdapterConfigured(); - onClose(); + onOpenChange(false); } catch (error) { console.error('Failed to complete initialization', error); } }, [ completeInitialization, onAdapterConfigured, - onClose, + onOpenChange, registryAddress, selectedAgent, marketAdapter, @@ -397,7 +397,7 @@ export function VaultInitializationModal({ return ( } - onClose={onClose} + onClose={() => onOpenChange(false)} /> {currentStep === 'deploy' && ( diff --git a/app/autovault/[chainId]/[vaultAddress]/components/VaultSettingsModal.tsx b/app/autovault/[chainId]/[vaultAddress]/components/VaultSettingsModal.tsx index c433367b..78fb7be4 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/VaultSettingsModal.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/VaultSettingsModal.tsx @@ -18,7 +18,7 @@ const TABS: { id: SettingsTab; label: string }[] = [ type VaultSettingsModalProps = { isOpen: boolean; - onClose: () => void; + onOpenChange: (open: boolean) => void; initialTab?: SettingsTab; isOwner: boolean; onUpdateMetadata: (values: { name?: string; symbol?: string }) => Promise; @@ -45,7 +45,7 @@ type VaultSettingsModalProps = { export function VaultSettingsModal({ isOpen, - onClose, + onOpenChange, initialTab = 'general', isOwner, onUpdateMetadata, @@ -133,7 +133,7 @@ export function VaultSettingsModal({ return ( } - onClose={onClose} + onClose={() => onOpenChange(false)} auxiliaryAction={ onRefresh ? { diff --git a/app/autovault/[chainId]/[vaultAddress]/components/settings/AddMarketCapModal.tsx b/app/autovault/[chainId]/[vaultAddress]/components/settings/AddMarketCapModal.tsx index b52d6de8..f195f7db 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/settings/AddMarketCapModal.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/settings/AddMarketCapModal.tsx @@ -10,7 +10,7 @@ type AddMarketCapModalProps = { vaultAsset: Address; chainId: SupportedNetworks; existingMarketIds: Set; - onClose: () => void; + onOpenChange: (open: boolean) => void; onAdd: (markets: Market[]) => void; }; @@ -22,7 +22,7 @@ export function AddMarketCapModal({ vaultAsset, chainId, existingMarketIds, - onClose, + onOpenChange, onAdd, }: AddMarketCapModalProps) { return ( @@ -33,7 +33,7 @@ export function AddMarketCapModal({ chainId={chainId} excludeMarketIds={existingMarketIds} multiSelect - onClose={onClose} + onOpenChange={onOpenChange} onSelect={onAdd} confirmButtonText={undefined} // Use default dynamic text /> diff --git a/app/autovault/[chainId]/[vaultAddress]/components/settings/EditCaps.tsx b/app/autovault/[chainId]/[vaultAddress]/components/settings/EditCaps.tsx index faab78dd..bffce5e8 100644 --- a/app/autovault/[chainId]/[vaultAddress]/components/settings/EditCaps.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/components/settings/EditCaps.tsx @@ -570,7 +570,7 @@ export function EditCaps({ vaultAsset={vaultAsset} chainId={chainId} existingMarketIds={existingMarketIds} - onClose={() => setShowAddMarketModal(false)} + onOpenChange={setShowAddMarketModal} onAdd={handleAddMarkets} /> )} diff --git a/app/autovault/[chainId]/[vaultAddress]/content.tsx b/app/autovault/[chainId]/[vaultAddress]/content.tsx index 41ba63b6..8b8c26bd 100644 --- a/app/autovault/[chainId]/[vaultAddress]/content.tsx +++ b/app/autovault/[chainId]/[vaultAddress]/content.tsx @@ -299,7 +299,7 @@ export default function VaultContent() { {/* Settings Modal */} setShowSettings(false)} + onOpenChange={setShowSettings} initialTab={settingsTab} isOwner={vault.isOwner} onUpdateMetadata={handleUpdateMetadata} @@ -330,7 +330,7 @@ export default function VaultContent() { {networkConfig?.vaultConfig?.marketV1AdapterFactory && ( setShowInitializationModal(false)} + onOpenChange={setShowInitializationModal} vaultAddress={vaultAddressValue} chainId={chainId} marketAdapter={vault.adapter} diff --git a/app/autovault/components/AutovaultContent.tsx b/app/autovault/components/AutovaultContent.tsx index 41fb7b75..01e6152b 100644 --- a/app/autovault/components/AutovaultContent.tsx +++ b/app/autovault/components/AutovaultContent.tsx @@ -84,7 +84,7 @@ export default function AutovaultContent() { {/* Deployment Modal */} setShowDeploymentModal(false)} + onOpenChange={setShowDeploymentModal} existingVaults={vaults} />
diff --git a/app/autovault/components/deployment/DeploymentModal.tsx b/app/autovault/components/deployment/DeploymentModal.tsx index d2ee6332..ecd78694 100644 --- a/app/autovault/components/deployment/DeploymentModal.tsx +++ b/app/autovault/components/deployment/DeploymentModal.tsx @@ -19,11 +19,12 @@ const VAULT_SUPPORTED_NETWORKS: SupportedNetworks[] = ALL_SUPPORTED_NETWORKS.fil type DeploymentModalContentProps = { isOpen: boolean; - onClose: () => void; + + onOpenChange: (open: boolean) => void existingVaults: UserVaultV2[]; }; -function DeploymentModalContent({ isOpen, onClose, existingVaults }: DeploymentModalContentProps) { +function DeploymentModalContent({ isOpen, onOpenChange, existingVaults }: DeploymentModalContentProps) { const { selectedTokenAndNetwork, needSwitchChain, switchToNetwork, createVault, isDeploying } = useDeployment(); // Load balances and tokens at modal level @@ -57,7 +58,7 @@ function DeploymentModalContent({ isOpen, onClose, existingVaults }: DeploymentM return ( } - onClose={onClose} + onClose={() => onOpenChange(false)} /> @@ -145,14 +146,14 @@ function DeploymentModalContent({ isOpen, onClose, existingVaults }: DeploymentM type DeploymentModalProps = { isOpen: boolean; - onClose: () => void; + onOpenChange: (open: boolean) => void; existingVaults: UserVaultV2[]; }; -export function DeploymentModal({ isOpen, onClose, existingVaults }: DeploymentModalProps) { +export function DeploymentModal({ isOpen, onOpenChange, existingVaults }: DeploymentModalProps) { return ( - + ); } diff --git a/app/market/[chainId]/[marketid]/content.tsx b/app/market/[chainId]/[marketid]/content.tsx index 7ed063cc..bbfbbc5e 100644 --- a/app/market/[chainId]/[marketid]/content.tsx +++ b/app/market/[chainId]/[marketid]/content.tsx @@ -213,7 +213,7 @@ function MarketContent() { {showSupplyModal && ( setShowSupplyModal(false)} + onOpenChange={setShowSupplyModal} position={userPosition} isMarketPage refetch={handleRefreshAllSync} @@ -223,7 +223,7 @@ function MarketContent() { {showBorrowModal && ( setShowBorrowModal(false)} + onOpenChange={setShowBorrowModal} oraclePrice={oraclePrice} refetch={handleRefreshAllSync} isRefreshing={isRefreshing} diff --git a/src/components/common/Modal/Modal.tsx b/src/components/common/Modal/Modal.tsx index d7ca8152..cfc0820f 100644 --- a/src/components/common/Modal/Modal.tsx +++ b/src/components/common/Modal/Modal.tsx @@ -1,5 +1,3 @@ -'use client'; - import React, { useEffect, useState } from 'react'; import { Modal as HeroModal, ModalContent } from '@heroui/react'; @@ -71,7 +69,7 @@ export function Modal({ - {async (closeModal) => + {(closeModal) => typeof children === 'function' ? children(closeModal) : children} From aa16b9a677cc87c11debc549e6d9b9b0ff5f60f3 Mon Sep 17 00:00:00 2001 From: antoncoding Date: Thu, 13 Nov 2025 18:16:55 -0300 Subject: [PATCH 11/11] chore: fix build --- src/components/common/Modal/Modal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/common/Modal/Modal.tsx b/src/components/common/Modal/Modal.tsx index cfc0820f..317c7f9c 100644 --- a/src/components/common/Modal/Modal.tsx +++ b/src/components/common/Modal/Modal.tsx @@ -69,6 +69,7 @@ export function Modal({ + {/* eslint-disable-next-line @typescript-eslint/promise-function-async */} {(closeModal) => typeof children === 'function' ? children(closeModal) : children}