mirror of
https://github.com/apotdevin/thunderhub.git
synced 2026-08-13 12:33:08 +02:00
Feat/amb 2389/asset usd balances (#684)
* feat: show asset balances in USD (AMB-2389)
Add prices { usd } to the getTapSupportedAssets query via the Amboss
trade API. Wire the price data through the server types and resolver,
then display a USD equivalent (≈ $X.XX) per balance entry in AssetsList.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: format balance using precision and display USD value
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Bufo <32884105+bufo24@users.noreply.github.com>
Co-authored-by: Rajat Khanduri <38693805+wthrajat@users.noreply.github.com>
This commit is contained in:
parent
211aa23bc0
commit
e3f882b329
8 changed files with 74 additions and 1 deletions
|
|
@ -812,6 +812,11 @@ type TapAssetList {
|
|||
assets: [TapAsset!]!
|
||||
}
|
||||
|
||||
type TapAssetPrice {
|
||||
id: String
|
||||
usd: Float
|
||||
}
|
||||
|
||||
enum TapAssetType {
|
||||
COLLECTIBLE
|
||||
NORMAL
|
||||
|
|
@ -874,6 +879,7 @@ type TapSupportedAsset {
|
|||
groupKey: String
|
||||
id: String!
|
||||
precision: Int!
|
||||
prices: TapAssetPrice
|
||||
symbol: String!
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ export type GetTapSupportedAssetsQuery = {
|
|||
precision: number;
|
||||
assetId?: string | null;
|
||||
groupKey?: string | null;
|
||||
prices?: { __typename?: 'TapAssetPrice'; usd?: number | null } | null;
|
||||
}>;
|
||||
};
|
||||
};
|
||||
|
|
@ -33,6 +34,9 @@ export const GetTapSupportedAssetsDocument = gql`
|
|||
precision
|
||||
assetId
|
||||
groupKey
|
||||
prices {
|
||||
usd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ export const GET_TAP_SUPPORTED_ASSETS = gql`
|
|||
precision
|
||||
assetId
|
||||
groupKey
|
||||
prices {
|
||||
usd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { Card, CardContent } from '@/components/ui/card';
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { useGetTapAssetsQuery } from '../../graphql/queries/__generated__/getTapAssets.generated';
|
||||
import { useGetTapBalancesQuery } from '../../graphql/queries/__generated__/getTapBalances.generated';
|
||||
import { useGetTapSupportedAssetsQuery } from '../../graphql/queries/__generated__/getTapSupportedAssets.generated';
|
||||
import { TapBalanceGroupBy } from '../../graphql/types';
|
||||
import { getErrorContent } from '../../utils/error';
|
||||
import { cn } from '../../lib/utils';
|
||||
|
|
@ -55,6 +56,17 @@ export const AssetsList: FC = () => {
|
|||
onError: error => toast.error(getErrorContent(error)),
|
||||
});
|
||||
|
||||
const { data: supportedData } = useGetTapSupportedAssetsQuery();
|
||||
|
||||
const priceMap = new Map<string, { usd: number; precision: number }>();
|
||||
for (const asset of supportedData?.getTapSupportedAssets?.list || []) {
|
||||
const price = asset.prices?.usd;
|
||||
if (price == null) continue;
|
||||
const entry = { usd: price, precision: asset.precision };
|
||||
if (asset.assetId) priceMap.set(asset.assetId, entry);
|
||||
if (asset.groupKey) priceMap.set(asset.groupKey, entry);
|
||||
}
|
||||
|
||||
if (assetsLoading || balancesLoading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center py-12">
|
||||
|
|
@ -112,6 +124,15 @@ export const AssetsList: FC = () => {
|
|||
const keyLabel =
|
||||
groupBy === TapBalanceGroupBy.GroupKey ? 'Group key' : 'Asset ID';
|
||||
|
||||
const priceEntry =
|
||||
priceMap.get(entry.groupKey || '') ||
|
||||
priceMap.get(entry.assetId || '');
|
||||
const usdValue =
|
||||
priceEntry && entry.balance
|
||||
? (Number(entry.balance) / 10 ** priceEntry.precision) *
|
||||
priceEntry.usd
|
||||
: null;
|
||||
|
||||
return (
|
||||
<Card key={`${keyValue}-${i}`}>
|
||||
<CardContent className="p-4">
|
||||
|
|
@ -132,8 +153,25 @@ export const AssetsList: FC = () => {
|
|||
</div>
|
||||
<div className="flex flex-col items-end gap-1">
|
||||
<span className="text-lg font-semibold">
|
||||
{entry.balance || '0'}
|
||||
{priceEntry
|
||||
? (
|
||||
Number(entry.balance) /
|
||||
10 ** priceEntry.precision
|
||||
).toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
})
|
||||
: entry.balance || '0'}
|
||||
</span>
|
||||
{usdValue != null && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
≈ $
|
||||
{usdValue.toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
})}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ export const getSupportedAssetsQuery = gql`
|
|||
description
|
||||
precision
|
||||
type
|
||||
prices {
|
||||
id
|
||||
usd
|
||||
}
|
||||
taproot_asset_details {
|
||||
asset_id
|
||||
group_key
|
||||
|
|
|
|||
|
|
@ -882,6 +882,7 @@ describe('TapdResolver trading queries', () => {
|
|||
precision: 2,
|
||||
assetId: undefined,
|
||||
groupKey: 'tapGroupKey1',
|
||||
prices: null,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -922,6 +923,7 @@ describe('TapdResolver trading queries', () => {
|
|||
precision: 0,
|
||||
assetId: 'tapAssetId2',
|
||||
groupKey: undefined,
|
||||
prices: null,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -982,6 +984,7 @@ describe('TapdResolver trading queries', () => {
|
|||
precision: 0,
|
||||
assetId: undefined,
|
||||
groupKey: undefined,
|
||||
prices: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ interface TradeApiSupportedAsset {
|
|||
description?: string;
|
||||
precision?: number;
|
||||
taproot_asset_details?: { asset_id?: string; group_key?: string };
|
||||
prices?: { id?: string; usd?: number };
|
||||
}
|
||||
|
||||
const ASSET_TYPE_MAP: Record<string, TapAssetType> = {
|
||||
|
|
@ -767,6 +768,7 @@ export class TapdResolver {
|
|||
precision: a.precision ?? 0,
|
||||
assetId: a.taproot_asset_details?.asset_id,
|
||||
groupKey: a.taproot_asset_details?.group_key,
|
||||
prices: a.prices ?? null,
|
||||
})),
|
||||
totalCount: assets.total_count,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
Field,
|
||||
Float,
|
||||
InputType,
|
||||
Int,
|
||||
ObjectType,
|
||||
|
|
@ -416,6 +417,15 @@ export class TapTradeOfferList {
|
|||
totalCount: number;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
export class TapAssetPrice {
|
||||
@Field({ nullable: true })
|
||||
id?: string;
|
||||
|
||||
@Field(() => Float, { nullable: true })
|
||||
usd?: number;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
export class TapSupportedAsset {
|
||||
@Field()
|
||||
|
|
@ -435,6 +445,9 @@ export class TapSupportedAsset {
|
|||
|
||||
@Field({ nullable: true })
|
||||
groupKey?: string;
|
||||
|
||||
@Field(() => TapAssetPrice, { nullable: true })
|
||||
prices?: TapAssetPrice;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue