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

feat: new you have (Portfolio) for Extension mode #1655

Merged
merged 33 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
479df64
style: work in progress
Nick-1979 Nov 14, 2024
03f3c2c
style: add available
Nick-1979 Nov 14, 2024
be11d21
feat: add withDecimal
Nick-1979 Nov 14, 2024
8b6309c
style: adjust logo
Nick-1979 Nov 14, 2024
c33e855
style: adjust stuff
Nick-1979 Nov 14, 2024
c2eaa3c
chore: remove unused
Nick-1979 Nov 15, 2024
1735b0d
style: adjust space
Nick-1979 Nov 15, 2024
16549ba
chore: adjust height
Nick-1979 Nov 15, 2024
3dad7ca
Merge branch 'main' into newYouHave
Nick-1979 Nov 15, 2024
dfb792f
style: adjust currency dialog
Nick-1979 Nov 16, 2024
b444aa5
style: move starts center
Nick-1979 Nov 16, 2024
81f0147
chore: add tooltip
Nick-1979 Nov 16, 2024
ebc8e45
refactor: adjust spacing
Nick-1979 Nov 16, 2024
9ed7ed6
style: increase font size
Nick-1979 Nov 16, 2024
28e609d
refactor: remove theme as props
Nick-1979 Nov 16, 2024
a4a2adf
refactor: remove unused
Nick-1979 Nov 16, 2024
3f98446
style: adjust starts placement
Nick-1979 Nov 16, 2024
e6117b0
docs: update news
Nick-1979 Nov 16, 2024
811769a
docs: update translations
Nick-1979 Nov 16, 2024
4a1f321
style: adjust portfolio bg effect
Nick-1979 Nov 16, 2024
3d738a7
style: adjust font sizes
Nick-1979 Nov 16, 2024
ed9d845
style: adjust fontSizes
Nick-1979 Nov 16, 2024
f061cf6
refactor: minor styling and refactor in menu transitions (#1657)
AMIRKHANEF Nov 16, 2024
e16eb2a
style: adjust light mode color
Nick-1979 Nov 16, 2024
6ffc4e5
style: add new green color
Nick-1979 Nov 16, 2024
ec5f133
style: reduce font size (#1658)
AMIRKHANEF Nov 16, 2024
be34cbc
style: adjust spacings
Nick-1979 Nov 16, 2024
537d208
fix: badge text color
Nick-1979 Nov 16, 2024
1499c25
fix: signal indicator border issue
Nick-1979 Nov 16, 2024
b48da3d
chore: minor adjustments
Nick-1979 Nov 16, 2024
f017e4b
chore: remove unused
Nick-1979 Nov 16, 2024
24100db
style: adjust titles
Nick-1979 Nov 16, 2024
05c88fc
style: make extension profile tabs smoother
Nick-1979 Nov 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions packages/extension-polkagate/src/components/FormatPrice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ export function nFormatter (num: number, decimalPoint: number) {
const DECIMAL_POINTS_FOR_CRYPTO_AS_CURRENCY = 4;
const SMALL_DECIMALS_FONT_SIZE_REDUCTION = 20;

const DecimalPart = ({ value, withCountUp }: { value: string | number, withCountUp: boolean | undefined }) => (
withCountUp
? <CountUp
duration={1}
end={Number(getDecimal(value))}
prefix={'.'}
/>
: <>{`.${getDecimal(value)}`}</>
);

function FormatPrice ({ amount, commify, decimalPoint = 2, decimals, fontSize, fontWeight, height, lineHeight = 1, mt = '0px', num, price, sign, skeletonHeight = 15, textAlign = 'left', textColor, width = '90px', withCountUp, withSmallDecimal }: Props): React.ReactElement<Props> {
const currency = useCurrency();
const theme = useTheme();
Expand Down Expand Up @@ -135,16 +145,10 @@ function FormatPrice ({ amount, commify, decimalPoint = 2, decimals, fontSize, f
lineHeight={lineHeight}
sx={{ color: theme.palette.secondary.contrastText }}
>
{withCountUp
? <CountUp
duration={1}
end={Number(getDecimal(total))}
prefix={'.'}
/>
: <>
{`.${getDecimal(total)}`}
</>
}
<DecimalPart
value={total}
withCountUp={withCountUp}
/>
</Typography>
}
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@ export interface CurrencyItemType {
sign: string;
}

export default function Currency (): React.ReactElement {
interface Props {
color?: string;
dialogLeft?: number;
fontSize?: string;
height?: string;
minWidth?: string;
}

export default function Currency ({ color, fontSize = '22px', height, minWidth, dialogLeft=260 }: Props): React.ReactElement {
// export default function Currency ({ color, fontSize = '22px' }: Props): React.ReactElement {
const theme = useTheme();

const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const [currencyToShow, setCurrencyToShow] = useState<CurrencyItemType | undefined>();

const textColor = useMemo(() => theme.palette.mode === 'dark' ? theme.palette.text.primary : theme.palette.text.secondary, [theme.palette.mode, theme.palette.text.primary, theme.palette.text.secondary]);
const textColor = useMemo(() => color || (theme.palette.mode === 'dark' ? theme.palette.text.primary : theme.palette.text.secondary), [color, theme]);

useLayoutEffect(() => {
if (currencyToShow) {
Expand All @@ -46,9 +55,17 @@ export default function Currency (): React.ReactElement {

return (
<>
<Grid alignItems='center' component='button' container direction='column' item justifyContent='center' onClick={onCurrencyClick} sx={{ ...HEADER_COMPONENT_STYLE, zIndex: anchorEl && theme.zIndex.modal + 1 }}>
<Grid
alignItems='center' component='button' container direction='column' item justifyContent='center' onClick={onCurrencyClick}
sx={{
...HEADER_COMPONENT_STYLE,
height: height || HEADER_COMPONENT_STYLE?.height,
minWidth: minWidth || HEADER_COMPONENT_STYLE?.minWidth,
zIndex: anchorEl && theme.zIndex.modal + 1
}}
>
<Infotip2 text={currencyToShow?.currency}>
<Typography color={textColor} fontSize='22px' fontWeight={500}>
<Typography color={textColor} fontSize={ fontSize } fontWeight={500}>
{currencyToShow?.sign || '$'}
</Typography>
</Infotip2>
Expand All @@ -62,7 +79,7 @@ export default function Currency (): React.ReactElement {
boxShadow: theme.palette.mode === 'dark'
? '0px 4px 4px rgba(255, 255, 255, 0.25)'
: '0px 0px 25px 0px rgba(0, 0, 0, 0.50)',
left: anchorEl?.getBoundingClientRect().right - 260,
left: anchorEl?.getBoundingClientRect().right - dialogLeft,
position: 'absolute',
top: anchorEl?.getBoundingClientRect().bottom - 30
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
}
Expand Down
14 changes: 9 additions & 5 deletions packages/extension-polkagate/src/hooks/useYouHave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { amountToHuman } from '../util/utils';
import { usePrices } from '.';

export interface YouHaveType {
available: number;
change: number;
date: number;
portfolio: number;
Expand Down Expand Up @@ -45,8 +46,9 @@ export default function useYouHave (): YouHaveType | undefined | null {
return undefined;
}

let totalPrice = 0;
let totalBeforeChange = 0;
let portfolio = 0;
let available = 0;
let change = 0;
const balances = accountsAssets.balances;
const date = Math.min(accountsAssets.timeStamp, pricesInCurrencies.date);

Expand All @@ -56,14 +58,16 @@ export default function useYouHave (): YouHaveType | undefined | null {
const tokenValue = pricesInCurrencies.prices[asset.priceId]?.value ?? 0;
const tokenPriceChange = pricesInCurrencies.prices[asset.priceId]?.change ?? 0;
const currentAssetPrice = calcPrice(tokenValue, asset.totalBalance, asset.decimal);
const currentAvailableAssetPrice = calcPrice(tokenValue, asset.availableBalance, asset.decimal);

totalPrice += currentAssetPrice;
totalBeforeChange += calcChange(tokenValue, Number(asset.totalBalance) / (10 ** asset.decimal), tokenPriceChange);
portfolio += currentAssetPrice;
available += currentAvailableAssetPrice;
change += calcChange(tokenValue, Number(asset.totalBalance) / (10 ** asset.decimal), tokenPriceChange);
});
});
});

return { change: totalBeforeChange, date, portfolio: totalPrice } as unknown as YouHaveType;
return { available, change, date, portfolio } as unknown as YouHaveType;
}, [accountsAssets, pricesInCurrencies]);

return youHave;
Expand Down
22 changes: 10 additions & 12 deletions packages/extension-polkagate/src/partials/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@

/* eslint-disable react/jsx-max-props-per-line */

import type { Theme } from '@mui/material/styles';

import { Close as CloseIcon } from '@mui/icons-material';
import { Divider, Grid, IconButton, Typography } from '@mui/material';
import { keyframes } from '@mui/material/styles';
import { keyframes, useTheme } from '@mui/material/styles';
import React, { useCallback, useContext, useState } from 'react';

import { AccountContext, ActionContext, MenuItem, TwoButtons, VaadinIcon, Warning } from '../components';
Expand All @@ -21,24 +19,24 @@ import SettingSubMenu from './SettingSubMenu';
import VersionSocial from './VersionSocial';

interface Props {
theme: Theme;
setShowMenu: React.Dispatch<React.SetStateAction<boolean>>;
}

const COLLAPSIBLE_MENUS = {
NONE: 0,
NEW_ACCOUNT: 1,
IMPORT_ACCOUNT: 2,
SETTING: 3
};
const enum COLLAPSIBLE_MENUS {
NONE,
NEW_ACCOUNT,
IMPORT_ACCOUNT,
SETTING
}
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved

const Div = () => <Divider sx={{ bgcolor: 'divider', height: '1px', justifySelf: 'flex-end', mx: '10px', width: '83%' }} />;

function Menu ({ setShowMenu, theme }: Props): React.ReactElement<Props> {
function Menu ({ setShowMenu }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const theme = useTheme();
const onAction = useContext(ActionContext);

const [collapsedMenu, setCollapsedMenu] = useState<number>(COLLAPSIBLE_MENUS.SETTING);
const [collapsedMenu, setCollapsedMenu] = useState(COLLAPSIBLE_MENUS.SETTING);
const [isTestnetEnableConfirmed, setIsTestnetEnableConfirmed] = useState<boolean>();
const [showWarning, setShowWarning] = useState<boolean>();
const [closeMenu, setCloseMenu] = useState<boolean>(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export default function SettingSubMenu ({ isTestnetEnabledChecked, onChange, set
<IconButton
sx={{ height: '35px', p: 0, width: '35px' }}
>
<ThemeChanger color= 'secondary.light' left='4px' noBorder />
<ThemeChanger color= 'secondary.light' noBorder />
</IconButton>
</Infotip2>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export default function AiBackgroundImage ({ bgImage, setBgImage }: Props): Reac
<Grid alignItems='baseline' container item justifyContent='flex-end' xs>
<Grid item onClick={onAiBackground}>
<Infotip2 showInfoMark text={t('Click to set an AI-generated background.')}>
<Typography sx={{ cursor: 'pointer', fontSize: '11px', pl: '5px', textDecoration: 'underline', userSelect: 'none' }}>
<Typography sx={{ color: 'secondary.contrastText', cursor: 'pointer', fontSize: '11px', pl: '5px', textDecoration: 'underline', userSelect: 'none' }}>
{t('AI Background')}
</Typography>
</Infotip2>
Expand Down
5 changes: 3 additions & 2 deletions packages/extension-polkagate/src/popup/home/ProfileTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,12 @@ function ProfileTab ({ index, isContainerHovered, isSelected, orderedAccounts, t
}}
>
<Grid alignItems='center' container item justifyContent='center' sx={{ display: 'flex', flexDirection: 'row', flexWrap: 'nowrap', minWidth: '40px', px: '8px', width: 'fit-content' }}>
<Typography color='text.primary' fontSize='14px' fontWeight={400} sx={{ lineHeight: 'normal', maxWidth: '100px', overflowX: 'hidden', textOverflow: 'ellipsis', transition: 'visibility 0.1s ease', userSelect: 'none', visibility: visibleContent ? 'visible' : 'hidden', whiteSpace: 'nowrap', width: 'fit-content' }} textAlign='center'>
<Typography color='text.primary' fontSize='14px' sx={{ lineHeight: 'normal', maxWidth: '100px', overflowX: 'hidden', textOverflow: 'ellipsis', transition: 'visibility 0.1s ease', userSelect: 'none', visibility: visibleContent ? 'visible' : 'hidden', whiteSpace: 'nowrap', width: 'fit-content' }} textAlign='center'>
{t(text)}
</Typography>
{areAllHidden && isSelected &&
<VaadinIcon icon='vaadin:eye-slash' style={{ display: 'block', height: '13px', marginLeft: '5px', width: '15px' }} />}
<VaadinIcon icon='vaadin:eye-slash' style={{ display: 'block', height: '13px', marginLeft: '5px', width: '15px' }} />
}
</Grid>
</Collapse>
</Grid>
Expand Down
149 changes: 117 additions & 32 deletions packages/extension-polkagate/src/popup/home/YouHave.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@

import type { YouHaveType } from '../../hooks/useYouHave';

import { Box, Grid, Typography, useTheme } from '@mui/material';
import React from 'react';
import { MoreVert as MoreVertIcon } from '@mui/icons-material';
import { Box, Grid, IconButton, Stack, Typography, useTheme } from '@mui/material';
import React, { useCallback, useMemo, useState } from 'react';
import CountUp from 'react-countup';

import { stars6Black, stars6White } from '../../assets/icons';
import { FormatPrice } from '../../components';
import { stars5Black, stars5White } from '../../assets/icons';
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
import { logoBlack, logoWhite } from '../../assets/logos';
import { FormatPrice, Infotip2 } from '../../components';
import HideBalance from '../../components/SVG/HideBalance';
import { useIsHideNumbers, useYouHave } from '../../hooks';
import Currency from '../../fullscreen/homeFullScreen/partials/Currency';
import { changeSign, PORTFOLIO_CHANGE_DECIMAL } from '../../fullscreen/homeFullScreen/partials/TotalBalancePieChart';
import { useCurrency, useIsHideNumbers, useYouHave } from '../../hooks';
import { PRICE_VALIDITY_PERIOD } from '../../hooks/usePrices';
import useTranslation from '../../hooks/useTranslation';
import Menu from '../../partials/Menu';
import { COIN_GECKO_PRICE_CHANGE_DURATION } from '../../util/api/getPrices';
import { countDecimalPlaces, fixFloatingPoint } from '../../util/utils';

export const isPriceOutdated = (youHave: YouHaveType | null | undefined): boolean | undefined =>
youHave ? (Date.now() - youHave.date > 2 * PRICE_VALIDITY_PERIOD) : undefined;
Expand All @@ -22,43 +30,120 @@ export default function YouHave (): React.ReactElement {
const { t } = useTranslation();
const theme = useTheme();
const youHave = useYouHave();
const currency = useCurrency();

const isDark = theme.palette.mode === 'dark';

const { isHideNumbers, toggleHideNumbers } = useIsHideNumbers();
const [isMenuOpen, setOpenMenu] = useState(false);

const portfolioChange = useMemo(() => {
if (!youHave?.change) {
return 0;
}

const value = fixFloatingPoint(youHave.change, PORTFOLIO_CHANGE_DECIMAL, false, true);

return parseFloat(value);
}, [youHave?.change]);

const onMenuClick = useCallback(() => {
setOpenMenu((open) => !open);
}, []);

return (
<Grid container sx={{ pb: '10px', position: 'relative', pt: '5px', textAlign: 'center', zIndex: 1 }}>
<Grid item xs={12}>
<Typography sx={{ fontSize: '16px', fontVariant: 'small-caps' }}>
{t('My Portfolio')}
</Typography>
</Grid>
<Grid container item justifyContent='center' xs={12}>
{isHideNumbers
? <Box
component='img'
src={(theme.palette.mode === 'dark' ? stars6White : stars6Black) as string}
sx={{ height: '36px', width: '154px' }}
/>
: <FormatPrice
fontSize='32px'
fontWeight={500}
height={36}
num={youHave?.portfolio }
skeletonHeight={36}
textColor= { isPriceOutdated(youHave) ? 'primary.light' : 'text.primary'}
width='223px'
withCountUp
withSmallDecimal
/>
}
<Grid alignItems='center' item sx={{ position: 'absolute', right: '14px', top: '25px' }}>
<Grid alignItems='flex-start' container sx={{ bgcolor: 'background.paper', borderRadius: '10px', minHeight: '125px', m: '20px 4% 10px', width: '100%', boxShadow: isDark ? '3px 2px 15px rgba(255, 255, 255, 0.25)' : '2px 3px 4px 2px rgba(0, 0, 0, 0.10)' }}>
<Grid container sx={{ position: 'relative', px: '10px', py: '5px' }}>
<Grid container item sx={{ textAlign: 'left' }}>
<Typography sx={{ fontSize: '16px', fontVariant: 'small-caps', fontWeight: 400, mt: '10px' }}>
{t('My Portfolio')}
</Typography>
</Grid>
<Grid container item justifyContent='flex-start' pt='15px'>
{isHideNumbers
? <Box
component='img'
src={(theme.palette.mode === 'dark' ? stars5White : stars5Black) as string}
sx={{ height: '20px', width: '317px' }}
/>
: <>
<Stack alignItems='center' direction='row' justifyContent='space-between' sx={{ flexWrap: 'wrap', mr: '15px', textAlign: 'start', width: '100%' }}>
<Stack alignItems='flex-start' direction='row' sx= {{ ml: '-5px' }}>
<Currency
color='secondary.light'
dialogLeft ={64}
fontSize='25px'
height='27px'
minWidth='27px'
/>
<FormatPrice
fontSize='28px'
fontWeight={500}
num={youHave?.portfolio}
sign= ' '
skeletonHeight={28}
textColor={isPriceOutdated(youHave) ? 'primary.light' : 'text.primary'}
width='100px'
withCountUp
withSmallDecimal
/>
</Stack>
<Typography sx={{ color: !youHave?.change ? 'secondary.contrastText' : youHave.change > 0 ? 'success.main' : 'warning.main', fontSize: '15px', fontWeight: 400 }}>
<CountUp
decimals={countDecimalPlaces(portfolioChange) || PORTFOLIO_CHANGE_DECIMAL}
duration={1}
end={portfolioChange}
prefix={`${changeSign(youHave?.change)}${currency?.sign}`}
suffix={`(${COIN_GECKO_PRICE_CHANGE_DURATION}h)`}
/>
</Typography>
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
</Stack>
<Stack alignItems='center' direction='row' spacing={1} sx={{ ml: '5px', mt: '5px', textAlign: 'start', width: '100%' }}>
<FormatPrice
fontSize='14px'
fontWeight={400}
num={youHave?.available}
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
skeletonHeight={14}
textColor={ 'primary.light' }
width='100px'
withCountUp
/>
<Typography sx={{ color: 'primary.light', fontSize: '14px', fontWeight: 400 }}>
{t('available')}
</Typography>
</Stack>
</>
}
<Infotip2 text={t('Menu options')}>
<IconButton
onClick={onMenuClick}
sx={{ p: 0, position: 'absolute', pt: '3px', right: '3px', top: '8px' }}
>
<MoreVertIcon sx={{ color: 'secondary.light', fontSize: '33px' }} />
</IconButton>
</Infotip2>
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
</Grid>
<Grid item sx={{ position: 'absolute', right: '30px', top: '5px' }}>
<HideBalance
darkColor={theme.palette.secondary.light}
hide={isHideNumbers}
lightColor={theme.palette.secondary.light}
onClick={toggleHideNumbers}
size={22}
size={20}
/>
</Grid>
</Grid>
<Box
alt={t('PolkaGate logo')}
component='img'
src={theme.palette.mode === 'dark' ? logoBlack as string : logoWhite as string}
sx={{ filter: 'drop-shadow(1px 1px 1px rgba(0, 0, 0, 0.5))', height: 40, left: 'calc(50% - 20px)', position: 'absolute', top: '5px', width: 40 }}
/>
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
{isMenuOpen &&
<Menu
setShowMenu={setOpenMenu}
/>
}
Nick-1979 marked this conversation as resolved.
Show resolved Hide resolved
</Grid>
);
}
Loading
Loading