From 1c1e004f8bd3113cb71caafa42cca7ed1c744b25 Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Sun, 19 May 2024 21:34:11 +0700 Subject: [PATCH 01/27] PnL with mock data --- apps/wallet/src/components/TotalPnL.tsx | 109 ++++++++++++++++++ apps/wallet/src/features/Home/TokenValue.tsx | 35 +++--- .../Widget/BuiltInNetwork/TokenList/Item.tsx | 18 ++- .../BuiltInNetwork/WalletCard/Balance.tsx | 8 +- 4 files changed, 150 insertions(+), 20 deletions(-) create mode 100644 apps/wallet/src/components/TotalPnL.tsx diff --git a/apps/wallet/src/components/TotalPnL.tsx b/apps/wallet/src/components/TotalPnL.tsx new file mode 100644 index 000000000..97d391bc9 --- /dev/null +++ b/apps/wallet/src/components/TotalPnL.tsx @@ -0,0 +1,109 @@ +import type { FC } from 'react'; +import { StyleSheet } from 'react-native'; +import { Text, View } from '@walless/gui'; + +interface Props { + value: number; + percentage: number; + isDarkTheme: boolean; +} + +const TotalPnL: FC = ({ value, percentage, isDarkTheme = false }) => { + const isLost = value < 0; + + return ( + + + ${value} + + + + {!isLost && '+'} + {percentage}% + + + + ); +}; + +export default TotalPnL; + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + }, + lightThemeProfitValue: { + color: '#60C591', + fontSize: 20, + }, + darkThemeProfitValue: { + color: '#173124', + fontSize: 20, + }, + lightThemeLostValue: { + color: '#AE3939', + fontSize: 20, + }, + darkThemeLostValue: { + color: '#173124', + fontSize: 20, + }, + lightThemeProfitPercentage: { + color: '#60C591', + }, + lightThemeLostPercentage: { + color: '#AE3939', + }, + darkThemeProfitPercentage: { + color: '#173124', + }, + darkThemeLostPercentage: { + color: '#173124', + }, + percentageContainer: { + borderRadius: 4, + paddingVertical: 4, + paddingHorizontal: 8, + }, + lightThemeProfitPercentageContainer: { + backgroundColor: '#AE393933', + }, + darkThemeProfitPercentageContainer: { + backgroundColor: '#60C591', + }, + lightThemeLostPercentageContainer: { + backgroundColor: '#AE393933', + }, + darkThemeLostPercentageContainer: { + backgroundColor: '#AE3939', + }, +}); diff --git a/apps/wallet/src/features/Home/TokenValue.tsx b/apps/wallet/src/features/Home/TokenValue.tsx index 74c946ff1..432044524 100644 --- a/apps/wallet/src/features/Home/TokenValue.tsx +++ b/apps/wallet/src/features/Home/TokenValue.tsx @@ -2,6 +2,7 @@ import type { FC } from 'react'; import { StyleSheet, View } from 'react-native'; import { Hoverable, Text } from '@walless/gui'; import { Eye, EyeOff } from '@walless/icons'; +import TotalPnL from 'components/TotalPnL'; import { useSettings } from 'utils/hooks'; interface Props { @@ -10,10 +11,6 @@ interface Props { const TokenValue: FC = ({ value }) => { const { setting, setPrivacy } = useSettings(); - const balanceTextStyle = [ - styles.balanceText, - setting.hideBalance && styles.protectedBalance, - ]; const handleToggleTokenValue = async () => { setPrivacy(!setting.hideBalance); @@ -22,17 +19,20 @@ const TokenValue: FC = ({ value }) => { return ( Token value - - - {setting.hideBalance ? '****' : '$' + value.toFixed(2)} - - - {setting.hideBalance ? ( - - ) : ( - - )} - + + + + {setting.hideBalance ? '****' : '$' + value.toFixed(2)} + + + {setting.hideBalance ? ( + + ) : ( + + )} + + + ); @@ -53,14 +53,13 @@ const styles = StyleSheet.create({ flexDirection: 'row', alignItems: 'center', gap: 12, - minHeight: 84, }, balanceText: { color: '#FFFFFF', fontSize: 40, fontWeight: '500', }, - protectedBalance: { - paddingTop: 16, + balanceAndPercentageContainer: { + alignItems: 'center', }, }); diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx index 85a78087d..8ec7410b9 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx @@ -25,7 +25,10 @@ export const TokenItem: FC = ({ style, token, onPress }) => { {itemName} - {formatQuote(unitQuote)} + + {formatQuote(unitQuote)} + +7.34% + {balance} @@ -75,4 +78,17 @@ const styles = StyleSheet.create({ color: '#566674', fontSize: 13, }, + unitQuoteContainer: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + }, + profitText: { + color: '#60C591', + fontSize: 10, + }, + lostText: { + color: '#AE3939', + fontSize: 10, + }, }); diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx index 237754573..d9b259084 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx @@ -2,6 +2,7 @@ import type { FC } from 'react'; import { StyleSheet } from 'react-native'; import { Hoverable, Text, View } from '@walless/gui'; import { Eye, EyeOff } from '@walless/icons'; +import TotalPnL from 'components/TotalPnL'; import numeral from 'numeral'; interface Props { @@ -30,6 +31,9 @@ export const WalletBalance: FC = ({ {getValuationDisplay(valuation, hideBalance)} + + + ); }; @@ -44,7 +48,6 @@ const styles = StyleSheet.create({ flexDirection: 'row', alignItems: 'center', paddingLeft: 5, - paddingBottom: 20, gap: 10, }, balanceText: { @@ -60,6 +63,9 @@ const styles = StyleSheet.create({ opacity: 0.6, marginLeft: 34, }, + pnLContainer: { + paddingLeft: 15, + }, }); const getValuationDisplay = (valuation: number, isPrivate?: boolean) => { From 857cbb404f2524862ed0913667d277842765a25e Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Mon, 20 May 2024 12:51:23 +0700 Subject: [PATCH 02/27] adjust some details of value pnl --- apps/wallet/src/components/TotalPnL.tsx | 14 +++++++------- .../Widget/BuiltInNetwork/TokenList/Item.tsx | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/wallet/src/components/TotalPnL.tsx b/apps/wallet/src/components/TotalPnL.tsx index 97d391bc9..d0d70c335 100644 --- a/apps/wallet/src/components/TotalPnL.tsx +++ b/apps/wallet/src/components/TotalPnL.tsx @@ -24,7 +24,7 @@ const TotalPnL: FC = ({ value, percentage, isDarkTheme = false }) => { : styles.lightThemeProfitValue } > - ${value} + {isLost ? `$${-value}` : `$${value}`} Date: Sat, 25 May 2024 17:03:39 +0700 Subject: [PATCH 03/27] fix some details in token item pnl --- apps/wallet/src/components/TotalPnL.tsx | 2 +- .../src/features/Widget/BuiltInNetwork/TokenList/Item.tsx | 8 ++++++-- .../features/Widget/BuiltInNetwork/TokenList/index.tsx | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/wallet/src/components/TotalPnL.tsx b/apps/wallet/src/components/TotalPnL.tsx index d0d70c335..0aec49077 100644 --- a/apps/wallet/src/components/TotalPnL.tsx +++ b/apps/wallet/src/components/TotalPnL.tsx @@ -24,7 +24,7 @@ const TotalPnL: FC = ({ value, percentage, isDarkTheme = false }) => { : styles.lightThemeProfitValue } > - {isLost ? `$${-value}` : `$${value}`} + {isLost ? `-$${-value}` : `+$${value}`} ; token: TokenDocument; onPress?: () => void; + pnl?: number; } -export const TokenItem: FC = ({ style, token, onPress }) => { +export const TokenItem: FC = ({ style, token, onPress, pnl }) => { const { symbol, image, quotes, balance } = token; const unitQuote = quotes?.usd; const totalQuote = unitQuote && unitQuote * balance; const iconSource = image ? { uri: image } : assets.misc.unknownToken; const itemName = symbol || 'Unknown'; + const isLost = pnl && pnl < 0; return ( @@ -27,7 +29,9 @@ export const TokenItem: FC = ({ style, token, onPress }) => { {itemName} {formatQuote(unitQuote)} - +7.34% + + {isLost ? '-' : '+'} {Math.abs(pnl ?? 0)}% + diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/index.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/index.tsx index 8c758fa42..59129376f 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/index.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/index.tsx @@ -38,6 +38,7 @@ export const TokenList = ({ token={item} style={itemStyle} onPress={handlePressItem} + pnl={-5} /> ); }; From a190a22aec325c79cd98e193891d699751495045 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 26 May 2024 16:09:23 +0700 Subject: [PATCH 04/27] Adding query P&L token --- packages/graphql/query/token.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/graphql/query/token.ts b/packages/graphql/query/token.ts index aee2309f7..4271f27ba 100644 --- a/packages/graphql/query/token.ts +++ b/packages/graphql/query/token.ts @@ -18,6 +18,7 @@ export const tokenByAddress = gql` address name quotes + pnl24h } } `; @@ -29,6 +30,7 @@ export const tokensByAddress = gql` address name quotes + pnl24h } } `; From 7fa2d18bb9d1cd27d8f1ef59ca4137b9070f7890 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 26 May 2024 16:24:18 +0700 Subject: [PATCH 05/27] Add field to TokenMetadata --- packages/core/utils/assets.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/utils/assets.ts b/packages/core/utils/assets.ts index 3a93563bf..bc1613b22 100644 --- a/packages/core/utils/assets.ts +++ b/packages/core/utils/assets.ts @@ -36,6 +36,7 @@ export type TokenMetadata = { name: string; symbol: string; image: string; + pnl24h: number; }; export type SuiTokenMetadata = TokenMetadata & { From 577057ff738a8957170ea190eb7f410a90edae35 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 26 May 2024 16:58:39 +0700 Subject: [PATCH 06/27] Remove pnl24h in TokenMetadata --- packages/core/utils/assets.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/utils/assets.ts b/packages/core/utils/assets.ts index bc1613b22..3a93563bf 100644 --- a/packages/core/utils/assets.ts +++ b/packages/core/utils/assets.ts @@ -36,7 +36,6 @@ export type TokenMetadata = { name: string; symbol: string; image: string; - pnl24h: number; }; export type SuiTokenMetadata = TokenMetadata & { From 2cde3c9081740bbfeb82f899781c8fa28af703b6 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 26 May 2024 17:00:10 +0700 Subject: [PATCH 07/27] Update schema --- schema.graphql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/schema.graphql b/schema.graphql index 91e47cdb7..d3631dca0 100644 --- a/schema.graphql +++ b/schema.graphql @@ -344,6 +344,9 @@ type TokenInfo { """""" timestamp: DateTime! + + """""" + pnl24h: Float! } """""" From ff45dd1c696d4805664540f43e5108a706e6d43f Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 31 May 2024 16:53:01 +0700 Subject: [PATCH 08/27] add type pnl24h to TokenInfo --- packages/graphql/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/graphql/types.ts b/packages/graphql/types.ts index 3143836c6..ebd703f4b 100644 --- a/packages/graphql/types.ts +++ b/packages/graphql/types.ts @@ -313,6 +313,7 @@ export type TokenInfo = { platforms: Scalars['JSON']['output']; quotes: Scalars['JSON']['output']; symbol: Scalars['String']['output']; + pnl24h: Scalars['Float']['output'] timestamp: Scalars['DateTime']['output']; }; @@ -637,6 +638,7 @@ export type TokenInfoResolvers; platforms?: Resolver; quotes?: Resolver; + pnl24h?:Resolver symbol?: Resolver; timestamp?: Resolver; __isTypeOf?: IsTypeOfResolverFn; From 94aaa528a1a41bf4facf804567a26650e40ade58 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 3 Jun 2024 12:23:52 +0700 Subject: [PATCH 09/27] Add pnl24h --- apps/wallet/src/engine/runners/solana/subscription.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/wallet/src/engine/runners/solana/subscription.ts b/apps/wallet/src/engine/runners/solana/subscription.ts index 5e14a4b33..e07741877 100644 --- a/apps/wallet/src/engine/runners/solana/subscription.ts +++ b/apps/wallet/src/engine/runners/solana/subscription.ts @@ -230,6 +230,10 @@ const handleInitAccountOnLogsChange = async ( const quotes = await getTokenQuotes([ { address: token.mint, network: token.network }, ]); + token.pnl24h = + quotes[ + makeHashId({ address: token.mint, network: token.network }) + ].pnl24h; token.quotes = quotes[ makeHashId({ address: token.mint, network: token.network }) From 861bb69cc9c4ce08b94c15c8121672af1dfc574f Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 3 Jun 2024 12:25:36 +0700 Subject: [PATCH 10/27] Add pnl to Token struct --- packages/core/utils/assets.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/utils/assets.ts b/packages/core/utils/assets.ts index 3a93563bf..cb4266eb4 100644 --- a/packages/core/utils/assets.ts +++ b/packages/core/utils/assets.ts @@ -30,6 +30,7 @@ export type Token = { owner: string; balance: number; quotes?: Record; + pnl24h: number; } & TokenMetadata; export type TokenMetadata = { From 3806c6ecb993d48951038edcf66423afa67cf128 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Wed, 31 Jul 2024 21:02:09 +0700 Subject: [PATCH 11/27] feat: sync pnl schema from server --- .gitignore | 3 +- packages/core/utils/assets.ts | 9 ++- packages/graphql/query/token.ts | 11 +++- packages/graphql/types.ts | 82 ++++++++++++++++++++------ schema.graphql | 101 ++++++++++++++++++++------------ 5 files changed, 146 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index 896181c0f..1b09fcd08 100644 --- a/.gitignore +++ b/.gitignore @@ -74,4 +74,5 @@ cli/tokens/**/cache.json cli/tokens/**/config.json cli/tokens/**/sugar.log -playground \ No newline at end of file +playground +.nvmrc diff --git a/packages/core/utils/assets.ts b/packages/core/utils/assets.ts index 0db0f6848..8d5019b80 100644 --- a/packages/core/utils/assets.ts +++ b/packages/core/utils/assets.ts @@ -30,9 +30,16 @@ export type Token = { owner: string; balance: number; quotes?: Record; - pnl24h: number; + pnl?: TokenPnL; } & TokenMetadata; +export type TokenPnL = { + currentPrice: number; + priceChangePercentage24H: number; + priceChangePercentage7d: number; + priceChangePercentage30d: number; +}; + export type TokenMetadata = { name: string; symbol: string; diff --git a/packages/graphql/query/token.ts b/packages/graphql/query/token.ts index 4271f27ba..acb4bd7cb 100644 --- a/packages/graphql/query/token.ts +++ b/packages/graphql/query/token.ts @@ -7,6 +7,9 @@ export const tokenById = gql` address name quotes + pnl { + currentPrice + } } } `; @@ -18,7 +21,9 @@ export const tokenByAddress = gql` address name quotes - pnl24h + pnl { + currentPrice + } } } `; @@ -30,7 +35,9 @@ export const tokensByAddress = gql` address name quotes - pnl24h + pnl { + currentPrice + } } } `; diff --git a/packages/graphql/types.ts b/packages/graphql/types.ts index 7e2b7f3c6..847ce7114 100644 --- a/packages/graphql/types.ts +++ b/packages/graphql/types.ts @@ -65,6 +65,20 @@ export type ActionCount = { type?: Maybe; }; +export type ActionInput = { + category: ActionCategory; + cycleInHours?: InputMaybe; + mechanism: VerifyMechanism; + metadata?: InputMaybe>>; + milestone?: InputMaybe; + points: Scalars['Float']['input']; + streak?: InputMaybe; + type: Scalars['String']['input']; + validFrom?: InputMaybe; + validUntil?: InputMaybe; + verifier?: InputMaybe; +}; + export type ActionMetadata = { __typename?: 'ActionMetadata'; key?: Maybe; @@ -93,20 +107,6 @@ export type Boost = { validUntil?: Maybe; }; -export type CreateActionInput = { - category: ActionCategory; - cycleInHours?: InputMaybe; - metadata?: InputMaybe>>; - milestone?: InputMaybe; - points: Scalars['Float']['input']; - streak?: InputMaybe; - type: Scalars['String']['input']; - validFrom?: InputMaybe; - validUntil?: InputMaybe; - verifier?: InputMaybe; - verifyMechanism: VerifyMechanism; -}; - export type Device = { __typename?: 'Device'; appVersion?: Maybe; @@ -183,9 +183,11 @@ export type RootMutation = { claimWalletInvitation?: Maybe; createLoyaltyAction?: Maybe; createLoyaltyBoost?: Maybe; + deleteLoyaltyAction?: Maybe; deleteWidget?: Maybe; deleteWidgetAccount?: Maybe; doLoyaltyAction?: Maybe; + doLoyaltyActionManually?: Maybe; doRecurringThenStreakThenMilestoneActionsByType?: Maybe>>; joinWaitlist?: Maybe; registerAccount?: Maybe; @@ -193,6 +195,7 @@ export type RootMutation = { registerWidgetAccount?: Maybe; sendEmergencyKit?: Maybe; trackAccountWallets?: Maybe; + updateLoyaltyAction?: Maybe; updateWidgetAccountRole?: Maybe; updateWidgetOwner?: Maybe; updateWidgetStatus?: Maybe; @@ -220,7 +223,7 @@ export type RootMutationClaimWalletInvitationArgs = { export type RootMutationCreateLoyaltyActionArgs = { - input: CreateActionInput; + input: ActionInput; }; @@ -233,6 +236,11 @@ export type RootMutationCreateLoyaltyBoostArgs = { }; +export type RootMutationDeleteLoyaltyActionArgs = { + id: Scalars['String']['input']; +}; + + export type RootMutationDeleteWidgetArgs = { id: Scalars['String']['input']; }; @@ -248,6 +256,12 @@ export type RootMutationDoLoyaltyActionArgs = { }; +export type RootMutationDoLoyaltyActionManuallyArgs = { + actionId: Scalars['String']['input']; + email: Scalars['String']['input']; +}; + + export type RootMutationDoRecurringThenStreakThenMilestoneActionsByTypeArgs = { type: Scalars['String']['input']; }; @@ -286,6 +300,12 @@ export type RootMutationTrackAccountWalletsArgs = { }; +export type RootMutationUpdateLoyaltyActionArgs = { + id: Scalars['String']['input']; + input: ActionInput; +}; + + export type RootMutationUpdateWidgetAccountRoleArgs = { id: Scalars['String']['input']; role: WidgetAccountRole; @@ -430,9 +450,18 @@ export type TokenInfo = { id: Scalars['String']['output']; name: Scalars['String']['output']; platforms: Scalars['JSON']['output']; + pnl: TokenPnL; quotes: Scalars['JSON']['output']; symbol: Scalars['String']['output']; - pnl24h: Scalars['Float']['output'] + timestamp: Scalars['DateTime']['output']; +}; + +export type TokenPnL = { + __typename?: 'TokenPnL'; + currentPrice: Scalars['Float']['output']; + priceChangePercentage7d?: Maybe; + priceChangePercentage24H?: Maybe; + priceChangePercentage30d?: Maybe; timestamp: Scalars['DateTime']['output']; }; @@ -580,12 +609,12 @@ export type ResolversTypes = { Action: ResolverTypeWrapper; ActionCategory: ActionCategory; ActionCount: ResolverTypeWrapper; + ActionInput: ActionInput; ActionMetadata: ResolverTypeWrapper; ActionMetadataInput: ActionMetadataInput; ActionRecord: ResolverTypeWrapper; Boolean: ResolverTypeWrapper; Boost: ResolverTypeWrapper; - CreateActionInput: CreateActionInput; DateTime: ResolverTypeWrapper; Device: ResolverTypeWrapper; DeviceInfoInput: DeviceInfoInput; @@ -607,6 +636,7 @@ export type ResolversTypes = { SystemInfo: ResolverTypeWrapper; Token: ResolverTypeWrapper; TokenInfo: ResolverTypeWrapper; + TokenPnL: ResolverTypeWrapper; TrackAccountWalletInput: TrackAccountWalletInput; Uint32: ResolverTypeWrapper; UserProgress: ResolverTypeWrapper; @@ -624,12 +654,12 @@ export type ResolversParentTypes = { Account: Account; Action: Action; ActionCount: ActionCount; + ActionInput: ActionInput; ActionMetadata: ActionMetadata; ActionMetadataInput: ActionMetadataInput; ActionRecord: ActionRecord; Boolean: Scalars['Boolean']['output']; Boost: Boost; - CreateActionInput: CreateActionInput; DateTime: Scalars['DateTime']['output']; Device: Device; DeviceInfoInput: DeviceInfoInput; @@ -650,6 +680,7 @@ export type ResolversParentTypes = { SystemInfo: SystemInfo; Token: Token; TokenInfo: TokenInfo; + TokenPnL: TokenPnL; TrackAccountWalletInput: TrackAccountWalletInput; Uint32: Scalars['Uint32']['output']; UserProgress: UserProgress; @@ -792,9 +823,11 @@ export type RootMutationResolvers, ParentType, ContextType, RequireFields>; createLoyaltyAction?: Resolver, ParentType, ContextType, RequireFields>; createLoyaltyBoost?: Resolver, ParentType, ContextType, RequireFields>; + deleteLoyaltyAction?: Resolver, ParentType, ContextType, RequireFields>; deleteWidget?: Resolver, ParentType, ContextType, RequireFields>; deleteWidgetAccount?: Resolver, ParentType, ContextType, RequireFields>; doLoyaltyAction?: Resolver, ParentType, ContextType, RequireFields>; + doLoyaltyActionManually?: Resolver, ParentType, ContextType, RequireFields>; doRecurringThenStreakThenMilestoneActionsByType?: Resolver>>, ParentType, ContextType, RequireFields>; joinWaitlist?: Resolver, ParentType, ContextType, RequireFields>; registerAccount?: Resolver, ParentType, ContextType, RequireFields>; @@ -802,6 +835,7 @@ export type RootMutationResolvers, ParentType, ContextType, RequireFields>; sendEmergencyKit?: Resolver, ParentType, ContextType, RequireFields>; trackAccountWallets?: Resolver, ParentType, ContextType, RequireFields>; + updateLoyaltyAction?: Resolver, ParentType, ContextType, RequireFields>; updateWidgetAccountRole?: Resolver, ParentType, ContextType, RequireFields>; updateWidgetOwner?: Resolver, ParentType, ContextType, RequireFields>; updateWidgetStatus?: Resolver, ParentType, ContextType, RequireFields>; @@ -864,13 +898,22 @@ export type TokenInfoResolvers; name?: Resolver; platforms?: Resolver; + pnl?: Resolver; quotes?: Resolver; - pnl24h?:Resolver symbol?: Resolver; timestamp?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; +export type TokenPnLResolvers = { + currentPrice?: Resolver; + priceChangePercentage7d?: Resolver, ParentType, ContextType>; + priceChangePercentage24H?: Resolver, ParentType, ContextType>; + priceChangePercentage30d?: Resolver, ParentType, ContextType>; + timestamp?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export interface Uint32ScalarConfig extends GraphQLScalarTypeConfig { name: 'Uint32'; } @@ -940,6 +983,7 @@ export type Resolvers = { SystemInfo?: SystemInfoResolvers; Token?: TokenResolvers; TokenInfo?: TokenInfoResolvers; + TokenPnL?: TokenPnLResolvers; Uint32?: GraphQLScalarType; UserProgress?: UserProgressResolvers; WalletInvitation?: WalletInvitationResolvers; diff --git a/schema.graphql b/schema.graphql index f77e25901..a5714f689 100644 --- a/schema.graphql +++ b/schema.graphql @@ -103,90 +103,90 @@ type ActionCount { } """""" -type ActionMetadata { +input ActionInput { """""" - key: String + category: ActionCategory! """""" - value: String -} + cycleInHours: Float = 0 -"""""" -input ActionMetadataInput { """""" - key: String + mechanism: VerifyMechanism! """""" - value: String -} + metadata: [ActionMetadataInput] -"""""" -type ActionRecord { """""" - actionId: String + milestone: Int = 0 """""" - timestamp: DateTime + points: Float! """""" - userId: String -} + streak: Int = 0 -"""""" -type Boost { """""" - actionId: String + type: String! """""" - id: String + validFrom: DateTime = "0001-01-01 00:00:00 +0000 UTC" """""" - multiplier: Float + validUntil: DateTime = "0001-01-01 00:00:00 +0000 UTC" """""" - points: Float + verifier: String = "" +} +"""""" +type ActionMetadata { """""" - validFrom: DateTime + key: String """""" - validUntil: DateTime + value: String } """""" -input CreateActionInput { +input ActionMetadataInput { """""" - category: ActionCategory! + key: String """""" - cycleInHours: Float = 0 + value: String +} +"""""" +type ActionRecord { """""" - metadata: [ActionMetadataInput] + actionId: String """""" - milestone: Int = 0 + timestamp: DateTime """""" - points: Float! + userId: String +} +"""""" +type Boost { """""" - streak: Int = 0 + actionId: String """""" - type: String! + id: String """""" - validFrom: DateTime = "0001-01-01 00:00:00 +0000 UTC" + multiplier: Float """""" - validUntil: DateTime = "0001-01-01 00:00:00 +0000 UTC" + points: Float """""" - verifier: String = "" + validFrom: DateTime """""" - verifyMechanism: VerifyMechanism! + validUntil: DateTime } """ @@ -367,11 +367,14 @@ type RootMutation { claimWalletInvitation(code: String!, email: String!): Boolean """""" - createLoyaltyAction(input: CreateActionInput!): Action + createLoyaltyAction(input: ActionInput!): Action """""" createLoyaltyBoost(actionId: String!, multiplier: Float!, points: Float!, validFrom: DateTime!, validUntil: DateTime!): Boost + """""" + deleteLoyaltyAction(id: String!): Boolean + """""" deleteWidget(id: String!): Boolean @@ -381,6 +384,9 @@ type RootMutation { """""" doLoyaltyAction(actionId: String!): ActionRecord + """""" + doLoyaltyActionManually(actionId: String!, email: String!): ActionRecord + """""" doRecurringThenStreakThenMilestoneActionsByType(type: String!): [ActionRecord] @@ -402,6 +408,9 @@ type RootMutation { """""" trackAccountWallets(wallets: [TrackAccountWalletInput]!): Int + """""" + updateLoyaltyAction(id: String!, input: ActionInput!): Action + """""" updateWidgetAccountRole(id: String!, role: WidgetAccountRole!): WidgetAccount @@ -540,6 +549,9 @@ type TokenInfo { """""" platforms: JSON! + """""" + pnl: TokenPnL! + """""" quotes: JSON! @@ -548,9 +560,24 @@ type TokenInfo { """""" timestamp: DateTime! +} + +"""""" +type TokenPnL { + """""" + currentPrice: Float! + + """""" + priceChangePercentage7d: Float """""" - pnl24h: Float! + priceChangePercentage24H: Float + + """""" + priceChangePercentage30d: Float + + """""" + timestamp: DateTime! } """""" From d53d9844045bd94ddcae12bcda22eab59eab8cd3 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Wed, 31 Jul 2024 21:07:31 +0700 Subject: [PATCH 12/27] feat: sync changes from types --- apps/wallet/src/engine/runners/solana/subscription.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/wallet/src/engine/runners/solana/subscription.ts b/apps/wallet/src/engine/runners/solana/subscription.ts index e07741877..35544e5f2 100644 --- a/apps/wallet/src/engine/runners/solana/subscription.ts +++ b/apps/wallet/src/engine/runners/solana/subscription.ts @@ -230,10 +230,8 @@ const handleInitAccountOnLogsChange = async ( const quotes = await getTokenQuotes([ { address: token.mint, network: token.network }, ]); - token.pnl24h = - quotes[ - makeHashId({ address: token.mint, network: token.network }) - ].pnl24h; + token.pnl = + quotes[makeHashId({ address: token.mint, network: token.network })].pnl; token.quotes = quotes[ makeHashId({ address: token.mint, network: token.network }) From 5519006bce71b0a56e0908b9671dc3e5d2a8f495 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Thu, 1 Aug 2024 00:49:27 +0700 Subject: [PATCH 13/27] feat-wip: working with PnL UI --- .../src/engine/runners/solana/tokens.ts | 14 +++++---- .../Widget/BuiltInNetwork/TokenList/Item.tsx | 6 ++-- .../Widget/BuiltInNetwork/TokenList/index.tsx | 2 +- .../BuiltInNetwork/WalletCard/Balance.tsx | 10 +++++-- .../BuiltInNetwork/WalletCard/index.tsx | 3 ++ .../features/Widget/BuiltInNetwork/index.tsx | 3 +- apps/wallet/src/utils/api.ts | 13 +++++++++ apps/wallet/src/utils/hooks/wallet.ts | 29 +++++++++++++++---- packages/graphql/query/token.ts | 3 ++ packages/graphql/types.ts | 12 ++++---- schema.graphql | 6 ++-- 11 files changed, 74 insertions(+), 27 deletions(-) diff --git a/apps/wallet/src/engine/runners/solana/tokens.ts b/apps/wallet/src/engine/runners/solana/tokens.ts index e3e3619b6..82eb19021 100644 --- a/apps/wallet/src/engine/runners/solana/tokens.ts +++ b/apps/wallet/src/engine/runners/solana/tokens.ts @@ -4,7 +4,7 @@ import { LAMPORTS_PER_SOL } from '@solana/web3.js'; import type { NetworkCluster, SolanaToken } from '@walless/core'; import { Networks } from '@walless/core'; import type { TokenDocument } from '@walless/store'; -import { getTokenQuote } from 'utils/api'; +import { getTokenQuote as getTokenInfo } from 'utils/api'; import { solMint, wrappedSolMint } from 'utils/constants'; import { addTokenToStorage } from 'utils/storage'; @@ -23,11 +23,12 @@ export const queryTokens = async ( cluster, wallet, ).then(async (doc) => { - const quotes = await getTokenQuote({ + const tokenInfo = await getTokenInfo({ address: wrappedSolMint, network: doc.network, }); - doc.quotes = quotes?.quotes; + doc.quotes = tokenInfo?.quotes; + doc.pnl = tokenInfo?.pnl; await addTokenToStorage(doc); return doc; @@ -42,11 +43,12 @@ export const queryTokens = async ( account, ); - const quotes = await getTokenQuote({ - address: doc.mint, + const tokenInfo = await getTokenInfo({ + address: 'BDHqX9YfJE3M6caox3obUX5YpWHz2cjnGFiZJtRghdCo', network: doc.network, }); - doc.quotes = quotes?.quotes; + doc.quotes = tokenInfo?.quotes; + doc.pnl = tokenInfo?.pnl; await addTokenToStorage(doc); return doc; diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx index 9a09553f3..c0bca5db6 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx @@ -1,6 +1,7 @@ import type { FC } from 'react'; import type { StyleProp, ViewStyle } from 'react-native'; import { Image, StyleSheet } from 'react-native'; +import type { TokenPnL } from '@walless/core'; import { Hoverable, Text, View } from '@walless/gui'; import type { TokenDocument } from '@walless/store'; import assets from 'utils/assets'; @@ -10,10 +11,11 @@ interface Props { style?: StyleProp; token: TokenDocument; onPress?: () => void; - pnl?: number; + tokenPnL?: TokenPnL; } -export const TokenItem: FC = ({ style, token, onPress, pnl }) => { +export const TokenItem: FC = ({ style, token, onPress, tokenPnL }) => { + const pnl = tokenPnL?.priceChangePercentage24H || 0; const { symbol, image, quotes, balance } = token; const unitQuote = quotes?.usd; const totalQuote = unitQuote && unitQuote * balance; diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/index.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/index.tsx index aaa638713..f6db0a1c6 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/index.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/index.tsx @@ -42,7 +42,7 @@ export const TokenList = ({ index === items.length - 1 && styles.lastItem, ]} onPress={handlePressItem} - pnl={-5} + tokenPnL={item.pnl} /> ); }; diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx index bb9cf80b0..80c66943f 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx @@ -3,24 +3,26 @@ import { StyleSheet } from 'react-native'; import { Hoverable, Text, View } from '@walless/gui'; import { Eye, EyeOff } from '@walless/icons'; import TotalPnL from 'components/TotalPnL'; -import numeral from 'numeral'; import { getValuationDisplay } from 'utils/helper'; interface Props { onHide: (next: boolean) => void; hideBalance: boolean; valuation?: number; + pnl?: number; } export const WalletBalance: FC = ({ onHide, hideBalance, valuation = 0, + pnl = 0, }) => { const balanceTextStyle = [ styles.balanceText, hideBalance && styles.protectedBalance, ]; + const pnlRates = (pnl / (valuation != 0 ? valuation : 1)) * 100; return ( @@ -33,7 +35,11 @@ export const WalletBalance: FC = ({ - + ); diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/index.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/index.tsx index a1bbc4777..2d80a4a12 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/index.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/index.tsx @@ -15,6 +15,7 @@ interface Props { item: PublicKeyDocument; skin: CardSkin; valuation?: number; + pnl?: number; hideBalance: boolean; onCopyAddress?: (value: string) => void; onChangePrivateSetting?: (value: boolean) => void; @@ -26,6 +27,7 @@ export const WalletCard: FC = ({ item, skin, valuation = 0, + pnl = 0, hideBalance, onCopyAddress, onChangePrivateSetting, @@ -58,6 +60,7 @@ export const WalletCard: FC = ({ hideBalance={hideBalance} valuation={valuation} onHide={handleHide} + pnl={pnl} /> {skin.largeIconSrc && ( diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/index.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/index.tsx index bd68650f0..7067fecb4 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/index.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/index.tsx @@ -36,7 +36,7 @@ export const BuiltInNetwork: FC = ({ id }) => { const [activeTabIndex, setActiveTabIndex] = useState(0); const keys = usePublicKeys(network); const [headerLayout, setHeaderLayout] = useState(); - const { valuation } = useTokens(network); + const { valuation, pnl } = useTokens(network); const cardSkin = useMemo(() => getWalletCardSkin(network), [network]); const opacityAnimated = useOpacityAnimated({ from: 0, to: 1 }); @@ -127,6 +127,7 @@ export const BuiltInNetwork: FC = ({ id }) => { index={index} item={item} valuation={valuation} + pnl={pnl} skin={cardSkin} hideBalance={false} width={headerLayout.width} diff --git a/apps/wallet/src/utils/api.ts b/apps/wallet/src/utils/api.ts index 23ccd5ddf..1f586eb95 100644 --- a/apps/wallet/src/utils/api.ts +++ b/apps/wallet/src/utils/api.ts @@ -41,3 +41,16 @@ export const getTokenQuote = async (token: IToken) => { console.log('failed to get token quote:', error); } }; + +export const getTokenPnL = async (token: IToken) => { + try { + const response = await qlClient.request< + { tokenByAddress: TokenInfo }, + { address: string } + >(queries.tokenByAddress, { address: makeHashId(token) }); + + return response.tokenByAddress; + } catch (error) { + console.log('failed to get token quote:', error); + } +}; diff --git a/apps/wallet/src/utils/hooks/wallet.ts b/apps/wallet/src/utils/hooks/wallet.ts index de5d4b5ab..e2901f15e 100644 --- a/apps/wallet/src/utils/hooks/wallet.ts +++ b/apps/wallet/src/utils/hooks/wallet.ts @@ -55,9 +55,17 @@ const getTokenValue = (token: TokenDocument, currency: string) => { return quote * balance; }; +const getTokenPnLValue = (token: TokenDocument, totalValue: number) => { + const { pnl } = token; + const totalPnL = pnl?.priceChangePercentage24H || 0; + + return (totalPnL / 100) * totalValue; +}; + type TokenResult = { tokens: TokenDocument[]; valuation: number; + pnl: number; }; export const useTokens = ( @@ -75,6 +83,7 @@ export const useTokens = ( }); let valuation = 0; + let pnl = 0; switch (network) { case Networks.solana: { @@ -85,7 +94,9 @@ export const useTokens = ( const isSol = token.mint === solMint; if (isNetworkValid && (isSol || isAvailable)) { - valuation += getTokenValue(token, currency); + const totalValue = getTokenValue(token, currency); + valuation += totalValue; + pnl += getTokenPnLValue(token, totalValue); filteredTokens.push(token); } } @@ -103,6 +114,7 @@ export const useTokens = ( return { tokens: filteredTokens, valuation, + pnl, }; } case Networks.sui: { @@ -113,7 +125,9 @@ export const useTokens = ( const isSUI = token.coinType === SUI_COIN_TYPE; if (isNetworkValid && (isSUI || isAvailable)) { - valuation += getTokenValue(token, currency); + const totalValue = getTokenValue(token, currency); + valuation += totalValue; + pnl += getTokenPnLValue(token, totalValue); filteredTokens.push(token); } } @@ -131,19 +145,22 @@ export const useTokens = ( return { tokens: filteredTokens, valuation, + pnl, }; } case Networks.tezos: { - return { tokens, valuation }; + return { tokens, valuation, pnl }; } case Networks.aptos: { - return { tokens, valuation }; + return { tokens, valuation, pnl }; } default: { tokens.forEach((token) => { - valuation += getTokenValue(token, currency); + const totalValue = getTokenValue(token, currency); + valuation += totalValue; + pnl += getTokenPnLValue(token, totalValue); }); - return { tokens, valuation }; + return { tokens, valuation, pnl }; } } }, [map, network, address]) as never as TokenResult; diff --git a/packages/graphql/query/token.ts b/packages/graphql/query/token.ts index acb4bd7cb..206d8045c 100644 --- a/packages/graphql/query/token.ts +++ b/packages/graphql/query/token.ts @@ -9,6 +9,7 @@ export const tokenById = gql` quotes pnl { currentPrice + priceChangePercentage24H } } } @@ -23,6 +24,7 @@ export const tokenByAddress = gql` quotes pnl { currentPrice + priceChangePercentage24H } } } @@ -37,6 +39,7 @@ export const tokensByAddress = gql` quotes pnl { currentPrice + priceChangePercentage24H } } } diff --git a/packages/graphql/types.ts b/packages/graphql/types.ts index 847ce7114..905a5adad 100644 --- a/packages/graphql/types.ts +++ b/packages/graphql/types.ts @@ -459,9 +459,9 @@ export type TokenInfo = { export type TokenPnL = { __typename?: 'TokenPnL'; currentPrice: Scalars['Float']['output']; - priceChangePercentage7d?: Maybe; - priceChangePercentage24H?: Maybe; - priceChangePercentage30d?: Maybe; + priceChangePercentage7d: Scalars['Float']['output']; + priceChangePercentage24H: Scalars['Float']['output']; + priceChangePercentage30d: Scalars['Float']['output']; timestamp: Scalars['DateTime']['output']; }; @@ -907,9 +907,9 @@ export type TokenInfoResolvers = { currentPrice?: Resolver; - priceChangePercentage7d?: Resolver, ParentType, ContextType>; - priceChangePercentage24H?: Resolver, ParentType, ContextType>; - priceChangePercentage30d?: Resolver, ParentType, ContextType>; + priceChangePercentage7d?: Resolver; + priceChangePercentage24H?: Resolver; + priceChangePercentage30d?: Resolver; timestamp?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; diff --git a/schema.graphql b/schema.graphql index a5714f689..5d4f33317 100644 --- a/schema.graphql +++ b/schema.graphql @@ -568,13 +568,13 @@ type TokenPnL { currentPrice: Float! """""" - priceChangePercentage7d: Float + priceChangePercentage7d: Float! """""" - priceChangePercentage24H: Float + priceChangePercentage24H: Float! """""" - priceChangePercentage30d: Float + priceChangePercentage30d: Float! """""" timestamp: DateTime! From 942f658e90df7dd87e261343ee427a94682c8d94 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Thu, 1 Aug 2024 23:44:53 +0700 Subject: [PATCH 14/27] chore: make tokenPnL render with 4 precision --- .../src/features/Widget/BuiltInNetwork/TokenList/Item.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx index c0bca5db6..baa4a54bb 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx @@ -32,7 +32,7 @@ export const TokenItem: FC = ({ style, token, onPress, tokenPnL }) => { {formatQuote(unitQuote)} - {isLost ? '-' : '+'} {Math.abs(pnl ?? 0)}% + {isLost ? '-' : '+'} {Math.abs(Math.round(pnl * 10000) / 10000 ?? 0)}% From f7aa19dafea97f48f6ca6839d5bfee2286511792 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Thu, 8 Aug 2024 23:44:16 +0700 Subject: [PATCH 15/27] fix: fix render wrong pnl percentage container --- apps/wallet/src/components/TotalPnL.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/wallet/src/components/TotalPnL.tsx b/apps/wallet/src/components/TotalPnL.tsx index 0aec49077..80141b69f 100644 --- a/apps/wallet/src/components/TotalPnL.tsx +++ b/apps/wallet/src/components/TotalPnL.tsx @@ -30,8 +30,12 @@ const TotalPnL: FC = ({ value, percentage, isDarkTheme = false }) => { style={[ styles.percentageContainer, isDarkTheme - ? styles.darkThemeProfitPercentageContainer - : styles.lightThemeProfitPercentageContainer, + ? isLost + ? styles.darkThemeLostPercentageContainer + : styles.darkThemeProfitPercentageContainer + : isLost + ? styles.lightThemeLostPercentageContainer + : styles.lightThemeProfitPercentageContainer, ]} > Date: Thu, 1 Aug 2024 23:45:21 +0700 Subject: [PATCH 16/27] feat: calc tokenPnL --- apps/wallet/src/features/Home/TokenValue.tsx | 10 ++++++++-- .../Widget/BuiltInNetwork/WalletCard/Balance.tsx | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/wallet/src/features/Home/TokenValue.tsx b/apps/wallet/src/features/Home/TokenValue.tsx index 432044524..4a9b629f3 100644 --- a/apps/wallet/src/features/Home/TokenValue.tsx +++ b/apps/wallet/src/features/Home/TokenValue.tsx @@ -3,7 +3,7 @@ import { StyleSheet, View } from 'react-native'; import { Hoverable, Text } from '@walless/gui'; import { Eye, EyeOff } from '@walless/icons'; import TotalPnL from 'components/TotalPnL'; -import { useSettings } from 'utils/hooks'; +import { useSettings, useTokens } from 'utils/hooks'; interface Props { value: number; @@ -11,10 +11,12 @@ interface Props { const TokenValue: FC = ({ value }) => { const { setting, setPrivacy } = useSettings(); + const { valuation, pnl } = useTokens(); const handleToggleTokenValue = async () => { setPrivacy(!setting.hideBalance); }; + const pnlRates = (pnl / (valuation != 0 ? valuation : 1)) * 100; return ( @@ -32,7 +34,11 @@ const TokenValue: FC = ({ value }) => { )} - + ); diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx index 80c66943f..3cb45ba46 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/WalletCard/Balance.tsx @@ -36,9 +36,9 @@ export const WalletBalance: FC = ({ @@ -71,6 +71,6 @@ const styles = StyleSheet.create({ marginLeft: 34, }, pnLContainer: { - paddingLeft: 15, + paddingLeft: 10, }, }); From 66398b1aa054998983174da5a1dfc454b18a4394 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Thu, 8 Aug 2024 23:59:22 +0700 Subject: [PATCH 17/27] chore: remove hardcoded address --- apps/wallet/src/engine/runners/solana/tokens.ts | 2 +- .../src/features/Widget/BuiltInNetwork/TokenList/Item.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/wallet/src/engine/runners/solana/tokens.ts b/apps/wallet/src/engine/runners/solana/tokens.ts index 82eb19021..7d91e8b22 100644 --- a/apps/wallet/src/engine/runners/solana/tokens.ts +++ b/apps/wallet/src/engine/runners/solana/tokens.ts @@ -44,7 +44,7 @@ export const queryTokens = async ( ); const tokenInfo = await getTokenInfo({ - address: 'BDHqX9YfJE3M6caox3obUX5YpWHz2cjnGFiZJtRghdCo', + address: doc.mint, network: doc.network, }); doc.quotes = tokenInfo?.quotes; diff --git a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx index baa4a54bb..26935d4fd 100644 --- a/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx +++ b/apps/wallet/src/features/Widget/BuiltInNetwork/TokenList/Item.tsx @@ -32,7 +32,8 @@ export const TokenItem: FC = ({ style, token, onPress, tokenPnL }) => { {formatQuote(unitQuote)} - {isLost ? '-' : '+'} {Math.abs(Math.round(pnl * 10000) / 10000 ?? 0)}% + {isLost ? '-' : '+'}{' '} + {Math.abs(Math.round(pnl * 10000) / 10000 ?? 0)}% From fd5674c87586790fa1a0489b688b5f1175f74769 Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Mon, 12 Aug 2024 15:40:20 +0700 Subject: [PATCH 18/27] fix: add custom wallet info to the remote config --- .../Explorer/Highlights/HighlightItem.tsx | 4 ++- .../features/Explorer/Widgets/WidgetItem.tsx | 4 ++- apps/wallet/src/features/Explorer/index.tsx | 12 +++---- apps/wallet/src/stacks/Dashboard/index.tsx | 2 +- apps/wallet/src/stacks/Explorer/Sidebar.tsx | 2 +- apps/wallet/src/state/widget/shared.ts | 25 --------------- apps/wallet/src/utils/constants.ts | 19 ++++++++++++ apps/wallet/src/utils/hooks/widget.ts | 31 ++++++++++++++++--- apps/wallet/src/utils/widget.ts | 6 ++-- packages/core/utils/entity.ts | 8 +++++ packages/core/utils/widget.ts | 4 +-- 11 files changed, 73 insertions(+), 44 deletions(-) diff --git a/apps/wallet/src/features/Explorer/Highlights/HighlightItem.tsx b/apps/wallet/src/features/Explorer/Highlights/HighlightItem.tsx index 6dd82ebad..e19efb2de 100644 --- a/apps/wallet/src/features/Explorer/Highlights/HighlightItem.tsx +++ b/apps/wallet/src/features/Explorer/Highlights/HighlightItem.tsx @@ -16,7 +16,9 @@ interface HighlightItemProps { } const HighlightItem: FC = ({ widget }) => { - const addedWidgets = useWidgets().map((widget) => widget._id); + const addedWidgets = useWidgets({ filterAdded: true }).map( + (widget) => widget._id, + ); const coverImgResource = runtime.isMobile ? assets.widget[widget._id]?.storeMeta.coverUri diff --git a/apps/wallet/src/features/Explorer/Widgets/WidgetItem.tsx b/apps/wallet/src/features/Explorer/Widgets/WidgetItem.tsx index d4125e9c5..a42130aa4 100644 --- a/apps/wallet/src/features/Explorer/Widgets/WidgetItem.tsx +++ b/apps/wallet/src/features/Explorer/Widgets/WidgetItem.tsx @@ -18,7 +18,9 @@ const WidgetItem: FC = ({ widget }) => { ? assets.widget[widget._id]?.storeMeta.coverUri : { uri: widget.storeMeta.coverUri }; - const addedWidgets = useWidgets().map((widget) => widget._id); + const addedWidgets = useWidgets({ filterAdded: true }).map( + (widget) => widget._id, + ); const isAdded = addedWidgets.includes(widget._id); const handleOpenWidget = (id: string) => { diff --git a/apps/wallet/src/features/Explorer/index.tsx b/apps/wallet/src/features/Explorer/index.tsx index acb07d26a..9d9cc2c0b 100644 --- a/apps/wallet/src/features/Explorer/index.tsx +++ b/apps/wallet/src/features/Explorer/index.tsx @@ -4,8 +4,7 @@ import type { StyleProp, ViewStyle } from 'react-native'; import { ScrollView, StyleSheet } from 'react-native'; import { View } from '@walless/gui'; import type { WidgetDocument } from '@walless/store'; -import { mockWidgets } from 'state/widget'; -import { useNfts, useTokens } from 'utils/hooks'; +import { useNfts, useTokens, useWidgets } from 'utils/hooks'; import { filterMap } from 'utils/widget'; import Header from './Header'; @@ -24,10 +23,11 @@ interface Props { export const ExplorerFeature: FC = ({ style }) => { const { tokens } = useTokens(); const { nfts } = useNfts(); + const widgets = useWidgets({}); - const widgets = useMemo( + const filteredWidgets = useMemo( () => - mockWidgets.filter((widget) => { + widgets.filter((widget) => { if (filterMap[widget._id]) { const filters = filterMap[widget._id]; return filters?.some((filter) => filter(widget)); @@ -44,8 +44,8 @@ export const ExplorerFeature: FC = ({ style }) => { - - + + ); diff --git a/apps/wallet/src/stacks/Dashboard/index.tsx b/apps/wallet/src/stacks/Dashboard/index.tsx index bf61ff7f1..475b07731 100644 --- a/apps/wallet/src/stacks/Dashboard/index.tsx +++ b/apps/wallet/src/stacks/Dashboard/index.tsx @@ -26,7 +26,7 @@ const Tab = createBottomTabNavigator(); export const DashboardStack = () => { useNotificationPermissionRequest(); const { showFirstTimePopup: showPopup } = useSnapshot(appState); - const widgets = useWidgets(); + const widgets = useWidgets({ filterAdded: true }); useEffect(() => { const alreadyHavePixeverse = widgets.some( diff --git a/apps/wallet/src/stacks/Explorer/Sidebar.tsx b/apps/wallet/src/stacks/Explorer/Sidebar.tsx index 8d08d32c4..cf64ffa24 100644 --- a/apps/wallet/src/stacks/Explorer/Sidebar.tsx +++ b/apps/wallet/src/stacks/Explorer/Sidebar.tsx @@ -16,7 +16,7 @@ export const sidebarWidth = 64; export const Sidebar: FC = ({ state }) => { const drawerStatus = useDrawerStatus(); const { profile } = useSnapshot(appState); - const widgets = useWidgets(); + const widgets = useWidgets({ filterAdded: true }); useEffect(() => { runtimeActions.toggleDrawer(drawerStatus === 'open'); diff --git a/apps/wallet/src/state/widget/shared.ts b/apps/wallet/src/state/widget/shared.ts index 7ad265a69..02be7148a 100644 --- a/apps/wallet/src/state/widget/shared.ts +++ b/apps/wallet/src/state/widget/shared.ts @@ -1,4 +1,3 @@ -import type { CustomWalletAssets } from '@walless/core'; import { Networks, WidgetSubcategories } from '@walless/core'; import { gradientDirection } from '@walless/gui'; import type { WidgetDocument } from '@walless/store'; @@ -266,30 +265,6 @@ export const mockWidgets: WidgetDocument[] = [ image: '/img/widget/samo-ad-1.png', }, ], - tokens: new Map([ - [ - '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU', - { - mintAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU', - amount: 50000, - }, - ], - [ - 'So11111111111111111111111111111111111111112', - { - mintAddress: 'So11111111111111111111111111111111111111112', - }, - ], - ]), - nfts: new Map([ - [ - '98fe506a37c46d67b7212ec689decd6fcd7137ea751fb88d9c7fe89c60c5215f', - { - mintAddress: - '98fe506a37c46d67b7212ec689decd6fcd7137ea751fb88d9c7fe89c60c5215f', - }, - ], - ]), network: Networks.solana, }, }, diff --git a/apps/wallet/src/utils/constants.ts b/apps/wallet/src/utils/constants.ts index 98177309f..bc3d44ede 100644 --- a/apps/wallet/src/utils/constants.ts +++ b/apps/wallet/src/utils/constants.ts @@ -15,6 +15,25 @@ export const defaultRemoteConfig: RemoteConfig = { experimentalEnabled: true, deepAnalyticsEnabled: true, minimalVersion: '1.0.0', + customWallets: { + samo: { + tokens: { + '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU': { + mintAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU', + amount: 50000, + }, + So11111111111111111111111111111111111111112: { + mintAddress: 'So11111111111111111111111111111111111111112', + }, + }, + nfts: { + '98fe506a37c46d67b7212ec689decd6fcd7137ea751fb88d9c7fe89c60c5215f': { + mintAddress: + '98fe506a37c46d67b7212ec689decd6fcd7137ea751fb88d9c7fe89c60c5215f', + }, + }, + }, + }, }; /** diff --git a/apps/wallet/src/utils/hooks/widget.ts b/apps/wallet/src/utils/hooks/widget.ts index e0c77a9f7..cd7a13e45 100644 --- a/apps/wallet/src/utils/hooks/widget.ts +++ b/apps/wallet/src/utils/hooks/widget.ts @@ -1,14 +1,37 @@ import { useMemo } from 'react'; +import type { CustomWalletMetadata } from '@walless/core'; +import { WidgetSubcategories } from '@walless/core'; import { sortBy } from 'lodash'; -import { widgetState } from 'state/widget'; +import { appState } from 'state/app'; +import { mockWidgets, widgetState } from 'state/widget'; import { useSnapshot } from './aliased'; -export const useWidgets = () => { +interface Options { + filterAdded?: boolean; +} + +export const useWidgets = ({ filterAdded }: Options) => { const { map } = useSnapshot(widgetState); + const { remoteConfig } = useSnapshot(appState); return useMemo(() => { - const widgets = Array.from(map.values()); - return sortBy(widgets, 'timestamp'); + if (filterAdded) { + const widgets = Array.from(map.values()); + return sortBy(widgets, 'timestamp'); + } + + const widgets = mockWidgets.map((widget) => { + if (widget.category === WidgetSubcategories.CUSTOM_WALLET) { + (widget.metadata as CustomWalletMetadata).tokens = + remoteConfig.customWallets?.[widget._id].tokens; + (widget.metadata as CustomWalletMetadata).nfts = + remoteConfig.customWallets?.[widget._id].nfts; + } + + return widget; + }); + + return widgets; }, [map]); }; diff --git a/apps/wallet/src/utils/widget.ts b/apps/wallet/src/utils/widget.ts index 13174cb34..3e9148d13 100644 --- a/apps/wallet/src/utils/widget.ts +++ b/apps/wallet/src/utils/widget.ts @@ -93,7 +93,7 @@ export const filterByOwnedTokens = (widget: WidgetDocument) => { const requiredTokens = (widget.metadata as CustomWalletMetadata)?.tokens; const filteredTokens = ownedTokens.filter((ownedToken) => { const id = getTokenAddress(ownedToken); - return requiredTokens?.has(id); + return requiredTokens?.[id]; }); return filteredTokens; @@ -105,7 +105,7 @@ export const explorerFilterByTokenBalances = (widget: WidgetDocument) => { const filteredTokens = tokens.filter((token) => { const id = getTokenAddress(token as TokenDocument); - const requiredToken = requiredTokens?.get(id); + const requiredToken = requiredTokens?.[id]; return ( requiredToken?.amount !== undefined && @@ -125,7 +125,7 @@ export const filterByOwnedNfts = (widget: WidgetDocument) => { const filteredNfts = ownedNfts.filter((ownedNft) => { const splittedStrings = ownedNft.collectionId?.split('/') || []; const id = splittedStrings[2] || ''; - return requiredNfts?.has(id); + return requiredNfts?.[id]; }); return filteredNfts; diff --git a/packages/core/utils/entity.ts b/packages/core/utils/entity.ts index 0098808c6..463d4fe03 100644 --- a/packages/core/utils/entity.ts +++ b/packages/core/utils/entity.ts @@ -1,4 +1,5 @@ import type { NetworkCluster, Networks } from './common'; +import type { CustomWalletAssets } from './widget'; export interface AptosTokenMetadata { creatorAddress: string; @@ -35,6 +36,13 @@ export interface RemoteConfig { experimentalEnabled: boolean; deepAnalyticsEnabled: boolean; minimalVersion: string; + customWallets?: Record< + string, + { + tokens?: Record; + nfts?: Record; + } + >; } export interface UserProfile { diff --git a/packages/core/utils/widget.ts b/packages/core/utils/widget.ts index 8466b0244..86342a0e7 100644 --- a/packages/core/utils/widget.ts +++ b/packages/core/utils/widget.ts @@ -44,8 +44,8 @@ export interface CustomWalletMetadata { }; activeTabStyle?: TabItemStyle; advertisements: CustomWalletAdvertisement[]; - tokens?: Map; - nfts?: Map; + tokens?: Record; + nfts?: Record; network: Networks; } From 9d754e211241dcc1be3bbe54efadf2b3ed67afb3 Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Mon, 12 Aug 2024 15:50:08 +0700 Subject: [PATCH 19/27] fix: add all the custom stuff to remote config --- apps/wallet/src/state/widget/shared.ts | 45 -------------------------- apps/wallet/src/utils/constants.ts | 44 +++++++++++++++++++++++++ apps/wallet/src/utils/hooks/widget.ts | 7 ++-- packages/core/utils/entity.ts | 10 ++---- 4 files changed, 49 insertions(+), 57 deletions(-) diff --git a/apps/wallet/src/state/widget/shared.ts b/apps/wallet/src/state/widget/shared.ts index 02be7148a..dc887c570 100644 --- a/apps/wallet/src/state/widget/shared.ts +++ b/apps/wallet/src/state/widget/shared.ts @@ -1,5 +1,4 @@ import { Networks, WidgetSubcategories } from '@walless/core'; -import { gradientDirection } from '@walless/gui'; import type { WidgetDocument } from '@walless/store'; // TODO: this mocked data is for web only @@ -223,49 +222,5 @@ export const mockWidgets: WidgetDocument[] = [ loveCount: 46, activeCount: 202, }, - metadata: { - coverBanner: '/img/widget/samo-banner.png', - iconSrc: '/img/widget/samo-icon.png', - backgroundColor: '#141121', - actionButtonBackgroundColors: { - send: '#0051BD', - receive: '#3D55BF', - buy: '#7E60D2', - swap: '#C36BE5', - }, - activeTabStyle: { - linearGradient: { - direction: gradientDirection.LeftToRight, - colors: ['#1A4FB5', '#C36BE5'], - }, - textStyle: { - color: 'white', - fontWeight: '500', - }, - }, - advertisements: [ - { - title: 'Get your SAMO debit card', - link: '', - image: '/img/widget/samo-ad-1.png', - }, - { - title: 'Get your SAMO debit card', - link: '', - image: '/img/widget/samo-ad-1.png', - }, - { - title: 'Get your SAMO debit card', - link: '', - image: '/img/widget/samo-ad-1.png', - }, - { - title: 'Get your SAMO debit card', - link: '', - image: '/img/widget/samo-ad-1.png', - }, - ], - network: Networks.solana, - }, }, ]; diff --git a/apps/wallet/src/utils/constants.ts b/apps/wallet/src/utils/constants.ts index bc3d44ede..db2f33fb5 100644 --- a/apps/wallet/src/utils/constants.ts +++ b/apps/wallet/src/utils/constants.ts @@ -1,4 +1,6 @@ import type { Config, RemoteConfig } from '@walless/core'; +import { Networks } from '@walless/core'; +import { gradientDirection } from '@walless/gui'; export const noHeaderNavigation = { headerShown: false, @@ -17,6 +19,48 @@ export const defaultRemoteConfig: RemoteConfig = { minimalVersion: '1.0.0', customWallets: { samo: { + coverBanner: '/img/widget/samo-banner.png', + iconSrc: '/img/widget/samo-icon.png', + backgroundColor: '#141121', + actionButtonBackgroundColors: { + send: '#0051BD', + receive: '#3D55BF', + buy: '#7E60D2', + swap: '#C36BE5', + }, + activeTabStyle: { + linearGradient: { + direction: gradientDirection.LeftToRight, + colors: ['#1A4FB5', '#C36BE5'], + }, + textStyle: { + color: 'white', + fontWeight: '500', + }, + }, + advertisements: [ + { + title: 'Get your SAMO debit card', + link: '', + image: '/img/widget/samo-ad-1.png', + }, + { + title: 'Get your SAMO debit card', + link: '', + image: '/img/widget/samo-ad-1.png', + }, + { + title: 'Get your SAMO debit card', + link: '', + image: '/img/widget/samo-ad-1.png', + }, + { + title: 'Get your SAMO debit card', + link: '', + image: '/img/widget/samo-ad-1.png', + }, + ], + network: Networks.solana, tokens: { '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU': { mintAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU', diff --git a/apps/wallet/src/utils/hooks/widget.ts b/apps/wallet/src/utils/hooks/widget.ts index cd7a13e45..70f77a05a 100644 --- a/apps/wallet/src/utils/hooks/widget.ts +++ b/apps/wallet/src/utils/hooks/widget.ts @@ -23,10 +23,9 @@ export const useWidgets = ({ filterAdded }: Options) => { const widgets = mockWidgets.map((widget) => { if (widget.category === WidgetSubcategories.CUSTOM_WALLET) { - (widget.metadata as CustomWalletMetadata).tokens = - remoteConfig.customWallets?.[widget._id].tokens; - (widget.metadata as CustomWalletMetadata).nfts = - remoteConfig.customWallets?.[widget._id].nfts; + widget.metadata = remoteConfig.customWallets?.[ + widget._id + ] as CustomWalletMetadata; } return widget; diff --git a/packages/core/utils/entity.ts b/packages/core/utils/entity.ts index 463d4fe03..c2595ba9c 100644 --- a/packages/core/utils/entity.ts +++ b/packages/core/utils/entity.ts @@ -1,5 +1,5 @@ import type { NetworkCluster, Networks } from './common'; -import type { CustomWalletAssets } from './widget'; +import type { CustomWalletMetadata } from './widget'; export interface AptosTokenMetadata { creatorAddress: string; @@ -36,13 +36,7 @@ export interface RemoteConfig { experimentalEnabled: boolean; deepAnalyticsEnabled: boolean; minimalVersion: string; - customWallets?: Record< - string, - { - tokens?: Record; - nfts?: Record; - } - >; + customWallets?: Record; } export interface UserProfile { From e165d2ab21a092984048af2e976c9e461c535ec7 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Tue, 13 Aug 2024 00:51:02 +0700 Subject: [PATCH 20/27] chore: only render pnl if percentages is different than 0 --- apps/wallet/src/components/TokenList/Item.tsx | 10 ++++++---- apps/wallet/src/components/TotalPnL.tsx | 6 +++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/wallet/src/components/TokenList/Item.tsx b/apps/wallet/src/components/TokenList/Item.tsx index 26935d4fd..3107e164f 100644 --- a/apps/wallet/src/components/TokenList/Item.tsx +++ b/apps/wallet/src/components/TokenList/Item.tsx @@ -15,14 +15,17 @@ interface Props { } export const TokenItem: FC = ({ style, token, onPress, tokenPnL }) => { - const pnl = tokenPnL?.priceChangePercentage24H || 0; + const pnl = tokenPnL?.priceChangePercentage24H ?? 0; const { symbol, image, quotes, balance } = token; const unitQuote = quotes?.usd; const totalQuote = unitQuote && unitQuote * balance; + const iconSource = image ? { uri: image } : assets.misc.unknownToken; + const fixedPnL = Math.round(pnl * 10000) / 10000; const itemName = symbol || 'Unknown'; - const isLost = pnl && pnl < 0; + const isLost = fixedPnL < 0; + const isProfit = fixedPnL > 0; return ( @@ -32,8 +35,7 @@ export const TokenItem: FC = ({ style, token, onPress, tokenPnL }) => { {formatQuote(unitQuote)} - {isLost ? '-' : '+'}{' '} - {Math.abs(Math.round(pnl * 10000) / 10000 ?? 0)}% + {isLost ? `-${-fixedPnL}` : isProfit ? `+${fixedPnL}` : null} diff --git a/apps/wallet/src/components/TotalPnL.tsx b/apps/wallet/src/components/TotalPnL.tsx index 80141b69f..88c1cff88 100644 --- a/apps/wallet/src/components/TotalPnL.tsx +++ b/apps/wallet/src/components/TotalPnL.tsx @@ -10,6 +10,7 @@ interface Props { const TotalPnL: FC = ({ value, percentage, isDarkTheme = false }) => { const isLost = value < 0; + const isProfit = value > 0; return ( @@ -24,7 +25,7 @@ const TotalPnL: FC = ({ value, percentage, isDarkTheme = false }) => { : styles.lightThemeProfitValue } > - {isLost ? `-$${-value}` : `+$${value}`} + {isLost ? `-$${-value}` : isProfit ? `+$${value}` : null} = ({ value, percentage, isDarkTheme = false }) => { : styles.lightThemeProfitPercentage } > - {!isLost && '+'} - {percentage}% + {isLost ? `${percentage}%` : isProfit ? `+${percentage}%` : null} From f02ae39b2503023c637fe1ae7a0ffa932768e1c9 Mon Sep 17 00:00:00 2001 From: Dat Nguyen Date: Tue, 13 Aug 2024 01:18:43 +0700 Subject: [PATCH 21/27] feat: revise pnl colors based on figma styles --- apps/wallet/src/components/TotalPnL.tsx | 82 +++++++------------------ 1 file changed, 21 insertions(+), 61 deletions(-) diff --git a/apps/wallet/src/components/TotalPnL.tsx b/apps/wallet/src/components/TotalPnL.tsx index 88c1cff88..1e0d02a23 100644 --- a/apps/wallet/src/components/TotalPnL.tsx +++ b/apps/wallet/src/components/TotalPnL.tsx @@ -15,41 +15,23 @@ const TotalPnL: FC = ({ value, percentage, isDarkTheme = false }) => { return ( - {isLost ? `-$${-value}` : isProfit ? `+$${value}` : null} + {isLost ? `≈ -$${-value}` : isProfit ? `≈ +$${value}` : null} - + {isLost ? `${percentage}%` : isProfit ? `+${percentage}%` : null} @@ -65,49 +47,27 @@ const styles = StyleSheet.create({ alignItems: 'center', gap: 8, }, - lightThemeProfitValue: { - color: '#60C591', - fontSize: 20, - }, - darkThemeProfitValue: { + pnlTextBase: { color: '#ffffff', - fontSize: 20, }, - lightThemeLostValue: { - color: '#AE3939', + pnlValueBase: { fontSize: 20, }, - darkThemeLostValue: { - color: '#ffffff', - fontSize: 20, + darkThemePnLText: { + color: '#babdc0', }, - lightThemeProfitPercentage: { - color: '#60C591', - }, - lightThemeLostPercentage: { - color: '#AE3939', - }, - darkThemeProfitPercentage: { - color: '#ffffff', - }, - darkThemeLostPercentage: { + lightThemePnLText: { color: '#ffffff', }, - percentageContainer: { + percentageContainerBase: { borderRadius: 4, paddingVertical: 4, paddingHorizontal: 8, }, - lightThemeProfitPercentageContainer: { - backgroundColor: '#AE393933', - }, - darkThemeProfitPercentageContainer: { - backgroundColor: '#2A9960', - }, - lightThemeLostPercentageContainer: { - backgroundColor: '#AE393933', + ProfitPercentageContainer: { + backgroundColor: '#29985F', }, - darkThemeLostPercentageContainer: { - backgroundColor: '#941200', + LostPercentageContainer: { + backgroundColor: '#DB1901', }, }); From 2f50ebc8a327631fa3a19094cbda930c21403726 Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Thu, 15 Aug 2024 14:47:52 +0700 Subject: [PATCH 22/27] change default value of option filter added to true --- .../Explorer/Highlights/HighlightItem.tsx | 4 +-- .../features/Explorer/Widgets/WidgetItem.tsx | 4 +-- apps/wallet/src/features/Explorer/index.tsx | 2 +- apps/wallet/src/stacks/Dashboard/index.tsx | 2 +- apps/wallet/src/stacks/Explorer/Sidebar.tsx | 2 +- apps/wallet/src/utils/hooks/widget.ts | 31 ++++++++++--------- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/wallet/src/features/Explorer/Highlights/HighlightItem.tsx b/apps/wallet/src/features/Explorer/Highlights/HighlightItem.tsx index e19efb2de..6dd82ebad 100644 --- a/apps/wallet/src/features/Explorer/Highlights/HighlightItem.tsx +++ b/apps/wallet/src/features/Explorer/Highlights/HighlightItem.tsx @@ -16,9 +16,7 @@ interface HighlightItemProps { } const HighlightItem: FC = ({ widget }) => { - const addedWidgets = useWidgets({ filterAdded: true }).map( - (widget) => widget._id, - ); + const addedWidgets = useWidgets().map((widget) => widget._id); const coverImgResource = runtime.isMobile ? assets.widget[widget._id]?.storeMeta.coverUri diff --git a/apps/wallet/src/features/Explorer/Widgets/WidgetItem.tsx b/apps/wallet/src/features/Explorer/Widgets/WidgetItem.tsx index a42130aa4..d4125e9c5 100644 --- a/apps/wallet/src/features/Explorer/Widgets/WidgetItem.tsx +++ b/apps/wallet/src/features/Explorer/Widgets/WidgetItem.tsx @@ -18,9 +18,7 @@ const WidgetItem: FC = ({ widget }) => { ? assets.widget[widget._id]?.storeMeta.coverUri : { uri: widget.storeMeta.coverUri }; - const addedWidgets = useWidgets({ filterAdded: true }).map( - (widget) => widget._id, - ); + const addedWidgets = useWidgets().map((widget) => widget._id); const isAdded = addedWidgets.includes(widget._id); const handleOpenWidget = (id: string) => { diff --git a/apps/wallet/src/features/Explorer/index.tsx b/apps/wallet/src/features/Explorer/index.tsx index 9d9cc2c0b..60747d9d3 100644 --- a/apps/wallet/src/features/Explorer/index.tsx +++ b/apps/wallet/src/features/Explorer/index.tsx @@ -23,7 +23,7 @@ interface Props { export const ExplorerFeature: FC = ({ style }) => { const { tokens } = useTokens(); const { nfts } = useNfts(); - const widgets = useWidgets({}); + const widgets = useWidgets({ filterAdded: false }); const filteredWidgets = useMemo( () => diff --git a/apps/wallet/src/stacks/Dashboard/index.tsx b/apps/wallet/src/stacks/Dashboard/index.tsx index 475b07731..bf61ff7f1 100644 --- a/apps/wallet/src/stacks/Dashboard/index.tsx +++ b/apps/wallet/src/stacks/Dashboard/index.tsx @@ -26,7 +26,7 @@ const Tab = createBottomTabNavigator(); export const DashboardStack = () => { useNotificationPermissionRequest(); const { showFirstTimePopup: showPopup } = useSnapshot(appState); - const widgets = useWidgets({ filterAdded: true }); + const widgets = useWidgets(); useEffect(() => { const alreadyHavePixeverse = widgets.some( diff --git a/apps/wallet/src/stacks/Explorer/Sidebar.tsx b/apps/wallet/src/stacks/Explorer/Sidebar.tsx index cf64ffa24..8d08d32c4 100644 --- a/apps/wallet/src/stacks/Explorer/Sidebar.tsx +++ b/apps/wallet/src/stacks/Explorer/Sidebar.tsx @@ -16,7 +16,7 @@ export const sidebarWidth = 64; export const Sidebar: FC = ({ state }) => { const drawerStatus = useDrawerStatus(); const { profile } = useSnapshot(appState); - const widgets = useWidgets({ filterAdded: true }); + const widgets = useWidgets(); useEffect(() => { runtimeActions.toggleDrawer(drawerStatus === 'open'); diff --git a/apps/wallet/src/utils/hooks/widget.ts b/apps/wallet/src/utils/hooks/widget.ts index 70f77a05a..1a2f65419 100644 --- a/apps/wallet/src/utils/hooks/widget.ts +++ b/apps/wallet/src/utils/hooks/widget.ts @@ -11,26 +11,29 @@ interface Options { filterAdded?: boolean; } -export const useWidgets = ({ filterAdded }: Options) => { +export const useWidgets = (option?: Options) => { const { map } = useSnapshot(widgetState); const { remoteConfig } = useSnapshot(appState); return useMemo(() => { - if (filterAdded) { - const widgets = Array.from(map.values()); - return sortBy(widgets, 'timestamp'); - } + if (option) { + const { filterAdded } = option; + if (!filterAdded) { + const widgets = mockWidgets.map((widget) => { + if (widget.category === WidgetSubcategories.CUSTOM_WALLET) { + widget.metadata = remoteConfig.customWallets?.[ + widget._id + ] as CustomWalletMetadata; + } - const widgets = mockWidgets.map((widget) => { - if (widget.category === WidgetSubcategories.CUSTOM_WALLET) { - widget.metadata = remoteConfig.customWallets?.[ - widget._id - ] as CustomWalletMetadata; - } + return widget; + }); - return widget; - }); + return widgets; + } + } - return widgets; + const widgets = Array.from(map.values()); + return sortBy(widgets, 'timestamp'); }, [map]); }; From 12c0f060a3f8909caddf388d780d306164526b8e Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Thu, 15 Aug 2024 14:49:26 +0700 Subject: [PATCH 23/27] get remote config of custom wallets on firebase --- apps/wallet/src/state/bootstrap.ts | 2 +- apps/wallet/src/utils/firebase/index.web.ts | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/wallet/src/state/bootstrap.ts b/apps/wallet/src/state/bootstrap.ts index 1f04dbd18..d57434b7b 100644 --- a/apps/wallet/src/state/bootstrap.ts +++ b/apps/wallet/src/state/bootstrap.ts @@ -45,7 +45,7 @@ import { widgetState } from './widget'; export const bootstrap = async (): Promise => { const startTime = new Date(); - appState.remoteConfig = loadRemoteConfig(); + appState.remoteConfig = await loadRemoteConfig(); await configure(storage); await migrateDatabase(storage, 'app', appMigrations).then(async () => { diff --git a/apps/wallet/src/utils/firebase/index.web.ts b/apps/wallet/src/utils/firebase/index.web.ts index 690f49650..548b2ad67 100644 --- a/apps/wallet/src/utils/firebase/index.web.ts +++ b/apps/wallet/src/utils/firebase/index.web.ts @@ -1,11 +1,10 @@ import { getAnalytics, logEvent } from '@firebase/analytics'; import { - activate, - fetchConfig, + fetchAndActivate, getAll, getRemoteConfig, } from '@firebase/remote-config'; -import type { RemoteConfig } from '@walless/core'; +import type { CustomWalletMetadata, RemoteConfig } from '@walless/core'; import { defaultRemoteConfig } from 'utils/constants'; import { app } from './index.ext'; @@ -18,15 +17,21 @@ export const remoteConfig = getRemoteConfig(app); remoteConfig.settings.minimumFetchIntervalMillis = __DEV__ ? 10000 : 3600000; remoteConfig.defaultConfig = defaultRemoteConfig as never; -export const loadRemoteConfig = (): RemoteConfig => { - activate(remoteConfig); - fetchConfig(remoteConfig); +export const loadRemoteConfig = async (): Promise => { + await fetchAndActivate(remoteConfig); const allConfig = getAll(remoteConfig); + const customWalletsString = allConfig.customWallets?.asString(); + const customWallets = JSON.parse(customWalletsString) as Record< + string, + CustomWalletMetadata + >; + return { experimentalEnabled: allConfig.experimentalEnabled?.asBoolean(), deepAnalyticsEnabled: allConfig.deepAnalyticsEnabled?.asBoolean(), minimalVersion: allConfig.minimalVersion?.asString() || '1.0.0', + customWallets: customWallets, }; }; From a34aeefe864cc4f6bac68972767a17c610c96cda Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Thu, 15 Aug 2024 16:47:07 +0700 Subject: [PATCH 24/27] add whitelist for custom wallet --- apps/wallet/src/state/bootstrap.ts | 1 + apps/wallet/src/utils/constants.ts | 1 + apps/wallet/src/utils/widget.ts | 13 ++++++++++++- packages/core/utils/widget.ts | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/wallet/src/state/bootstrap.ts b/apps/wallet/src/state/bootstrap.ts index d57434b7b..7ae45b217 100644 --- a/apps/wallet/src/state/bootstrap.ts +++ b/apps/wallet/src/state/bootstrap.ts @@ -46,6 +46,7 @@ import { widgetState } from './widget'; export const bootstrap = async (): Promise => { const startTime = new Date(); appState.remoteConfig = await loadRemoteConfig(); + console.log(appState.remoteConfig); await configure(storage); await migrateDatabase(storage, 'app', appMigrations).then(async () => { diff --git a/apps/wallet/src/utils/constants.ts b/apps/wallet/src/utils/constants.ts index db2f33fb5..b2e45cd4e 100644 --- a/apps/wallet/src/utils/constants.ts +++ b/apps/wallet/src/utils/constants.ts @@ -76,6 +76,7 @@ export const defaultRemoteConfig: RemoteConfig = { '98fe506a37c46d67b7212ec689decd6fcd7137ea751fb88d9c7fe89c60c5215f', }, }, + whitelist: ['thongqtran2@gmail.com'], }, }, }; diff --git a/apps/wallet/src/utils/widget.ts b/apps/wallet/src/utils/widget.ts index 3e9148d13..316962623 100644 --- a/apps/wallet/src/utils/widget.ts +++ b/apps/wallet/src/utils/widget.ts @@ -9,6 +9,8 @@ import { nftState, tokenState } from 'state/assets'; export type WidgetFilter = (widget: WidgetDocument) => boolean; +import { appState } from 'state/app'; + import { solMint, SUI_COIN_TYPE, wrappedSolMint } from './constants'; const getTokenAddress = (token: TokenDocument) => { @@ -131,6 +133,11 @@ export const filterByOwnedNfts = (widget: WidgetDocument) => { return filteredNfts; }; +export const explorerFilterByUserWhitelist = (widget: WidgetDocument) => { + const whitelist = (widget.metadata as CustomWalletMetadata).whitelist; + return whitelist.includes(appState.profile.email || ''); +}; + export const explorerFilterByOwnedNfts = (widget: WidgetDocument) => { return filterByOwnedNfts(widget).length > 0; }; @@ -144,5 +151,9 @@ const getSolanaMintAddress = (mint: string) => { }; export const filterMap: Record = { - samo: [explorerFilterByTokenBalances, explorerFilterByOwnedNfts], + samo: [ + explorerFilterByTokenBalances, + explorerFilterByOwnedNfts, + explorerFilterByUserWhitelist, + ], }; diff --git a/packages/core/utils/widget.ts b/packages/core/utils/widget.ts index 86342a0e7..26bef5426 100644 --- a/packages/core/utils/widget.ts +++ b/packages/core/utils/widget.ts @@ -47,6 +47,7 @@ export interface CustomWalletMetadata { tokens?: Record; nfts?: Record; network: Networks; + whitelist: string[]; } export enum WidgetCategories { From bc884cd2b8a70333ef71c9c4062e6a3545932465 Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Thu, 15 Aug 2024 16:48:04 +0700 Subject: [PATCH 25/27] fix: remove redundant log --- apps/wallet/src/state/bootstrap.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/wallet/src/state/bootstrap.ts b/apps/wallet/src/state/bootstrap.ts index 7ae45b217..d57434b7b 100644 --- a/apps/wallet/src/state/bootstrap.ts +++ b/apps/wallet/src/state/bootstrap.ts @@ -46,7 +46,6 @@ import { widgetState } from './widget'; export const bootstrap = async (): Promise => { const startTime = new Date(); appState.remoteConfig = await loadRemoteConfig(); - console.log(appState.remoteConfig); await configure(storage); await migrateDatabase(storage, 'app', appMigrations).then(async () => { From 732ec79a35ab8b59e8a04446ea3d25ce673e4840 Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Thu, 15 Aug 2024 17:01:59 +0700 Subject: [PATCH 26/27] fix: change the way to get widget (from mock data to hook) --- .../src/features/Widget/CustomWalletLayout/index.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx b/apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx index 0602bea34..d49381fb7 100644 --- a/apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx +++ b/apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx @@ -21,8 +21,12 @@ import type { WidgetDocument, } from '@walless/store'; import { showCopiedModal } from 'modals/Notification'; -import { mockWidgets } from 'state/widget'; -import { getTokenValue, useOpacityAnimated, usePublicKeys } from 'utils/hooks'; +import { + getTokenValue, + useOpacityAnimated, + usePublicKeys, + useWidgets, +} from 'utils/hooks'; import { copy } from 'utils/system'; import { filterByOwnedNfts, filterByOwnedTokens } from 'utils/widget'; @@ -58,7 +62,7 @@ const convertCustomMetadataToCardSkin = ( }; export const CustomWalletLayout: FC = ({ id }) => { - const customWalletWidget = mockWidgets.find((item) => item._id === id); + const customWalletWidget = useWidgets().find((item) => item._id === id); const [activeTabIndex, setActiveTabIndex] = useState(0); const [headerLayout, setHeaderLayout] = useState(); const customWalletMetadata = @@ -66,6 +70,8 @@ export const CustomWalletLayout: FC = ({ id }) => { const network = customWalletMetadata.network; + console.log(customWalletMetadata); + const keys = usePublicKeys(network); const filteredTokens = filterByOwnedTokens( customWalletWidget as WidgetDocument, From 35f80931884fe6ae3d32ab446cf0a61ca36044a8 Mon Sep 17 00:00:00 2001 From: ltminhthu Date: Thu, 15 Aug 2024 17:03:16 +0700 Subject: [PATCH 27/27] fix: remove log debug --- apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx b/apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx index d49381fb7..496090213 100644 --- a/apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx +++ b/apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx @@ -70,8 +70,6 @@ export const CustomWalletLayout: FC = ({ id }) => { const network = customWalletMetadata.network; - console.log(customWalletMetadata); - const keys = usePublicKeys(network); const filteredTokens = filterByOwnedTokens( customWalletWidget as WidgetDocument,