diff --git a/apps/dapp/package.json b/apps/dapp/package.json index 6e44cadf..f58e1764 100644 --- a/apps/dapp/package.json +++ b/apps/dapp/package.json @@ -10,13 +10,8 @@ "test": "jest apps/dapp" }, "dependencies": { - "@chakra-ui/icons": "^2.1.1", - "@chakra-ui/next-js": "^2.2.0", - "@chakra-ui/react": "^2.8.2", - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", - "@mui/material": "^5.16.4", - "@mui/x-charts": "^7.11.0", + "@chakra-ui/react": "^3.0.2", + "@emotion/react": "^11.13.3", "@reduxjs/toolkit": "^2.2.6", "@repo/ui": "*", "@soroban-react/chains": "^9.1.13", @@ -30,14 +25,16 @@ "@soroban-react/xbull": "^9.1.3", "@stellar/stellar-sdk": "12.2.0", "axios": "^1.7.7", - "framer-motion": "^11.3.0", "next": "15.0.0-rc.0", + "next-themes": "^0.3.0", "react": "19.0.0-rc-f994737d14-20240522", "react-dom": "19.0.0-rc-f994737d14-20240522", + "react-icons": "^5.3.0", "react-redux": "^9.1.2" }, "devDependencies": { "@jest/globals": "^29.7.0", + "@chakra-ui/cli": "^3.0.0", "@repo/eslint-config": "*", "@repo/typescript-config": "*", "@testing-library/jest-dom": "6.1.5", @@ -53,4 +50,4 @@ "ts-jest": "^29.2.5", "typescript": "5.3.3" } -} +} \ No newline at end of file diff --git a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx index eec7ff62..6c028f7b 100644 --- a/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx +++ b/apps/dapp/src/components/DeployVault/AddNewStrategyButton.tsx @@ -1,33 +1,36 @@ +'use client' import React from 'react' import { useEffect, useState } from 'react' import { Button, - Modal, - ModalOverlay, - ModalContent, - ModalHeader, - ModalFooter, - ModalBody, - ModalCloseButton, - useDisclosure, IconButton, - Select, + NativeSelectField, } from '@chakra-ui/react' -import { AddIcon } from '@chakra-ui/icons' +import { MdAdd } from 'react-icons/md' +import { + DialogBackdrop, + DialogBody, + DialogContent, + DialogFooter, + DialogRoot, + DialogTrigger, +} from '@/components/ui/dialog' import { useAppDispatch, useAppSelector } from '@/store/lib/storeHooks' import { pushStrategy, getDefaultStrategies } from '@/store/lib/features/vaultStore' import { useSorobanReact } from '@soroban-react/core' import { Strategy } from '@/store/lib/features/walletStore' +import { NativeSelectRoot } from '../ui/native-select' function AddNewStrategyButton() { + const [open, setOpen] = useState(false) const strategies = useAppSelector(state => state.newVault.strategies) const dispatch = useAppDispatch(); const { activeChain } = useSorobanReact() const [defaultStrategies, setDefaultStrategies] = useState([]) - const [newStrategy, setNewStrategy] = useState() + const [newStrategy, setNewStrategy] = useState({ address: '', name: '', share: 0, index: '0' }) const [newAddress, setNewAddress] = useState() const [newName, setNewName] = useState() - const [selectValue, setSelectValue] = useState('') + const [selectValue, setSelectValue] = useState(['']) useEffect(() => { @@ -38,21 +41,18 @@ function AddNewStrategyButton() { fetchStragegies() }, [activeChain?.networkPassphrase]) - const { isOpen, onOpen, onClose } = useDisclosure() - const handleOpenModal = () => { - isOpen ? onClose() : onOpen() - } const resetForm = () => { setNewStrategy({ address: '', name: '', share: 0, index: '0' }) setNewAddress('') setNewName('') - setSelectValue('') + setSelectValue(['']) + setOpen(false) } const handleInputSelect = async (e: any) => { const value = e.target.value - setSelectValue(value) + await setSelectValue(value) const isDefaultStrategy = await defaultStrategies.find(strategy => strategy.address === value) if (!!isDefaultStrategy) { setNewStrategy(isDefaultStrategy) @@ -61,7 +61,7 @@ function AddNewStrategyButton() { const addStrategy = async () => { const isDefaultStrategy = await defaultStrategies.find(strategy => strategy.address === newStrategy?.address) - const hasEmptyFields = newStrategy?.address === '' || newStrategy?.name === '' || newName === '' || newAddress === '' + const hasEmptyFields = newStrategy?.address === '' || newStrategy?.name === '' const strategyExists = strategies.find((strategy: Strategy) => strategy.address === newStrategy?.address) if (strategyExists) { console.error('Strategy already exists') @@ -73,41 +73,46 @@ function AddNewStrategyButton() { } await dispatch(pushStrategy(newStrategy!)) resetForm() - isOpen ? onClose() : onOpen() } return ( - <> - - - - - Add new strategy - - - - - - - - - } - onClick={addStrategy} - /> - - - - + { setOpen(e.open) }} placement={'center'}> + + + + + + + + { handleInputSelect(e) }}> + {defaultStrategies.map((strategy) => { + return ( + + ) + })} + + + + + + + + + + + ) } diff --git a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx index 7b809f69..d6372293 100644 --- a/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx +++ b/apps/dapp/src/components/DeployVault/ConfirmDelpoyModal.tsx @@ -3,17 +3,9 @@ import { useAppDispatch, useAppSelector } from "@/store/lib/storeHooks" import { Box, Button, - CircularProgress, Link, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalFooter, - ModalHeader, - ModalOverlay, + ProgressCircleRoot, Text, - useSteps, } from "@chakra-ui/react" import { Address, @@ -26,12 +18,16 @@ import { useFactoryCallback, FactoryMethod } from '@/hooks/useFactory' import { VaultPreview } from "./VaultPreview"; import { DeploySteps } from "./DeploySteps"; import { useEffect, useState } from "react"; -import { WarningIcon, CheckCircleIcon, ExternalLinkIcon } from '@chakra-ui/icons' +import { PiWarningCircleFill } from "react-icons/pi"; +import { FaCheckCircle } from "react-icons/fa"; import { NewVaultState } from "@/store/lib/features/vaultStore"; import { useSorobanReact } from "@soroban-react/core"; import { randomBytes } from "crypto"; import { StrategyMethod, useStrategyCallback } from "@/hooks/useStrategy"; +import { LuExternalLink } from "react-icons/lu"; +import { ProgressCircleRing } from "../ui/progress-circle"; +import { DialogBody, DialogCloseTrigger, DialogFooter, DialogHeader, DialogTitle } from "../ui/dialog"; interface Status { isSuccess: boolean, @@ -50,9 +46,6 @@ export interface ChartData { } export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClose: () => void }) => { - const { goToNext, setActiveStep, activeStep } = useSteps({ - index: 0 - }); const sorobanContext = useSorobanReact(); const { activeChain } = sorobanContext; const factory = useFactoryCallback(); @@ -172,7 +165,7 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo ]; - goToNext(); + //goToNext(); let result: any; try { result = await factory( @@ -183,7 +176,7 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo } catch (e: any) { console.error(e) - setActiveStep(3) + //setActiveStep(3) setStatus({ ...status, hasError: true, @@ -199,7 +192,7 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo address: parsedResult } dispatch(pushVault(tempVault)); - setActiveStep(3); + //setActiveStep(3); setStatus({ ...status, isSuccess: true, @@ -218,7 +211,7 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo message: undefined, txHash: undefined }); - setActiveStep(0); + //setActiveStep(0); //await dispatch(resetStrategies()) onClose(); } @@ -259,15 +252,19 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo autoCloseModal(); } }, [status.isSuccess, status.hasError]) + const activeStep: number = 0; + //to-do Use chakra-ui stepper component return ( + <> - - - - Deploying {indexName === "" ? 'new index' : indexName} - - + + + Deploying {indexName === "" ? 'new index' : indexName} + + + + {activeStep == 0 && ( @@ -275,43 +272,44 @@ export const ConfirmDelpoyModal = ({ isOpen, onClose }: { isOpen: boolean, onClo {activeStep == 1 && ( Please, sign the transaction in your wallet. - + + + )} {(activeStep == 3 && status.hasError) && ( - + {`${status.message}`} )} {(activeStep == 3 && status.isSuccess === true && status.txHash != undefined) && ( <> - + {`${status.message}`} - - View on explorer + + View on explorer )} - + - + {(activeStep == 0 && !status.hasError) && ( )} - - - + + ) } \ No newline at end of file diff --git a/apps/dapp/src/components/DeployVault/DeploySteps.tsx b/apps/dapp/src/components/DeployVault/DeploySteps.tsx index a7efea41..f9936c25 100644 --- a/apps/dapp/src/components/DeployVault/DeploySteps.tsx +++ b/apps/dapp/src/components/DeployVault/DeploySteps.tsx @@ -1,5 +1,4 @@ -import { Stack, Step, StepIcon, StepIndicator, Stepper, StepSeparator, StepStatus, Text, useSteps } from "@chakra-ui/react" -import { WarningIcon } from '@chakra-ui/icons' +import { Stack, StepsItem, StepsList, StepsRoot, Text } from "@chakra-ui/react" const steps = [ { title: 'Review Vault', description: 'Review vault' }, @@ -8,10 +7,6 @@ const steps = [ ] export function DeploySteps({ activeStep, hasError }: { activeStep: number, hasError: boolean }) { - const { setActiveStep } = useSteps({ - index: 0, - count: steps.length, - }) const activeStepText = steps[activeStep]?.description @@ -20,16 +15,19 @@ export function DeploySteps({ activeStep, hasError }: { activeStep: number, hasE {activeStepText} - - {steps.map((step, index) => ( - + + + + + + + {/* {steps.map((step, index) => ( : } /> - - ))} - + ))} */} + ) } diff --git a/apps/dapp/src/components/DeployVault/DeployVault.tsx b/apps/dapp/src/components/DeployVault/DeployVault.tsx index 7c86cf12..b698a579 100644 --- a/apps/dapp/src/components/DeployVault/DeployVault.tsx +++ b/apps/dapp/src/components/DeployVault/DeployVault.tsx @@ -1,12 +1,13 @@ import { useState } from 'react' import { Card, - Button, Grid, GridItem, Container, Input, - Text, + Button, + Box, + DialogTrigger, } from '@chakra-ui/react' import ItemSlider from './Slider' import AddNewStrategyButton from './AddNewStrategyButton' @@ -14,6 +15,7 @@ import { useAppDispatch, useAppSelector } from '@/store/lib/storeHooks' import { ConfirmDelpoyModal } from './ConfirmDelpoyModal' import { setName } from '@/store/lib/features/vaultStore' import { Strategy } from '@/store/lib/features/walletStore' +import { DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogRoot, DialogTitle } from '../ui/dialog' export const DeployVault = () => { const dispatch = useAppDispatch() @@ -30,9 +32,8 @@ export const DeployVault = () => { } return ( - - - + + { {strategies.map((strategy, index) => ( ))} + {strategies.length > 0 &&

Total: {totalValues}%

-
- -
-
+ + } + + + setOpenConfirm(e.open)}> + + + + + + + + + + + + ) } diff --git a/apps/dapp/src/components/DeployVault/Slider.tsx b/apps/dapp/src/components/DeployVault/Slider.tsx index 1241f419..d3ad0f3a 100644 --- a/apps/dapp/src/components/DeployVault/Slider.tsx +++ b/apps/dapp/src/components/DeployVault/Slider.tsx @@ -1,21 +1,17 @@ import React, { useEffect } from 'react' import { - Slider, - SliderTrack, - SliderFilledTrack, - SliderThumb, - Button, - Tooltip, Grid, GridItem, Input, - InputGroup, - InputRightAddon, - IconButton + IconButton, + HStack, + Button } from '@chakra-ui/react' -import { DeleteIcon } from '@chakra-ui/icons' +import { FaRegTrashCan } from "react-icons/fa6"; import { useAppDispatch, useAppSelector } from '@/store/lib/storeHooks' import { setStrategyValue, removeStrategy } from '@/store/lib/features/vaultStore' +import { InputGroup } from '../ui/input-group' +import { Slider } from '../ui/slider' function ItemSlider({ @@ -28,11 +24,8 @@ function ItemSlider({ name?: string, }) { const dispatch = useAppDispatch() - const [showTooltip, setShowTooltip] = React.useState(false) - const totalShares = useAppSelector(state => state.newVault.totalValues) const [inputValue, setInputValue] = React.useState(share) - const setVal = (val: number) => { const total = totalShares! - share + val if (total <= 100) { @@ -96,72 +89,59 @@ function ItemSlider({ }, [share]) return ( - + <> +

{name ? name : address}

} variant='outline' colorScheme='red' size={'xs'} - /> + > + +
- - + + + + + + + - % - - - - { setVal(v) }} - onMouseEnter={() => setShowTooltip(true)} - onMouseLeave={() => setShowTooltip(false)} - onChangeEnd={(val) => setVal(val)}> - - - - setVal(val.value[0])} + /> + + + - -
+ Set Max + + +
+ ) } diff --git a/apps/dapp/src/components/DeployVault/VaultPreview.tsx b/apps/dapp/src/components/DeployVault/VaultPreview.tsx index 05ea2206..8b8a0b25 100644 --- a/apps/dapp/src/components/DeployVault/VaultPreview.tsx +++ b/apps/dapp/src/components/DeployVault/VaultPreview.tsx @@ -2,32 +2,24 @@ import React, { useState } from 'react' import { Box, Table, - Thead, - Tbody, - Tr, - Th, - Td, - TableContainer, - Tooltip, Text, Grid, GridItem, Input, - FormControl, - FormLabel, - FormErrorMessage, - InputGroup, IconButton, - InputRightElement, + Fieldset, + Stack, } from '@chakra-ui/react' import { shortenAddress } from '@/helpers/shortenAddress' -import { PieChart } from '@mui/x-charts' + import { ChartData } from './ConfirmDelpoyModal' import { setEmergencyManager, setFeeReceiver, setManager } from '@/store/lib/features/vaultStore' import { useAppDispatch } from '@/store/lib/storeHooks' import { StrKey } from '@stellar/stellar-sdk' -import { LinkIcon } from '@chakra-ui/icons' +import { FaRegPaste } from "react-icons/fa6"; import { useSorobanReact } from '@soroban-react/core' +import { InputGroup } from '../ui/input-group' +import { Tooltip } from '../ui/tooltip' interface FormControlInterface { @@ -146,7 +138,7 @@ export const VaultPreview = ({ data }: { data: ChartData[] }) => { return ( <> - { ]} width={500} height={200} - /> + /> */} Strategies - - - - - - - - - - + + + + Name + Address + Percentage + + + {data.map((strategy: ChartData, index: number) => ( - - - - - + + {strategy.label} + + + {strategy.address ? shortenAddress(strategy.address) : '-'} + + + {strategy.value}% + ))} - -
NameAddressPercentage
{strategy.label} - - {strategy.address ? shortenAddress(strategy.address) : '-'} - - {strategy.value}%
-
+ + { gap={6} > - - Manager - - handleManagerChange(event?.target.value)} - value={formControl.manager.value} - placeholder='GAFS3TLVM...' - sx={{ pr: 8 }} - /> - - + Manager + + } - bg={'whiteAlpha.500'} size={'sm'} - backdropFilter={'blur(1px)'} onClick={() => handleManagerChange(address!)} - /> - - - - A valid Stellar / Soroban address is required. - + > + + + + }> + handleManagerChange(event?.target.value)} + value={formControl.manager.value} + placeholder='GAFS3TLVM...' + /> + + + A valid Stellar / Soroban address is required. + - - Emergency manager - - handleEmergencyManagerChange(event?.target.value)} - value={formControl.emergencyManager.value} - placeholder='GAFS3TLVM...' - sx={{ pr: 8 }} - /> - - + Emergency manager + + } - bg={'whiteAlpha.500'} size={'sm'} - backdropFilter={'blur(1px)'} onClick={() => handleEmergencyManagerChange(address!)} - /> - - - - A valid Stellar / Soroban address is required. - + > + + + + }> + handleEmergencyManagerChange(event?.target.value)} + value={formControl.emergencyManager.value} + placeholder='GAFS3TLVM...' + /> + + + A valid Stellar / Soroban address is required. + - - Fee reciever - - handleFeeReceiverChange(event?.target.value)} - value={formControl.feeReceiver.value} - placeholder='GAFS3TLVM...' - sx={{ pr: 8 }} - /> - - + Fee reciever + + } - bg={'whiteAlpha.500'} size={'sm'} - backdropFilter={'blur(1px)'} onClick={() => handleFeeReceiverChange(address!)} - /> - - - - A valid Stellar / Soroban address is required. - + > + + + + }> + handleFeeReceiverChange(event?.target.value)} + value={formControl.feeReceiver.value} + placeholder='GAFS3TLVM...' + /> + + + A valid Stellar / Soroban address is required. + diff --git a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx index 43a65e14..20f4fcd9 100644 --- a/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx +++ b/apps/dapp/src/components/InteractWithVault/InteractWithVault.tsx @@ -2,23 +2,23 @@ import { VaultMethod, useVaultCallback } from '@/hooks/useVault' import { useAppSelector } from '@/store/lib/storeHooks' import { Button, - Card, Input, Textarea, Text, Grid, GridItem, - InputGroup, - InputRightAddon, - Select + Stack, + InputAddon, + NativeSelectField, } from '@chakra-ui/react' import { useSorobanReact } from '@soroban-react/core' import { Address, nativeToScVal, scValToNative, xdr } from '@stellar/stellar-sdk' import React, { useEffect, useState } from 'react' +import { DialogBody, DialogContent, DialogHeader } from '../ui/dialog' +import { NativeSelectRoot } from '../ui/native-select' export const InteractWithVault = () => { const [amount, set_amount] = useState(0) - const [isLoading, setIsLoading] = useState(false) const selectedVault = useAppSelector(state => state.wallet.vaults.selectedVault) const vaultMethod = selectedVault?.method @@ -63,54 +63,68 @@ export const InteractWithVault = () => { return ( <> - - - - {selectedVault?.method === 'deposit' ? 'Deposit to' : 'Withdraw from'}: - - -