From d6ac2cb1763b21ec69570b654830160fcddc446d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nishan=20=28o=5E=E2=96=BD=5Eo=29?= Date: Tue, 7 Nov 2023 09:06:44 +0530 Subject: [PATCH 1/6] fix: add buy sell retry mechanism (#2505) --- .../creator-token/use-creator-token-buy.ts | 32 +++++++++++++------ .../creator-token/use-creator-token-sell.ts | 31 ++++++++++++------ 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/packages/app/hooks/creator-token/use-creator-token-buy.ts b/packages/app/hooks/creator-token/use-creator-token-buy.ts index b60a100b7..b1936b8a6 100644 --- a/packages/app/hooks/creator-token/use-creator-token-buy.ts +++ b/packages/app/hooks/creator-token/use-creator-token-buy.ts @@ -6,10 +6,11 @@ import { creatorTokenSwapRouterAbi } from "app/abi/CreatorTokenSwapRouterAbi"; import { getChannelByIdCacheKey } from "app/components/creator-channels/hooks/use-channel-detail"; import { getChannelMessageKey } from "app/components/creator-channels/hooks/use-channel-messages"; import { axios } from "app/lib/axios"; +import { Logger } from "app/lib/logger"; import { useLogInPromise } from "app/lib/login-promise"; import { captureException } from "app/lib/sentry"; import { publicClient } from "app/lib/wallet-public-client"; -import { formatAPIErrorMessage } from "app/utilities"; +import { delay, formatAPIErrorMessage } from "app/utilities"; import { toast } from "design-system/toast"; @@ -191,15 +192,26 @@ export const useCreatorTokenBuy = (params: { }) ); - await axios({ - url: "/v1/creator-token/poll-buy", - method: "POST", - data: { - creator_token_id: profileData.data.profile.creator_token.id, - quantity: tokenAmount, - tx_hash: transactionHash, - }, - }); + for (let i = 0; i < 3; i++) { + try { + await axios({ + url: "/v1/creator-token/poll-buy", + method: "POST", + data: { + creator_token_id: + profileData.data.profile.creator_token.id, + quantity: tokenAmount, + tx_hash: transactionHash, + }, + }); + break; + } catch (e) { + Logger.error("tx not found"); + } + + await delay(2000); + } + mutate( (key: any) => { const channelId = profileData.data?.profile.channels[0]?.id; diff --git a/packages/app/hooks/creator-token/use-creator-token-sell.ts b/packages/app/hooks/creator-token/use-creator-token-sell.ts index 92deb7de5..ba1da91f5 100644 --- a/packages/app/hooks/creator-token/use-creator-token-sell.ts +++ b/packages/app/hooks/creator-token/use-creator-token-sell.ts @@ -11,7 +11,7 @@ import { axios } from "app/lib/axios"; import { Logger } from "app/lib/logger"; import { useLogInPromise } from "app/lib/login-promise"; import { publicClient } from "app/lib/wallet-public-client"; -import { formatAPIErrorMessage } from "app/utilities"; +import { delay, formatAPIErrorMessage } from "app/utilities"; import { toast } from "design-system/toast"; @@ -160,15 +160,26 @@ export const useCreatorTokenSell = () => { contractAddress: arg.contractAddress, }) ); - await axios({ - url: "/v1/creator-token/poll-sell", - method: "POST", - data: { - creator_token_id: arg.creatorTokenId, - token_ids: tokenIds, - tx_hash: txHash, - }, - }); + + for (let i = 0; i < 3; i++) { + try { + await axios({ + url: "/v1/creator-token/poll-sell", + method: "POST", + data: { + creator_token_id: arg.creatorTokenId, + token_ids: tokenIds, + tx_hash: txHash, + }, + }); + break; + } catch (e) { + Logger.error("tx not found"); + } + + await delay(2000); + } + return true; } } From 1c6df10c5b6fbcb3a664cd7ce05fcbf0a1a6b37d Mon Sep 17 00:00:00 2001 From: Alan Toa <37520667+alantoa@users.noreply.github.com> Date: Tue, 7 Nov 2023 15:06:26 +0800 Subject: [PATCH 2/6] feat: top creator token (#2501) * feat: add top creator token module * improvements * update the old design of creator token * update endpoint * improvements --- .../creator-token/creator-token-users.tsx | 197 +++++++++++++++++- .../creator-token/top-creator-token.tsx | 118 ++++------- packages/app/components/home/header.tsx | 5 +- .../home/top-part-creator-tokens.tsx | 124 ++++++++--- .../app/components/profile/profile.web.tsx | 13 +- .../app/components/profile/tokens-tab.tsx | 18 +- .../hooks/creator-token/use-creator-tokens.ts | 53 ++++- packages/app/navigation/linking.ts | 2 +- .../creator-token/top-creator-token.tsx | 6 +- packages/design-system/icon/GoldHexagon.svg | 1 + packages/design-system/icon/GoldHexagon.tsx | 35 ++++ packages/design-system/icon/icon.stories.tsx | 1 + packages/design-system/icon/index.ts | 1 + 13 files changed, 438 insertions(+), 136 deletions(-) create mode 100644 packages/design-system/icon/GoldHexagon.svg create mode 100644 packages/design-system/icon/GoldHexagon.tsx diff --git a/packages/app/components/creator-token/creator-token-users.tsx b/packages/app/components/creator-token/creator-token-users.tsx index fafc92fba..a9c9fa83e 100644 --- a/packages/app/components/creator-token/creator-token-users.tsx +++ b/packages/app/components/creator-token/creator-token-users.tsx @@ -2,15 +2,25 @@ import { Platform } from "react-native"; import { Avatar } from "@showtime-xyz/universal.avatar"; import { useIsDarkMode } from "@showtime-xyz/universal.hooks"; -import { Showtime } from "@showtime-xyz/universal.icon"; +import { + GoldHexagon, + Showtime, + ShowtimeRounded, +} from "@showtime-xyz/universal.icon"; import { PressableHover } from "@showtime-xyz/universal.pressable-hover"; import { useRouter } from "@showtime-xyz/universal.router"; +import { Skeleton } from "@showtime-xyz/universal.skeleton"; import { colors } from "@showtime-xyz/universal.tailwind"; import { Text } from "@showtime-xyz/universal.text"; +import { VerificationBadge } from "@showtime-xyz/universal.verification-badge"; import { View, ViewProps } from "@showtime-xyz/universal.view"; -import { CreatorTokenUser } from "app/hooks/creator-token/use-creator-tokens"; +import { + CreatorTokenUser, + TopCreatorTokenUser, +} from "app/hooks/creator-token/use-creator-tokens"; import { useHeaderHeight } from "app/lib/react-navigation/elements"; +import { formatAddressShort } from "app/utilities"; export const CreatorTokensTitle = ({ title }: { title: string }) => { const headerHeight = useHeaderHeight(); @@ -32,7 +42,7 @@ export const CreatorTokensTitle = ({ title }: { title: string }) => { ); }; -export const TopCreatorTokensItem = ({ +export const CreatorTokenCard = ({ index, tw, item, @@ -75,3 +85,184 @@ export const TopCreatorTokensItem = ({ ); }; + +export const TopCreatorTokenListItem = ({ + index, + tw, + item, + showName = false, + ...rest +}: ViewProps & { + index?: number; + item: CreatorTokenUser; + showName?: boolean; +}) => { + const router = useRouter(); + return ( + router.push(`/@${item.username}`)} + {...rest} + > + + {index != undefined ? ( + index < 3 ? ( + + + + + {index + 1} + + ) : ( + + + {index + 1} + + + ) + ) : null} + + + + {showName ? ( + + {item.name ? ( + <> + + {item.name} + + + + ) : null} + + + + {item.username ? ( + <>@{item.username} + ) : ( + <>{formatAddressShort(item.wallet_address)} + )} + + {Boolean(item.verified) && ( + + + + )} + + + ) : ( + + @{item?.username} + + )} + + + + ); +}; +export const TopCreatorTokenItem = ({ + index, + tw, + item, + ...rest +}: ViewProps & { + index?: number; + item: TopCreatorTokenUser; +}) => { + const router = useRouter(); + const isDark = useIsDarkMode(); + return ( + router.push(`/@${item.owner_profile.username}`)} + {...rest} + > + + + {index != undefined ? ( + index < 3 ? ( + + + + + {index + 1} + + ) : ( + + + {index + 1} + + + ) + ) : null} + + + + + + + {item?.owner_profile?.username ? ( + <> + + @{item.owner_profile.username} + + + + ) : null} + {Boolean(item.owner_profile?.verified) && ( + + + + )} + + + + {item.nft_count} + + + + + + + + + ); +}; + +export const TopCreatorTokenSkeleton = ({ tw, ...rest }: ViewProps) => { + return ( + + + + + + + + + + + + + + + ); +}; diff --git a/packages/app/components/creator-token/top-creator-token.tsx b/packages/app/components/creator-token/top-creator-token.tsx index 19b2a0ef5..7fb1be4fc 100644 --- a/packages/app/components/creator-token/top-creator-token.tsx +++ b/packages/app/components/creator-token/top-creator-token.tsx @@ -18,69 +18,40 @@ import { EmptyPlaceholder } from "app/components/empty-placeholder"; import { ErrorBoundary } from "app/components/error-boundary"; import { CreatorTokenUser, + TopCreatorTokenUser, useCreatorTokenCollectors, + useTopCreatorToken, } from "app/hooks/creator-token/use-creator-tokens"; -import { useHeaderHeight } from "app/lib/react-navigation/elements"; -import { breakpoints } from "design-system/theme"; - -import { TopCreatorTokensItem } from "./creator-token-users"; - -const Header = () => { - const headerHeight = useHeaderHeight(); - return ( - <> - - - - Top Creator Tokens - - - - ); -}; +import { + TopCreatorTokenItem, + TopCreatorTokenSkeleton, +} from "./creator-token-users"; -const keyExtractor = (item: CreatorTokenUser) => `${item.profile_id}`; +const keyExtractor = (item: TopCreatorTokenUser) => `${item.id}`; export const TopCreatorTokens = () => { - const { height: screenHeight, width } = useWindowDimensions(); - const isMdWidth = width >= breakpoints["md"]; - const { data: list, isLoading } = useCreatorTokenCollectors(27); + const { height: screenHeight } = useWindowDimensions(); + const { data: list, isLoading, fetchMore } = useTopCreatorToken(); - const numColumns = 3; + const numColumns = 1; const renderItem = useCallback( ({ item, index, - }: ListRenderItemInfo) => { - return ; + }: ListRenderItemInfo) => { + return ; }, [] ); - const getItemType = useCallback( - (_: CreatorTokenUser, index: number) => { - const marginLeft = isMdWidth ? 0 : index % numColumns === 0 ? 0 : 8; - if (marginLeft) { - return "right"; - } - return "left"; - }, - [isMdWidth, numColumns] - ); - const ListEmptyComponent = useCallback(() => { - if (isLoading) { + if (!isLoading) { return ( - - + + {new Array(6).fill(0).map((_, i) => { + return ; + })} ); } @@ -94,35 +65,30 @@ export const TopCreatorTokens = () => { }, [isLoading]); return ( - - - - - - - + + + ); }; diff --git a/packages/app/components/home/header.tsx b/packages/app/components/home/header.tsx index c019cf039..76cd42392 100644 --- a/packages/app/components/home/header.tsx +++ b/packages/app/components/home/header.tsx @@ -261,10 +261,7 @@ export const ListHeaderComponent = memo(function ListHeaderComponent() { ) )} - {/* - // TODO: Creator Tokens P1 - - */} + ); diff --git a/packages/app/components/home/top-part-creator-tokens.tsx b/packages/app/components/home/top-part-creator-tokens.tsx index 678553948..6df6d33d2 100644 --- a/packages/app/components/home/top-part-creator-tokens.tsx +++ b/packages/app/components/home/top-part-creator-tokens.tsx @@ -1,44 +1,106 @@ +import { useMemo } from "react"; +import { Platform } from "react-native"; + import { useRouter } from "@showtime-xyz/universal.router"; import { Text } from "@showtime-xyz/universal.text"; import { View } from "@showtime-xyz/universal.view"; -import { useCreatorTokenCollectors } from "app/hooks/creator-token/use-creator-tokens"; +import { + useCreatorTokenCollectors, + useTopCreatorToken, +} from "app/hooks/creator-token/use-creator-tokens"; -import { TopCreatorTokensItem } from "../creator-token/creator-token-users"; +import { + TopCreatorTokenItem, + TopCreatorTokenSkeleton, +} from "../creator-token/creator-token-users"; export const TopPartCreatorTokens = () => { const router = useRouter(); - const { data, isLoading } = useCreatorTokenCollectors(27); - if ((!data?.length || data?.length === 0) && !isLoading) { - return null; - } + const { data, isLoading } = useTopCreatorToken(6); + + const leftData = useMemo(() => { + return data?.slice(0, 3); + }, [data]); + const rightData = useMemo(() => { + return data?.slice(3, 6); + }, [data]); + return ( - - - Top Creator Tokens - - { - router.push("/creator-token/top"); - }} - tw="text-xs font-semibold text-gray-500" - > - See more - - - - {data?.map((item, i) => { - return ( - - ); - })} - + {data?.length > 0 ? ( + + + Top Creator Tokens + + { + const as = `/creator-token/top`; + router.push( + Platform.select({ + native: as, + web: { + pathname: router.pathname, + query: { + ...router.query, + topCreatorTokenModal: true, + }, + } as any, + }), + Platform.select({ native: as, web: router.asPath }) + ); + }} + tw="text-xs font-semibold text-indigo-700" + > + See all + + + ) : null} + {isLoading ? ( + + + {leftData?.map((_, i) => { + return ; + })} + + {rightData.length > 0 ? ( + + {rightData?.map((_, i) => { + return ; + })} + + ) : null} + + ) : ( + + + {leftData?.map((item, i) => { + return ( + + ); + })} + + {rightData.length > 0 ? ( + + {rightData?.map((item, i) => { + return ( + + ); + })} + + ) : null} + + )} ); }; diff --git a/packages/app/components/profile/profile.web.tsx b/packages/app/components/profile/profile.web.tsx index 1e4853912..5eaab131b 100644 --- a/packages/app/components/profile/profile.web.tsx +++ b/packages/app/components/profile/profile.web.tsx @@ -27,6 +27,12 @@ import { Text } from "@showtime-xyz/universal.text"; import { View } from "@showtime-xyz/universal.view"; import { Card } from "app/components/card"; +import { EmptyPlaceholder } from "app/components/empty-placeholder"; +import { ButtonGoldLinearGradient } from "app/components/gold-gradient"; +import { HeaderLeft } from "app/components/header"; +import { HeaderRightSm } from "app/components/header/header-right.sm"; +import { CreatorTokensBanner } from "app/components/home/header"; +import { TopPartCreatorTokens } from "app/components/home/top-part-creator-tokens"; import { DESKTOP_PROFILE_WIDTH } from "app/constants/layout"; import { ProfileTabsNFTProvider } from "app/context/profile-tabs-nft-context"; import { @@ -54,12 +60,6 @@ import { import { Spinner } from "design-system/spinner"; -import { MessageItem } from "../creator-channels/components/message-item"; -import { EmptyPlaceholder } from "../empty-placeholder"; -import { ButtonGoldLinearGradient } from "../gold-gradient"; -import { HeaderLeft } from "../header"; -import { HeaderRightSm } from "../header/header-right.sm"; -import { CreatorTokensBanner } from "../home/header"; import { CreatorTokensPanel } from "./creator-tokens-panel"; import { MyCollection } from "./my-collection"; import { ProfileError } from "./profile-error"; @@ -367,6 +367,7 @@ const Profile = ({ username }: ProfileScreenProps) => { {isSelf && } + ) : null} diff --git a/packages/app/components/profile/tokens-tab.tsx b/packages/app/components/profile/tokens-tab.tsx index dcb84e74e..464c8a5fb 100644 --- a/packages/app/components/profile/tokens-tab.tsx +++ b/packages/app/components/profile/tokens-tab.tsx @@ -48,7 +48,7 @@ import { formatNumber } from "app/utilities"; import SvgUnlocked from "design-system/icon/Unlocked"; import { ChannelPermissions } from "../creator-channels/types"; -import { TopCreatorTokensItem } from "../creator-token/creator-token-users"; +import { TopCreatorTokenListItem } from "../creator-token/creator-token-users"; import { EmptyPlaceholder } from "../empty-placeholder"; import { FilterContext } from "./fillter-context"; import { MyCollection } from "./my-collection"; @@ -234,7 +234,7 @@ export const CreatorTokenCollectors = ({ return ( - + {name ? name : `@${username}`} collectors {/* {count > 6 ? ( @@ -266,11 +266,11 @@ export const CreatorTokenCollectors = ({ {data?.map((item, i) => { return ( - ); })} @@ -296,7 +296,7 @@ export const CreatorTokenCollected = ({ return ( - + {name ? name : `@${username}`} collected {/* {count > 6 ? ( @@ -330,11 +330,11 @@ export const CreatorTokenCollected = ({ {data?.map((item, i) => { return ( - ); })} diff --git a/packages/app/hooks/creator-token/use-creator-tokens.ts b/packages/app/hooks/creator-token/use-creator-tokens.ts index 157464f6e..735c4163e 100644 --- a/packages/app/hooks/creator-token/use-creator-tokens.ts +++ b/packages/app/hooks/creator-token/use-creator-tokens.ts @@ -1,8 +1,12 @@ -import { useMemo } from "react"; +import { useMemo, useCallback } from "react"; import useSWR from "swr"; -import { fetcher } from "app/hooks/use-infinite-list-query"; +import { + fetcher, + useInfiniteListQuerySWR, +} from "app/hooks/use-infinite-list-query"; +import { Profile } from "app/types"; export type CreatorTokenUser = { verified: boolean; @@ -14,10 +18,20 @@ export type CreatorTokenUser = { wallet_address_nonens: string; img_url: string; }; +export type TopCreatorTokenUser = { + id: number; + owner_profile: Profile; + owner_address: string; + name: string; + token_uri: string; + nft_count: number; +}; export type CreatorTokenCollectors = { profiles: CreatorTokenUser[]; }; - +export type TopCreatorToken = { + creator_tokens: TopCreatorTokenUser[]; +}; export const useCreatorTokenCollectors = ( creatorTokenId?: number | string, limit?: number @@ -69,3 +83,36 @@ export const useCreatorTokenCoLlected = ( error, }; }; +export const useTopCreatorToken = (limit: number = 10) => { + const fetchUrl = useCallback( + (index: number, previousPageData: []) => { + if (previousPageData && !previousPageData.length) return null; + return `/v1/creator-token/top?page=${index + 1}&limit=${limit}`; + }, + [limit] + ); + + const queryState = useInfiniteListQuerySWR(fetchUrl, { + pageSize: limit, + }); + const newData = useMemo(() => { + let newData: TopCreatorTokenUser[] = []; + if ( + queryState.data && + queryState.data[0] && + queryState.data[0].creator_tokens + ) { + queryState.data[0].creator_tokens.forEach((p) => { + if (p) { + newData = newData.concat(p); + } + }); + } + return newData; + }, [queryState.data]); + + return { + ...queryState, + data: newData, + }; +}; diff --git a/packages/app/navigation/linking.ts b/packages/app/navigation/linking.ts index f9f642068..1f9472294 100644 --- a/packages/app/navigation/linking.ts +++ b/packages/app/navigation/linking.ts @@ -93,7 +93,7 @@ export const linking: LinkingOptions = { channelUnlocked: "channels/:contractAddress/unlocked", inviteCreatorToken: "creator-token/invite-creator-token", creatorTokensShare: "creator-token/:username/share", - topCreatorToken: "creator-token/:profileId/top", + topCreatorToken: "creator-token/top", creatorTokenCollectors: "creator-token/:creatorTokenId/collectors", creatorTokenCollected: "creator-token/:profileId/collected", creatorTokensImportAllowlistSuccess: diff --git a/packages/app/screens/creator-token/top-creator-token.tsx b/packages/app/screens/creator-token/top-creator-token.tsx index 037d7cdb5..64a2e0896 100644 --- a/packages/app/screens/creator-token/top-creator-token.tsx +++ b/packages/app/screens/creator-token/top-creator-token.tsx @@ -7,9 +7,9 @@ import { withColorScheme } from "app/components/memo-with-theme"; import { useTrackPageViewed } from "app/lib/analytics"; const TopCreatorTokenModalScreen = withModalScreen(TopCreatorTokens, { - title: "", - matchingPathname: "/creator-token/[profileId]/top", - matchingQueryParam: "TopcreatorTokenScreenModal", + title: "Top Creator Tokens", + matchingPathname: "/creator-token/top", + matchingQueryParam: "topCreatorTokenModal", enableContentPanningGesture: false, snapPoints: ["90%"], }); diff --git a/packages/design-system/icon/GoldHexagon.svg b/packages/design-system/icon/GoldHexagon.svg new file mode 100644 index 000000000..72383cca6 --- /dev/null +++ b/packages/design-system/icon/GoldHexagon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/design-system/icon/GoldHexagon.tsx b/packages/design-system/icon/GoldHexagon.tsx new file mode 100644 index 000000000..798531478 --- /dev/null +++ b/packages/design-system/icon/GoldHexagon.tsx @@ -0,0 +1,35 @@ +import * as React from "react"; + +import Svg, { SvgProps, LinearGradient, Stop, Path } from "react-native-svg"; + +const SvgGoldHexagon = (props: SvgProps) => ( + + + + + + + + + + + + + + + + + + +); +export default SvgGoldHexagon; diff --git a/packages/design-system/icon/icon.stories.tsx b/packages/design-system/icon/icon.stories.tsx index d575651ff..c583d4465 100644 --- a/packages/design-system/icon/icon.stories.tsx +++ b/packages/design-system/icon/icon.stories.tsx @@ -210,6 +210,7 @@ export const Default = () => { + Social Icons diff --git a/packages/design-system/icon/index.ts b/packages/design-system/icon/index.ts index 4c6dae72f..e7d5f1003 100644 --- a/packages/design-system/icon/index.ts +++ b/packages/design-system/icon/index.ts @@ -163,6 +163,7 @@ export { default as PieChart } from "./PieChart"; export { default as AccessTicket } from "./AccessTicket"; export { default as InviteTicket } from "./InviteTicket"; export { default as ArrowTopRounded } from "./ArrowTopRounded"; +export { default as GoldHexagon } from "./GoldHexagon"; //#region social icons export { default as Twitter } from "./Twitter"; From 9b88e27426ae932fdaac9aef5cc5bc033c016397 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 7 Nov 2023 07:09:01 +0000 Subject: [PATCH 3/6] release v149.0.18 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 02c30314c..aad22308a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "showtime", - "version": "149.0.17", + "version": "149.0.18", "private": true, "license": "MIT", "devDependencies": { From 1dca3c2b9f4e510fdd57ed7404a3246b7a04441e Mon Sep 17 00:00:00 2001 From: Alan Toa <37520667+alantoa@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:42:37 +0800 Subject: [PATCH 4/6] new desktop UI for the top creator token (#2506) * new desktop UI for the top creator token * fix spacing * rename Trending with top creator tokens --- apps/next/src/pages/_app.tsx | 2 - .../creator-token/creator-token-users.tsx | 249 ++++++++++++------ .../creator-token/top-creator-token.tsx | 69 +++-- .../app/components/header/header-title.tsx | 2 +- packages/app/components/home/header.tsx | 5 +- packages/app/components/home/index.tsx | 13 +- .../home/top-part-creator-tokens.tsx | 41 +-- .../app/components/profile/tokens-tab.tsx | 10 +- .../hooks/creator-token/use-creator-tokens.ts | 35 +-- packages/app/navigation/linking.ts | 1 - .../app/navigation/root-stack-navigator.tsx | 8 +- packages/app/navigation/types.ts | 1 - .../creator-token/top-creator-token.tsx | 23 -- packages/app/screens/trending.tsx | 12 +- .../tab-view/scrollable-tab-bar.tsx | 1 + 15 files changed, 282 insertions(+), 190 deletions(-) delete mode 100644 packages/app/screens/creator-token/top-creator-token.tsx diff --git a/apps/next/src/pages/_app.tsx b/apps/next/src/pages/_app.tsx index 298d315f8..d1fddfe16 100644 --- a/apps/next/src/pages/_app.tsx +++ b/apps/next/src/pages/_app.tsx @@ -41,7 +41,6 @@ import { CreatorTokenCollectedScreen } from "app/screens/creator-token/creator-t import { CreatorTokenCollectorsScreen } from "app/screens/creator-token/creator-token-collectors"; import { InviteCreatorTokenScreen } from "app/screens/creator-token/invite-creator-token"; import { CreatorTokenInviteSignInScreen } from "app/screens/creator-token/invite-sign-in"; -import { TopCreatorTokenScreen } from "app/screens/creator-token/top-creator-token"; import { CreatorTokensExplanationScreen } from "app/screens/creator-tokens-explanation"; import { CreatorTokensSelfServeExplainerScreen } from "app/screens/creator-tokens-self-serve-explainer"; import { CreatorTokensShareModalScreen } from "app/screens/creator-tokens-share"; @@ -267,7 +266,6 @@ function App({ Component, pageProps, router }: AppProps) { - {/* Login should be the last so it renders on top of others if needed */} diff --git a/packages/app/components/creator-token/creator-token-users.tsx b/packages/app/components/creator-token/creator-token-users.tsx index a9c9fa83e..c1ac230d4 100644 --- a/packages/app/components/creator-token/creator-token-users.tsx +++ b/packages/app/components/creator-token/creator-token-users.tsx @@ -1,4 +1,4 @@ -import { Platform } from "react-native"; +import { Platform, useWindowDimensions } from "react-native"; import { Avatar } from "@showtime-xyz/universal.avatar"; import { useIsDarkMode } from "@showtime-xyz/universal.hooks"; @@ -20,8 +20,11 @@ import { TopCreatorTokenUser, } from "app/hooks/creator-token/use-creator-tokens"; import { useHeaderHeight } from "app/lib/react-navigation/elements"; +import { Link } from "app/navigation/link"; import { formatAddressShort } from "app/utilities"; +import { breakpoints } from "design-system/theme"; + export const CreatorTokensTitle = ({ title }: { title: string }) => { const headerHeight = useHeaderHeight(); return ( @@ -42,51 +45,8 @@ export const CreatorTokensTitle = ({ title }: { title: string }) => { ); }; -export const CreatorTokenCard = ({ - index, - tw, - item, - ...rest -}: ViewProps & { index: number; item: CreatorTokenUser }) => { - const isDark = useIsDarkMode(); - const router = useRouter(); - return ( - router.push(`/@${item.username}`)} - {...rest} - > - <> - - - - - - - - @{item?.username} - - {/* - $2.60 */} - - {/* - {index + 1} - */} - - ); -}; -export const TopCreatorTokenListItem = ({ +export const TopCreatorTokenItemOnProfile = ({ index, tw, item, @@ -180,54 +140,141 @@ export const TopCreatorTokenItem = ({ }) => { const router = useRouter(); const isDark = useIsDarkMode(); + return ( - router.push(`/@${item.owner_profile.username}`)} - {...rest} + - - - {index != undefined ? ( - index < 3 ? ( - - - + + + + {index != undefined ? ( + index < 3 ? ( + + + + + {index + 1} - {index + 1} + ) : ( + + + {index + 1} + + + ) + ) : null} + + + + + + + @ + {item.owner_profile?.username + ? item.owner_profile?.username + : formatAddressShort(item.owner_address)} + + {Boolean(item.owner_profile?.verified) && ( + + + + )} - ) : ( - - - {index + 1} + + + {item.nft_count} + + - ) - ) : null} + + - - - - - - {item?.owner_profile?.username ? ( - <> - - @{item.owner_profile.username} + + + ); +}; +export const TopCreatorTokenListItem = ({ + index, + tw, + item, + isSimplified = false, + isMdWidth, + ...rest +}: ViewProps & { + index?: number; + item: TopCreatorTokenUser; + isSimplified?: boolean; + isMdWidth?: boolean; +}) => { + const isDark = useIsDarkMode(); + if (!isMdWidth) { + return ; + } + return ( + + + + + {index != undefined ? ( + index < 3 ? ( + + + + + {index + 1} + + ) : ( + + + {index + 1} - - - ) : null} + + ) + ) : null} + + + + + + + @ + {item.owner_profile?.username + ? item.owner_profile?.username + : formatAddressShort(item.owner_address)} + + {Boolean(item.owner_profile?.verified) && ( )} - + + {!isSimplified ? ( + + + {item.owner_profile?.name} + + + + {item.owner_profile?.bio} + + + ) : null} - + ); }; @@ -266,3 +330,28 @@ export const TopCreatorTokenSkeleton = ({ tw, ...rest }: ViewProps) => { ); }; + +export const TopCreatorTokenListItemSkeleton = ({ + tw, + isMdWidth, + ...rest +}: ViewProps & { + isMdWidth: boolean; +}) => { + if (!isMdWidth) { + return ; + } + return ( + + + + + + + + + + + + ); +}; diff --git a/packages/app/components/creator-token/top-creator-token.tsx b/packages/app/components/creator-token/top-creator-token.tsx index 7fb1be4fc..1ea6399d0 100644 --- a/packages/app/components/creator-token/top-creator-token.tsx +++ b/packages/app/components/creator-token/top-creator-token.tsx @@ -3,36 +3,57 @@ import { useWindowDimensions, Platform } from "react-native"; import type { ListRenderItemInfo } from "@shopify/flash-list"; -import { Avatar } from "@showtime-xyz/universal.avatar"; -import { useIsDarkMode } from "@showtime-xyz/universal.hooks"; -import { Showtime } from "@showtime-xyz/universal.icon"; import { InfiniteScrollList } from "@showtime-xyz/universal.infinite-scroll-list"; -import { PressableHover } from "@showtime-xyz/universal.pressable-hover"; -import { useRouter } from "@showtime-xyz/universal.router"; -import Spinner from "@showtime-xyz/universal.spinner"; -import { colors } from "@showtime-xyz/universal.tailwind"; import { Text } from "@showtime-xyz/universal.text"; import { View, ViewProps } from "@showtime-xyz/universal.view"; import { EmptyPlaceholder } from "app/components/empty-placeholder"; import { ErrorBoundary } from "app/components/error-boundary"; import { - CreatorTokenUser, TopCreatorTokenUser, - useCreatorTokenCollectors, useTopCreatorToken, } from "app/hooks/creator-token/use-creator-tokens"; +import { useHeaderHeight } from "app/lib/react-navigation/elements"; + +import { breakpoints } from "design-system/theme"; import { - TopCreatorTokenItem, + TopCreatorTokenListItem, + TopCreatorTokenListItemSkeleton, TopCreatorTokenSkeleton, } from "./creator-token-users"; +const Header = () => { + const headerHeight = useHeaderHeight(); + return ( + <> + + + + Top Creator Tokens + + + + ); +}; const keyExtractor = (item: TopCreatorTokenUser) => `${item.id}`; -export const TopCreatorTokens = () => { - const { height: screenHeight } = useWindowDimensions(); +export const TopCreatorTokens = ({ + isSimplified, + disableFetchMore, +}: { + isSimplified?: boolean; + disableFetchMore?: boolean; +}) => { + const { height: screenHeight, width } = useWindowDimensions(); const { data: list, isLoading, fetchMore } = useTopCreatorToken(); - + const isMdWidth = width >= breakpoints["md"]; const numColumns = 1; const renderItem = useCallback( @@ -40,17 +61,26 @@ export const TopCreatorTokens = () => { item, index, }: ListRenderItemInfo) => { - return ; + return ( + + ); }, - [] + [isSimplified, isMdWidth] ); const ListEmptyComponent = useCallback(() => { - if (!isLoading) { + if (isLoading) { return ( {new Array(6).fill(0).map((_, i) => { - return ; + return ( + + ); })} ); @@ -62,7 +92,7 @@ export const TopCreatorTokens = () => { hideLoginBtn /> ); - }, [isLoading]); + }, [isLoading, isMdWidth]); return ( @@ -84,8 +114,9 @@ export const TopCreatorTokens = () => { paddingHorizontal: 12, }} overscan={12} + ListHeaderComponent={Header} containerTw="px-4" - onEndReached={fetchMore} + onEndReached={disableFetchMore ? () => {} : fetchMore} ListEmptyComponent={ListEmptyComponent} estimatedItemSize={46} /> diff --git a/packages/app/components/header/header-title.tsx b/packages/app/components/header/header-title.tsx index 5161a1452..70fb10b3f 100644 --- a/packages/app/components/header/header-title.tsx +++ b/packages/app/components/header/header-title.tsx @@ -4,7 +4,7 @@ import { View } from "@showtime-xyz/universal.view"; const titleMap = new Map([ ["/notifications", "Notifications"], - ["/trending", "Trending"], + ["/trending", "Top Creator Tokens"], ["/settings", "Settings"], ]); diff --git a/packages/app/components/home/header.tsx b/packages/app/components/home/header.tsx index 76cd42392..ec52a0517 100644 --- a/packages/app/components/home/header.tsx +++ b/packages/app/components/home/header.tsx @@ -182,6 +182,8 @@ export const CreatorTokensBanner = ({ export const ListHeaderComponent = memo(function ListHeaderComponent() { const { width } = useWindowDimensions(); const isMdWidth = width >= breakpoints["md"]; + const isLgWidth = width >= breakpoints["xl"]; + const { data: banners = [], isLoading: isLoadingBanner } = useBanners(); const router = useRouter(); const pagerWidth = isMdWidth @@ -261,8 +263,7 @@ export const ListHeaderComponent = memo(function ListHeaderComponent() { ) )} - - + {isLgWidth ? null : } ); }); diff --git a/packages/app/components/home/index.tsx b/packages/app/components/home/index.tsx index dfdd70e62..afa65b4bd 100644 --- a/packages/app/components/home/index.tsx +++ b/packages/app/components/home/index.tsx @@ -7,6 +7,7 @@ import { } from "@showtime-xyz/universal.infinite-scroll-list"; import { View } from "@showtime-xyz/universal.view"; +import { TopCreatorTokens } from "app/components/creator-token/top-creator-token"; import { ErrorBoundary } from "app/components/error-boundary"; import { VideoConfigContext } from "app/context/video-config-context"; import { withViewabilityInfiniteScrollList } from "app/hocs/with-viewability-infinite-scroll-list"; @@ -14,6 +15,7 @@ import { useFeed } from "app/hooks/use-feed"; import { usePlatformBottomHeight } from "app/hooks/use-platform-bottom-height"; import { useHeaderHeight } from "app/lib/react-navigation/elements"; import { useScrollToTop } from "app/lib/react-navigation/native"; +import { Sticky } from "app/lib/stickynode"; import { NFT } from "app/types"; import { breakpoints } from "design-system/theme"; @@ -25,12 +27,14 @@ import { TrendingCarousel } from "./trending-carousel"; const ViewabilityInfiniteScrollList = withViewabilityInfiniteScrollList(InfiniteScrollList); - +const RIGHT_SIDE_WIDTH = 300; export const Home = () => { const bottomBarHeight = usePlatformBottomHeight(); const headerHeight = useHeaderHeight(); const { width, height } = useWindowDimensions(); const isMdWidth = width >= breakpoints["md"]; + const isLgWidth = width >= breakpoints["xl"]; + const { data, isLoading } = useFeed(); const listRef = useRef(); useScrollToTop(listRef); @@ -106,7 +110,7 @@ export const Home = () => { return ( { /> + {isLgWidth ? ( + + + + ) : null} ); diff --git a/packages/app/components/home/top-part-creator-tokens.tsx b/packages/app/components/home/top-part-creator-tokens.tsx index 6df6d33d2..2697772b2 100644 --- a/packages/app/components/home/top-part-creator-tokens.tsx +++ b/packages/app/components/home/top-part-creator-tokens.tsx @@ -28,34 +28,19 @@ export const TopPartCreatorTokens = () => { return ( - {data?.length > 0 ? ( - - - Top Creator Tokens - - { - const as = `/creator-token/top`; - router.push( - Platform.select({ - native: as, - web: { - pathname: router.pathname, - query: { - ...router.query, - topCreatorTokenModal: true, - }, - } as any, - }), - Platform.select({ native: as, web: router.asPath }) - ); - }} - tw="text-xs font-semibold text-indigo-700" - > - See all - - - ) : null} + + + Top Creator Tokens + + { + router.push("/trending"); + }} + tw="text-xs font-semibold text-indigo-700" + > + See all + + {isLoading ? ( diff --git a/packages/app/components/profile/tokens-tab.tsx b/packages/app/components/profile/tokens-tab.tsx index 464c8a5fb..be8362a91 100644 --- a/packages/app/components/profile/tokens-tab.tsx +++ b/packages/app/components/profile/tokens-tab.tsx @@ -48,7 +48,7 @@ import { formatNumber } from "app/utilities"; import SvgUnlocked from "design-system/icon/Unlocked"; import { ChannelPermissions } from "../creator-channels/types"; -import { TopCreatorTokenListItem } from "../creator-token/creator-token-users"; +import { TopCreatorTokenItemOnProfile } from "../creator-token/creator-token-users"; import { EmptyPlaceholder } from "../empty-placeholder"; import { FilterContext } from "./fillter-context"; import { MyCollection } from "./my-collection"; @@ -266,10 +266,10 @@ export const CreatorTokenCollectors = ({ {data?.map((item, i) => { return ( - ); @@ -330,10 +330,10 @@ export const CreatorTokenCollected = ({ {data?.map((item, i) => { return ( - ); diff --git a/packages/app/hooks/creator-token/use-creator-tokens.ts b/packages/app/hooks/creator-token/use-creator-tokens.ts index 735c4163e..1a6cd8483 100644 --- a/packages/app/hooks/creator-token/use-creator-tokens.ts +++ b/packages/app/hooks/creator-token/use-creator-tokens.ts @@ -20,7 +20,7 @@ export type CreatorTokenUser = { }; export type TopCreatorTokenUser = { id: number; - owner_profile: Profile; + owner_profile?: Profile; owner_address: string; name: string; token_uri: string; @@ -83,34 +83,35 @@ export const useCreatorTokenCoLlected = ( error, }; }; -export const useTopCreatorToken = (limit: number = 10) => { +export const useTopCreatorToken = (limit: number = 15) => { const fetchUrl = useCallback( - (index: number, previousPageData: []) => { - if (previousPageData && !previousPageData.length) return null; + (index: number, previousPageData: any) => { + if (previousPageData && !previousPageData?.creator_tokens.length) + return null; + return `/v1/creator-token/top?page=${index + 1}&limit=${limit}`; }, [limit] ); - const queryState = useInfiniteListQuerySWR(fetchUrl, { - pageSize: limit, - }); + const { data, ...queryState } = useInfiniteListQuerySWR( + fetchUrl, + { + pageSize: limit, + } + ); + const newData = useMemo(() => { - let newData: TopCreatorTokenUser[] = []; - if ( - queryState.data && - queryState.data[0] && - queryState.data[0].creator_tokens - ) { - queryState.data[0].creator_tokens.forEach((p) => { + let newData: TopCreatorToken["creator_tokens"] = []; + if (data) { + data.forEach((p) => { if (p) { - newData = newData.concat(p); + newData = newData.concat(p.creator_tokens); } }); } return newData; - }, [queryState.data]); - + }, [data]); return { ...queryState, data: newData, diff --git a/packages/app/navigation/linking.ts b/packages/app/navigation/linking.ts index 1f9472294..1c5f139fe 100644 --- a/packages/app/navigation/linking.ts +++ b/packages/app/navigation/linking.ts @@ -93,7 +93,6 @@ export const linking: LinkingOptions = { channelUnlocked: "channels/:contractAddress/unlocked", inviteCreatorToken: "creator-token/invite-creator-token", creatorTokensShare: "creator-token/:username/share", - topCreatorToken: "creator-token/top", creatorTokenCollectors: "creator-token/:creatorTokenId/collectors", creatorTokenCollected: "creator-token/:profileId/collected", creatorTokensImportAllowlistSuccess: diff --git a/packages/app/navigation/root-stack-navigator.tsx b/packages/app/navigation/root-stack-navigator.tsx index eb1001856..f3818364e 100644 --- a/packages/app/navigation/root-stack-navigator.tsx +++ b/packages/app/navigation/root-stack-navigator.tsx @@ -28,7 +28,6 @@ import { CreatorTokenCollectorsScreen } from "app/screens/creator-token/creator- import { InviteCreatorTokenScreen } from "app/screens/creator-token/invite-creator-token"; import { CreatorTokenInviteSignInScreen } from "app/screens/creator-token/invite-sign-in"; import { ReviewCreatorTokenScreen } from "app/screens/creator-token/review-creator-token"; -import { TopCreatorTokenScreen } from "app/screens/creator-token/top-creator-token"; import { CreatorTokensExplanationScreen } from "app/screens/creator-tokens-explanation"; import { CreatorTokensSelfServeExplainerScreen } from "app/screens/creator-tokens-self-serve-explainer"; import { CreatorTokensShareModalScreen } from "app/screens/creator-tokens-share"; @@ -243,13 +242,8 @@ export function RootStackNavigator() { /> - { - useTrackPageViewed({ name: "TopCreatorTokensScreen" }); - if (Platform.OS === "web") { - return ; - } - return ; -}); diff --git a/packages/app/screens/trending.tsx b/packages/app/screens/trending.tsx index a7eb64956..7a3e0686b 100644 --- a/packages/app/screens/trending.tsx +++ b/packages/app/screens/trending.tsx @@ -1,13 +1,21 @@ +import { View } from "@showtime-xyz/universal.view"; + +import { TopCreatorTokens } from "app/components/creator-token/top-creator-token"; import { withColorScheme } from "app/components/memo-with-theme"; import { useIntroducingCreatorChannels } from "app/components/onboarding/introducing-creator-channels"; -import Trending from "app/components/trending"; import { useTrackPageViewed } from "app/lib/analytics"; const TrendingScreen = withColorScheme(() => { useTrackPageViewed({ name: "Trending" }); useIntroducingCreatorChannels(); - return ; + return ( + + + + + + ); }); export { TrendingScreen }; diff --git a/packages/design-system/tab-view/scrollable-tab-bar.tsx b/packages/design-system/tab-view/scrollable-tab-bar.tsx index 1815dc36c..45b9cecdf 100644 --- a/packages/design-system/tab-view/scrollable-tab-bar.tsx +++ b/packages/design-system/tab-view/scrollable-tab-bar.tsx @@ -40,6 +40,7 @@ export const ScollableTabBar = ({ fontSize: 14, textTransform: "none", marginHorizontal: 0, + marginVertical: 0, }} indicatorStyle={{ backgroundColor: isDark ? "#FFF" : colors.gray[900] }} tabStyle={{ From ff7bc5e6e02a386165a921dfae144ea266c45066 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 7 Nov 2023 10:46:56 +0000 Subject: [PATCH 5/6] release v149.0.19 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aad22308a..b3801098e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "showtime", - "version": "149.0.18", + "version": "149.0.19", "private": true, "license": "MIT", "devDependencies": { From c280886ebe472bfced19fafd0647d97465a0a011 Mon Sep 17 00:00:00 2001 From: Alan Toa <37520667+alantoa@users.noreply.github.com> Date: Tue, 7 Nov 2023 20:35:33 +0800 Subject: [PATCH 6/6] fix: limit top creator tokens on home (#2507) * fix: limit top creator tokens on home * fix spacing * fix spacing issue * increase fontsize * increase title fontsize * ui improments --- .../creator-token/creator-token-users.tsx | 4 ++-- .../creator-token/top-creator-token.tsx | 8 +++++--- packages/app/components/home/index.tsx | 15 ++++++++++---- .../hooks/creator-token/use-creator-tokens.ts | 20 +++++++++++++------ 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/packages/app/components/creator-token/creator-token-users.tsx b/packages/app/components/creator-token/creator-token-users.tsx index c1ac230d4..a6ab8edb5 100644 --- a/packages/app/components/creator-token/creator-token-users.tsx +++ b/packages/app/components/creator-token/creator-token-users.tsx @@ -296,10 +296,10 @@ export const TopCreatorTokenListItem = ({ > {item.owner_profile?.name} - + {item.owner_profile?.bio} diff --git a/packages/app/components/creator-token/top-creator-token.tsx b/packages/app/components/creator-token/top-creator-token.tsx index 1ea6399d0..6355feabe 100644 --- a/packages/app/components/creator-token/top-creator-token.tsx +++ b/packages/app/components/creator-token/top-creator-token.tsx @@ -36,7 +36,7 @@ const Header = () => { }} /> - + Top Creator Tokens @@ -47,12 +47,14 @@ const keyExtractor = (item: TopCreatorTokenUser) => `${item.id}`; export const TopCreatorTokens = ({ isSimplified, disableFetchMore, + limit, }: { isSimplified?: boolean; disableFetchMore?: boolean; + limit?: number; }) => { const { height: screenHeight, width } = useWindowDimensions(); - const { data: list, isLoading, fetchMore } = useTopCreatorToken(); + const { data: list, isLoading, fetchMore } = useTopCreatorToken(limit); const isMdWidth = width >= breakpoints["md"]; const numColumns = 1; @@ -113,7 +115,7 @@ export const TopCreatorTokens = ({ contentContainerStyle={{ paddingHorizontal: 12, }} - overscan={12} + overscan={20} ListHeaderComponent={Header} containerTw="px-4" onEndReached={disableFetchMore ? () => {} : fetchMore} diff --git a/packages/app/components/home/index.tsx b/packages/app/components/home/index.tsx index afa65b4bd..92eea8be7 100644 --- a/packages/app/components/home/index.tsx +++ b/packages/app/components/home/index.tsx @@ -33,7 +33,8 @@ export const Home = () => { const headerHeight = useHeaderHeight(); const { width, height } = useWindowDimensions(); const isMdWidth = width >= breakpoints["md"]; - const isLgWidth = width >= breakpoints["xl"]; + const isXlWidth = width >= breakpoints["xl"]; + const is2XlWidth = width >= breakpoints["2xl"]; const { data, isLoading } = useFeed(); const listRef = useRef(); @@ -142,9 +143,15 @@ export const Home = () => { /> - {isLgWidth ? ( - - + {isXlWidth ? ( + + ) : null} diff --git a/packages/app/hooks/creator-token/use-creator-tokens.ts b/packages/app/hooks/creator-token/use-creator-tokens.ts index 1a6cd8483..8d2f32372 100644 --- a/packages/app/hooks/creator-token/use-creator-tokens.ts +++ b/packages/app/hooks/creator-token/use-creator-tokens.ts @@ -94,12 +94,13 @@ export const useTopCreatorToken = (limit: number = 15) => { [limit] ); - const { data, ...queryState } = useInfiniteListQuerySWR( - fetchUrl, - { - pageSize: limit, - } - ); + const { + data, + fetchMore: fetchMoreData, + ...queryState + } = useInfiniteListQuerySWR(fetchUrl, { + pageSize: limit, + }); const newData = useMemo(() => { let newData: TopCreatorToken["creator_tokens"] = []; @@ -112,8 +113,15 @@ export const useTopCreatorToken = (limit: number = 15) => { } return newData; }, [data]); + + const fetchMore = useCallback(() => { + if (newData.length >= 100) return; + fetchMoreData(); + }, [fetchMoreData, newData.length]); + return { ...queryState, + fetchMore, data: newData, }; };