Skip to content

Commit

Permalink
Merge branch 'dev' of https://github.com/cocrafts/walless into loyalty
Browse files Browse the repository at this point in the history
  • Loading branch information
halv1s committed Aug 31, 2024
2 parents 7ea0105 + fdc772d commit b79408d
Show file tree
Hide file tree
Showing 26 changed files with 2,506 additions and 1,410 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,5 @@ cli/tokens/**/cache.json
cli/tokens/**/config.json
cli/tokens/**/sugar.log

playground
playground
.nvmrc
30 changes: 28 additions & 2 deletions apps/wallet/src/components/TokenList/Item.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -10,22 +11,33 @@ interface Props {
style?: StyleProp<ViewStyle>;
token: TokenDocument;
onPress?: () => void;
tokenPnL?: TokenPnL;
}

export const TokenItem: FC<Props> = ({ style, token, onPress }) => {
export const TokenItem: FC<Props> = ({ style, token, onPress, tokenPnL }) => {
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 = fixedPnL < 0;
const isProfit = fixedPnL > 0;

return (
<Hoverable style={[styles.container, style]} onPress={onPress}>
<Image style={styles.iconImg} source={iconSource} resizeMode="cover" />
<View style={styles.infoContainer}>
<Text style={styles.primaryText}>{itemName}</Text>
<Text style={styles.secondaryText}>{formatQuote(unitQuote)}</Text>
<View style={styles.unitQuoteContainer}>
<Text style={styles.secondaryText}>{formatQuote(unitQuote)}</Text>
<Text style={isLost ? styles.lostText : styles.profitText}>
{isLost ? `-${-fixedPnL}` : isProfit ? `+${fixedPnL}` : null}
</Text>
</View>
</View>
<View style={styles.balanceContainer}>
<Text style={styles.primaryText}>{balance}</Text>
Expand Down Expand Up @@ -75,4 +87,18 @@ const styles = StyleSheet.create({
color: '#566674',
fontSize: 13,
},
unitQuoteContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
profitText: {
color: '#60C591',
fontSize: 10,
alignSelf: 'flex-end',
},
lostText: {
color: '#AE3939',
fontSize: 10,
},
});
1 change: 1 addition & 0 deletions apps/wallet/src/components/TokenList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const TokenList = <T extends Token>({
index === tokens.length - 1 && styles.lastItem,
]}
onPress={handlePressItem}
tokenPnL={item.pnl}
/>
);
};
Expand Down
73 changes: 73 additions & 0 deletions apps/wallet/src/components/TotalPnL.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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<Props> = ({ value, percentage, isDarkTheme = false }) => {
const isLost = value < 0;
const isProfit = value > 0;

return (
<View style={styles.container}>
<Text
style={[
styles.pnlTextBase,
styles.pnlValueBase,
isDarkTheme ? styles.darkThemePnLText : styles.lightThemePnLText,
]}
>
{isLost ? `≈ -$${-value}` : isProfit ? `≈ +$${value}` : null}
</Text>
<View
style={[
styles.percentageContainerBase,
isLost
? styles.LostPercentageContainer
: styles.ProfitPercentageContainer,
]}
>
<Text style={[styles.pnlTextBase]}>
{isLost ? `${percentage}%` : isProfit ? `+${percentage}%` : null}
</Text>
</View>
</View>
);
};

export default TotalPnL;

const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
pnlTextBase: {
color: '#ffffff',
},
pnlValueBase: {
fontSize: 20,
},
darkThemePnLText: {
color: '#babdc0',
},
lightThemePnLText: {
color: '#ffffff',
},
percentageContainerBase: {
borderRadius: 4,
paddingVertical: 4,
paddingHorizontal: 8,
},
ProfitPercentageContainer: {
backgroundColor: '#29985F',
},
LostPercentageContainer: {
backgroundColor: '#DB1901',
},
});
2 changes: 2 additions & 0 deletions apps/wallet/src/engine/runners/solana/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ const handleInitAccountOnLogsChange = async (
const quotes = await getTokenQuotes([
{ address: token.mint, network: token.network },
]);
token.pnl =
quotes[makeHashId({ address: token.mint, network: token.network })].pnl;
token.quotes =
quotes[
makeHashId({ address: token.mint, network: token.network })
Expand Down
12 changes: 7 additions & 5 deletions apps/wallet/src/engine/runners/solana/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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;
Expand All @@ -42,11 +43,12 @@ export const queryTokens = async (
account,
);

const quotes = await getTokenQuote({
const tokenInfo = await getTokenInfo({
address: doc.mint,
network: doc.network,
});
doc.quotes = quotes?.quotes;
doc.quotes = tokenInfo?.quotes;
doc.pnl = tokenInfo?.pnl;

await addTokenToStorage(doc);
return doc;
Expand Down
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 @@ -23,10 +22,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 @@ -42,8 +42,8 @@ export const ExplorerFeature: FC<Props> = ({ style }) => {
<Header style={styles.headerContainer} />
<ScrollView showsVerticalScrollIndicator={false}>
<Missions style={styles.missionContainer} />
<Highlights widgets={widgets} />
<Widgets widgets={widgets} />
<Highlights widgets={filteredWidgets} />
<Widgets widgets={filteredWidgets} />
</ScrollView>
</View>
);
Expand Down
43 changes: 24 additions & 19 deletions apps/wallet/src/features/Home/TokenValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,43 @@ import type { FC } from 'react';
import { StyleSheet, View } from 'react-native';
import { Hoverable, Text } from '@walless/gui';
import { Eye, EyeOff } from '@walless/icons';
import { useSettings } from 'utils/hooks';
import TotalPnL from 'components/TotalPnL';
import { useSettings, useTokens } from 'utils/hooks';

interface Props {
value: number;
}

const TokenValue: FC<Props> = ({ value }) => {
const { setting, setPrivacy } = useSettings();
const balanceTextStyle = [
styles.balanceText,
setting.hideBalance && styles.protectedBalance,
];
const { valuation, pnl } = useTokens();

const handleToggleTokenValue = async () => {
setPrivacy(!setting.hideBalance);
};
const pnlRates = (pnl / (valuation != 0 ? valuation : 1)) * 100;

return (
<View style={styles.container}>
<Text style={styles.headingText}>Token value</Text>
<View style={styles.balanceContainer}>
<Text style={balanceTextStyle}>
{setting.hideBalance ? '****' : '$' + value.toFixed(2)}
</Text>
<Hoverable onPress={handleToggleTokenValue}>
{setting.hideBalance ? (
<Eye size={20} color="#566674" />
) : (
<EyeOff size={20} color="#566674" />
)}
</Hoverable>
<View style={styles.balanceAndPercentageContainer}>
<View style={styles.balanceContainer}>
<Text style={styles.balanceText}>
{setting.hideBalance ? '****' : '$' + value.toFixed(2)}
</Text>
<Hoverable onPress={handleToggleTokenValue}>
{setting.hideBalance ? (
<Eye size={20} color="#566674" />
) : (
<EyeOff size={20} color="#566674" />
)}
</Hoverable>
</View>
<TotalPnL
value={Math.round(pnl * 100) / 100}
percentage={Math.round(pnlRates * 100) / 100}
isDarkTheme={true}
/>
</View>
</View>
);
Expand All @@ -53,14 +59,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',
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,27 @@ 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 { getValuationDisplay } from 'utils/helper';

interface Props {
onHide: (next: boolean) => void;
hideBalance: boolean;
valuation?: number;
pnl?: number;
}

export const WalletBalance: FC<Props> = ({
onHide,
hideBalance,
valuation = 0,
pnl = 0,
}) => {
const balanceTextStyle = [
styles.balanceText,
hideBalance && styles.protectedBalance,
];
const pnlRates = (pnl / (valuation != 0 ? valuation : 1)) * 100;

return (
<View style={styles.container}>
Expand All @@ -30,6 +34,13 @@ export const WalletBalance: FC<Props> = ({
{getValuationDisplay(valuation, hideBalance)}
</Text>
</View>
<View style={styles.pnLContainer}>
<TotalPnL
value={Math.round(pnl * 100) / 100}
percentage={Math.round(pnlRates * 100) / 100}
isDarkTheme={false}
/>
</View>
</View>
);
};
Expand All @@ -44,7 +55,6 @@ const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
paddingLeft: 5,
paddingBottom: 20,
gap: 10,
},
balanceText: {
Expand All @@ -60,4 +70,7 @@ const styles = StyleSheet.create({
opacity: 0.6,
marginLeft: 34,
},
pnLContainer: {
paddingLeft: 10,
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface Props {
item: PublicKeyDocument;
skin: CardSkin;
valuation?: number;
pnl?: number;
hideBalance: boolean;
onCopyAddress?: (value: string) => void;
onChangePrivateSetting?: (value: boolean) => void;
Expand All @@ -26,6 +27,7 @@ export const WalletCard: FC<Props> = ({
item,
skin,
valuation = 0,
pnl = 0,
hideBalance,
onCopyAddress,
onChangePrivateSetting,
Expand Down Expand Up @@ -58,6 +60,7 @@ export const WalletCard: FC<Props> = ({
hideBalance={hideBalance}
valuation={valuation}
onHide={handleHide}
pnl={pnl}
/>
{skin.largeIconSrc && (
<View pointerEvents="none" style={styles.markContainer}>
Expand Down
Loading

0 comments on commit b79408d

Please sign in to comment.