From 4c785465473407a90af8d9d7a87164daed376981 Mon Sep 17 00:00:00 2001 From: Daniil Polienko Date: Tue, 6 Feb 2024 19:39:46 +0400 Subject: [PATCH 01/60] feat: refactor input components --- components/apps/disperse/index.tsx | 231 ------------------ .../designSystem/SmolTokenAmountInput.tsx | 79 ++---- components/designSystem/SmolTokenSelector.tsx | 44 ++++ .../designSystem/SmolTokenSelectorButton.tsx | 52 ++++ .../disperse => sections/Disperse}/Wizard.tsx | 0 components/sections/Disperse/index.tsx | 148 +++++++++++ .../Disperse}/useDisperse.tsx | 16 +- package.json | 202 +++++++-------- pages/apps/disperse.tsx | 20 +- yarn.lock | 8 +- 10 files changed, 400 insertions(+), 400 deletions(-) delete mode 100644 components/apps/disperse/index.tsx create mode 100644 components/designSystem/SmolTokenSelector.tsx create mode 100644 components/designSystem/SmolTokenSelectorButton.tsx rename components/{apps/disperse => sections/Disperse}/Wizard.tsx (100%) create mode 100644 components/sections/Disperse/index.tsx rename components/{apps/disperse => sections/Disperse}/useDisperse.tsx (87%) diff --git a/components/apps/disperse/index.tsx b/components/apps/disperse/index.tsx deleted file mode 100644 index c1d5c520..00000000 --- a/components/apps/disperse/index.tsx +++ /dev/null @@ -1,231 +0,0 @@ -import React, {Fragment, memo, useCallback} from 'react'; -import IconSquareMinus from 'components/icons/IconSquareMinus'; -import IconSquarePlus from 'components/icons/IconSquarePlus'; -import {useTokensWithBalance} from 'hooks/useTokensWithBalance'; -import { - handleInputChangeEventValue, - isZeroAddress, - parseUnits, - toAddress, - toNormalizedBN -} from '@builtbymom/web3/utils'; -import {newVoidRow, useDisperse} from '@disperse/useDisperse'; -import {AddressLikeInput} from '@common/AddressLikeInput'; -import {MultipleTokenSelector} from '@common/TokenInput/TokenSelector'; - -import {DisperseWizard} from './Wizard'; - -import type {ReactElement} from 'react'; -import type {TAddress, TNormalizedBN, TToken} from '@builtbymom/web3/types'; -import type {TDisperseConfiguration} from '@disperse/useDisperse'; - -function AmountToSendInput(props: { - token: TToken | undefined; - amount: TNormalizedBN | undefined; - onChange: (amount: TNormalizedBN) => void; -}): ReactElement { - return ( -
-
- e.preventDefault()} - min={0} - step={1 / 10 ** (props.token?.decimals || 18)} - inputMode={'numeric'} - placeholder={'0'} - pattern={'^((?:0|[1-9]+)(?:.(?:d+?[1-9]|[1-9]))?)$'} - onChange={e => props.onChange(handleInputChangeEventValue(e, props.token?.decimals || 18))} - value={props.amount?.normalized} - /> -
-
- ); -} - -const Disperse = memo(function Disperse(): ReactElement { - const {configuration, dispatchConfiguration} = useDisperse(); - const {tokensWithBalance} = useTokensWithBalance(); - - const checkAlreadyExists = useCallback( - (UUID: string, address: TAddress): boolean => { - if (isZeroAddress(address)) { - return false; - } - return configuration.receivers.some((row): boolean => row.UUID !== UUID && row.address === address); - }, - [configuration.receivers] - ); - - function onHandleMultiplePaste(_: string, pasted: string): void { - const separators = [' ', '-', ';', ',', '.']; - const addressAmounts = pasted - .replaceAll(' ', '') - .replaceAll('\t', '') - .split('\n') - .map((line): [string, string] => { - //remove all separators that are next to each other - let cleanedLine = separators.reduce( - (acc, separator): string => acc.replaceAll(separator + separator, separator), - line - ); - for (let i = 0; i < 3; i++) { - cleanedLine = separators.reduce( - (acc, separator): string => acc.replaceAll(separator + separator, separator), - cleanedLine - ); - } - - const addressAmount = cleanedLine.split( - separators.find((separator): boolean => cleanedLine.includes(separator)) ?? ' ' - ); - return [addressAmount[0], addressAmount[1]]; - }); - - const newRows = addressAmounts.map((addressAmount): TDisperseConfiguration['receivers'][0] => { - const row = newVoidRow(); - row.address = toAddress(addressAmount[0]); - row.label = String(addressAmount[0]); - try { - if (addressAmount[1].includes('.') || addressAmount[1].includes(',')) { - const normalizedAmount = Number(addressAmount[1]); - const raw = parseUnits(normalizedAmount, configuration.tokenToSend?.decimals || 18); - const amount = toNormalizedBN(raw, configuration.tokenToSend?.decimals || 18); - row.amount = amount; - } else { - const amount = toNormalizedBN(addressAmount[1], configuration.tokenToSend?.decimals || 18); - row.amount = amount; - } - } catch (e) { - row.amount = toNormalizedBN(0n, configuration.tokenToSend?.decimals || 18); - } - return row; - }); - - dispatchConfiguration({ - type: 'ADD_RECEIVERS', - payload: newRows.filter((row): boolean => { - if (!row.address || isZeroAddress(row.address)) { - return false; - } - if (checkAlreadyExists(row.UUID, row.address)) { - return false; - } - if (!row.amount || row.amount.raw === 0n) { - return false; - } - return true; - }) - }); - } - - return ( -
-
-
-
- {'Who gets what?'} -

- { - 'Drop the wallet, ENS, or Lens handle of who you want to receive the tokens, and enter the amount each address should receive. Add more receivers by clicking the +. Clicking is fun.' - } -

-
- -
=> e.preventDefault()} - className={'mt-6 grid w-full grid-cols-12 flex-row items-start justify-between gap-4'}> -
- {'Token to send'} - - dispatchConfiguration({type: 'SET_TOKEN_TO_SEND', payload: newToken}) - } - /> -
- -
-
-

{'Receivers'}

-

{'Amount'}

-
-
- {configuration.receivers.map((receiver): ReactElement => { - return ( - - - dispatchConfiguration({ - type: 'UPD_RECEIVER_BY_UUID', - payload: {...receiver, label} - }) - } - onChange={(address): void => { - dispatchConfiguration({ - type: 'UPD_RECEIVER_BY_UUID', - payload: {...receiver, address: toAddress(address)} - }); - }} - onPaste={onHandleMultiplePaste} - /> -
- { - dispatchConfiguration({ - type: 'UPD_RECEIVER_BY_UUID', - payload: {...receiver, amount} - }); - }} - /> - - dispatchConfiguration({ - type: 'DEL_RECEIVER_BY_UUID', - payload: receiver.UUID - }) - } - className={ - 'size-4 cursor-pointer text-neutral-400 transition-colors hover:text-neutral-900' - } - /> - - dispatchConfiguration({ - type: 'ADD_SIBLING_RECEIVER_FROM_UUID', - payload: receiver.UUID - }) - } - className={ - 'size-4 cursor-pointer text-neutral-400 transition-colors hover:text-neutral-900' - } - /> -
-
- ); - })} -
-
- - - -
-
-
- ); -}); - -export default Disperse; diff --git a/components/designSystem/SmolTokenAmountInput.tsx b/components/designSystem/SmolTokenAmountInput.tsx index 40b521c6..cbf64cb4 100644 --- a/components/designSystem/SmolTokenAmountInput.tsx +++ b/components/designSystem/SmolTokenAmountInput.tsx @@ -1,21 +1,11 @@ import React, {useCallback, useState} from 'react'; import {getNewInput} from 'components/sections/Send/useSendFlow'; -import {useBalancesCurtain} from 'contexts/useBalancesCurtain'; import {parseUnits} from 'viem'; -import { - cl, - fromNormalized, - isAddress, - percentOf, - toBigInt, - toNormalizedBN, - zeroNormalizedBN -} from '@builtbymom/web3/utils'; -import {IconChevron} from '@icons/IconChevron'; -import {IconWallet} from '@icons/IconWallet'; +import {cl, fromNormalized, percentOf, toBigInt, toNormalizedBN, zeroNormalizedBN} from '@builtbymom/web3/utils'; import {useDeepCompareEffect} from '@react-hookz/web'; import {handleLowAmount} from '@utils/helpers'; -import {ImageWithFallback} from '@common/ImageWithFallback'; + +import {SmolTokenSelectorButton} from './SmolTokenSelectorButton'; import type {ReactElement} from 'react'; import type {TNormalizedBN, TToken} from '@builtbymom/web3/types'; @@ -48,7 +38,6 @@ export function SmolTokenAmountInput({ initialValue }: TTokenAmountInput): ReactElement { const [isFocused, set_isFocused] = useState(false); - const {onOpenCurtain} = useBalancesCurtain(); const {token} = value; @@ -114,18 +103,23 @@ export function SmolTokenAmountInput({ }); }; - const onSelectToken = (valueBigInt: bigint, token: TToken): void => { + const onSelectToken = (token: TToken): void => { + onSetValue({ + token, + isValid: true, + error: undefined + }); + }; + + const onSetTokenValue = (valueBigInt: bigint, token: TToken): void => { if (token.balance.raw < valueBigInt) { return onSetValue({ - token, normalizedBigAmount: toNormalizedBN(valueBigInt, token?.decimals || 18), isValid: false, error: 'Insufficient balance' }); } - onSetValue({ - token, normalizedBigAmount: toNormalizedBN(valueBigInt, token?.decimals || 18), isValid: true, error: undefined @@ -150,7 +144,8 @@ export function SmolTokenAmountInput({ const normalizedAmount = String( toNormalizedBN(initialValue.amount, initialValue?.token?.decimals || 18).normalized ); - onSelectToken(initialValue.amount, initialValue.token); + onSelectToken(initialValue.token); + onSetTokenValue(initialValue.amount, initialValue.token); onChange(normalizedAmount, initialTokenBalance, initialValue.token); } @@ -221,44 +216,14 @@ export function SmolTokenAmountInput({ - +
+ +
); diff --git a/components/designSystem/SmolTokenSelector.tsx b/components/designSystem/SmolTokenSelector.tsx new file mode 100644 index 00000000..514946b2 --- /dev/null +++ b/components/designSystem/SmolTokenSelector.tsx @@ -0,0 +1,44 @@ +import {useCallback, useState} from 'react'; +import {cl} from '@builtbymom/web3/utils'; + +import {SmolTokenSelectorButton} from './SmolTokenSelectorButton'; + +import type {TToken} from '@builtbymom/web3/types'; + +export function SmolTokenSelector({ + onSelectToken, + token +}: { + onSelectToken: (token: TToken) => void; + token: TToken | undefined; +}): JSX.Element { + const [isFocused] = useState(false); + + const getBorderColor = useCallback((): string => { + if (isFocused) { + return 'border-neutral-600'; + } + // if (value.isValid === false) { + // return 'border-red'; + // } + return 'border-neutral-400'; + }, [isFocused]); + + return ( +
+
+ +
+
+ ); +} diff --git a/components/designSystem/SmolTokenSelectorButton.tsx b/components/designSystem/SmolTokenSelectorButton.tsx new file mode 100644 index 00000000..266dd65b --- /dev/null +++ b/components/designSystem/SmolTokenSelectorButton.tsx @@ -0,0 +1,52 @@ +import {useBalancesCurtain} from 'contexts/useBalancesCurtain'; +import {cl, parseUnits} from '@builtbymom/web3/utils'; +import {IconChevron} from '@icons/IconChevron'; +import {ImageWithFallback} from '@common/ImageWithFallback'; + +import type {TToken} from '@builtbymom/web3/types'; + +export function SmolTokenSelectorButton({ + onSelectToken, + onSetTokenValue, + token, + amount +}: { + onSelectToken: (token: TToken) => void; + onSetTokenValue?: (value: bigint, token: TToken) => void; + token: TToken | undefined; + amount?: string; +}): JSX.Element { + const {onOpenCurtain} = useBalancesCurtain(); + + return ( + <> + + + ); +} diff --git a/components/apps/disperse/Wizard.tsx b/components/sections/Disperse/Wizard.tsx similarity index 100% rename from components/apps/disperse/Wizard.tsx rename to components/sections/Disperse/Wizard.tsx diff --git a/components/sections/Disperse/index.tsx b/components/sections/Disperse/index.tsx new file mode 100644 index 00000000..b1d5ac9e --- /dev/null +++ b/components/sections/Disperse/index.tsx @@ -0,0 +1,148 @@ +import React, {memo} from 'react'; +import {SmolTokenSelector} from 'components/designSystem/SmolTokenSelector'; + +import {useDisperse} from './useDisperse'; + +import type {ReactElement} from 'react'; +import type {TToken} from '@builtbymom/web3/types'; + +// function AmountToSendInput(props: { +// token: TToken | undefined; +// amount: TNormalizedBN | undefined; +// onChange: (amount: TNormalizedBN) => void; +// }): ReactElement { +// return ( +//
+//
+// e.preventDefault()} +// min={0} +// step={1 / 10 ** (props.token?.decimals || 18)} +// inputMode={'numeric'} +// placeholder={'0'} +// pattern={'^((?:0|[1-9]+)(?:.(?:d+?[1-9]|[1-9]))?)$'} +// onChange={e => props.onChange(handleInputChangeEventValue(e, props.token?.decimals || 18))} +// value={props.amount?.normalized} +// /> +//
+//
+// ); +// } + +const Disperse = memo(function Disperse(): ReactElement { + const {configuration, dispatchConfiguration} = useDisperse(); + + // const checkAlreadyExists = useCallback( + // (UUID: string, address: TAddress): boolean => { + // if (isZeroAddress(address)) { + // return false; + // } + // return configuration.receivers.some((row): boolean => row.UUID !== UUID && row.address === address); + // }, + // [configuration.receivers] + // ); + + // function onHandleMultiplePaste(_: string, pasted: string): void { + // const separators = [' ', '-', ';', ',', '.']; + // const addressAmounts = pasted + // .replaceAll(' ', '') + // .replaceAll('\t', '') + // .split('\n') + // .map((line): [string, string] => { + // //remove all separators that are next to each other + // let cleanedLine = separators.reduce( + // (acc, separator): string => acc.replaceAll(separator + separator, separator), + // line + // ); + // for (let i = 0; i < 3; i++) { + // cleanedLine = separators.reduce( + // (acc, separator): string => acc.replaceAll(separator + separator, separator), + // cleanedLine + // ); + // } + + // const addressAmount = cleanedLine.split( + // separators.find((separator): boolean => cleanedLine.includes(separator)) ?? ' ' + // ); + // return [addressAmount[0], addressAmount[1]]; + // }); + + // const newRows = addressAmounts.map((addressAmount): TDisperseConfiguration['receivers'][0] => { + // const row = newVoidRow(); + // row.address = toAddress(addressAmount[0]); + // row.label = String(addressAmount[0]); + // try { + // if (addressAmount[1].includes('.') || addressAmount[1].includes(',')) { + // const normalizedAmount = Number(addressAmount[1]); + // const raw = parseUnits(normalizedAmount, configuration.tokenToSend?.decimals || 18); + // const amount = toNormalizedBN(raw, configuration.tokenToSend?.decimals || 18); + // row.amount = amount; + // } else { + // const amount = toNormalizedBN(addressAmount[1], configuration.tokenToSend?.decimals || 18); + // row.amount = amount; + // } + // } catch (e) { + // row.amount = toNormalizedBN(0n, configuration.tokenToSend?.decimals || 18); + // } + // return row; + // }); + + // dispatchConfiguration({ + // type: 'ADD_RECEIVERS', + // payload: newRows.filter((row): boolean => { + // if (!row.address || isZeroAddress(row.address)) { + // return false; + // } + // if (checkAlreadyExists(row.UUID, row.address)) { + // return false; + // } + // if (!row.amount || row.amount.raw === 0n) { + // return false; + // } + // return true; + // }) + // }); + // } + const onSelectToken = (token: TToken): void => { + dispatchConfiguration({type: 'SET_TOKEN_TO_SEND', payload: token}); + }; + + return ( +
+
+

{'Receiver'}

+ +
+ {/*
+

{'Token'}

+ {configuration.inputs.map(input => ( +
+ +
+ ))} +
+
+ +
+ + */} +
+ ); +}); + +export default Disperse; diff --git a/components/apps/disperse/useDisperse.tsx b/components/sections/Disperse/useDisperse.tsx similarity index 87% rename from components/apps/disperse/useDisperse.tsx rename to components/sections/Disperse/useDisperse.tsx index fab1730b..0543d529 100755 --- a/components/apps/disperse/useDisperse.tsx +++ b/components/sections/Disperse/useDisperse.tsx @@ -1,7 +1,9 @@ import React, {createContext, useContext, useMemo, useReducer, useState} from 'react'; +import {optionalRenderProps} from '@utils/react/optionalRenderProps'; -import type {Dispatch} from 'react'; +import type {Dispatch, ReactElement} from 'react'; import type {TAddress, TNormalizedBN, TToken} from '@builtbymom/web3/types'; +import type {TOptionalRenderProps} from '@utils/react/optionalRenderProps'; export type TDisperseReceiver = { address: TAddress | undefined; @@ -92,7 +94,11 @@ const configurationReducer = (state: TDisperseConfiguration, action: TDisperseAc }; const DisperseContext = createContext(defaultProps); -export const DisperseContextApp = ({children}: {children: React.ReactElement}): React.ReactElement => { +export const DisperseContextApp = ({ + children +}: { + children: TOptionalRenderProps; +}): React.ReactElement => { const [isDispersed, set_isDispersed] = useState(false); const [configuration, dispatch] = useReducer(configurationReducer, defaultProps.configuration); @@ -114,7 +120,11 @@ export const DisperseContextApp = ({children}: {children: React.ReactElement}): [configuration, isDispersed] ); - return {children}; + return ( + + {optionalRenderProps(children, contextValue)} + + ); }; export const useDisperse = (): TDisperse => { diff --git a/package.json b/package.json index dfcb7c6e..fe460f9d 100644 --- a/package.json +++ b/package.json @@ -1,103 +1,103 @@ { - "name": "smol", - "version": "1.0.0", - "private": false, - "homepage": "./", - "scripts": { - "dev": "next", - "dev:ts": "tsc --watch", - "start": "tsc && next build && next start", - "build": "tsc && next build", - "prepare": "husky install", - "prettier": "prettier --check \"./**/**/*.{json,js,ts,tsx,scss}\"", - "prettier-format": "prettier --config .prettierrc \"./**/**/*.{json,js,ts,tsx,scss,md}\" --write", - "export": "tsc && next build && next export -o ipfs", - "lint": "eslint . --ext .js,.jsx,.ts,.tsx" - }, - "dependencies": { - "@closeio/use-abortable-effect": "^1.0.0", - "@gnosis.pm/gp-v2-contracts": "^1.1.2", - "@gnosis.pm/safe-apps-react-sdk": "^4.6.2", - "@headlessui/react": "^1.7.18", - "@popperjs/core": "^2.11.8", - "@radix-ui/react-dialog": "^1.0.5", - "@radix-ui/react-dropdown-menu": "^2.0.6", - "@radix-ui/react-popover": "^1.0.7", - "@radix-ui/react-select": "^2.0.0", - "@radix-ui/react-tooltip": "^1.0.7", - "@rainbow-me/rainbowkit": "^1.3.3", - "@react-hookz/web": "^24.0.2", - "@tailwindcss/forms": "^0.5.7", - "@tailwindcss/typography": "^0.5.10", - "@vercel/analytics": "^1.1.2", - "@wagmi/core": "^1.4.3", - "@yearn-finance/web-lib": "^3.0.133", - "axios": "^1.6.7", - "cmdk": "^0.2.0", - "date-fns": "^3.3.1", - "dayjs": "^1.11.10", - "formidable": "^3.5.1", - "framer-motion": "^11.0.3", - "graphql-request": "^6.1.0", - "html2canvas": "^1.4.1", - "identicon.js": "^2.3.3", - "lottie-react": "^2.4.0", - "next": "^13.5.4", - "next-pwa": "^5.6.0", - "next-seo": "^6.4.0", - "papaparse": "^5.4.1", - "react": "^18.2.0", - "react-day-picker": "^8.10.0", - "react-dom": "^18.2.0", - "react-dom-confetti": "^0.2.0", - "react-popper": "^2.3.0", - "sharp": "^0.33.2", - "swr": "^2.2.4", - "tailwindcss": "^3.4.1", - "tailwindcss-animate": "^1.0.7", - "telegraf": "^4.15.3", - "use-indexeddb": "^2.0.2", - "uuid": "^9.0.1", - "viem": "^1.15.4", - "wagmi": "^1.4.3", - "web3-eth-abi": "^1.10.0" - }, - "devDependencies": { - "@builtbymom/web3": "^0.0.36", - "@commitlint/cli": "^18.6.0", - "@commitlint/config-conventional": "^18.6.0", - "@total-typescript/ts-reset": "^0.5.1", - "@types/node": "^20.11.7", - "@types/nprogress": "^0.2.3", - "@types/react": "^18.2.48", - "@types/react-dom": "^18.2.18", - "@typescript-eslint/eslint-plugin": "^6.19.1", - "@typescript-eslint/parser": "^6.19.1", - "autoprefixer": "^10.4.17", - "babel-loader": "^9.1.3", - "bun-types": "^1.0.25", - "eslint": "^8.56.0", - "eslint-config-next": "^14.1.0", - "eslint-config-prettier": "^9.1.0", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-brackets": "^0.1.3", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-simple-import-sort": "^10.0.0", - "eslint-plugin-tailwindcss": "^3.14.1", - "eslint-plugin-unused-imports": "^3.0.0", - "husky": "^9.0.6", - "lint-staged": "^15.2.0", - "next-transpile-modules": "^10.0.1", - "postcss": "^8.4.33", - "postcss-import": "^16.0.0", - "postcss-nesting": "^12.0.2", - "prettier": "^3.2.4", - "sass": "^1.70.0", - "stylelint": "^16.2.0", - "stylelint-config-standard": "^36.0.0", - "ts-loader": "^9.5.1", - "typescript": "^5.3.3" - } + "name": "smol", + "version": "1.0.0", + "private": false, + "homepage": "./", + "scripts": { + "dev": "next", + "dev:ts": "tsc --watch", + "start": "tsc && next build && next start", + "build": "tsc && next build", + "prepare": "husky install", + "prettier": "prettier --check \"./**/**/*.{json,js,ts,tsx,scss}\"", + "prettier-format": "prettier --config .prettierrc \"./**/**/*.{json,js,ts,tsx,scss,md}\" --write", + "export": "tsc && next build && next export -o ipfs", + "lint": "eslint . --ext .js,.jsx,.ts,.tsx" + }, + "dependencies": { + "@closeio/use-abortable-effect": "^1.0.0", + "@gnosis.pm/gp-v2-contracts": "^1.1.2", + "@gnosis.pm/safe-apps-react-sdk": "^4.6.2", + "@headlessui/react": "^1.7.18", + "@popperjs/core": "^2.11.8", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-tooltip": "^1.0.7", + "@rainbow-me/rainbowkit": "^1.3.3", + "@react-hookz/web": "^24.0.2", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.10", + "@vercel/analytics": "^1.1.2", + "@wagmi/core": "^1.4.3", + "@yearn-finance/web-lib": "^3.0.133", + "axios": "^1.6.7", + "cmdk": "^0.2.0", + "date-fns": "^3.3.1", + "dayjs": "^1.11.10", + "formidable": "^3.5.1", + "framer-motion": "^11.0.3", + "graphql-request": "^6.1.0", + "html2canvas": "^1.4.1", + "identicon.js": "^2.3.3", + "lottie-react": "^2.4.0", + "next": "^13.5.4", + "next-pwa": "^5.6.0", + "next-seo": "^6.4.0", + "papaparse": "^5.4.1", + "react": "^18.2.0", + "react-day-picker": "^8.10.0", + "react-dom": "^18.2.0", + "react-dom-confetti": "^0.2.0", + "react-popper": "^2.3.0", + "sharp": "^0.33.2", + "swr": "^2.2.4", + "tailwindcss": "^3.4.1", + "tailwindcss-animate": "^1.0.7", + "telegraf": "^4.15.3", + "use-indexeddb": "^2.0.2", + "uuid": "^9.0.1", + "viem": "^1.15.4", + "wagmi": "^1.4.3", + "web3-eth-abi": "^1.10.0" + }, + "devDependencies": { + "@builtbymom/web3": "^0.0.36", + "@commitlint/cli": "^18.6.0", + "@commitlint/config-conventional": "^18.6.0", + "@total-typescript/ts-reset": "^0.5.1", + "@types/node": "^20.11.7", + "@types/nprogress": "^0.2.3", + "@types/react": "^18.2.48", + "@types/react-dom": "^18.2.18", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", + "autoprefixer": "^10.4.17", + "babel-loader": "^9.1.3", + "bun-types": "^1.0.25", + "eslint": "^8.56.0", + "eslint-config-next": "^14.1.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-brackets": "^0.1.3", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-plugin-tailwindcss": "^3.14.1", + "eslint-plugin-unused-imports": "^3.0.0", + "husky": "^9.0.6", + "lint-staged": "^15.2.0", + "next-transpile-modules": "^10.0.1", + "postcss": "^8.4.33", + "postcss-import": "^16.0.0", + "postcss-nesting": "^12.0.2", + "prettier": "^3.2.4", + "sass": "^1.70.0", + "stylelint": "^16.2.0", + "stylelint-config-standard": "^36.0.0", + "ts-loader": "^9.5.1", + "typescript": "^5.3.3" + } } diff --git a/pages/apps/disperse.tsx b/pages/apps/disperse.tsx index bf8ee384..38036495 100755 --- a/pages/apps/disperse.tsx +++ b/pages/apps/disperse.tsx @@ -1,12 +1,24 @@ import React, {Fragment} from 'react'; import {DefaultSeo} from 'next-seo'; -import Disperse from '@disperse/index'; -import {DisperseContextApp} from '@disperse/useDisperse'; +import Disperse from 'components/sections/Disperse/index'; +import {DisperseContextApp} from 'components/sections/Disperse/useDisperse'; +import {BalancesCurtainContextApp} from 'contexts/useBalancesCurtain'; import type {ReactElement} from 'react'; function DispersePage(): ReactElement { - return ; + return ( + + {({configuration}) => ( + + + + )} + + ); } DispersePage.getLayout = function getLayout(page: ReactElement): ReactElement { @@ -38,7 +50,7 @@ DispersePage.getLayout = function getLayout(page: ReactElement): ReactElement { cardType: 'summary_large_image' }} /> - {page} + {page} ); }; diff --git a/yarn.lock b/yarn.lock index 7f935af8..aec0d8c1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -999,10 +999,10 @@ wagmi "^1.4.7" zod "^3.22.4" -"@builtbymom/web3@^0.0.33": - version "0.0.33" - resolved "https://registry.yarnpkg.com/@builtbymom/web3/-/web3-0.0.33.tgz#b0c109d6322420976fc14bd7cea97d59798c6a17" - integrity sha512-BgYbyMrEf7w3lSnCsjDtqfEn7oUjcW+hyrvPrEWsJ3HHoTNwKpq+Mh5jnT07zsHZX9u6rvRpJbZv+AifXHpQGQ== +"@builtbymom/web3@^0.0.36": + version "0.0.36" + resolved "https://registry.yarnpkg.com/@builtbymom/web3/-/web3-0.0.36.tgz#b60771a6fd95edde36bc26ec38767a3972190c9a" + integrity sha512-Ch5uusYPx963mxjm3RVLPAy1WdnQ+NLbSNtOl4+RTAnxZEOljPJDRlPecBDGpYDo+A4QsQ6oMF6HocZ/+CfAig== dependencies: "@rainbow-me/rainbowkit" "^1.3.0" "@react-hookz/web" "^24.0.2" From 96ebd0db72aca68532db3751fea22f05499ac125 Mon Sep 17 00:00:00 2001 From: Daniil Polienko Date: Sun, 11 Feb 2024 16:45:24 +0400 Subject: [PATCH 02/60] feat: init disperse v2 --- components/common/Primitives/Warning.tsx | 21 +- components/designSystem/SmolAddressInput.tsx | 2 +- components/designSystem/SmolAmountInput.tsx | 154 +++++++++++ .../designSystem/SmolTokenAmountInput.tsx | 9 +- .../DisperseAddressAndAmountInputs.tsx | 53 ++++ components/sections/Disperse/Wizard.tsx | 257 +++++++++--------- components/sections/Disperse/index.tsx | 39 +-- components/sections/Disperse/useDisperse.tsx | 95 ++++--- components/sections/Send/Wizard.tsx | 6 +- components/sections/Send/index.tsx | 8 +- components/sections/Send/useSendFlow.tsx | 8 +- utils/notifier.ts | 4 +- 12 files changed, 453 insertions(+), 203 deletions(-) create mode 100644 components/designSystem/SmolAmountInput.tsx create mode 100644 components/sections/Disperse/DisperseAddressAndAmountInputs.tsx diff --git a/components/common/Primitives/Warning.tsx b/components/common/Primitives/Warning.tsx index 079d536d..498af3a0 100644 --- a/components/common/Primitives/Warning.tsx +++ b/components/common/Primitives/Warning.tsx @@ -1,17 +1,19 @@ import {cl} from '@builtbymom/web3/utils'; -import type {ReactElement} from 'react'; +import type {ReactElement, ReactNode} from 'react'; export type TWarningType = 'error' | 'warning' | 'info'; export function Warning({ message, type, - shopType = false + statusIcon, + title }: { - message: string | ReactElement; + message: string | ReactNode; type: TWarningType; - shopType?: boolean; + statusIcon?: ReactElement; + title?: string; }): ReactElement { const getWarningColors = (): string => { if (type === 'error') { @@ -20,13 +22,16 @@ export function Warning({ if (type === 'warning') { return 'border-[#FF9900] text-[#FF9900] bg-[#FFF3D3]'; } - return 'border-neutral-600 text-neutral-700 bg-neutral-300'; + return 'border-neutral-600 text-neutral-700 bg-neutral-100'; }; return ( -
- {shopType && {type}} -

{message}

+
+ {title && {title}} +
+ {statusIcon &&
{statusIcon}
} + {message &&
{message}
} +
); } diff --git a/components/designSystem/SmolAddressInput.tsx b/components/designSystem/SmolAddressInput.tsx index 7ecda1f9..ffe4c869 100644 --- a/components/designSystem/SmolAddressInput.tsx +++ b/components/designSystem/SmolAddressInput.tsx @@ -227,7 +227,7 @@ export function SmolAddressInput({onSetValue, value, initialStateFromUrl}: TAddr }, [isFocused, value.isValid, isCheckingValidity]); return ( -
+