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

add epoch progress ui with placeholders #2585

Merged
merged 25 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f26e0b2
add epoch progress ui with placeholders
paulclindo Dec 18, 2021
f40c170
integrate epochProgress data
paulclindo Dec 20, 2021
a72e0e8
add percentage
paulclindo Dec 20, 2021
362a565
remove log
paulclindo Dec 21, 2021
68bfdad
Merge branch 'develop' into add-epoch-history
vsubhuman Jan 7, 2022
0ac1bb1
add start epoch date
paulclindo Jan 8, 2022
8a984d2
Merge branch 'develop' into add-epoch-history
vsubhuman Mar 9, 2022
5aa0168
Merge branch 'develop' of github.com:Emurgo/yoroi-frontend into add-e…
Jun 28, 2022
e26e792
add epoch progress ui with placeholders
nistadev Jul 4, 2022
598e1e6
integrate epochProgress data
nistadev Jul 4, 2022
1648637
add percentage
paulclindo Dec 20, 2021
6730fde
remove log
paulclindo Dec 21, 2021
a8d1f15
add start epoch date
paulclindo Jan 8, 2022
67b2918
Merge branch 'add-epoch-history' of github.com:Emurgo/yoroi-frontend …
nistadev Jul 4, 2022
30d9b54
Merge branch 'develop' of github.com:Emurgo/yoroi-frontend into add-e…
nistadev Jul 6, 2022
49418ef
Fixed styles to match last revamp version
nistadev Jul 7, 2022
ea7de80
Fix typo
nistadev Jul 7, 2022
7a64116
Merge branch 'develop' into add-epoch-history
vsubhuman Jul 7, 2022
1ca7033
Calculate days left to finish epoch
nistadev Jul 7, 2022
f2c7ef1
Merge branch 'add-epoch-history' of github.com:Emurgo/yoroi-frontend …
nistadev Jul 7, 2022
2c943b1
Merge branch 'develop' of github.com:Emurgo/yoroi-frontend into add-e…
nistadev Jul 7, 2022
51e41fc
Merge branch 'develop' into add-epoch-history
vsubhuman Jul 29, 2022
8445516
Merge branch 'develop' into add-epoch-history
vsubhuman Aug 8, 2022
9da5868
lint fixes
vsubhuman Aug 8, 2022
ea587a1
Merge branch 'develop' into add-epoch-history
vsubhuman Aug 8, 2022
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// @flow
import type { Node } from 'react';
import { Box } from '@mui/system';
import { CircularProgress, Stack, Typography } from '@mui/material';

type Props = {|
+percentage: number,
+days: string,
+currentEpoch: number,
+startEpochDate: string,
+endEpochDate: string,
|};

export function EpochProgressCard({
percentage,
days,
currentEpoch,
startEpochDate,
endEpochDate,
}: Props): Node {
return (
<Box>
<Stack direction="row" spacing={2} justifyContent="flex-start">
<Graph value={percentage} days={days} />
<Stack direction="column" flexGrow="1">
<Title label="Current Epoch" value={currentEpoch} />
<Stack direction="row" spacing={3} mt="50px" justifyContent="space-between">
<LabelWithValue label="Epoch started at" value={startEpochDate} />
<LabelWithValue label="Epoch ends at" value={endEpochDate} />
</Stack>
</Stack>
</Stack>
</Box>
);
}

type TitleProps = {|
+label: string,
+value: string | number,
|};
const Title = ({ label, value }: TitleProps): Node => {
return (
<Box>
<Typography fontWeight="500" color="var(--yoroi-palette-primary-300)">
{label}: {value}
</Typography>
</Box>
);
};

type InfoColumnProps = {|
+label: string,
+value: string | number,
|};
const LabelWithValue = ({ label, value }: InfoColumnProps): Node => {
return (
<Box>
<Typography
style={{ textTransform: 'uppercase' }}
variant="caption"
mb="4px"
color="var(--yoroi-palette-gray-600)"
>
{label}
</Typography>
<Typography color="var(--yoroi-palette-gray-900)">{value}</Typography>
</Box>
);
};

const Graph = ({ value, days }): Node => {
return (
<Box mr="8px" position="relative" display="flex" justifyContent="center">
<CircularProgress
size={120}
thickness={7}
variant="determinate"
value={value}
sx={{
color: 'var(--yoroi-palette-primary-300)',
animationDuration: '550ms',
position: 'absolute',
zIndex: 1,
}}
/>
<CircularProgress
size={120}
thickness={7}
variant="determinate"
sx={{
color: 'var(--yoroi-palette-gray-50)',
}}
value={100}
/>
<Box
position="absolute"
sx={{
top: '30%',
left: '50%',
transform: 'translate(-50%)',
textAlign: 'center',
}}
>
<Typography variant="h4" color="var(--yoroi-palette-gray-900)">
{value}%
</Typography>
<Typography variant="caption1" fontSize="12px" color="var(--yoroi-palette-gray-600)">
{days} days
</Typography>
</Box>
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,29 @@ import { Box, styled } from '@mui/system';
import { TabContext, TabList, TabPanel } from '@mui/lab';
import { IconButton, Tab, Typography } from '@mui/material';
import { observer } from 'mobx-react';
import { ReactComponent as InfoIconSVG } from '../../../../assets/images/info-icon.inline.svg';
import { ReactComponent as CloseIcon } from '../../../../assets/images/forms/close.inline.svg';
import { ReactComponent as InfoIconSVG } from '../../../../assets/images/info-icon.inline.svg';
import { ReactComponent as CloseIcon } from '../../../../assets/images/forms/close.inline.svg';
import DelegatedStakePoolCard from './DelegatedStakePoolCard';
import { defineMessages, injectIntl } from 'react-intl';
import type { $npm$ReactIntl$IntlShape } from 'react-intl';
import globalMessages from '../../../../i18n/global-messages';
import type { PoolData } from '../../../../containers/wallet/staking/SeizaFetcher';
import RewardGraph from './RewardsGraph';
import type { GraphData } from '../dashboard/StakingDashboard';
import { EpochProgressCard } from './EpochProgressCard';
import moment from 'moment';

type Props = {|
delegatedPool: PoolData,
epochProgress: {|
currentEpoch: number,
startEpochDate: string,
endEpochDate: string,
percentage: number,
|},
+undelegate: void | (void => Promise<void>),
+epochLength: ?number,
+graphData: GraphData
+graphData: GraphData,
|};

type Intl = {|
Expand All @@ -46,9 +54,10 @@ function StakingTabs({
delegatedPool,
epochLength,
undelegate,
epochProgress,
intl,
graphData
}: Props & Intl): Node {
graphData,
}: Props & Intl): Node {
const [value, setValue] = useState(0);

const handleChange = (event, newValue) => {
Expand All @@ -63,9 +72,9 @@ function StakingTabs({
return epochLength === 1
? intl.formatMessage(messages.singleEpochAxisLabel)
: intl.formatMessage(messages.epochAxisLabel, { epochLength });
}
};

const { hideYAxis, items } = graphData.rewardsGraphData
const { hideYAxis, items } = graphData.rewardsGraphData;
const tabs = [
{
id: 0,
Expand Down Expand Up @@ -99,8 +108,16 @@ function StakingTabs({
{
id: 2,
label: 'Epoch progress',
disabled: true,
component: <Box>TODO: Epoch progress!</Box>,
disabled: false,
component: (
<EpochProgressCard
percentage={epochProgress.percentage}
days={moment(epochProgress.endEpochDate).diff(moment(), 'days')}
currentEpoch={epochProgress.currentEpoch}
startEpochDate={epochProgress.startEpochDate}
endEpochDate={epochProgress.endEpochDate}
/>
),
},
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,13 @@ import type { GeneratedData as DeregisterDialogContainerData } from '../../trans
import UndelegateDialog from '../../../components/wallet/staking/dashboard/UndelegateDialog';
import type { PoolRequest } from '../../../api/jormungandr/lib/storage/bridge/delegationUtils';
import { generateGraphData } from '../../../utils/graph';
import { ApiOptions, getApiForNetwork, } from '../../../api/common/utils';
import type { CurrentTimeRequests, TimeCalcRequests } from '../../../stores/base/BaseCardanoTimeStore';
import type { TokenEntry } from '../../../api/common/lib/MultiToken';
import { ApiOptions, getApiForNetwork } from '../../../api/common/utils';
import type {
CurrentTimeRequests,
TimeCalcRequests,
} from '../../../stores/base/BaseCardanoTimeStore';
import moment from 'moment';

export type GeneratedData = typeof StakingPage.prototype.generated;
// populated by ConfigWebpackPlugin
Expand Down Expand Up @@ -81,8 +85,9 @@ class StakingPage extends Component<AllProps> {
if (!isCardanoHaskell(publicDeriver.getParent().getNetworkInfo())) {
return undefined;
}
const adaDelegationRequests = this.generated.stores.substores.ada.delegation
.getDelegationRequests(publicDeriver);
const adaDelegationRequests = this.generated.stores.substores.ada.delegation.getDelegationRequests(
publicDeriver
);
if (adaDelegationRequests == null) return undefined;
return adaDelegationRequests.getRegistrationHistory.result?.current;
};
Expand Down Expand Up @@ -168,6 +173,37 @@ class StakingPage extends Component<AllProps> {


getStakePools: (PublicDeriver<>) => Node | void = publicDeriver => {
const timeStore = this.generated.stores.time;
const timeCalcRequests = timeStore.getTimeCalcRequests(publicDeriver);
const currTimeRequests = timeStore.getCurrentTimeRequests(publicDeriver);
const toAbsoluteSlot = timeCalcRequests.requests.toAbsoluteSlot.result;
if (toAbsoluteSlot == null) return undefined;
const toRealTime = timeCalcRequests.requests.toRealTime.result;
if (toRealTime == null) return undefined;
const timeSinceGenesis = timeCalcRequests.requests.timeSinceGenesis.result;
if (timeSinceGenesis == null) return undefined;
const getEpochLength = timeCalcRequests.requests.currentEpochLength.result;
if (getEpochLength == null) return undefined;
const currentEpoch = currTimeRequests.currentEpoch;
const epochLength = getEpochLength();

const getDateFromEpoch = epoch => {
const epochTime = toRealTime({
absoluteSlotNum: toAbsoluteSlot({
epoch,
// in Jormungandr, rewards were distributed at the start of the epoch
// in Haskell, rewards are calculated at the start of the epoch but distributed at the end
slot: isJormungandr(publicDeriver.getParent().getNetworkInfo()) ? 0 : getEpochLength(),
}),
timeSinceGenesisFunc: timeSinceGenesis,
});
const epochMoment = moment(epochTime).format('lll');
return epochMoment;
};

const endEpochDate = getDateFromEpoch(currentEpoch);
const previousEpochDate = getDateFromEpoch(currentEpoch - 1);

const delegationStore = this.generated.stores.delegation;
const delegationRequests = delegationStore.getDelegationRequests(publicDeriver);
if (delegationRequests == null) {
Expand Down Expand Up @@ -212,20 +248,26 @@ class StakingPage extends Component<AllProps> {
// tw: '',
// },
// };

return (
<StakingTabs
epochProgress={{
startEpochDate: previousEpochDate,
currentEpoch,
endEpochDate,
percentage: Math.floor((100 * currTimeRequests.currentSlot) / epochLength),
}}
delegatedPool={delegatedPool}
undelegate={
// don't support undelegation for ratio stake since it's a less intuitive UX
currentPools.length === 1 && isJormungandr(publicDeriver.getParent().getNetworkInfo())
? async () => {
this.generated.actions.dialogs.open.trigger({ dialog: UndelegateDialog });
await this.generated.actions.jormungandr
.delegationTransaction.createTransaction.trigger({
await this.generated.actions.jormungandr.delegationTransaction.createTransaction.trigger(
{
publicDeriver,
poolRequest: undefined,
});
}
);
}
: undefined
}
Expand All @@ -246,8 +288,8 @@ class StakingPage extends Component<AllProps> {
toUnitOfAccount: TokenEntry => void | {| currency: string, amount: string |} = entry => {
const { stores } = this.generated;
const tokenRow = stores.tokenInfoStore.tokenInfo
.get(entry.networkId.toString())
?.get(entry.identifier);
.get(entry.networkId.toString())
?.get(entry.identifier);
if (tokenRow == null) return undefined;

if (!stores.profile.unitOfAccount.enabled) return undefined;
Expand Down Expand Up @@ -362,10 +404,11 @@ class StakingPage extends Component<AllProps> {
onNext={() => {
// note: purposely don't await
// since the next dialog will properly render the spinner
this.generated.actions.ada.delegationTransaction
.createWithdrawalTxForWallet.trigger({
publicDeriver,
});
this.generated.actions.ada.delegationTransaction.createWithdrawalTxForWallet.trigger(
{
publicDeriver,
}
);
this.generated.actions.dialogs.open.trigger({
dialog: WithdrawalTxDialogContainer,
});
Expand Down Expand Up @@ -455,15 +498,15 @@ class StakingPage extends Component<AllProps> {
|},
|},
|},
time: {|
getCurrentTimeRequests: (PublicDeriver<>) => CurrentTimeRequests,
getTimeCalcRequests: (PublicDeriver<>) => TimeCalcRequests,
|},
delegation: {|
selectedPage: number,
getLocalPoolInfo: ($ReadOnly<NetworkRow>, string) => void | PoolMeta,
getDelegationRequests: (PublicDeriver<>) => void | DelegationRequests,
|},
time: {|
getCurrentTimeRequests: (PublicDeriver<>) => CurrentTimeRequests,
getTimeCalcRequests: (PublicDeriver<>) => TimeCalcRequests,
|},
profile: {|
shouldHideBalance: boolean,
unitOfAccount: UnitOfAccountSettingType,
Expand Down Expand Up @@ -507,10 +550,11 @@ class StakingPage extends Component<AllProps> {
}
return {
getTimeCalcRequests: (undefined: any),
getCurrentTimeRequests: () => { throw new Error(`${nameof(StakingPage)} api not supported`) },
getCurrentTimeRequests: () => {
throw new Error(`${nameof(StakingPage)} api not supported`);
},
};
})();

return Object.freeze({
stores: {
wallets: {
Expand All @@ -525,6 +569,7 @@ class StakingPage extends Component<AllProps> {
getLocalPoolInfo: stores.delegation.getLocalPoolInfo,
getDelegationRequests: stores.delegation.getDelegationRequests,
},
time,
uiDialogs: {
isOpen: stores.uiDialogs.isOpen,
getParam: stores.uiDialogs.getParam,
Expand All @@ -540,7 +585,6 @@ class StakingPage extends Component<AllProps> {
coinPriceStore: {
getCurrentPrice: stores.coinPriceStore.getCurrentPrice,
},
time,
substores: {
ada: {
delegation: {
Expand Down