Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 134
Refactor Token Filtering and Display Logic for Artist Coins#12893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
a8c1610e05cc94c7e70a01d725d6ded47fa35684a1File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| import { useMemo } from 'react' | ||
| import { | ||
| useCurrentUserId, | ||
| useUserCoins, | ||
| useQueryContext, | ||
| UserCoin | ||
| } from '~/api' | ||
| import { useFeatureFlag } from '~/hooks' | ||
| import { FeatureFlags } from '~/services' | ||
| import type { TokenInfo } from '~/store' | ||
| import { ownedCoinsFilter } from '~/utils' | ||
| /** | ||
| * Hook to filter tokens based on user ownership and positive balance | ||
| * Respects the ARTIST_COINS feature flag - when disabled, only shows AUDIO tokens | ||
| */ | ||
| export const useOwnedTokens = (allTokens: TokenInfo[]) => { | ||
| const { data: currentUserId } = useCurrentUserId() | ||
| const { data: userCoins } = useUserCoins({ userId: currentUserId }) | ||
| const { env } = useQueryContext() | ||
| const { isEnabled: isArtistCoinsEnabled } = useFeatureFlag( | ||
| FeatureFlags.ARTIST_COINS | ||
| ) | ||
| const ownedTokens = useMemo(() => { | ||
| if (!userCoins || !allTokens.length) { | ||
| return [] | ||
| } | ||
| const filteredUserCoins = userCoins.filter( | ||
| ownedCoinsFilter(!!isArtistCoinsEnabled, env.WAUDIO_MINT_ADDRESS) | ||
| ) | ||
| // Create a map of user's owned tokens by mint address | ||
| const userOwnedMints = new Set( | ||
| filteredUserCoins.map((coin: UserCoin) => coin.mint) | ||
| ) | ||
| // Filter available tokens to only include ones the user owns | ||
| const ownedTokensList = allTokens.filter((token) => | ||
| userOwnedMints.has(token.address) | ||
| ) | ||
| return ownedTokensList | ||
| }, [userCoins, allTokens, isArtistCoinsEnabled, env.WAUDIO_MINT_ADDRESS]) | ||
| return { | ||
| ownedTokens, | ||
| isLoading: !userCoins | ||
| } | ||
| } | ||
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import { UserCoin } from '~/api' | ||
faridsalau marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /** | ||
| * Creates a predicate function for filtering user coins based on the ARTIST_COINS feature flag and balance requirements | ||
| * | ||
| * @param isArtistCoinsEnabled - Whether the ARTIST_COINS feature flag is enabled | ||
| * @param wAudioMintAddress - The WAUDIO mint address from environment | ||
| * @returns Predicate function that can be used with Array.filter() | ||
| */ | ||
| export const ownedCoinsFilter = | ||
| (isArtistCoinsEnabled: boolean, wAudioMintAddress: string) => | ||
| (coin: UserCoin): boolean => { | ||
| if (!isArtistCoinsEnabled) { | ||
| // When artist coins disabled, only show AUDIO | ||
| return coin.mint === wAudioMintAddress | ||
| } | ||
| // When artist coins enabled, show all non-USDC tokens with balance > 0 | ||
| // OR AUDIO regardless of balance | ||
| return ( | ||
| coin.ticker !== 'USDC' && | ||
| (coin.balance > 0 || coin.mint === wAudioMintAddress) | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -164,6 +164,78 @@ export const formatCurrency = ( | ||
| } | ||
| } | ||
| /** | ||
| * Formats a number with subscript notation for many leading zeros after decimal. | ||
| * For example: 0.000068352 → 0.0₄68352 | ||
| * | ||
| * @param num - The number to format | ||
| * @param locale - Locale for number formatting (defaults to 'en-US') | ||
| * @returns Formatted string with subscript notation for leading zeros | ||
| */ | ||
| export const formatCurrencyWithSubscript = ( | ||
| num: number, | ||
| locale: string = 'en-US' | ||
| ): string => { | ||
| if (num === 0) return '$0.00' | ||
| try { | ||
| const decimalPlaces = getCurrencyDecimalPlaces(num) | ||
| const formatted = new Intl.NumberFormat(locale, { | ||
faridsalau marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| style: 'currency', | ||
| currency: 'USD', | ||
| minimumFractionDigits: Math.min(decimalPlaces, 2), | ||
| maximumFractionDigits: decimalPlaces | ||
| }).format(num) | ||
| // Extract the number part (remove currency symbol and commas) | ||
| const numberPart = formatted.replace(/[^0-9.-]/g, '').replace(/,/g, '') | ||
| // Check if there are leading zeros after decimal that should be subscripted | ||
| const parts = numberPart.split('.') | ||
| if (parts.length === 2 && parts[0] === '0') { | ||
| const decimalPart = parts[1] | ||
| // Find consecutive zeros after the decimal | ||
| const zeroMatch = decimalPart.match(/^0+/) | ||
| if (zeroMatch) { | ||
| const zeroCount = zeroMatch[0].length | ||
| const remainingDigits = decimalPart.substring(zeroCount) | ||
| // Only apply subscript if there are 3 or more leading zeros | ||
| if (zeroCount >= 3 && remainingDigits.length > 0) { | ||
| // Create subscript number (Unicode subscript digits) | ||
| const subscriptDigits = zeroCount | ||
| .toString() | ||
| .split('') | ||
| .map((digit) => { | ||
| const subscripts = [ | ||
faridsalau marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| '₀', | ||
| '₁', | ||
| '₂', | ||
| '₃', | ||
| '₄', | ||
| '₅', | ||
| '₆', | ||
| '₇', | ||
| '₈', | ||
| '₉' | ||
| ] | ||
| return subscripts[parseInt(digit)] | ||
| }) | ||
| .join('') | ||
| // Format as $0.0[subscript][remaining digits] | ||
| return `$0.0${subscriptDigits}${remainingDigits}` | ||
| } | ||
| } | ||
| } | ||
| return formatted | ||
| } catch { | ||
| return `$${num.toFixed(2)}` | ||
| } | ||
| } | ||
| export const formatCurrencyWithMax = ( | ||
| num: number, | ||
| max: number, | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's going on with
allTokens? it is an arg but then gets returned with no changes?can we just select
allTokensfrom some other hook inside this hook?and maybe don't need to return it?