Skip to content
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

[wallet] feat: using custom wallet data from remote config #609

Merged
merged 8 commits into from
Aug 15, 2024
Merged
12 changes: 6 additions & 6 deletions apps/wallet/src/features/Explorer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -24,10 +23,11 @@ interface Props {
export const ExplorerFeature: FC<Props> = ({ style }) => {
const { tokens } = useTokens();
const { nfts } = useNfts();
const widgets = useWidgets({ filterAdded: false });

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));
Expand All @@ -44,8 +44,8 @@ export const ExplorerFeature: FC<Props> = ({ style }) => {
<ScrollView showsVerticalScrollIndicator={false}>
<LoyaltyBar style={styles.loyaltyContainer} />
<Missions style={styles.missionContainer} />
<Highlights widgets={widgets} />
<Widgets widgets={widgets} />
<Highlights widgets={filteredWidgets} />
<Widgets widgets={filteredWidgets} />
</ScrollView>
</View>
);
Expand Down
10 changes: 7 additions & 3 deletions apps/wallet/src/features/Widget/CustomWalletLayout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -58,7 +62,7 @@ const convertCustomMetadataToCardSkin = (
};

export const CustomWalletLayout: FC<Props> = ({ 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<LayoutRectangle>();
const customWalletMetadata =
Expand Down
2 changes: 1 addition & 1 deletion apps/wallet/src/state/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import { widgetState } from './widget';

export const bootstrap = async (): Promise<void> => {
const startTime = new Date();
appState.remoteConfig = loadRemoteConfig();
appState.remoteConfig = await loadRemoteConfig();

await configure(storage);
await migrateDatabase(storage, 'app', appMigrations).then(async () => {
Expand Down
70 changes: 0 additions & 70 deletions apps/wallet/src/state/widget/shared.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import type { CustomWalletAssets } from '@walless/core';
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
Expand Down Expand Up @@ -224,73 +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',
},
],
tokens: new Map<string, CustomWalletAssets>([
[
'7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',
{
mintAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',
amount: 50000,
},
],
[
'So11111111111111111111111111111111111111112',
{
mintAddress: 'So11111111111111111111111111111111111111112',
},
],
]),
nfts: new Map<string, CustomWalletAssets>([
[
'98fe506a37c46d67b7212ec689decd6fcd7137ea751fb88d9c7fe89c60c5215f',
{
mintAddress:
'98fe506a37c46d67b7212ec689decd6fcd7137ea751fb88d9c7fe89c60c5215f',
},
],
]),
network: Networks.solana,
},
},
];
64 changes: 64 additions & 0 deletions apps/wallet/src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -15,6 +17,68 @@ export const defaultRemoteConfig: RemoteConfig = {
experimentalEnabled: true,
deepAnalyticsEnabled: true,
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',
amount: 50000,
},
So11111111111111111111111111111111111111112: {
mintAddress: 'So11111111111111111111111111111111111111112',
},
},
nfts: {
'98fe506a37c46d67b7212ec689decd6fcd7137ea751fb88d9c7fe89c60c5215f': {
mintAddress:
'98fe506a37c46d67b7212ec689decd6fcd7137ea751fb88d9c7fe89c60c5215f',
},
},
whitelist: ['[email protected]'],
},
},
};

/**
Expand Down
17 changes: 11 additions & 6 deletions apps/wallet/src/utils/firebase/index.web.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<RemoteConfig> => {
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,
};
};

Expand Down
29 changes: 27 additions & 2 deletions apps/wallet/src/utils/hooks/widget.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
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 = (option?: Options) => {
const { map } = useSnapshot(widgetState);
const { remoteConfig } = useSnapshot(appState);

return useMemo(() => {
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;
}

return widget;
});

return widgets;
}
}

const widgets = Array.from(map.values());
return sortBy(widgets, 'timestamp');
}, [map]);
Expand Down
19 changes: 15 additions & 4 deletions apps/wallet/src/utils/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -93,7 +95,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;
Expand All @@ -105,7 +107,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 &&
Expand All @@ -125,12 +127,17 @@ 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;
};

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;
};
Expand All @@ -144,5 +151,9 @@ const getSolanaMintAddress = (mint: string) => {
};

export const filterMap: Record<string, WidgetFilter[]> = {
samo: [explorerFilterByTokenBalances, explorerFilterByOwnedNfts],
samo: [
explorerFilterByTokenBalances,
explorerFilterByOwnedNfts,
explorerFilterByUserWhitelist,
],
};
2 changes: 2 additions & 0 deletions packages/core/utils/entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { NetworkCluster, Networks } from './common';
import type { CustomWalletMetadata } from './widget';

export interface AptosTokenMetadata {
creatorAddress: string;
Expand Down Expand Up @@ -35,6 +36,7 @@ export interface RemoteConfig {
experimentalEnabled: boolean;
deepAnalyticsEnabled: boolean;
minimalVersion: string;
customWallets?: Record<string, CustomWalletMetadata>;
}

export interface UserProfile {
Expand Down
5 changes: 3 additions & 2 deletions packages/core/utils/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ export interface CustomWalletMetadata {
};
activeTabStyle?: TabItemStyle;
advertisements: CustomWalletAdvertisement[];
tokens?: Map<string, CustomWalletAssets>;
nfts?: Map<string, CustomWalletAssets>;
tokens?: Record<string, CustomWalletAssets>;
nfts?: Record<string, CustomWalletAssets>;
network: Networks;
whitelist: string[];
}

export enum WidgetCategories {
Expand Down
Loading