From cbde610e47199f5a877a5228a1c7800d4619df1c Mon Sep 17 00:00:00 2001 From: AzizbekFayziyev Date: Sat, 6 Sep 2025 14:27:53 +0500 Subject: [PATCH 1/5] add: interactive guide --- package-lock.json | 140 +++++++- package.json | 1 + src/components/UI/GuideContent/index.tsx | 12 + src/components/UI/GuideContent/types.ts | 4 + src/components/UI/GuideTooltip/index.tsx | 37 ++ .../UI/GuideTooltip/styles.module.scss | 77 +++++ .../default/GuideRegistrator/index.tsx | 16 + .../LabeledInput/styles.module.scss | 6 +- src/components/dex/InputPanelItem/index.tsx | 14 +- .../dex/InputPanelItem/styles.module.scss | 3 +- src/components/dex/OrdersPool/index.tsx | 2 +- .../dex/OrdersPool/styles.module.scss | 2 +- .../components/DexGuide/index.tsx | 102 ++++++ src/components/dex/TradingHeader/index.tsx | 135 ++++---- .../dex/TradingHeader/styles.module.scss | 4 +- .../dex/UserOrders/cards/styles.module.scss | 326 +++++++++--------- src/components/dex/UserOrders/index.tsx | 2 +- .../dex/UserOrders/styles.module.scss | 6 +- src/pages/dex/trading/[id].tsx | 5 +- src/store/guide-provider.tsx | 191 ++++++++++ src/styles/Trading.module.scss | 3 +- src/styles/themes/dark.scss | 1 + src/styles/themes/light.scss | 1 + 23 files changed, 841 insertions(+), 249 deletions(-) create mode 100644 src/components/UI/GuideContent/index.tsx create mode 100644 src/components/UI/GuideContent/types.ts create mode 100644 src/components/UI/GuideTooltip/index.tsx create mode 100644 src/components/UI/GuideTooltip/styles.module.scss create mode 100644 src/components/default/GuideRegistrator/index.tsx create mode 100644 src/components/dex/TradingHeader/components/DexGuide/index.tsx create mode 100644 src/store/guide-provider.tsx diff --git a/package-lock.json b/package-lock.json index 1b906eb..97a328c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "react-apexcharts": "^1.5.0", "react-dom": "18.2.0", "react-intersection-observer": "^9.10.3", + "react-joyride": "^2.9.3", "sequelize": "^6.37.3", "sha256": "^0.2.0", "socket.io": "^4.6.1", @@ -2401,6 +2402,12 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@gilbarbara/deep-equal": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@gilbarbara/deep-equal/-/deep-equal-0.3.1.tgz", + "integrity": "sha512-I7xWjLs2YSVMc5gGx1Z3ZG1lgFpITPndpi8Ku55GeEIKpACCPQNS/OTqQbxgTCfq0Ncvcc+CrFov96itVh6Qvw==", + "license": "MIT" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -4223,7 +4230,6 @@ "version": "15.7.14", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", - "dev": true, "license": "MIT" }, "node_modules/@types/qs": { @@ -4244,7 +4250,6 @@ "version": "18.2.16", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.16.tgz", "integrity": "sha512-LLFWr12ZhBJ4YVw7neWLe6Pk7Ey5R9OCydfuMsz1L8bZxzaawJj2p06Q8/EFEHDeTBQNFLF62X+CG7B2zIyu0Q==", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -4266,7 +4271,6 @@ "version": "0.26.0", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.26.0.tgz", "integrity": "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==", - "dev": true, "license": "MIT" }, "node_modules/@types/semver": { @@ -6315,6 +6319,12 @@ "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "license": "MIT" }, + "node_modules/deep-diff": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz", + "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==", + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -6325,7 +6335,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8701,6 +8710,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-lite": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-lite/-/is-lite-1.2.1.tgz", + "integrity": "sha512-pgF+L5bxC+10hLBgf6R2P4ZZUBOQIIacbdo8YvuCP8/JvsWxG7aZ9p10DYuLtifFci4l3VITphhMlMV4Y+urPw==", + "license": "MIT" + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -10344,6 +10359,17 @@ "node": ">=12.13.0" } }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -11246,6 +11272,55 @@ "react": "^18.2.0" } }, + "node_modules/react-floater": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/react-floater/-/react-floater-0.7.9.tgz", + "integrity": "sha512-NXqyp9o8FAXOATOEo0ZpyaQ2KPb4cmPMXGWkx377QtJkIXHlHRAGer7ai0r0C1kG5gf+KJ6Gy+gdNIiosvSicg==", + "license": "MIT", + "dependencies": { + "deepmerge": "^4.3.1", + "is-lite": "^0.8.2", + "popper.js": "^1.16.0", + "prop-types": "^15.8.1", + "tree-changes": "^0.9.1" + }, + "peerDependencies": { + "react": "15 - 18", + "react-dom": "15 - 18" + } + }, + "node_modules/react-floater/node_modules/@gilbarbara/deep-equal": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@gilbarbara/deep-equal/-/deep-equal-0.1.2.tgz", + "integrity": "sha512-jk+qzItoEb0D0xSSmrKDDzf9sheQj/BAPxlgNxgmOaA3mxpUa6ndJLYGZKsJnIVEQSD8zcTbyILz7I0HcnBCRA==", + "license": "MIT" + }, + "node_modules/react-floater/node_modules/is-lite": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/is-lite/-/is-lite-0.8.2.tgz", + "integrity": "sha512-JZfH47qTsslwaAsqbMI3Q6HNNjUuq6Cmzzww50TdP5Esb6e1y2sK2UAaZZuzfAzpoI2AkxoPQapZdlDuP6Vlsw==", + "license": "MIT" + }, + "node_modules/react-floater/node_modules/tree-changes": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.9.3.tgz", + "integrity": "sha512-vvvS+O6kEeGRzMglTKbc19ltLWNtmNt1cpBoSYLj/iEcPVvpJasemKOlxBrmZaCtDJoF+4bwv3m01UKYi8mukQ==", + "license": "MIT", + "dependencies": { + "@gilbarbara/deep-equal": "^0.1.1", + "is-lite": "^0.8.2" + } + }, + "node_modules/react-innertext": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/react-innertext/-/react-innertext-1.1.5.tgz", + "integrity": "sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": ">=0.0.0 <=99", + "react": ">=0.0.0 <=99" + } + }, "node_modules/react-intersection-observer": { "version": "9.16.0", "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz", @@ -11267,6 +11342,41 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/react-joyride": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/react-joyride/-/react-joyride-2.9.3.tgz", + "integrity": "sha512-1+Mg34XK5zaqJ63eeBhqdbk7dlGCFp36FXwsEvgpjqrtyywX2C6h9vr3jgxP0bGHCw8Ilsp/nRDzNVq6HJ3rNw==", + "license": "MIT", + "dependencies": { + "@gilbarbara/deep-equal": "^0.3.1", + "deep-diff": "^1.0.2", + "deepmerge": "^4.3.1", + "is-lite": "^1.2.1", + "react-floater": "^0.7.9", + "react-innertext": "^1.1.5", + "react-is": "^16.13.1", + "scroll": "^3.0.1", + "scrollparent": "^2.1.0", + "tree-changes": "^0.11.2", + "type-fest": "^4.27.0" + }, + "peerDependencies": { + "react": "15 - 18", + "react-dom": "15 - 18" + } + }, + "node_modules/react-joyride/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/readable-stream": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", @@ -11739,6 +11849,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/scroll": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scroll/-/scroll-3.0.1.tgz", + "integrity": "sha512-pz7y517OVls1maEzlirKO5nPYle9AXsFzTMNJrRGmT951mzpIBy7sNHOg5o/0MQd/NqliCiWnAi0kZneMPFLcg==", + "license": "MIT" + }, "node_modules/scroll-into-view-if-needed": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", @@ -11748,6 +11864,12 @@ "compute-scroll-into-view": "^3.0.2" } }, + "node_modules/scrollparent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.1.0.tgz", + "integrity": "sha512-bnnvJL28/Rtz/kz2+4wpBjHzWoEzXhVg/TE8BeVGJHUqE8THNIRnDxDWMktwM+qahvlRdvlLdsQfYe+cuqfZeA==", + "license": "ISC" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -13015,6 +13137,16 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" }, + "node_modules/tree-changes": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.11.3.tgz", + "integrity": "sha512-r14mvDZ6tqz8PRQmlFKjhUVngu4VZ9d92ON3tp0EGpFBE6PAHOq8Bx8m8ahbNoGE3uI/npjYcJiqVydyOiYXag==", + "license": "MIT", + "dependencies": { + "@gilbarbara/deep-equal": "^0.3.1", + "is-lite": "^1.2.1" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", diff --git a/package.json b/package.json index 1a84a9b..61da024 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "react-apexcharts": "^1.5.0", "react-dom": "18.2.0", "react-intersection-observer": "^9.10.3", + "react-joyride": "^2.9.3", "sequelize": "^6.37.3", "sha256": "^0.2.0", "socket.io": "^4.6.1", diff --git a/src/components/UI/GuideContent/index.tsx b/src/components/UI/GuideContent/index.tsx new file mode 100644 index 0000000..5e3b92f --- /dev/null +++ b/src/components/UI/GuideContent/index.tsx @@ -0,0 +1,12 @@ +import { useEffect } from 'react'; +import { GuideContentProps } from './types'; + +function GuideContent({ onEnter, text }: GuideContentProps) { + useEffect(() => { + if (onEnter) onEnter(); + }, [onEnter]); + + return

{text}

; +} + +export default GuideContent; diff --git a/src/components/UI/GuideContent/types.ts b/src/components/UI/GuideContent/types.ts new file mode 100644 index 0000000..adf3d1f --- /dev/null +++ b/src/components/UI/GuideContent/types.ts @@ -0,0 +1,4 @@ +export interface GuideContentProps { + text: string; + onEnter?: () => void; +} diff --git a/src/components/UI/GuideTooltip/index.tsx b/src/components/UI/GuideTooltip/index.tsx new file mode 100644 index 0000000..caa01b1 --- /dev/null +++ b/src/components/UI/GuideTooltip/index.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import type { TooltipRenderProps } from 'react-joyride'; +import styles from './styles.module.scss'; +import Button from '../Button/Button'; + +export default function GuideTooltip({ + index, + size, + step, + primaryProps, + skipProps, + tooltipProps, + isLastStep, +}: TooltipRenderProps) { + return ( +
+
+
+ {index + 1}/{size} +
+
+ {typeof step.content === 'string' ?

{step.content}

: step.content} +
+ + +
+ + {!isLastStep && ( + + )} +
+ ); +} diff --git a/src/components/UI/GuideTooltip/styles.module.scss b/src/components/UI/GuideTooltip/styles.module.scss new file mode 100644 index 0000000..bc18efb --- /dev/null +++ b/src/components/UI/GuideTooltip/styles.module.scss @@ -0,0 +1,77 @@ +.tooltip { + transition: none !important; + width: 300px; + + &__body { + width: 100%; + text-align: center; + border-radius: 10px; + background-color: #fff; + padding: 15px; + display: flex; + flex-direction: column; + gap: 10px; + } + + &__index { + font-size: 20px; + font-weight: 600; + color: #0c0c3a; + line-height: 100%; + } + + &__content, + &__content p { + color: #0c0c3a; + font-size: 14px; + font-weight: 400; + line-height: 140%; + } + + &__btn { + padding: 13px; + font-size: 14px; + font-weight: 500; + line-height: 100%; + } + + &__skip { + margin-top: 8px; + width: 100%; + cursor: pointer; + font-size: 14px; + font-weight: 500; + line-height: 140%; + color: var(--guide-skip-btn); + background-color: transparent !important; + } +} + +@media screen and (max-width:620px) { + .tooltip { + width: 200px; + + &__body { + gap: 8px; + padding: 10px; + } + + &__content, + &__content p { + font-size: 12px; + } + + &__btn, + &__skip { + font-size: 12px; + } + + &__btn { + padding: 10px; + } + + &__index { + font-size: 16px; + } + } +} \ No newline at end of file diff --git a/src/components/default/GuideRegistrator/index.tsx b/src/components/default/GuideRegistrator/index.tsx new file mode 100644 index 0000000..8e96994 --- /dev/null +++ b/src/components/default/GuideRegistrator/index.tsx @@ -0,0 +1,16 @@ +import { useTour } from '@/store/guide-provider'; +import { useEffect } from 'react'; +import type { Step } from 'react-joyride'; + +type Props = { name: string; steps: Step[]; autoStartOnceVersion?: string }; + +export default function GuideRegistrator({ name, steps, autoStartOnceVersion }: Props) { + const { register, startOnce } = useTour(name); + + useEffect(() => { + register(name, steps); + if (autoStartOnceVersion) startOnce(autoStartOnceVersion); + }, [name, steps, register, startOnce, autoStartOnceVersion]); + + return <>; +} diff --git a/src/components/dex/InputPanelItem/components/LabeledInput/styles.module.scss b/src/components/dex/InputPanelItem/components/LabeledInput/styles.module.scss index ac2cefa..bc28171 100644 --- a/src/components/dex/InputPanelItem/components/LabeledInput/styles.module.scss +++ b/src/components/dex/InputPanelItem/components/LabeledInput/styles.module.scss @@ -48,7 +48,7 @@ align-items: center; justify-content: center; - >p { + > p { font-size: 14px; font-weight: 400; white-space: nowrap; @@ -76,9 +76,9 @@ &__currency { padding: 0 8px; - >p { + > p { font-size: 12px; } } } -} \ No newline at end of file +} diff --git a/src/components/dex/InputPanelItem/index.tsx b/src/components/dex/InputPanelItem/index.tsx index 58c2014..58f8dd8 100644 --- a/src/components/dex/InputPanelItem/index.tsx +++ b/src/components/dex/InputPanelItem/index.tsx @@ -50,9 +50,13 @@ function InputPanelItem(props: InputPanelItemProps) { const [hasImmediateMatch, setHasImmediateMatch] = useState(false); const isBuy = buySellState?.code === 'buy'; - function goToSuitableTab() { + function goToTab(name?: string) { const params = new URLSearchParams(searchParams.toString()); - params.set('tab', 'matches'); + if (name) { + params.set('tab', name); + } else { + params.delete('tab'); + } router.replace(`${pathname}?${params.toString()}`, undefined, { shallow: true, @@ -93,6 +97,8 @@ function InputPanelItem(props: InputPanelItemProps) { if (result.success) { if (result.data?.immediateMatch) { setHasImmediateMatch(true); + goToTab(); + scrollToOrderList(); } onAfter(); resetForm(); @@ -125,7 +131,7 @@ function InputPanelItem(props: InputPanelItemProps) { const isButtonDisabled = !priceValid || !amountValid || !totalValid || creatingState; return ( -
+
{hasImmediateMatch && ( { scrollToOrderList(); - goToSuitableTab(); + goToTab('matches'); setHasImmediateMatch(false); }} > diff --git a/src/components/dex/InputPanelItem/styles.module.scss b/src/components/dex/InputPanelItem/styles.module.scss index 5afa1e7..446f562 100644 --- a/src/components/dex/InputPanelItem/styles.module.scss +++ b/src/components/dex/InputPanelItem/styles.module.scss @@ -144,7 +144,6 @@ } } - @media screen and (max-width: 640px) { .inputPanel { padding: 0; @@ -195,4 +194,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/components/dex/OrdersPool/index.tsx b/src/components/dex/OrdersPool/index.tsx index 08670d5..f6e25ea 100644 --- a/src/components/dex/OrdersPool/index.tsx +++ b/src/components/dex/OrdersPool/index.tsx @@ -170,7 +170,7 @@ const OrdersPool = (props: OrdersPoolProps) => { useMouseLeave(ordersInfoRef, () => setOrdersInfoTooltip(null)); return ( <> -
+
diff --git a/src/components/dex/OrdersPool/styles.module.scss b/src/components/dex/OrdersPool/styles.module.scss index c160bdb..3803c6e 100644 --- a/src/components/dex/OrdersPool/styles.module.scss +++ b/src/components/dex/OrdersPool/styles.module.scss @@ -262,4 +262,4 @@ .tooltip { display: none; } -} \ No newline at end of file +} diff --git a/src/components/dex/TradingHeader/components/DexGuide/index.tsx b/src/components/dex/TradingHeader/components/DexGuide/index.tsx new file mode 100644 index 0000000..6dd75ed --- /dev/null +++ b/src/components/dex/TradingHeader/components/DexGuide/index.tsx @@ -0,0 +1,102 @@ +import GuideRegistrator from '@/components/default/GuideRegistrator'; +import GuideContent from '@/components/UI/GuideContent'; +import { useMediaQuery } from '@/hook/useMediaQuery'; +import { usePathname, useSearchParams } from 'next/navigation'; +import { useRouter } from 'next/router'; +import React from 'react'; +import { Placement, Step } from 'react-joyride'; + +const DexGuide = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const pathname = usePathname(); + const isMobile = useMediaQuery(`(max-width: 620px)`); + + const getPlacement = (position: 'auto' | Placement | 'center' | undefined) => { + if (isMobile) return 'auto'; + + return position; + }; + + const changeTab = (name?: string) => { + const params = new URLSearchParams(searchParams.toString()); + + if (name) { + params.set('tab', name); + } else { + params.delete('tab'); + } + + const qs = params.toString(); + router.replace(qs ? `${pathname}?${qs}` : pathname, undefined, { + shallow: true, + scroll: false, + }); + }; + + const steps: Step[] = [ + { + target: '[data-tour="orders-pool"]', + placement: getPlacement('right-start'), + content: ( + + ), + disableBeacon: true, + }, + { + target: '[data-tour="input-panel"]', + placement: getPlacement('left-start'), + content: ( + + ), + }, + { + target: '[data-tour="user-orders"]', + placement: getPlacement('top-start'), + content: ( + changeTab()} + text="This tab shows all of your active orders. You can track price, quantity, and cancel them anytime." + /> + ), + }, + { + target: '[data-tour="user-orders"]', + placement: getPlacement('top-start'), + content: ( + changeTab('matches')} + text="Here you see orders that have been successfully matched and executed." + /> + ), + }, + { + target: '[data-tour="user-orders"]', + placement: getPlacement('top-start'), + content: ( + changeTab('requests')} + text="This section lists your pending requests that are waiting for approval or fulfillment." + /> + ), + }, + { + target: '[data-tour="user-orders"]', + placement: getPlacement('top-start'), + content: ( + changeTab('offers')} + text="In this tab you can find offers you’ve made to other traders that are not yet matched." + /> + ), + }, + ]; + + return ( + <> + + + ); +}; + +export default DexGuide; diff --git a/src/components/dex/TradingHeader/index.tsx b/src/components/dex/TradingHeader/index.tsx index c740d8f..0924910 100644 --- a/src/components/dex/TradingHeader/index.tsx +++ b/src/components/dex/TradingHeader/index.tsx @@ -6,11 +6,13 @@ import BackButton from '@/components/default/BackButton/BackButton'; import { roundTo, notationToString, classes } from '@/utils/utils'; import questionIcon from '@/assets/images/UI/question.svg'; import Image from 'next/image'; +import { useTour } from '@/store/guide-provider'; import styles from './styles.module.scss'; import StatItem from './components/StatItem'; import { TradingHeaderProps } from './types'; import CurrencyIcon from './components/CurrencyIcon'; import AssetRow from './components/AssetRow'; +import DexGuide from './components/DexGuide'; const TradingHeader = ({ pairStats, @@ -21,6 +23,8 @@ const TradingHeader = ({ secondAssetId, pairData, }: TradingHeaderProps) => { + const { start, isRunning } = useTour('dex-onboarding'); + const currencyNames = { firstCurrencyName: pairData?.first_currency?.name || '', secondCurrencyName: pairData?.second_currency?.name || '', @@ -59,76 +63,85 @@ const TradingHeader = ({ ]; return ( -
-
-
-
- -
+ <> + +
+
+
+
+ +
-
-

- {!pairData ? ( - '...' - ) : ( - <> - {firstCurrencyName} - /{secondCurrencyName} - - )} -

- -
-

= 0 ? styles.green : styles.red, +

+

+ {!pairData ? ( + '...' + ) : ( + <> + {firstCurrencyName} + /{secondCurrencyName} + )} - > - {roundTo(notationToString(pairStats?.rate || 0, 8))}

- {pairRateUsd &&

~ ${pairRateUsd}

} + +
+

= 0 ? styles.green : styles.red, + )} + > + {roundTo(notationToString(pairStats?.rate || 0, 8))} +

+ {pairRateUsd && ( +

~ ${pairRateUsd}

+ )} +
+ + {pairData && firstAssetLink && secondAssetLink && ( +
+ + +
+ )} + + {stats.map(({ Img, title, value, coefficient }) => ( + + ))}
- {pairData && firstAssetLink && secondAssetLink && ( -
- - -
- )} +
+ - {stats.map(({ Img, title, value, coefficient }) => ( - - ))} + +
- -
- - - -
-
+ ); }; diff --git a/src/components/dex/TradingHeader/styles.module.scss b/src/components/dex/TradingHeader/styles.module.scss index 892de98..d0cd246 100644 --- a/src/components/dex/TradingHeader/styles.module.scss +++ b/src/components/dex/TradingHeader/styles.module.scss @@ -22,7 +22,7 @@ background-color: var(--icon-bg-color); border-radius: 50%; - >img { + > img { width: 24px; height: auto; } @@ -169,4 +169,4 @@ gap: 12px; } } -} \ No newline at end of file +} diff --git a/src/components/dex/UserOrders/cards/styles.module.scss b/src/components/dex/UserOrders/cards/styles.module.scss index 2293e5c..8919c89 100644 --- a/src/components/dex/UserOrders/cards/styles.module.scss +++ b/src/components/dex/UserOrders/cards/styles.module.scss @@ -1,206 +1,206 @@ .cards { - margin-top: 10px; - display: flex; - flex-direction: column; - gap: 10px; + margin-top: 10px; + display: flex; + flex-direction: column; + gap: 10px; - .card { - position: relative; - display: flex; - flex-direction: column; - gap: 15px; - padding: 6px 10px; + .card { + position: relative; + display: flex; + flex-direction: column; + gap: 15px; + padding: 6px 10px; - &::before { - content: ''; - position: absolute; - left: 0; - top: 0; - width: 2px; - height: 100%; - } + &::before { + content: ''; + position: absolute; + left: 0; + top: 0; + width: 2px; + height: 100%; + } - &.sell { - &::before { - background-color: #ff6767; - } + &.sell { + &::before { + background-color: #ff6767; + } - .card__type { - color: #ff6767; - text-transform: capitalize; - } - } + .card__type { + color: #ff6767; + text-transform: capitalize; + } + } - &.buy { - &::before { - background-color: #16d1d6; - } + &.buy { + &::before { + background-color: #16d1d6; + } - .card__type { - color: #16d1d6; - text-transform: capitalize; - } - } + .card__type { + color: #16d1d6; + text-transform: capitalize; + } + } - &__row { - width: 100%; - display: flex; - align-items: center; - gap: 40px; + &__row { + width: 100%; + display: flex; + align-items: center; + gap: 40px; - &.sm { - gap: 18px; + &.sm { + gap: 18px; - .card__col { - min-width: 50px; - } - } - } + .card__col { + min-width: 50px; + } + } + } - &__label { - color: var(--table-th-color); - font-size: 12px; - font-weight: 500; - line-height: 100%; - } + &__label { + color: var(--table-th-color); + font-size: 12px; + font-weight: 500; + line-height: 100%; + } - &__value { - font-size: 12px; - font-weight: 500; - line-height: 100%; + &__value { + font-size: 12px; + font-weight: 500; + line-height: 100%; - &.primary { - color: #1f8feb; - } + &.primary { + color: #1f8feb; + } - &.secondary { - color: var(--table-th-color); - } + &.secondary { + color: var(--table-th-color); + } - span { - color: var(--table-th-color); - font-size: 11px; - font-weight: 500; - line-height: 100%; - } - } + span { + color: var(--table-th-color); + font-size: 11px; + font-weight: 500; + line-height: 100%; + } + } - &__col { - min-width: 100px; - display: flex; - flex-direction: column; - gap: 10px; - } + &__col { + min-width: 100px; + display: flex; + flex-direction: column; + gap: 10px; + } - &__pair { - .card__value { - display: flex; - align-items: center; - gap: 8px; - } + &__pair { + .card__value { + display: flex; + align-items: center; + gap: 8px; + } - .card__type { - display: none; - } - } + .card__type { + display: none; + } + } - &__flex { - gap: 10px; - display: flex; - align-items: center; - justify-content: space-between; - } + &__flex { + gap: 10px; + display: flex; + align-items: center; + justify-content: space-between; + } - &__actions { - display: flex; - align-items: center; - gap: 4px; - margin-left: auto; - } - } + &__actions { + display: flex; + align-items: center; + gap: 4px; + margin-left: auto; + } + } - .mobile { - display: none; - } + .mobile { + display: none; + } } @media screen and (max-width: 640px) { - .cards .card { - gap: 10px; + .cards .card { + gap: 10px; - &__row { - gap: 15px; + &__row { + gap: 15px; - &.sm { - gap: 5px; - } - } + &.sm { + gap: 5px; + } + } - &__col { - min-width: 80px; + &__col { + min-width: 80px; - &_direction { - display: none; - } - } + &_direction { + display: none; + } + } - &__label { - font-size: 10px; - } + &__label { + font-size: 10px; + } - &__value { - font-size: 11px; - } + &__value { + font-size: 11px; + } - &__pair { - .card__label { - display: none; - } + &__pair { + .card__label { + display: none; + } - .card__value { - font-size: 12px; - } + .card__value { + font-size: 12px; + } - .card__type { - font-size: 12px; - display: inline-block; - } - } - } + .card__type { + font-size: 12px; + display: inline-block; + } + } + } } @media screen and (max-width: 500px) { - .cards .card { - &__row { - justify-content: space-between; + .cards .card { + &__row { + justify-content: space-between; - &.sm { - justify-content: flex-start; - } - } + &.sm { + justify-content: flex-start; + } + } - &__col { - min-width: auto; - } + &__col { + min-width: auto; + } - &__flex { - flex-direction: column; - } + &__flex { + flex-direction: column; + } - &__price { - display: none; + &__price { + display: none; - &.mobile { - display: flex; - } - } + &.mobile { + display: flex; + } + } - &__offers { - display: none; + &__offers { + display: none; - &.mobile { - display: flex; - } - } - } -} \ No newline at end of file + &.mobile { + display: flex; + } + } + } +} diff --git a/src/components/dex/UserOrders/index.tsx b/src/components/dex/UserOrders/index.tsx index 61e56df..89e1a9b 100644 --- a/src/components/dex/UserOrders/index.tsx +++ b/src/components/dex/UserOrders/index.tsx @@ -373,7 +373,7 @@ const UserOrders = ({ return ( <> -
+
p { + > p { width: 100%; font-size: 12px; font-weight: 400; @@ -76,7 +76,7 @@ } } - >span { + > span { line-height: 1; color: var(--font-dimmed-color); font-size: 11px; @@ -115,4 +115,4 @@ margin-bottom: 10px; } } -} \ No newline at end of file +} diff --git a/src/pages/dex/trading/[id].tsx b/src/pages/dex/trading/[id].tsx index e1fd5ba..5b28310 100644 --- a/src/pages/dex/trading/[id].tsx +++ b/src/pages/dex/trading/[id].tsx @@ -29,6 +29,7 @@ import useTradeInit from '@/hook/useTradeInit'; import useMatrixAddresses from '@/hook/useMatrixAddresses'; import takeOrderClick from '@/utils/takeOrderClick'; import useUpdateUser from '@/hook/useUpdateUser'; +import { GuideProvider } from '@/store/guide-provider'; function Trading() { const { alertState, alertSubtitle, setAlertState } = useAlert(); @@ -137,7 +138,7 @@ function Trading() { }; return ( - <> +
@@ -233,7 +234,7 @@ function Trading() { )}