diff --git a/.husky/pre-commit b/.husky/pre-commit index b1dd4d8a8e..19c3fa6e16 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,5 @@ yarn dlx lint-staged +yarn workspaces foreach --all -p run typecheck # Format python file changes cd packages/sdk/python/human-protocol-sdk diff --git a/packages/apps/dashboard/client/.gitignore b/packages/apps/dashboard/client/.gitignore index a547bf36d8..adc48a4b49 100644 --- a/packages/apps/dashboard/client/.gitignore +++ b/packages/apps/dashboard/client/.gitignore @@ -17,6 +17,7 @@ dist-ssr !.vscode/extensions.json .idea .DS_Store +.eslintcache *.suo *.ntvs* *.njsproj diff --git a/packages/apps/dashboard/client/index.html b/packages/apps/dashboard/client/index.html index c533b6ac6b..3b1a160e05 100644 --- a/packages/apps/dashboard/client/index.html +++ b/packages/apps/dashboard/client/index.html @@ -18,6 +18,6 @@
- + diff --git a/packages/apps/dashboard/client/package.json b/packages/apps/dashboard/client/package.json index d8349972ea..8e0eef6f20 100644 --- a/packages/apps/dashboard/client/package.json +++ b/packages/apps/dashboard/client/package.json @@ -9,11 +9,12 @@ "clean": "tsc --build --clean && rm -rf dist", "start": "vite", "build": "tsc --build && vite build", - "lint": "eslint . --report-unused-disable-directives --max-warnings 0", + "lint": "yarn typecheck && eslint . --report-unused-disable-directives --max-warnings 0", "lint:fix": "eslint . --fix", "preview": "vite preview", "vercel-build": "yarn workspace human-protocol build:libs && yarn build", - "test": "exit 0" + "test": "exit 0", + "typecheck": "tsc --noEmit" }, "dependencies": { "@emotion/react": "^11.11.4", @@ -62,13 +63,12 @@ "sass": "^1.85.0", "typescript": "^5.6.3", "typescript-eslint": "^8.33.0", - "vite": "^6.2.4", - "vite-plugin-svgr": "^4.2.0" + "vite": "^6.2.4" }, "lint-staged": { "*.{ts,tsx}": [ "prettier --write", - "eslint --fix" + "eslint --cache --fix" ] } } diff --git a/packages/apps/dashboard/client/src/assets/styles/favicon.ico b/packages/apps/dashboard/client/public/favicon.ico similarity index 100% rename from packages/apps/dashboard/client/src/assets/styles/favicon.ico rename to packages/apps/dashboard/client/public/favicon.ico diff --git a/packages/apps/dashboard/client/public/vite.svg b/packages/apps/dashboard/client/public/vite.svg deleted file mode 100644 index c200287f03..0000000000 --- a/packages/apps/dashboard/client/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/apps/dashboard/client/src/App.tsx b/packages/apps/dashboard/client/src/App.tsx deleted file mode 100644 index c78a2f31b6..0000000000 --- a/packages/apps/dashboard/client/src/App.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { FC } from 'react'; - -import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; - -import Graph from '@/pages/Graph'; -import Home from '@/pages/Home'; -import LeaderBoard from '@/pages/Leaderboard'; -import SearchResults from '@/pages/SearchResults'; - -const App: FC = () => { - return ( - - - } /> - } /> - } /> - } /> - Not find} /> - - - ); -}; - -export default App; diff --git a/packages/apps/dashboard/client/src/app/AppRoutes.tsx b/packages/apps/dashboard/client/src/app/AppRoutes.tsx new file mode 100644 index 0000000000..866ee88553 --- /dev/null +++ b/packages/apps/dashboard/client/src/app/AppRoutes.tsx @@ -0,0 +1,26 @@ +import { FC } from 'react'; + +import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; + +import GraphPage from '@/pages/graph'; +import HomePage from '@/pages/home'; +import LeaderboardPage from '@/pages/leaderboard'; +import SearchResultsPage from '@/pages/searchResults'; + +import { ROUTES } from './config/routes'; + +const AppRoutes: FC = () => { + return ( + + + } /> + } /> + } /> + } /> + Not found} /> + + + ); +}; + +export default AppRoutes; diff --git a/packages/apps/dashboard/client/src/app/config/routes.ts b/packages/apps/dashboard/client/src/app/config/routes.ts new file mode 100644 index 0000000000..9990f8335a --- /dev/null +++ b/packages/apps/dashboard/client/src/app/config/routes.ts @@ -0,0 +1,6 @@ +export const ROUTES = { + HOME: '/', + LEADERBOARD: '/leaderboard', + GRAPH: '/graph', + SEARCH: '/search/:chainId/:address', +} as const; diff --git a/packages/apps/dashboard/client/src/main.tsx b/packages/apps/dashboard/client/src/app/index.tsx similarity index 80% rename from packages/apps/dashboard/client/src/main.tsx rename to packages/apps/dashboard/client/src/app/index.tsx index 0474e89a76..04a926ce42 100644 --- a/packages/apps/dashboard/client/src/main.tsx +++ b/packages/apps/dashboard/client/src/app/index.tsx @@ -3,10 +3,9 @@ import React from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import ReactDOM from 'react-dom/client'; -import ThemeProvider from '@/providers/ThemeProvider'; - -import App from './App'; -import '@/assets/styles/main.scss'; +import AppRoutes from './AppRoutes'; +import ThemeProvider from './providers/ThemeProvider'; +import './styles/main.scss'; import 'simplebar-react/dist/simplebar.min.css'; const queryClient = new QueryClient({ @@ -20,7 +19,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render( - + diff --git a/packages/apps/dashboard/client/src/providers/ThemeProvider.tsx b/packages/apps/dashboard/client/src/app/providers/ThemeProvider.tsx similarity index 97% rename from packages/apps/dashboard/client/src/providers/ThemeProvider.tsx rename to packages/apps/dashboard/client/src/app/providers/ThemeProvider.tsx index 41b3005a65..82045f6af2 100644 --- a/packages/apps/dashboard/client/src/providers/ThemeProvider.tsx +++ b/packages/apps/dashboard/client/src/app/providers/ThemeProvider.tsx @@ -13,7 +13,7 @@ import { ThemeProvider as MuiThemeProvider, } from '@mui/material'; -import { createAppTheme } from '../theme'; +import { createAppTheme } from '@/shared/ui/theme'; const THEME_STORAGE_KEY = 'dashboard-app-theme-mode'; const RELEASE_DARK_MODE = false; // TODO: remove this once we release the dark mode diff --git a/packages/apps/dashboard/client/src/assets/styles/_const.scss b/packages/apps/dashboard/client/src/app/styles/_const.scss similarity index 100% rename from packages/apps/dashboard/client/src/assets/styles/_const.scss rename to packages/apps/dashboard/client/src/app/styles/_const.scss diff --git a/packages/apps/dashboard/client/src/assets/styles/_graph-swipper.scss b/packages/apps/dashboard/client/src/app/styles/_graph-swipper.scss similarity index 100% rename from packages/apps/dashboard/client/src/assets/styles/_graph-swipper.scss rename to packages/apps/dashboard/client/src/app/styles/_graph-swipper.scss diff --git a/packages/apps/dashboard/client/src/assets/styles/_home-page.scss b/packages/apps/dashboard/client/src/app/styles/_home-page.scss similarity index 100% rename from packages/apps/dashboard/client/src/assets/styles/_home-page.scss rename to packages/apps/dashboard/client/src/app/styles/_home-page.scss diff --git a/packages/apps/dashboard/client/src/assets/styles/_page-wrapper.scss b/packages/apps/dashboard/client/src/app/styles/_page-wrapper.scss similarity index 100% rename from packages/apps/dashboard/client/src/assets/styles/_page-wrapper.scss rename to packages/apps/dashboard/client/src/app/styles/_page-wrapper.scss diff --git a/packages/apps/dashboard/client/src/assets/styles/_search.scss b/packages/apps/dashboard/client/src/app/styles/_search.scss similarity index 100% rename from packages/apps/dashboard/client/src/assets/styles/_search.scss rename to packages/apps/dashboard/client/src/app/styles/_search.scss diff --git a/packages/apps/dashboard/client/src/assets/styles/_shadow-icon.scss b/packages/apps/dashboard/client/src/app/styles/_shadow-icon.scss similarity index 100% rename from packages/apps/dashboard/client/src/assets/styles/_shadow-icon.scss rename to packages/apps/dashboard/client/src/app/styles/_shadow-icon.scss diff --git a/packages/apps/dashboard/client/src/assets/styles/main.scss b/packages/apps/dashboard/client/src/app/styles/main.scss similarity index 100% rename from packages/apps/dashboard/client/src/assets/styles/main.scss rename to packages/apps/dashboard/client/src/app/styles/main.scss diff --git a/packages/apps/dashboard/client/src/assets/bing.png b/packages/apps/dashboard/client/src/assets/bing.png deleted file mode 100644 index c1eab49c16..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/bing.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/bitfinex.png b/packages/apps/dashboard/client/src/assets/bitfinex.png deleted file mode 100644 index 2908ffb464..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/bitfinex.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/coinlist.png b/packages/apps/dashboard/client/src/assets/coinlist.png deleted file mode 100644 index 68b8e6110c..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/coinlist.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/ethereum.png b/packages/apps/dashboard/client/src/assets/ethereum.png deleted file mode 100644 index fcd17dba96..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/ethereum.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/exchange.png b/packages/apps/dashboard/client/src/assets/exchange.png deleted file mode 100644 index d48b1b3d00..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/exchange.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/gate.png b/packages/apps/dashboard/client/src/assets/gate.png deleted file mode 100644 index ff63264f50..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/gate.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/human.png b/packages/apps/dashboard/client/src/assets/human.png deleted file mode 100644 index c42b6b71cc..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/human.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/icons/binance.svg b/packages/apps/dashboard/client/src/assets/icons/binance.svg deleted file mode 100644 index ab171b13dd..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/binance.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/celo.svg b/packages/apps/dashboard/client/src/assets/icons/celo.svg deleted file mode 100644 index 6fa2e074a4..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/celo.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/discord.svg b/packages/apps/dashboard/client/src/assets/icons/discord.svg deleted file mode 100644 index 079c049929..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/discord.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/ethereum.svg b/packages/apps/dashboard/client/src/assets/icons/ethereum.svg deleted file mode 100644 index aaafc35867..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/ethereum.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/exchange-oracle.svg b/packages/apps/dashboard/client/src/assets/icons/exchange-oracle.svg deleted file mode 100644 index 5452044828..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/exchange-oracle.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/excluded/escrow.svg b/packages/apps/dashboard/client/src/assets/icons/excluded/escrow.svg deleted file mode 100644 index 44d5e471a0..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/excluded/escrow.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/excluded/wallet.svg b/packages/apps/dashboard/client/src/assets/icons/excluded/wallet.svg deleted file mode 100644 index f081e6fda0..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/excluded/wallet.svg +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/human-app.svg b/packages/apps/dashboard/client/src/assets/icons/human-app.svg deleted file mode 100644 index 9a9290e7c2..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/human-app.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/job-launcher.svg b/packages/apps/dashboard/client/src/assets/icons/job-launcher.svg deleted file mode 100644 index 433c97afa8..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/job-launcher.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/moonbeam.svg b/packages/apps/dashboard/client/src/assets/icons/moonbeam.svg deleted file mode 100644 index 800dd14dec..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/moonbeam.svg +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/okx.svg b/packages/apps/dashboard/client/src/assets/icons/okx.svg deleted file mode 100644 index 515c561adf..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/okx.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/polygon.svg b/packages/apps/dashboard/client/src/assets/icons/polygon.svg deleted file mode 100644 index 2dfb9ed98f..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/polygon.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/recording-oracle.svg b/packages/apps/dashboard/client/src/assets/icons/recording-oracle.svg deleted file mode 100644 index e703d0b8a3..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/recording-oracle.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/reputation-oracle.svg b/packages/apps/dashboard/client/src/assets/icons/reputation-oracle.svg deleted file mode 100644 index 69f056ede0..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/reputation-oracle.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/icons/xlayer.svg b/packages/apps/dashboard/client/src/assets/icons/xlayer.svg deleted file mode 100644 index b3c4db1cb6..0000000000 --- a/packages/apps/dashboard/client/src/assets/icons/xlayer.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/packages/apps/dashboard/client/src/assets/lbank.png b/packages/apps/dashboard/client/src/assets/lbank.png deleted file mode 100644 index 4ebb88b9d3..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/lbank.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/logo-mobile.png b/packages/apps/dashboard/client/src/assets/logo-mobile.png deleted file mode 100644 index 34bedd58fc..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/logo-mobile.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/logo.png b/packages/apps/dashboard/client/src/assets/logo.png deleted file mode 100644 index dc273f1d30..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/logo.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/probitGlobal.png b/packages/apps/dashboard/client/src/assets/probitGlobal.png deleted file mode 100644 index acd09acf2a..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/probitGlobal.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/recording.png b/packages/apps/dashboard/client/src/assets/recording.png deleted file mode 100644 index f4daa1fff7..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/recording.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/assets/reputation.png b/packages/apps/dashboard/client/src/assets/reputation.png deleted file mode 100644 index 23e3c8865a..0000000000 Binary files a/packages/apps/dashboard/client/src/assets/reputation.png and /dev/null differ diff --git a/packages/apps/dashboard/client/src/components/Breadcrumbs/index.ts b/packages/apps/dashboard/client/src/components/Breadcrumbs/index.ts deleted file mode 100644 index 3ff68ca589..0000000000 --- a/packages/apps/dashboard/client/src/components/Breadcrumbs/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Breadcrumbs'; diff --git a/packages/apps/dashboard/client/src/components/Charts/CustomChartTooltip.tsx b/packages/apps/dashboard/client/src/components/Charts/CustomChartTooltip.tsx deleted file mode 100644 index 43e186ae67..0000000000 --- a/packages/apps/dashboard/client/src/components/Charts/CustomChartTooltip.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord'; -import { Grid, Typography } from '@mui/material'; -import Box from '@mui/material/Box'; -import Card from '@mui/material/Card'; -import Stack from '@mui/material/Stack'; -import { NumericFormat } from 'react-number-format'; -import { TooltipProps } from 'recharts'; - -import { GraphPageChartDataConfigObject } from '@/components/Charts/AreaChart'; -import { formatDate } from '@/helpers/formatDate'; - -const renderTitle = (title: string) => { - const currentTitle: GraphPageChartDataConfigObject = { - totalTransactionAmount: 'Transfer Amount', - totalTransactionCount: 'Transactions Count', - solved: 'Number of Tasks', - dailyUniqueReceivers: 'Unique Receivers', - dailyUniqueSenders: 'Unique Senders', - }; - return currentTitle[title as keyof GraphPageChartDataConfigObject]; -}; - -const CustomChartTooltip = ({ - payload, - label, - active, -}: TooltipProps) => { - if (active) { - return ( - - - - {formatDate(label, 'MMMM DD, YYYY')} - - {payload?.map((elem) => ( - - - - - - {renderTitle(elem.name ?? '')} - - - - - - {' '} - {elem.name === 'totalTransactionAmount' ? 'HMT' : ''} - - - - ))} - - - ); - } - return null; -}; - -export default CustomChartTooltip; diff --git a/packages/apps/dashboard/client/src/components/Charts/index.ts b/packages/apps/dashboard/client/src/components/Charts/index.ts deleted file mode 100644 index 52e979682c..0000000000 --- a/packages/apps/dashboard/client/src/components/Charts/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './AreaChart'; -export * from './CustomChartTooltip'; -export * from './CustomXAxisTick'; -export * from './ToggleCharts'; diff --git a/packages/apps/dashboard/client/src/components/Clipboard/index.ts b/packages/apps/dashboard/client/src/components/Clipboard/index.ts deleted file mode 100644 index cea243dcd0..0000000000 --- a/packages/apps/dashboard/client/src/components/Clipboard/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Clipboard'; diff --git a/packages/apps/dashboard/client/src/components/CustomTooltip/index.tsx b/packages/apps/dashboard/client/src/components/CustomTooltip/index.tsx deleted file mode 100644 index 781ad47b0f..0000000000 --- a/packages/apps/dashboard/client/src/components/CustomTooltip/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from './CustomTooltip'; diff --git a/packages/apps/dashboard/client/src/components/DataEntry/index.ts b/packages/apps/dashboard/client/src/components/DataEntry/index.ts deleted file mode 100644 index b2655c7380..0000000000 --- a/packages/apps/dashboard/client/src/components/DataEntry/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './DatePicker'; -export * from './ToggleButtons'; diff --git a/packages/apps/dashboard/client/src/components/Footer/index.ts b/packages/apps/dashboard/client/src/components/Footer/index.ts deleted file mode 100644 index be92134c1b..0000000000 --- a/packages/apps/dashboard/client/src/components/Footer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Footer'; diff --git a/packages/apps/dashboard/client/src/components/Header/index.ts b/packages/apps/dashboard/client/src/components/Header/index.ts deleted file mode 100644 index 579f1ac23f..0000000000 --- a/packages/apps/dashboard/client/src/components/Header/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Header'; diff --git a/packages/apps/dashboard/client/src/components/Home/FormatNumber.tsx b/packages/apps/dashboard/client/src/components/Home/FormatNumber.tsx deleted file mode 100644 index c4836609fc..0000000000 --- a/packages/apps/dashboard/client/src/components/Home/FormatNumber.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { NumericFormat } from 'react-number-format'; - -export const FormatNumber = ({ - value, -}: { - value: number | string | undefined | null; -}) => { - return ( - - ); -}; -export const FormatNumberWithDecimals = ({ - value, -}: { - value: number | string | undefined | null; -}) => { - if (value && Number(value) < 1) { - return {value}; - } - return ( - - ); -}; diff --git a/packages/apps/dashboard/client/src/components/Home/index.ts b/packages/apps/dashboard/client/src/components/Home/index.ts deleted file mode 100644 index 7117ca0dc1..0000000000 --- a/packages/apps/dashboard/client/src/components/Home/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './SmallGraph'; -export * from './GraphSwiper'; diff --git a/packages/apps/dashboard/client/src/components/Icons/AvalancheIcon.tsx b/packages/apps/dashboard/client/src/components/Icons/AvalancheIcon.tsx deleted file mode 100644 index 83d1eae24a..0000000000 --- a/packages/apps/dashboard/client/src/components/Icons/AvalancheIcon.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { FC } from 'react'; - -import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; - -export const AvalancheIcon: FC = (props) => { - return ( - - - - - - - ); -}; diff --git a/packages/apps/dashboard/client/src/components/Icons/CeloIcon.tsx b/packages/apps/dashboard/client/src/components/Icons/CeloIcon.tsx deleted file mode 100644 index 19e30cba4d..0000000000 --- a/packages/apps/dashboard/client/src/components/Icons/CeloIcon.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { FC } from 'react'; - -import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; - -export const CeloIcon: FC = (props) => { - return ( - - - - - - ); -}; - -export default CeloIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/MoonbaseAlphaIcon.tsx b/packages/apps/dashboard/client/src/components/Icons/MoonbaseAlphaIcon.tsx deleted file mode 100644 index 6e64c1fafb..0000000000 --- a/packages/apps/dashboard/client/src/components/Icons/MoonbaseAlphaIcon.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { FC } from 'react'; - -import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; - -export const MoonbaseAlphaIcon: FC = (props) => { - return ( - - - - - - - - - - - - - - - - - - ); -}; - -export default MoonbaseAlphaIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/MoonbeamIcon.tsx b/packages/apps/dashboard/client/src/components/Icons/MoonbeamIcon.tsx deleted file mode 100644 index b2de436954..0000000000 --- a/packages/apps/dashboard/client/src/components/Icons/MoonbeamIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { FC } from 'react'; - -import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; - -export const MoonbeamIcon: FC = (props) => { - return ( - - - - ); -}; - -export default MoonbeamIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/XLayerIcon.tsx b/packages/apps/dashboard/client/src/components/Icons/XLayerIcon.tsx deleted file mode 100644 index 7e9ff61b98..0000000000 --- a/packages/apps/dashboard/client/src/components/Icons/XLayerIcon.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { FC } from 'react'; - -import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; - -export const XLayerIcon: FC = (props) => { - return ( - - - - - - - - - - - - - - - - - - ); -}; diff --git a/packages/apps/dashboard/client/src/components/NetworkIcon/index.tsx b/packages/apps/dashboard/client/src/components/NetworkIcon/index.tsx deleted file mode 100644 index 176f2c13e9..0000000000 --- a/packages/apps/dashboard/client/src/components/NetworkIcon/index.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import CeloIcon from '@/assets/icons/celo.svg'; -import { AvalancheIcon } from '@/components/Icons/AvalancheIcon'; -import BinanceSmartChainIcon from '@/components/Icons/BinanceSmartChainIcon'; -import EthereumIcon from '@/components/Icons/EthereumIcon'; -import HumanIcon from '@/components/Icons/HumanIcon'; -import MoonbaseAlphaIcon from '@/components/Icons/MoonbaseAlphaIcon'; -import MoonbeamIcon from '@/components/Icons/MoonbeamIcon'; -import PolygonIcon from '@/components/Icons/PolygonIcon'; -import { XLayerIcon } from '@/components/Icons/XLayerIcon'; - -export const NetworkIcon = ({ chainId }: { chainId: number }) => { - const icon = (() => { - switch (chainId) { - case 1: - case 4: - case 5: - case 11155111: - return ; - case 56: - case 97: - return ; - case 137: - case 80001: - case 80002: - return ; - case 1284: - return ; - case 1287: - return ; - case 42220: - case 44787: - return ; - case 195: - case 196: - return ; - case 43113: - case 43114: - return ; - default: - return ; - } - })(); - - return <>{icon}; -}; diff --git a/packages/apps/dashboard/client/src/components/NothingFound/index.ts b/packages/apps/dashboard/client/src/components/NothingFound/index.ts deleted file mode 100644 index 3a4c58b3b9..0000000000 --- a/packages/apps/dashboard/client/src/components/NothingFound/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './NothingFound'; diff --git a/packages/apps/dashboard/client/src/components/PageWrapper/index.ts b/packages/apps/dashboard/client/src/components/PageWrapper/index.ts deleted file mode 100644 index ee1a8716a0..0000000000 --- a/packages/apps/dashboard/client/src/components/PageWrapper/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './PageWrapper'; diff --git a/packages/apps/dashboard/client/src/components/SearchResults/index.ts b/packages/apps/dashboard/client/src/components/SearchResults/index.ts deleted file mode 100644 index 46e0669dbc..0000000000 --- a/packages/apps/dashboard/client/src/components/SearchResults/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './TitleSectionWrapper'; diff --git a/packages/apps/dashboard/client/src/components/ShadowIcon/index.ts b/packages/apps/dashboard/client/src/components/ShadowIcon/index.ts deleted file mode 100644 index fbddef1da6..0000000000 --- a/packages/apps/dashboard/client/src/components/ShadowIcon/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ShadowIcon'; diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/components/AddressCell.tsx b/packages/apps/dashboard/client/src/features/Leaderboard/components/AddressCell.tsx deleted file mode 100644 index 8901834946..0000000000 --- a/packages/apps/dashboard/client/src/features/Leaderboard/components/AddressCell.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Box } from '@mui/material'; - -import AbbreviateClipboard from '@/components/SearchResults/AbbreviateClipboard'; - -export const AddressCell = ({ - chainId, - address, -}: { - chainId: string; - address: string; -}) => ( - - - -); diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/components/ChainCell.tsx b/packages/apps/dashboard/client/src/features/Leaderboard/components/ChainCell.tsx deleted file mode 100644 index 9da3ec67f6..0000000000 --- a/packages/apps/dashboard/client/src/features/Leaderboard/components/ChainCell.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Typography } from '@mui/material'; - -import { NetworkIcon } from '@/components/NetworkIcon'; -import { getNetwork } from '@/utils/config/networks'; - -export const ChainCell = ({ chainId }: { chainId: number }) => ( - - - {getNetwork(chainId)?.name} - -); diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/components/EntityIcon.tsx b/packages/apps/dashboard/client/src/features/Leaderboard/components/EntityIcon.tsx deleted file mode 100644 index 009c31990b..0000000000 --- a/packages/apps/dashboard/client/src/features/Leaderboard/components/EntityIcon.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Role } from '@human-protocol/sdk'; - -import { ExchangeOracleIcon } from '@/components/Icons/ExchangeOracleIcon'; -import HumanIcon from '@/components/Icons/HumanIcon'; -import { JobLauncher } from '@/components/Icons/JobLauncher'; -import { RecordingOracle } from '@/components/Icons/RecordingOracle'; -import { ReputationOracle } from '@/components/Icons/ReputationOracle'; - -export const EntityIcon: React.FC<{ role: string }> = ({ role }) => { - switch (role) { - case Role.JobLauncher: - return ; - case Role.RecordingOracle: - return ; - case Role.ReputationOracle: - return ; - case Role.ExchangeOracle: - return ; - default: - return ; - } -}; diff --git a/packages/apps/dashboard/client/src/features/graph/api/useChartData.ts b/packages/apps/dashboard/client/src/features/graph/api/useChartData.ts new file mode 100644 index 0000000000..b6e27a522d --- /dev/null +++ b/packages/apps/dashboard/client/src/features/graph/api/useChartData.ts @@ -0,0 +1,113 @@ +import { useMemo } from 'react'; + +import { useQuery, keepPreviousData } from '@tanstack/react-query'; +import dayjs from 'dayjs'; +import { useDebounce } from 'use-debounce'; + +import apiPaths from '@/shared/api/apiPaths'; +import httpClient from '@/shared/api/httpClient'; +import validateResponse from '@/shared/lib/validateResponse'; + +import { + hcaptchaDailyStatsSchema, + HcaptchaDailyStats, +} from '../model/hcaptchaDailyStatsSchema'; +import { + hmtDailyStatsSchema, + HMTDailyStats, +} from '../model/hmtDailyStatsSchema'; + +export type ChartData = (HMTDailyStats & Omit)[]; + +const mergeResponses = ( + hcaptchaStatsResults: HcaptchaDailyStats[], + hmtStatsResults: HMTDailyStats[] +): ChartData => { + const allDates = Array.from( + new Set([ + ...hcaptchaStatsResults.map(({ date }) => date), + ...hmtStatsResults.map(({ date }) => date), + ]) + ).sort((a, b) => (dayjs(a).isBefore(dayjs(b)) ? -1 : 1)); + + const hcaptchaStatsResultsMap = new Map(); + const hmtStatsResultsMap = new Map(); + + hcaptchaStatsResults.forEach((entry) => { + hcaptchaStatsResultsMap.set(entry.date, entry); + }); + + hmtStatsResults.forEach((entry) => { + hmtStatsResultsMap.set(entry.date, entry); + }); + + return allDates.map((date) => { + const hmtStatsEntry: HMTDailyStats = hmtStatsResultsMap.get(date) || { + dailyUniqueReceivers: 0, + dailyUniqueSenders: 0, + date: date, + totalTransactionAmount: 0, + totalTransactionCount: 0, + }; + + const hcaptchaStatsEntry: HcaptchaDailyStats = hcaptchaStatsResultsMap.get( + date + ) || { + date: date, + solved: 0, + }; + + return { ...hmtStatsEntry, ...hcaptchaStatsEntry }; + }); +}; + +const DEBOUNCE_MS = 300; + +const useChartData = (from: dayjs.Dayjs, to: dayjs.Dayjs) => { + const queryParams = useMemo( + () => ({ + from: from.format('YYYY-MM-DD'), + to: to.format('YYYY-MM-DD'), + }), + [from, to] + ); + + const [debouncedQueryParams] = useDebounce(queryParams, DEBOUNCE_MS); + + return useQuery({ + queryFn: async () => { + const { data: hmtDailyStats } = await httpClient.get( + apiPaths.hmtDailyStats.path, + { + params: debouncedQueryParams, + } + ); + const { data: hcaptchDailyStats } = await httpClient.get( + apiPaths.hcaptchaStatsDaily.path, + { + params: debouncedQueryParams, + } + ); + + const validHmtDailyStats = validateResponse( + hmtDailyStats, + hmtDailyStatsSchema + ); + + const validHcaptchaGeneralStats = validateResponse( + hcaptchDailyStats, + hcaptchaDailyStatsSchema + ); + + return mergeResponses( + validHcaptchaGeneralStats.results, + validHmtDailyStats.results + ); + }, + staleTime: DEBOUNCE_MS, + queryKey: ['useChartData', debouncedQueryParams], + placeholderData: keepPreviousData, + }); +}; + +export default useChartData; diff --git a/packages/apps/dashboard/client/src/features/graph/index.ts b/packages/apps/dashboard/client/src/features/graph/index.ts new file mode 100644 index 0000000000..9cb08db244 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/graph/index.ts @@ -0,0 +1 @@ +export { default } from './ui/AreaChart'; diff --git a/packages/apps/dashboard/client/src/helpers/formatDate.ts b/packages/apps/dashboard/client/src/features/graph/lib/formatDate.ts similarity index 52% rename from packages/apps/dashboard/client/src/helpers/formatDate.ts rename to packages/apps/dashboard/client/src/features/graph/lib/formatDate.ts index d2cf178433..eee127a6ab 100644 --- a/packages/apps/dashboard/client/src/helpers/formatDate.ts +++ b/packages/apps/dashboard/client/src/features/graph/lib/formatDate.ts @@ -1,5 +1,7 @@ import dayjs from 'dayjs'; -export const formatDate = (date: string, dateFormat?: string) => { +const formatDate = (date: string, dateFormat?: string) => { return dayjs(new Date(date)).format(dateFormat ?? 'dd/MM/yyyy'); }; + +export default formatDate; diff --git a/packages/apps/dashboard/client/src/helpers/formatNumber.ts b/packages/apps/dashboard/client/src/features/graph/lib/formatNumber.ts similarity index 72% rename from packages/apps/dashboard/client/src/helpers/formatNumber.ts rename to packages/apps/dashboard/client/src/features/graph/lib/formatNumber.ts index 029a6ae604..c4a391b9d8 100644 --- a/packages/apps/dashboard/client/src/helpers/formatNumber.ts +++ b/packages/apps/dashboard/client/src/features/graph/lib/formatNumber.ts @@ -1,4 +1,4 @@ -export const formatNumber = (number: number) => { +const formatNumber = (number: number) => { if (number >= 1000000) { return `${(number / 1000000).toFixed()} M`; } @@ -9,3 +9,5 @@ export const formatNumber = (number: number) => { return `${number.toString()}`; }; + +export default formatNumber; diff --git a/packages/apps/dashboard/client/src/features/graph/model/hcaptchaDailyStatsSchema.ts b/packages/apps/dashboard/client/src/features/graph/model/hcaptchaDailyStatsSchema.ts new file mode 100644 index 0000000000..6b8d16a1ac --- /dev/null +++ b/packages/apps/dashboard/client/src/features/graph/model/hcaptchaDailyStatsSchema.ts @@ -0,0 +1,18 @@ +import { z } from 'zod'; + +export const hcaptchaDailyStatsSchema = z.object({ + from: z.string().optional(), + to: z.string().optional(), + results: z.array( + z.object({ + solved: z.number(), + date: z.string(), + }) + ), +}); + +export type HcaptchaDailyStatsResponse = z.infer< + typeof hcaptchaDailyStatsSchema +>; + +export type HcaptchaDailyStats = HcaptchaDailyStatsResponse['results'][number]; diff --git a/packages/apps/dashboard/client/src/features/graph/model/hmtDailyStatsSchema.ts b/packages/apps/dashboard/client/src/features/graph/model/hmtDailyStatsSchema.ts new file mode 100644 index 0000000000..5e4a86629a --- /dev/null +++ b/packages/apps/dashboard/client/src/features/graph/model/hmtDailyStatsSchema.ts @@ -0,0 +1,29 @@ +import { z } from 'zod'; + +export const hmtDailyStatsSchema = z.object({ + from: z.string().optional(), + to: z.string().optional(), + results: z.array( + z.object({ + totalTransactionAmount: z.string().transform((value, ctx) => { + const valueAsNumber = Number(value); + if (Number.isNaN(valueAsNumber)) { + ctx.addIssue({ + path: ['totalTransactionAmount'], + code: z.ZodIssueCode.custom, + }); + } + + return valueAsNumber / 10 ** 18; + }), + totalTransactionCount: z.number(), + dailyUniqueSenders: z.number(), + dailyUniqueReceivers: z.number(), + date: z.string(), + }) + ), +}); + +export type HMTDailyStatsResponse = z.output; + +export type HMTDailyStats = HMTDailyStatsResponse['results'][number]; diff --git a/packages/apps/dashboard/client/src/utils/hooks/use-graph-page-chart-params.tsx b/packages/apps/dashboard/client/src/features/graph/store/useChartParamsStore.ts similarity index 96% rename from packages/apps/dashboard/client/src/utils/hooks/use-graph-page-chart-params.tsx rename to packages/apps/dashboard/client/src/features/graph/store/useChartParamsStore.ts index 0869e4dc69..7755ed615d 100644 --- a/packages/apps/dashboard/client/src/utils/hooks/use-graph-page-chart-params.tsx +++ b/packages/apps/dashboard/client/src/features/graph/store/useChartParamsStore.ts @@ -58,7 +58,7 @@ const INITIAL_RANGE_PARAMS = { to: dayjs(), }; -export const useGraphPageChartParams = create((set) => ({ +const useChartParamsStore = create((set) => ({ dateRangeParams: INITIAL_RANGE_PARAMS, selectedTimePeriod: '1W', setFromDate: (fromDate: Dayjs | null) => { @@ -116,3 +116,5 @@ export const useGraphPageChartParams = create((set) => ({ })); }, })); + +export default useChartParamsStore; diff --git a/packages/apps/dashboard/client/src/components/Charts/AreaChart.tsx b/packages/apps/dashboard/client/src/features/graph/ui/AreaChart.tsx similarity index 90% rename from packages/apps/dashboard/client/src/components/Charts/AreaChart.tsx rename to packages/apps/dashboard/client/src/features/graph/ui/AreaChart.tsx index 36f5fa95b1..73a297367d 100644 --- a/packages/apps/dashboard/client/src/components/Charts/AreaChart.tsx +++ b/packages/apps/dashboard/client/src/features/graph/ui/AreaChart.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react'; +import { FC, useEffect, useRef, useState } from 'react'; import { Typography, useTheme } from '@mui/material'; import Card from '@mui/material/Card'; @@ -14,34 +14,35 @@ import { ResponsiveContainer, } from 'recharts'; -import CustomXAxisTick from '@/components/Charts/CustomXAxisTick'; -import ToggleCharts from '@/components/Charts/ToggleCharts'; -import DatePicker from '@/components/DataEntry/DatePicker'; -import ToggleButtons from '@/components/DataEntry/ToggleButtons'; -import { formatNumber } from '@/helpers/formatNumber'; -import { - GraphPageChartData, - useGraphPageChartData, -} from '@/services/api/use-graph-page-chart-data'; -import { +import DatePicker from '@/shared/ui/DatePicker'; + +import useChartData, { ChartData } from '../api/useChartData'; +import formatNumber from '../lib/formatNumber'; +import useChartParamsStore, { initialAllTime, - useGraphPageChartParams, -} from '@/utils/hooks/use-graph-page-chart-params'; +} from '../store/useChartParamsStore'; -import CustomChartTooltip from './CustomChartTooltip'; +import ChartTooltip from './ChartTooltip'; +import CustomXAxisTick from './CustomXAxisTick'; +import ToggleButtons from './ToggleButtons'; +import ToggleCharts from './ToggleCharts'; -export type GraphPageChartDataConfigObject = Partial< - Record +export type ChartDataConfigObject = Partial< + Record >; -const CHECKED_CHARTS_DEFAULT_STATE: GraphPageChartDataConfigObject = { +type AreaChartProps = { + changeDateOnScroll?: boolean; +}; + +const CHECKED_CHARTS_DEFAULT_STATE: ChartDataConfigObject = { totalTransactionAmount: true, totalTransactionCount: true, solved: true, dailyUniqueReceivers: true, dailyUniqueSenders: true, }; -const HOVERED_CHARTS_DEFAULT_STATE: GraphPageChartDataConfigObject = { +const HOVERED_CHARTS_DEFAULT_STATE: ChartDataConfigObject = { totalTransactionAmount: false, totalTransactionCount: false, solved: false, @@ -50,12 +51,12 @@ const HOVERED_CHARTS_DEFAULT_STATE: GraphPageChartDataConfigObject = { }; type SumOfNumericChartDataProperties = Record< - keyof Omit, + keyof Omit, number >; const sumNumericProperties = ( - chartData: GraphPageChartData + chartData: ChartData ): SumOfNumericChartDataProperties => { return chartData.reduce( (acc, chartEntry) => { @@ -76,20 +77,16 @@ const sumNumericProperties = ( ); }; -export const AreaChart = ({ - changeDateOnScroll = false, -}: { - changeDateOnScroll?: boolean; -}) => { - const { data } = useGraphPageChartData(); - const theme = useTheme(); - const chartData = data || []; +const AreaChart: FC = ({ changeDateOnScroll = false }) => { const { setFromDate, setToDate, clearTimePeriod, dateRangeParams: { from, to }, - } = useGraphPageChartParams(); + } = useChartParamsStore(); + const { data } = useChartData(from, to); + const theme = useTheme(); + const chartData = data || []; const sum = sumNumericProperties(chartData); const [checkedCharts, setCheckedCharts] = useState( CHECKED_CHARTS_DEFAULT_STATE @@ -314,7 +311,7 @@ export const AreaChart = ({ dataKey="date" tickMargin={10} /> - } /> + } /> {checkedCharts.totalTransactionAmount && ( ); }; + +export default AreaChart; diff --git a/packages/apps/dashboard/client/src/features/graph/ui/ChartTooltip.tsx b/packages/apps/dashboard/client/src/features/graph/ui/ChartTooltip.tsx new file mode 100644 index 0000000000..a1c474da5b --- /dev/null +++ b/packages/apps/dashboard/client/src/features/graph/ui/ChartTooltip.tsx @@ -0,0 +1,85 @@ +import { FC } from 'react'; + +import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord'; +import { Grid, Typography } from '@mui/material'; +import Box from '@mui/material/Box'; +import Card from '@mui/material/Card'; +import Stack from '@mui/material/Stack'; +import { TooltipProps } from 'recharts'; + +import FormattedNumber from '@/shared/ui/FormattedNumber'; + +import formatDate from '../lib/formatDate'; + +import { ChartDataConfigObject } from './AreaChart'; + +const renderTitle = (title: string) => { + const currentTitle: ChartDataConfigObject = { + totalTransactionAmount: 'Transfer Amount', + totalTransactionCount: 'Transactions Count', + solved: 'Number of Tasks', + dailyUniqueReceivers: 'Unique Receivers', + dailyUniqueSenders: 'Unique Senders', + }; + return currentTitle[title as keyof ChartDataConfigObject]; +}; + +const ChartTooltip: FC> = ({ + payload, + label, + active, +}) => { + if (!active) return null; + + return ( + + + + {formatDate(label, 'MMMM DD, YYYY')} + + {payload?.map((elem) => ( + + + + + + {renderTitle(elem.name ?? '')} + + + + + + {' '} + {elem.name === 'totalTransactionAmount' ? 'HMT' : ''} + + + + ))} + + + ); +}; + +export default ChartTooltip; diff --git a/packages/apps/dashboard/client/src/components/Charts/CustomXAxisTick.tsx b/packages/apps/dashboard/client/src/features/graph/ui/CustomXAxisTick.tsx similarity index 91% rename from packages/apps/dashboard/client/src/components/Charts/CustomXAxisTick.tsx rename to packages/apps/dashboard/client/src/features/graph/ui/CustomXAxisTick.tsx index 3cdcc81b5b..7d351507c6 100644 --- a/packages/apps/dashboard/client/src/components/Charts/CustomXAxisTick.tsx +++ b/packages/apps/dashboard/client/src/features/graph/ui/CustomXAxisTick.tsx @@ -2,7 +2,7 @@ import { useTheme } from '@mui/material'; // @ts-expect-error -- import error, but this type work property import { ContentRenderer } from 'recharts'; -import { formatDate } from '@/helpers/formatDate'; +import formatDate from '../lib/formatDate'; const CustomXAxisTick = ({ x, y, payload }: ContentRenderer) => { const theme = useTheme(); diff --git a/packages/apps/dashboard/client/src/components/Home/GraphSwiper.tsx b/packages/apps/dashboard/client/src/features/graph/ui/GraphSwiper.tsx similarity index 81% rename from packages/apps/dashboard/client/src/components/Home/GraphSwiper.tsx rename to packages/apps/dashboard/client/src/features/graph/ui/GraphSwiper.tsx index cb42b9e8f5..67775b3f45 100644 --- a/packages/apps/dashboard/client/src/components/Home/GraphSwiper.tsx +++ b/packages/apps/dashboard/client/src/features/graph/ui/GraphSwiper.tsx @@ -1,17 +1,22 @@ -import { useEffect } from 'react'; +import { FC, useEffect } from 'react'; import { Navigation } from 'swiper/modules'; import { Swiper, SwiperSlide } from 'swiper/react'; -import SmallGraph from '@/components/Home/SmallGraph'; import 'swiper/css'; import 'swiper/css/navigation'; -import { useGraphPageChartData } from '@/services/api/use-graph-page-chart-data'; -import { useGraphPageChartParams } from '@/utils/hooks/use-graph-page-chart-params'; -const GraphSwiper = () => { - const { data } = useGraphPageChartData(); - const { revertToInitialParams } = useGraphPageChartParams(); +import useChartData from '../api/useChartData'; +import useChartParamsStore from '../store/useChartParamsStore'; + +import SmallGraph from './SmallGraph'; + +const GraphSwiper: FC = () => { + const { + revertToInitialParams, + dateRangeParams: { from, to }, + } = useChartParamsStore(); + const { data } = useChartData(from, to); useEffect(() => { revertToInitialParams(); diff --git a/packages/apps/dashboard/client/src/components/Home/SmallGraph.tsx b/packages/apps/dashboard/client/src/features/graph/ui/SmallGraph.tsx similarity index 70% rename from packages/apps/dashboard/client/src/components/Home/SmallGraph.tsx rename to packages/apps/dashboard/client/src/features/graph/ui/SmallGraph.tsx index ba5b9cd44e..f03d15b7d0 100644 --- a/packages/apps/dashboard/client/src/components/Home/SmallGraph.tsx +++ b/packages/apps/dashboard/client/src/features/graph/ui/SmallGraph.tsx @@ -1,4 +1,4 @@ -import { Fragment } from 'react'; +import { FC, Fragment } from 'react'; import { useTheme } from '@mui/material'; import Box from '@mui/material/Box'; @@ -16,50 +16,51 @@ import { TooltipProps, } from 'recharts'; -import ToggleButtons from '@/components/DataEntry/ToggleButtons'; -import { formatDate } from '@/helpers/formatDate'; -import { formatNumber } from '@/helpers/formatNumber'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; -const CustomSmallChartTooltip = ({ +import formatDate from '../lib/formatDate'; +import formatNumber from '../lib/formatNumber'; + +import ToggleButtons from './ToggleButtons'; + +const CustomSmallChartTooltip: FC> = ({ payload, active, -}: TooltipProps) => { - if (active) { - return ( - - - {payload?.map((elem) => ( - - - {formatDate(elem.payload.date, 'MMMM DD, YYYY')} - - - {elem.value ? elem.value.toLocaleString('en-US') : ''} - - - ))} - - - ); - } - return null; +}) => { + if (!active) return null; + + return ( + + + {payload?.map((elem) => ( + + + {formatDate(elem.payload.date, 'MMMM DD, YYYY')} + + + {elem.value ? elem.value.toLocaleString('en-US') : ''} + + + ))} + + + ); }; -interface SmallGraphProps { +type SmallGraphProps = { graphData: { date: string; value: number; }[]; title: string; -} +}; const GraphSettings = ({ title }: { title: string }) => ( ( ); -const SmallGraph = ({ title, graphData }: SmallGraphProps) => { +const SmallGraph: FC = ({ title, graphData }) => { const isMobile = useIsMobile(); const theme = useTheme(); diff --git a/packages/apps/dashboard/client/src/components/DataEntry/ToggleButtons.tsx b/packages/apps/dashboard/client/src/features/graph/ui/ToggleButtons.tsx similarity index 93% rename from packages/apps/dashboard/client/src/components/DataEntry/ToggleButtons.tsx rename to packages/apps/dashboard/client/src/features/graph/ui/ToggleButtons.tsx index 29c523d3d9..9ef5a320b4 100644 --- a/packages/apps/dashboard/client/src/components/DataEntry/ToggleButtons.tsx +++ b/packages/apps/dashboard/client/src/features/graph/ui/ToggleButtons.tsx @@ -4,11 +4,10 @@ import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; import dayjs from 'dayjs'; -import { +import useChartParamsStore, { TIME_PERIOD_OPTIONS, TimePeriod, - useGraphPageChartParams, -} from '@/utils/hooks/use-graph-page-chart-params'; +} from '../store/useChartParamsStore'; export const StyledToggleButtonGroup = styled(ToggleButtonGroup)( ({ theme }) => ({ @@ -26,7 +25,7 @@ export const StyledToggleButtonGroup = styled(ToggleButtonGroup)( const ToggleButtons = () => { const { setTimePeriod, selectedTimePeriod, dateRangeParams } = - useGraphPageChartParams(); + useChartParamsStore(); const checkIfSelected = (element: TimePeriod) => { if (element.name !== 'ALL') { diff --git a/packages/apps/dashboard/client/src/components/Charts/ToggleCharts.tsx b/packages/apps/dashboard/client/src/features/graph/ui/ToggleCharts.tsx similarity index 90% rename from packages/apps/dashboard/client/src/components/Charts/ToggleCharts.tsx rename to packages/apps/dashboard/client/src/features/graph/ui/ToggleCharts.tsx index 58d2196304..b699b14f8d 100644 --- a/packages/apps/dashboard/client/src/components/Charts/ToggleCharts.tsx +++ b/packages/apps/dashboard/client/src/features/graph/ui/ToggleCharts.tsx @@ -1,8 +1,10 @@ +import { FC } from 'react'; + import { FormControlLabel, FormGroup, Typography } from '@mui/material'; import Checkbox from '@mui/material/Checkbox'; import Stack from '@mui/material/Stack'; -import { FormatNumber } from '@/components/Home/FormatNumber'; +import FormattedNumber from '@/shared/ui/FormattedNumber'; interface ToggleChartsProps { handleChange: (event: React.ChangeEvent) => void; @@ -17,12 +19,12 @@ interface ToggleChartsProps { }[]; } -const ToggleCharts = ({ +const ToggleCharts: FC = ({ handleChange, chartOptions, onMouseLeave, onMouseEnter, -}: ToggleChartsProps) => { +}) => { return ( {elem.title} - {elem.amount ? : 0} + {elem.amount ? : 0} {elem.name === 'totalTransactionAmount' && elem.isAreaChart && ( { + return useQuery({ + queryFn: async () => { + const { data } = await httpClient.get(apiPaths.generalStats.path); + + const validResponse = validateResponse(data, generalStatsResponseSchema); + + return validResponse; + }, + queryKey: ['useGeneralStats'], + }); +}; + +export default useGeneralStats; diff --git a/packages/apps/dashboard/client/src/features/home/api/useHcaptchaGeneralStats.ts b/packages/apps/dashboard/client/src/features/home/api/useHcaptchaGeneralStats.ts new file mode 100644 index 0000000000..afd902db3f --- /dev/null +++ b/packages/apps/dashboard/client/src/features/home/api/useHcaptchaGeneralStats.ts @@ -0,0 +1,25 @@ +import { useQuery } from '@tanstack/react-query'; + +import apiPaths from '@/shared/api/apiPaths'; +import httpClient from '@/shared/api/httpClient'; +import validateResponse from '@/shared/lib/validateResponse'; + +import { hcaptchaGeneralStatsResponseSchema } from '../model/hcaptchaGeneralStats'; + +const useHcaptchaGeneralStats = () => { + return useQuery({ + queryFn: async () => { + const { data } = await httpClient.get(apiPaths.hcaptchaGeneralStats.path); + + const validResponse = validateResponse( + data, + hcaptchaGeneralStatsResponseSchema + ); + + return validResponse; + }, + queryKey: ['useHcaptchaGeneralStats'], + }); +}; + +export default useHcaptchaGeneralStats; diff --git a/packages/apps/dashboard/client/src/features/home/model/generalStats.ts b/packages/apps/dashboard/client/src/features/home/model/generalStats.ts new file mode 100644 index 0000000000..367015e609 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/home/model/generalStats.ts @@ -0,0 +1,8 @@ +import { z } from 'zod'; + +export const generalStatsResponseSchema = z.object({ + totalHolders: z.number(), + totalTransactions: z.number(), +}); + +export type GeneralStats = z.infer; diff --git a/packages/apps/dashboard/client/src/features/home/model/hcaptchaGeneralStats.ts b/packages/apps/dashboard/client/src/features/home/model/hcaptchaGeneralStats.ts new file mode 100644 index 0000000000..28e0722769 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/home/model/hcaptchaGeneralStats.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; + +export const hcaptchaGeneralStatsResponseSchema = z.object({ + solved: z.number(), +}); + +export type HcaptchaGeneralStats = z.infer< + typeof hcaptchaGeneralStatsResponseSchema +>; diff --git a/packages/apps/dashboard/client/src/pages/Home/HMTPrice.tsx b/packages/apps/dashboard/client/src/features/home/ui/HmtPrice.tsx similarity index 69% rename from packages/apps/dashboard/client/src/pages/Home/HMTPrice.tsx rename to packages/apps/dashboard/client/src/features/home/ui/HmtPrice.tsx index 0d7236c038..5adbc00b5f 100644 --- a/packages/apps/dashboard/client/src/pages/Home/HMTPrice.tsx +++ b/packages/apps/dashboard/client/src/features/home/ui/HmtPrice.tsx @@ -1,10 +1,10 @@ import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; -import { useHMTPrice } from '../../services/api/use-hmt-price'; +import useHmtPrice from '@/shared/api/useHmtPrice'; -const HMTPrice = () => { - const { data, isError, isPending, isSuccess } = useHMTPrice(); +const HmtPrice = () => { + const { data, isError, isPending, isSuccess } = useHmtPrice(); return ( @@ -18,4 +18,4 @@ const HMTPrice = () => { ); }; -export default HMTPrice; +export default HmtPrice; diff --git a/packages/apps/dashboard/client/src/pages/Home/Holders.tsx b/packages/apps/dashboard/client/src/features/home/ui/Holders.tsx similarity index 70% rename from packages/apps/dashboard/client/src/pages/Home/Holders.tsx rename to packages/apps/dashboard/client/src/features/home/ui/Holders.tsx index 0fc3d025f8..ed62824cce 100644 --- a/packages/apps/dashboard/client/src/pages/Home/Holders.tsx +++ b/packages/apps/dashboard/client/src/features/home/ui/Holders.tsx @@ -1,8 +1,9 @@ import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; -import { FormatNumber } from '@/components/Home/FormatNumber'; -import { useGeneralStats } from '@/services/api/use-general-stats'; +import FormattedNumber from '@/shared/ui/FormattedNumber'; + +import useGeneralStats from '../api/useGeneralStats'; const Holders = () => { const { data, isSuccess, isPending, isError } = useGeneralStats(); @@ -11,7 +12,7 @@ const Holders = () => { Holders - {isSuccess && } + {isSuccess && } {isPending && '...'} {isError && 'No data'} diff --git a/packages/apps/dashboard/client/src/pages/Home/TotalNumberOfTasks.tsx b/packages/apps/dashboard/client/src/features/home/ui/TotalNumberOfTasks.tsx similarity index 71% rename from packages/apps/dashboard/client/src/pages/Home/TotalNumberOfTasks.tsx rename to packages/apps/dashboard/client/src/features/home/ui/TotalNumberOfTasks.tsx index 83783a3a35..715d56712c 100644 --- a/packages/apps/dashboard/client/src/pages/Home/TotalNumberOfTasks.tsx +++ b/packages/apps/dashboard/client/src/features/home/ui/TotalNumberOfTasks.tsx @@ -1,8 +1,9 @@ import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; -import { FormatNumber } from '@/components/Home/FormatNumber'; -import { useHcaptchaGeneralStats } from '@/services/api/use-hcaptcha-general-stats'; +import FormattedNumber from '@/shared/ui/FormattedNumber'; + +import useHcaptchaGeneralStats from '../api/useHcaptchaGeneralStats'; const TotalNumberOfTasks = () => { const { data, isError, isPending, isSuccess } = useHcaptchaGeneralStats(); @@ -11,7 +12,7 @@ const TotalNumberOfTasks = () => { Total Number of Tasks - {isSuccess && } + {isSuccess && } {isPending && '...'} {isError && 'No data'} diff --git a/packages/apps/dashboard/client/src/pages/Home/TotalTransactions.tsx b/packages/apps/dashboard/client/src/features/home/ui/TotalTransactions.tsx similarity index 71% rename from packages/apps/dashboard/client/src/pages/Home/TotalTransactions.tsx rename to packages/apps/dashboard/client/src/features/home/ui/TotalTransactions.tsx index 3e2959c3ed..5bd9a31a0c 100644 --- a/packages/apps/dashboard/client/src/pages/Home/TotalTransactions.tsx +++ b/packages/apps/dashboard/client/src/features/home/ui/TotalTransactions.tsx @@ -1,8 +1,9 @@ import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; -import { FormatNumber } from '@/components/Home/FormatNumber'; -import { useGeneralStats } from '@/services/api/use-general-stats'; +import FormattedNumber from '@/shared/ui/FormattedNumber'; + +import useGeneralStats from '../api/useGeneralStats'; const TotalTransactions = () => { const { data, isError, isPending, isSuccess } = useGeneralStats(); @@ -11,7 +12,7 @@ const TotalTransactions = () => { Total Transactions - {isSuccess && } + {isSuccess && } {isPending && '...'} {isError && 'No data'} diff --git a/packages/apps/dashboard/client/src/features/leaderboard/api/useLeaderboardDetails.ts b/packages/apps/dashboard/client/src/features/leaderboard/api/useLeaderboardDetails.ts new file mode 100644 index 0000000000..6c2e3a4457 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/leaderboard/api/useLeaderboardDetails.ts @@ -0,0 +1,28 @@ +import { useQuery } from '@tanstack/react-query'; + +import apiPaths from '@/shared/api/apiPaths'; +import httpClient from '@/shared/api/httpClient'; +import validateResponse from '@/shared/lib/validateResponse'; + +import { leaderboardResponseSchema } from '../model/leaderboardSchema'; + +const useLeaderboardDetails = (chainId: number, first?: number) => { + return useQuery({ + queryFn: async () => { + if (chainId === -1) { + return []; + } + + const { data } = await httpClient.get(apiPaths.leaderboardDetails.path, { + params: { chainId, first }, + }); + + const validResponse = validateResponse(data, leaderboardResponseSchema); + + return validResponse; + }, + queryKey: ['useLeaderboardDetails', chainId, first], + }); +}; + +export default useLeaderboardDetails; diff --git a/packages/apps/dashboard/client/src/features/leaderboard/index.ts b/packages/apps/dashboard/client/src/features/leaderboard/index.ts new file mode 100644 index 0000000000..9959a98e9f --- /dev/null +++ b/packages/apps/dashboard/client/src/features/leaderboard/index.ts @@ -0,0 +1 @@ +export { default } from './ui/Leaderboard'; diff --git a/packages/apps/dashboard/client/src/features/leaderboard/model/leaderboardSchema.ts b/packages/apps/dashboard/client/src/features/leaderboard/model/leaderboardSchema.ts new file mode 100644 index 0000000000..03bb6609f7 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/leaderboard/model/leaderboardSchema.ts @@ -0,0 +1,48 @@ +import { z } from 'zod'; + +export const reputationSchema = z.unknown().transform((value) => { + try { + const knownReputation = z + .union([z.literal('Low'), z.literal('Medium'), z.literal('High')]) + .parse(value); + + return knownReputation; + } catch (error) { + console.error(error); + return 'Unknown'; + } +}); + +export type Reputation = z.infer; + +const leaderboardEntity = z.object({ + address: z.string(), + role: z.string(), + amountStaked: z + .string() + .transform((value, ctx) => { + const valueAsNumber = Number(value); + + if (Number.isNaN(valueAsNumber)) { + ctx.addIssue({ + path: ['amountStaked'], + code: z.ZodIssueCode.custom, + }); + } + + return valueAsNumber / 10 ** 18; + }) + .nullable(), + reputation: reputationSchema, + fee: z.number().nullable(), + jobTypes: z.array(z.string()).nullable(), + url: z.string().nullable(), + website: z.string().nullable(), + chainId: z.number(), + name: z.string().nullable(), + category: z.string().nullable(), +}); + +export const leaderboardResponseSchema = z.array(leaderboardEntity); +export type LeaderboardEntity = z.infer; +export type LeaderboardData = z.infer; diff --git a/packages/apps/dashboard/client/src/features/leaderboard/store/useLeaderboardFiltersStore.ts b/packages/apps/dashboard/client/src/features/leaderboard/store/useLeaderboardFiltersStore.ts new file mode 100644 index 0000000000..7b8d2b28c5 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/leaderboard/store/useLeaderboardFiltersStore.ts @@ -0,0 +1,15 @@ +import { create } from 'zustand'; + +type LeaderboardFiltersStore = { + chainId: number; + setChainId: (chainId: number) => void; +}; + +const useLeaderboardFiltersStore = create((set) => ({ + chainId: -1, + setChainId: (chainId) => { + set({ chainId }); + }, +})); + +export default useLeaderboardFiltersStore; diff --git a/packages/apps/dashboard/client/src/features/leaderboard/ui/AddressCell.tsx b/packages/apps/dashboard/client/src/features/leaderboard/ui/AddressCell.tsx new file mode 100644 index 0000000000..f2935aa8fa --- /dev/null +++ b/packages/apps/dashboard/client/src/features/leaderboard/ui/AddressCell.tsx @@ -0,0 +1,22 @@ +import { FC } from 'react'; + +import { ChainId } from '@human-protocol/sdk'; +import Box from '@mui/material/Box'; + +import AbbreviateClipboard from '@/shared/ui/AbbreviateClipboard'; + +type Props = { + chainId: ChainId; + address: string; +}; + +const AddressCell: FC = ({ chainId, address }) => ( + + + +); + +export default AddressCell; diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/components/CategoryCell.tsx b/packages/apps/dashboard/client/src/features/leaderboard/ui/CategoryCell.tsx similarity index 75% rename from packages/apps/dashboard/client/src/features/Leaderboard/components/CategoryCell.tsx rename to packages/apps/dashboard/client/src/features/leaderboard/ui/CategoryCell.tsx index 92392ed41f..aff8549534 100644 --- a/packages/apps/dashboard/client/src/features/Leaderboard/components/CategoryCell.tsx +++ b/packages/apps/dashboard/client/src/features/leaderboard/ui/CategoryCell.tsx @@ -1,19 +1,11 @@ -import { Chip, Box } from '@mui/material'; +import { FC } from 'react'; -interface CategoryCellProps { - value?: string; -} +import Box from '@mui/material/Box'; +import Chip from '@mui/material/Chip'; -export const CategoryCell = ({ value }: CategoryCellProps) => - value?.length ? ( - - - - ) : null; +type CategoryCellProps = { + value?: string; +}; const getCategoryLabel = (category: string) => { switch (category) { @@ -36,3 +28,16 @@ const getCategoryColor = (category: string) => { return 'default'; } }; + +const CategoryCell: FC = ({ value }) => + value?.length ? ( + + + + ) : null; + +export default CategoryCell; diff --git a/packages/apps/dashboard/client/src/features/leaderboard/ui/ChainCell.tsx b/packages/apps/dashboard/client/src/features/leaderboard/ui/ChainCell.tsx new file mode 100644 index 0000000000..028b9dcaf2 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/leaderboard/ui/ChainCell.tsx @@ -0,0 +1,29 @@ +import { FC } from 'react'; + +import { ChainId } from '@human-protocol/sdk'; +import Typography from '@mui/material/Typography'; + +import { getNetwork } from '@/shared/lib/networks'; +import { NetworkIcon } from '@/shared/ui/NetworkIcon'; + +type Props = { + chainId: ChainId; +}; + +const ChainCell: FC = ({ chainId }) => ( + + + {getNetwork(chainId)?.name} + +); + +export default ChainCell; diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/components/DataGridWrapper.tsx b/packages/apps/dashboard/client/src/features/leaderboard/ui/DataGridWrapper.tsx similarity index 84% rename from packages/apps/dashboard/client/src/features/Leaderboard/components/DataGridWrapper.tsx rename to packages/apps/dashboard/client/src/features/leaderboard/ui/DataGridWrapper.tsx index 16ce2f550d..bc71c3b905 100644 --- a/packages/apps/dashboard/client/src/features/Leaderboard/components/DataGridWrapper.tsx +++ b/packages/apps/dashboard/client/src/features/leaderboard/ui/DataGridWrapper.tsx @@ -1,22 +1,23 @@ -import { Box, Typography } from '@mui/material'; +import { FC } from 'react'; + +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; import { DataGrid } from '@mui/x-data-grid'; -import Loader from '@/components/Loader'; -import { LeaderBoardData } from '@/services/api/use-leaderboard-details'; -import { handleErrorMessage } from '@/services/handle-error-message'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; +import handleErrorMessage from '@/shared/lib/handleErrorMessage'; +import Loader from '@/shared/ui/Loader'; -import useDataGrid from '../hooks/useDataGrid'; +import { LeaderboardData } from '../model/leaderboardSchema'; +import useDataGrid from '../ui/useDataGrid'; -export const DataGridWrapper = ({ - data = [], - status, - error, -}: { - data: LeaderBoardData | undefined; +type Props = { + data: LeaderboardData | undefined; status: 'success' | 'error' | 'pending'; error: unknown; -}) => { +}; + +const DataGridWrapper: FC = ({ data = [], status, error }) => { const { columns, rows } = useDataGrid(data); const isMobile = useIsMobile(); @@ -117,3 +118,5 @@ export const DataGridWrapper = ({ ); }; + +export default DataGridWrapper; diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/index.tsx b/packages/apps/dashboard/client/src/features/leaderboard/ui/Leaderboard.tsx similarity index 66% rename from packages/apps/dashboard/client/src/features/Leaderboard/index.tsx rename to packages/apps/dashboard/client/src/features/leaderboard/ui/Leaderboard.tsx index 75e42c0460..baea7f9a8b 100644 --- a/packages/apps/dashboard/client/src/features/Leaderboard/index.tsx +++ b/packages/apps/dashboard/client/src/features/leaderboard/ui/Leaderboard.tsx @@ -4,25 +4,22 @@ import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import { useNavigate } from 'react-router-dom'; -import { LeaderBoardData } from '@/services/api/use-leaderboard-details'; +import useLeaderboardDetails from '../api/useLeaderboardDetails'; +import useLeaderboardFiltersStore from '../store/useLeaderboardFiltersStore'; -import { DataGridWrapper } from './components/DataGridWrapper'; -import { SelectNetwork } from './components/SelectNetwork'; +import DataGridWrapper from './DataGridWrapper'; +import SelectNetwork from './SelectNetwork'; type Props = { - data: LeaderBoardData | undefined; - status: 'success' | 'error' | 'pending'; - error: unknown; viewAllBanner?: boolean; + first?: number; }; -export const Leaderboard: FC = ({ - data, - status, - error, - viewAllBanner, -}) => { +const Leaderboard: FC = ({ viewAllBanner, first }) => { const navigate = useNavigate(); + const { chainId } = useLeaderboardFiltersStore(); + const { data, status, error } = useLeaderboardDetails(chainId, first); + return ( = ({ fullWidth sx={{ borderColor: 'primary.main', - cursor: 'pointer', }} onClick={() => navigate('/leaderboard')} > @@ -58,3 +54,5 @@ export const Leaderboard: FC = ({ ); }; + +export default Leaderboard; diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/components/RoleCell.tsx b/packages/apps/dashboard/client/src/features/leaderboard/ui/RoleCell.tsx similarity index 72% rename from packages/apps/dashboard/client/src/features/Leaderboard/components/RoleCell.tsx rename to packages/apps/dashboard/client/src/features/leaderboard/ui/RoleCell.tsx index e2db9ec66b..f65a2a7da4 100644 --- a/packages/apps/dashboard/client/src/features/Leaderboard/components/RoleCell.tsx +++ b/packages/apps/dashboard/client/src/features/leaderboard/ui/RoleCell.tsx @@ -1,18 +1,29 @@ +import { FC, PropsWithChildren } from 'react'; + import { Launch as LaunchIcon } from '@mui/icons-material'; -import { Box, Typography } from '@mui/material'; +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; import { Link } from 'react-router-dom'; -import { CaseConverter } from '@/utils/case-converter'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; - +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; +import convertSnakeToHumanReadable from '@/shared/lib/convertSnakeToHumanReadable'; +import EntityIcon from '@/shared/ui/EntityIcon'; -import { EntityIcon } from './EntityIcon'; +type WrapperProps = { + websiteUrl?: string; +}; +type Props = { + rank: number; + role: string; + websiteUrl?: string; + name?: string; +}; -const Wrapper = ({ - children, +const Wrapper: FC> = ({ websiteUrl, -}: React.PropsWithChildren<{ websiteUrl?: string }>) => { + children, +}) => { return websiteUrl ? ( { +const RoleCell: FC = ({ rank, role, websiteUrl, name }) => { const isMobile = useIsMobile(); - const humanReadableRole = CaseConverter.convertSnakeToHumanReadable(role); + const humanReadableRole = convertSnakeToHumanReadable(role); const formattedName = name ? name.split(' ')[0] : null; return ( @@ -74,3 +75,5 @@ export const RoleCell = ({ ); }; + +export default RoleCell; diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/components/SelectNetwork.tsx b/packages/apps/dashboard/client/src/features/leaderboard/ui/SelectNetwork.tsx similarity index 83% rename from packages/apps/dashboard/client/src/features/Leaderboard/components/SelectNetwork.tsx rename to packages/apps/dashboard/client/src/features/leaderboard/ui/SelectNetwork.tsx index 0ff63569cd..555c9a8b3a 100644 --- a/packages/apps/dashboard/client/src/features/Leaderboard/components/SelectNetwork.tsx +++ b/packages/apps/dashboard/client/src/features/leaderboard/ui/SelectNetwork.tsx @@ -7,20 +7,16 @@ import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import Select, { SelectChangeEvent } from '@mui/material/Select'; -import { NetworkIcon } from '@/components/NetworkIcon'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; -import { useFilteredNetworks } from '@/utils/hooks/use-filtered-networks'; -import { useLeaderboardSearch } from '@/utils/hooks/use-leaderboard-search'; +import useFilteredNetworks from '@/shared/api/useFilteredNetworks'; +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; +import { NetworkIcon } from '@/shared/ui/NetworkIcon'; +import useLeaderboardFiltersStore from '../store/useLeaderboardFiltersStore'; - -export const SelectNetwork = () => { - const { - setChainId, - filterParams: { chainId }, - } = useLeaderboardSearch(); - +const SelectNetwork = () => { + const { chainId, setChainId } = useLeaderboardFiltersStore(); const { filteredNetworks, isLoading } = useFilteredNetworks(); + const isMobile = useIsMobile(); useEffect(() => { if (chainId === -1 && filteredNetworks.length > 0) { @@ -28,8 +24,6 @@ export const SelectNetwork = () => { } }, [chainId, filteredNetworks, setChainId]); - const isMobile = useIsMobile(); - const handleChange = (event: SelectChangeEvent) => { const value = Number(event.target.value); setChainId(value); diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/components/TextCell.tsx b/packages/apps/dashboard/client/src/features/leaderboard/ui/TextCell.tsx similarity index 52% rename from packages/apps/dashboard/client/src/features/Leaderboard/components/TextCell.tsx rename to packages/apps/dashboard/client/src/features/leaderboard/ui/TextCell.tsx index 0daad03b1a..a3f78f9ebf 100644 --- a/packages/apps/dashboard/client/src/features/Leaderboard/components/TextCell.tsx +++ b/packages/apps/dashboard/client/src/features/leaderboard/ui/TextCell.tsx @@ -1,10 +1,12 @@ -import { Typography } from '@mui/material'; +import { FC } from 'react'; -interface TextCellProps { +import Typography from '@mui/material/Typography'; + +type TextCellProps = { value: string; -} +}; -export const TextCell = ({ value }: TextCellProps) => ( +const TextCell: FC = ({ value }) => ( ( {value} ); + +export default TextCell; diff --git a/packages/apps/dashboard/client/src/features/Leaderboard/hooks/useDataGrid.tsx b/packages/apps/dashboard/client/src/features/leaderboard/ui/useDataGrid.tsx similarity index 83% rename from packages/apps/dashboard/client/src/features/Leaderboard/hooks/useDataGrid.tsx rename to packages/apps/dashboard/client/src/features/leaderboard/ui/useDataGrid.tsx index 01117644a2..f2e2f630f2 100644 --- a/packages/apps/dashboard/client/src/features/Leaderboard/hooks/useDataGrid.tsx +++ b/packages/apps/dashboard/client/src/features/leaderboard/ui/useDataGrid.tsx @@ -1,21 +1,22 @@ import { useMemo } from 'react'; import HelpOutlineIcon from '@mui/icons-material/HelpOutline'; -import { Box, Typography } from '@mui/material'; +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid'; -import CustomTooltip from '@/components/CustomTooltip'; -import { LeaderBoardData } from '@/services/api/use-leaderboard-details'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; -import { useLeaderboardSearch } from '@/utils/hooks/use-leaderboard-search'; +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; +import CustomTooltip from '@/shared/ui/CustomTooltip'; -import { AddressCell } from '../components/AddressCell'; -import { CategoryCell } from '../components/CategoryCell'; -import { ChainCell } from '../components/ChainCell'; -import { RoleCell } from '../components/RoleCell'; -import { SelectNetwork } from '../components/SelectNetwork'; -import { TextCell } from '../components/TextCell'; +import { LeaderboardData } from '../model/leaderboardSchema'; +import useLeaderboardFiltersStore from '../store/useLeaderboardFiltersStore'; +import AddressCell from './AddressCell'; +import CategoryCell from './CategoryCell'; +import ChainCell from './ChainCell'; +import RoleCell from './RoleCell'; +import SelectNetwork from './SelectNetwork'; +import TextCell from './TextCell'; const InfoTooltip = ({ title }: { title: string }) => ( @@ -27,11 +28,8 @@ const InfoTooltip = ({ title }: { title: string }) => ( ); -const useDataGrid = (data: LeaderBoardData) => { - const { - filterParams: { chainId }, - } = useLeaderboardSearch(); - +const useDataGrid = (data: LeaderboardData) => { + const { chainId } = useLeaderboardFiltersStore(); const isMobile = useIsMobile(); const formattedData = useMemo(() => { diff --git a/packages/apps/dashboard/client/src/features/searchResults/api/useAddressDetails.ts b/packages/apps/dashboard/client/src/features/searchResults/api/useAddressDetails.ts new file mode 100644 index 0000000000..547adb1331 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/api/useAddressDetails.ts @@ -0,0 +1,29 @@ +import { useQuery } from '@tanstack/react-query'; + +import apiPaths from '@/shared/api/apiPaths'; +import httpClient from '@/shared/api/httpClient'; +import validateResponse from '@/shared/lib/validateResponse'; + +import { addressDetailsResponseSchema } from '../model/addressDetailsSchema'; + +const useAddressDetails = (chainId: number, address: string) => { + return useQuery({ + queryFn: async () => { + const { data } = await httpClient.get( + `${apiPaths.addressDetails.path}/${address}`, + { params: { chainId: chainId || -1 } } + ); + + const validResponse = validateResponse( + data, + addressDetailsResponseSchema + ); + + return validResponse; + }, + queryKey: ['useAddressDetails', address, chainId], + enabled: !!chainId && !!address, + }); +}; + +export default useAddressDetails; diff --git a/packages/apps/dashboard/client/src/features/searchResults/api/useEscrowDetails.ts b/packages/apps/dashboard/client/src/features/searchResults/api/useEscrowDetails.ts new file mode 100644 index 0000000000..2c946b1b69 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/api/useEscrowDetails.ts @@ -0,0 +1,79 @@ +import { useQuery } from '@tanstack/react-query'; + +import apiPaths from '@/shared/api/apiPaths'; +import httpClient from '@/shared/api/httpClient'; +import validateResponse from '@/shared/lib/validateResponse'; + +import { paginatedEscrowDetailsSchema } from '../model/escrowDetailsSchema'; + +type Props = { + role: string | null; + chainId: number; + address: string; + page: number; + lastPageIndex: number | undefined; + setLastPageIndex: (lastPageIndex: number | undefined) => void; + params: { + skip: number; + first: number; + }; +}; + +const useEscrowDetails = ({ + role, + chainId, + address, + page, + lastPageIndex, + setLastPageIndex, + params, +}: Props) => { + const dto = { + chainId, + role, + skip: params.skip, + first: params.first, + }; + + return useQuery({ + queryFn: async () => { + const { data } = await httpClient.get( + `${apiPaths.escrowDetails.path}/${address}`, + { params: dto } + ); + + const validResponse = validateResponse( + data, + paginatedEscrowDetailsSchema + ); + + // check if last page + if (lastPageIndex === undefined) { + const { data: lastPageCheckData } = await httpClient.get( + `${apiPaths.escrowDetails.path}/${address}`, + { + params: { + ...dto, + skip: dto.skip + validResponse.results.length, + first: 1, + }, + } + ); + const validLastPageCheckData = validateResponse( + lastPageCheckData, + paginatedEscrowDetailsSchema + ); + + if (validLastPageCheckData.results.length === 0) { + setLastPageIndex(page + 1); + } + } + + return validResponse; + }, + queryKey: ['useEscrowDetails', address, dto], + enabled: !!chainId && !!address, + }); +}; + +export default useEscrowDetails; diff --git a/packages/apps/dashboard/client/src/features/searchResults/api/useKvStoreData.ts b/packages/apps/dashboard/client/src/features/searchResults/api/useKvStoreData.ts new file mode 100644 index 0000000000..056bb530ee --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/api/useKvStoreData.ts @@ -0,0 +1,26 @@ +import { useQuery } from '@tanstack/react-query'; + +import apiPaths from '@/shared/api/apiPaths'; +import httpClient from '@/shared/api/httpClient'; +import validateResponse from '@/shared/lib/validateResponse'; + +import { kvstoreDataSchema } from '../model/kvStoreDataSchema'; + +const useKvstoreData = (chainId: number, address: string) => { + return useQuery({ + queryKey: ['kvstoreData', address], + queryFn: async () => { + const { data } = await httpClient.get( + `${apiPaths.kvstore.path}/${address}`, + { params: { chain_id: chainId || -1 } } + ); + + const validResponse = validateResponse(data, kvstoreDataSchema); + + return validResponse; + }, + enabled: !!chainId && !!address, + }); +}; + +export default useKvstoreData; diff --git a/packages/apps/dashboard/client/src/features/searchResults/api/useTransactionDetails.ts b/packages/apps/dashboard/client/src/features/searchResults/api/useTransactionDetails.ts new file mode 100644 index 0000000000..eee96a4a69 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/api/useTransactionDetails.ts @@ -0,0 +1,78 @@ +import { useQuery } from '@tanstack/react-query'; + +import apiPaths from '@/shared/api/apiPaths'; +import httpClient from '@/shared/api/httpClient'; +import validateResponse from '@/shared/lib/validateResponse'; + +import { paginatedTransactionDetailsSchema } from '../model/transactionDetailsSchema'; + +type Props = { + chainId: number; + address: string; + page: number; + lastPageIndex: number | undefined; + setLastPageIndex: (lastPageIndex: number | undefined) => void; + params: { + skip: number; + first: number; + }; +}; + +const useTransactionDetails = ({ + chainId, + address, + page, + lastPageIndex, + setLastPageIndex, + params, +}: Props) => { + const dto = { + chainId, + skip: params.skip, + first: params.first, + }; + + return useQuery({ + queryFn: async () => { + const { data } = await httpClient.get( + `${apiPaths.transactionDetails.path}/${address}`, + { + params: dto, + } + ); + + const validResponse = validateResponse( + data, + paginatedTransactionDetailsSchema + ); + + // check if last page + if (lastPageIndex === undefined) { + const { data: lastPageCheckData } = await httpClient.get( + `${apiPaths.transactionDetails.path}/${address}`, + { + params: { + ...dto, + skip: dto.skip + validResponse.results.length, + first: 1, + }, + } + ); + const validLastPageCheckData = validateResponse( + lastPageCheckData, + paginatedTransactionDetailsSchema + ); + + if (validLastPageCheckData.results.length === 0) { + setLastPageIndex(page + 1); + } + } + + return validResponse; + }, + queryKey: ['useTransactionDetails', address, dto], + enabled: !!chainId && !!address, + }); +}; + +export default useTransactionDetails; diff --git a/packages/apps/dashboard/client/src/features/searchResults/hooks/usePagination.ts b/packages/apps/dashboard/client/src/features/searchResults/hooks/usePagination.ts new file mode 100644 index 0000000000..342dc03695 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/hooks/usePagination.ts @@ -0,0 +1,66 @@ +import { useCallback, useState } from 'react'; + +type PaginationState = { + params: { + first: number; + skip: number; + }; + pagination: { + page: number; + pageSize: number; + lastPageIndex?: number; + }; + setNextPage: () => void; + setPrevPage: () => void; + setPageSize: (pageSize: number) => void; + setLastPageIndex: (lastPageIndex: number | undefined) => void; +}; + +const INITIAL_PAGE_SIZE = 10; + +const usePagination = (): PaginationState => { + const [page, setPage] = useState(0); + const [pageSize, setPageSize] = useState(INITIAL_PAGE_SIZE); + const [lastPageIndex, setLastPageIndex] = useState(); + + const skip = page * pageSize; + + const setNextPage = useCallback(() => { + setPage((prev) => prev + 1); + }, []); + + const setPrevPage = useCallback(() => { + setPage((prev) => Math.max(0, prev - 1)); + }, []); + + const handleSetPageSize = useCallback((newPageSize: number) => { + setPageSize(newPageSize); + setPage(0); + setLastPageIndex(undefined); + }, []); + + const handleSetLastPageIndex = useCallback( + (newLastPageIndex: number | undefined) => { + setLastPageIndex(newLastPageIndex); + }, + [] + ); + + return { + params: { + first: pageSize, + skip, + }, + pagination: { + page, + pageSize, + lastPageIndex, + }, + setNextPage, + setPrevPage, + setPageSize: handleSetPageSize, + setLastPageIndex: handleSetLastPageIndex, + }; +}; + +export default usePagination; diff --git a/packages/apps/dashboard/client/src/features/searchResults/index.ts b/packages/apps/dashboard/client/src/features/searchResults/index.ts new file mode 100644 index 0000000000..5d2cfb86b4 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/index.ts @@ -0,0 +1 @@ +export { default } from './ui/SearchResults'; diff --git a/packages/apps/dashboard/client/src/services/api/use-address-details.tsx b/packages/apps/dashboard/client/src/features/searchResults/model/addressDetailsSchema.ts similarity index 74% rename from packages/apps/dashboard/client/src/services/api/use-address-details.tsx rename to packages/apps/dashboard/client/src/features/searchResults/model/addressDetailsSchema.ts index 179bfd2641..42d7f3881d 100644 --- a/packages/apps/dashboard/client/src/services/api/use-address-details.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/model/addressDetailsSchema.ts @@ -1,13 +1,7 @@ import { Role } from '@human-protocol/sdk'; -import { useQuery } from '@tanstack/react-query'; import { z } from 'zod'; -import { reputationSchema } from '@/services/api/use-leaderboard-details'; -import { useWalletSearch } from '@/utils/hooks/use-wallet-search'; - -import { apiPaths } from '../api-paths'; -import { httpService } from '../http-service'; -import { validateResponse } from '../validate-response'; +import { reputationSchema } from '@/features/leaderboard/model/leaderboardSchema'; const transformOptionalTokenAmount = ( value: string | undefined | null, @@ -70,7 +64,7 @@ const escrowSchema = z.object({ finalResultsUrl: z.string().nullable(), }); -export type AddressDetailsEscrowSchema = z.infer; +export type AddressDetailsEscrow = z.infer; const operatorSchema = z.object({ chainId: z.number(), @@ -101,32 +95,10 @@ const operatorSchema = z.object({ export type AddressDetailsOperator = z.infer; -const addressDetailsResponseSchema = z.object({ +export const addressDetailsResponseSchema = z.object({ wallet: z.optional(walletSchema), escrow: z.optional(escrowSchema), operator: z.optional(operatorSchema), }); export type AddressDetails = z.infer; - -export function useAddressDetails() { - const { filterParams } = useWalletSearch(); - - return useQuery({ - queryFn: async () => { - const address = filterParams.address || '0x0'; - const { data } = await httpService.get( - `${apiPaths.addressDetails.path}/${address}`, - { params: { chainId: filterParams.chainId || -1 } } - ); - - const validResponse = validateResponse( - data, - addressDetailsResponseSchema - ); - - return validResponse; - }, - queryKey: ['useAddressDetails', filterParams.address, filterParams.chainId], - }); -} diff --git a/packages/apps/dashboard/client/src/features/searchResults/model/escrowDetailsSchema.ts b/packages/apps/dashboard/client/src/features/searchResults/model/escrowDetailsSchema.ts new file mode 100644 index 0000000000..2299f070b5 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/model/escrowDetailsSchema.ts @@ -0,0 +1,21 @@ +import { z } from 'zod'; + +const escrowDetailsSchema = z.object({ + chainId: z.number(), + address: z.string(), + status: z.string(), +}); + +export type EscrowDetails = z.infer; + +export const paginatedEscrowDetailsSchema = z.object({ + address: z.string(), + chainId: z.number(), + first: z.number(), + skip: z.number(), + results: z.array(escrowDetailsSchema), +}); + +export type PaginatedEscrowDetails = z.infer< + typeof paginatedEscrowDetailsSchema +>; diff --git a/packages/apps/dashboard/client/src/features/searchResults/model/kvStoreDataSchema.ts b/packages/apps/dashboard/client/src/features/searchResults/model/kvStoreDataSchema.ts new file mode 100644 index 0000000000..35c8f60378 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/model/kvStoreDataSchema.ts @@ -0,0 +1,10 @@ +import { z } from 'zod'; + +export const kvstoreDataSchema = z.array( + z.object({ + key: z.string(), + value: z.string(), + }) +); + +export type KvstoreData = z.infer; diff --git a/packages/apps/dashboard/client/src/features/searchResults/model/transactionDetailsSchema.ts b/packages/apps/dashboard/client/src/features/searchResults/model/transactionDetailsSchema.ts new file mode 100644 index 0000000000..810967e0f2 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/model/transactionDetailsSchema.ts @@ -0,0 +1,36 @@ +import { z } from 'zod'; + +const internalTransactionSchema = z.object({ + from: z.string(), + to: z.string(), + value: z.string(), + method: z.string(), + receiver: z.string().nullable(), + escrow: z.string().nullable(), + token: z.string().nullable(), +}); + +const transactionDetailsSchema = z.object({ + txHash: z.string(), + method: z.string(), + from: z.string(), + to: z.string(), + receiver: z.string().nullable(), + block: z.number(), + value: z.string(), + internalTransactions: z.array(internalTransactionSchema), +}); + +export type TransactionDetails = z.infer; + +export const paginatedTransactionDetailsSchema = z.object({ + address: z.string(), + chainId: z.number(), + first: z.number(), + skip: z.number(), + results: z.array(transactionDetailsSchema), +}); + +export type PaginatedTransactionDetails = z.infer< + typeof paginatedTransactionDetailsSchema +>; diff --git a/packages/apps/dashboard/client/src/components/Clipboard/Clipboard.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/Clipboard.tsx similarity index 89% rename from packages/apps/dashboard/client/src/components/Clipboard/Clipboard.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/Clipboard.tsx index 7601d81cf3..7d4c256570 100644 --- a/packages/apps/dashboard/client/src/components/Clipboard/Clipboard.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/Clipboard.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { FC, useState } from 'react'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import Card from '@mui/material/Card'; @@ -6,13 +6,13 @@ import IconButton from '@mui/material/IconButton'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import CustomTooltip from '@/components/CustomTooltip'; +import CustomTooltip from '@/shared/ui/CustomTooltip'; -interface ClipboardProps { +type ClipboardProps = { value: string; -} +}; -const Clipboard = ({ value }: ClipboardProps) => { +const Clipboard: FC = ({ value }) => { const [tooltipOpen, setTooltipOpen] = useState(false); return ( diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/EscrowAddress/EscrowAddress.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/EscrowAddress.tsx similarity index 90% rename from packages/apps/dashboard/client/src/pages/SearchResults/EscrowAddress/EscrowAddress.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/EscrowAddress.tsx index 73c77b5a1f..8801d5d77a 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/EscrowAddress/EscrowAddress.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/EscrowAddress.tsx @@ -1,15 +1,22 @@ +import { FC } from 'react'; + import Chip from '@mui/material/Chip'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import TitleSectionWrapper from '@/components/SearchResults'; -import SectionWrapper from '@/components/SectionWrapper'; -import { AddressDetailsEscrowSchema } from '@/services/api/use-address-details'; +import SectionWrapper from '@/shared/ui/SectionWrapper'; + +import { AddressDetailsEscrow } from '../model/addressDetailsSchema'; -import HmtBalance from '../HmtBalance'; +import HmtBalance from './HmtBalance'; +import TitleSectionWrapper from './TitleSectionWrapper'; + +type Props = { + data: AddressDetailsEscrow; +}; -const EscrowAddress = ({ - data: { +const EscrowAddress: FC = ({ data }) => { + const { token, balance, factoryAddress, @@ -20,10 +27,7 @@ const EscrowAddress = ({ exchangeOracle, recordingOracle, reputationOracle, - }, -}: { - data: AddressDetailsEscrowSchema; -}) => { + } = data; return ( diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/HmtBalance/index.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/HmtBalance.tsx similarity index 68% rename from packages/apps/dashboard/client/src/pages/SearchResults/HmtBalance/index.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/HmtBalance.tsx index 00c25526e7..aa4f482b53 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/HmtBalance/index.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/HmtBalance.tsx @@ -2,17 +2,17 @@ import { FC } from 'react'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import { NumericFormat } from 'react-number-format'; -import { useHMTPrice } from '@/services/api/use-hmt-price'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; +import useHmtPrice from '@/shared/api/useHmtPrice'; +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; +import FormattedNumber from '@/shared/ui/FormattedNumber'; type Props = { balance?: number | null; }; const HmtBalance: FC = ({ balance }) => { - const { data, isError, isPending } = useHMTPrice(); + const { data, isError, isPending } = useHmtPrice(); const isMobile = useIsMobile(); if (isError) { @@ -30,12 +30,7 @@ const HmtBalance: FC = ({ balance }) => { return ( - + { - const { data, isError, isPending, isSuccess } = useHMTPrice(); + const { data, isError, isPending, isSuccess } = useHmtPrice(); return ( diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/KVStore/index.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/KvStore.tsx similarity index 82% rename from packages/apps/dashboard/client/src/pages/SearchResults/KVStore/index.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/KvStore.tsx index bb16776c85..ea51fc7548 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/KVStore/index.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/KvStore.tsx @@ -1,4 +1,3 @@ - import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; @@ -7,11 +6,14 @@ import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; import Typography from '@mui/material/Typography'; -import SectionWrapper from '@/components/SectionWrapper'; -import useKvstoreData from '@/services/api/use-kvstore-data'; +import useGlobalFiltersStore from '@/shared/store/useGlobalFiltersStore'; +import SectionWrapper from '@/shared/ui/SectionWrapper'; + +import useKvstoreData from '../api/useKvStoreData'; const KVStore = () => { - const { data } = useKvstoreData(); + const { chainId, address } = useGlobalFiltersStore(); + const { data } = useKvstoreData(chainId, address); if (data?.length === 0) { return null; diff --git a/packages/apps/dashboard/client/src/components/NothingFound/NothingFound.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/NothingFound.tsx similarity index 90% rename from packages/apps/dashboard/client/src/components/NothingFound/NothingFound.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/NothingFound.tsx index 724fe89541..0eb637f207 100644 --- a/packages/apps/dashboard/client/src/components/NothingFound/NothingFound.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/NothingFound.tsx @@ -1,9 +1,7 @@ -import { FC } from 'react'; - import Link from '@mui/material/Link'; import Typography from '@mui/material/Typography'; -const NothingFound: FC = () => { +const NothingFound = () => { return ( <> Nothing found :( diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetails.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorAddress.tsx similarity index 79% rename from packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetails.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/OperatorAddress.tsx index cb2d6edd12..9f47bdbbc8 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetails.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorAddress.tsx @@ -1,3 +1,5 @@ +import { FC } from 'react'; + import { Role } from '@human-protocol/sdk'; import Box from '@mui/material/Box'; import Chip from '@mui/material/Chip'; @@ -7,45 +9,30 @@ import ListItem from '@mui/material/ListItem'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import ExchangeOracleIcon from '@/assets/icons/exchange-oracle.svg'; -import JobLauncherIcon from '@/assets/icons/job-launcher.svg'; -import RecordingOracleIcon from '@/assets/icons/recording-oracle.svg'; -import ReputationOracleIcon from '@/assets/icons/reputation-oracle.svg'; -import TitleSectionWrapper from '@/components/SearchResults/TitleSectionWrapper'; -import SectionWrapper from '@/components/SectionWrapper'; -import { env } from '@/helpers/env'; -import { RoleDetailsEscrowsTable } from '@/pages/SearchResults/RoleDetails/RoleDetailsEscrows/RoleDetailsEscrowsTable'; -import { AddressDetailsOperator } from '@/services/api/use-address-details'; +import { env } from '@/shared/config/env'; +import EntityIcon from '@/shared/ui/EntityIcon'; +import SectionWrapper from '@/shared/ui/SectionWrapper'; + +import { AddressDetailsOperator } from '../model/addressDetailsSchema'; -import HmtBalance from '../HmtBalance'; -import HmtPrice from '../HmtPrice'; -import KVStore from '../KVStore'; -import ReputationScore from '../ReputationScore'; -import StakeInfo from '../StakeInfo'; +import HmtBalance from './HmtBalance'; +import HmtPrice from './HmtPrice'; +import KVStore from './KvStore'; +import EscrowsTable from './OperatorEscrows/EscrowsTable'; +import ReputationScore from './ReputationScore'; +import StakeInfo from './StakeInfo'; +import TitleSectionWrapper from './TitleSectionWrapper'; -interface RoleInfoProps { +type RoleInfoProps = { title: string; points: string[]; role: string; -} - -const renderRoleIcon = (role: string | null) => { - if (!role) return null; - - const roleIcons = { - [Role.ReputationOracle]: , - [Role.ExchangeOracle]: , - [Role.JobLauncher]: , - [Role.RecordingOracle]: , - }; - - return roleIcons[role]; }; -const RoleInformation = ({ title, points, role }: RoleInfoProps) => { +const RoleInformation: FC = ({ title, points, role }) => { return ( - {renderRoleIcon(role)} + {title} @@ -120,7 +107,7 @@ const renderRoleDetailsInfo = (role: string | null) => { ); }; -const RoleDetails = ({ data }: { data: AddressDetailsOperator }) => { +const OperatorAddress = ({ data }: { data: AddressDetailsOperator }) => { const { balance, role, @@ -221,8 +208,8 @@ const RoleDetails = ({ data }: { data: AddressDetailsOperator }) => { amountWithdrawable={amountWithdrawable} /> - + ); }; -export default RoleDetails; +export default OperatorAddress; diff --git a/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorEscrows/EscrowsTable.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorEscrows/EscrowsTable.tsx new file mode 100644 index 0000000000..02c973e230 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorEscrows/EscrowsTable.tsx @@ -0,0 +1,82 @@ +import { FC } from 'react'; + +import Table from '@mui/material/Table'; +import TableContainer from '@mui/material/TableContainer'; +import TableFooter from '@mui/material/TableFooter'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import Typography from '@mui/material/Typography'; + +import useGlobalFiltersStore from '@/shared/store/useGlobalFiltersStore'; +import SectionWrapper from '@/shared/ui/SectionWrapper'; + +import useEscrowDetails from '../../api/useEscrowDetails'; +import usePagination from '../../hooks/usePagination'; +import TablePagination from '../TablePagination'; + +import EscrowsTableBody from './EscrowsTableBody'; + +type Props = { + role: string | null; +}; + +const EscrowsTable: FC = ({ role }) => { + const { chainId, address } = useGlobalFiltersStore(); + const { + pagination: { page, pageSize, lastPageIndex }, + params, + setPageSize, + setNextPage, + setPrevPage, + setLastPageIndex, + } = usePagination(); + const { data, isLoading, error } = useEscrowDetails({ + role, + chainId, + address, + page, + lastPageIndex, + params, + setLastPageIndex, + }); + + return ( + + + Escrows + + + + + + + + + + + + +
+
+
+ ); +}; + +export default EscrowsTable; diff --git a/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorEscrows/EscrowsTableBody.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorEscrows/EscrowsTableBody.tsx new file mode 100644 index 0000000000..34cbef9bdd --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorEscrows/EscrowsTableBody.tsx @@ -0,0 +1,72 @@ +import { FC } from 'react'; + +import { TableRow } from '@mui/material'; +import CircularProgress from '@mui/material/CircularProgress'; +import Link from '@mui/material/Link'; +import MuiTableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; + +import handleErrorMessage from '@/shared/lib/handleErrorMessage'; +import useGlobalFiltersStore from '@/shared/store/useGlobalFiltersStore'; + +import { PaginatedEscrowDetails } from '../../model/escrowDetailsSchema'; + +import EscrowsTableBodyContainer from './EscrowsTableBodyContainer'; + +type Props = { + data: PaginatedEscrowDetails | undefined; + isLoading: boolean; + error: Error | null; +}; + +const EscrowsTableBody: FC = ({ data, isLoading, error }) => { + const { chainId } = useGlobalFiltersStore(); + + if (isLoading) { + return ( + + + + ); + } + + if (error) { + return ( + +
{handleErrorMessage(error)}
+
+ ); + } + + if (!data?.results.length) { + return ( + +
No escrows launched yet
+
+ ); + } + + return ( + + {data.results.map((elem, idx) => ( + + + + {elem.address} + + + + ))} + + ); +}; + +export default EscrowsTableBody; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetailsEscrows/tableComponents/EscrowsTableBodyContainer.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorEscrows/EscrowsTableBodyContainer.tsx similarity index 69% rename from packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetailsEscrows/tableComponents/EscrowsTableBodyContainer.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/OperatorEscrows/EscrowsTableBodyContainer.tsx index 9b00b73d4f..fe7f2c329e 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetailsEscrows/tableComponents/EscrowsTableBodyContainer.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/OperatorEscrows/EscrowsTableBodyContainer.tsx @@ -1,11 +1,9 @@ -import { Grid } from '@mui/material'; +import { FC, PropsWithChildren } from 'react'; + +import Grid from '@mui/material/Grid'; import MuiTableBody from '@mui/material/TableBody'; -export const EscrowsTableBodyContainer = ({ - children, -}: { - children: JSX.Element; -}) => { +const EscrowsTableBodyContainer: FC = ({ children }) => { return ( ); }; + +export default EscrowsTableBodyContainer; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/ReputationScore/index.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/ReputationScore.tsx similarity index 95% rename from packages/apps/dashboard/client/src/pages/SearchResults/ReputationScore/index.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/ReputationScore.tsx index 2f2c6f0b8b..6dc9a20c09 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/ReputationScore/index.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/ReputationScore.tsx @@ -11,7 +11,7 @@ type ReputationAttributes = { colors: { title: string; border: string }; }; -export const ReputationScore = ({ reputation }: Props) => { +const ReputationScore = ({ reputation }: Props) => { const theme = useTheme(); const reputationAttributes: Record = { diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/SearchResults.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/SearchResults.tsx similarity index 61% rename from packages/apps/dashboard/client/src/pages/SearchResults/SearchResults.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/SearchResults.tsx index 14ab19de83..e9b30182a3 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/SearchResults.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/SearchResults.tsx @@ -1,30 +1,32 @@ import { useEffect, useState } from 'react'; -import Stack from '@mui/material/Stack'; +import { Stack } from '@mui/material'; import { AxiosError } from 'axios'; import { useLocation, useParams } from 'react-router-dom'; -import Breadcrumbs from '@/components/Breadcrumbs'; -import Clipboard from '@/components/Clipboard'; -import { EscrowAddressIcon } from '@/components/Icons/EscrowAddressIcon'; -import { WalletIcon } from '@/components/Icons/WalletIcon'; -import Loader from '@/components/Loader'; -import NothingFound from '@/components/NothingFound'; -import PageWrapper from '@/components/PageWrapper'; -import SearchBar from '@/components/SearchBar/SearchBar'; -import ShadowIcon from '@/components/ShadowIcon'; -import EscrowAddress from '@/pages/SearchResults/EscrowAddress'; -import RoleDetails from '@/pages/SearchResults/RoleDetails/RoleDetails'; -import WalletAddress from '@/pages/SearchResults/WalletAddress'; -import { - AddressDetails, - useAddressDetails, -} from '@/services/api/use-address-details'; -import { handleErrorMessage } from '@/services/handle-error-message'; -import { getNetwork } from '@/utils/config/networks'; -import { useWalletSearch } from '@/utils/hooks/use-wallet-search'; - -import { WalletAddressTransactionsTable } from './WalletAddress/WalletAddressTransactions/WalletAddressTransactionsTable'; +import handleErrorMessage from '@/shared/lib/handleErrorMessage'; +import { getNetwork } from '@/shared/lib/networks'; +import useGlobalFiltersStore from '@/shared/store/useGlobalFiltersStore'; +import EscrowAddressIcon from '@/shared/ui/icons/EscrowAddressIcon'; +import WalletIcon from '@/shared/ui/icons/WalletIcon'; +import Loader from '@/shared/ui/Loader'; +import ShadowIcon from '@/shared/ui/ShadowIcon'; + +import useAddressDetails from '../api/useAddressDetails'; +import { AddressDetails } from '../model/addressDetailsSchema'; + +import Clipboard from './Clipboard'; +import EscrowAddress from './EscrowAddress'; +import NothingFound from './NothingFound'; +import OperatorAddress from './OperatorAddress'; +import WalletAddress from './WalletAddress'; +import WalletTransactionsTable from './WalletTransactionsTable'; + +enum ParamsStatus { + LOADING = 'loading', + ERROR = 'error', + SUCCESS = 'success', +} const renderCurrentResultType = ( addressDetails: AddressDetails, @@ -75,64 +77,14 @@ const ResultError = ({ error }: { error: unknown }) => { return {handleErrorMessage(error)}; }; -const Results = () => { - const { data, status, error } = useAddressDetails(); - const { filterParams } = useWalletSearch(); - - if (status === 'pending' && !data) { - return ; - } - - if (status === 'error') { - return ; - } - - const showTransactions = !!data.wallet || !!data.operator; - - const walletData = - data.wallet || - (data.operator && data.operator.role === null ? data.operator : undefined); - - return ( - <> - - {renderCurrentResultType(data, filterParams.address)} - - - {data.operator && data.operator.role ? ( - - ) : null} - {walletData ? : null} - {data.escrow && } - {showTransactions && } - - ); -}; - -enum ParamsStatus { - LOADING = 'loading', - ERROR = 'error', - SUCCESS = 'success', -} - const SearchResults = () => { - const location = useLocation(); - const { chainId: urlChainId, address: urlAddress } = useParams(); - const { - setAddress, - setChainId, - filterParams: { chainId, address }, - } = useWalletSearch(); - const [paramsStatus, setParamsStatus] = useState( ParamsStatus.LOADING ); + const location = useLocation(); + const { chainId: urlChainId, address: urlAddress } = useParams(); + const { address, chainId, setAddress, setChainId } = useGlobalFiltersStore(); + const { data, status, error } = useAddressDetails(chainId, address); useEffect(() => { setParamsStatus(ParamsStatus.LOADING); @@ -172,18 +124,46 @@ const SearchResults = () => { } }, [address, chainId, paramsStatus]); + if ( + paramsStatus === ParamsStatus.LOADING || + (status === 'pending' && !data) + ) { + return ; + } + + if (paramsStatus === ParamsStatus.ERROR) { + return Something went wrong; + } + + if (status === 'error') { + return ; + } + + const showTransactions = !!data.wallet || !!data.operator; + + const walletData = + data.wallet || + (data.operator && data.operator.role === null ? data.operator : undefined); + return ( - - - - {paramsStatus === ParamsStatus.LOADING && ( - - )} - {paramsStatus === ParamsStatus.ERROR && ( - Something went wrong - )} - {paramsStatus === ParamsStatus.SUCCESS && } - + <> + + {renderCurrentResultType(data, address)} + + + {data.operator && data.operator.role ? ( + + ) : null} + {walletData ? : null} + {data.escrow && } + {showTransactions && } + ); }; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/StakeInfo/index.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/StakeInfo.tsx similarity index 89% rename from packages/apps/dashboard/client/src/pages/SearchResults/StakeInfo/index.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/StakeInfo.tsx index 23702ac62b..449d26c9ea 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/StakeInfo/index.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/StakeInfo.tsx @@ -2,10 +2,10 @@ import { FC } from 'react'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import { NumericFormat } from 'react-number-format'; -import SectionWrapper from '@/components/SectionWrapper'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; +import FormattedNumber from '@/shared/ui/FormattedNumber'; +import SectionWrapper from '@/shared/ui/SectionWrapper'; type Props = { amountStaked?: number | null; @@ -17,10 +17,8 @@ const renderAmount = (amount: number | null | undefined, isMobile: boolean) => { return ( - diff --git a/packages/apps/dashboard/client/src/features/searchResults/ui/TablePagination.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/TablePagination.tsx new file mode 100644 index 0000000000..a0611b80ee --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/TablePagination.tsx @@ -0,0 +1,92 @@ +import { FC, useEffect } from 'react'; + +import { TablePagination as MuiTablePagination } from '@mui/material'; + +import useGlobalFiltersStore from '@/shared/store/useGlobalFiltersStore'; + +type Props = { + page: number; + pageSize: number; + resultsLength: number; + lastPageIndex: number | undefined; + isDataLoading: boolean | undefined; + setPageSize: (pageSize: number) => void; + setNextPage: () => void; + setPrevPage: () => void; + setLastPageIndex: (lastPageIndex: number | undefined) => void; +}; + +const TablePagination: FC = ({ + page, + pageSize, + resultsLength, + lastPageIndex, + isDataLoading, + setPageSize, + setNextPage, + setPrevPage, + setLastPageIndex, +}) => { + const { chainId, address } = useGlobalFiltersStore(); + + useEffect(() => { + if ( + resultsLength !== undefined && + resultsLength === 0 && + page > 0 && + !isDataLoading + ) { + setLastPageIndex(page); + setPrevPage(); + } + }, [resultsLength, page, setLastPageIndex, setPrevPage, isDataLoading]); + + useEffect(() => { + setLastPageIndex(undefined); + }, [address, chainId, setLastPageIndex]); + + useEffect(() => { + return () => { + setPageSize(10); + }; + }, [setPageSize]); + + return ( + {}} + page={page} + component="td" + rowsPerPage={pageSize} + onRowsPerPageChange={(event) => { + setPageSize(Number(event.target.value)); + }} + rowsPerPageOptions={[5, 10]} + labelDisplayedRows={({ from, to }) => { + const effectiveTo = resultsLength ? from + resultsLength - 1 : to; + return `${from}–${effectiveTo}`; + }} + slotProps={{ + actions: { + nextButton: { + onClick: () => { + setNextPage(); + }, + disabled: + lastPageIndex !== undefined && + (page === lastPageIndex || lastPageIndex - 1 === page), + }, + previousButton: { + onClick: () => { + setPrevPage(); + }, + }, + }, + }} + /> + ); +}; + +export default TablePagination; diff --git a/packages/apps/dashboard/client/src/components/SearchResults/TitleSectionWrapper.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/TitleSectionWrapper.tsx similarity index 95% rename from packages/apps/dashboard/client/src/components/SearchResults/TitleSectionWrapper.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/TitleSectionWrapper.tsx index a7c49b216a..3eacd67706 100644 --- a/packages/apps/dashboard/client/src/components/SearchResults/TitleSectionWrapper.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/TitleSectionWrapper.tsx @@ -6,7 +6,7 @@ import Box from '@mui/material/Box'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import CustomTooltip from '@/components/CustomTooltip'; +import CustomTooltip from '@/shared/ui/CustomTooltip'; type Props = { title: string; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddress.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletAddress.tsx similarity index 77% rename from packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddress.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/WalletAddress.tsx index 3512e50f97..5275c53c20 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddress.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletAddress.tsx @@ -2,21 +2,22 @@ import { FC } from 'react'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import { NumericFormat } from 'react-number-format'; -import TitleSectionWrapper from '@/components/SearchResults'; -import SectionWrapper from '@/components/SectionWrapper'; +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; +import FormattedNumber from '@/shared/ui/FormattedNumber'; +import SectionWrapper from '@/shared/ui/SectionWrapper'; + import { AddressDetailsOperator, AddressDetailsWallet, -} from '@/services/api/use-address-details'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; +} from '../model/addressDetailsSchema'; -import HmtBalance from '../HmtBalance'; -import HmtPrice from '../HmtPrice'; -import KVStore from '../KVStore'; -import ReputationScore from '../ReputationScore'; -import StakeInfo from '../StakeInfo'; +import HmtBalance from './HmtBalance'; +import HmtPrice from './HmtPrice'; +import KVStore from './KvStore'; +import ReputationScore from './ReputationScore'; +import StakeInfo from './StakeInfo'; +import TitleSectionWrapper from './TitleSectionWrapper'; type Props = { data: AddressDetailsWallet | AddressDetailsOperator; @@ -56,10 +57,8 @@ const WalletAddress: FC = ({ data }) => { tooltip="Total amount earned by participating in jobs" > - diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableBody.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableBody.tsx similarity index 71% rename from packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableBody.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableBody.tsx index 3edd02e454..d2122d76cb 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableBody.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableBody.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import { FC, useState } from 'react'; import AddCircleIcon from '@mui/icons-material/AddCircle'; import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; @@ -10,35 +10,22 @@ import MuiTableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; import TableRow from '@mui/material/TableRow'; -import AbbreviateClipboard from '@/components/SearchResults/AbbreviateClipboard'; -import { TransactionTableCellMethod } from '@/pages/SearchResults/WalletAddress/WalletAddressTransactions/cells/TransactionTableCellMethod'; -import { TransactionTableCellValue } from '@/pages/SearchResults/WalletAddress/WalletAddressTransactions/cells/TransactionTableCellValue'; -import { TransactionsTableBodyContainer } from '@/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableBodyContainer'; -import { useTransactionDetails } from '@/services/api/use-transaction-details'; -import { handleErrorMessage } from '@/services/handle-error-message'; -import { useTransactionDetailsDto } from '@/utils/hooks/use-transactions-details-dto'; -import { useWalletSearch } from '@/utils/hooks/use-wallet-search'; +import handleErrorMessage from '@/shared/lib/handleErrorMessage'; +import AbbreviateClipboard from '@/shared/ui/AbbreviateClipboard'; -export const TransactionsTableBody: React.FC = () => { - const { data, isPending, isError, error } = useTransactionDetails(); - const { filterParams } = useWalletSearch(); - const { - setLastPageIndex, - setPrevPage, - pagination: { page }, - } = useTransactionDetailsDto(); +import { PaginatedTransactionDetails } from '../../model/transactionDetailsSchema'; - useEffect(() => { - if (data?.results.length === 0) { - setLastPageIndex(page); - setPrevPage(); - } - }, [data?.results, page, setLastPageIndex, setPrevPage]); +import TransactionsTableBodyContainer from './TransactionsTableBodyContainer'; +import TransactionsTableCellMethod from './TransactionsTableCellMethod'; +import TransactionsTableCellValue from './TransactionsTableCellValue'; - useEffect(() => { - setLastPageIndex(undefined); - }, [filterParams.address, filterParams.chainId, setLastPageIndex]); +type Props = { + data: PaginatedTransactionDetails | undefined; + isLoading: boolean; + error: Error | null; +}; +const TransactionsTableBody: FC = ({ data, isLoading, error }) => { const [expandedRows, setExpandedRows] = useState>({}); const toggleRow = (idx: number) => { @@ -48,7 +35,7 @@ export const TransactionsTableBody: React.FC = () => { })); }; - if (isPending) { + if (isLoading) { return ( @@ -56,7 +43,7 @@ export const TransactionsTableBody: React.FC = () => { ); } - if (isError) { + if (error) { return (
{handleErrorMessage(error)}
@@ -64,7 +51,7 @@ export const TransactionsTableBody: React.FC = () => { ); } - if (!data.results.length) { + if (!data?.results.length) { return (
No data
@@ -101,7 +88,7 @@ export const TransactionsTableBody: React.FC = () => {
- + { {elem.block} - @@ -137,7 +124,7 @@ export const TransactionsTableBody: React.FC = () => { > - + { - @@ -168,3 +155,5 @@ export const TransactionsTableBody: React.FC = () => { ); }; + +export default TransactionsTableBody; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableBodyContainer.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableBodyContainer.tsx similarity index 71% rename from packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableBodyContainer.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableBodyContainer.tsx index ea5a84943b..133bb36a0f 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableBodyContainer.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableBodyContainer.tsx @@ -1,10 +1,10 @@ -import { Grid } from '@mui/material'; +import { FC, PropsWithChildren } from 'react'; + +import Grid from '@mui/material/Grid'; import MuiTableBody from '@mui/material/TableBody'; -export const TransactionsTableBodyContainer = ({ +const TransactionsTableBodyContainer: FC = ({ children, -}: { - children: JSX.Element; }) => { return ( @@ -26,3 +26,5 @@ export const TransactionsTableBodyContainer = ({ ); }; + +export default TransactionsTableBodyContainer; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/cells/TransactionTableCellMethod.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableCellMethod.tsx similarity index 93% rename from packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/cells/TransactionTableCellMethod.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableCellMethod.tsx index 72d63b90a9..ac8d85d7ec 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/cells/TransactionTableCellMethod.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableCellMethod.tsx @@ -70,7 +70,7 @@ const methodAttributes: Record< }, }; -export const TransactionTableCellMethod = ({ method }: { method: string }) => { +const TransactionsTableCellMethod = ({ method }: { method: string }) => { const theme = useTheme(); const currentStatusColors = methodAttributes[method]?.color || { text: 'primary.main', @@ -97,3 +97,5 @@ export const TransactionTableCellMethod = ({ method }: { method: string }) => { /> ); }; + +export default TransactionsTableCellMethod; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/cells/TransactionTableCellValue.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableCellValue.tsx similarity index 71% rename from packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/cells/TransactionTableCellValue.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableCellValue.tsx index ee8a5ecc2f..4c031b002c 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/cells/TransactionTableCellValue.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableCellValue.tsx @@ -1,9 +1,9 @@ import HelpOutlineIcon from '@mui/icons-material/HelpOutline'; import Typography from '@mui/material/Typography'; -import CustomTooltip from '@/components/CustomTooltip'; -import { formatHMTDecimals } from '@/helpers/formatHMTDecimals'; -import { useHMTPrice } from '@/services/api/use-hmt-price'; +import useHmtPrice from '@/shared/api/useHmtPrice'; +import formatHmtDecimals from '@/shared/lib/formatHmtDecimals'; +import CustomTooltip from '@/shared/ui/CustomTooltip'; const InfoTooltip = ({ title }: { title: string }) => ( @@ -16,14 +16,14 @@ const InfoTooltip = ({ title }: { title: string }) => ( ); -export const TransactionTableCellValue = ({ +const TransactionsTableCellValue = ({ value, method, }: { value: string; method: string; }) => { - const { isError, isPending } = useHMTPrice(); + const { isError, isPending } = useHmtPrice(); if (isError) { return N/A; @@ -35,7 +35,7 @@ export const TransactionTableCellValue = ({ return ( - {formatHMTDecimals(value)} + {formatHmtDecimals(value)} HMT @@ -45,3 +45,5 @@ export const TransactionTableCellValue = ({ ); }; + +export default TransactionsTableCellValue; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableHead.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableHead.tsx similarity index 92% rename from packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableHead.tsx rename to packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableHead.tsx index 5a5fbf0538..060380626b 100644 --- a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableHead.tsx +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactions/TransactionsTableHead.tsx @@ -4,7 +4,7 @@ import TableCell from '@mui/material/TableCell'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; -import CustomTooltip from '@/components/CustomTooltip'; +import CustomTooltip from '@/shared/ui/CustomTooltip'; const InfoTooltip = ({ title }: { title: string }) => ( ( ); -export const TransactionsTableHead = () => { +const TransactionsTableHead = () => { return ( { ); }; + +export default TransactionsTableHead; diff --git a/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactionsTable.tsx b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactionsTable.tsx new file mode 100644 index 0000000000..2dbe0da623 --- /dev/null +++ b/packages/apps/dashboard/client/src/features/searchResults/ui/WalletTransactionsTable.tsx @@ -0,0 +1,90 @@ +import Table from '@mui/material/Table'; +import TableContainer from '@mui/material/TableContainer'; +import TableFooter from '@mui/material/TableFooter'; +import TableRow from '@mui/material/TableRow'; +import Typography from '@mui/material/Typography'; +import SimpleBar from 'simplebar-react'; + +import useGlobalFiltersStore from '@/shared/store/useGlobalFiltersStore'; +import SectionWrapper from '@/shared/ui/SectionWrapper'; + +import useTransactionDetails from '../api/useTransactionDetails'; +import usePagination from '../hooks/usePagination'; + +import TablePagination from './TablePagination'; +import TransactionsTableBody from './WalletTransactions/TransactionsTableBody'; +import TransactionsTableHead from './WalletTransactions/TransactionsTableHead'; + +const WalletTransactionsTable = () => { + const { chainId, address } = useGlobalFiltersStore(); + const { + pagination: { page, pageSize, lastPageIndex }, + params, + setPageSize, + setNextPage, + setPrevPage, + setLastPageIndex, + } = usePagination(); + const { data, isLoading, error } = useTransactionDetails({ + chainId, + address, + page, + lastPageIndex, + setLastPageIndex, + params, + }); + + return ( + + + Transactions + + + + + + +
+
+ + + + + + +
+
+
+ ); +}; + +export default WalletTransactionsTable; diff --git a/packages/apps/dashboard/client/src/helpers/abbreviateValue.ts b/packages/apps/dashboard/client/src/helpers/abbreviateValue.ts deleted file mode 100644 index 45feadaf9d..0000000000 --- a/packages/apps/dashboard/client/src/helpers/abbreviateValue.ts +++ /dev/null @@ -1,12 +0,0 @@ -const abbreviateValue = (value: string | null) => { - if (value) { - const first3Letters = value.slice(0, 5); - const last5Letters = value.slice(-5); - - return `${first3Letters}...${last5Letters}`; - } - - return null; -}; - -export default abbreviateValue; diff --git a/packages/apps/dashboard/client/src/helpers/index.ts b/packages/apps/dashboard/client/src/helpers/index.ts deleted file mode 100644 index f2f42df6a9..0000000000 --- a/packages/apps/dashboard/client/src/helpers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from 'src/helpers/abbreviateValue'; diff --git a/packages/apps/dashboard/client/src/helpers/isValidEVMAddress.ts b/packages/apps/dashboard/client/src/helpers/isValidEVMAddress.ts deleted file mode 100644 index 8b4e86d412..0000000000 --- a/packages/apps/dashboard/client/src/helpers/isValidEVMAddress.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const isValidEVMAddress = (input: string): boolean => { - const evmRegex = /^0x[a-fA-F0-9]{40}$/; - return evmRegex.test(input); -}; diff --git a/packages/apps/dashboard/client/src/pages/Graph/index.ts b/packages/apps/dashboard/client/src/pages/Graph/index.ts deleted file mode 100644 index 8c491e7e8c..0000000000 --- a/packages/apps/dashboard/client/src/pages/Graph/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Graph'; diff --git a/packages/apps/dashboard/client/src/pages/Home/Leaderboard.tsx b/packages/apps/dashboard/client/src/pages/Home/Leaderboard.tsx deleted file mode 100644 index 8666c6bbdd..0000000000 --- a/packages/apps/dashboard/client/src/pages/Home/Leaderboard.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { useLeaderboardDetails } from '@/services/api/use-leaderboard-details'; - -import { Leaderboard as LeaderboardFeature } from '../../features/Leaderboard'; - -export const Leaderboard = () => { - const { data, status, error } = useLeaderboardDetails(4); - - return ( - - ); -}; diff --git a/packages/apps/dashboard/client/src/pages/Home/index.ts b/packages/apps/dashboard/client/src/pages/Home/index.ts deleted file mode 100644 index 41e08eefd0..0000000000 --- a/packages/apps/dashboard/client/src/pages/Home/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Home'; diff --git a/packages/apps/dashboard/client/src/pages/Leaderboard/index.tsx b/packages/apps/dashboard/client/src/pages/Leaderboard/index.tsx deleted file mode 100644 index b32decf434..0000000000 --- a/packages/apps/dashboard/client/src/pages/Leaderboard/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import Breadcrumbs from '@/components/Breadcrumbs'; -import { LeaderboardIcon } from '@/components/Icons/LeaderboardIcon'; -import PageWrapper from '@/components/PageWrapper'; -import ShadowIcon from '@/components/ShadowIcon'; -import { useLeaderboardDetails } from '@/services/api/use-leaderboard-details'; - -import { Leaderboard } from '../../features/Leaderboard/index'; - -const LeaderBoard = () => { - const { data, status, error } = useLeaderboardDetails(); - - return ( - - - } - /> - - - ); -}; - -export default LeaderBoard; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/EscrowAddress/index.ts b/packages/apps/dashboard/client/src/pages/SearchResults/EscrowAddress/index.ts deleted file mode 100644 index b7ba591a2c..0000000000 --- a/packages/apps/dashboard/client/src/pages/SearchResults/EscrowAddress/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './EscrowAddress'; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetailsEscrows/RoleDetailsEscrowsTable.tsx b/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetailsEscrows/RoleDetailsEscrowsTable.tsx deleted file mode 100644 index 3364163f08..0000000000 --- a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetailsEscrows/RoleDetailsEscrowsTable.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { useEffect } from 'react'; - -import Stack from '@mui/material/Stack'; -import Table from '@mui/material/Table'; -import TableContainer from '@mui/material/TableContainer'; -import TableHead from '@mui/material/TableHead'; -import TablePagination from '@mui/material/TablePagination'; -import TableRow from '@mui/material/TableRow'; -import Typography from '@mui/material/Typography'; - -import SectionWrapper from '@/components/SectionWrapper'; -import { EscrowsTableBody } from '@/pages/SearchResults/RoleDetails/RoleDetailsEscrows/tableComponents/EscrowsTableBody'; -import { useEscrowDetails } from '@/services/api/use-escrows-details'; -import { useEscrowDetailsDto } from '@/utils/hooks/use-escrows-details-dto'; - -export const RoleDetailsEscrowsTable = ({ role }: { role: string | null }) => { - const { data } = useEscrowDetails({ role }); - const { - pagination: { page, pageSize, lastPageIndex }, - setPageSize, - setNextPage, - setPrevPage, - } = useEscrowDetailsDto(); - - useEffect(() => { - return () => { - setPageSize(10); - }; - }, [setPageSize]); - - return ( - - - Escrows - - - - - - - -
-
- - {}} - page={page} - rowsPerPage={pageSize} - onRowsPerPageChange={(event) => { - setPageSize(Number(event.target.value)); - }} - rowsPerPageOptions={[5, 10]} - labelDisplayedRows={({ from, to }) => { - const effectiveTo = data?.results - ? from + data.results.length - 1 - : to; - return `${from}–${effectiveTo}`; - }} - component="div" - slotProps={{ - actions: { - nextButton: { - onClick: () => { - setNextPage(); - }, - disabled: - lastPageIndex !== undefined && - (page === lastPageIndex || lastPageIndex - 1 === page), - }, - previousButton: { - onClick: () => { - setPrevPage(); - }, - }, - }, - }} - /> - -
- ); -}; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetailsEscrows/tableComponents/EscrowsTableBody.tsx b/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetailsEscrows/tableComponents/EscrowsTableBody.tsx deleted file mode 100644 index 2fb9f4a4f8..0000000000 --- a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/RoleDetailsEscrows/tableComponents/EscrowsTableBody.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { useEffect } from 'react'; - -import { Stack, TableRow } from '@mui/material'; -import CircularProgress from '@mui/material/CircularProgress'; -import Link from '@mui/material/Link'; -import MuiTableBody from '@mui/material/TableBody'; -import TableCell from '@mui/material/TableCell'; -import { useNavigate } from 'react-router-dom'; - -import { EscrowsTableBodyContainer } from '@/pages/SearchResults/RoleDetails/RoleDetailsEscrows/tableComponents/EscrowsTableBodyContainer'; -import { AddressDetailsOperator } from '@/services/api/use-address-details'; -import { useEscrowDetails } from '@/services/api/use-escrows-details'; -import { handleErrorMessage } from '@/services/handle-error-message'; -import { useEscrowDetailsDto } from '@/utils/hooks/use-escrows-details-dto'; -import { useWalletSearch } from '@/utils/hooks/use-wallet-search'; - - -export const EscrowsTableBody = ({ - role, -}: { - role: AddressDetailsOperator['role']; -}) => { - const navigate = useNavigate(); - const { filterParams } = useWalletSearch(); - const { data, isPending, isError, error } = useEscrowDetails({ role }); - const { - setLastPageIndex, - setPrevPage, - pagination: { page }, - } = useEscrowDetailsDto(); - - useEffect(() => { - if (data?.results.length === 0) { - setLastPageIndex(page); - setPrevPage(); - } - }, [data?.results, page, setLastPageIndex, setPrevPage]); - - useEffect(() => { - setLastPageIndex(undefined); - }, [filterParams.address, filterParams.chainId, setLastPageIndex]); - - if (isPending) { - return ( - - - - ); - } - - if (isError) { - return ( - -
{handleErrorMessage(error)}
-
- ); - } - - if (!data.results.length) { - return ( - -
No escrows launched yet
-
- ); - } - - return ( - - {data.results.map((elem, idx) => ( - - - { - e.stopPropagation(); - e.preventDefault(); - navigate(`/search/${filterParams.chainId}/${elem.address}`); - }} - > - - {elem.address} - - - - - ))} - - ); -}; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/index.ts b/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/index.ts deleted file mode 100644 index 6c3987e4fa..0000000000 --- a/packages/apps/dashboard/client/src/pages/SearchResults/RoleDetails/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './RoleDetails'; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/WalletAddressTransactionsTable.tsx b/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/WalletAddressTransactionsTable.tsx deleted file mode 100644 index 5a88d704c6..0000000000 --- a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/WalletAddressTransactions/WalletAddressTransactionsTable.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { useEffect } from 'react'; - -import Table from '@mui/material/Table'; -import TableContainer from '@mui/material/TableContainer'; -import TableFooter from '@mui/material/TableFooter'; -import TablePagination from '@mui/material/TablePagination'; -import TableRow from '@mui/material/TableRow'; -import Typography from '@mui/material/Typography'; -import SimpleBar from 'simplebar-react'; - -import SectionWrapper from '@/components/SectionWrapper'; -import { TransactionsTableBody } from '@/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableBody'; -import { TransactionsTableHead } from '@/pages/SearchResults/WalletAddress/WalletAddressTransactions/tableComponents/TransactionsTableHead'; -import { useTransactionDetails } from '@/services/api/use-transaction-details'; -import { useTransactionDetailsDto } from '@/utils/hooks/use-transactions-details-dto'; - -export const WalletAddressTransactionsTable = () => { - const { data } = useTransactionDetails(); - const { - pagination: { page, pageSize, lastPageIndex }, - setPageSize, - setNextPage, - setPrevPage, - } = useTransactionDetailsDto(); - - useEffect(() => { - return () => { - setPageSize(10); - }; - }, [setPageSize]); - - return ( - - - Transactions - - - - - - -
-
- - - - {}} - page={page} - component="td" - rowsPerPage={pageSize} - onRowsPerPageChange={(event) => { - setPageSize(Number(event.target.value)); - }} - rowsPerPageOptions={[5, 10]} - labelDisplayedRows={({ from, to }) => { - const effectiveTo = data?.results - ? from + data.results.length - 1 - : to; - return `${from}–${effectiveTo}`; - }} - slotProps={{ - actions: { - nextButton: { - onClick: () => { - setNextPage(); - }, - disabled: - lastPageIndex !== undefined && - (page === lastPageIndex || lastPageIndex - 1 === page), - }, - previousButton: { - onClick: () => { - setPrevPage(); - }, - }, - }, - }} - /> - - -
-
-
- ); -}; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/index.ts b/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/index.ts deleted file mode 100644 index f9385021f9..0000000000 --- a/packages/apps/dashboard/client/src/pages/SearchResults/WalletAddress/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './WalletAddress'; diff --git a/packages/apps/dashboard/client/src/pages/SearchResults/index.ts b/packages/apps/dashboard/client/src/pages/SearchResults/index.ts deleted file mode 100644 index 43ac09d5da..0000000000 --- a/packages/apps/dashboard/client/src/pages/SearchResults/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './SearchResults'; diff --git a/packages/apps/dashboard/client/src/pages/graph/index.ts b/packages/apps/dashboard/client/src/pages/graph/index.ts new file mode 100644 index 0000000000..375e4a10e9 --- /dev/null +++ b/packages/apps/dashboard/client/src/pages/graph/index.ts @@ -0,0 +1 @@ +export { default } from './ui/GraphPage'; diff --git a/packages/apps/dashboard/client/src/pages/Graph/Graph.tsx b/packages/apps/dashboard/client/src/pages/graph/ui/GraphPage.tsx similarity index 50% rename from packages/apps/dashboard/client/src/pages/Graph/Graph.tsx rename to packages/apps/dashboard/client/src/pages/graph/ui/GraphPage.tsx index 39335560e4..fb598362b4 100644 --- a/packages/apps/dashboard/client/src/pages/Graph/Graph.tsx +++ b/packages/apps/dashboard/client/src/pages/graph/ui/GraphPage.tsx @@ -1,12 +1,12 @@ import { useEffect } from 'react'; -import Breadcrumbs from '@/components/Breadcrumbs'; -import { AreaChart } from '@/components/Charts'; -import PageWrapper from '@/components/PageWrapper'; -import { useGraphPageChartParams } from '@/utils/hooks/use-graph-page-chart-params'; +import AreaChart from '@/features/graph'; +import useChartParamsStore from '@/features/graph/store/useChartParamsStore'; +import Breadcrumbs from '@/shared/ui/Breadcrumbs'; +import PageWrapper from '@/widgets/page-wrapper'; const Graph = () => { - const { revertToInitialParams } = useGraphPageChartParams(); + const { revertToInitialParams } = useChartParamsStore(); useEffect(() => { revertToInitialParams(); diff --git a/packages/apps/dashboard/client/src/pages/home/index.ts b/packages/apps/dashboard/client/src/pages/home/index.ts new file mode 100644 index 0000000000..6648d3e441 --- /dev/null +++ b/packages/apps/dashboard/client/src/pages/home/index.ts @@ -0,0 +1 @@ +export { default } from './ui/HomePage'; diff --git a/packages/apps/dashboard/client/src/pages/Home/Home.tsx b/packages/apps/dashboard/client/src/pages/home/ui/HomePage.tsx similarity index 81% rename from packages/apps/dashboard/client/src/pages/Home/Home.tsx rename to packages/apps/dashboard/client/src/pages/home/ui/HomePage.tsx index 5b60eae7b8..a92bd05c73 100644 --- a/packages/apps/dashboard/client/src/pages/Home/Home.tsx +++ b/packages/apps/dashboard/client/src/pages/home/ui/HomePage.tsx @@ -9,19 +9,18 @@ import Typography from '@mui/material/Typography'; import Grid from '@mui/material/Unstable_Grid2'; import { Link } from 'react-router-dom'; -import CustomTooltip from '@/components/CustomTooltip'; -import GraphSwiper from '@/components/Home/GraphSwiper'; -import { LeaderboardIcon } from '@/components/Icons/LeaderboardIcon'; -import PageWrapper from '@/components/PageWrapper'; -import SearchBar from '@/components/SearchBar/SearchBar'; -import ShadowIcon from '@/components/ShadowIcon'; -import HMTPrice from '@/pages/Home/HMTPrice'; -import Holders from '@/pages/Home/Holders'; -import TotalNumberOfTasks from '@/pages/Home/TotalNumberOfTasks'; -import TotalTransactions from '@/pages/Home/TotalTransactions'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; - -import { Leaderboard } from './Leaderboard'; +import GraphSwiper from '@/features/graph/ui/GraphSwiper'; +import HmtPrice from '@/features/home/ui/HmtPrice'; +import Holders from '@/features/home/ui/Holders'; +import TotalNumberOfTasks from '@/features/home/ui/TotalNumberOfTasks'; +import TotalTransactions from '@/features/home/ui/TotalTransactions'; +import Leaderboard from '@/features/leaderboard'; +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; +import CustomTooltip from '@/shared/ui/CustomTooltip'; +import LeaderboardIcon from '@/shared/ui/icons/LeaderboardIcon'; +import SearchBar from '@/shared/ui/SearchBar'; +import ShadowIcon from '@/shared/ui/ShadowIcon'; +import PageWrapper from '@/widgets/page-wrapper'; const CardWrapper = styled(Grid)(({ theme }) => ({ display: 'flex', @@ -62,7 +61,7 @@ const renderViewChartsButton = (show: boolean) => { } }; -const Home: FC = () => { +const HomePage: FC = () => { const isMobile = useIsMobile(); return ( @@ -77,7 +76,7 @@ const Home: FC = () => { Token - + @@ -127,9 +126,9 @@ const Home: FC = () => { title="Leaderboard" img={} /> - + ); }; -export default Home; +export default HomePage; diff --git a/packages/apps/dashboard/client/src/pages/leaderboard/index.ts b/packages/apps/dashboard/client/src/pages/leaderboard/index.ts new file mode 100644 index 0000000000..1ffb7778d2 --- /dev/null +++ b/packages/apps/dashboard/client/src/pages/leaderboard/index.ts @@ -0,0 +1 @@ +export { default } from './ui/LeaderboardPage'; diff --git a/packages/apps/dashboard/client/src/pages/leaderboard/ui/LeaderboardPage.tsx b/packages/apps/dashboard/client/src/pages/leaderboard/ui/LeaderboardPage.tsx new file mode 100644 index 0000000000..c50eb67e7f --- /dev/null +++ b/packages/apps/dashboard/client/src/pages/leaderboard/ui/LeaderboardPage.tsx @@ -0,0 +1,21 @@ +import Leaderboard from '@/features/leaderboard'; +import Breadcrumbs from '@/shared/ui/Breadcrumbs'; +import LeaderboardIcon from '@/shared/ui/icons/LeaderboardIcon'; +import ShadowIcon from '@/shared/ui/ShadowIcon'; +import PageWrapper from '@/widgets/page-wrapper'; + +const LeaderboardPage = () => { + return ( + + + } + /> + + + ); +}; + +export default LeaderboardPage; diff --git a/packages/apps/dashboard/client/src/pages/searchResults/index.ts b/packages/apps/dashboard/client/src/pages/searchResults/index.ts new file mode 100644 index 0000000000..6d66d62fbc --- /dev/null +++ b/packages/apps/dashboard/client/src/pages/searchResults/index.ts @@ -0,0 +1 @@ +export { default } from './ui/SearchResultsPage'; diff --git a/packages/apps/dashboard/client/src/pages/searchResults/ui/SearchResultsPage.tsx b/packages/apps/dashboard/client/src/pages/searchResults/ui/SearchResultsPage.tsx new file mode 100644 index 0000000000..02ae0f5ffc --- /dev/null +++ b/packages/apps/dashboard/client/src/pages/searchResults/ui/SearchResultsPage.tsx @@ -0,0 +1,15 @@ +import SearchResults from '@/features/searchResults'; +import Breadcrumbs from '@/shared/ui/Breadcrumbs'; +import SearchBar from '@/shared/ui/SearchBar'; +import PageWrapper from '@/widgets/page-wrapper'; + +const SearchResultsPage = () => { + return ( + + + + + + ); +}; +export default SearchResultsPage; diff --git a/packages/apps/dashboard/client/src/services/api/use-escrows-details.tsx b/packages/apps/dashboard/client/src/services/api/use-escrows-details.tsx deleted file mode 100644 index 8a0ac01e07..0000000000 --- a/packages/apps/dashboard/client/src/services/api/use-escrows-details.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { z } from 'zod'; - -import { AddressDetailsOperator } from '@/services/api/use-address-details'; -import { validateResponse } from '@/services/validate-response'; -import { useEscrowDetailsDto } from '@/utils/hooks/use-escrows-details-dto'; -import { useWalletSearch } from '@/utils/hooks/use-wallet-search'; - -import { apiPaths } from '../api-paths'; -import { httpService } from '../http-service'; - -const escrowDetailsSuccessResponseSchema = z.object({ - chainId: z.number(), - address: z.string(), - status: z.string(), -}); - -export type TransactionDetails = z.infer< - typeof escrowDetailsSuccessResponseSchema ->; - -const paginatedEscrowsDetailsSuccessResponseSchema = z.object({ - address: z.string(), - chainId: z.number(), - first: z.number(), - skip: z.number(), - results: z.array(escrowDetailsSuccessResponseSchema), -}); - -export type PaginatedEscrowDetails = z.infer< - typeof paginatedEscrowsDetailsSuccessResponseSchema ->; - -export interface PaginatedEscrowsDetailsDto { - skip: number; - first: number; - chainId: number; - role: AddressDetailsOperator['role']; -} - -export function useEscrowDetails({ - role, -}: { - role: AddressDetailsOperator['role']; -}) { - const { filterParams } = useWalletSearch(); - const { - setLastPageIndex, - pagination: { page, lastPageIndex }, - params, - } = useEscrowDetailsDto(); - - const dto: PaginatedEscrowsDetailsDto = { - chainId: filterParams.chainId, - skip: params.skip, - first: params.first, - role, - }; - - return useQuery({ - queryFn: async () => { - const { data } = await httpService.get( - `${apiPaths.escrowDetails.path}/${filterParams.address}`, - { - params: dto, - } - ); - - const validResponse = validateResponse( - data, - paginatedEscrowsDetailsSuccessResponseSchema - ); - - // check if last page - if (lastPageIndex === undefined) { - const { data: lastPageCheckData } = await httpService.get( - `${apiPaths.escrowDetails.path}/${filterParams.address}`, - { - params: { - ...dto, - skip: dto.skip + validResponse.results.length, - first: 1, - }, - } - ); - const validLastPageCheckData = validateResponse( - lastPageCheckData, - paginatedEscrowsDetailsSuccessResponseSchema - ); - - if (validLastPageCheckData.results.length === 0) { - setLastPageIndex(page + 1); - } - } - - return validResponse; - }, - queryKey: ['useEscrowDetails', filterParams.address, dto], - }); -} diff --git a/packages/apps/dashboard/client/src/services/api/use-general-stats.tsx b/packages/apps/dashboard/client/src/services/api/use-general-stats.tsx deleted file mode 100644 index e087a7a97e..0000000000 --- a/packages/apps/dashboard/client/src/services/api/use-general-stats.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { z } from 'zod'; - -import { validateResponse } from '@/services/validate-response'; - -import { apiPaths } from '../api-paths'; -import { httpService } from '../http-service'; - -const successGeneralStatsResponseSchema = z.object({ - totalHolders: z.number(), - totalTransactions: z.number(), -}); - -export type GeneralStats = z.infer; - -export function useGeneralStats() { - return useQuery({ - queryFn: async () => { - const { data } = await httpService.get(apiPaths.generalStats.path); - - const validResponse = validateResponse( - data, - successGeneralStatsResponseSchema - ); - - return validResponse; - }, - queryKey: ['useGeneralStats'], - }); -} diff --git a/packages/apps/dashboard/client/src/services/api/use-graph-page-chart-data.tsx b/packages/apps/dashboard/client/src/services/api/use-graph-page-chart-data.tsx deleted file mode 100644 index 63032aaf65..0000000000 --- a/packages/apps/dashboard/client/src/services/api/use-graph-page-chart-data.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { useMemo } from 'react'; - -import { useQuery, keepPreviousData } from '@tanstack/react-query'; -import dayjs from 'dayjs'; -import { useDebounce } from 'use-debounce'; -import { z } from 'zod'; - -import { validateResponse } from '@/services/validate-response'; -import { useGraphPageChartParams } from '@/utils/hooks/use-graph-page-chart-params'; - -import { apiPaths } from '../api-paths'; -import { httpService } from '../http-service'; - -const hmtDailyStatSchemaResponseSchema = z.object({ - from: z.string().optional(), - to: z.string().optional(), - results: z.array( - z.object({ - totalTransactionAmount: z.string().transform((value, ctx) => { - const valueAsNumber = Number(value); - if (Number.isNaN(valueAsNumber)) { - ctx.addIssue({ - path: ['totalTransactionAmount'], - code: z.ZodIssueCode.custom, - }); - } - - return valueAsNumber / 10 ** 18; - }), - totalTransactionCount: z.number(), - dailyUniqueSenders: z.number(), - dailyUniqueReceivers: z.number(), - date: z.string(), - }) - ), -}); - -export type HMTDailyStatsResponse = z.output< - typeof hmtDailyStatSchemaResponseSchema ->; -export type HMTDailyStat = HMTDailyStatsResponse['results'][number]; - -const hcaptchaDailyStatsResponseSchema = z.object({ - from: z.string().optional(), - to: z.string().optional(), - results: z.array( - z.object({ - solved: z.number(), - date: z.string(), - }) - ), -}); - -export type HcaptchaDailyStatsResponse = z.infer< - typeof hcaptchaDailyStatsResponseSchema ->; -export type HcaptchaDailyStat = HcaptchaDailyStatsResponse['results'][number]; - -export type GraphPageChartData = (HMTDailyStat & - Omit)[]; - -const mergeResponses = ( - hcaptchaStatsResults: HcaptchaDailyStat[], - hmtStatsResults: HMTDailyStat[] -): GraphPageChartData => { - const allDates = Array.from( - new Set([ - ...hcaptchaStatsResults.map(({ date }) => date), - ...hmtStatsResults.map(({ date }) => date), - ]) - ).sort((a, b) => (dayjs(a).isBefore(dayjs(b)) ? -1 : 1)); - - const hcaptchaStatsResultsMap = new Map(); - const hmtStatsResultsMap = new Map(); - - hcaptchaStatsResults.forEach((entry) => { - hcaptchaStatsResultsMap.set(entry.date, entry); - }); - - hmtStatsResults.forEach((entry) => { - hmtStatsResultsMap.set(entry.date, entry); - }); - return allDates.map((date) => { - const hmtStatsEntry: HMTDailyStat = hmtStatsResultsMap.get(date) || { - dailyUniqueReceivers: 0, - dailyUniqueSenders: 0, - date: date, - totalTransactionAmount: 0, - totalTransactionCount: 0, - }; - - const hcaptchaStatsEntry: HcaptchaDailyStat = hcaptchaStatsResultsMap.get( - date - ) || { - date: date, - solved: 0, - }; - return { ...hmtStatsEntry, ...hcaptchaStatsEntry }; - }); -}; - -const DEBOUNCE_MS = 300; - -export function useGraphPageChartData() { - const { dateRangeParams } = useGraphPageChartParams(); - const queryParams = useMemo( - () => ({ - from: dateRangeParams.from.format('YYYY-MM-DD'), - to: dateRangeParams.to.format('YYYY-MM-DD'), - }), - [dateRangeParams.from, dateRangeParams.to] - ); - - const [debouncedQueryParams] = useDebounce(queryParams, DEBOUNCE_MS); - - return useQuery({ - queryFn: async () => { - const { data: hmtDailyStats } = await httpService.get( - apiPaths.hmtDailyStats.path, - { - params: debouncedQueryParams, - } - ); - const { data: hcaptchDailyStats } = await httpService.get( - apiPaths.hcaptchaStatsDaily.path, - { - params: debouncedQueryParams, - } - ); - - const validHmtDailyStats = validateResponse( - hmtDailyStats, - hmtDailyStatSchemaResponseSchema - ); - - const validHcaptchaGeneralStats = validateResponse( - hcaptchDailyStats, - hcaptchaDailyStatsResponseSchema - ); - - return mergeResponses( - validHcaptchaGeneralStats.results, - validHmtDailyStats.results - ); - }, - staleTime: DEBOUNCE_MS, - queryKey: ['useGraphPageChartData', debouncedQueryParams], - placeholderData: keepPreviousData, - }); -} diff --git a/packages/apps/dashboard/client/src/services/api/use-hcaptcha-general-stats.tsx b/packages/apps/dashboard/client/src/services/api/use-hcaptcha-general-stats.tsx deleted file mode 100644 index e6256c24fe..0000000000 --- a/packages/apps/dashboard/client/src/services/api/use-hcaptcha-general-stats.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { z } from 'zod'; - -import { validateResponse } from '@/services/validate-response'; - -import { apiPaths } from '../api-paths'; -import { httpService } from '../http-service'; - -const successHcaptchaGeneralStatsResponseSchema = z.object({ - solved: z.number(), -}); - -export type HcaptchaGeneralStats = z.infer< - typeof successHcaptchaGeneralStatsResponseSchema ->; - -export function useHcaptchaGeneralStats() { - return useQuery({ - queryFn: async () => { - const { data } = await httpService.get( - apiPaths.hcaptchaGeneralStats.path - ); - - const validResponse = validateResponse( - data, - successHcaptchaGeneralStatsResponseSchema - ); - - return validResponse; - }, - queryKey: ['useHcaptchaGeneralStats'], - }); -} diff --git a/packages/apps/dashboard/client/src/services/api/use-hmt-price.tsx b/packages/apps/dashboard/client/src/services/api/use-hmt-price.tsx deleted file mode 100644 index c3427cdeeb..0000000000 --- a/packages/apps/dashboard/client/src/services/api/use-hmt-price.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { z } from 'zod'; - -import { validateResponse } from '@/services/validate-response'; - -import { apiPaths } from '../api-paths'; -import { httpService } from '../http-service'; - -const successHMTPriceResponseSchema = z.object({ - hmtPrice: z.number(), -}); - -export type HMTPrice = z.infer; - -export function useHMTPrice() { - return useQuery({ - queryFn: async () => { - const { data } = await httpService.get(apiPaths.statsHmtPrice.path); - - const validResponse = validateResponse( - data, - successHMTPriceResponseSchema - ); - - return validResponse.hmtPrice; - }, - queryKey: ['useHMTPrice'], - }); -} diff --git a/packages/apps/dashboard/client/src/services/api/use-kvstore-data.tsx b/packages/apps/dashboard/client/src/services/api/use-kvstore-data.tsx deleted file mode 100644 index bbc26e77f0..0000000000 --- a/packages/apps/dashboard/client/src/services/api/use-kvstore-data.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { z } from 'zod'; - -import { apiPaths } from '@/services/api-paths'; -import { httpService } from '@/services/http-service'; -import { validateResponse } from '@/services/validate-response'; -import { useWalletSearch } from '@/utils/hooks/use-wallet-search'; - -const kvstoreDataSchema = z.array( - z.object({ - key: z.string(), - value: z.string(), - }) -); - -export type KvstoreData = z.infer; - -const useKvstoreData = () => { - const { filterParams } = useWalletSearch(); - - return useQuery({ - queryKey: ['kvstoreData', filterParams.address], - queryFn: async () => { - const { data } = await httpService.get( - `${apiPaths.kvstore.path}/${filterParams.address}`, - { params: { chain_id: filterParams.chainId || -1 } } - ); - - const validResponse = validateResponse(data, kvstoreDataSchema); - - return validResponse; - }, - }); -}; - -export default useKvstoreData; diff --git a/packages/apps/dashboard/client/src/services/api/use-leaderboard-details.tsx b/packages/apps/dashboard/client/src/services/api/use-leaderboard-details.tsx deleted file mode 100644 index 37919661ba..0000000000 --- a/packages/apps/dashboard/client/src/services/api/use-leaderboard-details.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { z } from 'zod'; - -import { validateResponse } from '@/services/validate-response'; -import { useLeaderboardSearch } from '@/utils/hooks/use-leaderboard-search'; - -import { apiPaths } from '../api-paths'; -import { httpService } from '../http-service'; - -export const reputationSchema = z.unknown().transform((value) => { - try { - const knownReputation = z - .union([z.literal('Low'), z.literal('Medium'), z.literal('High')]) - .parse(value); - - return knownReputation; - } catch (error) { - console.error(error); - return 'Unknown'; - } -}); - -export type Reputation = z.infer; - -const leaderBoardEntity = z.object({ - address: z.string(), - role: z.string(), - amountStaked: z - .string() - .transform((value, ctx) => { - const valueAsNumber = Number(value); - - if (Number.isNaN(valueAsNumber)) { - ctx.addIssue({ - path: ['amountStaked'], - code: z.ZodIssueCode.custom, - }); - } - - return valueAsNumber / 10 ** 18; - }) - .nullable(), - reputation: reputationSchema, - fee: z.number().nullable(), - jobTypes: z.array(z.string()).nullable(), - url: z.string().nullable(), - website: z.string().nullable(), - chainId: z.number(), - name: z.string().nullable(), - category: z.string().nullable(), -}); - -export const leaderBoardSuccessResponseSchema = z.array(leaderBoardEntity); -export type LeaderBoardEntity = z.infer; -export type LeaderBoardData = z.infer; - -export function useLeaderboardDetails(first?: number) { - const { - filterParams: { chainId }, - } = useLeaderboardSearch(); - - return useQuery({ - queryFn: async () => { - if (chainId === -1) { - return []; - } - - const { data } = await httpService.get(apiPaths.leaderboardDetails.path, { - params: { chainId, first }, - }); - - const validResponse = validateResponse( - data, - leaderBoardSuccessResponseSchema - ); - - return validResponse; - }, - queryKey: ['useLeaderboardDetails', chainId, first], - }); -} diff --git a/packages/apps/dashboard/client/src/services/api/use-transaction-details.tsx b/packages/apps/dashboard/client/src/services/api/use-transaction-details.tsx deleted file mode 100644 index b4f2fe453c..0000000000 --- a/packages/apps/dashboard/client/src/services/api/use-transaction-details.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { z } from 'zod'; - -import { validateResponse } from '@/services/validate-response'; -import { useTransactionDetailsDto } from '@/utils/hooks/use-transactions-details-dto'; -import { useWalletSearch } from '@/utils/hooks/use-wallet-search'; - -import { apiPaths } from '../api-paths'; -import { httpService } from '../http-service'; - -const internalTransactionSchema = z.object({ - from: z.string(), - to: z.string(), - value: z.string(), - method: z.string(), - receiver: z.string().nullable(), - escrow: z.string().nullable(), - token: z.string().nullable(), -}); -const transactionDetailsSuccessResponseSchema = z.object({ - txHash: z.string(), - method: z.string(), - from: z.string(), - to: z.string(), - receiver: z.string().nullable(), - block: z.number(), - value: z.string(), - internalTransactions: z.array(internalTransactionSchema), -}); - -export type TransactionDetails = z.infer< - typeof transactionDetailsSuccessResponseSchema ->; - -const paginatedTransactionDetailsSuccessResponseSchema = z.object({ - address: z.string(), - chainId: z.number(), - first: z.number(), - skip: z.number(), - results: z.array(transactionDetailsSuccessResponseSchema), -}); - -export type PaginatedTransactionDetails = z.infer< - typeof paginatedTransactionDetailsSuccessResponseSchema ->; - -export interface PaginatedTransactionDetailsDto { - skip: number; - first: number; - chainId: number; -} - -export function useTransactionDetails() { - const { filterParams } = useWalletSearch(); - const { - params, - pagination: { lastPageIndex, page }, - setLastPageIndex, - } = useTransactionDetailsDto(); - - const dto: PaginatedTransactionDetailsDto = { - chainId: filterParams.chainId, - skip: params.skip, - first: params.first, - }; - - return useQuery({ - queryFn: async () => { - const { data } = await httpService.get( - `${apiPaths.transactionDetails.path}/${filterParams.address}`, - { - params: dto, - } - ); - - const validResponse = validateResponse( - data, - paginatedTransactionDetailsSuccessResponseSchema - ); - - // check if last page - if (lastPageIndex === undefined) { - const { data: lastPageCheckData } = await httpService.get( - `${apiPaths.transactionDetails.path}/${filterParams.address}`, - { - params: { - ...dto, - skip: dto.skip + validResponse.results.length, - first: 1, - }, - } - ); - const validLastPageCheckData = validateResponse( - lastPageCheckData, - paginatedTransactionDetailsSuccessResponseSchema - ); - - if (validLastPageCheckData.results.length === 0) { - setLastPageIndex(page + 1); - } - } - - return validResponse; - }, - queryKey: ['useTransactionDetails', filterParams.address, dto], - }); -} diff --git a/packages/apps/dashboard/client/src/services/http-service.ts b/packages/apps/dashboard/client/src/services/http-service.ts deleted file mode 100644 index 92fbd08e36..0000000000 --- a/packages/apps/dashboard/client/src/services/http-service.ts +++ /dev/null @@ -1,7 +0,0 @@ -import axios from 'axios'; - -import { env } from '../helpers/env'; - -export const httpService = axios.create({ - baseURL: env.VITE_API_URL, -}); diff --git a/packages/apps/dashboard/client/src/services/api-paths.ts b/packages/apps/dashboard/client/src/shared/api/apiPaths.ts similarity index 93% rename from packages/apps/dashboard/client/src/services/api-paths.ts rename to packages/apps/dashboard/client/src/shared/api/apiPaths.ts index dfa16f9f30..8bff832b59 100644 --- a/packages/apps/dashboard/client/src/services/api-paths.ts +++ b/packages/apps/dashboard/client/src/shared/api/apiPaths.ts @@ -1,4 +1,4 @@ -export const apiPaths = { +const apiPaths = { hcaptchaGeneralStats: { path: '/stats/hcaptcha/general', }, @@ -33,3 +33,5 @@ export const apiPaths = { path: '/details/kvstore', }, } as const; + +export default apiPaths; diff --git a/packages/apps/dashboard/client/src/shared/api/httpClient.ts b/packages/apps/dashboard/client/src/shared/api/httpClient.ts new file mode 100644 index 0000000000..0a222e29e8 --- /dev/null +++ b/packages/apps/dashboard/client/src/shared/api/httpClient.ts @@ -0,0 +1,9 @@ +import axios from 'axios'; + +import { env } from '@/shared/config/env'; + +const httpClient = axios.create({ + baseURL: env.VITE_API_URL, +}); + +export default httpClient; diff --git a/packages/apps/dashboard/client/src/utils/hooks/use-filtered-networks.ts b/packages/apps/dashboard/client/src/shared/api/useFilteredNetworks.ts similarity index 67% rename from packages/apps/dashboard/client/src/utils/hooks/use-filtered-networks.ts rename to packages/apps/dashboard/client/src/shared/api/useFilteredNetworks.ts index 3cc624434e..861b903ca0 100644 --- a/packages/apps/dashboard/client/src/utils/hooks/use-filtered-networks.ts +++ b/packages/apps/dashboard/client/src/shared/api/useFilteredNetworks.ts @@ -3,13 +3,14 @@ import { useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; import { z } from 'zod'; -import { apiPaths } from '@/services/api-paths'; -import { httpService } from '@/services/http-service'; -import { networks as allNetworks } from '@/utils/config/networks'; +import { networks as allNetworks } from '@/shared/lib/networks'; + +import apiPaths from './apiPaths'; +import httpClient from './httpClient'; const enabledChainsSchema = z.array(z.number()); -export const useFilteredNetworks = () => { +const useFilteredNetworks = () => { const { data: enabledChains, isLoading, @@ -17,7 +18,7 @@ export const useFilteredNetworks = () => { } = useQuery({ queryKey: ['enabledChains'], queryFn: async () => { - const response = await httpService.get(apiPaths.enabledChains.path); + const response = await httpClient.get(apiPaths.enabledChains.path); return enabledChainsSchema.parse(response.data); }, }); @@ -30,3 +31,5 @@ export const useFilteredNetworks = () => { return { filteredNetworks, isLoading, error }; }; + +export default useFilteredNetworks; diff --git a/packages/apps/dashboard/client/src/shared/api/useHmtPrice.ts b/packages/apps/dashboard/client/src/shared/api/useHmtPrice.ts new file mode 100644 index 0000000000..ad74d8cf2a --- /dev/null +++ b/packages/apps/dashboard/client/src/shared/api/useHmtPrice.ts @@ -0,0 +1,28 @@ +import { useQuery } from '@tanstack/react-query'; +import { z } from 'zod'; + +import validateResponse from '@/shared/lib/validateResponse'; + +import apiPaths from './apiPaths'; +import httpClient from './httpClient'; + +const hmtPriceResponseSchema = z.object({ + hmtPrice: z.number(), +}); + +export type HmtPrice = z.infer; + +const useHmtPrice = () => { + return useQuery({ + queryFn: async () => { + const { data } = await httpClient.get(apiPaths.statsHmtPrice.path); + + const validResponse = validateResponse(data, hmtPriceResponseSchema); + + return validResponse.hmtPrice; + }, + queryKey: ['useHmtPrice'], + }); +}; + +export default useHmtPrice; diff --git a/packages/apps/dashboard/client/src/helpers/env.ts b/packages/apps/dashboard/client/src/shared/config/env.ts similarity index 100% rename from packages/apps/dashboard/client/src/helpers/env.ts rename to packages/apps/dashboard/client/src/shared/config/env.ts diff --git a/packages/apps/dashboard/client/src/utils/hooks/use-breakpoints.tsx b/packages/apps/dashboard/client/src/shared/hooks/useBreakpoints.tsx similarity index 100% rename from packages/apps/dashboard/client/src/utils/hooks/use-breakpoints.tsx rename to packages/apps/dashboard/client/src/shared/hooks/useBreakpoints.tsx diff --git a/packages/apps/dashboard/client/src/shared/lib/abbreviateAddress.ts b/packages/apps/dashboard/client/src/shared/lib/abbreviateAddress.ts new file mode 100644 index 0000000000..39cfa892b0 --- /dev/null +++ b/packages/apps/dashboard/client/src/shared/lib/abbreviateAddress.ts @@ -0,0 +1,12 @@ +const abbreviateAddress = (address: string | null) => { + if (address) { + const first3Letters = address.slice(0, 5); + const last5Letters = address.slice(-5); + + return `${first3Letters}...${last5Letters}`; + } + + return null; +}; + +export default abbreviateAddress; diff --git a/packages/apps/dashboard/client/src/shared/lib/convertSnakeToHumanReadable.ts b/packages/apps/dashboard/client/src/shared/lib/convertSnakeToHumanReadable.ts new file mode 100644 index 0000000000..ea4b8843ed --- /dev/null +++ b/packages/apps/dashboard/client/src/shared/lib/convertSnakeToHumanReadable.ts @@ -0,0 +1,8 @@ +const convertSnakeToHumanReadable = (string: string) => { + return string + .split('_') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) + .join(' '); +}; + +export default convertSnakeToHumanReadable; diff --git a/packages/apps/dashboard/client/src/helpers/formatHMTDecimals.ts b/packages/apps/dashboard/client/src/shared/lib/formatHmtDecimals.ts similarity index 87% rename from packages/apps/dashboard/client/src/helpers/formatHMTDecimals.ts rename to packages/apps/dashboard/client/src/shared/lib/formatHmtDecimals.ts index 8a6adfd05b..c0610ad83b 100644 --- a/packages/apps/dashboard/client/src/helpers/formatHMTDecimals.ts +++ b/packages/apps/dashboard/client/src/shared/lib/formatHmtDecimals.ts @@ -1,6 +1,6 @@ import { formatEther } from 'ethers'; -export const formatHMTDecimals = (value: string) => { +const formatHmtDecimals = (value: string) => { const formattedValue = Number(formatEther(value)); if (Number.isInteger(formattedValue)) { @@ -22,3 +22,5 @@ export const formatHMTDecimals = (value: string) => { ? formattedValue.toFixed(4) : formattedValue.toString(); }; + +export default formatHmtDecimals; diff --git a/packages/apps/dashboard/client/src/services/handle-error-message.ts b/packages/apps/dashboard/client/src/shared/lib/handleErrorMessage.ts similarity index 76% rename from packages/apps/dashboard/client/src/services/handle-error-message.ts rename to packages/apps/dashboard/client/src/shared/lib/handleErrorMessage.ts index 4e69c870ac..ff81428b80 100644 --- a/packages/apps/dashboard/client/src/services/handle-error-message.ts +++ b/packages/apps/dashboard/client/src/shared/lib/handleErrorMessage.ts @@ -1,7 +1,7 @@ import { AxiosError } from 'axios'; import { ZodError } from 'zod'; -export function handleErrorMessage(unknownError: unknown): string { +const handleErrorMessage = (unknownError: unknown): string => { if (unknownError instanceof AxiosError) { return unknownError.message; } @@ -15,4 +15,6 @@ export function handleErrorMessage(unknownError: unknown): string { } return 'Something went wrong'; -} +}; + +export default handleErrorMessage; diff --git a/packages/apps/dashboard/client/src/shared/lib/isValidEvmAddress.ts b/packages/apps/dashboard/client/src/shared/lib/isValidEvmAddress.ts new file mode 100644 index 0000000000..375c45011b --- /dev/null +++ b/packages/apps/dashboard/client/src/shared/lib/isValidEvmAddress.ts @@ -0,0 +1,6 @@ +const isValidEVMAddress = (input: string): boolean => { + const evmRegex = /^0x[a-fA-F0-9]{40}$/; + return evmRegex.test(input); +}; + +export default isValidEVMAddress; diff --git a/packages/apps/dashboard/client/src/utils/config/networks.ts b/packages/apps/dashboard/client/src/shared/lib/networks.ts similarity index 96% rename from packages/apps/dashboard/client/src/utils/config/networks.ts rename to packages/apps/dashboard/client/src/shared/lib/networks.ts index 05d80ebb58..68d850c418 100644 --- a/packages/apps/dashboard/client/src/utils/config/networks.ts +++ b/packages/apps/dashboard/client/src/shared/lib/networks.ts @@ -1,7 +1,7 @@ import type { Chain } from 'viem/chains'; import * as chains from 'viem/chains'; -import { env } from '@/helpers/env'; +import { env } from '@/shared/config/env'; //TODO: temporal fix. Should be fetched from API. https://github.com/humanprotocol/human-protocol/issues/2855 const ENABLED_CHAIN_IDS = env.VITE_ENABLED_CHAIN_IDS; diff --git a/packages/apps/dashboard/client/src/services/validate-response.ts b/packages/apps/dashboard/client/src/shared/lib/validateResponse.ts similarity index 82% rename from packages/apps/dashboard/client/src/services/validate-response.ts rename to packages/apps/dashboard/client/src/shared/lib/validateResponse.ts index d91f29b073..d2c74bed9c 100644 --- a/packages/apps/dashboard/client/src/services/validate-response.ts +++ b/packages/apps/dashboard/client/src/shared/lib/validateResponse.ts @@ -1,6 +1,6 @@ import { ZodError, type z } from 'zod'; -export const validateResponse = ( +const validateResponse = ( object: unknown, zodObject: T ): z.infer => { @@ -19,3 +19,5 @@ export const validateResponse = ( throw error; } }; + +export default validateResponse; diff --git a/packages/apps/dashboard/client/src/shared/store/useGlobalFiltersStore.ts b/packages/apps/dashboard/client/src/shared/store/useGlobalFiltersStore.ts new file mode 100644 index 0000000000..0bfeef257c --- /dev/null +++ b/packages/apps/dashboard/client/src/shared/store/useGlobalFiltersStore.ts @@ -0,0 +1,21 @@ +import { create } from 'zustand'; + +type GlobalFiltersStore = { + address: string; + chainId: number; + setAddress: (address: string) => void; + setChainId: (chainId: number) => void; +}; + +const useGlobalFiltersStore = create((set) => ({ + address: '', + chainId: -1, + setAddress: (address) => { + set({ address }); + }, + setChainId: (chainId) => { + set({ chainId }); + }, +})); + +export default useGlobalFiltersStore; diff --git a/packages/apps/dashboard/client/src/services/global.type.ts b/packages/apps/dashboard/client/src/shared/types/global.type.ts similarity index 100% rename from packages/apps/dashboard/client/src/services/global.type.ts rename to packages/apps/dashboard/client/src/shared/types/global.type.ts diff --git a/packages/apps/dashboard/client/src/components/SearchResults/AbbreviateClipboard.tsx b/packages/apps/dashboard/client/src/shared/ui/AbbreviateClipboard/index.tsx similarity index 90% rename from packages/apps/dashboard/client/src/components/SearchResults/AbbreviateClipboard.tsx rename to packages/apps/dashboard/client/src/shared/ui/AbbreviateClipboard/index.tsx index f59a321b95..83c1e14638 100644 --- a/packages/apps/dashboard/client/src/components/SearchResults/AbbreviateClipboard.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/AbbreviateClipboard/index.tsx @@ -7,8 +7,8 @@ import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; import { useNavigate } from 'react-router-dom'; -import CustomTooltip from '@/components/CustomTooltip'; -import abbreviateValue from '@/helpers/abbreviateValue'; +import abbreviateAddress from '@/shared/lib/abbreviateAddress'; +import CustomTooltip from '@/shared/ui/CustomTooltip'; interface AbbreviateClipboardProps { value: string; @@ -49,11 +49,11 @@ const AbbreviateClipboard = ({ value, link }: AbbreviateClipboardProps) => { }, }} > - {abbreviateValue(value)} + {abbreviateAddress(value)} ) : ( - <>{abbreviateValue(value)} + <>{abbreviateAddress(value)} )}
, 'open' | 'onOpen' | 'onClose'>; } -const CustomDaterPicker = ({ props }: CustomDatePickerProps) => { - const [open, setOpen] = useState(false); +const CustomDatePicker = ({ props }: CustomDatePickerProps) => { + const [open, setOpen] = useState(false); return ( { return ( - = ({ role }) => { + switch (role) { + case Role.JobLauncher: + return ; + case Role.RecordingOracle: + return ; + case Role.ReputationOracle: + return ; + case Role.ExchangeOracle: + return ; + default: + return ; + } +}; + +export default EntityIcon; diff --git a/packages/apps/dashboard/client/src/shared/ui/FormattedNumber/index.tsx b/packages/apps/dashboard/client/src/shared/ui/FormattedNumber/index.tsx new file mode 100644 index 0000000000..43f4a848dd --- /dev/null +++ b/packages/apps/dashboard/client/src/shared/ui/FormattedNumber/index.tsx @@ -0,0 +1,22 @@ +import { FC } from 'react'; + +import { NumericFormat } from 'react-number-format'; + +type Props = { + value: number | string | undefined | null; + decimalScale?: number; +}; + +const FormattedNumber: FC = ({ value, decimalScale = 9 }) => { + return ( + + ); +}; + +export default FormattedNumber; diff --git a/packages/apps/dashboard/client/src/components/Loader/index.tsx b/packages/apps/dashboard/client/src/shared/ui/Loader/index.tsx similarity index 100% rename from packages/apps/dashboard/client/src/components/Loader/index.tsx rename to packages/apps/dashboard/client/src/shared/ui/Loader/index.tsx diff --git a/packages/apps/dashboard/client/src/shared/ui/NetworkIcon/index.tsx b/packages/apps/dashboard/client/src/shared/ui/NetworkIcon/index.tsx new file mode 100644 index 0000000000..5126ad866e --- /dev/null +++ b/packages/apps/dashboard/client/src/shared/ui/NetworkIcon/index.tsx @@ -0,0 +1,26 @@ +import { ChainId } from '@human-protocol/sdk'; + +import BinanceSmartChainIcon from '@/shared/ui/icons/BinanceSmartChainIcon'; +import EthereumIcon from '@/shared/ui/icons/EthereumIcon'; +import HumanIcon from '@/shared/ui/icons/HumanIcon'; +import PolygonIcon from '@/shared/ui/icons/PolygonIcon'; + +export const NetworkIcon = ({ chainId }: { chainId: ChainId }) => { + const icon = (() => { + switch (chainId) { + case 1: + case 11155111: + return ; + case 56: + case 97: + return ; + case 137: + case 80002: + return ; + default: + return ; + } + })(); + + return <>{icon}; +}; diff --git a/packages/apps/dashboard/client/src/components/SearchBar/SearchBar.tsx b/packages/apps/dashboard/client/src/shared/ui/SearchBar/index.tsx similarity index 77% rename from packages/apps/dashboard/client/src/components/SearchBar/SearchBar.tsx rename to packages/apps/dashboard/client/src/shared/ui/SearchBar/index.tsx index c8f5f325e6..939908955f 100644 --- a/packages/apps/dashboard/client/src/components/SearchBar/SearchBar.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/SearchBar/index.tsx @@ -17,13 +17,12 @@ import IconButton from '@mui/material/IconButton'; import clsx from 'clsx'; import { useNavigate } from 'react-router-dom'; -import CustomTooltip from '@/components/CustomTooltip'; -import { NetworkIcon } from '@/components/NetworkIcon'; -import { useIsMobile } from '@/utils/hooks/use-breakpoints'; -import { useFilteredNetworks } from '@/utils/hooks/use-filtered-networks'; -import { useWalletSearch } from '@/utils/hooks/use-wallet-search'; - -import { isValidEVMAddress } from '../../helpers/isValidEVMAddress'; +import useFilteredNetworks from '@/shared/api/useFilteredNetworks'; +import { useIsMobile } from '@/shared/hooks/useBreakpoints'; +import isValidEvmAddress from '@/shared/lib/isValidEvmAddress'; +import useGlobalFiltersStore from '@/shared/store/useGlobalFiltersStore'; +import CustomTooltip from '@/shared/ui/CustomTooltip'; +import { NetworkIcon } from '@/shared/ui/NetworkIcon'; import { endAdornmentInputAdornmentSx, @@ -33,12 +32,12 @@ import { muiTextFieldInputPropsSx, muiTextFieldSx, gridSx, -} from './SearchBar.styles'; +} from './styles'; -interface SearchBarProps { +type SearchBarProps = { className?: string; initialInputValue?: string; -} +}; const SearchBar: FC = ({ className = '', @@ -46,7 +45,7 @@ const SearchBar: FC = ({ }) => { const isMobile = useIsMobile(); const { filteredNetworks, isLoading } = useFilteredNetworks(); - const { filterParams, setChainId, setAddress } = useWalletSearch(); + const { address, chainId, setChainId, setAddress } = useGlobalFiltersStore(); const navigate = useNavigate(); const [inputValue, setInputValue] = useState(initialInputValue); const [error, setError] = useState(null); @@ -54,34 +53,30 @@ const SearchBar: FC = ({ const theme = useTheme(); useEffect(() => { - setInputValue(filterParams.address); - }, [filterParams.address]); + setInputValue(address); + }, [address]); useEffect(() => { - if ( - !isLoading && - filteredNetworks.length > 0 && - filterParams.chainId === -1 - ) { + if (!isLoading && filteredNetworks.length > 0 && chainId === -1) { setChainId(filteredNetworks[0].id); } - }, [filteredNetworks, isLoading, filterParams.chainId, setChainId]); + }, [filteredNetworks, isLoading, chainId, setChainId]); const navigateToAddress = useCallback(() => { - if (!isValidEVMAddress(inputValue)) { + if (!isValidEvmAddress(inputValue)) { setError('Invalid EVM address.'); return; } setAddress(inputValue); - navigate(`/search/${filterParams.chainId}/${inputValue}`); - }, [inputValue, filterParams.chainId, navigate, setAddress]); + navigate(`/search/${chainId}/${inputValue}`); + }, [inputValue, chainId, navigate, setAddress]); const handleInputChange = (event: React.ChangeEvent) => { const value = event.target.value; setInputValue(value); - if (isValidEVMAddress(value)) { + if (isValidEvmAddress(value)) { setError(null); } else if (value.length > 0) { setError('Invalid EVM address. Must start with 0x and be 42 characters.'); @@ -115,15 +110,12 @@ const SearchBar: FC = ({ const renderSelectedValue = ( n.id === filterParams.chainId)?.id || -1 - } + chainId={filteredNetworks.find((n) => n.id === chainId)?.id || -1} />
- {isMobile || filterParams.chainId === -1 + {isMobile || chainId === -1 ? null - : filteredNetworks.find((n) => n.id === filterParams.chainId)?.name || - ''} + : filteredNetworks.find((n) => n.id === chainId)?.name || ''}
); @@ -152,21 +144,19 @@ const SearchBar: FC = ({ sx={startAdornmentInputAdornmentSx(theme)} > - value={filterParams.chainId} + value={chainId} displayEmpty sx={muiSelectSx(theme)} onChange={handleSelectChange} renderValue={() => - filterParams.chainId === -1 - ? renderEmptyValue - : renderSelectedValue + chainId === -1 ? renderEmptyValue : renderSelectedValue } > {filteredNetworks.map((network) => ( diff --git a/packages/apps/dashboard/client/src/components/SearchBar/SearchBar.styles.ts b/packages/apps/dashboard/client/src/shared/ui/SearchBar/styles.ts similarity index 100% rename from packages/apps/dashboard/client/src/components/SearchBar/SearchBar.styles.ts rename to packages/apps/dashboard/client/src/shared/ui/SearchBar/styles.ts diff --git a/packages/apps/dashboard/client/src/components/SectionWrapper/index.tsx b/packages/apps/dashboard/client/src/shared/ui/SectionWrapper/index.tsx similarity index 100% rename from packages/apps/dashboard/client/src/components/SectionWrapper/index.tsx rename to packages/apps/dashboard/client/src/shared/ui/SectionWrapper/index.tsx diff --git a/packages/apps/dashboard/client/src/components/ShadowIcon/ShadowIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/ShadowIcon/index.tsx similarity index 100% rename from packages/apps/dashboard/client/src/components/ShadowIcon/ShadowIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/ShadowIcon/index.tsx diff --git a/packages/apps/dashboard/client/src/components/Icons/BinanceSmartChainIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/BinanceSmartChainIcon.tsx similarity index 99% rename from packages/apps/dashboard/client/src/components/Icons/BinanceSmartChainIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/BinanceSmartChainIcon.tsx index 4986041821..4e99f7ee6a 100644 --- a/packages/apps/dashboard/client/src/components/Icons/BinanceSmartChainIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/BinanceSmartChainIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const BinanceSmartChainIcon: FC = (props) => { +const BinanceSmartChainIcon: FC = (props) => { return ( = (props) => { +const DarkModeIcon: FC = (props) => { return ( = (props) => { ); }; + +export default DarkModeIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/DiscordIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/DiscordIcon.tsx similarity index 100% rename from packages/apps/dashboard/client/src/components/Icons/DiscordIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/DiscordIcon.tsx diff --git a/packages/apps/dashboard/client/src/components/Icons/EscrowAddressIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/EscrowAddressIcon.tsx similarity index 98% rename from packages/apps/dashboard/client/src/components/Icons/EscrowAddressIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/EscrowAddressIcon.tsx index 754095c5b6..fe065f746d 100644 --- a/packages/apps/dashboard/client/src/components/Icons/EscrowAddressIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/EscrowAddressIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const EscrowAddressIcon: FC = (props) => { +const EscrowAddressIcon: FC = (props) => { return ( = (props) => { ); }; + +export default EscrowAddressIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/EthereumIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/EthereumIcon.tsx similarity index 94% rename from packages/apps/dashboard/client/src/components/Icons/EthereumIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/EthereumIcon.tsx index 5166d0b871..61e39522cf 100644 --- a/packages/apps/dashboard/client/src/components/Icons/EthereumIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/EthereumIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const EthereumIcon: FC = (props) => { +const EthereumIcon: FC = (props) => { return ( diff --git a/packages/apps/dashboard/client/src/components/Icons/ExchangeOracleIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/ExchangeOracleIcon.tsx similarity index 93% rename from packages/apps/dashboard/client/src/components/Icons/ExchangeOracleIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/ExchangeOracleIcon.tsx index be1d4c4bfd..f4fd72d70d 100644 --- a/packages/apps/dashboard/client/src/components/Icons/ExchangeOracleIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/ExchangeOracleIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const ExchangeOracleIcon: FC = (props) => { +const ExchangeOracleIcon: FC = (props) => { return ( = (props) => { ); }; + +export default ExchangeOracleIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/HumanIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/HumanIcon.tsx similarity index 97% rename from packages/apps/dashboard/client/src/components/Icons/HumanIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/HumanIcon.tsx index cfcc3ab87c..90581b56c1 100644 --- a/packages/apps/dashboard/client/src/components/Icons/HumanIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/HumanIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const HumanIcon: FC = (props) => { +const HumanIcon: FC = (props) => { return ( = (props) => { +const JobLauncherIcon: FC = (props) => { return ( = (props) => { ); }; + +export default JobLauncherIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/LeaderboardIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/LeaderboardIcon.tsx similarity index 98% rename from packages/apps/dashboard/client/src/components/Icons/LeaderboardIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/LeaderboardIcon.tsx index b975b6d247..585a217543 100644 --- a/packages/apps/dashboard/client/src/components/Icons/LeaderboardIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/LeaderboardIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const LeaderboardIcon: FC = (props) => { +const LeaderboardIcon: FC = (props) => { return ( = (props) => { ); }; + +export default LeaderboardIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/LightModeIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/LightModeIcon.tsx similarity index 94% rename from packages/apps/dashboard/client/src/components/Icons/LightModeIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/LightModeIcon.tsx index eae0b2bd2e..5e8866c7f8 100644 --- a/packages/apps/dashboard/client/src/components/Icons/LightModeIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/LightModeIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const LightModeIcon: FC = (props) => { +const LightModeIcon: FC = (props) => { return ( = (props) => { ); }; + +export default LightModeIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/LogoBlockIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/LogoBlockIcon.tsx similarity index 99% rename from packages/apps/dashboard/client/src/components/Icons/LogoBlockIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/LogoBlockIcon.tsx index 82d9a19225..ea6291608a 100644 --- a/packages/apps/dashboard/client/src/components/Icons/LogoBlockIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/LogoBlockIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const LogoBlockIcon: FC = (props) => { +const LogoBlockIcon: FC = (props) => { return ( = (props) => { ); }; + +export default LogoBlockIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/LogoBlockIconMobile.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/LogoBlockIconMobile.tsx similarity index 99% rename from packages/apps/dashboard/client/src/components/Icons/LogoBlockIconMobile.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/LogoBlockIconMobile.tsx index 48f12c2a4e..1fdf5e9d2c 100644 --- a/packages/apps/dashboard/client/src/components/Icons/LogoBlockIconMobile.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/LogoBlockIconMobile.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const LogoBlockIconMobile: FC = (props) => { +const LogoBlockIconMobile: FC = (props) => { return ( = (props) => { ); }; + +export default LogoBlockIconMobile; diff --git a/packages/apps/dashboard/client/src/components/Icons/PolygonIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/PolygonIcon.tsx similarity index 97% rename from packages/apps/dashboard/client/src/components/Icons/PolygonIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/PolygonIcon.tsx index 9233ed8930..0eb1c1ef40 100644 --- a/packages/apps/dashboard/client/src/components/Icons/PolygonIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/PolygonIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const PolygonIcon: FC = (props) => { +const PolygonIcon: FC = (props) => { return ( = (props) => { +const RecordingOracleIcon: FC = (props) => { return ( = (props) => { ); }; + +export default RecordingOracleIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/ReputationOracle.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/ReputationOracleIcon.tsx similarity index 95% rename from packages/apps/dashboard/client/src/components/Icons/ReputationOracle.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/ReputationOracleIcon.tsx index 6a0bfee79c..67639b7fca 100644 --- a/packages/apps/dashboard/client/src/components/Icons/ReputationOracle.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/ReputationOracleIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const ReputationOracle: FC = (props) => { +const ReputationOracleIcon: FC = (props) => { return ( = (props) => { ); }; + +export default ReputationOracleIcon; diff --git a/packages/apps/dashboard/client/src/components/Icons/WalletIcon.tsx b/packages/apps/dashboard/client/src/shared/ui/icons/WalletIcon.tsx similarity index 99% rename from packages/apps/dashboard/client/src/components/Icons/WalletIcon.tsx rename to packages/apps/dashboard/client/src/shared/ui/icons/WalletIcon.tsx index 00a4435de9..d8f159c4fa 100644 --- a/packages/apps/dashboard/client/src/components/Icons/WalletIcon.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/icons/WalletIcon.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon'; -export const WalletIcon: FC = (props) => { +const WalletIcon: FC = (props) => { return ( = (props) => { ); }; + +export default WalletIcon; diff --git a/packages/apps/dashboard/client/src/theme.tsx b/packages/apps/dashboard/client/src/shared/ui/theme/index.tsx similarity index 71% rename from packages/apps/dashboard/client/src/theme.tsx rename to packages/apps/dashboard/client/src/shared/ui/theme/index.tsx index 55d021e695..56307ab400 100644 --- a/packages/apps/dashboard/client/src/theme.tsx +++ b/packages/apps/dashboard/client/src/shared/ui/theme/index.tsx @@ -7,6 +7,8 @@ import { PaletteColor, } from '@mui/material/styles/createPalette'; +import { lightPalette, darkPalette } from './palette'; + declare module '@mui/material/Typography' { interface TypographyPropsVariantOverrides { tooltip: true; @@ -97,145 +99,7 @@ export const createAppTheme = (mode: 'light' | 'dark') => { return createTheme({ palette: { mode, - ...(mode === 'light' - ? { - primary: { - main: '#320a8d', - light: '#320a8d', - }, - secondary: { - main: '#6309ff', - light: '#1406B280', - dark: '#14062b', - }, - text: { - primary: '#320a8d', - secondary: '#858ec6', - }, - info: { - main: '#eeeeee', - light: '#f5f5f5', - dark: '#bdbdbd', - }, - sky: { - main: '#858ec6', - light: '#858ec6', - dark: '#dadef0cc', - contrastText: '#858ec6', - }, - white: { - main: '#ffffff', - light: '#f6f5fc', - dark: '#f6f7fe', - contrastText: '#f9faff', - }, - success: { - main: '#0ad397', - light: '#2e7d3280', - }, - warning: { - main: '#ffb300', - light: '#ffd54f', - }, - error: { - main: '#ffb300', - light: '#f20d5f', - }, - orange: { - main: '#ed6c02', - light: '#ed6c0280', - }, - ocean: { - main: '#304ffe', - light: '#8c9eff', - dark: '#03a9f4', - }, - fog: { - main: '#858ec6', - light: '#cbcfe6', - dark: '#e5e7f3', - }, - link: { - main: '#0000ee', - hover: '#1406b2', - visited: '#551a8b', - }, - table: { - main: '#ffffff01', - selected: '#1406b21f', - secondary: '#1406b20a', - }, - overlay: '#1406b20a', - } - : { - primary: { - main: '#320a8d', - light: '#320a8d', - }, - secondary: { - main: '#6309ff', - light: '#1406B280', - dark: '#14062b', - }, - text: { - primary: '#320a8d', - secondary: '#858ec6', - }, - info: { - main: '#eeeeee', - light: '#f5f5f5', - dark: '#bdbdbd', - }, - sky: { - main: '#858ec6', - light: '#858ec6', - dark: '#dadef0cc', - contrastText: '#858ec6', - }, - white: { - main: '#ffffff', - light: '#f6f5fc', - dark: '#f6f7fe', - contrastText: '#f9faff', - }, - success: { - main: '#0ad397', - light: '#2e7d3280', - }, - warning: { - main: '#ffb300', - light: '#ffd54f', - }, - error: { - main: '#ffb300', - light: '#f20d5f', - }, - orange: { - main: '#ed6c02', - light: '#ed6c0280', - }, - ocean: { - main: '#304ffe', - light: '#8c9eff', - dark: '#03a9f4', - }, - fog: { - main: '#858ec6', - light: '#cbcfe6', - dark: '#e5e7f3', - }, - link: { - main: '#0000ee', - hover: '#1406b2', - visited: '#551a8b', - }, - table: { - main: '#ffffff01', - selected: '#1406b21f', - secondary: '#1406b20a', - }, - overlay: '#1406b20a', - }), + ...(mode === 'light' ? lightPalette : darkPalette), }, typography: { fontFamily: 'Inter, Arial, sans-serif', diff --git a/packages/apps/dashboard/client/src/shared/ui/theme/palette.ts b/packages/apps/dashboard/client/src/shared/ui/theme/palette.ts new file mode 100644 index 0000000000..7790326b36 --- /dev/null +++ b/packages/apps/dashboard/client/src/shared/ui/theme/palette.ts @@ -0,0 +1,139 @@ +export const lightPalette = { + primary: { + main: '#320a8d', + light: '#320a8d', + }, + secondary: { + main: '#6309ff', + light: '#1406B280', + dark: '#14062b', + }, + text: { + primary: '#320a8d', + secondary: '#858ec6', + }, + info: { + main: '#eeeeee', + light: '#f5f5f5', + dark: '#bdbdbd', + }, + sky: { + main: '#858ec6', + light: '#858ec6', + dark: '#dadef0cc', + contrastText: '#858ec6', + }, + white: { + main: '#ffffff', + light: '#f6f5fc', + dark: '#f6f7fe', + contrastText: '#f9faff', + }, + success: { + main: '#0ad397', + light: '#2e7d3280', + }, + warning: { + main: '#ffb300', + light: '#ffd54f', + }, + error: { + main: '#ffb300', + light: '#f20d5f', + }, + orange: { + main: '#ed6c02', + light: '#ed6c0280', + }, + ocean: { + main: '#304ffe', + light: '#8c9eff', + dark: '#03a9f4', + }, + fog: { + main: '#858ec6', + light: '#cbcfe6', + dark: '#e5e7f3', + }, + link: { + main: '#0000ee', + hover: '#1406b2', + visited: '#551a8b', + }, + table: { + main: '#ffffff01', + selected: '#1406b21f', + secondary: '#1406b20a', + }, + overlay: '#1406b20a', +}; + +export const darkPalette = { + primary: { + main: '#320a8d', + light: '#320a8d', + }, + secondary: { + main: '#6309ff', + light: '#1406B280', + dark: '#14062b', + }, + text: { + primary: '#320a8d', + secondary: '#858ec6', + }, + info: { + main: '#eeeeee', + light: '#f5f5f5', + dark: '#bdbdbd', + }, + sky: { + main: '#858ec6', + light: '#858ec6', + dark: '#dadef0cc', + contrastText: '#858ec6', + }, + white: { + main: '#ffffff', + light: '#f6f5fc', + dark: '#f6f7fe', + contrastText: '#f9faff', + }, + success: { + main: '#0ad397', + light: '#2e7d3280', + }, + warning: { + main: '#ffb300', + light: '#ffd54f', + }, + error: { + main: '#ffb300', + light: '#f20d5f', + }, + orange: { + main: '#ed6c02', + light: '#ed6c0280', + }, + ocean: { + main: '#304ffe', + light: '#8c9eff', + dark: '#03a9f4', + }, + fog: { + main: '#858ec6', + light: '#cbcfe6', + dark: '#e5e7f3', + }, + link: { + main: '#0000ee', + hover: '#1406b2', + visited: '#551a8b', + }, + table: { + main: '#ffffff01', + selected: '#1406b21f', + secondary: '#1406b20a', + }, + overlay: '#1406b20a', +}; diff --git a/packages/apps/dashboard/client/src/utils/case-converter.ts b/packages/apps/dashboard/client/src/utils/case-converter.ts deleted file mode 100644 index d17b45eaf0..0000000000 --- a/packages/apps/dashboard/client/src/utils/case-converter.ts +++ /dev/null @@ -1,8 +0,0 @@ -export class CaseConverter { - static convertSnakeToHumanReadable(string: string): string { - return string - .split('_') - .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) - .join(' '); - } -} diff --git a/packages/apps/dashboard/client/src/utils/hooks/use-escrows-details-dto.ts b/packages/apps/dashboard/client/src/utils/hooks/use-escrows-details-dto.ts deleted file mode 100644 index deabad31bf..0000000000 --- a/packages/apps/dashboard/client/src/utils/hooks/use-escrows-details-dto.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { create } from 'zustand'; - -export interface EscrowDetailsDto { - params: { - first: number; - skip: number; - }; - pagination: { - page: number; - pageSize: number; - lastPageIndex?: number; - }; - setNextPage: () => void; - setPrevPage: () => void; - setPageSize: (pageSize: number) => void; - setLastPageIndex: (lastPageIndex: number | undefined) => void; -} - -const INITIAL_PAGE_SIZE = 10; - -export const useEscrowDetailsDto = create((set) => ({ - params: { - first: INITIAL_PAGE_SIZE, - skip: 0, - }, - pagination: { - page: 0, - pageSize: INITIAL_PAGE_SIZE, - lastPage: false, - }, - setNextPage() { - set((state) => { - const nextPage = state.pagination.page + 1; - const newSkip = nextPage * state.params.first; - - return { - ...state, - params: { - ...state.params, - skip: newSkip, - }, - pagination: { - ...state.pagination, - page: nextPage, - }, - }; - }); - }, - setPrevPage() { - set((state) => { - const prevPage = - state.pagination.page === 0 ? 0 : state.pagination.page - 1; - const offSetPages = prevPage === 0 ? 0 : state.pagination.page - 1; - const newSkip = state.params.first * offSetPages; - - return { - ...state, - params: { - ...state.params, - skip: newSkip, - }, - pagination: { - ...state.pagination, - page: prevPage, - }, - }; - }); - }, - setPageSize(pageSize: number) { - set((state) => { - return { - ...state, - pagination: { - lastPage: false, - page: 0, - pageSize: pageSize, - }, - params: { - ...state.params, - first: pageSize, - skip: 0, - }, - }; - }); - }, - setLastPageIndex(lastPageIndex: number | undefined) { - set((state) => { - return { - ...state, - pagination: { - ...state.pagination, - lastPageIndex, - }, - }; - }); - }, -})); diff --git a/packages/apps/dashboard/client/src/utils/hooks/use-leaderboard-search.ts b/packages/apps/dashboard/client/src/utils/hooks/use-leaderboard-search.ts deleted file mode 100644 index f470ac22b9..0000000000 --- a/packages/apps/dashboard/client/src/utils/hooks/use-leaderboard-search.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { create } from 'zustand'; - -export interface LeaderboardSearchStore { - filterParams: { - chainId: number; - }; - setChainId: (chainId: number) => void; -} - -export const useLeaderboardSearch = create((set) => ({ - filterParams: { - chainId: -1, - }, - setChainId: (chainId) => { - set((state) => ({ - filterParams: { - ...state.filterParams, - chainId, - }, - })); - }, -})); diff --git a/packages/apps/dashboard/client/src/utils/hooks/use-transactions-details-dto.ts b/packages/apps/dashboard/client/src/utils/hooks/use-transactions-details-dto.ts deleted file mode 100644 index ce4219c922..0000000000 --- a/packages/apps/dashboard/client/src/utils/hooks/use-transactions-details-dto.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { create } from 'zustand'; - -export interface TransactionDetailsDto { - params: { - first: number; - skip: number; - }; - pagination: { - page: number; - pageSize: number; - lastPageIndex?: number; - }; - setNextPage: () => void; - setPrevPage: () => void; - setPageSize: (pageSize: number) => void; - setLastPageIndex: (lastPageIndex: number | undefined) => void; -} - -const INITIAL_PAGE_SIZE = 10; - -export const useTransactionDetailsDto = create( - (set) => ({ - params: { - first: INITIAL_PAGE_SIZE, - skip: 0, - }, - pagination: { - page: 0, - pageSize: INITIAL_PAGE_SIZE, - lastPage: false, - }, - setNextPage() { - set((state) => { - const nextPage = state.pagination.page + 1; - const newSkip = nextPage * state.params.first; - - return { - ...state, - params: { - ...state.params, - skip: newSkip, - }, - pagination: { - ...state.pagination, - page: nextPage, - }, - }; - }); - }, - setPrevPage() { - set((state) => { - const prevPage = - state.pagination.page === 0 ? 0 : state.pagination.page - 1; - const offSetPages = prevPage === 0 ? 0 : state.pagination.page - 1; - const newSkip = state.params.first * offSetPages; - - return { - ...state, - params: { - ...state.params, - skip: newSkip, - }, - pagination: { - ...state.pagination, - page: prevPage, - }, - }; - }); - }, - setPageSize(pageSize: number) { - set((state) => { - return { - ...state, - pagination: { - lastPage: false, - page: 0, - pageSize: pageSize, - }, - params: { - ...state.params, - first: pageSize, - skip: 0, - }, - }; - }); - }, - setLastPageIndex(lastPageIndex: number | undefined) { - set((state) => { - return { - ...state, - pagination: { - ...state.pagination, - lastPageIndex, - }, - }; - }); - }, - }) -); diff --git a/packages/apps/dashboard/client/src/utils/hooks/use-wallet-search.ts b/packages/apps/dashboard/client/src/utils/hooks/use-wallet-search.ts deleted file mode 100644 index 6ff0ec5092..0000000000 --- a/packages/apps/dashboard/client/src/utils/hooks/use-wallet-search.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { create } from 'zustand'; - -export interface WalletSearchStore { - filterParams: { - address: string; - chainId: number; - }; - setAddress: (address: string) => void; - setChainId: (chainId: number) => void; -} - -export const useWalletSearch = create((set) => ({ - filterParams: { - address: '', - chainId: -1, - }, - setAddress: (address) => { - set((state) => ({ - filterParams: { - ...state.filterParams, - address, - }, - })); - }, - setChainId: (chainId) => { - set((state) => ({ - filterParams: { - ...state.filterParams, - chainId, - }, - })); - }, -})); diff --git a/packages/apps/dashboard/client/src/widgets/footer/index.ts b/packages/apps/dashboard/client/src/widgets/footer/index.ts new file mode 100644 index 0000000000..95b6a1947f --- /dev/null +++ b/packages/apps/dashboard/client/src/widgets/footer/index.ts @@ -0,0 +1 @@ +export { default } from './ui/Footer'; diff --git a/packages/apps/dashboard/client/src/components/Footer/Footer.tsx b/packages/apps/dashboard/client/src/widgets/footer/ui/Footer.tsx similarity index 97% rename from packages/apps/dashboard/client/src/components/Footer/Footer.tsx rename to packages/apps/dashboard/client/src/widgets/footer/ui/Footer.tsx index a649b59936..1695d72ed0 100644 --- a/packages/apps/dashboard/client/src/components/Footer/Footer.tsx +++ b/packages/apps/dashboard/client/src/widgets/footer/ui/Footer.tsx @@ -9,8 +9,8 @@ import Box from '@mui/material/Box'; import Link from '@mui/material/Link'; import Typography from '@mui/material/Typography'; -import DiscordIcon from '@/components/Icons/DiscordIcon'; -import { env } from '@/helpers/env'; +import { env } from '@/shared/config/env'; +import DiscordIcon from '@/shared/ui/icons/DiscordIcon'; const StyledLink = styled(Link)(({ theme }) => ({ textDecoration: 'none', diff --git a/packages/apps/dashboard/client/src/widgets/header/index.ts b/packages/apps/dashboard/client/src/widgets/header/index.ts new file mode 100644 index 0000000000..529d6ba12a --- /dev/null +++ b/packages/apps/dashboard/client/src/widgets/header/index.ts @@ -0,0 +1 @@ +export { default } from './ui/Header'; diff --git a/packages/apps/dashboard/client/src/components/Header/Header.tsx b/packages/apps/dashboard/client/src/widgets/header/ui/Header.tsx similarity index 95% rename from packages/apps/dashboard/client/src/components/Header/Header.tsx rename to packages/apps/dashboard/client/src/widgets/header/ui/Header.tsx index 1d0197b81f..8b2703c8e4 100644 --- a/packages/apps/dashboard/client/src/components/Header/Header.tsx +++ b/packages/apps/dashboard/client/src/widgets/header/ui/Header.tsx @@ -12,9 +12,9 @@ import styled from '@mui/material/styles/styled'; import Toolbar from '@mui/material/Toolbar'; import { Link } from 'react-router-dom'; -import { LogoBlockIcon } from '@/components/Icons/LogoBlockIcon'; -import { LogoBlockIconMobile } from '@/components/Icons/LogoBlockIconMobile'; -import { env } from '@/helpers/env'; +import { env } from '@/shared/config/env'; +import LogoBlockIcon from '@/shared/ui/icons/LogoBlockIcon'; +import LogoBlockIconMobile from '@/shared/ui/icons/LogoBlockIconMobile'; const NavLink = styled(MuiLink)(({ theme }) => ({ color: theme.palette.primary.main, diff --git a/packages/apps/dashboard/client/src/components/ThemeModeSwitch/index.tsx b/packages/apps/dashboard/client/src/widgets/header/ui/ThemeModeSwitch.tsx similarity index 72% rename from packages/apps/dashboard/client/src/components/ThemeModeSwitch/index.tsx rename to packages/apps/dashboard/client/src/widgets/header/ui/ThemeModeSwitch.tsx index ebcaaab1f0..7be9bd599c 100644 --- a/packages/apps/dashboard/client/src/components/ThemeModeSwitch/index.tsx +++ b/packages/apps/dashboard/client/src/widgets/header/ui/ThemeModeSwitch.tsx @@ -2,8 +2,8 @@ import { FC } from 'react'; import { IconButton, useTheme } from '@mui/material'; -import { DarkModeIcon } from '@/components/Icons/DarkModeIcon'; -import { LightModeIcon } from '@/components/Icons/LightModeIcon'; +import DarkModeIcon from '@/shared/ui/icons/DarkModeIcon'; +import LightModeIcon from '@/shared/ui/icons/LightModeIcon'; const ThemeModeSwitch: FC = () => { const { isDarkMode, toggleColorMode } = useTheme(); diff --git a/packages/apps/dashboard/client/src/widgets/page-wrapper/index.ts b/packages/apps/dashboard/client/src/widgets/page-wrapper/index.ts new file mode 100644 index 0000000000..e80355c905 --- /dev/null +++ b/packages/apps/dashboard/client/src/widgets/page-wrapper/index.ts @@ -0,0 +1 @@ +export { default } from './ui/PageWrapper'; diff --git a/packages/apps/dashboard/client/src/components/PageWrapper/PageWrapper.tsx b/packages/apps/dashboard/client/src/widgets/page-wrapper/ui/PageWrapper.tsx similarity index 86% rename from packages/apps/dashboard/client/src/components/PageWrapper/PageWrapper.tsx rename to packages/apps/dashboard/client/src/widgets/page-wrapper/ui/PageWrapper.tsx index d5061f2ad1..e4096036c4 100644 --- a/packages/apps/dashboard/client/src/components/PageWrapper/PageWrapper.tsx +++ b/packages/apps/dashboard/client/src/widgets/page-wrapper/ui/PageWrapper.tsx @@ -2,8 +2,8 @@ import { FC, PropsWithChildren } from 'react'; import clsx from 'clsx'; -import Footer from '@/components/Footer'; -import Header from '@/components/Header'; +import Footer from '@/widgets/footer'; +import Header from '@/widgets/header'; const PageWrapper: FC< PropsWithChildren<{ diff --git a/packages/apps/dashboard/client/tsconfig.json b/packages/apps/dashboard/client/tsconfig.json index e3e56d6ef4..6b867f9387 100644 --- a/packages/apps/dashboard/client/tsconfig.json +++ b/packages/apps/dashboard/client/tsconfig.json @@ -3,7 +3,7 @@ "target": "ES2022", "useDefineForClassFields": true, "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", + "module": "ES2022", "skipLibCheck": true, /* Bundler mode */ @@ -12,7 +12,7 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx", + "jsx": "preserve", /* Linting */ "strict": true, diff --git a/packages/apps/dashboard/client/vite.config.ts b/packages/apps/dashboard/client/vite.config.ts index 7ff2b356c4..1d90c510e5 100644 --- a/packages/apps/dashboard/client/vite.config.ts +++ b/packages/apps/dashboard/client/vite.config.ts @@ -3,16 +3,11 @@ import * as path from 'path'; import react from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; import { nodePolyfills } from 'vite-plugin-node-polyfills'; -import svgr from 'vite-plugin-svgr'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [ react(), - svgr({ - include: '**/*.svg', - exclude: 'src/assets/icons/excluded/**/*.svg', - }), nodePolyfills({ protocolImports: true, }), diff --git a/yarn.lock b/yarn.lock index e092f6ed77..e663727004 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3941,7 +3941,6 @@ __metadata: use-debounce: "npm:^10.0.2" vite: "npm:^6.2.4" vite-plugin-node-polyfills: "npm:^0.23.0" - vite-plugin-svgr: "npm:^4.2.0" zod: "npm:^3.23.8" zustand: "npm:^4.5.4" languageName: unknown