From 2e2dfd303ef6c9a23569095fbcd5a9333b2eff9c Mon Sep 17 00:00:00 2001 From: Edvin Dzidic Date: Fri, 9 May 2025 13:29:01 +0200 Subject: [PATCH 1/3] Add YPP referral pagination (#6503) * Add hook which correctly fetches and paginates ypp referral data, integrate hook and add necessary changes to make it work * Update VITE_YOUTUBE_SYNC_API_URL in .env --- packages/atlas/src/.env | 2 +- .../YppReferralTable/YppReferralTable.tsx | 6 +- .../src/hooks/useYppReferralPagination.ts | 59 +++++++++++++++++++ .../YppDashboardReferralsTab.tsx | 42 ++++--------- 4 files changed, 77 insertions(+), 32 deletions(-) create mode 100644 packages/atlas/src/hooks/useYppReferralPagination.ts diff --git a/packages/atlas/src/.env b/packages/atlas/src/.env index a703273f46..c2bec199a5 100644 --- a/packages/atlas/src/.env +++ b/packages/atlas/src/.env @@ -21,7 +21,7 @@ VITE_WALLET_CONNECT_PROJECT_ID=33b2609463e399daee8c51726546c8dd # YPP configuration VITE_GOOGLE_CONSOLE_CLIENT_ID=246331758613-rc1psegmsr9l4e33nqu8rre3gno5dsca.apps.googleusercontent.com -VITE_YOUTUBE_SYNC_API_URL=https://35.156.81.207.nip.io +VITE_YOUTUBE_SYNC_API_URL=https://172.236.19.60.nip.io VITE_YOUTUBE_COLLABORATOR_MEMBER_ID=18 # Analytics tools diff --git a/packages/atlas/src/components/YppReferralTable/YppReferralTable.tsx b/packages/atlas/src/components/YppReferralTable/YppReferralTable.tsx index 8ce702be07..46ddcf5d68 100644 --- a/packages/atlas/src/components/YppReferralTable/YppReferralTable.tsx +++ b/packages/atlas/src/components/YppReferralTable/YppReferralTable.tsx @@ -22,9 +22,9 @@ export type YppReferral = { type YppReferralTableProps = { isLoading: boolean data: YppReferral[] -} +} & Pick -export const YppReferralTable = ({ isLoading, data }: YppReferralTableProps) => { +export const YppReferralTable = ({ isLoading, data, pagination }: YppReferralTableProps) => { const mappedData: TableProps['data'] = useMemo( () => data.map((entry) => ({ @@ -41,6 +41,8 @@ export const YppReferralTable = ({ isLoading, data }: YppReferralTableProps) => title="Channels you referred" columns={COLUMNS} data={isLoading ? tableLoadingData : mappedData} + pagination={pagination} + pageSize={pagination?.itemsPerPage} /> ) } diff --git a/packages/atlas/src/hooks/useYppReferralPagination.ts b/packages/atlas/src/hooks/useYppReferralPagination.ts new file mode 100644 index 0000000000..c9d32b82d0 --- /dev/null +++ b/packages/atlas/src/hooks/useYppReferralPagination.ts @@ -0,0 +1,59 @@ +import { useMemo, useState } from 'react' +import { useQuery } from 'react-query' + +import { axiosInstance } from '@/api/axios' +import { YppReferral } from '@/components/YppReferralTable/YppReferralTable' +import { atlasConfig } from '@/config' +import { useUser } from '@/providers/user/user.hooks' +import { YppSyncedChannel } from '@/views/global/YppLandingView/YppLandingView.types' + +const YPP_SYNC_URL = atlasConfig.features.ypp.youtubeSyncApiUrl + +const separateListIntoChunks = (list: Array, chunkSize: number): Array => { + const chunks = [] + + for (let index = 0; index < list.length; index += chunkSize) { + chunks.push(list.slice(index, index + chunkSize)) + } + + return chunks +} + +export const useYppReferralPagination = ({ initialPageSize = 10 }: { initialPageSize?: number }) => { + const [currentPage, setCurrentPage] = useState(0) + const [perPage, setPerPage] = useState(initialPageSize) + const { channelId } = useUser() + + const { isLoading, data } = useQuery( + ['referralsTable', channelId], + () => axiosInstance.get(`${YPP_SYNC_URL}/channels/${channelId}/referrals`), + { enabled: !!channelId } + ) + + const yppReferrals: YppReferral[] = useMemo( + () => + // TODO: For large arrays, the creation of new Date instances for sorting might be a performance consideration. + data?.data + .sort((channelA, channelB) => new Date(channelB.createdAt).getTime() - new Date(channelA.createdAt).getTime()) + .map((channelData) => { + return { + date: new Date(channelData.createdAt), + channelId: String(channelData.joystreamChannelId), + status: channelData.yppStatus, + } + }) ?? [], + [data?.data] + ) + + const pages = separateListIntoChunks(yppReferrals, perPage) + + return { + currentPage, + setCurrentPage, + yppReferrals: pages[currentPage] ?? [], + totalCount: yppReferrals.length, + isLoading, + setPerPage, + perPage, + } +} diff --git a/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardReferralsTab/YppDashboardReferralsTab.tsx b/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardReferralsTab/YppDashboardReferralsTab.tsx index 030e516446..20b9549b37 100644 --- a/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardReferralsTab/YppDashboardReferralsTab.tsx +++ b/packages/atlas/src/views/studio/YppDashboard/tabs/YppDashboardReferralsTab/YppDashboardReferralsTab.tsx @@ -1,40 +1,18 @@ -import { useMemo } from 'react' -import { useQuery } from 'react-query' - -import { axiosInstance } from '@/api/axios' import { SvgActionLinkUrl } from '@/assets/icons' import { EmptyFallback } from '@/components/EmptyFallback' -import { YppReferral, YppReferralTable } from '@/components/YppReferralTable/YppReferralTable' +import { YppReferralTable } from '@/components/YppReferralTable/YppReferralTable' import { ReferralLinkButton } from '@/components/_ypp/ReferralLinkButton' -import { atlasConfig } from '@/config' -import { useUser } from '@/providers/user/user.hooks' -import { YppSyncedChannel } from '@/views/global/YppLandingView/YppLandingView.types' +import { useYppReferralPagination } from '@/hooks/useYppReferralPagination' import { FallbackContainer } from '../YppDashboardTabs.styles' -const YPP_SYNC_URL = atlasConfig.features.ypp.youtubeSyncApiUrl +const TILES_PER_PAGE = 10 export const YppDashboardReferralsTab = () => { - const { channelId } = useUser() - const { isLoading, data } = useQuery( - ['referralsTable', channelId], - () => axiosInstance.get(`${YPP_SYNC_URL}/channels/${channelId}/referrals`), - { enabled: !!channelId } - ) + const { isLoading, yppReferrals, currentPage, setCurrentPage, perPage, setPerPage, totalCount } = + useYppReferralPagination({ initialPageSize: TILES_PER_PAGE }) - const mappedData: YppReferral[] = useMemo( - () => - data?.data.map((channelData) => { - return { - date: new Date(channelData.createdAt), - channelId: String(channelData.joystreamChannelId), - status: channelData.yppStatus, - } - }) ?? [], - [data?.data] - ) - - if (!isLoading && !mappedData?.length) { + if (!isLoading && totalCount === 0) { return ( { ) } - return + return ( + + ) } From 515c12db70681596442f25837844cd8ce5694162 Mon Sep 17 00:00:00 2001 From: Edvin Dzidic Date: Fri, 9 May 2025 14:15:20 +0200 Subject: [PATCH 2/3] Add market transactions pagination (#6505) * Move fetching functionality and add pagination within useMarketTransactionsPagination hook, accomodate code to integrate pagination * Remove unnecessary comment * Update packages/atlas/src/hooks/useMarketTransactionsPagination.ts --------- Co-authored-by: Leszek Wiesner --- .../AmmTransactionsTable.tsx | 6 ++- .../hooks/useMarketTransactionsPagination.ts | 54 +++++++++++++++++++ .../studio/CrtDashboard/tabs/CrtMarketTab.tsx | 22 +++----- 3 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 packages/atlas/src/hooks/useMarketTransactionsPagination.ts diff --git a/packages/atlas/src/components/_crt/AmmTransactionsTable/AmmTransactionsTable.tsx b/packages/atlas/src/components/_crt/AmmTransactionsTable/AmmTransactionsTable.tsx index 878129a6df..9ab701a47e 100644 --- a/packages/atlas/src/components/_crt/AmmTransactionsTable/AmmTransactionsTable.tsx +++ b/packages/atlas/src/components/_crt/AmmTransactionsTable/AmmTransactionsTable.tsx @@ -50,9 +50,9 @@ type AmmTransactionsTableProps = { data: FullAmmCurveFragment['transactions'] loading: boolean symbol: string -} +} & Pick -export const AmmTransactionsTable = ({ data, loading, symbol }: AmmTransactionsTableProps) => { +export const AmmTransactionsTable = ({ data, loading, symbol, pagination }: AmmTransactionsTableProps) => { const mappedData = useMemo( () => data.map((row) => ({ @@ -80,6 +80,8 @@ export const AmmTransactionsTable = ({ data, loading, symbol }: AmmTransactionsT data={loading ? tableLoadingData : mappedData ?? []} columns={COLUMNS} emptyState={tableEmptyState} + pagination={pagination} + pageSize={pagination?.itemsPerPage} /> ) } diff --git a/packages/atlas/src/hooks/useMarketTransactionsPagination.ts b/packages/atlas/src/hooks/useMarketTransactionsPagination.ts new file mode 100644 index 0000000000..745ddf0569 --- /dev/null +++ b/packages/atlas/src/hooks/useMarketTransactionsPagination.ts @@ -0,0 +1,54 @@ +import { useState } from 'react' + +import { useGetFullAmmCurveQuery } from '@/api/queries/__generated__/creatorTokens.generated' +import { SentryLogger } from '@/utils/logs' + +const separateListIntoChunks = (list: Array, chunkSize: number): Array => { + const chunks = [] + + for (let index = 0; index < list.length; index += chunkSize) { + chunks.push(list.slice(index, index + chunkSize)) + } + + return chunks +} + +export const useMarketTransactionsPagination = ({ + ammId, + initialPageSize = 10, +}: { + ammId?: string + initialPageSize?: number +}) => { + const [currentPage, setCurrentPage] = useState(0) + const [perPage, setPerPage] = useState(initialPageSize) + + const { data, loading } = useGetFullAmmCurveQuery({ + variables: { + where: { + id_eq: ammId, + }, + }, + skip: !ammId, + onError: (error) => { + SentryLogger.error('Failed to fetch AMM curve', 'CrtMarketTab', error) + }, + }) + + const marketTransactions = data?.ammCurves[0].transactions ?? [] + + const pages = separateListIntoChunks( + [...marketTransactions].sort((transactionA, transactionB) => transactionB.createdIn - transactionA.createdIn), + perPage + ) + + return { + currentPage, + setCurrentPage, + marketTransactions: pages[currentPage] ?? [], + totalCount: marketTransactions.length, + loading, + setPerPage, + perPage, + } +} diff --git a/packages/atlas/src/views/studio/CrtDashboard/tabs/CrtMarketTab.tsx b/packages/atlas/src/views/studio/CrtDashboard/tabs/CrtMarketTab.tsx index dc45cf9830..737c0e3a02 100644 --- a/packages/atlas/src/views/studio/CrtDashboard/tabs/CrtMarketTab.tsx +++ b/packages/atlas/src/views/studio/CrtDashboard/tabs/CrtMarketTab.tsx @@ -1,7 +1,6 @@ import BN from 'bn.js' import { useMemo } from 'react' -import { useGetFullAmmCurveQuery } from '@/api/queries/__generated__/creatorTokens.generated' import { FullCreatorTokenFragment } from '@/api/queries/__generated__/fragments.generated' import { SvgJoyTokenMonochrome24 } from '@/assets/icons' import { FlexBox } from '@/components/FlexBox' @@ -10,29 +9,23 @@ import { WidgetTile } from '@/components/WidgetTile' import { AmmTransactionsTable } from '@/components/_crt/AmmTransactionsTable/AmmTransactionsTable' import { SkeletonLoader } from '@/components/_loaders/SkeletonLoader' import { atlasConfig } from '@/config' +import { useMarketTransactionsPagination } from '@/hooks/useMarketTransactionsPagination' import { useMediaMatch } from '@/hooks/useMediaMatch' import { HAPI_TO_JOY_RATE } from '@/joystream-lib/config' import { calcBuyMarketPricePerToken } from '@/utils/crts' -import { SentryLogger } from '@/utils/logs' type CrtMarketTabProps = { token: FullCreatorTokenFragment } +const TILES_PER_PAGE = 10 + export const CrtMarketTab = ({ token }: CrtMarketTabProps) => { const mdMatch = useMediaMatch('md') const currentAmm = token.ammCurves.find((curve) => !curve.finalized) - const { data, loading } = useGetFullAmmCurveQuery({ - variables: { - where: { - id_eq: currentAmm?.id, - }, - }, - skip: !currentAmm, - onError: (error) => { - SentryLogger.error('Failed to fetch AMM curve', 'CrtMarketTab', error) - }, - }) + const { loading, marketTransactions, currentPage, setCurrentPage, perPage, setPerPage, totalCount } = + useMarketTransactionsPagination({ ammId: currentAmm?.id, initialPageSize: TILES_PER_PAGE }) + const pricePerUnit = useMemo( () => calcBuyMarketPricePerToken(currentAmm?.mintedByAmm, currentAmm?.ammSlopeParameter, currentAmm?.ammInitPrice), [currentAmm?.ammInitPrice, currentAmm?.ammSlopeParameter, currentAmm?.mintedByAmm] @@ -103,7 +96,8 @@ export const CrtMarketTab = ({ token }: CrtMarketTabProps) => { ) From cc39bd7263372449ea6bc490395713cfc7d75378 Mon Sep 17 00:00:00 2001 From: Lezek123 Date: Fri, 9 May 2025 14:30:21 +0200 Subject: [PATCH 3/3] Update CHANGELOG and bump versions --- CHANGELOG.md | 9 ++++++++- package.json | 2 +- packages/atlas/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0af113783..5f8173a288 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [5.6.1] - 2026-05-09 + +### Fixed + +- YPP referrals pagination issue in Gleev studio: https://github.com/Joystream/atlas/issues/6502 +- Market transactions pagination issue in Gleev studio (CRT dashboard): https://github.com/Joystream/atlas/issues/6438 + ## [5.6.0] - 2024-12-23 **IMPORTANT:** Depends on Orion release `4.2.0`. @@ -19,7 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added hadling for `ExtrinsicFailed` errors - Added adequate cleanup of cached optimistic state on error - Fixed optimistic actions to be able to handle situations when there are multiple comments in `UNCONFIRMED` state -- Fixed a bug with invalid condition inside `transactions.manager.tsx` causing `onTxSync` to errously timeout in some cases. +- Fixed a bug with invalid condition inside `transactions.manager.tsx` causing `onTxSync` to errously timeout in some cases. ## [5.5.0] - 2024-11-07 diff --git a/package.json b/package.json index c08e5dc10a..8fa654b700 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "description": "UI for consuming Joystream - a user governed video platform", - "version": "5.6.0", + "version": "5.6.1", "license": "GPL-3.0", "workspaces": [ "packages/*" diff --git a/packages/atlas/package.json b/packages/atlas/package.json index d1eaa00449..fd21f46037 100644 --- a/packages/atlas/package.json +++ b/packages/atlas/package.json @@ -1,7 +1,7 @@ { "name": "@joystream/atlas", "description": "UI for consuming Joystream - a user governed video platform", - "version": "5.6.0", + "version": "5.6.1", "license": "GPL-3.0", "scripts": { "start": "vite",