diff --git a/src/app/heartbeats/tx/[id]/page.tsx b/src/app/heartbeats/tx/[id]/page.tsx index 4a8f2caa4..68b91b84b 100644 --- a/src/app/heartbeats/tx/[id]/page.tsx +++ b/src/app/heartbeats/tx/[id]/page.tsx @@ -1,3 +1,4 @@ +import { CDN_URL } from '@/config'; import MainLayout from '@/layouts/MainLayout'; import TxExplorerModule from '@/modules/l2-rollup-detail/TxExplorer'; import { Metadata } from 'next'; @@ -6,6 +7,8 @@ const TITLE = 'Bitcoin Heartbeat | Welcome to the future of Bitcoin.'; const DESCRIPTION = 'Provide transparent and verifiable insights into Bitcoin rollups.'; +const THUMBNAIL = `${CDN_URL}/pages/bvm-studio/bvm-heartbeat-metadata.png`; + export const metadata: Metadata = { applicationName: TITLE, title: { @@ -22,7 +25,7 @@ export const metadata: Metadata = { }, images: [ { - url: '/heartbeat/metadata.png', + url: THUMBNAIL, width: 1200, height: 630, alt: TITLE, @@ -36,7 +39,7 @@ export const metadata: Metadata = { template: '', }, description: DESCRIPTION, - images: '/heartbeat/metadata.png', + images: THUMBNAIL, }, }; diff --git a/src/components/TextNumberTooSmallDecimal/index.tsx b/src/components/TextNumberTooSmallDecimal/index.tsx index 91bdead52..db0846708 100644 --- a/src/components/TextNumberTooSmallDecimal/index.tsx +++ b/src/components/TextNumberTooSmallDecimal/index.tsx @@ -1,11 +1,11 @@ -import { MIN_DECIMAL } from "@/constants/constants"; -import { formatCurrency } from "@/utils/format"; -import { Text } from "@chakra-ui/react"; -import BigNumber from "bignumber.js"; -import cs from "classnames"; -import { isNaN } from "lodash"; -import React, { useMemo } from "react"; -import s from "./styles.module.scss"; +import { MIN_DECIMAL } from '@/constants/constants'; +import { formatCurrency } from '@/utils/format'; +import { Text } from '@chakra-ui/react'; +import BigNumber from 'bignumber.js'; +import cs from 'classnames'; +import { isNaN } from 'lodash'; +import React, { useMemo } from 'react'; +import s from './styles.module.scss'; interface IProps { value: string; @@ -14,6 +14,7 @@ interface IProps { isSats?: boolean; hideSymbol?: boolean; decimals?: number; + symbol?: string; } const TextNumberTooSmallDecimal: React.FC = ({ @@ -23,6 +24,7 @@ const TextNumberTooSmallDecimal: React.FC = ({ isSats, hideSymbol, decimals = 2, + symbol, }) => { const parts = useMemo(() => { if ( @@ -34,7 +36,7 @@ const TextNumberTooSmallDecimal: React.FC = ({ @@ -49,7 +51,7 @@ const TextNumberTooSmallDecimal: React.FC = ({ className={cs(s.textContainer, className)} dangerouslySetInnerHTML={{ __html: `${formatCurrency(satAmount, 0, 2)}${ - hideSymbol ? "" : ' sats' + hideSymbol ? '' : ' sat' }`, }} style={style} @@ -62,7 +64,7 @@ const TextNumberTooSmallDecimal: React.FC = ({ diff --git a/src/components/TextNumberTooSmallDecimal/styles.module.scss b/src/components/TextNumberTooSmallDecimal/styles.module.scss index 25ff0a6a7..79d539fa0 100644 --- a/src/components/TextNumberTooSmallDecimal/styles.module.scss +++ b/src/components/TextNumberTooSmallDecimal/styles.module.scss @@ -1,11 +1,9 @@ .textContainer { - :global { - .decimal-number { - position: relative; - font-size: 70%; - top: 3px; - padding-inline: 2px; - font-weight: 700; - } + line-height: 140%; + display: inline-flex; + gap: 5px; + align-items: center; + span { + line-height: 140%; } } diff --git a/src/constants/home-content.tsx b/src/constants/home-content.tsx index 5470fd016..55bdbbd6a 100644 --- a/src/constants/home-content.tsx +++ b/src/constants/home-content.tsx @@ -227,7 +227,7 @@ export const STEP_2_SECTION = { bgColor: 'linear-gradient(138deg, rgba(179, 179, 179, 0.40) 1.72%, rgba(43, 43, 43, 0.32) 101.88%)', link: { - url: '/studio', + url: '/studio?template=6', target: '_blank', }, tags: [''], diff --git a/src/layouts/HeaderV4/menuConfig.ts b/src/layouts/HeaderV4/menuConfig.ts index e8ffe6172..a21df62ee 100644 --- a/src/layouts/HeaderV4/menuConfig.ts +++ b/src/layouts/HeaderV4/menuConfig.ts @@ -155,16 +155,15 @@ export const NAV_ITEMS_LEFT: Array = [ isNewWindow: false, isHide: false, }, - { - label: 'BVM', - href: '/bvm', + label: 'Ecosystem', + href: '/explore', isNewWindow: false, isHide: false, }, { - label: 'Ecosystem', - href: '/explore', + label: '$BVM', + href: '/bvm', isNewWindow: false, isHide: false, }, diff --git a/src/modules/ExploreModule/components/DappCard/index.tsx b/src/modules/ExploreModule/components/DappCard/index.tsx index 14fc10fd2..5c217c3e3 100644 --- a/src/modules/ExploreModule/components/DappCard/index.tsx +++ b/src/modules/ExploreModule/components/DappCard/index.tsx @@ -4,6 +4,7 @@ import Fade from '@interactive/Fade'; import ImagePlaceholder from '@components/ImagePlaceholder'; import Link from 'next/link'; import cn from 'classnames'; +import { Box } from '@chakra-ui/react'; export type TDappCardProps = { id?: string; @@ -24,7 +25,6 @@ export default function DappCard({ idx, ...props }: TDappCardProps): React.JSX.Element { - console.log('props.bgColor', props.bgColor); const { link } = props; return ( @@ -36,14 +36,19 @@ export default function DappCard({ })} style={{ background: props.bgColor }} > -
+ -
+

{props.title}

f.section === section.key) ?.map((item) => { - let checked = false; return item.fields.map((field) => { + let checked = false; + if (allThisDappForm.length > 0) { for (const key in formDappSignal.value) { if ( diff --git a/src/modules/blockchains/Buy/component4/Button/index.tsx b/src/modules/blockchains/Buy/component4/Button/index.tsx index 41ef220b8..4e22215ca 100644 --- a/src/modules/blockchains/Buy/component4/Button/index.tsx +++ b/src/modules/blockchains/Buy/component4/Button/index.tsx @@ -25,6 +25,8 @@ type DefaultButtonProps = { shape?: ButtonShape; icon?: boolean; disabled?: boolean; + dappKey?: string; + name?: string; }; type Props = DefaultButtonProps & ButtonProps; diff --git a/src/modules/blockchains/Buy/component4/CustomEdge/index.tsx b/src/modules/blockchains/Buy/component4/CustomEdge/index.tsx index 8f7da2d09..72cb36a24 100644 --- a/src/modules/blockchains/Buy/component4/CustomEdge/index.tsx +++ b/src/modules/blockchains/Buy/component4/CustomEdge/index.tsx @@ -1,32 +1,51 @@ -import { BaseEdge, EdgeLabelRenderer, EdgeProps, getSmoothStepPath, useReactFlow } from '@xyflow/react'; +import { + BaseEdge, + EdgeLabelRenderer, + EdgeProps, + getSmoothStepPath, + useInternalNode, + useReactFlow, +} from '@xyflow/react'; import s from './styles.module.scss'; -import React from 'react'; +import React, { memo } from 'react'; import Image from 'next/image'; +import { getEdgeParams } from '@/modules/blockchains/Buy/getEdgeParams'; -export default function CustomEdge({ +function CustomEdge({ id, sourceX, sourceY, targetX, targetY, + source, + target, sourcePosition, targetPosition, markerEnd, data, + style, label, + sourceHandleId, }: EdgeProps) { + const sourceNode = useInternalNode(source); + const targetNode = useInternalNode(target); + const { sx, sy, tx, ty, sourcePos, targetPos } = getEdgeParams( + sourceNode, + targetNode, + ); + const [edgePath, labelX, labelY] = getSmoothStepPath({ - sourceX, - sourceY, - targetX, - targetY, - sourcePosition, - targetPosition, + sourceX: sx, + sourceY: sy, + targetX: tx, + targetY: ty, + sourcePosition: sourcePos, + targetPosition: targetPos, }); return ( - + { label && ( @@ -43,3 +62,5 @@ export default function CustomEdge({ ); } + +export default memo(CustomEdge) diff --git a/src/modules/blockchains/Buy/component4/CustomNode/ChainNode.tsx b/src/modules/blockchains/Buy/component4/CustomNode/ChainNode.tsx index 0ca1bbc90..7501cd863 100644 --- a/src/modules/blockchains/Buy/component4/CustomNode/ChainNode.tsx +++ b/src/modules/blockchains/Buy/component4/CustomNode/ChainNode.tsx @@ -46,22 +46,15 @@ function ChainNode({ data, isConnectable }: NodeProps) { const { field } = useOrderFormStoreV3(); const { isCapture } = useCaptureStore(); - const { order, chainData, getBlockChainStatus, isUpdateFlow } = - useChainProvider(); + const { + order, + chainData, + getBlockChainStatus, + isUpdateFlow, + selectedCategoryMapping, + } = useChainProvider(); const { statusStr, statusColorStr, borderStatusStr } = getBlockChainStatus(); - const selectedCategoryMapping = React.useMemo(() => { - if (!order?.selectedOptions) return undefined; - - const mapping: Record = {}; - - order.selectedOptions.forEach((category) => { - mapping[category.key] = category; - }); - - return mapping; - }, [order?.selectedOptions]); - return (

diff --git a/src/modules/blockchains/Buy/component4/CustomNode/DappTemplateNode.tsx b/src/modules/blockchains/Buy/component4/CustomNode/DappTemplateNode.tsx index 75291caf5..005a00e5b 100644 --- a/src/modules/blockchains/Buy/component4/CustomNode/DappTemplateNode.tsx +++ b/src/modules/blockchains/Buy/component4/CustomNode/DappTemplateNode.tsx @@ -7,6 +7,7 @@ import AA from '@/modules/blockchains/Buy/dapp/AA'; import useDapps from '@/modules/blockchains/Buy/hooks/useDapps'; import { Field } from '@/modules/blockchains/Buy/signals/useDragSignal'; import { adjustBrightness, DragUtil } from '@/modules/blockchains/Buy/utils'; +import BottomButton from '@/modules/blockchains/dapp/components/BottomButton'; import { OrderItem } from '@/stores/states/l2services/types'; import { BlockModel, DappModel, FieldModel } from '@/types/customize-model'; import { Handle, HandleType, Node, NodeProps, Position } from '@xyflow/react'; @@ -15,7 +16,7 @@ import React, { memo, ReactElement } from 'react'; import Label from '../../components3/Label'; import { useCaptureStore } from '../../stores/index_v3'; import s from './styles.module.scss'; -import BottomButton from '@/modules/blockchains/dapp/components/BottomButton'; +import styles from '@/modules/blockchains/Buy/component4/Node_v2/styles.module.scss'; export enum StatusBox { DRAFTING = 'Drafting', @@ -23,6 +24,8 @@ export enum StatusBox { MISSING = 'Missing', RUNNING = 'Running', DOWN = 'Down', + PROCESSING = 'Processing', + INSTALLED = 'Installed', } export type DataNode = Node< @@ -48,6 +51,10 @@ function DappTemplateNode({ data, isConnectable }: NodeProps) { // const { templateDapps } = useTemplateFormStore(); const { getLabelWithLego } = useDapps(); + if (data.dapp?.key === 'airdrop') { + console.log('HEHEHEHEHHEHEHE', data); + } + const DappRendering = (): ReactElement => { const thisDapp = data.dapp; @@ -478,56 +485,64 @@ function DappTemplateNode({ data, isConnectable }: NodeProps) { }, [data.dapp]); function renderTitleStatus(status: StatusBox) { - switch (status) { - case StatusBox.DOWN: + switch (status.toLowerCase()) { + case StatusBox.DOWN.toLowerCase(): return 'Down temporarily'; - case StatusBox.DRAFTING: + case StatusBox.DRAFTING.toLowerCase(): return 'Drafting modules'; - case StatusBox.READY: + case StatusBox.READY.toLowerCase(): return 'Ready to launch'; - case StatusBox.MISSING: + case StatusBox.MISSING.toLowerCase(): return 'Missing fields'; - case StatusBox.RUNNING: + case StatusBox.RUNNING.toLowerCase(): return 'Running'; + case StatusBox.PROCESSING.toLowerCase(): + return 'Processing'; + case StatusBox.INSTALLED.toLowerCase(): + return 'Installed'; default: return data.status; } } function handleColorStatusNode(status: string) { - console.log('status out', status); - - switch (status) { - case 'Down temporarily': - case 'Run out': - case 'Ended': - case 'Expired': + switch (status.toLowerCase()) { + case 'down temporarily': + case 'run out': + case 'ended': + case 'expired': return StatusBox.DOWN; - case 'Drafting modules': - case 'Deposit now': + case 'drafting modules': + case 'deposit now': return StatusBox.DRAFTING; - case 'Ready to launch': + case 'ready to launch': return StatusBox.READY; - case 'Missing fields': + case 'missing fields': return StatusBox.MISSING; + case 'processing': + return StatusBox.PROCESSING; default: return StatusBox.RUNNING; } } return ( -
-
- {data.targetHandles?.map((handle) => ( - - ))} -
+
+ {/*
*/} + {/* {data.targetHandles?.map((handle) => (*/} + {/* */} + {/* ))}*/} + {/*
*/}
) { isCapture ? s.label_margin : '' }`} > - {data.label} + {data.label}: {data.dapp?.baseBlock.title}

{

{renderTitleStatus(data.status)}

} @@ -560,18 +577,54 @@ function DappTemplateNode({ data, isConnectable }: NodeProps) { {data.dapp && }
-
- {data.sourceHandles?.map((handle, index) => ( - - ))} -
+ {/*
*/} + {/* {data.sourceHandles?.map((handle, index) => (*/} + {/* */} + {/* ))}*/} + {/*
*/} + {data.sourceHandles?.map((handle, index) => ( + + ))} + {data.sourceHandles?.map((handle, index) => ( + + ))} + {data.sourceHandles?.map((handle, index) => ( + + ))} + {data.sourceHandles?.map((handle, index) => ( + + ))}
); } diff --git a/src/modules/blockchains/Buy/component4/CustomNode/styles.module.scss b/src/modules/blockchains/Buy/component4/CustomNode/styles.module.scss index d8ad5ca6d..8f27f27ee 100644 --- a/src/modules/blockchains/Buy/component4/CustomNode/styles.module.scss +++ b/src/modules/blockchains/Buy/component4/CustomNode/styles.module.scss @@ -1,60 +1,42 @@ .wrapperBox { - width: fit-content; - height: auto; - min-width: 300px; - border: 1px solid #555555; + min-width: 400px; + width: max-content; border-radius: 16px; - padding-bottom: 10px; - background-color: #fff !important; + border: 2px solid; + + * { + font-family: var(--font-SFProDisplay); + } + .inner { - position: relative; - background: white; - //padding: 20px; padding: 15px 30px 20px 35px; + background-color: #fff; + border-bottom-left-radius: inherit; + border-bottom-right-radius: inherit; } &_top { + border-top-left-radius: inherit; + border-top-right-radius: inherit; + border-bottom: 2px solid; + padding: 6px 8px; display: flex; justify-content: space-between; align-items: center; cursor: move; - min-height: 32px; - //margin-bottom: 6px; - border-top-left-radius: 16px; - border-top-right-radius: 16px; - padding: 6px 10px 6px 18px; - border-bottom: 1px solid; + &_heading { - font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; - font-weight: 600; font-size: 14px; - color: #555; - line-height: calc(20 / 14); + font-weight: 600; + line-height: 20px; } + &_left { display: flex; align-items: center; justify-content: flex-end; gap: 4px; cursor: pointer; - - p { - color: #4185ec; - margin-top: 3px; - font-weight: 600; - font-size: 14px; - line-height: calc(20 / 14); - &:hover { - text-decoration: underline; - } - } - &_icon { - max-width: 20px; - img { - width: 100%; - height: auto; - } - } } } } @@ -76,6 +58,10 @@ border-color: #00aa6c; background-color: #eefff9; } + &_Processing { + border-color: #00aa6c; + background-color: #eefff9; + } &_Down { border-color: #555555; background-color: #ececed; @@ -105,23 +91,32 @@ width: 8px; height: 8px; border-radius: 50%; - //background: #00AA6C; } + &_Drafting { background: #ffc700; } + &_Ready { background: #4185ec; } + &_Missing { background: #ff4747; } + &_Running { background: #00aa6c; } + + &_Processing { + background: #00aa6c; + } + &_Down { background: #555555; } + p { font-size: 12px; font-style: italic; @@ -129,9 +124,16 @@ //color: #00AA6C; margin-right: 4px; } + .titleTag { - font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; - letter-spacing: 0.3px; + font-size: 14px; + font-style: italic; + font-weight: 400; + line-height: 20px; + display: flex; + align-items: center; + gap: 4px; + &_Drafting { color: #ffc700; } @@ -145,8 +147,10 @@ &_Running { color: #00aa6c; } + &_Processing { + color: #00aa6c; + } &_Down { - text-decoration: underline; color: #555555; } } @@ -193,7 +197,6 @@ } } - .finalResult { flex: 1; //width: 100%; diff --git a/src/modules/blockchains/Buy/component4/DappRenderer/BridgeRenderer.tsx b/src/modules/blockchains/Buy/component4/DappRenderer/BridgeRenderer.tsx index 7a8047c07..38b7a90bc 100644 --- a/src/modules/blockchains/Buy/component4/DappRenderer/BridgeRenderer.tsx +++ b/src/modules/blockchains/Buy/component4/DappRenderer/BridgeRenderer.tsx @@ -15,6 +15,7 @@ import useOverlappingChainLegoStore from '../../stores/useOverlappingChainLegoSt import OptionInputValue from '@/modules/blockchains/Buy/component4/DappRenderer/OptionInputValue'; import styles from './styles.module.scss'; import { useBridgesModule } from '@/modules/blockchains/detail_v4/hook/useBridgesModule'; +import { Link } from '@chakra-ui/react'; const BridgeRenderer = () => { const { parsedCategories } = useModelCategoriesStore(); @@ -53,6 +54,16 @@ const BridgeRenderer = () => { if (!option) return null; + const itemDetailMapper = + detailBridgesMapperStatus[option.key] || {}; + const { + isDone, + label: labelDetail, + backgroundColor: backgroundColorDetail, + textColor: textColorDetail, + appURL, + } = itemDetailMapper; + return ( { icon={item.confuseIcon} zIndex={item.options.length - opIdx} // TODO: @Tony - status={{ - label: detailBridgesMapperStatus[option.key]?.label, - backgroundColor: - detailBridgesMapperStatus[option.key]?.backgroundColor, - textColor: - detailBridgesMapperStatus[option.key]?.textColor, - }} + status={ + isDone + ? undefined + : { + label: labelDetail, + backgroundColor: backgroundColorDetail, + textColor: textColorDetail, + } + } + suffixView={ + isDone ? ( + + View + + ) : undefined + } >
diff --git a/src/modules/blockchains/Buy/component4/ExtendsInput/index.tsx b/src/modules/blockchains/Buy/component4/ExtendsInput/index.tsx index 3b8b35292..6c7e652f6 100644 --- a/src/modules/blockchains/Buy/component4/ExtendsInput/index.tsx +++ b/src/modules/blockchains/Buy/component4/ExtendsInput/index.tsx @@ -149,7 +149,7 @@ const ExtendsInput = ({ if (typeof formDappToggle[key] !== 'undefined') { setToggle(formDappToggle[key]); } else { - formDappToggle = { + formDappSignal.value = { ...formDappToggle, [key]: Boolean(value), }; diff --git a/src/modules/blockchains/Buy/component4/Input/index.tsx b/src/modules/blockchains/Buy/component4/Input/index.tsx index 16269a33e..815567b55 100644 --- a/src/modules/blockchains/Buy/component4/Input/index.tsx +++ b/src/modules/blockchains/Buy/component4/Input/index.tsx @@ -70,14 +70,14 @@ const Input = ({ const key = FormDappUtil.getKeyForm(props, props, name); // console.log( - // 'formDappInput -> ', + // 'formDappInput222', // key, // formTemplateDappSignal.value, // formDappInput[key], // ); if (typeof formDappInput[key] === 'undefined') { - formDappInput = { + formDappSignal.value = { ...formDappInput, [key]: '', }; diff --git a/src/modules/blockchains/Buy/component4/Label/index.tsx b/src/modules/blockchains/Buy/component4/Label/index.tsx index e41dc1cb2..996d64c1d 100644 --- a/src/modules/blockchains/Buy/component4/Label/index.tsx +++ b/src/modules/blockchains/Buy/component4/Label/index.tsx @@ -1,10 +1,8 @@ -import React from 'react'; import Image from 'next/image'; +import React from 'react'; -import SvgInset from '@/components/SvgInset'; - -import styles from './styles.module.scss'; import { iconToolNames } from '@/modules/blockchains/Buy/Buy.data'; +import styles from './styles.module.scss'; type Props = { icon?: string; @@ -24,7 +22,6 @@ const Label = ({ icon, title }: Props) => { return (
{_icon && _icon} -

{title}

); diff --git a/src/modules/blockchains/Buy/component4/LabelCopy/index.tsx b/src/modules/blockchains/Buy/component4/LabelCopy/index.tsx new file mode 100644 index 000000000..e68e0ed96 --- /dev/null +++ b/src/modules/blockchains/Buy/component4/LabelCopy/index.tsx @@ -0,0 +1,30 @@ +import { formatAddressCenter } from '@/utils/string'; +import Image from 'next/image'; +import { ReactElement } from 'react'; +import toast from 'react-hot-toast'; +import s from './styles.module.scss'; + +export default function LabelCopy({ value }: { value: string }): ReactElement { + return ( +
+
{formatAddressCenter(value as string, 6)}
+
{ + navigator.clipboard.writeText(value as string); + toast.success('Copied to clipboard'); + }} + > + copy +
+
+ ); +} diff --git a/src/modules/blockchains/Buy/component4/LabelCopy/styles.module.scss b/src/modules/blockchains/Buy/component4/LabelCopy/styles.module.scss new file mode 100644 index 000000000..db13d0316 --- /dev/null +++ b/src/modules/blockchains/Buy/component4/LabelCopy/styles.module.scss @@ -0,0 +1,8 @@ +.content { + background-color: white; + border-radius: 24px; + height: 24px; + padding-left: 12px; + padding-right: 12px; + color: black !important; +} diff --git a/src/modules/blockchains/Buy/component4/Lego/index.tsx b/src/modules/blockchains/Buy/component4/Lego/index.tsx index 18ed4e923..88a93926f 100644 --- a/src/modules/blockchains/Buy/component4/Lego/index.tsx +++ b/src/modules/blockchains/Buy/component4/Lego/index.tsx @@ -105,6 +105,12 @@ const Lego = (props: Props) => { icon || null; + if(props.infoLego?.title === 'Staking') { + console.log('checked', checked); + + } + + return ( { + zIndex = 0, + background = '#A041FF', + disabled = false, + title = '', + icon, + children, + smallMarginHeaderTop = false, + label, + dapp, + linkDownloadFile, + ...rest +}: Props) => { const legoRef = React.useRef(null); const headerRef = React.useRef(null); const footerRef = React.useRef(null); @@ -55,18 +55,44 @@ const LegoParent = ({ window.open( `${dappState?.chain?.dappURL || ''}/apps/token/${label.actionID}`, ); + + return; + } + case DappType.staking: { + window.open(`${dappState?.chain?.dappURL || ''}/apps/staking`); return; } case DappType.yologame: { if (!label?.actionID) return; window.open( - `${dappState?.chain?.dappURL || ''}/apps/yolo-games?pool_id=${label.actionID}`, + `${dappState?.chain?.dappURL || ''}/apps/yolo-games?pool_id=${ + label.actionID + }`, ); return; } } }; + const isView = useMemo(() => { + switch (dapp?.key) { + case DappType.token_generation: { + if (!label?.actionID) return false; + return true; + } + case DappType.staking: { + return true; + } + case DappType.yologame: { + if (!label?.actionID) return false; + return true; + } + + default: + return false; + } + }, [label, dapp, DappType]); + React.useEffect(() => { let parentDOM = legoRef.current?.parentElement; if (!parentDOM) return; @@ -109,7 +135,7 @@ const LegoParent = ({ styles.lego__header__piece__top, { [styles.lego__header__piece__top__smallMargin]: - smallMarginHeaderTop, + smallMarginHeaderTop, }, )} > @@ -119,6 +145,7 @@ const LegoParent = ({
{_icon && _icon} {title} + {linkDownloadFile && ( {label && ( -
+
handleLabelClick()} - > - {label.title} -
+ )} ${isCapture ? styles.label_margin : ''}`} + style={{ + // @ts-ignore + // prettier-ignore + '--label-background': label.background ? label.background : undefined, + '--label-color': label.color ? label.color : undefined, + }} + onClick={() => handleLabelClick()} + > + {label.title} +
+ + {isView && ( + handleLabelClick()} className={styles.view}> + View + + )} + )}
@@ -175,7 +206,7 @@ const LegoParent = ({ styles.lego__footer__piece__bottom, { [styles.lego__footer__piece__bottom__smallMargin]: - smallMarginHeaderTop, + smallMarginHeaderTop, }, )} > diff --git a/src/modules/blockchains/Buy/component4/LegoParent/styles.module.scss b/src/modules/blockchains/Buy/component4/LegoParent/styles.module.scss index e20501ce4..1e3eff981 100644 --- a/src/modules/blockchains/Buy/component4/LegoParent/styles.module.scss +++ b/src/modules/blockchains/Buy/component4/LegoParent/styles.module.scss @@ -180,3 +180,23 @@ .label_margin { margin-top: -15px; } + +.view { + cursor: pointer; + position: absolute; + right: 0; + top: 48%; + transform: translateY(-48%) translateX(calc(100% + 100px)); + + border-radius: 4px; + padding: 0 14px; + font-size: 16px; + font-weight: 500; + line-height: 24px; + text-decoration: underline; + color: black; + + &:hover { + color: blue; + } +} diff --git a/src/modules/blockchains/Buy/component4/Node/Node.tsx b/src/modules/blockchains/Buy/component4/Node/Node.tsx index 6c566a741..4d0fcf53b 100644 --- a/src/modules/blockchains/Buy/component4/Node/Node.tsx +++ b/src/modules/blockchains/Buy/component4/Node/Node.tsx @@ -1,14 +1,14 @@ import { Handle, Position } from '@xyflow/react'; -import React, { useState } from 'react'; +import { useState } from 'react'; +import { idNodeSignal } from '@/modules/blockchains/Buy/hooks/useFocusNode'; import { NodeProps } from '@/types/node'; +import { useSignalEffect } from '@preact/signals-react'; import NodeNotification from '../YourNodes/NodeNotification'; import NodeContent from './NodeContent'; import NodeHeading from './NodeHeading'; import NodeOverlay from './NodeOverlay'; import styles from './styles.module.scss'; -import { idNodeSignal } from '@/modules/blockchains/Buy/hooks/useFocusNode'; -import { useSignalEffect } from '@preact/signals-react'; const Node = ({ dapp, @@ -20,24 +20,9 @@ const Node = ({ targetHandles, sourceHandles, mainContentStyles, + id, }: NodeProps) => { - const nodeRef = React.useRef(null); const [focus, setFocus] = useState(false); - React.useEffect(() => { - if (!nodeRef.current) return; - - const preventKeyDown = (e: KeyboardEvent) => { - e.stopPropagation(); - }; - - const node = nodeRef.current; - - node.addEventListener('keydown', preventKeyDown); - - return () => { - node.removeEventListener('keydown', preventKeyDown); - }; - }, []); useSignalEffect(() => { setFocus(idNodeSignal.value === dapp?.id); @@ -50,18 +35,6 @@ const Node = ({ borderColor, }} > -
- {targetHandles?.map((handle) => ( - - ))} -
- {overlay && } @@ -73,17 +46,46 @@ const Node = ({
-
- {sourceHandles?.map((handle, index) => ( - - ))} -
+ {sourceHandles?.map((handle, index) => ( + + ))} + {sourceHandles?.map((handle, index) => ( + + ))} + {sourceHandles?.map((handle, index) => ( + + ))} + {sourceHandles?.map((handle, index) => ( + + ))}
); }; diff --git a/src/modules/blockchains/Buy/component4/Node/NodeHeading.tsx b/src/modules/blockchains/Buy/component4/Node/NodeHeading.tsx index 6754fbed9..2b5c23ef9 100644 --- a/src/modules/blockchains/Buy/component4/Node/NodeHeading.tsx +++ b/src/modules/blockchains/Buy/component4/Node/NodeHeading.tsx @@ -8,11 +8,13 @@ import styles from './styles.module.scss'; const NodeHeading = ({ title, + icon, status, backgroundColor = '#FFF6D8', borderColor, textColor = '#555555', headingStyles, + iconOnClick, }: NodeHeadingProps) => { const haveAction = React.useMemo(() => !!status?.onClick, [status]); @@ -23,10 +25,22 @@ const NodeHeading = ({ backgroundColor, borderColor, color: textColor, + // @ts-ignore + '--textColor': textColor, ...headingStyles, }} > -
{title}
+
+ {title}{' '} + {icon && ( + + )} +
{status && (
{ + const renderDefaultNotfication = () => { + return notification && ; + }; + + const renderCustomNotfication = () => { + return customNotification; + }; + return (
-
- {targetHandles?.map((handle) => ( - - ))} -
- {overlay && } - - {notification && } + {customNotification + ? renderCustomNotfication() + : renderDefaultNotfication()}
{content.children}
-
- {sourceHandles?.map((handle, index) => ( - - ))} -
+ {sourceHandles?.map((handle, index) => ( + + ))} + {sourceHandles?.map((handle, index) => ( + + ))} + {sourceHandles?.map((handle, index) => ( + + ))} + {sourceHandles?.map((handle, index) => ( + + ))}
); }; diff --git a/src/modules/blockchains/Buy/component4/Node_v2/styles.module.scss b/src/modules/blockchains/Buy/component4/Node_v2/styles.module.scss index 8472f12df..ae6e9d03f 100644 --- a/src/modules/blockchains/Buy/component4/Node_v2/styles.module.scss +++ b/src/modules/blockchains/Buy/component4/Node_v2/styles.module.scss @@ -86,28 +86,41 @@ } } -.handles.sources { - right: 0; - top: 0; -} +//.handles.sources { +// right: 0; +// top: 0; +//} -.handles.target { - left: 0; - top: 0; -} +//.handles.top { +// //right: 0; +// top: 0; +//} +// +//.handles.bottom { +// //right: 0; +// bottom: 0; +//} + + +//.handles.target { +// left: 0; +// top: 0; +//} .handleDot { width: 6px; height: 6px; border-radius: 50%; - background: #777777; + //background: #777777; + background-color: transparent !important; + border-color: transparent !important; //position: absolute; //border: 1px solid #555555; z-index: 4; - :global { - .react-flow__handle { - background-color: #777777 !important; - position: relative !important; - } - } + //:global { + // .react-flow__handle { + // background-color: #777777 !important; + // position: relative !important; + // } + //} } diff --git a/src/modules/blockchains/Buy/component4/YourNodes/AACustomNotification.tsx b/src/modules/blockchains/Buy/component4/YourNodes/AACustomNotification.tsx new file mode 100644 index 000000000..f863e398a --- /dev/null +++ b/src/modules/blockchains/Buy/component4/YourNodes/AACustomNotification.tsx @@ -0,0 +1,57 @@ +import { useAAModule } from '@/modules/blockchains/detail_v4/hook/useAAModule'; +import copy from 'copy-to-clipboard'; +import toast from 'react-hot-toast'; + +import { Flex, Image as ImageChakra, Text } from '@chakra-ui/react'; + +const AACustomNotification = () => { + const { aaInstalledData, isDone } = useAAModule(); + + const paymasterAddress = aaInstalledData?.aaPaymasterContract || ''; + + if (!isDone) return null; + + return ( + + + Paymaster contract address: + + + {`${paymasterAddress}`} + { + if (paymasterAddress) { + copy(paymasterAddress); + toast.success('Copied successully!'); + } + }} + /> + + + ); +}; + +export default AACustomNotification; diff --git a/src/modules/blockchains/Buy/component4/YourNodes/AANode.tsx b/src/modules/blockchains/Buy/component4/YourNodes/AANode.tsx index 3866e5a22..710da24dc 100644 --- a/src/modules/blockchains/Buy/component4/YourNodes/AANode.tsx +++ b/src/modules/blockchains/Buy/component4/YourNodes/AANode.tsx @@ -1,7 +1,9 @@ -import React, { useMemo } from 'react'; +import React from 'react'; import AddressInput from '@/modules/blockchains/detail_v3/account-abstraction_v2/components/AddressInput'; +// import SelectTokenView from '@/modules/blockchains/detail_v3/account-abstraction_v2/components/SelectTokenView'; import FeeRateInput from '@/modules/blockchains/detail_v3/account-abstraction_v2/components/FeeRateInput'; + import { useChainProvider } from '@/modules/blockchains/detail_v4/provider/ChainProvider.hook'; import { DappNode as DappNodeProps } from '@/types/node'; import { useSignalEffect } from '@preact/signals-react'; @@ -19,16 +21,31 @@ import Image from 'next/image'; import Button from '../Button'; import Node from '../Node_v2/Node'; -import styles from './styles.module.scss'; import { useAccountAbstractionStore } from '@/modules/blockchains/detail_v3/account-abstraction_v2/store/hook'; -import { useParams } from 'next/navigation'; +import { useDAServicesHelper } from '@/modules/blockchains/detail_v4/hook/useDAServicesHelper'; +import { Button as ButtonChakra, Flex } from '@chakra-ui/react'; +import useNodeAction from '../../hooks/useNodeAction'; +import AACustomNotification from './AACustomNotification'; +import styles from './styles.module.scss'; -const AANode = ({ data }: NodeProps) => { +const AANode = ({ data, id }: NodeProps) => { const { dapp } = data; - const { isAAModuleLoading, aaStatusData, isCanNotEdit, getAATypeIconUrl } = - useAAModule(); - const { getAAStatus, isUpdateFlow } = useChainProvider(); - const { resetAAStore } = useAccountAbstractionStore(); + + const { + isAAModuleLoading, + aaStatusData, + isCanNotEdit, + isDone, + aaInstalledData, + getAATypeIconUrl, + } = useAAModule(); + + const paymasterAddress = aaInstalledData?.aaPaymasterContract || ''; + + const { handleOnClickCreateToken } = useNodeAction(); + const { getAAStatus, isUpdateFlow, isCreateChainFlow } = useChainProvider(); + const { resetAAStore, tokenContractAddress } = useAccountAbstractionStore(); + const { isEmptyIssueTokenList } = useDAServicesHelper(); const [draggedDappIndexes, setDraggedDappIndexes] = React.useState( [], @@ -43,6 +60,132 @@ const AANode = ({ data }: NodeProps) => { setDraggedDappIndexes(draggedDappIndexesSignal.value); }); + const renderNotification = () => { + if (isCreateChainFlow) { + return { + label: 'IMPORTANT', + message: + 'This module needs to be configured and completed later after the chain is deployed and the payment is confirmed', + }; + } else if (isEmptyIssueTokenList) { + return { + label: 'IMPORTANT', + message: + 'Data is not available at the moment. Please create Token first', + }; + } else { + return undefined; + } + }; + + const renderDefaultContentBox = () => { + return ( + <> + + + + + + + + + + + {/* {isDone && ( + + + + )} */} + + + + + {isUpdateFlow && !isCanNotEdit && ( +
+ +
+ )} + + ); + }; + + const renderContentBox = () => { + if (isCreateChainFlow) { + // return renderDefaultContentBox(); + return undefined; + } else if (isEmptyIssueTokenList) { + return ( + + { + handleOnClickCreateToken(); + }} + > + Create Token + + + ); + } else { + return renderDefaultContentBox(); + } + }; + if (typeof dappIndex === 'undefined') { return null; } @@ -50,15 +193,8 @@ const AANode = ({ data }: NodeProps) => { return ( } overlay={ isAAModuleLoading ? { @@ -70,6 +206,7 @@ const AANode = ({ data }: NodeProps) => { } key={JSON.stringify(data)} borderColor={aaStatusData?.borderColorStr} + id={id} heading={{ title: data.title, status: { @@ -80,75 +217,8 @@ const AANode = ({ data }: NodeProps) => { borderColor: aaStatusData?.borderColorStr, backgroundColor: aaStatusData?.bgColorStr, }} - // notification={{ - // }} content={{ - children: ( - <> - - - - - - - - - - - - - - {isUpdateFlow && !isCanNotEdit && ( -
- -
- )} - - ), + children: renderContentBox(), }} /> ); diff --git a/src/modules/blockchains/Buy/component4/YourNodes/BridgeNode.tsx b/src/modules/blockchains/Buy/component4/YourNodes/BridgeNode.tsx index f28138b79..1a9d5fd8a 100644 --- a/src/modules/blockchains/Buy/component4/YourNodes/BridgeNode.tsx +++ b/src/modules/blockchains/Buy/component4/YourNodes/BridgeNode.tsx @@ -6,7 +6,7 @@ import BridgeRenderer from '../DappRenderer/BridgeRenderer'; import Node from '../Node/Node'; import { useBridgesModule } from '@/modules/blockchains/detail_v4/hook/useBridgesModule'; -const BridgeNode = ({ data }: NodeProps) => { +const BridgeNode = ({ data, id }: NodeProps) => { const { statusMapper, getBridgeTypeIconUrl } = useBridgesModule(); const notification: NodeNotificationProps | undefined = React.useMemo(() => { @@ -32,6 +32,7 @@ const BridgeNode = ({ data }: NodeProps) => { content={{ children: , }} + id={id} mainContentStyles={{ padding: 0 }} /> ); diff --git a/src/modules/blockchains/Buy/component4/YourNodes/ChainNodeV2.tsx b/src/modules/blockchains/Buy/component4/YourNodes/ChainNodeV2.tsx index b6af1ad15..f5c8ab92a 100644 --- a/src/modules/blockchains/Buy/component4/YourNodes/ChainNodeV2.tsx +++ b/src/modules/blockchains/Buy/component4/YourNodes/ChainNodeV2.tsx @@ -1,19 +1,17 @@ -import React from 'react'; - +import TopupModal from '@/modules/blockchains/components/TopupModal'; import { useChainProvider } from '@/modules/blockchains/detail_v4/provider/ChainProvider.hook'; +import { useContactUs } from '@/Providers/ContactUsProvider/hook'; +import { useAppSelector } from '@/stores/hooks'; +import { getL2ServicesStateSelector } from '@/stores/states/l2services/selector'; import { ChainNode as ChainNodeProps } from '@/types/node'; +import { useDisclosure } from '@chakra-ui/react'; import { NodeProps } from '@xyflow/react'; import ChainRenderer from '../DappRenderer/ChainRenderer'; -// import Node from '../Node/Node'; -import Node from '../Node_v2/Node'; -import { getModuleIconUrlByType } from '@/modules/blockchains/detail_v4/helper/moduleIconHelper'; -import { useDisclosure } from '@chakra-ui/react'; -import TopupModal from '@/modules/blockchains/components/TopupModal'; -import { useAppSelector } from '@/stores/hooks'; -import { getL2ServicesStateSelector } from '@/stores/states/l2services/selector'; -import { useContactUs } from '@/Providers/ContactUsProvider/hook'; +import Node from '../Node/Node'; +import { useRouter } from 'next/navigation'; -const ChainNodeV2 = ({ data }: NodeProps) => { +const ChainNodeV2 = ({ data, id }: NodeProps) => { + const router = useRouter(); const { accountInforL2Service } = useAppSelector(getL2ServicesStateSelector); const { showContactUsModal } = useContactUs(); const { @@ -23,6 +21,8 @@ const ChainNodeV2 = ({ data }: NodeProps) => { getChainTypeIconUrl, isInsufficientBalance, textCTA, + order, + isUpdateFlow, } = useChainProvider(); const { statusStr: statusMessage, @@ -74,8 +74,15 @@ const ChainNodeV2 = ({ data }: NodeProps) => { : undefined } key={JSON.stringify(data)} + id={id} heading={{ title: data.title, + icon: isUpdateFlow + ? '/blockchains/customize/ic-infor.svg' + : undefined, + iconOnClick: () => { + router.push(`/chains/${order?.orderId}/detail`); + }, status: { message: statusMessage, color: borderColor, diff --git a/src/modules/blockchains/Buy/component4/YourNodes/DappNode.tsx b/src/modules/blockchains/Buy/component4/YourNodes/DappNode.tsx index 76bb038a4..d5c009d50 100644 --- a/src/modules/blockchains/Buy/component4/YourNodes/DappNode.tsx +++ b/src/modules/blockchains/Buy/component4/YourNodes/DappNode.tsx @@ -10,7 +10,7 @@ import { NodeProps } from '@xyflow/react'; import DappRenderer from '../DappRenderer'; import Node from '../Node/Node'; -const DappNode = ({ data }: NodeProps) => { +const DappNode = ({ data, id }: NodeProps) => { const { statusCode, statusStr } = useChainStatus(); const { isUpdateFlow } = useChainProvider(); @@ -66,6 +66,7 @@ const DappNode = ({ data }: NodeProps) => { message: data.statusMessage ?? 'Drafting modules', }, }} + id={id} notification={notification} content={{ children: , diff --git a/src/modules/blockchains/Buy/component4/YourNodes/GamingAppsNode.tsx b/src/modules/blockchains/Buy/component4/YourNodes/GamingAppsNode.tsx index 7c82d3922..5f4086acc 100644 --- a/src/modules/blockchains/Buy/component4/YourNodes/GamingAppsNode.tsx +++ b/src/modules/blockchains/Buy/component4/YourNodes/GamingAppsNode.tsx @@ -6,13 +6,13 @@ import GamingAppsRenderer from '../DappRenderer/GamingAppsRenderer'; import Node from '../Node/Node'; import { useGameModule } from '@/modules/blockchains/detail_v4/hook/useGameModule'; -const GamingAppsNode = ({ data }: NodeProps) => { +const GamingAppsNode = ({ data, id }: NodeProps) => { const { statusMapper, getGameTypeIconUrl } = useGameModule(); const notification: NodeNotificationProps | undefined = React.useMemo(() => { return undefined; }, []); - + console.log('statusMapper', statusMapper); return ( ) => { borderColor: statusMapper?.borderColorStr, backgroundColor: statusMapper?.bgColorStr, }} + id={id} notification={notification} content={{ children: , diff --git a/src/modules/blockchains/Buy/component4/YourNodes/node.constants.ts b/src/modules/blockchains/Buy/component4/YourNodes/node.constants.ts index 338e4a736..86dc824ff 100644 --- a/src/modules/blockchains/Buy/component4/YourNodes/node.constants.ts +++ b/src/modules/blockchains/Buy/component4/YourNodes/node.constants.ts @@ -26,7 +26,7 @@ export const dappKeyMapNodeKey: Record< staking: nodeKey.DAPP_NODE, airdrop: nodeKey.DAPP_NODE, yologame: nodeKey.DAPP_NODE, - orderbook: nodeKey.DAPP_NODE, + white_paper: nodeKey.DAPP_NODE, }); export const dappKeyToNodeKey = (dappKey: string) => { diff --git a/src/modules/blockchains/Buy/components/DescriptionModal/styles.module.scss b/src/modules/blockchains/Buy/components/DescriptionModal/styles.module.scss index ecb2f031b..5ede5cf1f 100644 --- a/src/modules/blockchains/Buy/components/DescriptionModal/styles.module.scss +++ b/src/modules/blockchains/Buy/components/DescriptionModal/styles.module.scss @@ -4,9 +4,7 @@ margin: 20px !important; } - .content { - margin-top: 24px; font-family: var(--font-SFProDisplay); font-size: 16px; @@ -15,6 +13,10 @@ letter-spacing: 0.01em; text-align: left; + ul { + padding-left: 1.1em; + } + h2 { font-family: var(--font-SFProDisplay); font-size: 18px; @@ -35,7 +37,7 @@ margin-bottom: 4px; } - i{ - color: #FF7E21; + i { + color: #ff7e21; } } diff --git a/src/modules/blockchains/Buy/components3/LaunchButton/index.tsx b/src/modules/blockchains/Buy/components3/LaunchButton/index.tsx index c29dbc93c..e3c271031 100644 --- a/src/modules/blockchains/Buy/components3/LaunchButton/index.tsx +++ b/src/modules/blockchains/Buy/components3/LaunchButton/index.tsx @@ -49,6 +49,7 @@ import useSubmitYoloGame from '@/modules/blockchains/Buy/components3/LaunchButto import useSubmitWalletType from '@/modules/blockchains/Buy/components3/LaunchButton/onSubmitWalletType'; import { useComputerNameInputStore } from '../ComputerNameInput/ComputerNameInputStore'; import BigNumber from 'bignumber.js'; +import useSubmitWhitePaper from '@/modules/blockchains/Buy/components3/LaunchButton/onSubmitWhitePaper'; const isExistIssueTokenDApp = (dyanmicFormAllData: any[]): boolean => { const inssueTokenDappList = dyanmicFormAllData @@ -130,6 +131,7 @@ const LaunchButton = ({ isUpdate }: { isUpdate?: boolean }) => { const { onSubmitTokenGeneration } = useSubmitFormTokenGeneration(); const { onSubmitYoloGame } = useSubmitYoloGame(); const { onSubmit: onSubmitWalletType } = useSubmitWalletType(); + const { onSubmitWhitePaper } = useSubmitWhitePaper(); const { chainName } = useOrderFormStore(); const searchParams = useSearchParams(); @@ -343,6 +345,13 @@ const LaunchButton = ({ isUpdate }: { isUpdate?: boolean }) => { dynamicFormValues: dynamicForm, }); + const whitePaperForms = retrieveFormsByDappKey({ + dappKey: DappType.white_paper, + }); + const whitePaperPositions = retrieveNodePositionsByDappKey({ + dappKey: DappType.white_paper, + }); + const yoloGameForms = retrieveFormsByDappKey({ dappKey: DappType.yologame, }); @@ -385,10 +394,17 @@ const LaunchButton = ({ isUpdate }: { isUpdate?: boolean }) => { yoloGameForms, yoloNodePositions, walletTypeForms, + whitePaperForms, + whitePaperPositions }); // console.log('UPDATE FLOW: --- dynamicForm --- ', dynamicForm); - // console.log('LEON LOG: 111', tokensForms); + console.log('LEON LOG: 111', { + stakingForms, + yoloGameForms, + airdropForms, + tokensForms + }); let isConfigDapp = false; try { @@ -398,7 +414,13 @@ const LaunchButton = ({ isUpdate }: { isUpdate?: boolean }) => { if (result) { //Config Account Abstraction... configAccountAbstraction(dynamicForm); - let isConfigDapp = false; + if (whitePaperForms && whitePaperForms.length > 0) { + await onSubmitWhitePaper({ + forms: whitePaperForms, + positions: whitePaperPositions, + }); + isConfigDapp = true; + } if (yoloGameForms && yoloGameForms.length > 0) { await onSubmitYoloGame({ forms: yoloGameForms, @@ -477,6 +499,7 @@ const LaunchButton = ({ isUpdate }: { isUpdate?: boolean }) => { setTimeout(() => { dispatch(requestReload()); setUpdated(true); + // window.location.reload(); }, 1000); } getOrderDetailByID(orderDetail.orderId); diff --git a/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitFormAirdrop.ts b/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitFormAirdrop.ts index 16c09c0d6..643274326 100644 --- a/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitFormAirdrop.ts +++ b/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitFormAirdrop.ts @@ -197,7 +197,6 @@ const useSubmitFormAirdrop = () => { body.tasks = tasks; await cAirdropAPI.setupTask(body); showSuccess({ message: 'Airdrop created successfully!.' }); - dispatch(requestReload()); handleReset(); // setLoading(false); } else { @@ -211,7 +210,6 @@ const useSubmitFormAirdrop = () => { body.receivers = result.data; await cAirdropAPI.setupTask(body); showSuccess({ message: 'Airdrop created successfully!.' }); - dispatch(requestReload()); handleReset(); // setLoading(false); }, diff --git a/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitStaking.tsx b/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitStaking.tsx index 2d3d9cdae..0e7532948 100644 --- a/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitStaking.tsx +++ b/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitStaking.tsx @@ -19,7 +19,7 @@ const useSubmitStaking = () => { // dappKey: 'staking', // }); - const params = []; + // const params = []; let index = 0; for (const form of forms) { @@ -59,22 +59,20 @@ const useSubmitStaking = () => { ); const formFinal = finalFormMappings.find((item) => !!item); - const info: any = formFinal?.info.find((item) => !!item); - // TODO: JACKIE - update position below const position: IPosition = { position_id: uuidv4(), position_x: positions[index].x ?? 0, position_y: positions[index].y ?? 0, }; + index++; - // console.log(position); await cStakeAPI.createNewStakingPool({ principle_token: formFinal?.staking_token, reward_token: formFinal?.reward_token, - base_ratio: Number(info?.apr?.replaceAll('%', '')) / 100, - token_price: 1 / Number(info?.rate), + base_ratio: Number((formFinal?.apr as any)?.replaceAll('%', '')) / 100, + token_price: 1 / Number(formFinal?.rate), ...position, // TODO: JACKIE - update position }); } catch (error) { diff --git a/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitWhitePaper.tsx b/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitWhitePaper.tsx new file mode 100644 index 000000000..3745a178e --- /dev/null +++ b/src/modules/blockchains/Buy/components3/LaunchButton/onSubmitWhitePaper.tsx @@ -0,0 +1,76 @@ +import { IRetrieveFormsByDappKey } from '@/modules/blockchains/Buy/hooks/useOneForm'; +import { extractedValue } from '@/modules/blockchains/dapp/hooks/utils'; +import { FormDappUtil } from '@/modules/blockchains/dapp/utils'; +import CYoloGameAPI from '@/services/api/dapp/yolo'; +import BigNumberJS from 'bignumber.js'; +import { IPosition } from '@/services/api/dapp/staking/interface'; +import { v4 as uuidv4 } from 'uuid'; +import CWhitePaperAPI from '@/services/api/dapp/whitePapers'; + +const useSubmitWhitePaper = () => { + const cWhitePaperAPI = new CWhitePaperAPI(); + + const onSubmitWhitePaper = async ({ forms, positions }: { forms: IRetrieveFormsByDappKey[][], positions?: Vector2[] }) => { + let index = 0; + + for (const form of forms) { + try { + let finalFormMappings: Record< + string, + { key: string; value: string }[] + >[] = []; + const formDapp = Object.assign({}, ...form); + const formDappInBase = Object.keys(formDapp).filter( + (key) => !FormDappUtil.isInBlock(key) && !FormDappUtil.isInSingle(key), + ); + const formDappInModule = Object.keys(formDapp).filter( + (key) => !FormDappUtil.isInModule(key), + ); + const formDappInSingle = Object.keys(formDapp).filter( + FormDappUtil.isInSingle, + ); + + finalFormMappings = extractedValue( + formDappInBase, + formDapp, + finalFormMappings, + ); + + finalFormMappings = extractedValue( + formDappInModule, + formDapp, + finalFormMappings, + ); + + finalFormMappings = extractedValue( + formDappInSingle, + formDapp, + finalFormMappings, + ); + const formFinal = finalFormMappings.find(item => !!item); + + // TODO: JACKIE - update position below + const position: IPosition = { + position_id: uuidv4(), + position_x: positions?.[index]?.x ?? 0, + position_y: positions?.[index]?.y ?? 0, + }; + index++; + + await cWhitePaperAPI.createWhitePaper( + formFinal?.token as unknown as string, + {...position} + ); + } catch (error) { + console.log(error); + } + } + + }; + + return { + onSubmitWhitePaper + } +} + +export default useSubmitWhitePaper; diff --git a/src/modules/blockchains/Buy/components3/LaunchButton/useSubmitFormTokenGeneration.ts b/src/modules/blockchains/Buy/components3/LaunchButton/useSubmitFormTokenGeneration.ts index bb95119db..a42ed4326 100644 --- a/src/modules/blockchains/Buy/components3/LaunchButton/useSubmitFormTokenGeneration.ts +++ b/src/modules/blockchains/Buy/components3/LaunchButton/useSubmitFormTokenGeneration.ts @@ -25,6 +25,7 @@ import { IRetrieveFormsByDappKey } from '../../hooks/useOneForm'; const useSubmitFormTokenGeneration = () => { const dappState = useAppSelector(dappSelector); const dispatch = useDispatch(); + const api = new CTokenGenerationAPI(); const handleReset = () => { // formDappInputSignal.value = {}; @@ -181,7 +182,6 @@ const useSubmitFormTokenGeneration = () => { try { for (const form of forms) { - // console.log('formxxxx', form); let dataMapping: Record[] = []; @@ -297,7 +297,10 @@ const useSubmitFormTokenGeneration = () => { }; index++; - const api = new CTokenGenerationAPI(); + console.log('LEON TEST: 444'); + + console.log('LEON TEST: 555'); + const tokenInfo = await api.generateNewToken({ data_hex: calldata, type: 'token', diff --git a/src/modules/blockchains/Buy/components3/LegoV3/index.tsx b/src/modules/blockchains/Buy/components3/LegoV3/index.tsx index 999261e56..f5032d7de 100644 --- a/src/modules/blockchains/Buy/components3/LegoV3/index.tsx +++ b/src/modules/blockchains/Buy/components3/LegoV3/index.tsx @@ -30,6 +30,8 @@ type LegoV3 = { backgroundColor: string; textColor: string; }; + + suffixView?: React.ReactNode; } & React.HTMLAttributes; function LegoV3({ @@ -50,6 +52,7 @@ function LegoV3({ checked = false, children, status, + suffixView, ...props }: LegoV3) { const refTooltip = React.useRef(null); @@ -208,6 +211,10 @@ function LegoV3({ {status.label}
)} + + {suffixView && ( +
{suffixView}
+ )}
); diff --git a/src/modules/blockchains/Buy/components3/LegoV3/styles.module.scss b/src/modules/blockchains/Buy/components3/LegoV3/styles.module.scss index a96884608..c2ad9fb67 100644 --- a/src/modules/blockchains/Buy/components3/LegoV3/styles.module.scss +++ b/src/modules/blockchains/Buy/components3/LegoV3/styles.module.scss @@ -282,3 +282,12 @@ color: #000000; border-radius: 99999px; } + +.suffixViewContainer { + padding: 0 12px; + position: absolute; + top: 50%; + right: -16px; + transform: translate(100%, -50%); + border-radius: 99999px; +} diff --git a/src/modules/blockchains/Buy/components3/NetworkDropdown/index.tsx b/src/modules/blockchains/Buy/components3/NetworkDropdown/index.tsx index e37e42c88..c21ec2555 100644 --- a/src/modules/blockchains/Buy/components3/NetworkDropdown/index.tsx +++ b/src/modules/blockchains/Buy/components3/NetworkDropdown/index.tsx @@ -73,6 +73,12 @@ const NetworkDropdown = ({}: Props) => { setIsOpenDropdown(false); }; + const handleOpenDropdown = () => { + if (isUpdateFlow) return; + + setIsOpenDropdown(!isOpenDropdown); + }; + const _icon = React.useMemo( () => getIcon(currentValue?.icon), [currentValue?.icon], @@ -100,7 +106,7 @@ const NetworkDropdown = ({}: Props) => {
setIsOpenDropdown(!isOpenDropdown)} + onClick={() => handleOpenDropdown()} > {_icon && icon} diff --git a/src/modules/blockchains/Buy/getEdgeParams.ts b/src/modules/blockchains/Buy/getEdgeParams.ts new file mode 100644 index 000000000..bed9896fb --- /dev/null +++ b/src/modules/blockchains/Buy/getEdgeParams.ts @@ -0,0 +1,100 @@ +import { Position, MarkerType } from '@xyflow/react'; + +// this helper function returns the intersection point +// of the line between the center of the intersectionNode and the target node +function getNodeIntersection(intersectionNode: any, targetNode: any) { + // https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a + const { width: intersectionNodeWidth, height: intersectionNodeHeight } = + intersectionNode.measured; + const intersectionNodePosition = intersectionNode.internals.positionAbsolute; + const targetPosition = targetNode.internals.positionAbsolute; + + const w = intersectionNodeWidth / 2; + const h = intersectionNodeHeight / 2; + + const x2 = intersectionNodePosition.x + w; + const y2 = intersectionNodePosition.y + h; + const x1 = targetPosition.x + targetNode.measured.width / 2; + const y1 = targetPosition.y + targetNode.measured.height / 2; + + const xx1 = (x1 - x2) / (2 * w) - (y1 - y2) / (2 * h); + const yy1 = (x1 - x2) / (2 * w) + (y1 - y2) / (2 * h); + const a = 1 / (Math.abs(xx1) + Math.abs(yy1)); + const xx3 = a * xx1; + const yy3 = a * yy1; + const x = w * (xx3 + yy3) + x2; + const y = h * (-xx3 + yy3) + y2; + + return { x, y }; +} + +// returns the position (top,right,bottom or right) passed node compared to the intersection point +function getEdgePosition(node: any, intersectionPoint: any) { + const n = { ...node.internals.positionAbsolute, ...node }; + const nx = Math.round(n.x); + const ny = Math.round(n.y); + const px = Math.round(intersectionPoint.x); + const py = Math.round(intersectionPoint.y); + + if (px <= nx + 1) { + return Position.Left; + } + if (px >= nx + n.measured.width - 1) { + return Position.Right; + } + if (py <= ny + 1) { + return Position.Top; + } + if (py >= n.y + n.measured.height - 1) { + return Position.Bottom; + } + + return Position.Top; +} + +// returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge +export function getEdgeParams(source: any, target: any) { + const sourceIntersectionPoint = getNodeIntersection(source, target); + const targetIntersectionPoint = getNodeIntersection(target, source); + + const sourcePos = getEdgePosition(source, sourceIntersectionPoint); + const targetPos = getEdgePosition(target, targetIntersectionPoint); + + return { + sx: sourceIntersectionPoint.x, + sy: sourceIntersectionPoint.y, + tx: targetIntersectionPoint.x, + ty: targetIntersectionPoint.y, + sourcePos, + targetPos, + }; +} + +// export function createNodesAndEdges() { +// const nodes = []; +// const edges = []; +// const center = { x: window.innerWidth / 2, y: window.innerHeight / 2 }; +// +// nodes.push({ id: 'target', data: { label: 'Target' }, position: center }); +// +// for (let i = 0; i < 8; i++) { +// const degrees = i * (360 / 8); +// const radians = degrees * (Math.PI / 180); +// const x = 250 * Math.cos(radians) + center.x; +// const y = 250 * Math.sin(radians) + center.y; +// +// nodes.push({ id: `${i}`, data: { label: 'Source' }, position: { x, y } }); +// +// edges.push({ +// id: `edge-${i}`, +// target: 'target', +// source: `${i}`, +// type: 'floating', +// markerEnd: { +// type: MarkerType.Arrow, +// }, +// }); +// } +// +// return { nodes, edges }; +// } diff --git a/src/modules/blockchains/Buy/hooks/useAutoUpdateNodePosition.ts b/src/modules/blockchains/Buy/hooks/useAutoUpdateNodePosition.ts index 052e89f6a..1c585703d 100644 --- a/src/modules/blockchains/Buy/hooks/useAutoUpdateNodePosition.ts +++ b/src/modules/blockchains/Buy/hooks/useAutoUpdateNodePosition.ts @@ -23,10 +23,10 @@ const useAutoUpdateNodePosition = () => { nodes.forEach((node: AppNode) => { const _node = node as unknown as AppNode; - if (_node.data.node !== 'dapp' || !l2ServiceUserAddress) return; + if (_node.data.node != 'template' || !l2ServiceUserAddress) return; const { data } = _node as DappNode; - if (data.dapp.isDefaultDapp || !!!data.positionId) return; + if (data.dapp?.isDefaultDapp || !!!data.positionId) return; promises.push( dappApi.updatePosition({ diff --git a/src/modules/blockchains/Buy/hooks/useCheckEdges.ts b/src/modules/blockchains/Buy/hooks/useCheckEdges.ts index 3b94672f7..ddb80a602 100644 --- a/src/modules/blockchains/Buy/hooks/useCheckEdges.ts +++ b/src/modules/blockchains/Buy/hooks/useCheckEdges.ts @@ -2,39 +2,29 @@ import useOrderFormStoreV3 from '@/modules/blockchains/Buy/stores/index_v3'; import useFlowStore from '@/modules/blockchains/Buy/stores/useFlowStore'; import React from 'react'; import { needReactFlowRenderSignal } from '../studio/ReactFlowRender'; +import { removeItemAtIndex } from '@/modules/blockchains/dapp/utils'; const useCheckEdges = () => { const { field } = useOrderFormStoreV3(); - const { nodes, setNodes, edges, setEdges } = useFlowStore(); + const { nodes, setNodes, edges, setEdges, removedNode, setRemovedNode } = useFlowStore(); const checkEdges = () => { - const blockchainNodeIndex = nodes.findIndex( - (node) => node.id === 'blockchain', - ); - const blockchainNode = nodes[blockchainNodeIndex]; + const indexEdgeRemoved = edges.findIndex(edge => edge.target === removedNode?.id ||edge.source === removedNode?.id); + console.log('indexEdgeRemoved', indexEdgeRemoved); + if(indexEdgeRemoved === -1) return; - if (!blockchainNode) return; - const sourceHandles = blockchainNode.data.sourceHandles; - const edgesData = edges.filter((edge) => edge.source === 'blockchain'); - - const newSourceHandles = sourceHandles.filter((sourceHandle) => { - const edgeIndex = edgesData.findIndex( - (edge) => edge.sourceHandle === sourceHandle, - ); - - return edgeIndex !== -1; - }); - - blockchainNode.data.sourceHandles = newSourceHandles; - - setNodes([...nodes]); + setEdges(removeItemAtIndex(edges, indexEdgeRemoved)); + setRemovedNode(null) needReactFlowRenderSignal.value = true; }; React.useEffect(() => { + console.log('runmnnn here'); + if(removedNode === null) return; checkEdges(); - }, [nodes.length]); + }, [removedNode]); + }; export default useCheckEdges; diff --git a/src/modules/blockchains/Buy/hooks/useCheckNodes.ts b/src/modules/blockchains/Buy/hooks/useCheckNodes.ts index baa8bc105..57a7b342c 100644 --- a/src/modules/blockchains/Buy/hooks/useCheckNodes.ts +++ b/src/modules/blockchains/Buy/hooks/useCheckNodes.ts @@ -3,7 +3,9 @@ import useOrderFormStoreV3 from '@/modules/blockchains/Buy/stores/index_v3'; import useFlowStore, { AppState, } from '@/modules/blockchains/Buy/stores/useFlowStore'; +import { useAAModule } from '@/modules/blockchains/detail_v4/hook/useAAModule'; import { useBridgesModule } from '@/modules/blockchains/detail_v4/hook/useBridgesModule'; +import { useGameModule } from '@/modules/blockchains/detail_v4/hook/useGameModule'; import { IModelOption } from '@/types/customize-model'; import { DappNode } from '@/types/node'; import handleStatusEdges from '@utils/helpers'; @@ -30,6 +32,8 @@ export default function useCheckNodes() { const { nodes, setNodes, edges, setEdges } = useFlowStore(); const { getCurrentFieldFromChain } = useFormChain(); const { lineBridgeStatus } = useBridgesModule(); + const { lineAAStatus } = useAAModule(); + const { statusMapper } = useGameModule(); const { dapps } = useDappsStore(); const store = useStoreApi(); const { @@ -42,14 +46,14 @@ export default function useCheckNodes() { const newDraggedDappIndexes = cloneDeep(draggedDappIndexesSignal.value); const newDraggedIds2D = cloneDeep(draggedIds2DSignal.value); let somethingChanged = false; - const transformedX = - (mouseDroppedPositionSignal.value.x - transformX) / zoomLevel; - const transformedY = - (mouseDroppedPositionSignal.value.y - transformY) / zoomLevel; - const positionTo = { - x: transformedX, - y: transformedY, - }; + // const transformedX = + // (mouseDroppedPositionSignal.value.x - transformX) / zoomLevel; + // const transformedY = + // (mouseDroppedPositionSignal.value.y - transformY) / zoomLevel; + // const positionTo = { + // x: transformedX, + // y: transformedY, + // }; if (!getCurrentFieldFromChain('wallet')) { const nodeIndex = nodes.findIndex( @@ -63,7 +67,6 @@ export default function useCheckNodes() { ); if (nodeIndex != -1) { - console.log('[useCheckNodes] case 1'); nodes.splice(nodeIndex, 1); setNodes(removeItemAtIndex(nodes, nodeIndex)); } @@ -92,7 +95,7 @@ export default function useCheckNodes() { id: newNodeId, type: dappKeyToNodeKey(thisDapp.key), dragHandle: '.drag-handle-area', - position: { x: 0, y: 0 }, + position: { x: 950, y: 30 }, data: { node: 'dapp', title: thisDapp.title, @@ -100,8 +103,10 @@ export default function useCheckNodes() { baseIndex: 0, categoryOption: {} as IModelOption, ids: [], - targetHandles: [`account_abstraction-t-${rootNode}`], - sourceHandles: [], + // targetHandles: [`account_abstraction-t-${rootNode}`], + targetHandles: [], + sourceHandles: [`account_abstraction-t-${rootNode}`], + // sourceHandles: [], }, }; @@ -123,17 +128,17 @@ export default function useCheckNodes() { target: `account_abstraction`, targetHandle: `account_abstraction-t-${rootNode}`, type: 'customEdge', - label: handleStatusEdges('', lineBridgeStatus, 'account_abstraction') + selectable: false, + selected: false, + focusable: false, + label: handleStatusEdges('', lineAAStatus, 'account_abstraction') .icon, - animated: handleStatusEdges( - '', - lineBridgeStatus, - 'account_abstraction', - ).animate, + animated: handleStatusEdges('', lineAAStatus, 'account_abstraction') + .animate, markerEnd: { type: MarkerType.Arrow, - width: 25, - height: 25, + width: 20, + height: 20, strokeWidth: 1, color: '#AAAAAA', }, @@ -164,7 +169,6 @@ export default function useCheckNodes() { ); if (nodeIndex != -1) { - console.log('[useCheckNodes] case 2'); nodes.splice(nodeIndex, 1); setNodes(removeItemAtIndex(nodes, nodeIndex)); } @@ -189,7 +193,7 @@ export default function useCheckNodes() { id: newNodeId, type: dappKeyToNodeKey(thisDapp.key), dragHandle: '.drag-handle-area', - position: positionTo, + position: { x: 500, y: 30 }, data: { node: 'dapp', title: thisDapp.title, @@ -197,8 +201,10 @@ export default function useCheckNodes() { baseIndex: 0, categoryOption: {} as IModelOption, ids: [], - targetHandles: [`bridge_apps-t-${rootNode}`], - sourceHandles: [], + // targetHandles: [`bridge_apps-t-${rootNode}`], + targetHandles: [], + sourceHandles: [`bridge_apps-t-${rootNode}`], + // sourceHandles: [], }, }; @@ -223,10 +229,13 @@ export default function useCheckNodes() { label: handleStatusEdges('', lineBridgeStatus, 'bridge_apps').icon, animated: handleStatusEdges('', lineBridgeStatus, 'bridge_apps') .animate, + selectable: false, + selected: false, + focusable: false, markerEnd: { type: MarkerType.Arrow, - width: 25, - height: 25, + width: 20, + height: 20, strokeWidth: 1, color: '#AAAAAA', }, @@ -283,7 +292,7 @@ export default function useCheckNodes() { id: newNodeId, type: dappKeyToNodeKey(thisDapp.key), dragHandle: '.drag-handle-area', - position: positionTo, + position: { x: 1500, y: 30 }, data: { node: 'dapp', title: thisDapp.title, @@ -291,8 +300,10 @@ export default function useCheckNodes() { baseIndex: 0, categoryOption: {} as IModelOption, ids: [], - targetHandles: [`gaming_apps-t-${rootNode}`], - sourceHandles: [], + // targetHandles: [`gaming_apps-t-${rootNode}`], + targetHandles: [], + sourceHandles: [`gaming_apps-t-${rootNode}`], + // sourceHandles: [], }, }; @@ -314,13 +325,17 @@ export default function useCheckNodes() { target: `gaming_apps`, targetHandle: `gaming_apps-t-${rootNode}`, type: 'customEdge', - label: handleStatusEdges('', lineBridgeStatus, 'gaming_apps').icon, - animated: handleStatusEdges('', lineBridgeStatus, 'gaming_apps') + label: handleStatusEdges('', statusMapper.statusStr, 'gaming_apps') + .icon, + animated: handleStatusEdges('', statusMapper.statusStr, 'gaming_apps') .animate, + selectable: false, + selected: false, + focusable: false, markerEnd: { type: MarkerType.Arrow, - width: 25, - height: 25, + width: 20, + height: 20, strokeWidth: 1, color: '#AAAAAA', }, diff --git a/src/modules/blockchains/Buy/hooks/useDapps.tsx b/src/modules/blockchains/Buy/hooks/useDapps.tsx index e85cebf7f..d8764e9ea 100644 --- a/src/modules/blockchains/Buy/hooks/useDapps.tsx +++ b/src/modules/blockchains/Buy/hooks/useDapps.tsx @@ -5,13 +5,16 @@ import DateTimeInput from '../component4/DateTimeInput'; import Dropdown from '../component4/Dropdown'; import ExtendsInput from '../component4/ExtendsInput'; import Input from '../component4/Input'; +import LabelCopy from '../component4/LabelCopy'; import Lego from '../component4/Lego'; import useDappsStore from '../stores/useDappStore'; import { FieldOption } from '../types'; import { adjustBrightness } from '../utils'; +import Button from '@/modules/blockchains/Buy/component4/Button'; const useDapps = () => { const { dapps } = useDappsStore(); + // const dappState = useAppSelector(dappSelector); const blockFieldMapping = React.useMemo(() => { return dapps.map((dapp) => { @@ -69,6 +72,16 @@ const useDapps = () => { }); }, [dapps]); + const handleFieldClick = (dapp: DappModel, field: any) => { + console.log('thisDapp, field', dapp, field); + switch (dapp?.key) { + case 'white_paper': { + return; + } + } + }; + + const getInputWithLego = React.useCallback( ( thisDapp: DappModel, @@ -171,6 +184,29 @@ const useDapps = () => { /> ); + } else if (field.type === 'button') { + return ( + + + + ); } }, [dapps], @@ -348,6 +384,50 @@ const useDapps = () => { /> ); + } else if ( + field.type === 'label_value' && + field.value !== '' && + field.value !== null && + field.value !== undefined && + field.value !== 'undefined' && + field.options.length === 0 + ) { + return ( + + + + ); + } else if (field.type === 'button') { + return ( + + + + ); } }, [dapps], diff --git a/src/modules/blockchains/Buy/hooks/useFetchingTemplate.ts b/src/modules/blockchains/Buy/hooks/useFetchingTemplate.ts index 54abdf3aa..847201538 100644 --- a/src/modules/blockchains/Buy/hooks/useFetchingTemplate.ts +++ b/src/modules/blockchains/Buy/hooks/useFetchingTemplate.ts @@ -26,9 +26,11 @@ import { parseStakingPools } from '../../dapp/parseUtils/staking'; import { useChainProvider } from '../../detail_v4/provider/ChainProvider.hook'; import { parseDappModel } from '../../utils'; import { nodeKey } from '../component4/YourNodes/node.constants'; +import { ENABLE_CHATBOX } from '../constants'; import { draggedDappIndexesSignal, draggedIds2DSignal, + isRenderedInUpdateFlowSignal, templateIds2DSignal, } from '../signals/useDragSignal'; import { @@ -38,11 +40,13 @@ import { import { useTemplateFormStore } from '../stores/useDappStore'; import useFlowStore, { AppNode, AppState } from '../stores/useFlowStore'; import useUpdateFlowStore from '../stores/useUpdateFlowStore'; +import { needReactFlowRenderSignal } from '../studio/ReactFlowRender'; import useAvailableListTemplate from '../studio/useAvailableListTemplate'; import useModelCategory from '../studio/useModelCategory'; import { DappType } from '../types'; import { cloneDeep, FormDappUtil } from '../utils'; import useDapps from './useDapps'; +import { parseWhitePapers } from '@/modules/blockchains/dapp/parseUtils/whitePaper'; export default function useFetchingTemplate() { const { templateList, templateDefault } = useAvailableListTemplate(); @@ -56,31 +60,30 @@ export default function useFetchingTemplate() { useChainProvider(); const { nodes, setNodes, edges, setEdges } = useFlowStore(); const { - categories, setParsedCategories, setCategories, setCategoriesTemplates, - categoriesTemplates, setCategoryMapping, } = useModelCategoriesStore(); const { field, setFields } = useOrderFormStoreV3(); const { setUpdated, updated } = useUpdateFlowStore(); - const param = useParams(); const searchParams = useSearchParams(); - const refUpdatedBaseDapp = React.useRef(false); const { setIsFirstLoadTemplateBox } = useStoreFirstLoadTemplateBox(); const { l2ServiceUserAddress } = useWeb3Auth(); - const { initTemplate, setTemplate } = useTemplate(); + const { setTemplate } = useTemplate(); const { templateDapps, templateForm, setTemplateForm, setTemplateDapps } = useTemplateFormStore(); const { counterFetchedDapp } = useAppSelector(commonSelector); const dappState = useAppSelector(dappSelector); - const { tokens, airdrops, stakingPools, yoloGames, walletType } = dappState; + const { tokens, airdrops, stakingPools, yoloGames, walletType, whitePapers } = + dappState; const [needSetDataTemplateToBox, setNeedSetDataTemplateToBox] = React.useState(false); const [needCheckAndAddAA, setNeedCheckAndAddAA] = React.useState(false); + const [needSetPreTemplate, setNeedSetPreTemplate] = React.useState(false); + const [reseted, setReseted] = React.useState(false); const convertData = (data: IModelCategory[]) => { const newData = data?.map((item) => { @@ -137,6 +140,7 @@ export default function useFetchingTemplate() { setCategoriesTemplates(templateList); setFields(newFields); setNeedSetDataTemplateToBox(true); + setNeedSetPreTemplate(true); }; const dataTemplateToBox = async () => { @@ -215,6 +219,8 @@ export default function useFetchingTemplate() { totalBase, ).fill([]); + console.log('[useFetchingTemplate] dataTemplateToBox', templateDapps); + Object.keys(templateForm).forEach((fieldKey) => { const value = templateForm[fieldKey]; const baseIndex = FormDappUtil.getBaseIndex(fieldKey); @@ -229,7 +235,11 @@ export default function useFetchingTemplate() { blockFieldMapping[item.key] = item; }); - if (!draggedIds2D[baseIndex][index] && !isInBase) { + if ( + draggedIds2D[baseIndex] && + !draggedIds2D[baseIndex][index] && + !isInBase + ) { const _key = isInBlock ? blockKey : key; const prefix = 'right-' + FormDappUtil.getBlockType(fieldKey); const children = !isInBlock @@ -276,13 +286,20 @@ export default function useFetchingTemplate() { const statusDapp = templateDapps[index].label?.status || ''; const titleStatusDapp = templateDapps[index].label?.title || ''; - const thisNode = [...tokens, ...airdrops, ...stakingPools, ...yoloGames][ - index - ]; - const defaultPositionX = 30 + 500 * xOffsetCount[dappKey]++; - const defaultPositionY = 30 + 500 * allDappKeys.indexOf(dappKey); - const xOffset = thisNode?.position_x ?? defaultPositionX; - const yOffset = thisNode?.position_y ?? defaultPositionY; + const thisNode = [ + ...tokens, + ...airdrops, + ...stakingPools, + ...yoloGames, + ...whitePapers, + ][index]; + const defaultPositionX = + 50 * (xOffsetCount[dappKey] - 1) + 500 * xOffsetCount[dappKey]++; + const defaultPositionY = 30 + 500 * (allDappKeys.indexOf(dappKey) + 1); + // const xOffset = thisNode?.position_x ?? defaultPositionX; + const xOffset = defaultPositionX; + // const yOffset = thisNode?.position_y ?? defaultPositionY; + const yOffset = defaultPositionY; const idNode = index.toString(); const isHandleExists = getHandleNodeBlockChain?.data?.sourceHandles?.some( (handle) => handle === `${rootNode}-s-${templateDapps[index].title}`, @@ -312,8 +329,8 @@ export default function useFetchingTemplate() { focusable: false, markerEnd: { type: MarkerType.Arrow, - width: 25, - height: 25, + width: 20, + height: 20, strokeWidth: 1, color: '#AAAAAA', }, @@ -323,20 +340,26 @@ export default function useFetchingTemplate() { }, }); + if (dappKey === 'airdrop') { + console.log('HEHEHEHEHHEHEHE', templateDapps[index], titleStatusDapp); + } + return { id: idNode, type: 'dappTemplate', dragHandle: '.drag-handle-area', data: { - node: 'dapp', + node: 'template', label: templateDapps[index].title, status: titleStatusDapp, isChain: false, dapp: templateDapps[index], ids, baseIndex: index, - targetHandles: [`${idNode}-t-${rootNode}`], - sourceHandles: [], + // targetHandles: [`${idNode}-t-${rootNode}`], + targetHandles: [], + sourceHandles: [`${idNode}-t-${rootNode}`], + // sourceHandles: [], itemId: thisNode?.id, positionId: thisNode?.position_id, }, @@ -360,6 +383,7 @@ export default function useFetchingTemplate() { // }; // }); // } + console.log('HEHEHEHEHHEHEHE', _newNodes); const map: any = {}; for (const element of [...newNodes, ...nodesData, ..._newNodes]) { map[element.id] = element; @@ -375,7 +399,6 @@ export default function useFetchingTemplate() { } else { setEdges([...edges, ...edgeData]); } - console.log('[useFetchingTemplate] case 1'); setNodes(newArray); setNeedSetDataTemplateToBox(false); setNeedCheckAndAddAA(true); @@ -427,11 +450,21 @@ export default function useFetchingTemplate() { }) : {}; + startIndex += parsedYoloGameData.length; + const parsedWhitePaperData = parseWhitePapers(whitePapers); + const parsedWhitePaperForm = parseDappModel({ + key: DappType.white_paper, + model: parsedWhitePaperData, + startIndex: startIndex, + }); + console.log('[useFetchingTemplate] parsedTokensData', { tokens, airdrops, stakingPools, parsedWalletData, + yoloGames, + whitePapers, }); setTemplateDapps([ @@ -440,6 +473,7 @@ export default function useFetchingTemplate() { ...parsedStakingPoolsData, ...parsedYoloGameData, ...parsedWalletData, + ...parsedWhitePaperData, ]); setTemplateForm({ ...parsedTokensForm.fieldValue, @@ -447,6 +481,7 @@ export default function useFetchingTemplate() { ...parsedStakingPoolsForm.fieldValue, ...parsedYoloGameForm.fieldValue, ...((parsedWalletForm as any)?.fieldValue || {}), + ...parsedWhitePaperForm.fieldValue, } as any); setNeedSetDataTemplateToBox(true); @@ -491,30 +526,82 @@ export default function useFetchingTemplate() { const newDraggedDappIndexes = []; if (isAAInstalled) { - newDraggedDappIndexes.push(0); + const dappIndex = dapps.findIndex( + (dapp) => dapp.key === 'account_abstraction', + ); + newDraggedDappIndexes.push(dappIndex); newDraggedIds2D.push([]); } if (isBridgeInstalled) { - newDraggedDappIndexes.push(1); + const dappIndex = dapps.findIndex((dapp) => dapp.key === 'bridge_apps'); + newDraggedDappIndexes.push(dappIndex); newDraggedIds2D.push([]); } if (isGamingAppsInstalled) { - newDraggedDappIndexes.push(2); + const dappIndex = dapps.findIndex((dapp) => dapp.key === 'gaming_apps'); + newDraggedDappIndexes.push(dappIndex); newDraggedIds2D.push([]); } draggedDappIndexesSignal.value = newDraggedDappIndexes; draggedIds2DSignal.value = newDraggedIds2D; + isRenderedInUpdateFlowSignal.value = true; setNeedCheckAndAddAA(false); }; + const setPreTemplate = () => { + if (isUpdateFlow && order) { + setTemplate(order.selectedOptions || []); + } else { + // const template = searchParams.get('template'); + + // console.log('template', template, templateDefault); + + // if (template || !ENABLE_CHATBOX) { + setTemplate(templateDefault || []); + // } else if (ENABLE_CHATBOX) { + // setTemplate([]); + // } + } + + setNeedSetPreTemplate(false); + }; + + React.useEffect(() => { + setNodes([]); + setEdges([]); + setCategories([]); + setParsedCategories([]); + setCategoriesTemplates([]); + setFields({}); + setCategoryMapping({}); + setTemplateDapps([]); + setTemplateForm(null); + + setNeedSetDataTemplateToBox(false); + setNeedSetPreTemplate(false); + setNeedCheckAndAddAA(false); + + draggedIds2DSignal.value = []; + draggedDappIndexesSignal.value = []; + templateIds2DSignal.value = []; + formTemplateDappSignal.value = {}; + formDappSignal.value = {}; + + needReactFlowRenderSignal.value = true; + + setReseted(true); + }, []); + React.useEffect(() => { + if (!reseted) return; + fetchData(); // parseDappApiToDappModel(); - }, []); + }, [reseted]); React.useEffect(() => { if (!isUpdateFlow) return; @@ -542,10 +629,8 @@ export default function useFetchingTemplate() { }, [needSetDataTemplateToBox]); React.useEffect(() => { - if (isUpdateFlow && order) { - setTemplate(order.selectedOptions || []); - } else { - setTemplate(templateDefault || []); - } - }, [categoriesTemplates, isUpdateFlow, templateDefault]); + if (!needSetPreTemplate) return; + + setPreTemplate(); + }, [needSetPreTemplate]); } diff --git a/src/modules/blockchains/Buy/hooks/useGettingDappLego.ts b/src/modules/blockchains/Buy/hooks/useGettingDappLego.ts index 1c3c9d849..275227c3c 100644 --- a/src/modules/blockchains/Buy/hooks/useGettingDappLego.ts +++ b/src/modules/blockchains/Buy/hooks/useGettingDappLego.ts @@ -12,7 +12,7 @@ const useGettingDappLego = () => { const { field, setFields } = useOrderFormStoreV3(); const { dappCount } = useFormDappToFormChain(); - const { order } = useChainProvider(); + const { order, selectedCategoryMapping } = useChainProvider(); console.log('[useGettingDappLego]', dappCount); @@ -66,38 +66,30 @@ const useGettingDappLego = () => { console.log('[useGettingDappLego] 111', { dappCount, newField }); for (const fieldKey in newField) { - const selectedCategory = order?.selectedOptions?.find( - (c) => c.key === fieldKey, - ); const category = categories?.find((c) => c.key === fieldKey); - console.log('[useGettingDappLego] 222', { - fieldKey, - category, - }); if (!category || ignoreKeys.includes(category.key) || category.isChain) continue; - console.log('[useGettingDappLego] 333', newField[fieldKey].value); - if (Array.isArray(newField[fieldKey].value)) { const newValues = (newField[fieldKey].value as string[]).filter( (v) => - !!dappCount[chainKeyToDappKey(v)] && - !selectedCategory?.options.find((c) => c.key === v), + !!( + !!dappCount[chainKeyToDappKey(v)] || + selectedCategoryMapping?.[fieldKey]?.options.find( + (o) => o.key === v, + ) + ), ); const isEmpty = newValues.length === 0; - console.log('[useGettingDappLego] 444', { - newValues, - isEmpty, - }); - newField[fieldKey].value = isEmpty ? null : newValues; newField[fieldKey].dragged = !isEmpty; } } + console.log('[useGettingDappLego] 555', { newField, newDraggedFields }); + setFields(newField); setDraggedFields(newDraggedFields); }; diff --git a/src/modules/blockchains/Buy/hooks/useHandleDragging.ts b/src/modules/blockchains/Buy/hooks/useHandleDragging.ts index ae27f6610..7e0ce28d0 100644 --- a/src/modules/blockchains/Buy/hooks/useHandleDragging.ts +++ b/src/modules/blockchains/Buy/hooks/useHandleDragging.ts @@ -39,7 +39,7 @@ import useOverlappingChainLegoStore from '../stores/useOverlappingChainLegoStore export default function useHandleDragging() { const { setOverlappingId } = useOverlappingChainLegoStore(); - const { nodes, setNodes, edges, setEdges } = useFlowStore(); + const { nodes, setNodes, edges, setEdges, setRemovedNode } = useFlowStore(); const { setIdDragging, rightDragging, @@ -128,10 +128,16 @@ export default function useHandleDragging() { const ignoreKeys = ['bridge_apps', 'gaming_apps']; console.log('runnnnnnnn 1'); if (!rightDragging && !overIsFinalDroppable && overSuffix1 !== 'right') { - if(isMultiChoice) { + if (isMultiChoice) { const currentValues = (field[activeKey].value || []) as string[]; const isCurrentEmpty = currentValues.length === 0; const newValue = [...currentValues, active.data.current.value]; + const bridgeAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'bridge_apps', + ); + const gamingAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'gaming_apps', + ); if (currentValues.includes(active.data.current.value)) return; @@ -140,19 +146,25 @@ export default function useHandleDragging() { if ( activeKey === 'bridge_apps' && - !draggedDappIndexesSignal.value.includes(1) && + !draggedDappIndexesSignal.value.includes(bridgeAppsIndex) && !activeIsParent ) { - draggedDappIndexesSignal.value = [...draggedDappIndexesSignal.value, 1]; + draggedDappIndexesSignal.value = [ + ...draggedDappIndexesSignal.value, + bridgeAppsIndex, + ]; draggedIds2DSignal.value = [...draggedIds2DSignal.value, []]; } if ( activeKey === 'gaming_apps' && - !draggedDappIndexesSignal.value.includes(2) && + !draggedDappIndexesSignal.value.includes(gamingAppsIndex) && !activeIsParent ) { - draggedDappIndexesSignal.value = [...draggedDappIndexesSignal.value, 2]; + draggedDappIndexesSignal.value = [ + ...draggedDappIndexesSignal.value, + gamingAppsIndex, + ]; draggedIds2DSignal.value = [...draggedIds2DSignal.value, []]; } @@ -262,12 +274,18 @@ export default function useHandleDragging() { // setValueOptionInputStore(optionKey, ''); deleteValueOptionInputStore(optionKey); }); + const bridgeAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'bridge_apps', + ); + const gamingAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'gaming_apps', + ); setField(activeKey, [], false); setDraggedFields(draggedFields.filter((field) => field !== activeKey)); if (activeKey === 'bridge_apps') { - const index = draggedDappIndexesSignal.value.indexOf(1); + const index = draggedDappIndexesSignal.value.indexOf(bridgeAppsIndex); if (index !== -1) { draggedDappIndexesSignal.value = removeItemAtIndex( @@ -279,11 +297,13 @@ export default function useHandleDragging() { index, ); } + console.log('nodessssss', nodes[ index + 1 + totalTemplateDapps]); + setRemovedNode(nodes[ index + 1 + totalTemplateDapps]) setNodes(removeItemAtIndex(nodes, index + 1 + totalTemplateDapps)); } if (activeKey === 'gaming_apps') { - const index = draggedDappIndexesSignal.value.indexOf(2); + const index = draggedDappIndexesSignal.value.indexOf(gamingAppsIndex); if (index !== -1) { draggedDappIndexesSignal.value = removeItemAtIndex( @@ -295,6 +315,8 @@ export default function useHandleDragging() { index, ); } + console.log('nodessssss1', nodes[ index + 1 + totalTemplateDapps]); + setRemovedNode(nodes[ index + 1 + totalTemplateDapps]) setNodes(removeItemAtIndex(nodes, index + 1 + totalTemplateDapps)); } @@ -303,13 +325,20 @@ export default function useHandleDragging() { console.log('runnnnnnnn 7'); // Multi choice case if ( - ((over && (overIsFinalDroppable || overIsParentOfActiveDroppable)) || - (!overIsFinalDroppable && overSuffix1 === 'right')) || !over + (over && (overIsFinalDroppable || overIsParentOfActiveDroppable)) || + (!overIsFinalDroppable && overSuffix1 === 'right') || + !over ) { console.log('runnnnnnnn 8'); const currentValues = (field[activeKey].value || []) as string[]; const isCurrentEmpty = currentValues.length === 0; const newValue = [...currentValues, active.data.current.value]; + const bridgeAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'bridge_apps', + ); + const gamingAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'gaming_apps', + ); if (currentValues.includes(active.data.current.value)) return; @@ -318,19 +347,25 @@ export default function useHandleDragging() { if ( activeKey === 'bridge_apps' && - !draggedDappIndexesSignal.value.includes(1) && + !draggedDappIndexesSignal.value.includes(bridgeAppsIndex) && !activeIsParent ) { - draggedDappIndexesSignal.value = [...draggedDappIndexesSignal.value, 1]; + draggedDappIndexesSignal.value = [ + ...draggedDappIndexesSignal.value, + bridgeAppsIndex, + ]; draggedIds2DSignal.value = [...draggedIds2DSignal.value, []]; } if ( activeKey === 'gaming_apps' && - !draggedDappIndexesSignal.value.includes(2) && + !draggedDappIndexesSignal.value.includes(gamingAppsIndex) && !activeIsParent ) { - draggedDappIndexesSignal.value = [...draggedDappIndexesSignal.value, 2]; + draggedDappIndexesSignal.value = [ + ...draggedDappIndexesSignal.value, + gamingAppsIndex, + ]; draggedIds2DSignal.value = [...draggedIds2DSignal.value, []]; } } else { @@ -353,10 +388,16 @@ export default function useHandleDragging() { setField(activeKey, newValue, !isEmpty); if (isEmpty) { + const bridgeAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'bridge_apps', + ); + const gamingAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'gaming_apps', + ); setDraggedFields(draggedFields.filter((field) => field !== activeKey)); if (activeKey === 'bridge_apps') { - const index = draggedDappIndexesSignal.value.indexOf(1); + const index = draggedDappIndexesSignal.value.indexOf(bridgeAppsIndex); if (index !== -1) { draggedDappIndexesSignal.value = removeItemAtIndex( @@ -367,12 +408,14 @@ export default function useHandleDragging() { draggedIds2DSignal.value, index, ); + console.log('nodessssss2', nodes[ index + 1 + totalTemplateDapps]); + setRemovedNode(nodes[ index + 1 + totalTemplateDapps]) setNodes(removeItemAtIndex(nodes, index + 1 + totalTemplateDapps)); } } if (activeKey === 'gaming_apps') { - const index = draggedDappIndexesSignal.value.indexOf(2); + const index = draggedDappIndexesSignal.value.indexOf(gamingAppsIndex); if (index !== -1) { draggedDappIndexesSignal.value = removeItemAtIndex( @@ -383,6 +426,8 @@ export default function useHandleDragging() { draggedIds2DSignal.value, index, ); + console.log('nodessssss3', nodes[ index + 1 + totalTemplateDapps]); + setRemovedNode(nodes[ index + 1 + totalTemplateDapps]) setNodes(removeItemAtIndex(nodes, index + 1 + totalTemplateDapps)); } } @@ -837,7 +882,7 @@ export default function useHandleDragging() { if (activeIsABaseModule) { const totalPlaced = draggedDappIndexesSignal.value.filter( (index) => index === dappIndex, - ).length + ).length; // prettier-ignore const canPlaceMoreBaseModule = baseModuleFieldMapping[dappIndex][activeOriginalKey].placableAmount === -1 || totalPlaced < baseModuleFieldMapping[dappIndex][activeOriginalKey].placableAmount; @@ -1078,17 +1123,21 @@ export default function useHandleDragging() { if (activeIsABase) { const totalTemplateDapps = (templateDapps || []).length; const removeIndex = activeBaseIndex + 1 + totalTemplateDapps; + console.log('JK HEHEHHE', { + nodes: nodes, + edges: edges.length, + removeIndex, + activeBaseIndex, + totalTemplateDapps, + }); const rootNode = 'blockchain'; + console.log('nodessssss', nodes[removeIndex]); + setRemovedNode(nodes[removeIndex]) - const newEdges = edges.filter( - (item) => item.target !== nodes[removeIndex].id, - ); let newNodes = removeItemAtIndex(nodes, removeIndex); - let getHandleNodeBlockChain = nodes.find( (item) => item.id === rootNode, ); - let countSourceHandle = 0; for (let i = 0; i < edges.length; i++) { @@ -1152,10 +1201,9 @@ export default function useHandleDragging() { }, }; }); - + console.log('JK HEHEHHE newNodes', newNodes); //Drag remove node setNodes(newNodes); - setEdges(newEdges); needReactFlowRenderSignal.value = true; return; diff --git a/src/modules/blockchains/Buy/hooks/useLineIssueToken.ts b/src/modules/blockchains/Buy/hooks/useLineIssueToken.ts new file mode 100644 index 000000000..1c9ff3667 --- /dev/null +++ b/src/modules/blockchains/Buy/hooks/useLineIssueToken.ts @@ -0,0 +1,188 @@ +import React, { useEffect } from 'react'; +import useFlowStore from '@/modules/blockchains/Buy/stores/useFlowStore'; +import { useParams } from 'next/navigation'; +import { useAAModule } from '@/modules/blockchains/detail_v4/hook/useAAModule'; +import { Edge, MarkerType } from '@xyflow/react'; +import { useChainProvider } from '@/modules/blockchains/detail_v4/provider/ChainProvider.hook'; +import handleStatusEdges from '@utils/helpers'; + +function useLineIssueToken(): void { + const { nodes, edges, setEdges } = useFlowStore() + const params = useParams(); + const isUpdateFlow = React.useMemo(() => !!params.id, [params.id]); + const { aaInstalledData } = useAAModule(); + const { getAAStatus } = useChainProvider(); + const { lineAAStatus } = useAAModule(); + function addLineIssueToken() { + if(nodes.length === 0) return; + const newEdges: Edge[] = []; + const nodesWithoutRoot = nodes.filter(node => node.id !== 'blockchain'); + // @ts-ignore + const tokenNodes = nodesWithoutRoot.filter(node => node.data?.dapp?.key === 'token_generation'); + // @ts-ignore + const dappNodes = nodesWithoutRoot.filter(node => node.data?.dapp?.key !== "token_generation"); + + + dappNodes.forEach(node => { + const dataNode = node.data; + // @ts-ignore + const tokenNameOfAirdrop = dataNode?.dapp?.baseBlock?.fields.find((item: any) => item.key == 'reward_token'); + // @ts-ignore + const tokenNameOfYOLO = dataNode?.dapp?.baseBlock?.fields.find((item: any) => item.key == 'settlement_token'); + // @ts-ignore + const statusNode = dataNode?.status; + tokenNodes.forEach(issueTokenNode => { + // @ts-ignore + const tokenNameOfIssueToken = issueTokenNode.data?.dapp?.baseBlock?.fields.find((item: any) => item.key == 'token_symbol'); + + // AA Node + // @ts-ignore + if(node.id === 'account_abstraction' && issueTokenNode.data?.dapp?.label?.actionID === aaInstalledData?.aaPaymasterTokenID) { + dataNode.sourceHandles.push(`account_abstraction-t-${issueTokenNode.id}`); + issueTokenNode.data.sourceHandles.push(`${issueTokenNode.id}-s-account_abstraction`) + const issueTokenToAA: Edge = { + id: `${Math.random()}`, + source: issueTokenNode.id, + target: node.id, + sourceHandle: `${issueTokenNode.id}-s-account_abstraction`, + targetHandle: `account_abstraction-t-${issueTokenNode.id}`, + label: handleStatusEdges('', lineAAStatus, 'account_abstraction') + .icon, + animated: handleStatusEdges('', lineAAStatus, 'account_abstraction') + .animate, + type: 'customEdge', + selectable: false, + selected: false, + focusable: false, + markerEnd: { + type: MarkerType.Arrow, + width: 20, + height: 20, + strokeWidth: 1, + color: '#FA9984', + }, + style: { + stroke: '#FA9984', + strokeWidth: 2, + }, + } + newEdges.push(issueTokenToAA); + } + + // Airdrop Node + // @ts-ignore + if(dataNode?.dapp?.id === 'airdrop' && tokenNameOfAirdrop?.options[0].key == tokenNameOfIssueToken?.value && checkStatusNode(statusNode)) { + dataNode.sourceHandles.push(`airdrop-t-${issueTokenNode.id}`); + issueTokenNode.data.sourceHandles.push(`${issueTokenNode.id}-s-airdrop`) + const issueTokenToAirdrop: Edge = { + id: `${Math.random()}`, + source: issueTokenNode.id, + target: node.id, + sourceHandle: `${issueTokenNode.id}-s-airdrop`, + targetHandle: `airdrop-t-${issueTokenNode.id}`, + label: '', + animated: false, + type: 'customEdge', + selectable: false, + selected: false, + focusable: false, + markerEnd: { + type: MarkerType.Arrow, + width: 20, + height: 20, + strokeWidth: 1, + color: '#FA9984', + }, + style: { + stroke: '#FA9984', + strokeWidth: 2, + }, + }; + newEdges.push(issueTokenToAirdrop); + } + + // Staking Node + // @ts-ignore + if(dataNode?.dapp?.id === 'staking' && tokenNameOfAirdrop?.options[0].key == tokenNameOfIssueToken?.value && checkStatusNode(statusNode)) { + dataNode.sourceHandles.push(`staking-t-${issueTokenNode.id}`); + issueTokenNode.data.sourceHandles.push(`${issueTokenNode.id}-s-staking`) + const issueTokenToStaking: Edge = { + id: `${Math.random()}`, + source: issueTokenNode.id, + target: node.id, + sourceHandle: `${issueTokenNode.id}-s-staking`, + targetHandle: `staking-t-${issueTokenNode.id}`, + label: '', + animated: false, + type: 'customEdge', + selectable: false, + selected: false, + focusable: false, + markerEnd: { + type: MarkerType.Arrow, + width: 20, + height: 20, + strokeWidth: 1, + color: '#FA9984', + }, + style: { + stroke: '#FA9984', + strokeWidth: 2, + }, + }; + newEdges.push(issueTokenToStaking); + } + + // Yolo Node + // @ts-ignore + if(dataNode?.dapp?.id === 'yologame' && tokenNameOfYOLO?.options[0].key == tokenNameOfIssueToken?.value && checkStatusNode(statusNode)) { + dataNode.sourceHandles.push(`yologame-t-${issueTokenNode.id}`); + issueTokenNode.data.sourceHandles.push(`${issueTokenNode.id}-s-yologame`) + const issueTokenToYolo: Edge = { + id: `${Math.random()}`, + source: issueTokenNode.id, + target: node.id, + sourceHandle: `${issueTokenNode.id}-s-yologame`, + targetHandle: `yologame-t-${issueTokenNode.id}`, + label: '', + animated: false, + type: 'customEdge', + selectable: false, + selected: false, + focusable: false, + markerEnd: { + type: MarkerType.Arrow, + width: 20, + height: 20, + strokeWidth: 1, + color: '#FA9984', + }, + style: { + stroke: '#FA9984', + strokeWidth: 2, + }, + }; + newEdges.push(issueTokenToYolo); + } + }) + + }) + + setEdges([...edges, ...newEdges]); + + } + + function checkStatusNode(status: string) { + const statusConnect = ['Processing', 'Running', 'Deployed']; + return statusConnect.some(statusApprove => statusApprove === status); + } + + useEffect(() => { + if (!isUpdateFlow) return; + addLineIssueToken(); + }, [nodes.length]); + +} + + +export default useLineIssueToken; diff --git a/src/modules/blockchains/Buy/hooks/useNodeAction.ts b/src/modules/blockchains/Buy/hooks/useNodeAction.ts new file mode 100644 index 000000000..bb0956a14 --- /dev/null +++ b/src/modules/blockchains/Buy/hooks/useNodeAction.ts @@ -0,0 +1,33 @@ +import { + draggedDappIndexesSignal, + draggedIds2DSignal, +} from '../signals/useDragSignal'; +import useDappsStore from '../stores/useDappStore'; +import useDraggingStore from '../stores/useDraggingStore'; + +const useNodeAction = () => { + const { dapps } = useDappsStore(); + const { setIsDragging } = useDraggingStore(); + + const handleOnClickCreateToken = () => { + const tokenDappIndex = dapps.findIndex( + (item) => item.key === 'token_generation', + ); + + setIsDragging(true); + + setTimeout(() => { + draggedDappIndexesSignal.value = [ + ...draggedDappIndexesSignal.value, + tokenDappIndex, + ]; + draggedIds2DSignal.value = [...draggedIds2DSignal.value, []]; + }, 300); + }; + + return { + handleOnClickCreateToken, + }; +}; + +export default useNodeAction; diff --git a/src/modules/blockchains/Buy/hooks/useNodeFlowControl.ts b/src/modules/blockchains/Buy/hooks/useNodeFlowControl.ts index c4485bbf5..5d81b7395 100644 --- a/src/modules/blockchains/Buy/hooks/useNodeFlowControl.ts +++ b/src/modules/blockchains/Buy/hooks/useNodeFlowControl.ts @@ -17,7 +17,12 @@ import useFlowStore, { AppState } from '../stores/useFlowStore'; import { mouseDroppedPositionSignal } from '@/modules/blockchains/Buy/signals/useMouseDroppedPosition'; import useDraggingStore from '@/modules/blockchains/Buy/stores/useDraggingStore'; import { needReactFlowRenderSignal } from '@/modules/blockchains/Buy/studio/ReactFlowRender'; +import { useAAModule } from '@/modules/blockchains/detail_v4/hook/useAAModule'; +import { useBridgesModule } from '@/modules/blockchains/detail_v4/hook/useBridgesModule'; +import { useGameModule } from '@/modules/blockchains/detail_v4/hook/useGameModule'; +import { IModelOption } from '@/types/customize-model'; import { DappNode } from '@/types/node'; +import handleStatusEdges from '@utils/helpers'; import { useChainProvider } from '../../detail_v4/provider/ChainProvider.hook'; import { dappKeyToNodeKey } from '../component4/YourNodes/node.constants'; import { @@ -28,10 +33,6 @@ import { import { useTemplateFormStore } from '../stores/useDappStore'; import useDraggedId2DStore from '../stores/useDraggedId2DStore'; import useModelCategoriesStore from '../stores/useModelCategoriesStore'; -import handleStatusEdges from '@utils/helpers'; -import { useAAModule } from '@/modules/blockchains/detail_v4/hook/useAAModule'; -import { useBridgesModule } from '@/modules/blockchains/detail_v4/hook/useBridgesModule'; -import { IModelOption } from '@/types/customize-model'; export default function useNodeFlowControl() { const { dapps } = useDapps(); @@ -41,6 +42,7 @@ export default function useNodeFlowControl() { const store = useStoreApi(); const { lineAAStatus } = useAAModule(); const { lineBridgeStatus } = useBridgesModule(); + const { statusMapper, getGameTypeIconUrl } = useGameModule(); const { transform: [transformX, transformY, zoomLevel], } = store.getState(); @@ -89,7 +91,6 @@ export default function useNodeFlowControl() { } as any; setNodes(newNodes); - console.log('[useNodeFlowControl] xxxxxx'); resetDragState(); } else if (!dragState.twoD.every((v) => v === -1)) { // handleAddBox(); @@ -97,6 +98,15 @@ export default function useNodeFlowControl() { }; useSignalEffect(() => { + const bridgeAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'bridge_apps', + ); + const gamingAppsIndex = dapps.findIndex( + (dapp) => dapp.key === 'gaming_apps', + ); + const accountAbstractionIndex = dapps.findIndex( + (dapp) => dapp.key === 'account_abstraction', + ); console.log('[useNodeFlowControl]', { nodes }); needReactFlowRenderSignal.value = true; @@ -105,7 +115,10 @@ export default function useNodeFlowControl() { needReactFlowRenderSignal.value = true; - if (draggedDappIndexesSignal.value.includes(0) && isAAInstalled) { + if ( + draggedDappIndexesSignal.value.includes(accountAbstractionIndex) && + isAAInstalled + ) { if (!nodes.some((node) => node.id === 'account_abstraction')) { const rootNode = 'blockchain'; const thisDapp = accountAbstractionAsADapp; @@ -123,7 +136,7 @@ export default function useNodeFlowControl() { id: newNodeId, type: dappKeyToNodeKey(thisDapp.key), dragHandle: '.drag-handle-area', - position: { x: 0, y: 0 }, + position: { x: 950, y: 30 }, data: { node: 'dapp', title: thisDapp.title, @@ -131,11 +144,12 @@ export default function useNodeFlowControl() { baseIndex: draggedIds2D.length - 1, categoryOption: categoryOption as IModelOption, ids: draggedIds2D[draggedIds2D.length - 1], - targetHandles: [`account_abstraction-t-${rootNode}`], - sourceHandles: [], + // targetHandles: [`account_abstraction-t-${rootNode}`], + targetHandles: [], + sourceHandles: [`account_abstraction-t-${rootNode}`], + // sourceHandles: [], }, }; - console.log('[useNodeFlowControl], zzzzzzzzzzzz'); setNodes([...nodesData, newNode]); setEdges([ ...edges, @@ -157,8 +171,8 @@ export default function useNodeFlowControl() { .animate, markerEnd: { type: MarkerType.Arrow, - width: 25, - height: 25, + width: 20, + height: 20, strokeWidth: 1, color: '#AAAAAA', }, @@ -172,9 +186,10 @@ export default function useNodeFlowControl() { } } - if (draggedDappIndexesSignal.value.includes(1) && isBridgeInstalled) { - console.log('[useNodeFlowControl] case 1'); - + if ( + draggedDappIndexesSignal.value.includes(bridgeAppsIndex) && + isBridgeInstalled + ) { if (!nodes.some((node) => node.id === 'bridge_apps')) { const rootNode = 'blockchain'; const thisDapp = bridgesAsADapp; @@ -184,7 +199,7 @@ export default function useNodeFlowControl() { id: newNodeId, type: dappKeyToNodeKey(thisDapp.key), dragHandle: '.drag-handle-area', - position: { x: 0, y: 0 }, + position: { x: 500, y: 30 }, data: { node: 'dapp', title: thisDapp.title, @@ -192,11 +207,12 @@ export default function useNodeFlowControl() { baseIndex: 0, categoryOption: {} as IModelOption, ids: [], - targetHandles: [`bridge_apps-t-${rootNode}`], - sourceHandles: [], + // targetHandles: [`bridge_apps-t-${rootNode}`], + targetHandles: [], + sourceHandles: [`bridge_apps-t-${rootNode}`], + // sourceHandles: [], }, }; - console.log('[useNodeFlowControl], qqqqqqqq'); setNodes([...nodesData, newNode]); setEdges([ @@ -218,8 +234,8 @@ export default function useNodeFlowControl() { type: 'customEdge', markerEnd: { type: MarkerType.Arrow, - width: 25, - height: 25, + width: 20, + height: 20, strokeWidth: 1, color: '#AAAAAA', }, @@ -233,17 +249,20 @@ export default function useNodeFlowControl() { } } - if (draggedDappIndexesSignal.value.includes(2) && isGamingAppsInstalled) { + if ( + draggedDappIndexesSignal.value.includes(gamingAppsIndex) && + isGamingAppsInstalled + ) { if (!nodes.some((node) => node.id === 'gaming_apps')) { const rootNode = 'blockchain'; - const thisDapp = bridgesAsADapp; + const thisDapp = gamingAppsAsADapp; let nodesData = nodes; const newNodeId = 'gaming_apps'; const newNode: DappNode = { id: newNodeId, type: dappKeyToNodeKey(thisDapp.key), dragHandle: '.drag-handle-area', - position: { x: 0, y: 0 }, + position: { x: 1500, y: 30 }, data: { node: 'dapp', title: thisDapp.title, @@ -251,12 +270,12 @@ export default function useNodeFlowControl() { baseIndex: 0, categoryOption: {} as IModelOption, ids: [], - targetHandles: [`gaming_apps-t-${rootNode}`], - sourceHandles: [], + // targetHandles: [`gaming_apps-t-${rootNode}`], + targetHandles: [], + sourceHandles: [`gaming_apps-t-${rootNode}`], + // sourceHandles: [], }, }; - console.log('[useNodeFlowControl], wwwwwwwwww'); - setNodes([...nodesData, newNode]); setEdges([ ...edges, @@ -267,9 +286,13 @@ export default function useNodeFlowControl() { sourceHandle: `${rootNode}-s-gaming_apps`, // target: `${newNodeId}`, target: `gaming_apps`, - label: handleStatusEdges('', lineBridgeStatus, 'gaming_apps').icon, - animated: handleStatusEdges('', lineBridgeStatus, 'gaming_apps') - .animate, + label: handleStatusEdges('', statusMapper.statusStr, 'gaming_apps') + .icon, + animated: handleStatusEdges( + '', + statusMapper.statusStr, + 'gaming_apps', + ).animate, targetHandle: `gaming_apps-t-${rootNode}`, selectable: false, selected: false, @@ -277,8 +300,8 @@ export default function useNodeFlowControl() { type: 'customEdge', markerEnd: { type: MarkerType.Arrow, - width: 25, - height: 25, + width: 20, + height: 20, strokeWidth: 1, color: '#AAAAAA', }, @@ -353,19 +376,14 @@ export default function useNodeFlowControl() { return; } - const transformedX = - (mouseDroppedPositionSignal.value.x - transformX) / zoomLevel; - const transformedY = - (mouseDroppedPositionSignal.value.y - transformY) / zoomLevel; - const positionTo = { - x: transformedX, - y: transformedY, - }; - const rootNode = 'blockchain'; let suffix = thisDapp.title; let statusMapping: any = ''; let newNodeId = `${nodes.length + 1}`; + let transformedX = + (mouseDroppedPositionSignal.value.x - transformX) / zoomLevel; + let transformedY = + (mouseDroppedPositionSignal.value.y - transformY) / zoomLevel; switch (thisDapp.key) { case accountAbstractionAsADapp.key: @@ -387,6 +405,11 @@ export default function useNodeFlowControl() { break; } + const positionTo = { + x: transformedX, + y: transformedY, + }; + const getHandleNodeBlockChain = nodes.find((item) => item.id === rootNode); const isHandleExists = edges.some( (handle) => handle.sourceHandle === `${rootNode}-s-${suffix}`, @@ -420,17 +443,17 @@ export default function useNodeFlowControl() { baseIndex: draggedIds2D.length - 1, categoryOption: categoryOption as IModelOption, ids: draggedIds2D[draggedIds2D.length - 1], - targetHandles: [`${newNodeId}-t-${rootNode}`], - sourceHandles: [], + // targetHandles: [`${newNodeId}-t-${rootNode}`], + targetHandles: [], + sourceHandles: [`${newNodeId}-t-${rootNode}`], + // sourceHandles: [], }, }; - console.log('[useNodeFlowControl], eeeeeeeeeeee'); - + console.log('statusMapping', statusMapping); setNodes([...nodesData, newNode]); setEdges([ ...edges, { - // id: `${edges.length + 1}`, id: `${Math.random()}`, source: rootNode, sourceHandle: `${rootNode}-s-${suffix}`, @@ -445,8 +468,8 @@ export default function useNodeFlowControl() { .animate, markerEnd: { type: MarkerType.Arrow, - width: 25, - height: 25, + width: 20, + height: 20, strokeWidth: 1, color: '#AAAAAA', }, @@ -458,7 +481,6 @@ export default function useNodeFlowControl() { ]); needReactFlowRenderSignal.value = true; resetDragState(); - console.log('run handleAddBox end'); }; return { diff --git a/src/modules/blockchains/Buy/hooks/useNodeHelper.ts b/src/modules/blockchains/Buy/hooks/useNodeHelper.ts index bfeba1156..934f91c7b 100644 --- a/src/modules/blockchains/Buy/hooks/useNodeHelper.ts +++ b/src/modules/blockchains/Buy/hooks/useNodeHelper.ts @@ -1,3 +1,4 @@ +import React from 'react'; import { IModelOption } from '@/types/customize-model'; import { DappNode } from '@/types/node'; import { MarkerType } from '@xyflow/react'; @@ -21,7 +22,15 @@ const useNodeHelper = () => { const { nodes, setNodes, edges, setEdges } = useFlowStore(); const { setDraggedIds2D } = useDraggedId2DStore(); - const addDappToNode = (dappIndex: number) => { + const [newState, setNewState] = React.useState({ + nodes, + edges, + }); + + const addDappToNode = ( + dappIndex: number, + { x = 600, y = 30 }: { x: number; y: number }, + ) => { const thisDapp = dapps[dappIndex]; if (!thisDapp) { return; @@ -40,11 +49,6 @@ const useNodeHelper = () => { return; } - const positionTo = { - x: 600, - y: 30, - }; - const rootNode = 'blockchain'; let suffix = thisDapp.title; @@ -53,7 +57,6 @@ const useNodeHelper = () => { (handle) => handle.sourceHandle === `${rootNode}-s-${suffix}`, ); let nodesData = nodes; - console.log('nodes frist', nodesData); if (!isHandleExists) { getHandleNodeBlockChain?.data?.sourceHandles?.push( @@ -83,81 +86,66 @@ const useNodeHelper = () => { id: newNodeId, type: dappKeyToNodeKey(thisDapp.key), dragHandle: '.drag-handle-area', - position: positionTo, + position: { + x, + y, + }, data: { node: 'dapp', title: thisDapp.title, dapp: thisDapp, - baseIndex: 0, + baseIndex: draggedIds2DSignal.value.length - 1, categoryOption: categoryOption as IModelOption, ids, - targetHandles: [`${newNodeId}-t-${rootNode}`], - sourceHandles: [], + targetHandles: [], + sourceHandles: [`${newNodeId}-t-${rootNode}`], }, }; - - draggedDappIndexesSignal.value = [dappIndex]; - draggedIds2DSignal.value = [[]]; - setDraggedIds2D([]); - console.log('[useSetDefaultDapp] case 1'); - - setNodes([...nodesData, newNode]); - setEdges([ - ...edges, - { - id: `${Math.random()}`, - source: rootNode, - sourceHandle: `${rootNode}-s-${suffix}`, - target: `${newNodeId}`, - targetHandle: `${newNodeId}-t-${rootNode}`, - type: 'customEdge', - label: '', - selectable: false, - selected: false, - focusable: false, - markerEnd: { - type: MarkerType.Arrow, - width: 25, - height: 25, - strokeWidth: 1, - color: '#AAAAAA', - }, - animated: true, - style: { - stroke: '#AAAAAA', - strokeWidth: 2, - }, + const newEdge = { + id: `${Math.random()}`, + source: rootNode, + sourceHandle: `${rootNode}-s-${suffix}`, + target: `${newNodeId}`, + targetHandle: `${newNodeId}-t-${rootNode}`, + type: 'customEdge', + label: '', + selectable: false, + selected: false, + focusable: false, + markerEnd: { + type: MarkerType.Arrow, + width: 25, + height: 25, + strokeWidth: 1, + color: '#AAAAAA', }, - ]); - needReactFlowRenderSignal.value = true; - console.log('[...nodesData, newNode]', [...nodesData, newNode]); - console.log('edge', [ - ...edges, - { - id: `${Math.random()}`, - source: rootNode, - sourceHandle: `${rootNode}-s-${suffix}`, - target: `${newNodeId}`, - targetHandle: `${newNodeId}-t-${rootNode}`, - type: 'customEdge', - label: '', - selectable: false, - selected: false, - focusable: false, - markerEnd: { - type: MarkerType.Arrow, - width: 25, - height: 25, - strokeWidth: 1, - color: '#AAAAAA', - }, - animated: true, - style: { - stroke: '#AAAAAA', - strokeWidth: 2, - }, + animated: true, + style: { + stroke: '#AAAAAA', + strokeWidth: 2, }, - ]); + }; + + draggedDappIndexesSignal.value = [ + ...draggedDappIndexesSignal.value, + dappIndex, + ]; + draggedIds2DSignal.value = [...draggedIds2DSignal.value, ids]; + + setDraggedIds2D([...draggedIds2DSignal.value]); + setNodes([...newState.nodes, newNode]); + setEdges([...newState.edges, newEdge]); + setNewState({ + nodes: [...newState.nodes, newNode], + edges: [...newState.edges, newEdge], + }); + + console.log('[SocketProvider] addDappToNode', { + nodes: [...newState.nodes, newNode], + edges: [...newState.edges, newEdge], + }); + + needReactFlowRenderSignal.value = true; }; return { addDappToNode }; diff --git a/src/modules/blockchains/Buy/hooks/useOnlyFetchDapp.ts b/src/modules/blockchains/Buy/hooks/useOnlyFetchDapp.ts index 44b085dec..24ca1a14d 100644 --- a/src/modules/blockchains/Buy/hooks/useOnlyFetchDapp.ts +++ b/src/modules/blockchains/Buy/hooks/useOnlyFetchDapp.ts @@ -4,14 +4,11 @@ import { useAppSelector } from '@/stores/hooks'; import { commonSelector } from '@/stores/states/common/selector'; import { dappSelector } from '@/stores/states/dapp/selector'; import { useParams, usePathname } from 'next/navigation'; -import { - accountAbstractionAsADapp, - bridgesAsADapp, - dappMockupData, - gamingAppsAsADapp, -} from '../mockup_3'; +import { accountAbstractionAsADapp, bridgesAsADapp, dappMockupData, gamingAppsAsADapp } from '../mockup_3'; import useDappsStore from '../stores/useDappStore'; -import { cloneDeep, preDataAirdropTask, preDataYoloGame } from '../utils'; +import { cloneDeep, preDataAirdropTask, preDataWhitePaper, preDataYoloGame } from '../utils'; +import { DappType } from '@/modules/blockchains/dapp/types'; +import { orderBy } from 'lodash'; const useOnlyFetchDapp = () => { const pathname = usePathname(); @@ -24,6 +21,60 @@ const useOnlyFetchDapp = () => { const dappState = useAppSelector(dappSelector); const { configs, tokens, airdropTasks, tokensAll } = dappState; + const configsMapping = React.useMemo(() => { + const _tokens = orderBy(tokensAll?.filter(token => token?.symbol && token.contract_address), token => token?.is_native, 'desc').map(token => ({ + key: token.contract_address || '', + title: token?.symbol || '', + value: token.contract_address || '', // contract_address + icon: token.image_url, // image_url + tooltip: '', + type: '', + options: [], + selectable: true, + })); + return configs?.map(config => { + switch (config.key) { + case DappType.staking: { + return { + ...config, + baseBlock: { + ...config.baseBlock, + fields: config.baseBlock.fields.map(field => { + if (field.key === 'staking_token' || field.key === 'reward_token') { + return { + ...field, + options: _tokens + } + } + return field; + }) + } + } + } + case DappType.airdrop: { + return { + ...config, + baseBlock: { + ...config.baseBlock, + fields: config.baseBlock.fields.map(field => { + if (field.key === 'reward_token') { + return { + ...field, + options: _tokens + } + } + return field; + }) + } + } + } + default: { + return config + } + } + }) + }, [configs, tokensAll]); + const fetchDapps = () => { const _dapps = [ accountAbstractionAsADapp, @@ -33,20 +84,23 @@ const useOnlyFetchDapp = () => { const otherDapps = isUpdateChain ? // ? cloneDeep(dappFromAPIMockupData) - cloneDeep(configs) + cloneDeep(configsMapping as any) : cloneDeep(dappMockupData); // defi_apps _dapps.push(...otherDapps); - const sortedDapps = _dapps.sort((a, b) => a.order - b.order); - - setDapps(preDataAirdropTask(sortedDapps, tokens, airdropTasks)); - setDapps(preDataYoloGame(sortedDapps, tokensAll)); + let sortedDapps = _dapps.sort((a, b) => a.order - b.order); + sortedDapps = preDataAirdropTask(sortedDapps, tokens, airdropTasks); + sortedDapps = preDataYoloGame(sortedDapps, tokensAll); + sortedDapps = preDataWhitePaper(sortedDapps, tokens); + setDapps(sortedDapps); + console.log('[useOnlyFetchDapp] dapps', sortedDapps); + // setDapps(preDataYoloGame(sortedDapps, tokensAll)); }; React.useEffect(() => { fetchDapps(); - }, [counterFetchedDapp, pathname, JSON.stringify(configs || {})]); + }, [counterFetchedDapp, pathname, JSON.stringify(configsMapping || {}), JSON.stringify(airdropTasks || {})]); }; export default useOnlyFetchDapp; diff --git a/src/modules/blockchains/Buy/hooks/useSetDefaultDapp.ts b/src/modules/blockchains/Buy/hooks/useSetDefaultDapp.ts index f5536e15e..84da52d8b 100644 --- a/src/modules/blockchains/Buy/hooks/useSetDefaultDapp.ts +++ b/src/modules/blockchains/Buy/hooks/useSetDefaultDapp.ts @@ -4,6 +4,9 @@ import useFlowStore from '../stores/useFlowStore'; import useModelCategoriesStore from '../stores/useModelCategoriesStore'; import useDapps from './useDapps'; import useNodeHelper from './useNodeHelper'; +import { dappKeyToChainKey } from '../utils'; +import { MarkerType } from '@xyflow/react'; +import { needReactFlowRenderSignal } from '../studio/ReactFlowRender'; const useSetDefaultDapp = () => { const searchParams = useSearchParams(); diff --git a/src/modules/blockchains/Buy/index_v8.tsx b/src/modules/blockchains/Buy/index_v8.tsx index a5dcda595..f1e23e41d 100644 --- a/src/modules/blockchains/Buy/index_v8.tsx +++ b/src/modules/blockchains/Buy/index_v8.tsx @@ -16,6 +16,8 @@ import useNodeFlowControl from './hooks/useNodeFlowControl'; import useOnlyFetchDapp from './hooks/useOnlyFetchDapp'; import useSetDefaultDapp from './hooks/useSetDefaultDapp'; import s from './styles_v6.module.scss'; +import useLineIssueToken from '@/modules/blockchains/Buy/hooks/useLineIssueToken'; +import useCheckEdges from '@/modules/blockchains/Buy/hooks/useCheckEdges'; const BuyPage = () => { const { handleDragStart, handleDragEnd, sensors } = useHandleDragging(); @@ -30,7 +32,7 @@ const BuyPage = () => { useGettingDappLego(); useCheckNodes(); useSetDefaultDapp(); - // useCheckEdges(); + useCheckEdges(); const { tabActive } = useTabs((state) => state); const isTabCode = React.useMemo(() => { diff --git a/src/modules/blockchains/Buy/mockup_3.ts b/src/modules/blockchains/Buy/mockup_3.ts index dbd981afb..cf9ef962a 100644 --- a/src/modules/blockchains/Buy/mockup_3.ts +++ b/src/modules/blockchains/Buy/mockup_3.ts @@ -60,6 +60,17 @@ export const accountAbstractionAsADapp: DappModel = { options: [], placeholder: '21,000', }, + { + background: '#009aa5', + key: 'input_apps_paymaster_address', + title: 'Paymaster contract address', + type: 'input', + icon: '', + value: '', + tooltip: '', + options: [], + placeholder: '21,000', + }, ], }, }; @@ -70,7 +81,7 @@ export const bridgesAsADapp: DappModel = { key: 'bridge_apps', title: 'Bridges', icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-issue-a-token.svg', - order: 2, + order: 1, color: '#855AFF', color_border: '#855AFF', created_at: '2021-09-14T09:00:00.000Z', @@ -109,7 +120,7 @@ export const gamingAppsAsADapp: DappModel = { key: 'gaming_apps', title: 'Gaming Apps', icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-issue-a-token.svg', - order: 3, + order: 1, color: '#FFB800', color_border: '#FFB800', created_at: '2021-09-14T09:00:00.000Z', @@ -904,151 +915,106 @@ export const dappMockupData: DappModel[] = [ }, sections: [ { - key: 'staking_token', - icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-eth.svg', - title: 'Staking Token', - tooltip: '', - required: true, - }, - { - key: 'reward_token', - icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-eth.svg', - title: 'Reward Token', - tooltip: '', - required: true, - }, - { - key: 'info', - icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-eth.svg', - title: 'Reward Rate', + key: 'information', + icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-issue-a-token.svg', + title: '', tooltip: '', - required: true, - }, - ], - baseModuleFields: [ - { - key: 'staking_token', - title: 'Staking Token', - icon: '', - placableAmount: -1, - section: 'staking_token', - preview: false, - background: '#A041FF', - fields: [ - { - key: 'bvm', - title: 'BVM', // symbol - value: '0x08b4e0434c42d9bfeeba468324ee5e2a23cd4222', // contract_address - icon: 'https://cdn.bvm.network/internal/8c50c936-cb41-40d0-8d93-8cdf7f88bd37.svg', // image_url - tooltip: '', - type: '', - options: [], - selectable: true, - }, - // { - // key: 'eth', - // title: 'ETH (Upgrade plan 99$)', // symbol - // value: '0x1234', // contract_address - // icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-eth.svg', // image_url - // tooltip: '', - // type: '', - // options: [], - // selectable: false, - // }, - ], - }, - ], - moduleFields: [ - { - key: 'reward_token', - title: 'Reward Token', - icon: '', - preview: false, - placableAmount: 1, - section: 'reward_token', - background: '#15C888', - fields: [ - { - key: 'bvm', - title: 'BVM', // symbol - value: '0x08b4e0434c42d9bfeeba468324ee5e2a23cd4222', // contract_address - icon: 'https://cdn.bvm.network/internal/8c50c936-cb41-40d0-8d93-8cdf7f88bd37.svg', // image_url - tooltip: '', - type: '', - options: [], - selectable: true, - }, - // { - // key: 'eth', - // title: 'ETH (Upgrade plan 99$)', // symbol - // value: '0x1234', // contract_address - // icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-eth.svg', // image_url - // tooltip: '', - // type: '', - // options: [], - // selectable: false, - // }, - ], - }, - ], - blockFields: [ - { - key: 'info', - title: 'Reward rate', - icon: '', - placableAmount: 1, - section: 'info', - preview: false, - background: '#C44127', - fields: [ - { - key: 'rate', - title: 'Rate', - inputType: 'number', - type: 'input', - icon: '', - value: '', - tooltip: 'Exchange rate between staking token and reward token.', - placeholder: 'eg. 1', - options: [], - background: '#C44127', - }, - { - key: 'apr', - title: 'APR', - type: 'input', - inputType: 'number', - icon: '', - value: '', - tooltip: '', - placeholder: 'eg. 20%', - options: [], - background: '#C44127', - }, - { - key: 'amount', - title: 'Reward amount', - previewTitle: 'Reward', - inputType: 'number', - type: 'input', - icon: '', - value: '', - tooltip: '', - placeholder: 'eg. 100,000', - options: [], - background: '#C44127', - }, - ], - }, + required: false, + } ], + baseModuleFields: [], + moduleFields: [], + blockFields: [], baseBlock: { key: '', title: 'Create a Staking Pool', icon: '', placableAmount: -1, - section: '', + section: 'information', preview: false, - fields: [], + fields: [ + { + key: 'staking_token', + title: 'Staking Token', + type: 'dropdown', + icon: '', + value: '', + tooltip: 'Exchange rate between staking token and reward token.', + placeholder: 'eg. 1', + options: [ + { + key: 'bvm', + title: 'BVM', // symbol + value: '0x08b4e0434c42d9bfeeba468324ee5e2a23cd4222', // contract_address + icon: 'https://cdn.bvm.network/internal/8c50c936-cb41-40d0-8d93-8cdf7f88bd37.svg', // image_url + tooltip: '', + type: '', + options: [], + selectable: true, + }, + ], + background: '#C001E6', + }, + { + key: 'reward_token', + title: 'Reward Token', + type: 'dropdown', + icon: '', + value: '', + tooltip: 'Exchange rate between staking token and reward token.', + placeholder: 'eg. 1', + options: [ + { + key: 'bvm', + title: 'BVM', // symbol + value: '0x08b4e0434c42d9bfeeba468324ee5e2a23cd4222', // contract_address + icon: 'https://cdn.bvm.network/internal/8c50c936-cb41-40d0-8d93-8cdf7f88bd37.svg', // image_url + tooltip: '', + type: '', + options: [], + selectable: true, + }, + ], + background: '#865AFF', + }, + { + key: 'rate', + title: 'Rate', + inputType: 'number', + type: 'input', + icon: '', + value: '', + tooltip: 'Exchange rate between staking token and reward token.', + placeholder: 'eg. 1', + options: [], + background: '#C44127', + }, + { + key: 'apr', + title: 'APR', + type: 'input', + inputType: 'number', + icon: '', + value: '', + tooltip: '', + placeholder: 'eg. 20%', + options: [], + background: '#C44127', + }, + { + key: 'amount', + title: 'Reward amount', + previewTitle: 'Reward', + inputType: 'number', + type: 'input', + icon: '', + value: '', + tooltip: '', + placeholder: 'eg. 100,000', + options: [], + background: '#C44127', + }, + ], }, }, { @@ -1069,13 +1035,13 @@ export const dappMockupData: DappModel[] = [ tooltip: '', required: true, }, - // { - // key: 'tasks', - // icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-eth.svg', - // title: 'Whitelisted', - // tooltip: '', - // required: true, - // }, + { + key: 'tasks', + icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-eth.svg', + title: 'Tasks', + tooltip: '', + required: true, + }, ], baseBlock: { preview: false, @@ -1113,77 +1079,39 @@ export const dappMockupData: DappModel[] = [ inputType: 'number', options: [], }, + { + key: 'start_date', + title: 'Start Date', + type: 'datetime', + value: '', + tooltip: '', + icon: '', + background: '#c4513a', + options: [], + }, + { + key: 'end_date', + title: 'End Date', + type: 'datetime', + value: '', + tooltip: '', + icon: '', + background: '#c4513a', + options: [], + }, + { + key: 'is_bvm_shard', + title: 'Shared holder', + type: 'extends', + value: '', + tooltip: '', + icon: '', + background: '#c4513a', + options: [], + } ], }, - singleFields: [ - { - title: 'Start Date', - key: 'start_date', - icon: '', - background: '#c4513a', - fields: [ - { - key: 'start_date', - title: 'Start date', - previewTitle: 'Start', - type: 'datetime', - icon: '', - value: '', - tooltip: '', - options: [], - selectable: true, - background: '#c4513a', - }, - ], - placableAmount: 1, - preview: false, - section: 'information', - }, - { - title: 'End Date', - key: 'end_date', - icon: '', - background: '#c4513a', - fields: [ - { - key: 'end_date', - title: 'End date', - previewTitle: 'End', - type: 'datetime', - icon: '', - value: '', - tooltip: '', - options: [], - background: '#c4513a', - }, - ], - placableAmount: 1, - preview: false, - section: 'information', - }, - { - title: 'Shared holder', - key: 'is_bvm_shard', - icon: '', - background: '#c4513a', - fields: [ - { - key: 'is_bvm_shard', - title: 'Shared holder', - type: 'extends', - icon: '', - value: 1, - tooltip: '', - options: [], - disabled: true, - background: '#c4513a', - }, - ], - placableAmount: 1, - preview: false, - section: 'information', - }, - ], + singleFields: [], }, { id: 'yologame', @@ -1316,11 +1244,11 @@ export const dappMockupData: DappModel[] = [ }, }, { - id: 'orderbook', - key: 'orderbook', + id: 'white_paper', + key: 'white_paper', title: 'White Paper', - icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-yolo.svg', - order: 8, + icon: 'https://storage.googleapis.com/bvm-network/image/ic-whitepaper.svg', + order: 5, color: '#F76649', created_at: '2021-09-14T09:00:00.000Z', updated_at: '2021-09-14T09:00:00.000Z', @@ -1342,8 +1270,8 @@ export const dappMockupData: DappModel[] = [ ], baseModuleFields: [ { - key: 'white_paper_token', - title: 'White Paper Token', + key: 'token', + title: 'Token', icon: '', placableAmount: -1, section: 'information', @@ -1366,119 +1294,23 @@ export const dappMockupData: DappModel[] = [ baseBlock: { key: '', title: 'Create a White Paper', - icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-yolo.svg', + icon: 'https://storage.googleapis.com/bvm-network/image/ic-whitepaper.svg', placableAmount: -1, section: '', preview: false, fields: [ - { - key: 'introduction', - title: 'Introduction', - inputType: 'text', - type: 'input', - icon: '', - value: '', - tooltip: 'Set the duration of each round in seconds.', - placeholder: - 'My token is called XYZ Coin, which is designed to facilitate fast, secure transactions on a decentralized network.', - options: [], - background: '#00AA6C', - }, - { - key: 'problem_statement', - title: 'Problem Statement', - inputType: 'text', - type: 'input', - icon: '', - value: '', - tooltip: - 'Enter the maximum number of participants allowed per round.', - placeholder: - 'The problem we are solving is the high transaction fees and slow processing times in current blockchain networks. ', - options: [], - background: '#0d2dd0', - }, - { - key: 'solution', - title: 'Solution', - inputType: 'text', - type: 'input', - icon: '', - value: '', - tooltip: - 'Specify the percentage of the fee that will be paid to the creators.', - placeholder: - 'XYZ Coin uses a new consensus algorithm that reduces fees and speeds up transaction times.', - options: [], - background: '#C44127', - }, // { - // key: 'tokenomics', - // title: 'Tokenomics', - // inputType: 'text', - // type: 'input', + // key: 'download', + // title: 'Download', + // inputType: '', + // type: 'button', // icon: '', // value: '', - // tooltip: - // 'Enter the maximum number of participants allowed per round.', + // tooltip: '', // placeholder: '', // options: [], - // background: '#0d2dd0', + // background: '#00AA6C', // }, - { - key: 'roadmap', - title: 'Roadmap', - inputType: 'text', - type: 'input', - icon: '', - value: '', - tooltip: - 'Enter the maximum number of participants allowed per round.', - placeholder: '', - options: [], - background: '#0d2dd0', - }, - { - key: 'team', - title: 'Team', - inputType: 'text', - type: 'input', - icon: '', - value: '', - tooltip: - 'Enter the maximum number of participants allowed per round.', - placeholder: '', - options: [], - background: '#0d2dd0', - }, - { - key: 'technology_unique_features', - title: 'Technology and Unique Features', - inputType: 'text', - type: 'input', - icon: '', - value: '', - tooltip: - 'Specify the percentage of the fee that will be paid to the creators.', - placeholder: - 'Our token uses a unique proof-of-stake consensus algorithm that allows for faster transactions and greater scalability. We also support smart contracts for decentralized applications.', - options: [], - background: '#C44127', - }, - { - key: 'legal_regulatory_compliance', - title: 'Legal and Regulatory Compliance', - inputType: 'text', - type: 'input', - icon: '', - value: '', - tooltip: - 'Specify the percentage of the fee that will be paid to the creators.', - placeholder: - 'We are ensuring compliance with all relevant regulations and have a legal team dedicated to navigating the complex regulatory landscape of cryptocurrency.', - options: [], - background: '#C44127', - }, ], }, }, diff --git a/src/modules/blockchains/Buy/signals/useDragSignal.ts b/src/modules/blockchains/Buy/signals/useDragSignal.ts index 28d323d63..a6d8bd04f 100644 --- a/src/modules/blockchains/Buy/signals/useDragSignal.ts +++ b/src/modules/blockchains/Buy/signals/useDragSignal.ts @@ -6,7 +6,7 @@ export type Field = { parentNames: string[]; children: Field[]; }; - +export const isRenderedInUpdateFlowSignal = signal(false); export const draggedIdsSignal = signal([]); export const draggedDappIndexesSignal = signal([]); export const draggedIds2DSignal = signal([]); diff --git a/src/modules/blockchains/Buy/stores/useFlowStore.ts b/src/modules/blockchains/Buy/stores/useFlowStore.ts index 53fccceef..a46ac08bf 100644 --- a/src/modules/blockchains/Buy/stores/useFlowStore.ts +++ b/src/modules/blockchains/Buy/stores/useFlowStore.ts @@ -21,6 +21,8 @@ export type AppState = { onConnect: OnConnect; setNodes: (nodes: AppNode[]) => void; setEdges: (edges: Edge[]) => void; + removedNode: AppNode | null; + setRemovedNode: (node: AppNode | null) => void; }; const useFlowStore = create((set, get) => ({ @@ -47,6 +49,10 @@ const useFlowStore = create((set, get) => ({ setEdges: (edges) => { set({ edges }); }, + removedNode: null, + setRemovedNode: (node) => { + set({ removedNode: node }); + }, })); export default useFlowStore; diff --git a/src/modules/blockchains/Buy/studio/ButtonStartChat/index.tsx b/src/modules/blockchains/Buy/studio/ButtonStartChat/index.tsx index f04a68de8..2fe48aeb2 100644 --- a/src/modules/blockchains/Buy/studio/ButtonStartChat/index.tsx +++ b/src/modules/blockchains/Buy/studio/ButtonStartChat/index.tsx @@ -1,10 +1,11 @@ import MagicIcon from '@/components/MagicIcon'; import { gsap } from 'gsap'; import { ReactElement, useEffect, useRef } from 'react'; +import { ENABLE_CHATBOX } from '../../constants'; import Chatbox from '../Chatbox'; import useChatBoxState from '../Chatbox/chatbox-store'; +import SocketProvider from '../Chatbox/SocketProvider'; import styles from './styles.module.scss'; -import { ENABLE_CHATBOX } from '../../constants'; export default function ButtonStartChat(): ReactElement { const { isChatboxOpen, setIsChatboxOpen } = useChatBoxState((state) => state); @@ -31,7 +32,7 @@ export default function ButtonStartChat(): ReactElement { if (!ENABLE_CHATBOX) return <>; return ( - <> + @@ -47,6 +48,6 @@ export default function ButtonStartChat(): ReactElement { >
- + ); } diff --git a/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonVoice/index.tsx b/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonVoice/index.tsx index 700eebad8..4ebb5d4e1 100644 --- a/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonVoice/index.tsx +++ b/src/modules/blockchains/Buy/studio/Chatbox/Actions/ButtonVoice/index.tsx @@ -37,6 +37,7 @@ export default function ButtonVoice({ isComplete: false, isListening: true, }); + const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition; @@ -50,6 +51,7 @@ export default function ButtonVoice({ const transcript = event.results[0][0].transcript; const message = `${inputMessage} ${transcript}`; setInputMessage(message); + setChatBoxStatus({ status: ChatBoxStatus.Close, isGenerating: false, @@ -82,6 +84,7 @@ export default function ButtonVoice({ const stopVoiceInput = useCallback(() => { if (recognition) { recognition.stop(); + setChatBoxStatus({ status: ChatBoxStatus.Close, isGenerating: false, @@ -119,34 +122,34 @@ export default function ButtonVoice({ }; }, [stopVoiceInput, isClose, isGenerating, isListening]); - useEffect(() => { - if (isListening) { - handleVoiceInput(); - } else { - stopVoiceInput(); - } + // useEffect(() => { + // if (isListening) { + // handleVoiceInput(); + // } else { + // stopVoiceInput(); + // } - return () => { - stopVoiceInput(); - }; - }, [isListening]); + // return () => { + // stopVoiceInput(); + // }; + // }, [isListening]); - useEffect(() => { - if (isOpenVoice) { - handleVoiceInput(); - } + // useEffect(() => { + // if (isOpenVoice) { + // handleVoiceInput(); + // } - return () => { - stopVoiceInput(); - }; - }, [isOpenVoice]); + // return () => { + // stopVoiceInput(); + // }; + // }, [isOpenVoice]); const Listening = useMemo((): ReactElement => { return (
-
+
{messages.map((message, index) => (
{message.sender === 'bot' ? ( - + ) : ( message.text )} diff --git a/src/modules/blockchains/Buy/studio/Chatbox/services/prompt.ts b/src/modules/blockchains/Buy/studio/Chatbox/services/prompt.ts index 735e28236..98932d943 100644 --- a/src/modules/blockchains/Buy/studio/Chatbox/services/prompt.ts +++ b/src/modules/blockchains/Buy/studio/Chatbox/services/prompt.ts @@ -56,3 +56,41 @@ export const sendPromptV2 = async ( throw error; } }; +export const sendPromptStream = async ( + body: SendPromptBodyRequestV2, + onChunk: (chunk: any) => void, +): Promise => { + console.log('[sendPromptV2] body', body); + + try { + const response = await fetch( + 'https://api-dojo2.eternalai.org/api/chat/assistant-v3', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }, + ); + + if (!response.body) { + throw new Error('Response body is unavailable'); + } + + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + + while (true) { + const { done, value } = await reader.read(); + + if (done) break; + + const chunk = decoder.decode(value, { stream: true }); + onChunk(chunk); + } + } catch (error) { + console.error('[sendPromptV2] error', error); + throw error; + } +}; diff --git a/src/modules/blockchains/Buy/studio/Chatbox/types.ts b/src/modules/blockchains/Buy/studio/Chatbox/types.ts index 3c82262b7..4d05ea1e4 100644 --- a/src/modules/blockchains/Buy/studio/Chatbox/types.ts +++ b/src/modules/blockchains/Buy/studio/Chatbox/types.ts @@ -24,6 +24,8 @@ export type SendPromptBodyRequest = { export type SendPromptBodyRequestV2 = { session_id: string; command: string; + stream?: boolean; + user_session?: string; current_state: PromptCategory[]; }; diff --git a/src/modules/blockchains/Buy/studio/Controls/index.tsx b/src/modules/blockchains/Buy/studio/Controls/index.tsx index 7220ed5b5..a7546c2ec 100644 --- a/src/modules/blockchains/Buy/studio/Controls/index.tsx +++ b/src/modules/blockchains/Buy/studio/Controls/index.tsx @@ -134,6 +134,7 @@ export default memo(function StudioControls() { id={item.key} isRequired={item.required} active={field[item.key].dragged} + needCheckIcon={item.required} description={{ title: item.title, content: item.tooltip, diff --git a/src/modules/blockchains/Buy/studio/Main/ChainInforView.tsx b/src/modules/blockchains/Buy/studio/Main/ChainInforView.tsx index 873620f81..2a74ffd27 100644 --- a/src/modules/blockchains/Buy/studio/Main/ChainInforView.tsx +++ b/src/modules/blockchains/Buy/studio/Main/ChainInforView.tsx @@ -24,9 +24,9 @@ const ChainInforView = (): ReactElement => { const menuEditItemOnClick = (menuItem: MenuEditItemType) => { switch (menuItem.value) { - case MenuEditItemEnum.ABC: + case MenuEditItemEnum.UpdateYourChainInfor: { - //TO DO ABC + //TO DO } break; case MenuEditItemEnum.ConfigYourDAppsDomain: diff --git a/src/modules/blockchains/Buy/studio/ReactFlowRender/index.tsx b/src/modules/blockchains/Buy/studio/ReactFlowRender/index.tsx index 2a8232035..6b24bff83 100644 --- a/src/modules/blockchains/Buy/studio/ReactFlowRender/index.tsx +++ b/src/modules/blockchains/Buy/studio/ReactFlowRender/index.tsx @@ -1,9 +1,9 @@ import CustomEdge from '@/modules/blockchains/Buy/component4/CustomEdge'; import CustomNode from '@/modules/blockchains/Buy/component4/CustomNode'; import useHandleReloadNode from '@/modules/blockchains/Buy/hooks/useHandleReloadNode'; -import MModal from '@/modules/blockchains/dapp/components/Modal'; +import useStoreFirstLoadTemplateBox from '@/modules/blockchains/Buy/stores/useFirstLoadTemplateBoxStore'; import { signal, useSignalEffect } from '@preact/signals-react'; -import { ReactFlow } from '@xyflow/react'; +import { ConnectionMode, ReactFlow } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; import { usePathname, useSearchParams } from 'next/navigation'; import React, { useState } from 'react'; @@ -12,18 +12,13 @@ import AANode from '../../component4/YourNodes/AANode'; import BridgeNode from '../../component4/YourNodes/BridgeNode'; import ChainNodeV2 from '../../component4/YourNodes/ChainNodeV2'; import DappNode from '../../component4/YourNodes/DappNode'; +import GamingAppsNode from '../../component4/YourNodes/GamingAppsNode'; import { nodeKey } from '../../component4/YourNodes/node.constants'; -import { - draggedDappIndexesSignal, - draggedIds2DSignal, - restoreLocal, -} from '../../signals/useDragSignal'; +import { restoreLocal } from '../../signals/useDragSignal'; import useFlowStore from '../../stores/useFlowStore'; import useModelCategoriesStore from '../../stores/useModelCategoriesStore'; import s from './styles.module.scss'; -import useStoreFirstLoadTemplateBox from '@/modules/blockchains/Buy/stores/useFirstLoadTemplateBoxStore'; -import { formDappSignal } from '@/modules/blockchains/Buy/signals/useFormDappsSignal'; -import GamingAppsNode from '../../component4/YourNodes/GamingAppsNode'; +import useLineIssueToken from '@/modules/blockchains/Buy/hooks/useLineIssueToken'; export const needReactFlowRenderSignal = signal(false); const currentPositionSignal = signal({ x: 0, y: 0, zoom: 1 }); @@ -40,6 +35,7 @@ const ReactFlowRenderer = React.memo(() => { const path = usePathname(); const { categories } = useModelCategoriesStore(); const searchParamm = useSearchParams(); + useLineIssueToken(); const [loaded, setLoaded] = React.useState(false); const [showModal, setShowModal] = React.useState(false); @@ -59,9 +55,7 @@ const ReactFlowRenderer = React.memo(() => { console.log('[ReactFlowRenderer]', { nodes, - draggedDappIndexesSignal: draggedDappIndexesSignal.value, - draggedIds2DSignal: draggedIds2DSignal.value, - formDappSignal: formDappSignal.value, + edges }); React.useEffect(() => { @@ -111,9 +105,13 @@ const ReactFlowRenderer = React.memo(() => { edgesFocusable={false} onInit={setRfInstance} zoomOnDoubleClick={false} + connectionMode={ConnectionMode.Loose} edges={edges} fitViewOptions={{ padding: 1 }} className={s.reactFlow} + // onNodeDrag={(event: React.MouseEvent, node: AppNode)=> { + // console.log('[ReactFlowRenderer] onNodeDrag', { event, node, nodes }); + // }} onNodeDragStop={() => { if (!isFirstLoadTemplateBox) return; if (path === '/studio') { diff --git a/src/modules/blockchains/Buy/studio/WorkArea/RightContent.tsx b/src/modules/blockchains/Buy/studio/WorkArea/RightContent.tsx index b828bb3c2..900d76a2a 100644 --- a/src/modules/blockchains/Buy/studio/WorkArea/RightContent.tsx +++ b/src/modules/blockchains/Buy/studio/WorkArea/RightContent.tsx @@ -10,12 +10,20 @@ export default function RightContent(): ReactElement { const flowRef = React.useRef(null); const { isCapture } = useCaptureStore(); const { addListeners, removeListeners } = useContainerMouse({ - ref: flowRef , handleOnTick, + ref: flowRef, handleOnTick, }); - function handleOnTick( contentRect: DOMRect, - mousePosition: { x: number; y: number }, - previousMousePosition: { x: number; y: number }) { - mouseDroppedPositionSignal.value = mousePosition + + function handleOnTick(contentRect: DOMRect, + mousePosition: { x: number; y: number }, + previousMousePosition: { x: number; y: number }) { + if (mousePosition.x === 0 && mousePosition.y === 0) { + mouseDroppedPositionSignal.value = { + x: 600, + y: 30, + }; + } else { + mouseDroppedPositionSignal.value = mousePosition; + } } React.useEffect(() => { @@ -36,5 +44,5 @@ export default function RightContent(): ReactElement { > -
+
; } diff --git a/src/modules/blockchains/Buy/types.ts b/src/modules/blockchains/Buy/types.ts index 4731f8168..42eca7c70 100644 --- a/src/modules/blockchains/Buy/types.ts +++ b/src/modules/blockchains/Buy/types.ts @@ -32,4 +32,5 @@ export enum DappType { yologame = 'yologame', orderbook = 'orderbook', walletType = 'wallet_type', + white_paper = 'white_paper', } diff --git a/src/modules/blockchains/Buy/utils.ts b/src/modules/blockchains/Buy/utils.ts index 5c4f9378a..52fe56887 100644 --- a/src/modules/blockchains/Buy/utils.ts +++ b/src/modules/blockchains/Buy/utils.ts @@ -278,19 +278,19 @@ export const preDataAirdropTask = ( if (fieldRewardToken > -1) { // // @ts-ignore - const options: any = tokens.map((t) => ({ - key: t.id, - title: t.name, - value: t.contract_address, - icon: t.image_url, - tooltip: '', - type: '', - options: [], - })); + // const options: any = tokens.map((t) => ({ + // key: t.id, + // title: t.name, + // value: t.contract_address, + // icon: t.image_url, + // tooltip: '', + // type: '', + // options: [], + // })); // @ts-ignore - _sortedDapps[_airdropIndex].baseBlock.fields[fieldRewardToken].options = - options; + // _sortedDapps[_airdropIndex].baseBlock.fields[fieldRewardToken].options = + // options; if (airdropTasks.length > 0) { const singleFields: BlockModel[] = cloneDeep( @@ -425,6 +425,47 @@ export const preDataYoloGame = ( return _sortedDapps; }; +export const preDataWhitePaper = ( + sortedDapps: DappModel[] = [], + tokens: IToken[], +) => { + const _sortedDapps = cloneDeep(sortedDapps); + + if (tokens.length > 0) { + const _appIndex = _sortedDapps.findIndex((v) => + compareString(v.key, DappType.white_paper), + ); + + if (_appIndex > -1) { + const fieldToken = _sortedDapps[ + _appIndex + ].baseModuleFields?.findIndex((v: BlockModel) => + compareString(v.key, 'token'), + ); + + // @ts-ignore + if (fieldToken > -1) { + // // @ts-ignore + const options: any = tokens.map((t) => ({ + key: t.id, + title: t.name, + value: t.contract_address, + icon: t.image_url, + tooltip: '', + type: '', + options: [], + selectable: true, + })); + + // @ts-ignore + _sortedDapps[_appIndex].baseModuleFields[fieldToken].fields = + options; + } + } + } + return _sortedDapps; +}; + export const getAirdropTaskKey = (task: IAirdropTask) => { if (compareString(task.type, 'follow') || compareString(task.id, '1')) { return 'follow_twitter_username'; diff --git a/src/modules/blockchains/Dashboard.page_v2.tsx b/src/modules/blockchains/Dashboard.page_v2.tsx index 6ffa03bf4..92d7f6990 100644 --- a/src/modules/blockchains/Dashboard.page_v2.tsx +++ b/src/modules/blockchains/Dashboard.page_v2.tsx @@ -18,14 +18,11 @@ import { useEffect, useState } from 'react'; import { TAB_ENUM, TAB_ENUM_MAP } from './Dashboard.constant_v2'; import { enhance } from './Dashboard.enhance'; import BillingPage from './components/BillingPage'; -// import BodyView from './components/Body'; -import { useRouter } from 'next/navigation'; import BodyView from './components/Body_v2'; import NetworkBar from './components/NetworkBar_V2'; import s from './styles.module.scss'; const Page = (props: any) => { - const router = useRouter(); const { onOpenTopUpModal } = props; const [activeTab, setChatTabIndex] = useState( TAB_ENUM.MANAGE_CHAINS, @@ -52,12 +49,6 @@ const Page = (props: any) => { } }, [loggedIn]); - // useEffect(() => { - // setTimeout(() => { - // router.push('/chains/66bb33f039450b503310947b'); - // }, 5000); - // }, []); - const renderTabbar = () => { return ( { fontWeight={500} color={'#000'} > - To see your ZK rollups -{' '} + To see your Bitcoin chain -{' '} { - @@ -80,30 +80,30 @@ const BlockchainSection = (props: Props) => { Number(blockTime) === 1 ? '1 second' : `${blockTime} seconds` }`} /> - )} + )} */} - - + + - + /> */} {!isMainnet && ( { {/* {item.serviceType === RollupEnum.Rollup_ZK && ( )} */} - {item.serviceType === RollupEnum.Rollup_ZK && ( + {/* {item.serviceType === RollupEnum.Rollup_ZK && ( - )} + )} */} ); diff --git a/src/modules/blockchains/components/Body_v2/L2Instance/HeaderRow_v2.tsx b/src/modules/blockchains/components/Body_v2/L2Instance/HeaderRow_v2.tsx index 945f188a3..cf4cff521 100644 --- a/src/modules/blockchains/components/Body_v2/L2Instance/HeaderRow_v2.tsx +++ b/src/modules/blockchains/components/Body_v2/L2Instance/HeaderRow_v2.tsx @@ -18,11 +18,10 @@ const HeaderRow = (props: Props) => { const { item, isOwner, depositOnClick, editOnClick } = props; const mapper = useOrderMapper(item); - const router = useRouter(); - - const isShowStatus = - item.status === OrderStatus.Started || - item.status === OrderStatus.Processing; + // const isShowStatus = + // item.status === OrderStatus.Started || + // item.status === OrderStatus.Processing; + const isShowStatus = true; const renderLeftView = () => { return ( @@ -30,7 +29,7 @@ const HeaderRow = (props: Props) => { flex={1} flexDir={'row'} gap={'12px'} - align={'center'} + align={'flex-start'} w={'100%'} justify={'flex-start'} > @@ -76,21 +75,6 @@ const HeaderRow = (props: Props) => { }} /> )} */} - - { - if (event.stopPropagation) event.stopPropagation(); - router.push(`/chains/${item?.orderId}/detail`); - }} - /> ); }; @@ -99,7 +83,7 @@ const HeaderRow = (props: Props) => { if (!isShowStatus) return null; return ( { const dispatch = useAppDispatch(); - const { onOpenWaittingSetingUp } = useDashboard(); - const { getMyOrderList } = useL2Service(); - // const allOrders = useAppSelector(allOrdersSelector); const myOrders = useAppSelector(myOrderListFilteredByNetwork); const { accountInforL2Service, isMyOrderListFetched } = useAppSelector( getL2ServicesStateSelector, diff --git a/src/modules/blockchains/dapp/components/BottomButton/index.tsx b/src/modules/blockchains/dapp/components/BottomButton/index.tsx index 6fbede629..9c1128e63 100644 --- a/src/modules/blockchains/dapp/components/BottomButton/index.tsx +++ b/src/modules/blockchains/dapp/components/BottomButton/index.tsx @@ -10,6 +10,8 @@ import { compareString } from '@/utils/string'; import { formatCurrency } from '@/utils/format'; import { DappModel } from '@/types/customize-model'; import { Text } from '@chakra-ui/react'; +import WhitePaperModal from '@/modules/blockchains/dapp/components/WhitePaperModal'; +import { IWhitePaper } from '@/services/api/dapp/whitePapers/interface'; interface IProps { color: string; @@ -22,7 +24,9 @@ const BottomButton = (props: IProps) => { const stakingPools = dappState.stakingPools; const [isShowTopup, setIsShowTopup] = useState(false); + const [isShowPreview, setIsShowPreview] = useState(false); const [topupInfo, setTopupInfo] = useState(); + const [tokenInfo, setTokenInfo] = useState(); const onActionClick = (params: { dapp: DappModel }) => { console.log(params.dapp?.action); @@ -86,6 +90,12 @@ const BottomButton = (props: IProps) => { ]); setIsShowTopup(true); break; + case DappType.white_paper: + setTokenInfo((params.dapp?.action as any).tokenInfo); + setTimeout(() => { + setIsShowPreview(true); + }, 1000) + break; default: break; } @@ -117,6 +127,13 @@ const BottomButton = (props: IProps) => { setIsShowTopup(false); }} /> + { + setIsShowPreview(false); + }} + tokenInfo={tokenInfo} + /> ); }; diff --git a/src/modules/blockchains/dapp/components/WhitePaperModal/index.tsx b/src/modules/blockchains/dapp/components/WhitePaperModal/index.tsx new file mode 100644 index 000000000..28e192a60 --- /dev/null +++ b/src/modules/blockchains/dapp/components/WhitePaperModal/index.tsx @@ -0,0 +1,261 @@ +import BaseModal from '@/components/BaseModal'; +import { Button, Flex, Text } from '@chakra-ui/react'; +import s from './styles.module.scss'; +import html2canvas from 'html2canvas'; +import jsPDF from 'jspdf'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import { marked } from 'marked'; +import { IWhitePaper } from '@/services/api/dapp/whitePapers/interface'; +import CWhitePaperAPI from '@/services/api/dapp/whitePapers'; +import { requestReload } from '@/stores/states/common/reducer'; +import { useDispatch } from 'react-redux'; +import { useAppSelector } from '@/stores/hooks'; +import { commonSelector } from '@/stores/states/common/selector'; +import { useChainProvider } from '@/modules/blockchains/detail_v4/provider/ChainProvider.hook'; + +interface IProps { + show: boolean; + onClose?: (() => void) | any; + tokenInfo?: IWhitePaper; +} + +const WhitePaperModal = (props: IProps) => { + const { show, onClose, tokenInfo} = props; + const contentRef = useRef(null); + const [isRegenerating, setIsRegenerating] = useState(false); + const [isDownloadingHtml, setIsDownloadingHtml] = useState(false); + const [isDownloadingPdf, setIsDownloadingPdf] = useState(false); + const [whitePaper, setWhitePaper] = useState(); + const { isOwnerChain } = useChainProvider(); + + const dispatch = useDispatch(); + const cWhitePaperAPI = new CWhitePaperAPI(); + const needReload = useAppSelector(commonSelector).needReload; + + const isAllDisabled = useMemo(() => { + return isRegenerating || isDownloadingHtml || isDownloadingPdf || !isOwnerChain; + }, [isRegenerating, isDownloadingHtml, isDownloadingPdf]); + + const markdownString = useMemo(() => { + return whitePaper?.white_paper || tokenInfo?.white_paper || ''; + }, [tokenInfo, whitePaper]); + + useEffect(() => { + if(tokenInfo?.id) { + getWhitePaperDetail(); + } + }, [tokenInfo?.id, needReload]); + + const getWhitePaperDetail = async () => { + const res = await cWhitePaperAPI.getWhitePaperDetail(tokenInfo?.id?.toString() as string); + setWhitePaper(res); + } + + useEffect(() => { + if(whitePaper?.status === 'processing') { + setIsRegenerating(true); + } else { + setIsRegenerating(false); + } + }, [whitePaper]); + + const convertMarkdownToHtml = (markdownText: string) => { + return marked(markdownText); + }; + + const regenerateContent = async () => { + try { + setIsRegenerating(true); + + await cWhitePaperAPI.reCreateWhitePaper( + tokenInfo?.token?.contract_address as string, + ); + + dispatch(requestReload()); + } catch (e) { + console.log('regenerateContent error', e); + } finally { + setIsRegenerating(false); + } + } + + const downloadHtml = async () => { + try { + setIsDownloadingHtml(true); + + const htmlString = await convertMarkdownToHtml(markdownString); + + const htmlContent = ` + + + + + + ${tokenInfo?.token?.symbol} White Paper + + + + ${htmlString} + + + `; + + const blob = new Blob([htmlContent], { type: 'text/html' }); + + const url = URL.createObjectURL(blob); + + const a = document.createElement('a'); + a.href = url; + a.download = `${tokenInfo?.token?.symbol}_white_paper.html`; + document.body.appendChild(a); + a.click(); + + document.body.removeChild(a); + + URL.revokeObjectURL(url); + } catch (e) { + console.log('downloadHtml error', e); + } finally { + setIsDownloadingHtml(false); + } + }; + + const downloadPdf = () => { + try { + setIsDownloadingPdf(true); + + const input = contentRef.current as HTMLDivElement; + html2canvas(input).then((canvas) => { + const imgData = canvas.toDataURL('image/png'); + const pdf = new jsPDF('p', 'mm', 'a4'); + const imgWidth = 210; + const pageHeight = 295; + const imgHeight = (canvas.height * imgWidth) / canvas.width; + let heightLeft = imgHeight; + + let position = 0; + + pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); + heightLeft -= pageHeight; + + while (heightLeft >= 0) { + position = heightLeft - imgHeight; + pdf.addPage(); + pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); + heightLeft -= pageHeight; + } + pdf.save(`${tokenInfo?.token?.symbol}_white_paper.pdf`); + setIsDownloadingPdf(false); + }); + } catch (e) { + setIsDownloadingPdf(false); + console.log('downloadPdf error', e); + } finally { + } + }; + + return ( + + +
+ { + isRegenerating && ( + White Paper's content is generating. Please wait some minutes! + ) + } + + + + {/**/} + +
+
+ ); +}; + +export default WhitePaperModal; diff --git a/src/modules/blockchains/dapp/components/WhitePaperModal/styles.module.scss b/src/modules/blockchains/dapp/components/WhitePaperModal/styles.module.scss new file mode 100644 index 000000000..b9fb1480f --- /dev/null +++ b/src/modules/blockchains/dapp/components/WhitePaperModal/styles.module.scss @@ -0,0 +1,68 @@ +.modalContent { + background-color: #fff !important; + font-family: var(--font-dmsans); + //max-width: 600px !important; + margin: 20px !important; + max-height: 100dvh; + overflow-y: auto; + + .whitePaperContent { + background: white; + color: black; + padding: 40px 80px; + + h1 { + font-size: 32px; + font-weight: 700; + white-space: pre-wrap; + } + + h2 { + font-weight: 700; + font-size: 20px; + } + + h3 { + font-size: 18px; + font-weight: bold; + } + + h4 { + font-size: 16px; + font-weight: bold; + } + + h5 { + font-size: 14px; + font-weight: bold; + } + + p { + margin-top: 4px; + margin-bottom: 4px; + } + + ul { + padding-inline-start: 40px; + } + ol { + padding-inline-start: 40px; + } + + a { + color: #0d87ff; + text-decoration: underline; + } + } + + :global { + .chakra-modal__body { + padding-left: 0; + padding-right: 0; + } + } +} + +.headerClassName { + +} diff --git a/src/modules/blockchains/dapp/hooks/useFetchDapp.tsx b/src/modules/blockchains/dapp/hooks/useFetchDapp.tsx index 9036a5ed0..dc4ceebed 100644 --- a/src/modules/blockchains/dapp/hooks/useFetchDapp.tsx +++ b/src/modules/blockchains/dapp/hooks/useFetchDapp.tsx @@ -11,6 +11,7 @@ import React, { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import CYoloGameAPI from '@/services/api/dapp/yolo'; import CTokenGenerationAPI from '@/services/api/dapp/token_generation'; +import CWhitePaperAPI from '@/services/api/dapp/whitePapers'; const useFetchDapp = () => { const params = useParams(); @@ -25,6 +26,7 @@ const useFetchDapp = () => { const stakingAPI = new CStakingAPI(); const tokenAirdropAPI = new CTokenAirdropAPI(); const yoloGameAPI = new CYoloGameAPI(); + const whitePaperAPI = new CWhitePaperAPI(); const dappState = useAppSelector(dappSelector); const needReload = useAppSelector(commonSelector).needReload; @@ -71,6 +73,10 @@ const useFetchDapp = () => { await yoloGameAPI.getYoloGameList(dappState?.chain?.chainId || ''); }; + const fetchWhitePaperList = async () => { + await whitePaperAPI.getWhitePaperList(); + }; + const getDappTasks = async () => { console.time('[useFetchDapp] getDappTasks time'); try { @@ -81,6 +87,7 @@ const useFetchDapp = () => { getListTask(), getListAirdrop(), fetchYoloGameList(), + fetchWhitePaperList(), ]); setLoading(true); console.time('[useFetchDapp] getDappTasks time'); @@ -94,7 +101,7 @@ const useFetchDapp = () => { React.useEffect(() => { fetchData(); - }, []); + }, [needReload]); useEffect(() => { if (dappState?.chain?.chainId) { diff --git a/src/modules/blockchains/dapp/parseUtils/airdrop.ts b/src/modules/blockchains/dapp/parseUtils/airdrop.ts index 956699426..6a4ff47cd 100644 --- a/src/modules/blockchains/dapp/parseUtils/airdrop.ts +++ b/src/modules/blockchains/dapp/parseUtils/airdrop.ts @@ -68,9 +68,12 @@ export const parseAirdrop = async (airdrop: IAirdrop, _token: IToken) => { } as any; } - // console.log('renderLabel[airdrop.status]', renderLabel[airdrop.status]); + console.log('renderLabel[airdrop.status]', renderLabel[airdrop.status]); - result.label = renderLabel[airdrop.status] as any; + result.label = { + ...renderLabel[airdrop.status], + title: renderLabel[airdrop.status].label, + } as any; const baseBlock: BlockModel = {} as BlockModel; diff --git a/src/modules/blockchains/dapp/parseUtils/issue-token.ts b/src/modules/blockchains/dapp/parseUtils/issue-token.ts index be8029091..297ad7e45 100644 --- a/src/modules/blockchains/dapp/parseUtils/issue-token.ts +++ b/src/modules/blockchains/dapp/parseUtils/issue-token.ts @@ -1,10 +1,10 @@ +import { DappType } from '@/modules/blockchains/dapp/types'; import { IToken, ITokenVesting, } from '@/services/api/dapp/token_generation/interface'; -import { DappType } from '@/modules/blockchains/dapp/types'; -import { formatCurrency } from '@utils/format'; import { BlockModel, DappModel, FieldModel } from '@/types/customize-model'; +import { formatCurrency } from '@utils/format'; export const parseIssuedToken = (token: IToken) => { const result = {} as DappModel; @@ -61,6 +61,15 @@ export const parseIssuedToken = (token: IToken) => { tooltip: '', options: [], }, + { + key: 'contract_address', + title: 'Contract Address', + type: 'label_value', + icon: '', + value: token?.contract_address || '', + tooltip: '', + options: [], + } ]; result.baseBlock = baseBlock; diff --git a/src/modules/blockchains/dapp/parseUtils/wallet-type.ts b/src/modules/blockchains/dapp/parseUtils/wallet-type.ts index 73aa47c91..cd698fe41 100644 --- a/src/modules/blockchains/dapp/parseUtils/wallet-type.ts +++ b/src/modules/blockchains/dapp/parseUtils/wallet-type.ts @@ -1,29 +1,26 @@ import { WalletType } from '@/stores/states/dapp/types'; +import { StatusBox } from '../../Buy/component4/CustomNode/DappTemplateNode'; export const parseWalletType = (walletType: WalletType): any[] => { - - let selected = {} + let selected = {}; switch (walletType) { case WalletType.inGame: - selected = - { - key: WalletType.inGame, - value: 'In Game', // contract_address - }; + selected = { + key: WalletType.inGame, + value: 'In Game', // contract_address + }; break; case WalletType.naka: - selected = - { - key: WalletType.naka, - value: 'Naka Wallet', // contract_address - }; + selected = { + key: WalletType.naka, + value: 'Naka Wallet', // contract_address + }; break; case WalletType.thirdWeb: - selected = - { - key: WalletType.thirdWeb, - value: 'ThirdWeb Wallet', // contract_address - }; + selected = { + key: WalletType.thirdWeb, + value: 'ThirdWeb Wallet', // contract_address + }; break; } @@ -39,10 +36,10 @@ export const parseWalletType = (walletType: WalletType): any[] => { updated_at: '2021-09-14T09:00:00.000Z', tooltip: '', label: { - title: 'New', + title: 'Installed', color: '#000', background: '#00AA6C', - status: '', + status: StatusBox.INSTALLED, }, sections: [ { @@ -79,7 +76,7 @@ export const parseWalletType = (walletType: WalletType): any[] => { type: 'input', options: [], selectable: true, - ...selected + ...selected, }, ], }, @@ -87,4 +84,4 @@ export const parseWalletType = (walletType: WalletType): any[] => { ]; return result; -} +}; diff --git a/src/modules/blockchains/dapp/parseUtils/whitePaper.ts b/src/modules/blockchains/dapp/parseUtils/whitePaper.ts new file mode 100644 index 000000000..8fb469418 --- /dev/null +++ b/src/modules/blockchains/dapp/parseUtils/whitePaper.ts @@ -0,0 +1,73 @@ +import { IWhitePaper } from '@/services/api/dapp/whitePapers/interface'; + +export const parseWhitePapers = (whitePapers: IWhitePaper[]): any[] => { + const result: any[] = []; + + for (const whitePaper of whitePapers) { + result.push( + { + id: 'white_paper', + key: 'white_paper', + title: 'White Paper', + icon: 'https://storage.googleapis.com/bvm-network/image/ic-whitepaper.svg', + order: 5, + color: '#F76649', + created_at: '2021-09-14T09:00:00.000Z', + updated_at: '2021-09-14T09:00:00.000Z', + tooltip: '', + label: { + title: 'New', + color: '#000', + background: '#00AA6C', + status: '', + }, + sections: [ + { + key: 'information', + icon: 'https://storage.googleapis.com/bvm-network/icons-tool/icon-eth.svg', + title: 'Information', + tooltip: '', + required: false, + }, + ], + baseBlock: { + key: '', + title: `${whitePaper.token?.symbol} White Paper`, + icon: 'https://storage.googleapis.com/bvm-network/image/ic-whitepaper.svg', + placableAmount: -1, + section: '', + preview: false, + fields: [ + { + key: 'token', + title: 'Token', + type: 'dropdown', + icon: '', + value: whitePaper.token.contract_address, + tooltip: '', + options: [ + { + key: whitePaper.token?.symbol as any, + title: whitePaper.token?.symbol as any, + value: whitePaper.token?.contract_address as any, + icon: (whitePaper.token?.image_url || '') as any, + tooltip: '', + type: '', + options: [], + }, + ], + background: '#A041FF', + }, + ], + }, + action: { + title: 'View', + actionMapperID: `${whitePaper.id}`, + tokenInfo: whitePaper, + } as any + } + ); + } + + return result; +} diff --git a/src/modules/blockchains/dapp/types.ts b/src/modules/blockchains/dapp/types.ts index 00a4ede5d..dafe2da4c 100644 --- a/src/modules/blockchains/dapp/types.ts +++ b/src/modules/blockchains/dapp/types.ts @@ -31,4 +31,5 @@ export enum DappType { yologame = 'yologame', orderbook = 'orderbook', walletType = 'wallet_type', + white_paper = 'white_paper', } diff --git a/src/modules/blockchains/detail_v2/components/Header/HeaderLeftView.tsx b/src/modules/blockchains/detail_v2/components/Header/HeaderLeftView.tsx index 15c6205a4..ffbdc9ca7 100644 --- a/src/modules/blockchains/detail_v2/components/Header/HeaderLeftView.tsx +++ b/src/modules/blockchains/detail_v2/components/Header/HeaderLeftView.tsx @@ -37,7 +37,7 @@ const HeaderLeftView = (props: Props) => { const menuEditItemOnClick = (menuItem: MenuEditItemType) => { switch (menuItem.value) { - case MenuEditItemEnum.ABC: + case MenuEditItemEnum.UpdateYourChainInfor: { // TO DO // Show Modal update your chain infor diff --git a/src/modules/blockchains/detail_v2/components/MenuEdit/index.tsx b/src/modules/blockchains/detail_v2/components/MenuEdit/index.tsx index 9de998114..f57d59f62 100644 --- a/src/modules/blockchains/detail_v2/components/MenuEdit/index.tsx +++ b/src/modules/blockchains/detail_v2/components/MenuEdit/index.tsx @@ -12,8 +12,7 @@ import { import MenuEditItem from './MenuEditItem'; export enum MenuEditItemEnum { - // UpdateYourChainInfor = 0, - ABC = 0, + UpdateYourChainInfor = 0, ConfigYourDAppsDomain, } @@ -24,11 +23,11 @@ export type MenuEditItemType = { }; const MenuEditItemList: MenuEditItemType[] = [ - // { - // key: 'A', - // value: MenuEditItemEnum.ABC, - // title: 'ABC Title', - // }, + { + key: 'A', + value: MenuEditItemEnum.UpdateYourChainInfor, + title: 'Update your chain', + }, { key: 'B', value: MenuEditItemEnum.ConfigYourDAppsDomain, diff --git a/src/modules/blockchains/detail_v3/account-abstraction_v2/components/AddressPaymasterInput/index.tsx b/src/modules/blockchains/detail_v3/account-abstraction_v2/components/AddressPaymasterInput/index.tsx new file mode 100644 index 000000000..ecc3b75d9 --- /dev/null +++ b/src/modules/blockchains/detail_v3/account-abstraction_v2/components/AddressPaymasterInput/index.tsx @@ -0,0 +1,57 @@ +import { useAAModule } from '@/modules/blockchains/detail_v4/hook/useAAModule'; +import { Flex, Image, Input, Text } from '@chakra-ui/react'; +import copy from 'copy-to-clipboard'; +import toast from 'react-hot-toast'; +import s from './styles.module.scss'; +import { formatAddressCenter } from '@/utils/string'; + +const AddressPaymasterInput = () => { + const { aaInstalledData } = useAAModule(); + + const paymasterAddress = aaInstalledData?.aaPaymasterContract || ''; + + return ( + + + - + + + {formatAddressCenter(paymasterAddress || '', 8) || ''} + + + + { + if (paymasterAddress) { + copy(paymasterAddress); + toast.success('Copied successully!'); + } + }} + /> + + + ); +}; + +export default AddressPaymasterInput; diff --git a/src/modules/blockchains/detail_v3/account-abstraction_v2/components/AddressPaymasterInput/styles.module.scss b/src/modules/blockchains/detail_v3/account-abstraction_v2/components/AddressPaymasterInput/styles.module.scss new file mode 100644 index 000000000..91dda5eeb --- /dev/null +++ b/src/modules/blockchains/detail_v3/account-abstraction_v2/components/AddressPaymasterInput/styles.module.scss @@ -0,0 +1,25 @@ +.input { + background-color: #ffffff !important; + color: #000000 !important; + width: 200px !important; + padding: 0 12px !important; + border-radius: 99999px !important; + outline: none !important; + height: 22px !important; + line-height: calc(20 / 14); + font-family: var(--font-SFProDisplay); + + &::placeholder { + color: #000000 !important; + opacity: 0.5 !important; + } + + &__disabled { + pointer-events: none !important; + cursor: not-allowed !important; + } +} + +.fontError { + font-family: var(--font-SFProDisplay); +} diff --git a/src/modules/blockchains/detail_v3/account-abstraction_v2/components/SelectTokenView/index.tsx b/src/modules/blockchains/detail_v3/account-abstraction_v2/components/SelectTokenView/index.tsx new file mode 100644 index 000000000..fa60384e8 --- /dev/null +++ b/src/modules/blockchains/detail_v3/account-abstraction_v2/components/SelectTokenView/index.tsx @@ -0,0 +1,66 @@ +import { useAAModule } from '@/modules/blockchains/detail_v4/hook/useAAModule'; +import { useDAServicesHelper } from '@/modules/blockchains/detail_v4/hook/useDAServicesHelper'; +import { useChainProvider } from '@/modules/blockchains/detail_v4/provider/ChainProvider.hook'; +import { Flex, Image, Tooltip } from '@chakra-ui/react'; +import { useState } from 'react'; + +const SelectTokenView = () => { + const { isUpdateFlow } = useChainProvider(); + const { aaStatusData, aaInstalledData, isCanNotEdit } = useAAModule(); + const { statusCode } = aaStatusData; + + const { tokenIssueList } = useDAServicesHelper(); + + const [tokenSelected, setTokenSelected] = useState(''); + + // const { + // setTokenContractAddress, + // tokenContractAddress, + // isTokenContractAddressFocused, + // tokenContractAddressErrMsg, + // setTokenContractFocused, + // checkTokenContractAddress, + // } = useAccountAbstractionStore(); + + return ( + + + + + + {/* */} + + ); +}; + +export default SelectTokenView; diff --git a/src/modules/blockchains/detail_v3/account-abstraction_v2/components/SelectTokenView/styles.module.scss b/src/modules/blockchains/detail_v3/account-abstraction_v2/components/SelectTokenView/styles.module.scss new file mode 100644 index 000000000..ed9c60cb8 --- /dev/null +++ b/src/modules/blockchains/detail_v3/account-abstraction_v2/components/SelectTokenView/styles.module.scss @@ -0,0 +1,29 @@ +.input { + background-color: #ffffff !important; + color: #000000 !important; + width: 200px !important; + padding: 0 12px !important; + border-radius: 99999px !important; + outline: none !important; + height: 22px !important; + line-height: calc(20 / 14); + font-family: var(--font-SFProDisplay); + + &::placeholder { + color: #000000 !important; + opacity: 0.5 !important; + } + + &__disabled { + pointer-events: none !important; + cursor: not-allowed !important; + } +} + +.fontError { + font-family: var(--font-SFProDisplay); +} + +.selectStyle { + color: #000 !important; +} diff --git a/src/modules/blockchains/detail_v4/enhance/enhance.loopFetchIssueTokenList.tsx b/src/modules/blockchains/detail_v4/enhance/enhance.loopFetchIssueTokenList.tsx new file mode 100644 index 000000000..626fd1adc --- /dev/null +++ b/src/modules/blockchains/detail_v4/enhance/enhance.loopFetchIssueTokenList.tsx @@ -0,0 +1,32 @@ +import { useEffect } from 'react'; +import { useDAServicesHelper } from '../hook/useDAServicesHelper'; + +const enhanceLoopFetchIssueTokenList = + (WrappedComponent: any) => (props: any) => { + const { chainDetailData } = props; + + const { loopFetchTokenIssueList, clearLoopFetchTokenIssueList } = + useDAServicesHelper(); + + useEffect(() => { + // console.log( + // '--- enhanceLoopFetchIssueTokenList useEffect START --- ', + // chainDetailData, + // ); + + if (chainDetailData && chainDetailData.chainId) { + loopFetchTokenIssueList(chainDetailData?.chainId); + } else { + clearLoopFetchTokenIssueList(); + } + + return () => { + console.log('--- enhanceLoopFetchIssueTokenList useEffect END --- '); + clearLoopFetchTokenIssueList(); + }; + }, []); + + return ; + }; + +export default enhanceLoopFetchIssueTokenList; diff --git a/src/modules/blockchains/detail_v4/enhance/enhance.loopFetchOrder.tsx b/src/modules/blockchains/detail_v4/enhance/enhance.loopFetchOrder.tsx index 143ae818f..be9fb7896 100644 --- a/src/modules/blockchains/detail_v4/enhance/enhance.loopFetchOrder.tsx +++ b/src/modules/blockchains/detail_v4/enhance/enhance.loopFetchOrder.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { useFetchOrderTimer } from '../hook/useFetchOrderTimer'; const enhanceLoopFetchOrder = (WrappedComponent: any) => (props: any) => { - const { orderId } = props; + const { orderId, chainDetailData } = props; const { loopFetchChainInfor, clearIntervalTimer } = useFetchOrderTimer( orderId!, diff --git a/src/modules/blockchains/detail_v4/enhance/index.tsx b/src/modules/blockchains/detail_v4/enhance/index.tsx index ade3419c0..826e3c804 100644 --- a/src/modules/blockchains/detail_v4/enhance/index.tsx +++ b/src/modules/blockchains/detail_v4/enhance/index.tsx @@ -9,6 +9,7 @@ import enhanceUpdateHandler from './enhance.updateHandler'; import enhanceValidateOrderData from './enhance.validateOrderData'; import enhanceCheckRedirect from './enhance.checkRedirect'; import enhanceLoopFetchOrder from './enhance.loopFetchOrder'; +import enhanceLoopFetchIssueTokenList from './enhance.loopFetchIssueTokenList'; // import withAuth from './enhance.withAuth'; @@ -45,6 +46,8 @@ export default compose( withAuth, // TO DO enhanceLoopFetchOrder, + enhanceLoopFetchIssueTokenList, + // --------------------------------- // Top Level UI // --------------------------------- diff --git a/src/modules/blockchains/detail_v4/enhance_create_flow/enhance.FilterWithDappParam.tsx b/src/modules/blockchains/detail_v4/enhance_create_flow/enhance.FilterWithDappParam.tsx new file mode 100644 index 000000000..53c5e44ff --- /dev/null +++ b/src/modules/blockchains/detail_v4/enhance_create_flow/enhance.FilterWithDappParam.tsx @@ -0,0 +1,37 @@ +import { useEffect, useState } from 'react'; +import { ChainDetailComponent, ChainDetailComponentProps } from '../types'; + +import { useAppDispatch } from '@/stores/hooks'; +import { + setDAppParam, + setTemplateParam, +} from '@/stores/states/l2services/reducer'; +import { DappParam } from '@/stores/states/l2services/types'; +import { useSearchParams } from 'next/navigation'; + +const enhanceFilterWithDappParam = + (WrappedComponent: ChainDetailComponent) => + (props: ChainDetailComponentProps) => { + // const { setDAppParamByData } = useAvailableListTemplate(); + const searchParams = useSearchParams(); + const dispatch = useAppDispatch(); + + const dappParam = searchParams.get('dapp'); + const templateParam = searchParams.get('template') || '-1'; + + console.log('[enhanceFilterWithDappParam] dappParam', dappParam); + + const [isInitFinish, setInitFinish] = useState(false); + + useEffect(() => { + // setDAppParamByData(dappParam); + dispatch(setDAppParam(dappParam as DappParam)); + dispatch(setTemplateParam(templateParam)); + setInitFinish(true); + }, [dappParam, templateParam]); + + if (!isInitFinish) return null; + if (isInitFinish) return ; + }; + +export default enhanceFilterWithDappParam; diff --git a/src/modules/blockchains/detail_v4/enhance_create_flow/index.tsx b/src/modules/blockchains/detail_v4/enhance_create_flow/index.tsx index 6a5839bca..34c8a7537 100644 --- a/src/modules/blockchains/detail_v4/enhance_create_flow/index.tsx +++ b/src/modules/blockchains/detail_v4/enhance_create_flow/index.tsx @@ -5,6 +5,7 @@ import enhanceClearStudioLocalStorage from './enhance.clearStudioLocalStorage'; import enhanceGetTemplateParam from './enhance.getTemplateParam'; import enhancePrepareData from './enhance.prepareData'; +import enhanceFilterWithDappParam from './enhance.FilterWithDappParam'; import withLoading from './enhance.withLoading'; @@ -22,6 +23,9 @@ export default compose( // withLoading, + // Already Data + enhanceFilterWithDappParam, + // Main Page enhance, ); diff --git a/src/modules/blockchains/detail_v4/hook/useAAModule.ts b/src/modules/blockchains/detail_v4/hook/useAAModule.ts index b5b12fc60..4c19cc771 100644 --- a/src/modules/blockchains/detail_v4/hook/useAAModule.ts +++ b/src/modules/blockchains/detail_v4/hook/useAAModule.ts @@ -80,6 +80,10 @@ export const useAAModule = () => { return aaStatusDetail === 'done'; }, [aaStatusDetail]); + const isDone = useMemo(() => { + return aaStatusDetail === 'done'; + }, [aaStatusDetail]); + const configAAHandler = async () => { try { if (!order) { @@ -154,6 +158,7 @@ export const useAAModule = () => { configAAHandler, isCanConfigAA, isCanNotEdit, + isDone, aaStatusDetail, isAAModuleLoading, checkTokenContractAddress, diff --git a/src/modules/blockchains/detail_v4/hook/useBridgesModule.ts b/src/modules/blockchains/detail_v4/hook/useBridgesModule.ts index 69ee668a4..70a1c2c6d 100644 --- a/src/modules/blockchains/detail_v4/hook/useBridgesModule.ts +++ b/src/modules/blockchains/detail_v4/hook/useBridgesModule.ts @@ -25,6 +25,8 @@ export const useBridgesModule = () => { const isSettingUp = item?.status === 'new' || item?.status === 'processing'; + const isDone = item?.status === 'done'; + let label = !isUpdateFlow ? '' : isSettingUp ? 'Setting up' : 'Running'; let backgroundColor = !isUpdateFlow ? 'transparent' @@ -39,6 +41,7 @@ export const useBridgesModule = () => { const mapper = { ...item, + isDone, label: label, backgroundColor: backgroundColor, textColor: textColor, diff --git a/src/modules/blockchains/detail_v4/hook/useDAServicesHelper.ts b/src/modules/blockchains/detail_v4/hook/useDAServicesHelper.ts new file mode 100644 index 000000000..2bfe8f6fd --- /dev/null +++ b/src/modules/blockchains/detail_v4/hook/useDAServicesHelper.ts @@ -0,0 +1,50 @@ +import { useAppDispatch, useAppSelector } from '@/stores/hooks'; +import { fetchIssueTokenListByChainID } from '@/stores/states/daServices/actions'; +import { useMemo, useRef } from 'react'; +import { useChainProvider } from '../provider/ChainProvider.hook'; +import { isEmpty } from 'lodash'; +import { getIsssueTokenListSelector } from '@/stores/states/daServices/selector'; + +const TIMER_INTERVAL = 10000; //10s + +export const useDAServicesHelper = () => { + const dispatch = useAppDispatch(); + const { order, isUpdateFlow } = useChainProvider(); + const tokenIssueList = useAppSelector(getIsssueTokenListSelector); + + // + const timerRef = useRef(); + + const clearLoopFetchTokenIssueList = () => { + clearInterval(timerRef.current); + timerRef.current = undefined; + }; + + const loopFetchTokenIssueList = (chainID: number | string) => { + clearLoopFetchTokenIssueList(); + if (!timerRef.current) { + dispatch(fetchIssueTokenListByChainID(chainID)); + timerRef.current = setInterval(() => { + dispatch(fetchIssueTokenListByChainID(chainID)); + }, TIMER_INTERVAL); + } + }; + + // + const isEmptyIssueTokenList = useMemo(() => { + return !tokenIssueList || isEmpty(tokenIssueList); + }, [tokenIssueList]); + + // RESULT + const result = { + tokenIssueList, + isEmptyIssueTokenList, + + loopFetchTokenIssueList, + clearLoopFetchTokenIssueList, + }; + + console.log('[useDAServicesHelper] -- ALl Data ', result); + + return result; +}; diff --git a/src/modules/blockchains/detail_v4/hook/useGameModule.ts b/src/modules/blockchains/detail_v4/hook/useGameModule.ts index 827aba925..5eb59fe2e 100644 --- a/src/modules/blockchains/detail_v4/hook/useGameModule.ts +++ b/src/modules/blockchains/detail_v4/hook/useGameModule.ts @@ -7,11 +7,10 @@ import { import * as CSS from 'csstype'; import { ResponsiveValue } from '@chakra-ui/react'; -export type GmaeModuleStatus = 'draft' | 'setting_up' | 'running' | 'down'; +export type GameModuleStatus = 'draft' | 'setting_up' | 'running' | 'down'; export const useGameModule = () => { - const { order, isUpdateFlow, isBridgeInstalled, isGamingAppsInstalled } = - useChainProvider(); + const { order, isUpdateFlow, isGamingAppsInstalled } = useChainProvider(); const gameDAppsIntalledList = useMemo(() => { return order?.dApps?.filter((item) => item.appCode?.includes('game')) || []; @@ -48,8 +47,8 @@ export const useGameModule = () => { return detailGameMapper; }, [gameDAppsIntalledList]); - const bridgeModuleStatus: GmaeModuleStatus = useMemo(() => { - if (!isUpdateFlow || !isBridgeInstalled) { + const moduleStatus: GameModuleStatus = useMemo(() => { + if (!isUpdateFlow || !isGamingAppsInstalled) { return 'draft'; } else { if (gameDAppsIntalledList.length < 1) { @@ -84,9 +83,10 @@ export const useGameModule = () => { return 'draft'; } } - }, [isUpdateFlow, isBridgeInstalled, gameDAppsIntalledList]); + }, [isUpdateFlow, isGamingAppsInstalled, gameDAppsIntalledList]); - const lineBridgeStatus = bridgeModuleStatus; + const lineBridgeStatus = moduleStatus; + const lineStatus = moduleStatus; const statusMapper = useMemo(() => { let statusCode = 'draft'; @@ -101,7 +101,7 @@ export const useGameModule = () => { fontStyle = 'normal'; textDecorationLine = 'none'; - switch (bridgeModuleStatus) { + switch (moduleStatus) { case 'draft': //Get above value break; @@ -139,10 +139,10 @@ export const useGameModule = () => { fontStyle, textDecorationLine, }; - }, [bridgeModuleStatus]); + }, [moduleStatus]); const getGameTypeIcon = (): ModuleTypeIcon => { - switch (bridgeModuleStatus) { + switch (moduleStatus) { case 'draft': return 'Drafting'; case 'setting_up': @@ -160,9 +160,10 @@ export const useGameModule = () => { return { lineBridgeStatus, + lineStatus, gameDAppsIntalledList, statusMapper, - bridgeModuleStatus, + moduleStatus, getGameTypeIconUrl, detailGameMapperStatus, diff --git a/src/modules/blockchains/detail_v4/provider/ChainProvider.tsx b/src/modules/blockchains/detail_v4/provider/ChainProvider.tsx index 80ffbc416..7fe69796e 100644 --- a/src/modules/blockchains/detail_v4/provider/ChainProvider.tsx +++ b/src/modules/blockchains/detail_v4/provider/ChainProvider.tsx @@ -1,33 +1,34 @@ 'use client'; +import { IToken } from '@/services/api/dapp/token_generation/interface'; import { useAppDispatch } from '@/stores/hooks'; import { OrderItem } from '@/stores/states/l2services/types'; -import { - PropsWithChildren, - createContext, - useEffect, - useMemo, - useState, -} from 'react'; -import { IChainProvider } from './ChainProvider.types'; +import { createContext, useEffect, useMemo, useState } from 'react'; import { getChainIDRandom } from '../../Buy/Buy.helpers'; +import { IChainProvider } from './ChainProvider.types'; export const ChainContext = createContext({ order: undefined, chainID: undefined, + tokenIssueList: [], }); export const ChainProvider = ({ children, orderData, + tokenIssueListData, }: { children?: any; orderData?: OrderItem; + tokenIssueListData?: IToken[]; }) => { const dispatch = useAppDispatch(); const [order, setOrder] = useState(orderData); const [chainID, setChainID] = useState(undefined); + const [tokenIssueList, setTokenIssueList] = useState( + tokenIssueListData || [], + ); const getChainIDRandomHandler = async () => { const chainID = await getChainIDRandom(); @@ -41,6 +42,10 @@ export const ChainProvider = ({ } }, [orderData]); + useEffect(() => { + setTokenIssueList(tokenIssueListData || []); + }, [tokenIssueListData]); + useEffect(() => { getChainIDRandomHandler(); }, []); @@ -49,8 +54,9 @@ export const ChainProvider = ({ () => ({ order, chainID, + tokenIssueList, }), - [order, chainID, dispatch], + [order, chainID, tokenIssueList, dispatch], ); // console.log('ChainContext -- value -- ', value); diff --git a/src/modules/blockchains/detail_v4/provider/ChainProvider.types.ts b/src/modules/blockchains/detail_v4/provider/ChainProvider.types.ts index b63a965fd..390b517c8 100644 --- a/src/modules/blockchains/detail_v4/provider/ChainProvider.types.ts +++ b/src/modules/blockchains/detail_v4/provider/ChainProvider.types.ts @@ -1,10 +1,12 @@ import { OrderItem } from '@/stores/states/l2services/types'; +import { IToken } from '@/services/api/dapp/token_generation/interface'; export type IChainProviderActions = {}; export type IChainProviderProps = { order: OrderItem | undefined; chainID: number | undefined; + tokenIssueList: IToken[]; }; export type IChainProvider = IChainProviderActions & IChainProviderProps; diff --git a/src/modules/blockchains/enhnace/enhance.withWaiting.tsx b/src/modules/blockchains/enhnace/enhance.withWaiting.tsx new file mode 100644 index 000000000..c90f507d9 --- /dev/null +++ b/src/modules/blockchains/enhnace/enhance.withWaiting.tsx @@ -0,0 +1,31 @@ +import { useEffect, useState } from 'react'; +import { DashboardProps, DashboardWrappedComponent } from '../Dashboard.types'; +import { Flex, Spinner } from '@chakra-ui/react'; + +const enhance = + (WrappedComponent: DashboardWrappedComponent) => (props: DashboardProps) => { + const [isInitDone, setInitDone] = useState(false); + + useEffect(() => { + setTimeout(() => { + setInitDone(true); + }, 1000); + }, []); + + if (!isInitDone) + return ( + + + + ); + return ; + }; + +export default enhance; diff --git a/src/modules/blockchains/enhnace/index.tsx b/src/modules/blockchains/enhnace/index.tsx index 2bfaf53bd..e91a373bf 100644 --- a/src/modules/blockchains/enhnace/index.tsx +++ b/src/modules/blockchains/enhnace/index.tsx @@ -11,6 +11,7 @@ import enhanceUpdateOrderModal from './enhance.UpdateOrderModal'; import enhanceWaittingSettingUpModal from './enhance.WaittingSettingUpModal'; import enhanceDappListModal from './enhance.DappListModal'; import enhanceInstallDappDetailModal from './enhance.InstallDappDetailModal'; +import withWaiting from './enhance.withWaiting'; import { DashboardContext } from '../providers/DashboardProvider'; @@ -34,5 +35,6 @@ export default compose( enhanceWaittingSettingUpModal, enhanceInstallDappDetailModal, enhanceDappListModal, + withWaiting, enhance, ); diff --git a/src/modules/l2-rollup-detail/TokenTransferTabBitcoin/index.tsx b/src/modules/l2-rollup-detail/TokenTransferTabBitcoin/index.tsx index 9f6c2cecc..5b2b1eca5 100644 --- a/src/modules/l2-rollup-detail/TokenTransferTabBitcoin/index.tsx +++ b/src/modules/l2-rollup-detail/TokenTransferTabBitcoin/index.tsx @@ -17,6 +17,7 @@ import { L2RollupDetailContext } from '../providers/l2-rollup-detail-context'; import s from './styles.module.scss'; import { useRouter } from 'next/navigation'; import { HEART_BEAT } from '@/constants/route-path'; +import TransactionsTabFBitcoin from '../TransactionsTabFBitcoin'; interface IProps {} @@ -25,7 +26,7 @@ const TokenTransferTabBitcoin = (props: IProps) => { const router = useRouter(); const rollupApi = new CRollupL2DetailBitcoinAPI(); - const [balanceType, setBalanceType] = useState('runes'); + const [balanceType, setBalanceType] = useState('fractal'); const [list, setList] = useState([]); @@ -319,7 +320,13 @@ const TokenTransferTabBitcoin = (props: IProps) => { borderRadius={'8px'} mb={'20px'} > - {BalanceTypes.map((balance) => ( + {[ + { + type: 'fractal', + title: 'Fractal', + }, + ...BalanceTypes, + ].map((balance) => ( { ))}
- - { - refParams.current = { - ...refParams.current, - page: refParams.current.page + 1, - }; - hasIncrementedPageRef.current = true; - fetchData(); - }} - isFetching={refreshing} - hasIncrementedPageRef={hasIncrementedPageRef} - onFetchNewData={onRefresh} - wrapClassName={s.wrapScroll} - dependData={list} - > - } - /> - {isFetching && } - - + {balanceType === 'fractal' ? ( + + ) : ( + + { + refParams.current = { + ...refParams.current, + page: refParams.current.page + 1, + }; + hasIncrementedPageRef.current = true; + fetchData(); + }} + isFetching={refreshing} + hasIncrementedPageRef={hasIncrementedPageRef} + onFetchNewData={onRefresh} + wrapClassName={s.wrapScroll} + dependData={list} + > + } + /> + {isFetching && } + + + )} ); }; diff --git a/src/modules/l2-rollup-detail/TransactionsTab/index.tsx b/src/modules/l2-rollup-detail/TransactionsTab/index.tsx index 890be654f..e3a9010ce 100644 --- a/src/modules/l2-rollup-detail/TransactionsTab/index.tsx +++ b/src/modules/l2-rollup-detail/TransactionsTab/index.tsx @@ -16,6 +16,7 @@ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; import { L2RollupDetailContext } from '../providers/l2-rollup-detail-context'; import s from './styles.module.scss'; import { HEART_BEAT } from '@/constants/route-path'; +import EmptyList from '@/components/ListTable/EmptyList'; interface IProps {} @@ -325,14 +326,13 @@ const TransactionsTab = (props: IProps) => { wrapClassName={s.wrapScroll} dependData={list} > - } - /> + {!isFetching && list.length === 0 && ( + } + /> + )} {isFetching && } diff --git a/src/modules/l2-rollup-detail/TransactionsTabFBitcoin/index.tsx b/src/modules/l2-rollup-detail/TransactionsTabFBitcoin/index.tsx new file mode 100644 index 000000000..d3ea431e7 --- /dev/null +++ b/src/modules/l2-rollup-detail/TransactionsTabFBitcoin/index.tsx @@ -0,0 +1,329 @@ +import AppLoading from '@/components/AppLoading'; +import EmptyList from '@/components/ListTable/EmptyList'; +import ScrollWrapper from '@/components/ScrollWrapper/ScrollWrapper'; +import { HEART_BEAT } from '@/constants/route-path'; +import CRollupL2DetailBitcoinAPI from '@/services/api/dapp/rollupl2-detail-bitcoin'; +import { IFBitcoinTransaction } from '@/services/api/dapp/rollupl2-detail-bitcoin/interface'; +import { shortCryptoAddress } from '@/utils/address'; +import { formatCurrency } from '@/utils/format'; +import { formatTimeAgo } from '@/utils/time'; +import { Box, Flex, Image, SimpleGrid, Text } from '@chakra-ui/react'; +import BigNumber from 'bignumber.js'; +import dayjs from 'dayjs'; +import { useRouter } from 'next/navigation'; +import { useContext, useEffect, useRef, useState } from 'react'; +import { + L2RollupExplorerContext, + L2RollupExplorerProvider, +} from '../providers/l2-rollup-explorer-context'; +import s from './styles.module.scss'; + +interface IProps {} + +const TransactionsTabFBitcoin = (props: IProps) => { + const { address, fbBlockCount } = useContext(L2RollupExplorerContext); + + const router = useRouter(); + + const rollupApi = new CRollupL2DetailBitcoinAPI(); + + const [list, setList] = useState([]); + + const [isFetching, setIsFetching] = useState(true); + const [refreshing, setRefreshing] = useState(false); + + const refInitial = useRef(false); + const endOfPaging = useRef(false); + const hasIncrementedPageRef = useRef(false); + const refParams = useRef({ + after_hash: '', + }); + + useEffect(() => { + fetchData(true); + }, [address]); + + const fetchData = async (isNew?: boolean) => { + try { + if (isNew) { + setIsFetching(true); + endOfPaging.current = false; + + setList([]); + refParams.current = { + ...refParams.current, + after_hash: '', + }; + const res = (await rollupApi.getRollupL2FractalBitcoinTokenTransactions( + { + user_address: address, + type: 'fractal', + ...refParams.current, + }, + )) as any; + + setList(res); + } else { + if (endOfPaging.current) return; + setIsFetching(true); + const res = (await rollupApi.getRollupL2FractalBitcoinTokenTransactions( + { + user_address: address, + type: 'fractal', + ...refParams.current, + }, + )) as any; + if (res && res?.length > 0) { + setList([...list, ...res]); + } else { + endOfPaging.current = true; + } + } + } catch (error) { + } finally { + setIsFetching(false); + hasIncrementedPageRef.current = false; + } + }; + + const onRefresh = async () => { + if (!refInitial.current) { + return; + } + try { + setRefreshing(true); + refParams.current = { + ...refParams.current, + after_hash: '', + }; + hasIncrementedPageRef.current = true; + await fetchData(true); + } catch (error) { + console.log('refreshing err', error); + } finally { + setRefreshing(false); + } + }; + + return ( + + 0 ? '' : s.shadow}`} + h="60vh" + > + { + if (list.length >= 10) { + refParams.current = { + ...refParams.current, + after_hash: list[list.length - 1].txid, + }; + hasIncrementedPageRef.current = true; + fetchData(); + } + }} + isFetching={refreshing} + hasIncrementedPageRef={hasIncrementedPageRef} + onFetchNewData={onRefresh} + wrapClassName={s.wrapScroll} + dependData={list} + > + + {list.length > 0 && + list.map((item) => { + return ( + + + + + + {item.txid} + + + + + {dayjs + .unix(Number(item.status.block_time)) + .format('HH:mm:ss MM/DD/YYYY')} + + {' '} + ({formatTimeAgo(item.status.block_time)}) + + + + + + + {item.vin.map((item) => { + return ( + + + {item.is_coinbase + ? 'Coinbase' + : shortCryptoAddress( + item.prevout.scriptpubkey_address, + 20, + )} + + {item.prevout?.value && ( + + {formatCurrency( + new BigNumber( + item.prevout.value || '0', + ).dividedBy(1e8), + 0, + 6, + )}{' '} + FB + + )} + + ); + })} + + + {item.vout.map((item) => { + return ( + + + {item.scriptpubkey_address + ? shortCryptoAddress( + item.scriptpubkey_address, + 20, + ) + : item.scriptpubkey_type.toUpperCase()} + + {item?.value && ( + + {formatCurrency( + new BigNumber(item.value || '0').dividedBy( + 1e8, + ), + 0, + 6, + )}{' '} + FB + + )} + + ); + })} + + + + + + Block:{' '} + {item?.status?.block_height || '-'} + + | + + Txn fee:{' '} + {item?.fee ? item?.fee + ' sats' : '-'} + + + + {item.status.confirmed + ? `${formatCurrency( + fbBlockCount - Number(item.status.block_height), + 0, + 2, + )} confirmed` + : 'Pending'} + + + + ); + })} + + {!isFetching && list.length === 0 && ( + } + /> + )} + {isFetching && } + + + + ); +}; + +const TransactionsTabFBitcoinModule = () => { + return ( + + + + ); +}; + +export default TransactionsTabFBitcoinModule; diff --git a/src/modules/l2-rollup-detail/TransactionsTabFBitcoin/styles.module.scss b/src/modules/l2-rollup-detail/TransactionsTabFBitcoin/styles.module.scss new file mode 100644 index 000000000..77233033c --- /dev/null +++ b/src/modules/l2-rollup-detail/TransactionsTabFBitcoin/styles.module.scss @@ -0,0 +1,73 @@ +.container { + width: 100%; + + .item { + border: 1px solid #efefef; + border-radius: 12px; + } +} + +.shadow { + box-shadow: 0px 0px 20px -6px #00000014; + border-radius: 12px; +} + +.wrapScroll { + overflow-x: auto !important; + + :global { + .chakra-table__container { + border-radius: 0px; + border: 0px solid transparent !important; + } + .isActiveRow { + background-color: rgba(26, 172, 235, 0.2) !important; + + p { + color: black !important; + } + } + } +} + +table { + &.tableContainer { + overflow-x: hidden; + + :global { + .chakra-table__container { + border-radius: 0px; + border: 0px solid transparent !important; + } + .isActiveRow { + background-color: rgba(26, 172, 235, 0.2) !important; + + p { + color: black !important; + } + } + } + + tbody { + border-top: 1px solid #efefef; + + tr { + td { + border-bottom: 0px; + } + } + } + + .title { + font-style: normal; + font-size: 14px; + + overflow: hidden; + text-overflow: ellipsis; + } + } +} + +.loading { + margin-top: 16px; +} diff --git a/src/modules/l2-rollup-detail/TxBTCExplorer/blockConfirm/index.tsx b/src/modules/l2-rollup-detail/TxBTCExplorer/blockConfirm/index.tsx index 4202047b1..88e55cb9f 100644 --- a/src/modules/l2-rollup-detail/TxBTCExplorer/blockConfirm/index.tsx +++ b/src/modules/l2-rollup-detail/TxBTCExplorer/blockConfirm/index.tsx @@ -10,10 +10,12 @@ import { useDispatch } from 'react-redux'; const BlockConfirm = ({ txBTC, + isFBTxAddress, setIndexBlock, setTimeAvg, }: { txBTC: ITxBTC; + isFBTxAddress: boolean; setIndexBlock: any; setTimeAvg: any; }) => { @@ -30,8 +32,8 @@ const BlockConfirm = ({ return; } const [rs, rs1, rs2] = await Promise.all([ - mempoolApi.getBlocks(), - mempoolApi.getTransactionStatus(txBTC.tx_id), + mempoolApi.getBlocks(isFBTxAddress), + mempoolApi.getTransactionStatus(txBTC.tx_id, isFBTxAddress), rollupDetailApi.getTimeAVG(), ]); if (rs1?.confirmed) { diff --git a/src/modules/l2-rollup-detail/TxBTCExplorer/index.tsx b/src/modules/l2-rollup-detail/TxBTCExplorer/index.tsx index bdce1e11f..d581ff5c9 100644 --- a/src/modules/l2-rollup-detail/TxBTCExplorer/index.tsx +++ b/src/modules/l2-rollup-detail/TxBTCExplorer/index.tsx @@ -35,9 +35,14 @@ import s from './styles.module.scss'; import TokenTransfers from './tokenTransfer'; import { shortCryptoAddress } from '@/utils/address'; import { isMobile } from 'react-device-detect'; +import { formatTimeAgo } from '@/utils/time'; const TxBTCExplorer = () => { - const { address, isBTCTxAddress } = useContext(L2RollupExplorerContext); + const { address, isBTCTxAddress, fbBlockCount } = useContext( + L2RollupExplorerContext, + ); + const [isFBTxAddress, setIsFBTxAddress] = useState(false); + const [loading, setLoading] = useState(true); const [txBTC, setTxBTC] = useState(); const coinPrices = useSelector(commonSelector).coinPrices; @@ -66,11 +71,16 @@ const TxBTCExplorer = () => { return; } - const [rs, rs1] = await Promise.all([ - rollupBitcoinApi.getTxBTC(address), - mempoolApi.getTransactionTime(address), - ]); + const rs = await rollupBitcoinApi.getTxBTC(address); + if (!rs?.tx_id) return; + + let isFBChain = false; + if (rs?.chain === 'fractal') { + isFBChain = true; + setIsFBTxAddress(true); + } + const rs1 = await mempoolApi.getTransactionTime(address, isFBChain); const _rs: any = rs; if (rs1?.[0]) { @@ -87,8 +97,10 @@ const TxBTCExplorer = () => { const timestamp = useMemo( () => - new BigNumber(txBTC?.transaction_time || '0').dividedBy(1000).toNumber(), - [txBTC], + new BigNumber(txBTC?.transaction_time || '0') + .dividedBy(isFBTxAddress ? 1 : 1000) + .toNumber(), + [txBTC, isFBTxAddress], ); const isProcessing = useMemo( @@ -104,7 +116,14 @@ const TxBTCExplorer = () => { } return ( - {formatCurrency(txBTC?.confirm, 0, 2)} confirmation + {formatCurrency( + isFBTxAddress + ? fbBlockCount - Number(txBTC?.height || '0') + : txBTC?.confirm, + 0, + 2, + )}{' '} + confirmation {labelAmountOrNumberAdds(txBTC?.confirm || 0)} ); @@ -145,7 +164,9 @@ const TxBTCExplorer = () => { gap={'4px'} flexDirection={['column', 'row']} > - Transaction + + {isFBTxAddress ? 'Fractal ' : ''}Transaction + { copy(address); @@ -162,6 +183,7 @@ const TxBTCExplorer = () => { {isProcessing && ( @@ -181,7 +203,7 @@ const TxBTCExplorer = () => { ) : ( <> {dayjs.unix(timestamp).format('YYYY-MM-DD HH:mm:ss')} - ({dayjs.unix(timestamp).toNow()}) + ({formatTimeAgo(timestamp)}) )} @@ -189,12 +211,25 @@ const TxBTCExplorer = () => { Fee - - {txBTC.transaction_symbol} + $ {formatCurrency( - new BigNumber(btcPrice).multipliedBy(txBTC.txfee).toString(), + new BigNumber(btcPrice) + .multipliedBy( + isFBTxAddress + ? new BigNumber(txBTC.txfee).dividedBy(1e8) + : txBTC.txfee, + ) + .toString(), )} @@ -218,7 +253,7 @@ const TxBTCExplorer = () => { Fee rate - + { isSats={true} hideSymbol={true} /> - sats/vB + sat/vB @@ -244,22 +279,34 @@ const TxBTCExplorer = () => { {formatCurrency( txBTC.input_details.reduce( - (p, c) => p + parseFloat(c.amount), + (p, c) => + p + + parseFloat( + isFBTxAddress + ? new BigNumber(c.amount).dividedBy(1e8).toString() + : c.amount, + ), 0, ), 2, 6, - )}{' '} - {txBTC.transaction_symbol} |{' '} + )} + {txBTC.transaction_symbol} |{' '} {formatCurrency( txBTC.output_details.reduce( - (p, c) => p + parseFloat(c.amount), + (p, c) => + p + + parseFloat( + isFBTxAddress + ? new BigNumber(c.amount).dividedBy(1e8).toString() + : c.amount, + ), 0, ), 2, 6, - )}{' '} - {txBTC.transaction_symbol} + )} + {txBTC.transaction_symbol}
@@ -306,6 +353,7 @@ const TxBTCExplorer = () => { symbol={txBTC.transaction_symbol} address={d.input_hash} tokenTransfer={txBTC.token_transfer} + isFBTxAddress={isFBTxAddress} /> ))} @@ -317,6 +365,7 @@ const TxBTCExplorer = () => { symbol={txBTC.transaction_symbol} address={d.output_hash} tokenTransfer={txBTC.token_transfer} + isFBTxAddress={isFBTxAddress} /> ))} diff --git a/src/modules/l2-rollup-detail/TxBTCExplorer/itemTransfer.tsx b/src/modules/l2-rollup-detail/TxBTCExplorer/itemTransfer.tsx index 7272f562d..ec1a2b684 100644 --- a/src/modules/l2-rollup-detail/TxBTCExplorer/itemTransfer.tsx +++ b/src/modules/l2-rollup-detail/TxBTCExplorer/itemTransfer.tsx @@ -9,7 +9,7 @@ import { compareString } from '@/utils/string'; import { Box, Flex, Text } from '@chakra-ui/react'; import copy from 'copy-to-clipboard'; import { useMemo } from 'react'; -import toast from 'react-hot-toast'; +import BigNumber from 'bignumber.js'; import s from './styles.module.scss'; import AddressCopy from './addressCopy'; import { useRouter } from 'next/navigation'; @@ -35,11 +35,13 @@ const ItemTransfer = ({ symbol, address, tokenTransfer, + isFBTxAddress, }: { data: ITxBTCPutDetail; symbol: string; address: string; tokenTransfer: ITxBTCTokenTransfer[]; + isFBTxAddress: boolean; }) => { const router = useRouter(); const token: ITxBTCTokenTransfer = useMemo( @@ -62,7 +64,14 @@ const ItemTransfer = ({ onClick={() => router.push(`${HEART_BEAT}/address/${address}`)} /> - {formatCurrency(data.amount, 0, 6)} {symbol} + {formatCurrency( + isFBTxAddress + ? new BigNumber(data.amount).dividedBy(1e8).toString() + : data.amount, + 0, + 6, + )}{' '} + {symbol} {token && ( diff --git a/src/modules/l2-rollup-detail/TxBTCExplorer/styles.module.scss b/src/modules/l2-rollup-detail/TxBTCExplorer/styles.module.scss index 9d7f916a4..16ec89747 100644 --- a/src/modules/l2-rollup-detail/TxBTCExplorer/styles.module.scss +++ b/src/modules/l2-rollup-detail/TxBTCExplorer/styles.module.scss @@ -146,6 +146,7 @@ border-radius: 4px; > p { font-size: 14px; + line-height: 140%; &:first-child { flex: 1; } @@ -153,8 +154,9 @@ flex: 2; } span { - opacity: 0.8; + opacity: 0.7; font-size: 10px; + line-height: 140%; } } &.rowItemBold { diff --git a/src/modules/l2-rollup-detail/TxExplorer/index.tsx b/src/modules/l2-rollup-detail/TxExplorer/index.tsx index a1a3f4d04..2f21241f3 100644 --- a/src/modules/l2-rollup-detail/TxExplorer/index.tsx +++ b/src/modules/l2-rollup-detail/TxExplorer/index.tsx @@ -51,7 +51,7 @@ const TxExplorerModuleHandle = () => { onClick={() => router.push(HEART_BEAT)} > - Bitcoin Heartbeat Project + Bitcoin Heartbeats Project { onClick={() => router.push(HEART_BEAT)} > - Bitcoin Heartbeat Project + Bitcoin Heartbeats Project { {`${formatCurrency(balanceBitcoinInfo?.balance, 2, 6)} BTC ${ rollupBitcoinBalances && rollupBitcoinBalances.length > 0 ? `($${formatCurrency( - rollupBitcoinBalances[0].amountUsd, + rollupBitcoinBalances.find( + (balance) => balance.title === 'BTC', + )?.amountUsd || 0, 2, 2, )})` diff --git a/src/modules/l2-rollup-detail/providers/l2-rollup-detail-context.tsx b/src/modules/l2-rollup-detail/providers/l2-rollup-detail-context.tsx index 48e9ccdf5..b9f08ce7e 100644 --- a/src/modules/l2-rollup-detail/providers/l2-rollup-detail-context.tsx +++ b/src/modules/l2-rollup-detail/providers/l2-rollup-detail-context.tsx @@ -286,6 +286,20 @@ export const L2RollupDetailProvider: React.FC = ({ count: assetBitcoin[balanceType.type].length, }; }), + { + amountUsd: new BigNumber( + new BigNumber( + balanceBitcoinInfo?.fractal?.funded_txo_sum || '0', + ).dividedBy(1e8), + ) + .multipliedBy( + new BigNumber(rollupTokensRate ? rollupTokensRate['BTC'] : 0), + ) + .toNumber(), + title: 'BTC (Fractal)', + color: '#F8C462', + count: 0, + }, ]; }, [balanceBitcoinInfo, rollupTokensRate, assetBitcoin]); diff --git a/src/modules/l2-rollup-detail/providers/l2-rollup-explorer-context.tsx b/src/modules/l2-rollup-detail/providers/l2-rollup-explorer-context.tsx index 7a6fc1b6e..8c6105d6f 100644 --- a/src/modules/l2-rollup-detail/providers/l2-rollup-explorer-context.tsx +++ b/src/modules/l2-rollup-detail/providers/l2-rollup-explorer-context.tsx @@ -1,17 +1,30 @@ -import { isValidBTCTxHash, isValidERC20TxHash } from '@/utils/form-validate'; +import CMempoolApi from '@/services/api/mempool'; +import { + isValidBTCTxHash, + isValidERC20TxHash, + isValidFractalBTCTxHash, +} from '@/utils/form-validate'; import { useParams } from 'next/navigation'; -import React, { PropsWithChildren, useMemo } from 'react'; +import React, { + PropsWithChildren, + useMemo, + useRef, + useState, + useEffect, +} from 'react'; export interface IL2RollupExplorerContext { address: string; isBTCTxAddress: boolean; isERC20TxAddress: boolean; + fbBlockCount: number; } const initialValue: IL2RollupExplorerContext = { address: '', isBTCTxAddress: false, isERC20TxAddress: false, + fbBlockCount: 0, }; export const L2RollupExplorerContext = @@ -23,6 +36,9 @@ export const L2RollupExplorerProvider: React.FC = ({ const params = useParams(); const address = useMemo(() => params?.id as string, [params]); + const mempoolApi = useRef(new CMempoolApi()).current; + + const [fbBlockCount, setFbBlockCount] = useState(0); const isBTCTxAddress = useMemo(() => isValidBTCTxHash(address), [address]); const isERC20TxAddress = useMemo( @@ -30,9 +46,20 @@ export const L2RollupExplorerProvider: React.FC = ({ [address], ); + useEffect(() => { + getFbBlockCount(); + }, []); + + const getFbBlockCount = async () => { + try { + const data = await mempoolApi.getFBMiningPool(); + if (data) setFbBlockCount(data?.blockCount); + } catch (error) {} + }; + const contextValues = React.useMemo((): IL2RollupExplorerContext => { - return { address, isBTCTxAddress, isERC20TxAddress }; - }, [address, isBTCTxAddress, isERC20TxAddress]); + return { address, isBTCTxAddress, isERC20TxAddress, fbBlockCount }; + }, [address, isBTCTxAddress, isERC20TxAddress, fbBlockCount]); return ( diff --git a/src/modules/l2-rollup/AddressesEngagement/ActiveAddressChainPercent.tsx b/src/modules/l2-rollup/AddressesEngagement/ActiveAddressChainPercent.tsx new file mode 100644 index 000000000..0ce3009fe --- /dev/null +++ b/src/modules/l2-rollup/AddressesEngagement/ActiveAddressChainPercent.tsx @@ -0,0 +1,98 @@ +import { useEffect, useMemo, useRef } from 'react'; + +import { formatCurrency } from '@/utils/format'; +// @ts-ignore +import CanvasJSReact from '@canvasjs/react-charts'; + +var CanvasJSChart = CanvasJSReact.CanvasJSChart; + +const ActiveAddressChainPercent = ({ data = [] }: { data: any }) => { + const chartComponentRef = useRef(null); + const options: any = useMemo(() => { + return { + animationEnabled: true, + exportEnabled: false, + dataPointWidth: 0, + height: 200, + title: { + text: '', + }, + legend: { + verticalAlign: 'center', + horizontalAlign: 'right', + }, + axisX: { + lineColor: '#f5f5f5', + gridColor: '#f5f5f5', + labelFontSize: 10, + labelFontColor: '#434343', + tickColor: '#f5f5f5', + }, + axisY: { + suffix: '%', + lineColor: '#f5f5f5', + gridColor: '#f5f5f5', + labelFontSize: 10, + labelFontColor: '#434343', + tickColor: '#f5f5f5', + }, + toolTip: { + shared: true, + contentFormatter: function (e: any) { + const dataPoint = e.entries?.[0]?.dataPoint?.label; + let str = + '

' + + dataPoint + + '

'; + for (let i = 0; i < e.entries.length; i++) { + const entryData = e.entries[i]; + + if (entryData.dataPoint.y) { + const temp = + '
' + + entryData.dataSeries.name + + ': ' + + formatCurrency(entryData.dataPoint.y, 0, 2, 'BTC', true) + + '%
'; + str = str.concat(temp); + } + } + return str; + }, + }, + // legend: { + // verticalAlign: 'center', + // horizontalAlign: 'right', + // reversed: true, + // cursor: 'pointer', + // }, + data: data, + }; + }, [data]); + + useEffect(() => { + if (chartComponentRef.current) { + chartComponentRef.current.set( + 'dataPointWidth', + Math.ceil( + chartComponentRef.current.axisX[0].bounds.width / + chartComponentRef.current.data[0].dataPoints.length, + ), + true, + ); + } + }, []); + + return ( + (chartComponentRef.current = ref)} + /> + ); +}; + +export default ActiveAddressChainPercent; diff --git a/src/modules/l2-rollup/AddressesEngagement/ActiveAddressChart.tsx b/src/modules/l2-rollup/AddressesEngagement/ActiveAddressChart.tsx new file mode 100644 index 000000000..ee5b54488 --- /dev/null +++ b/src/modules/l2-rollup/AddressesEngagement/ActiveAddressChart.tsx @@ -0,0 +1,136 @@ +import React, { useMemo, useRef } from 'react'; + +import * as Highcharts from 'highcharts'; +import HighchartsReact from 'highcharts-react-official'; +import dayjs from 'dayjs'; +import { formatCurrency } from '@/utils/format'; + +const ActiveAddressChart = ({ data = [] }: { data: any }) => { + const chartComponentRef = useRef(null); + const options: Highcharts.Options = useMemo(() => { + return { + title: { + text: '', + }, + xAxis: { + type: 'datetime', + labels: { + format: '{value:%b %y}', + style: { + fontSize: '10px', + color: '#434343', + }, + }, + gridLineColor: '#f5f5f5', + minorGridLineColor: '#f5f5f5', + lineColor: '#f5f5f5', + minorTickColor: '#f5f5f5', + tickColor: '#b3b3b3', + tickLength: 6, + tickPixelInterval: 180, + }, + yAxis: { + title: { + text: '', + }, + labels: { + style: { + fontSize: '10px', + color: '#434343', + }, + }, + }, + legend: { + enabled: false, + }, + series: [ + { + data: data, + }, + ], + chart: { + type: 'column', + height: '200px', + }, + plotOptions: { + column: { + pointPadding: 0, + borderWidth: 0, + allowPointSelect: true, + lineWidth: 4, + lineColor: { + linearGradient: { + x1: 0, + y1: 0, + x2: 0, + y2: 1, + }, + stops: [ + [0, 'rgba(250, 78, 14, 0.7)'], + [1, 'rgba(250, 78, 14, 1)'], + ], + }, + }, + area: { + marker: { + radius: 2, + }, + lineWidth: 2, + lineColor: { + linearGradient: { + x1: 0, + y1: 0, + x2: 0, + y2: 1, + }, + stops: [ + [0, 'rgba(250, 78, 14, 0.7)'], + [1, 'rgba(250, 78, 14, 1)'], + ], + }, + color: { + linearGradient: { + x1: 0, + y1: 0, + x2: 0, + y2: 1, + }, + stops: [ + [0, 'rgba(250, 78, 14, 0.2)'], + [1, 'rgba(250, 78, 14, 0.5)'], + ], + }, + states: { + hover: { + lineWidth: 4, + }, + }, + threshold: null, + }, + }, + tooltip: { + formatter: function () { + //@ts-ignore + const _this = this as any; + return ( + '' + + dayjs.unix((_this.x / 1000) as any).format('ll') + + '
' + + formatCurrency(_this.y, 0, 2, 'BTC', true) + + '' + ); + } as any, + }, + } as unknown as Highcharts.Options; + }, [data]); + + return ( + + ); +}; + +export default ActiveAddressChart; diff --git a/src/modules/l2-rollup/AddressesEngagement/ActiveAddressPerChain.tsx b/src/modules/l2-rollup/AddressesEngagement/ActiveAddressPerChain.tsx new file mode 100644 index 000000000..589070145 --- /dev/null +++ b/src/modules/l2-rollup/AddressesEngagement/ActiveAddressPerChain.tsx @@ -0,0 +1,85 @@ +import { useMemo, useRef } from 'react'; + +import { formatCurrency } from '@/utils/format'; +// @ts-ignore +import CanvasJSReact from '@canvasjs/react-charts'; + +var CanvasJSChart = CanvasJSReact.CanvasJSChart; + +const ActiveAddressPerChain = ({ data = [] }: { data: any }) => { + const chartComponentRef = useRef(null); + const options: any = useMemo(() => { + return { + animationEnabled: true, + exportEnabled: false, + title: { + text: '', + }, + height: 200, + legend: { + reversed: true, + verticalAlign: 'center', + horizontalAlign: 'right', + }, + axisY: { + title: '', + includeZero: true, + gridColor: '#f5f5f5', + lineColor: '#f5f5f5', + labelFontSize: 10, + labelFontColor: '#434343', + tickColor: '#f5f5f5', + }, + axisX: { + lineColor: '#f5f5f5', + gridColor: '#f5f5f5', + labelFontSize: 10, + labelFontColor: '#434343', + tickColor: '#f5f5f5', + }, + toolTip: { + shared: true, + contentFormatter: function (e: any) { + const dataPoint = e.entries?.[0]?.dataPoint?.label; + let str = + '

' + + dataPoint + + '

'; + for (let i = 0; i < e.entries.length; i++) { + const entryData = e.entries[i]; + if (entryData.dataPoint.y) { + const temp = + '
' + + entryData.dataSeries.name + + ': ' + + formatCurrency(entryData.dataPoint.y, 0, 2, 'BTC', true) + + '
'; + str = str.concat(temp); + } + } + return str; + }, + }, + // legend: { + // verticalAlign: 'center', + // horizontalAlign: 'right', + // reversed: true, + // cursor: 'pointer', + // }, + data: data, + }; + }, [data]); + + return ( + (chartComponentRef.current = ref)} + /> + ); +}; + +export default ActiveAddressPerChain; diff --git a/src/modules/l2-rollup/AddressesEngagement/index.tsx b/src/modules/l2-rollup/AddressesEngagement/index.tsx new file mode 100644 index 000000000..39aa3b8d9 --- /dev/null +++ b/src/modules/l2-rollup/AddressesEngagement/index.tsx @@ -0,0 +1,169 @@ +import CRollupL2API from '@/services/api/dapp/rollupl2'; +import { + IActiveAddressChart, + IRollupL2Info, +} from '@/services/api/dapp/rollupl2/interface'; +import { compareString } from '@/utils/string'; +import { + Box, + Flex, + Tab, + TabList, + TabPanel, + TabPanels, + Tabs, + Text, +} from '@chakra-ui/react'; +import cs from 'classnames'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import ActiveAddressChart from './ActiveAddressChart'; +import ActiveAddressPerChain from './ActiveAddressPerChain'; +import s from './styles.module.scss'; +import dayjs from 'dayjs'; +import ActiveAddressChainPercent from './ActiveAddressChainPercent'; +import BigNumber from 'bignumber.js'; + +const DAY_FILTERS = [ + { + value: 90, + label: '90 days', + }, + { + value: 180, + label: '180 days', + }, + { + value: 360, + label: '1 year', + }, + { + value: -1, + label: 'Maximum', + }, +]; + +const AddressesEngagement = () => { + const rollupApi = useRef(new CRollupL2API()).current; + const [charts, setCharts] = useState([]); + const [rollupData, setRollupData] = useState([]); + const [day, setDay] = useState(DAY_FILTERS[0].value); + + useEffect(() => { + getData(); + }, []); + + const getData = async () => { + try { + const rs = await rollupApi.getActiveAddress1D(); + setCharts(rs.charts); + setRollupData(rs.rollup_datas); + } catch (error) {} + }; + + const reCharts: IActiveAddressChart[] = useMemo(() => { + let _charts: IActiveAddressChart[] = []; + if (charts.length > day) { + _charts = charts.slice(charts.length - day, charts.length); + } else { + _charts = charts; + } + return _charts as unknown as IActiveAddressChart[]; + }, [charts, day]); + + const activeAddresses = useMemo(() => { + return reCharts.map((c) => [c.timestamp * 1000, c.address_actived_day]); + }, [reCharts]); + + const activeAddressPerChain = useMemo(() => { + return rollupData.map((c) => { + return { + type: 'stackedColumn', + name: c.name, + showInLegend: true, + yValueFormatString: '#,###', + dataPoints: reCharts.map((v) => ({ + label: dayjs.unix(v.timestamp).format('DD MMM, YY'), + y: v.chain_charts.find((_v) => compareString(_v.rollup_data_id, c.id)) + ?.address_actived_day, + })), + }; + }); + }, [reCharts, rollupData]); + + const activeAddressChainPercent = useMemo(() => { + return rollupData.map((c) => { + return { + type: 'stackedColumn100', + name: c.name, + showInLegend: true, + dataPoints: reCharts.map((v) => ({ + label: dayjs.unix(v.timestamp).format('DD MMM, YY'), + y: Number( + new BigNumber( + v.chain_charts.find((_v) => + compareString(_v.rollup_data_id, c.id), + )?.address_actived_day || 0, + ) + .dividedBy(v.address_actived_day) + .multipliedBy(100) + .toFixed(2), + ), + })), + }; + }); + }, [reCharts, rollupData]); + + return ( + <> + Layer 2 Daily Engagement + + Number of distinct addresses interacting with one or multiple Layer 2s + in a given day. + + + + + + Active Address + Active Address per Chain + Percentage + + + {DAY_FILTERS.map((d) => ( + setDay(d.value)} + > + {d.label} + + ))} + + + + + + + + + + + + + + + + + + ); +}; + +export default AddressesEngagement; diff --git a/src/modules/l2-rollup/AddressesEngagement/styles.module.scss b/src/modules/l2-rollup/AddressesEngagement/styles.module.scss new file mode 100644 index 000000000..b287dff00 --- /dev/null +++ b/src/modules/l2-rollup/AddressesEngagement/styles.module.scss @@ -0,0 +1,101 @@ +.title, +.desc { + color: white; +} +.title { + font-size: 20px; + font-weight: 800; +} + +.desc { + font-size: 12px; +} + +.chartWrapper { + background-color: #fff; + margin-top: 10px; + .filterWrapper { + background-color: #f5f5f5; + margin: 8px; + border-radius: 100px; + padding: 4px; + align-items: center; + cursor: pointer; + .btnFilter { + height: 100%; + justify-content: center; + align-items: center; + border-radius: 100px; + overflow: hidden; + padding: 6px 8px; + &.btnFilterActive { + background-color: #fff; + p { + opacity: 1; + } + } + p { + opacity: 0.7; + font-size: 10px; + } + &:hover { + p { + opacity: 1; + } + } + } + } + :global { + .highcharts-credits, + .canvasjs-chart-credit { + display: none !important; + } + .highcharts-point { + fill: rgba(250, 78, 14, 0.5); + &:hover { + fill: rgba(250, 78, 14, 1); + } + } + .tooltip-title { + font-size: 15px; + font-weight: 500; + display: block; + } + .tooltip-desc { + font-size: 14px; + font-weight: 700; + min-width: 100px; + display: block; + padding: 5px 0px; + } + .chakra-tabs { + padding: 12px 0px; + } + .chakra-tabs__tablist { + background-color: #f5f5f5; + margin: 8px; + border-radius: 100px; + overflow: hidden; + width: fit-content; + padding: 4px !important; + border: none; + + button { + margin-bottom: 0px !important; + outline: none !important; + outline-offset: 0px !important; + border: none !important; + opacity: 0.7; + border-radius: 100px; + font-size: 10px; + padding: 6px 8px; + &[aria-selected='true'] { + background-color: #fff; + border: none; + color: #000; + opacity: 1; + } + } + } + } +} diff --git a/src/modules/l2-rollup/index.tsx b/src/modules/l2-rollup/index.tsx index d881081a1..b11909023 100644 --- a/src/modules/l2-rollup/index.tsx +++ b/src/modules/l2-rollup/index.tsx @@ -26,6 +26,11 @@ import { Text, Tooltip, useDisclosure, + Tab, + TabList, + TabPanel, + TabPanels, + Tabs, } from '@chakra-ui/react'; import orderBy from 'lodash/orderBy'; import { useEffect, useMemo, useRef, useState } from 'react'; @@ -39,6 +44,7 @@ import { isMobile } from 'react-device-detect'; import { DotLottiePlayer } from '@dotlottie/react-player'; import AnimArrowDown from './AnimArrowDown'; import PowerBox from '@/modules/l2-rollup/PowerBox'; +import AddressesEngagement from './AddressesEngagement'; enum SortRollupType { name, @@ -62,7 +68,7 @@ interface ISort { ascending?: boolean; } -const SEARCH_BAR_HEIGHT = 72; +const SEARCH_BAR_HEIGHT = 92; const L2Rollup = () => { const { showContactUsModal } = useContactUs(); @@ -83,7 +89,7 @@ const L2Rollup = () => { const rollupL2Api = new CRollupL2API(); const [currentSort, setCurrentSort] = useState({ - type: SortRollupType.level, + type: SortRollupType.tps, ascending: false, }); @@ -1051,7 +1057,7 @@ const L2Rollup = () => { { mt={isShowIntro ? 'calc(100dvh - 696px)' : 'calc(100dvh - 412px)'} > {isShowIntro && renderIntro()} - - setHoverTooltip(true)} - onMouseLeave={() => setHoverTooltip(false)} + + - {hoverTooltip && ( - - About project Bitcoin Heartbeats - - )} - setIsShowIntro(!isShowIntro)} - /> - - - Live Data + Analytics + + setHoverTooltip(true)} + onMouseLeave={() => setHoverTooltip(false)} + > + {hoverTooltip && ( + + About Heartbeats + + )} + setIsShowIntro(!isShowIntro)} + /> + + + + + + + - Transaction Count - {`Today Ξ${formatCurrency( - (_dataChart.txs?.[_dataChart.txs.length - 1] as any) - ?.y as any, - 0, - 2, - )}`} - - } - /> - - Bitcoin l2 Active addresses - - - - {`Ξ${formatCurrency( + {renderItemTotal( + 'TPS', + formatCurrency(total.tps, MIN_DECIMAL, MIN_DECIMAL), + 'The total transactions per second', + bitcoinRollup + ? `(${formatCurrency( + Math.abs(total.tps / bitcoinRollup.tps), + MIN_DECIMAL, + MIN_DECIMAL, + )}x)` + : '-', + )} + {renderItemTotal( + 'Mgas/s', + formatCurrency(total.mgas, MIN_DECIMAL, MIN_DECIMAL), + 'The total megagas (Million Gas) per second', + '', + )} + {renderItemTotal( + 'KB/s', + formatCurrency(total.kbs, MIN_DECIMAL, MIN_DECIMAL), + 'Total KB per second', + bitcoinRollup + ? `(${formatCurrency( + Math.abs(total.kbs / bitcoinRollup.kbs), + MIN_DECIMAL, + MIN_DECIMAL, + )}x)` + : '-', + )} + + + + {data.length <= 0 ? ( + + + + ) : ( + + )} + + + + + + + Transaction Count + {`Today Ξ${formatCurrency( + (_dataChart.txs?.[_dataChart.txs.length - 1] as any) + ?.y as any, + 0, + 2, + )}`} + + } + /> + + + Bitcoin l2 Active addresses + + + + + {`Ξ${formatCurrency( + ( + _dataChart.addresses?.[ + _dataChart.addresses.length - 1 + ] as any + )?.y as any, + 0, + 2, + )}`} + + + + + + + + + + } + /> + + Fees Paid by Users + {`Today $${formatCurrency( ( - _dataChart.addresses?.[ - _dataChart.addresses.length - 1 + _dataChart.fees?.[ + _dataChart.fees.length - 1 ] as any )?.y as any, 0, 2, - )}`} - - - - - - - - - - } - /> - - Fees Paid by Users - {`Today $${formatCurrency( - (_dataChart.fees?.[_dataChart.fees.length - 1] as any) - ?.y as any, - 0, - 2, - )}`} - - } - /> - - - - * This data has been collected from{' '} - {chainsSupportForChart.join(', ')} chains.{' '} - Rollux, Merlin, Core, and Stacks will be coming soon. - - - + )}`} + + } + /> + + + + * This data has been collected from{' '} + {chainsSupportForChart.join(', ')} chains.{' '} + + Rollux, Merlin, Core, and Stacks will be coming soon. + + + + + + + + + + - - - Total - - - {renderItemTotal( - 'TPS', - formatCurrency(total.tps, MIN_DECIMAL, MIN_DECIMAL), - 'The total transactions per second', - bitcoinRollup - ? `(${formatCurrency( - Math.abs(total.tps / bitcoinRollup.tps), - MIN_DECIMAL, - MIN_DECIMAL, - )}x)` - : '-', - )} - {renderItemTotal( - 'Mgas/s', - formatCurrency(total.mgas, MIN_DECIMAL, MIN_DECIMAL), - 'The total megagas (Million Gas) per second', - '', - )} - {renderItemTotal( - 'KB/s', - formatCurrency(total.kbs, MIN_DECIMAL, MIN_DECIMAL), - 'Total KB per second', - bitcoinRollup - ? `(${formatCurrency( - Math.abs(total.kbs / bitcoinRollup.kbs), - MIN_DECIMAL, - MIN_DECIMAL, - )}x)` - : '-', - )} - - - - {data.length <= 0 ? ( - - - - ) : ( - - )} - button { + background: none; + border: none; + color: gray; + font-weight: 500; + background: #f4f4f4; + font-size: 14px; + line-height: 20px; + padding-top: 8px; + padding-bottom: 8px; + + flex: unset; + position: relative; + text-align: center; + width: 150px; + + &[aria-selected='true'] { + opacity: 1; + font-weight: 600; + color: #fff !important; + background: linear-gradient(95.67deg, #ffc076 7.06%, #ff0000 92.21%); + } + } + } + + .tabPanel { + > [role='tabpanel'] { + padding: 0; + border-color: transparent !important; + } + border-color: transparent !important; + } } .search { diff --git a/src/services/api/dapp/index.ts b/src/services/api/dapp/index.ts index 5096061d4..fc89d3811 100644 --- a/src/services/api/dapp/index.ts +++ b/src/services/api/dapp/index.ts @@ -55,10 +55,18 @@ class CDappAPI { }) => { try { - if (compareString(params.appName, DappType.walletType)) { - return JSON.stringify(dappMockupData.find((item) => item?.key === DappType.walletType) || {}); + // token_generation + const mockupApp = dappMockupData.find((item) => ( + item?.key === params.appName || (params.appName === 'create_token' && item?.key === DappType.token_generation) + )); + if (mockupApp) { + return JSON.stringify(mockupApp); } + // if (compareString(params.appName, DappType.walletType)) { + // return JSON.stringify(dappMockupData.find((item) => item?.key === DappType.walletType) || {}); + // } + const app = (await this.http.get( `/apps/detail-by-code/${params.appName}?network_id=${params.network_id}&address=${params.address}`, )) as any; @@ -122,8 +130,8 @@ class CDappAPI { DappType.staking, DappType.airdrop, DappType.yologame, - DappType.orderbook, DappType.walletType, + DappType.white_paper, ].map((app) => this.getDappConfig({ appName: app, diff --git a/src/services/api/dapp/rollupl2-detail-bitcoin/index.ts b/src/services/api/dapp/rollupl2-detail-bitcoin/index.ts index c5c3baa7e..32c4f28e6 100644 --- a/src/services/api/dapp/rollupl2-detail-bitcoin/index.ts +++ b/src/services/api/dapp/rollupl2-detail-bitcoin/index.ts @@ -5,6 +5,7 @@ import { IBitcoinTokenTransaction, ITxBTC, ISummaryInfo, + IFBitcoinTransaction, } from './interface'; class CRollupL2DetailBitcoinAPI extends CDappApiClient { @@ -51,6 +52,19 @@ class CRollupL2DetailBitcoinAPI extends CDappApiClient { } }; + getRollupL2FractalBitcoinTokenTransactions = async ( + params: any, + ): Promise => { + try { + const rs: any = await this.api.get( + `/explorer/transaction-list/${params.user_address}?after_hash=${params.after_hash}&type=${params.type}`, + ); + return rs; + } catch (error) { + return []; + } + }; + getRollupL2BitcoinSummary = async ( user_address: string, params: any, diff --git a/src/services/api/dapp/rollupl2-detail-bitcoin/interface.ts b/src/services/api/dapp/rollupl2-detail-bitcoin/interface.ts index 6a735ea1f..7815e1c36 100644 --- a/src/services/api/dapp/rollupl2-detail-bitcoin/interface.ts +++ b/src/services/api/dapp/rollupl2-detail-bitcoin/interface.ts @@ -1,4 +1,5 @@ export type BalanceBitcoinType = + | 'fractal' | 'runes' | 'brc20' | 'src20' @@ -56,6 +57,12 @@ export interface IBalanceBitcoinInfo { transaction_count: string; first_transaction_time: string; last_transaction_time: string; + fractal?: { + funded_txo_sum: number; + funded_txo_count: number; + spent_txo_count: number; + tx_count: number; + }; } export interface IBitcoinTokenTransaction { @@ -102,6 +109,7 @@ export interface ITxBTC { virtual_size: string; weight: string; token_transfer: ITxBTCTokenTransfer[]; + chain?: string; } export interface ITxBTCPutDetail { @@ -129,3 +137,45 @@ export interface ITxBTCTokenTransfer { symbol: string; output_index: string; } + +export interface IFBitcoinTransaction { + txid: string; + size: number; + weight: number; + fee: number; + vin: IFBTxVin[]; + vout: IFBTxVout[]; + status: IFBTxStatus; + order: number; + vsize: number; + adjustedVsize: number; + sigops: number; + feePerVsize: number; + adjustedFeePerVsize: number; + effectiveFeePerVsize: number; +} + +export interface IFBTxStatus { + confirmed: boolean; + block_height: number; + block_hash: string; + block_time: number; +} + +export interface IFBTxVin { + is_coinbase: boolean; + prevout: IFBTxVout; + scriptsig: string; + scriptsig_asm: string; + sequence: number; + vout: number; + txid: string; +} + +export interface IFBTxVout { + value: number; + scriptpubkey: string; + scriptpubkey_address: string; + scriptpubkey_asm: string; + scriptpubkey_type: string; +} diff --git a/src/services/api/dapp/rollupl2/index.ts b/src/services/api/dapp/rollupl2/index.ts index 2e8c3c858..f86167101 100644 --- a/src/services/api/dapp/rollupl2/index.ts +++ b/src/services/api/dapp/rollupl2/index.ts @@ -1,5 +1,9 @@ import CDappApiClient from '../dapp.client'; -import { IRollupChart1D, IRollupL2Info } from './interface'; +import { + IRollupActiveAddressChart1D, + IRollupChart1D, + IRollupL2Info, +} from './interface'; class CRollupL2API extends CDappApiClient { getRollupL2Info = async (): Promise => { @@ -18,6 +22,17 @@ class CRollupL2API extends CDappApiClient { return []; } }; + getActiveAddress1D = async (): Promise => { + try { + const rs: any = await this.api.get('rollup/active-address-chart-1d'); + return rs; + } catch (error) { + return { + rollup_datas: [], + charts: [], + }; + } + }; } export default CRollupL2API; diff --git a/src/services/api/dapp/rollupl2/interface.ts b/src/services/api/dapp/rollupl2/interface.ts index 86eba90a2..6dcade6d4 100644 --- a/src/services/api/dapp/rollupl2/interface.ts +++ b/src/services/api/dapp/rollupl2/interface.ts @@ -1,4 +1,5 @@ export interface IRollupL2Info { + id: number; name: string; block_number: number; block_time: string; @@ -30,3 +31,20 @@ export interface IRollupChart1D { address_actived: number; notes: string; } + +export interface IRollupActiveAddressChart1D { + rollup_datas: IRollupL2Info[]; + charts: IActiveAddressChart[]; +} + +export interface IActiveAddressChart { + timestamp: number; + address_actived_day: number; + chain_charts: IChainChart[]; +} + +export interface IChainChart { + rollup_data_id: number; + timestamp: number; + address_actived_day: number; +} diff --git a/src/services/api/dapp/token_generation/interface.ts b/src/services/api/dapp/token_generation/interface.ts index 57f1fda42..3942b7225 100644 --- a/src/services/api/dapp/token_generation/interface.ts +++ b/src/services/api/dapp/token_generation/interface.ts @@ -17,6 +17,7 @@ export interface IToken extends IPosition { decimals?: number; total_supply?: string; user_created?: boolean; + is_native?: boolean; vestings?: ITokenVesting[]; } diff --git a/src/services/api/dapp/types.ts b/src/services/api/dapp/types.ts index 8d184b62e..dbb230aaf 100644 --- a/src/services/api/dapp/types.ts +++ b/src/services/api/dapp/types.ts @@ -60,4 +60,4 @@ export interface IAppInfo { image_url: string } -export type AppCode = 'create_token' | 'staking' | 'account_abstraction' | 'btc_bridge' | 'eth_bridge' | 'airdrop' | 'yologame' | 'orderbook'; +export type AppCode = 'create_token' | 'staking' | 'account_abstraction' | 'btc_bridge' | 'eth_bridge' | 'airdrop' | 'yologame' | 'white_paper'; diff --git a/src/services/api/dapp/whitePapers/index.ts b/src/services/api/dapp/whitePapers/index.ts new file mode 100644 index 000000000..e50a1497d --- /dev/null +++ b/src/services/api/dapp/whitePapers/index.ts @@ -0,0 +1,34 @@ +import CDappApiClient from '@/services/api/dapp/dapp.client'; +import { setWhitePapers } from '@/stores/states/dapp/reducer'; +import { useAppDispatch } from '@/stores/hooks'; +import { IWhitePaper } from '@/services/api/dapp/whitePapers/interface'; + +class CWhitePaperAPI { + private api = new CDappApiClient().api; + private dispatch = useAppDispatch(); + + private getUrl = (url: string) => { + return `/tokens/whitepaper/${url}`; + }; + + createWhitePaper = async (token_address: string, data: any): Promise => { + return await this.api.post(this.getUrl(`${token_address}`), data); + }; + + getWhitePaperList = async (): Promise => { + const data: any = await this.api.get(this.getUrl('list'), ); + this.dispatch(setWhitePapers(data)); + return data; + }; + + reCreateWhitePaper = async (token_address: string): Promise => { + return await this.api.post(this.getUrl(`refresh/${token_address}`), {}); + }; + + getWhitePaperDetail = async (id: string): Promise => { + const data: any = await this.api.get(this.getUrl(`detail/${id}`)); + return data; + }; +} + +export default CWhitePaperAPI; diff --git a/src/services/api/dapp/whitePapers/interface.ts b/src/services/api/dapp/whitePapers/interface.ts new file mode 100644 index 000000000..b0cf41fb6 --- /dev/null +++ b/src/services/api/dapp/whitePapers/interface.ts @@ -0,0 +1,12 @@ +import { IPosition } from '@/services/api/dapp/staking/interface'; +import { IToken } from '@/services/api/dapp/token_generation/interface'; + +export interface IWhitePaper extends IPosition { + id: number + network_id: number + contract_address: string + token_id: number + white_paper: string + token: IToken + status: string; +} diff --git a/src/services/api/mempool/index.ts b/src/services/api/mempool/index.ts index 320cba6d0..6e29e23a7 100644 --- a/src/services/api/mempool/index.ts +++ b/src/services/api/mempool/index.ts @@ -1,8 +1,13 @@ import { Axios, AxiosError, AxiosResponse } from 'axios'; -import { IMempoolBlock, IMempoolTransactionStatus } from './interface'; +import { + IMempoolBlock, + IMempoolMining, + IMempoolTransactionStatus, +} from './interface'; class CMempoolApi { #api = new Axios({ baseURL: 'https://mempool.space/api' }); + #apiFB = new Axios({ baseURL: 'https://mempool.fractalbitcoin.io/api' }); constructor() { this.#api.interceptors.request.use( @@ -14,6 +19,15 @@ class CMempoolApi { }, ); + this.#apiFB.interceptors.request.use( + (config: any) => { + return config; + }, + (error: AxiosError) => { + Promise.reject(error); + }, + ); + this.#api.interceptors.response.use( (res: AxiosResponse) => { let result = res?.data || res?.data?.result; @@ -40,13 +54,41 @@ class CMempoolApi { } }, ); + + this.#apiFB.interceptors.response.use( + (res: AxiosResponse) => { + let result = res?.data || res?.data?.result; + const error = res?.data?.error; + if (error) { + return Promise.reject(error); + } + if (res?.data?.count !== undefined) { + result = { + rows: result, + count: res?.data?.count, + }; + } + return Promise.resolve(JSON.parse(result)); + }, + (error: any) => { + if (!error.response) { + return Promise.reject(error); + } else { + const response = error?.response?.data || error; + const errorMessage = + response?.error || error?.Message || JSON.stringify(error); + return Promise.reject(errorMessage); + } + }, + ); } - getBlocks = async (): Promise => { + getBlocks = async (isFBTxAddress?: boolean): Promise => { try { - const rs: IMempoolBlock[] = await this.#api.get( - '/v1/fees/mempool-blocks', - ); + const rs: IMempoolBlock[] = await (isFBTxAddress + ? this.#apiFB + : this.#api + ).get('/v1/fees/mempool-blocks'); return rs || []; } catch (error) { @@ -54,13 +96,19 @@ class CMempoolApi { } }; - getTransactionTime = async (txHash: string): Promise => { + getTransactionTime = async ( + txHash: string, + isFBTxAddress?: boolean, + ): Promise => { try { - const rs: any = await this.#api.get('/v1/transaction-times', { - params: { - 'txId[]': txHash, + const rs: any = await (isFBTxAddress ? this.#apiFB : this.#api).get( + '/v1/transaction-times', + { + params: { + 'txId[]': txHash, + }, }, - }); + ); return rs || []; } catch (error) { @@ -70,9 +118,22 @@ class CMempoolApi { getTransactionStatus = async ( txHash: string, + isFBTxAddress?: boolean, ): Promise => { try { - const rs: any = await this.#api.get(`/tx/${txHash}/status`); + const rs: any = await (isFBTxAddress ? this.#apiFB : this.#api).get( + `/tx/${txHash}/status`, + ); + + return rs; + } catch (error) { + return undefined; + } + }; + + getFBMiningPool = async (): Promise => { + try { + const rs: any = await this.#apiFB.get(`v1/mining/pools/1w`); return rs; } catch (error) { diff --git a/src/services/api/mempool/interface.ts b/src/services/api/mempool/interface.ts index 60ebd5b95..1018e37df 100644 --- a/src/services/api/mempool/interface.ts +++ b/src/services/api/mempool/interface.ts @@ -13,3 +13,8 @@ export interface IMempoolTransactionStatus { block_hash: string; block_time: number; } + +export interface IMempoolMining { + blockCount: number; + lastEstimatedHashrate: number; +} diff --git a/src/stores/reducer.ts b/src/stores/reducer.ts index b5a6ff948..584ef8cfa 100644 --- a/src/stores/reducer.ts +++ b/src/stores/reducer.ts @@ -12,6 +12,7 @@ import launchpad from '@/modules/Launchpad/store/reducer'; import lpEAIPayment from '@/modules/Launchpad/store/lpEAIPayment/reducer'; import referrals from '@/stores/states/referrals/reducer'; import dapp from '@/stores/states/dapp/reducer'; +import daServices from '@/stores/states/daServices/reducer'; export default { common, @@ -27,4 +28,5 @@ export default { lpEAIPayment, referrals, dapp, + daServices, }; diff --git a/src/stores/states/daServices/actions.ts b/src/stores/states/daServices/actions.ts new file mode 100644 index 000000000..535bf20b7 --- /dev/null +++ b/src/stores/states/daServices/actions.ts @@ -0,0 +1,27 @@ +import { DAServiceAPI } from '@/services/api/clients'; +import { IToken } from '@/services/api/dapp/token_generation/interface'; +import { createAsyncThunk } from '@reduxjs/toolkit'; +import { PREFIX } from './constants'; + +const fetchIssueTokenListByChainID = createAsyncThunk( + `${PREFIX}/fetchIssueTokenList`, + async (networkID: string | number, { getState }) => { + let tokenIssueList: IToken[] = []; + try { + tokenIssueList = await DAServiceAPI.get( + `/tokens/list?network_id=${networkID}`, + ); + } catch (error) { + // console.log('[getListIssueTokenByNetworkID] ERROR: ', error); + tokenIssueList = []; + } finally { + // console.log( + // '[fetchIssueTokenListByChainID] FINALLY - tokenIssueList : ', + // tokenIssueList, + // ); + return tokenIssueList; + } + }, +); + +export { fetchIssueTokenListByChainID }; diff --git a/src/stores/states/daServices/constants.ts b/src/stores/states/daServices/constants.ts new file mode 100644 index 000000000..4a9d0ea45 --- /dev/null +++ b/src/stores/states/daServices/constants.ts @@ -0,0 +1 @@ +export const PREFIX = 'daServices'; diff --git a/src/stores/states/daServices/reducer.ts b/src/stores/states/daServices/reducer.ts new file mode 100644 index 000000000..695101d50 --- /dev/null +++ b/src/stores/states/daServices/reducer.ts @@ -0,0 +1,42 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { fetchIssueTokenListByChainID } from './actions'; +import { PREFIX } from './constants'; + +import { IDAService } from './types'; + +export const initialState: IDAService = { + isIssueTokenListFetched: false, + isIssueTokenListFetching: false, + issueTokenList: [], +}; + +const slice = createSlice({ + name: PREFIX, + initialState, + reducers: { + setABC(state, action: PayloadAction) { + state.abc = action.payload; + }, + }, + + extraReducers: (builder) => { + builder + .addCase(fetchIssueTokenListByChainID.pending, (state) => { + state.isIssueTokenListFetching = true; + }) + .addCase(fetchIssueTokenListByChainID.fulfilled, (state, action) => { + state.isIssueTokenListFetching = false; + state.isIssueTokenListFetched = true; + state.issueTokenList = action.payload; + }) + .addCase(fetchIssueTokenListByChainID.rejected, (state, _) => { + state.isIssueTokenListFetching = false; + state.isIssueTokenListFetched = true; + state.issueTokenList = []; + }); + }, +}); + +export const { setABC } = slice.actions; + +export default slice.reducer; diff --git a/src/stores/states/daServices/selector.ts b/src/stores/states/daServices/selector.ts new file mode 100644 index 000000000..48e1f9004 --- /dev/null +++ b/src/stores/states/daServices/selector.ts @@ -0,0 +1,11 @@ +import { RootState } from '@/stores'; +import { createSelector } from '@reduxjs/toolkit'; + +const getDaServicesSelector = (state: RootState) => state.daServices; + +const getIsssueTokenListSelector = createSelector( + getDaServicesSelector, + (reducer) => reducer.issueTokenList, +); + +export { getDaServicesSelector, getIsssueTokenListSelector }; diff --git a/src/stores/states/daServices/types.ts b/src/stores/states/daServices/types.ts new file mode 100644 index 000000000..16563b22d --- /dev/null +++ b/src/stores/states/daServices/types.ts @@ -0,0 +1,9 @@ +import { IToken } from '@/services/api/dapp/token_generation/interface'; + +export interface IDAService { + abc?: any; + + isIssueTokenListFetched: boolean; + isIssueTokenListFetching: boolean; + issueTokenList: IToken[]; +} diff --git a/src/stores/states/dapp/reducer.ts b/src/stores/states/dapp/reducer.ts index e5608417e..93d101189 100644 --- a/src/stores/states/dapp/reducer.ts +++ b/src/stores/states/dapp/reducer.ts @@ -14,6 +14,7 @@ const initialState: DappState = { yoloGames: [], tokensAll: [], walletType: undefined, + whitePapers: [], }; const slice = createSlice({ @@ -56,6 +57,9 @@ const slice = createSlice({ setWalletType: (state, actions) => { state.walletType = actions.payload; }, + setWhitePapers: (state, actions) => { + state.whitePapers = actions.payload; + }, }, }); @@ -72,6 +76,7 @@ export const { setYoloGames, setTokensAll, setWalletType, + setWhitePapers, } = slice.actions; export default slice.reducer; diff --git a/src/stores/states/dapp/types.ts b/src/stores/states/dapp/types.ts index cbe35fe4f..5db2be240 100644 --- a/src/stores/states/dapp/types.ts +++ b/src/stores/states/dapp/types.ts @@ -5,6 +5,7 @@ import { IAirdrop, IAirdropTask } from '@/services/api/dapp/airdrop/interface'; import { DappModel } from '@/types/customize-model'; import { IAppInfo, IDappConfigs } from '@/services/api/dapp/types'; import { IYoloGame } from '@/services/api/dapp/yolo/interface'; +import { IWhitePaper } from '@/services/api/dapp/whitePapers/interface'; export enum WalletType { naka = "naka", @@ -25,4 +26,5 @@ export interface DappState { yoloGames: IYoloGame[]; tokensAll: IToken[]; walletType?: WalletType; + whitePapers: IWhitePaper[]; } diff --git a/src/stores/states/l2services/reducer.ts b/src/stores/states/l2services/reducer.ts index 0339f4211..fef2bf1a3 100644 --- a/src/stores/states/l2services/reducer.ts +++ b/src/stores/states/l2services/reducer.ts @@ -1,30 +1,30 @@ +import { IDApp } from '@/services/api/DAServices/types'; +import { IModelOption } from '@/types/customize-model'; +import { compareString } from '@/utils/string'; import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import uniqBy from 'lodash/uniqBy'; import { - fetchAllOrders, - fetchOrderList, - orderBuy, fetchAccountInfo, - fetchL2ServiceHistory, - fetchAvailableList, + fetchAllOrders, fetchAllOrdersV2, - fetchDAList, - fetchTemplateV2, - fetchOrderDetailByID, + fetchAvailableList, fetchAvailableListTemplate, + fetchDAList, + fetchL2ServiceHistory, fetchModelCategories, + fetchOrderDetailByID, + fetchOrderList, + fetchTemplateV2, + orderBuy, } from './actions'; import { APP_BLOCKCHAIN, PREFIX } from './constants'; import { L2ServicesState, + MonitorViewPage, OrderItem, ViewMode, ViewPage, - MonitorViewPage, } from './types'; -import uniqBy from 'lodash/uniqBy'; -import { IDApp } from '@/services/api/DAServices/types'; -import { IModelOption } from '@/types/customize-model'; -import { compareString } from '@/utils/string'; export const initialState: L2ServicesState = { isMyOrderListFetched: false, @@ -80,6 +80,8 @@ export const initialState: L2ServicesState = { isAvailableListTemplateFetching: false, isAvailableListTemplateFetched: false, availableListTemplate: undefined, + dAppParam: null, + templateParam: '0', // isModelCategoriesFetching: false, @@ -98,6 +100,12 @@ const slice = createSlice({ setViewMode(state, action: PayloadAction) { state.viewMode = action.payload; }, + setDAppParam(state, action: PayloadAction) { + state.dAppParam = action.payload; + }, + setTemplateParam(state, action: PayloadAction) { + state.templateParam = action.payload; + }, setL2ServiceAuth(state, action: PayloadAction) { state.isL2ServiceLogged = action.payload; }, @@ -322,6 +330,8 @@ const slice = createSlice({ }); export const { + setDAppParam, + setTemplateParam, setOrderSelected, resetOrders, setViewMode, @@ -335,6 +345,6 @@ export const { setDAppSelected, setDAppConfigSelected, setOpenWatchList, - updateWatchLists + updateWatchLists, } = slice.actions; export default slice.reducer; diff --git a/src/stores/states/l2services/selector.ts b/src/stores/states/l2services/selector.ts index f8e85f3da..1245f032d 100644 --- a/src/stores/states/l2services/selector.ts +++ b/src/stores/states/l2services/selector.ts @@ -1,21 +1,28 @@ -import { createSelector } from '@reduxjs/toolkit'; -import { OrderItem, L2ServicesState } from './types'; -import BigNumber from 'bignumber.js'; -import { RootState } from '@/stores'; -import formatter from '@/modules/price/Pricing.helper'; import { NetworkEnum, RollupEnum, } from '@/modules/blockchains/Buy/Buy.constanst'; +import formatter from '@/modules/price/Pricing.helper'; import { PRICING_PACKGE } from '@/modules/PricingV2/constants'; import { IExploreItem } from '@/services/api/l2services/types'; -import { - APP_AIRDROP, - APP_BLOCKCHAIN, - APP_STAKING, - APP_TOKEN_GERNERATION, -} from './constants'; +import { RootState } from '@/stores'; import { IModelOption } from '@/types/customize-model'; +import { createSelector } from '@reduxjs/toolkit'; +import BigNumber from 'bignumber.js'; +import { APP_BLOCKCHAIN } from './constants'; +import { L2ServicesState, OrderItem } from './types'; + +const BLACKLIST_CATEGORY_BY_TEMPLATE_PARAM_MAPPER: Record = { + '4': ['bridge_apps'], + '5': ['tools'], +}; + +const BLACKLIST_CATEGORY_BY_DAPP_PARAM_MAPPER: Record = { + token_generation: ['tools', 'bridge_apps'], + staking: ['tools', 'bridge_apps'], + airdrop: ['tools', 'bridge_apps'], + yologame: ['tools', 'bridge_apps'], +}; const getL2ServicesStateSelector = (state: RootState): L2ServicesState => state.l2Services; @@ -334,9 +341,29 @@ const getAvailableListTemplateSelector = createSelector( getL2ServicesStateSelector, (state) => { const availableListTemplate = state.availableListTemplate || []; + const param = state.dAppParam || state.templateParam; + console.log('[getAvailableListTemplateSelector] param', param); //Sort - const result = availableListTemplate; + let result = availableListTemplate; + + // if (param in BLACKLIST_CATEGORY_BY_TEMPLATE_PARAM_MAPPER) { + // result = [...result]; + // result[Number(param)] = result[Number(param)]?.filter((item) => { + // return !BLACKLIST_CATEGORY_BY_TEMPLATE_PARAM_MAPPER[param].includes( + // item.key, + // ); + // }); + // } else + + if (param in BLACKLIST_CATEGORY_BY_DAPP_PARAM_MAPPER) { + result = [...result]; + result[0] = result[0]?.filter((item) => { + return !BLACKLIST_CATEGORY_BY_DAPP_PARAM_MAPPER[param].includes( + item.key, + ); + }); + } return result; }, @@ -355,40 +382,34 @@ const getModelCategoriesSelector = createSelector( ); export { + accountInforSelector, + allOrdersSelector, + // + getAvailableListTemplateSelector, + getDADetailByIDSelector, + getDAListSelector, + getDappByAppNameIDSelector, + // + getDAppConfigByKeySelector, + //Dapp + getDappSelectedSelector, getL2ServicesStateSelector, - orderListSelector, - orderSelectedSelector, - withdrawableRewardSelector, + getModelCategoriesSelector, getOrderByIDSelector, - allOrdersSelector, + //Detail + getOrderDetailSelected, historyInfoSelector, + myOrderListFilteredByNetwork, myOrderListSelector, - accountInforSelector, - packageDataSelector, - packageDetailByPackageEnumSelector, myOrderListWithNetworkSelector, - myOrderListFilteredByNetwork, - - //Monitor - ZKOrdersSelector, OPOrdersSelector, - - //Dapp - getDappSelectedSelector, - getDAListSelector, - getDADetailByIDSelector, - + orderListSelector, + orderSelectedSelector, + packageDataSelector, + packageDetailByPackageEnumSelector, //Template templateV2Selector, - - //Detail - getOrderDetailSelected, - - // - getAvailableListTemplateSelector, - getModelCategoriesSelector, - - // - getDAppConfigByKeySelector, - getDappByAppNameIDSelector, + withdrawableRewardSelector, + //Monitor + ZKOrdersSelector, }; diff --git a/src/stores/states/l2services/types.ts b/src/stores/states/l2services/types.ts index 8128f9aa3..e3fdf7e65 100644 --- a/src/stores/states/l2services/types.ts +++ b/src/stores/states/l2services/types.ts @@ -318,6 +318,7 @@ interface IVerifyEmail { type ViewMode = 'Mainnet' | 'Testnet'; type ViewPage = 'Biiling' | 'ManageChains'; type MonitorViewPage = 'OP' | 'ZK'; +type DappParam = 'token_generation' | 'staking' | 'airdrop'; interface L2ServicesState { //My Order List @@ -370,7 +371,8 @@ interface L2ServicesState { isAvailableListTemplateFetching: boolean; isAvailableListTemplateFetched: boolean; availableListTemplate?: [IModelCategory[]]; - + dAppParam: DappParam | null; + templateParam: string; isModelCategoriesFetching: boolean; isModelCategoriesFetched: boolean; modelCategories?: IModelCategory[]; @@ -408,31 +410,32 @@ type WebsiteConfig = { }; export type { - IVerifySignatureReq, - IVerifySignatureResp, - IVerifyTokenReq, - IVerifyTokenResp, + AccountInfo, + AccountInfoResp, + DappParam, + HistoryItemResp, + IDAppInstalled, IGetNonceReq, IGetNonceResp, - OrderItem, - OrderItemResp, - AccountInfoResp, - AccountInfo, + IOrderBuyEstimateRespone, IOrderBuyReq, - IWithdrawFundReq, - HistoryItemResp, - IQuickStart, + IOrderBuyReq_V3, + IOrderUpdate, IPlugin, + IQuickStart, IVerifyEmail, - IOrderBuyEstimateRespone, + IVerifySignatureReq, + IVerifySignatureResp, + IVerifyTokenReq, + IVerifyTokenResp, + IWithdrawFundReq, L2ServicesState, - ViewMode, - ViewPage, MetaConfig, + MonitorViewPage, + OrderItem, + OrderItemResp, ThemeConfig, + ViewMode, + ViewPage, WebsiteConfig, - IOrderUpdate, - MonitorViewPage, - IOrderBuyReq_V3, - IDAppInstalled, }; diff --git a/src/styles/_global.scss b/src/styles/_global.scss index 4b812a764..17470996e 100644 --- a/src/styles/_global.scss +++ b/src/styles/_global.scss @@ -176,7 +176,7 @@ input[type='number'] { } .react-flow__handle { - position: unset !important; + //position: unset !important; background-color: #777777 !important; } @@ -214,4 +214,4 @@ input[type='number'] { .react-flow__edge-custom { pointer-events: none !important; -} \ No newline at end of file +} diff --git a/src/types/customize-model.d.ts b/src/types/customize-model.d.ts index a31e3d721..f324f030f 100644 --- a/src/types/customize-model.d.ts +++ b/src/types/customize-model.d.ts @@ -141,7 +141,7 @@ interface FieldModel { icon: string; title: string; value: string | number; - type: 'input' | 'dropdown' | 'extends' | 'group' | 'datetime' | 'list' | ''; + type: 'input' | 'dropdown' | 'extends' | 'group' | 'datetime' | 'list' | 'label_value' | 'button' | ''; tooltip: string; options: FieldModel[]; placeholder?: string; @@ -149,7 +149,7 @@ interface FieldModel { selectable?: boolean; background?: string; previewTitle?: string; - inputType?: 'text' | 'number' | 'file'; + inputType?: 'text' | 'number' | 'file' | ''; inputAccept?: 'image/*' | '.csv'; disabled?: boolean; } diff --git a/src/types/node.d.ts b/src/types/node.d.ts index 341ec841e..2b0eb61e2 100644 --- a/src/types/node.d.ts +++ b/src/types/node.d.ts @@ -5,6 +5,8 @@ import { DappModel, IModelOption } from './customize-model'; type NodeHeadingProps = { title: string; + icon?: string; + iconOnClick?: () => void; status?: { message: string; color?: string; @@ -49,10 +51,12 @@ type NodeViewAndAction = { type NodeOverlayProps = NodeOnlyViewProps | NodeViewAndAction; type NodeProps = { + id: string; dapp?: DappModel; heading: NodeHeadingProps; content: NodeContentProps; notification?: NodeNotificationProps; + customNotification?: React.ReactNode; overlay?: NodeOverlayProps; mainContentStyles?: React.CSSProperties; borderColor?: string; diff --git a/src/utils/form-validate.ts b/src/utils/form-validate.ts index 7346ab200..a23965e4e 100644 --- a/src/utils/form-validate.ts +++ b/src/utils/form-validate.ts @@ -21,6 +21,13 @@ export const isValidBTCTxHash = (txHash: string) => { return regex.test(txHash); }; +export const isValidFractalBTCTxHash = (txHash: string) => { + const hexPattern = /^[a-fA-F0-9]+$/; + + // Check if the hash matches the hex pattern and has an even length (since hex is in pairs) + return hexPattern.test(txHash) && txHash.length % 2 === 0; +}; + export const isValidERC20TxHash = (txHash: string) => { // Check if txHash is a 64-character hexadecimal string const regex = /^0x([A-Fa-f0-9]{64})$/; diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index ab6fbc13a..c34bbed4f 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -262,39 +262,41 @@ export function isLocalhost() { function handleStatusEdgeByBox(status: any) { switch (status) { - case "draft": - case "setting_up": + case 'draft': + case 'setting_up': + case 'Drafting Modules': case EAirdropStatus.new: case '': //draft return { animate: true, icon: '', - } - // down - case "down": - case "run_out": + }; + // down + case 'down': + case 'run_out': case EAirdropStatus.ended: - case "stopped": + case 'stopped': return { animate: true, icon: 'true', - } - //run + }; + //run default: return { animate: false, icon: '', - } + }; } } -export default function handleStatusEdges(statusDapp: any, status: aa, idNode: string) { - if(idNode === 'account-abstraction' || idNode === 'bridge_apps') { - return handleStatusEdgeByBox(status) +export default function handleStatusEdges(statusDapp: any, status: aa | string, idNode: string) { + if (idNode === 'account_abstraction' || idNode === 'bridge_apps' || idNode === 'gaming_apps') { + console.log('status here', status, idNode); + return handleStatusEdgeByBox(status); } - return handleStatusEdgeByBox(statusDapp) + return handleStatusEdgeByBox(statusDapp); } -type aa = "draft" | "running" | "down" | 'setting_up' | EAirdropStatus +type aa = 'draft' | 'running' | 'down' | 'setting_up' | EAirdropStatus diff --git a/src/utils/time.ts b/src/utils/time.ts index ab86c9da1..588ae5ef0 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -1,5 +1,6 @@ import moment from 'moment'; import isNumber from 'lodash/isNumber'; +import dayjs from 'dayjs'; const FORMAT_PATTERN = 'DD MMM hh:mm A'; @@ -48,6 +49,10 @@ function getCurrentUnixTimestamp() { return Math.floor(Date.now() / 1000); } +function formatTimeAgo(time: number) { + return dayjs.unix(time).toNow().replaceAll('in ', '') + ' ago'; +} + export { formatUnixDateTime, formatDateTime, @@ -55,4 +60,5 @@ export { isExpiredTime, getCurrentUnixTimestamp, formatTimeStamp, + formatTimeAgo, }; diff --git a/yarn.lock b/yarn.lock index 9ca1f8c74..e8ae7b6c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1030,6 +1030,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.14.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2" + integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.24.7", "@babel/template@^7.3.3": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" @@ -4977,6 +4984,11 @@ dependencies: parchment "^1.1.2" +"@types/raf@^3.4.0": + version "3.4.3" + resolved "https://registry.yarnpkg.com/@types/raf/-/raf-3.4.3.tgz#85f1d1d17569b28b8db45e16e996407a56b0ab04" + integrity sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw== + "@types/react-datepicker@^6.2.0": version "6.2.0" resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-6.2.0.tgz#1c93c10d12d1d683eacf46a82e35b953cd0da117" @@ -6676,6 +6688,11 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +btoa@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" + integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== + buffer-compare@=1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-compare/-/buffer-compare-1.1.1.tgz#5be7be853af89198d1f4ddc090d1d66a48aef596" @@ -6833,6 +6850,20 @@ caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001629: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001632.tgz#964207b7cba5851701afb4c8afaf1448db3884b6" integrity sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg== +canvg@^3.0.6: + version "3.0.10" + resolved "https://registry.yarnpkg.com/canvg/-/canvg-3.0.10.tgz#8e52a2d088b6ffa23ac78970b2a9eebfae0ef4b3" + integrity sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q== + dependencies: + "@babel/runtime" "^7.12.5" + "@types/raf" "^3.4.0" + core-js "^3.8.3" + raf "^3.4.1" + regenerator-runtime "^0.13.7" + rgbcolor "^1.0.1" + stackblur-canvas "^2.0.0" + svg-pathdata "^6.0.3" + ccount@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" @@ -7255,6 +7286,11 @@ core-js@^3.27.2: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.1.tgz#d21751ddb756518ac5a00e4d66499df981a62db9" integrity sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw== +core-js@^3.6.0, core-js@^3.8.3: + version "3.38.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.38.1.tgz#aa375b79a286a670388a1a363363d53677c0383e" + integrity sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw== + cosmiconfig-typescript-loader@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz#0d3becfe022a871f7275ceb2397d692e06045dc8" @@ -7854,6 +7890,11 @@ domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" +dompurify@^2.2.0: + version "2.5.6" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.5.6.tgz#8402b501611eaa7fb3786072297fcbe2787f8592" + integrity sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ== + domutils@^3.0.1: version "3.1.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" @@ -8695,6 +8736,11 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fflate@^0.4.8: + version "0.4.8" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" + integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== + fflate@^0.6.9: version "0.6.10" resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.6.10.tgz#5f40f9659205936a2d18abf88b2e7781662b6d43" @@ -9544,7 +9590,7 @@ html-url-attributes@^3.0.0: resolved "https://registry.yarnpkg.com/html-url-attributes/-/html-url-attributes-3.0.0.tgz#fc4abf0c3fb437e2329c678b80abb3c62cff6f08" integrity sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow== -html2canvas@^1.4.1: +html2canvas@^1.0.0-rc.5, html2canvas@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543" integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA== @@ -10878,6 +10924,21 @@ jsontokens@^4.0.1: "@noble/secp256k1" "^1.6.3" base64-js "^1.5.1" +jspdf@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jspdf/-/jspdf-2.5.1.tgz#00c85250abf5447a05f3b32ab9935ab4a56592cc" + integrity sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA== + dependencies: + "@babel/runtime" "^7.14.0" + atob "^2.1.2" + btoa "^1.2.1" + fflate "^0.4.8" + optionalDependencies: + canvg "^3.0.6" + core-js "^3.6.0" + dompurify "^2.2.0" + html2canvas "^1.0.0-rc.5" + jss-plugin-camel-case@^10.10.0: version "10.10.0" resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz#27ea159bab67eb4837fa0260204eb7925d4daa1c" @@ -11367,6 +11428,11 @@ markdown-table@^3.0.0: resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.3.tgz#e6331d30e493127e031dd385488b5bd326e4a6bd" integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw== +marked@^14.1.0: + version "14.1.2" + resolved "https://registry.yarnpkg.com/marked/-/marked-14.1.2.tgz#3cbc26b2d6832be32b75ae0746e0968c781b6156" + integrity sha512-f3r0yqpz31VXiDB/wj9GaOB0a2PRLQl6vJmXiFrniNwjkKdvakqJRULhjFKJpxOchlCRiG5fcacoUZY5Xa6PEQ== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -12843,6 +12909,11 @@ pathe@^1.1.1, pathe@^1.1.2: resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + picocolors@^1.0.0, picocolors@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" @@ -13193,6 +13264,13 @@ radix3@^1.1.0: resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.2.tgz#fd27d2af3896c6bf4bcdfab6427c69c2afc69ec0" integrity sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA== +raf@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" + integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== + dependencies: + performance-now "^2.1.0" + ramda@0.21.0: version "0.21.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" @@ -13790,6 +13868,11 @@ regenerate@^1.4.2: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== +regenerator-runtime@^0.13.7: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + regenerator-runtime@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" @@ -14045,6 +14128,11 @@ rgb-hex@^3.0.0: resolved "https://registry.yarnpkg.com/rgb-hex/-/rgb-hex-3.0.0.tgz#eab0168cc1279563b18a14605315389142e2e487" integrity sha512-8h7ZcwxCBDKvchSWbWngJuSCqJGQ6nDuLLg+QcRyQDbX9jMWt+PpPeXAhSla0GOooEomk3lCprUpGkMdsLjKyg== +rgbcolor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgbcolor/-/rgbcolor-1.0.1.tgz#d6505ecdb304a6595da26fa4b43307306775945d" + integrity sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw== + rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -14625,6 +14713,11 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" +stackblur-canvas@^2.0.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz#af931277d0b5096df55e1f91c530043e066989b6" + integrity sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ== + stackframe@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" @@ -14937,6 +15030,11 @@ svg-parser@^2.0.4: resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== +svg-pathdata@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/svg-pathdata/-/svg-pathdata-6.0.3.tgz#80b0e0283b652ccbafb69ad4f8f73e8d3fbf2cac" + integrity sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw== + svg-react-loader@^0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/svg-react-loader/-/svg-react-loader-0.4.6.tgz#b263efb3e3d2fff4c682a729351aba5f185051a1"