diff --git a/app/positions/components/PositionsContent.tsx b/app/positions/components/PositionsContent.tsx index d587003b..bcf0be9c 100644 --- a/app/positions/components/PositionsContent.tsx +++ b/app/positions/components/PositionsContent.tsx @@ -1,9 +1,12 @@ 'use client'; -import { useState } from 'react'; +import { useMemo, useState } from 'react'; +import { Name } from '@coinbase/onchainkit/identity'; import Link from 'next/link'; import { useParams } from 'next/navigation'; -import { FaHistory, FaGift, FaPlus } from 'react-icons/fa'; +import { FaHistory, FaGift, FaPlus, FaCircle } from 'react-icons/fa'; +import { useAccount } from 'wagmi'; +import { Avatar } from '@/components/Avatar/Avatar'; import Header from '@/components/layout/header/Header'; import EmptyScreen from '@/components/Status/EmptyScreen'; import LoadingScreen from '@/components/Status/LoadingScreen'; @@ -19,6 +22,12 @@ export default function Positions() { const [selectedPosition, setSelectedPosition] = useState(null); const { account } = useParams<{ account: string }>(); + const { address, isConnected } = useAccount(); + + const isOwner = useMemo(() => { + if (!account) return false; + return account === address; + }, [account, address]); const { loading, isRefetching, data: marketPositions, refetch } = useUserPositions(account); @@ -28,8 +37,32 @@ export default function Positions() {
+
+

Portfolio

+
-

Portfolio

+
+
+ + {isConnected && account === address && ( +
+
+ +
+
+ )} +
+
+ +
+
- + {isOwner && ( + + + + )}
@@ -102,6 +138,7 @@ export default function Positions() { ) : (
void; setShowSupplyModal: (show: boolean) => void; @@ -40,6 +42,7 @@ export function PositionsSummaryTable({ setSelectedPosition, refetch, isRefetching, + account, }: PositionsSummaryTableProps) { const [expandedRows, setExpandedRows] = useState>(new Set()); const [showRebalanceModal, setShowRebalanceModal] = useState(false); @@ -47,6 +50,12 @@ export function PositionsSummaryTable({ null, ); const [earningsPeriod, setEarningsPeriod] = useState(EarningsPeriod.Day); + const { address } = useAccount(); + + const isOwner = useMemo(() => { + if (!account) return false; + return account === address; + }, [marketPositions, address]); const getEarningsForPeriod = (position: MarketPosition) => { if (!position.earned) return '0'; @@ -218,17 +227,18 @@ export function PositionsSummaryTable({
- + setEarningsPeriod(key as EarningsPeriod)} > {Object.entries(periodLabels).map(([period, label]) => ( @@ -236,14 +246,15 @@ export function PositionsSummaryTable({ ))} - +
@@ -351,18 +362,25 @@ export function PositionsSummaryTable({ /> - diff --git a/app/positions/components/RebalanceModal.tsx b/app/positions/components/RebalanceModal.tsx index 808e3ce1..ad579967 100644 --- a/app/positions/components/RebalanceModal.tsx +++ b/app/positions/components/RebalanceModal.tsx @@ -230,8 +230,6 @@ export function RebalanceModal({ [chainId, groupedPosition.chainId], ); - console.log('needSwitchChain', needSwitchChain); - const handleExecuteRebalance = useCallback(async () => { if (needSwitchChain) { try { diff --git a/app/positions/components/onboarding/AssetSelection.tsx b/app/positions/components/onboarding/AssetSelection.tsx index 486d84d8..89241e18 100644 --- a/app/positions/components/onboarding/AssetSelection.tsx +++ b/app/positions/components/onboarding/AssetSelection.tsx @@ -114,7 +114,7 @@ export function AssetSelection() { role="button" key={`${token.symbol}-${token.network}`} onClick={() => handleTokenSelect(token)} - className="group relative flex items-start gap-4 rounded-lg border border-gray-200 bg-white p-4 text-left transition-all duration-300 hover:border-primary hover:shadow-lg dark:border-gray-700 dark:bg-gray-800/50 dark:hover:bg-gray-800" + className="group relative flex items-start gap-4 rounded border border-gray-200 bg-white p-4 text-left transition-all duration-300 hover:border-primary hover:shadow-lg dark:border-gray-700 dark:bg-gray-800/50 dark:hover:bg-gray-800" whileHover={{ scale: 1.02 }} transition={{ type: 'spring', stiffness: 300, damping: 20 }} > diff --git a/app/positions/components/onboarding/SetupPositions.tsx b/app/positions/components/onboarding/SetupPositions.tsx index 39dd010d..f59b3237 100644 --- a/app/positions/components/onboarding/SetupPositions.tsx +++ b/app/positions/components/onboarding/SetupPositions.tsx @@ -3,7 +3,9 @@ import { Button, Slider } from '@nextui-org/react'; import { LockClosedIcon, LockOpen1Icon } from '@radix-ui/react-icons'; import Image from 'next/image'; import { useRouter } from 'next/navigation'; +import { toast } from 'react-toastify'; import { formatUnits, parseUnits } from 'viem'; +import { useChainId, useSwitchChain } from 'wagmi'; import OracleVendorBadge from '@/components/OracleVendorBadge'; import { SupplyProcessModal } from '@/components/SupplyProcessModal'; import { useLocalStorage } from '@/hooks/useLocalStorage'; @@ -16,6 +18,7 @@ import { useOnboarding } from './OnboardingContext'; export function SetupPositions() { const router = useRouter(); + const chainId = useChainId(); const { selectedToken, selectedMarkets } = useOnboarding(); const { balances } = useUserBalances(); const [useEth] = useLocalStorage('useEth', false); @@ -27,6 +30,13 @@ export function SetupPositions() { const [error, setError] = useState(null); const [isSupplying, setIsSupplying] = useState(false); + const needSwitchChain = useMemo( + () => chainId !== selectedToken?.network, + [chainId, selectedToken], + ); + + const { switchChain } = useSwitchChain(); + // Redirect if no token selected useEffect(() => { if (!selectedToken) { @@ -222,7 +232,22 @@ export function SetupPositions() { } = useMultiMarketSupply(selectedToken!, supplies, useEth, usePermit2Setting); const handleSupply = async () => { - if (isSupplying) return; + if (isSupplying) { + toast.info('Supplying in progress'); + return; + } + + if (needSwitchChain && selectedToken) { + try { + switchChain({ chainId: selectedToken.network }); + toast.info('Network changed, please click again to execute'); + return; + } catch (switchError) { + console.error('Failed to switch network:', switchError); + toast.error('Failed to switch network'); + return; + } + } setIsSupplying(true); try { diff --git a/app/settings/faq/page.tsx b/app/settings/faq/page.tsx index bedae538..dbf09020 100644 --- a/app/settings/faq/page.tsx +++ b/app/settings/faq/page.tsx @@ -43,7 +43,7 @@ function FAQPage() {

Frequently Asked Questions

{faqs.map((faq, index) => ( -
+

{faq.question}

{faq.answer}

diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index 18012707..fe40c82b 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -6,9 +6,10 @@ import { MORPHO } from '@/utils/morpho'; type AvatarProps = { address: Address; size?: number; + rounded?: boolean; }; -export function Avatar({ address, size = 30 }: AvatarProps) { +export function Avatar({ address, size = 30, rounded = true }: AvatarProps) { const [useEffigy, setUseEffigy] = useState(true); const effigyUrl = `https://effigy.im/a/${address}.svg`; const dicebearUrl = `https://api.dicebear.com/7.x/pixel-art/png?seed=${address}`; @@ -34,7 +35,7 @@ export function Avatar({ address, size = 30 }: AvatarProps) { alt={`Avatar for ${address}`} width={size} height={size} - style={{ borderRadius: '50%' }} + style={{ borderRadius: rounded ? '50%' : '5px' }} onError={() => setUseEffigy(false)} />
diff --git a/src/components/supplyModal.tsx b/src/components/supplyModal.tsx index df833667..809e2619 100644 --- a/src/components/supplyModal.tsx +++ b/src/components/supplyModal.tsx @@ -76,8 +76,6 @@ export function SupplyModal({ market, onClose }: SupplyModalProps): JSX.Element tokenSymbol: market.loanAsset.symbol, }); - console.log('isApproved', isApproved); - const needSwitchChain = useMemo( () => chainId !== market.morphoBlue.chain.id, [chainId, market.morphoBlue.chain.id], diff --git a/src/hooks/useRebalance.ts b/src/hooks/useRebalance.ts index 431bceea..1abc56e2 100644 --- a/src/hooks/useRebalance.ts +++ b/src/hooks/useRebalance.ts @@ -204,6 +204,9 @@ export const useRebalance = (groupedPosition: GroupedPosition, onRebalance?: () const shares = groupedPosition.markets.find( (m) => m.market.uniqueKey === actions[0].fromMarket.uniqueKey, )?.supplyShares; + + console.log('shares', shares); + if (isWithdrawMax && shares === undefined) { throw new Error('No share found for max withdraw'); }
-
- +