Skip to content

Conversation

@SorinC6
Copy link
Contributor

@SorinC6 SorinC6 commented Dec 16, 2025

  • Layout and Summary Card

Tasks:


Note

Introduces the revamp Staking dashboard with rewards summary/graphs, new routing/context, query key factories, and supporting icons/utilities.

  • Staking (revamp):
    • Add StakingPage and layout under UI/pages/Staking/*, StakingRoot with RewardsSummaryCard and placeholder PoolList.
    • New StakingContextProvider with graph/data helpers (common/helpers/graph.ts), types, and i18n strings.
    • Implement reward history chart (RewardHistoryGraph, RewardGraphClean) and WithdrawButton flow.
  • Routing/Navigation:
    • Add ROUTES.STAKING_REVAMP.ROOT (/staking-revamp) and wrap with StakingSubpages (StakingContextProvider).
    • Show dev-only sidebar entry for staking revamp; wire route in Routes.js.
  • Queries:
    • Introduce React Query factories poolQueryKeys for pool list/info.
  • Icons:
    • Add Icon.StakingActive and Icon.TotalDelegated and export in icons/index.tsx.
  • Governance:
    • Simplify GovernanceContextProvider by removing pricing/formatting props and helpers.
  • Common:
    • Add HIDDEN_AMOUNT constant.
  • Dependencies:
    • Add @yoroi/api to package.json.

Written by Cursor Bugbot for commit 7e4e9af. This will update automatically on new commits. Configure here.

@Nebyt Nebyt added this to the 5.20.0 milestone Dec 16, 2025
Copy link
Contributor Author

@SorinC6 SorinC6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/check

@SorinC6 SorinC6 changed the title Staking Page Refactor Staking Page Refactor Part I Dec 16, 2025
Copy link
Contributor Author

@SorinC6 SorinC6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/check

Copy link
Collaborator

@loxator loxator left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some constants are typed as null | undefined, but usually its only checked for if(x == null), why not use something like if(!x) so it takes care of both cases?

Just some small comments as I am not versed with the business logic too much, better to get a review from @yushih too!

[initialState]
);

React.useEffect(() => {}, [stores]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty useEffect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in the next PR

<Box>
<Box display="block">
<Typography component="div" color="var(--yoroi-palette-gray-600)">
Stake Pool
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this come from useStrings()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in the next PR

Comment on lines +79 to +204
/* ---------- Styled components ---------- */

const Accordion = styled((props: MuiAccordionProps) => (
<MuiAccordion TransitionProps={{ timeout: { exit: 500 } }} disableGutters elevation={0} square {...props} />
))(() => ({
borderBottom: `1px solid var(--yoroi-palette-gray-50)`,
'&:not(:last-child)': {
borderBottom: 0,
},
'&:before': {
display: 'none',
},
paddingBottom: '16px',
marginBottom: '16px',
}));

const AccordionDetails = styled(MuiAccordionDetails)(() => ({
marginTop: '24px',
padding: 0,
}));

const AvatarImg = styled('img')({
width: '100%',
background: 'white',
objectFit: 'scale-down',
});

const AvatarWrapper = styled(Box)({
width: '24px',
height: '24px',
minWidth: '24px',
marginRight: '12px',
borderRadius: '20px',
overflow: 'hidden',
});

const ExpandMoreIcon: React.FC = () => (
<svg width="14" height="8" viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M0.292893 0.292893C0.683417 -0.0976311 1.31658 -0.0976311 1.70711 0.292893L7 5.58579L12.2929 0.292893C12.6834 -0.0976311 13.3166 -0.0976311 13.7071 0.292893C14.0976 0.683417 14.0976 1.31658 13.7071 1.70711L7.70711 7.70711C7.31658 8.09763 6.68342 8.09763 6.29289 7.70711L0.292893 1.70711C-0.0976311 1.31658 -0.0976311 0.683417 0.292893 0.292893Z"
fill="#6B7384"
/>
</svg>
);

const AccordionSummary = styled((props: MuiAccordionSummaryProps) => (
<MuiAccordionSummary expandIcon={<ExpandMoreIcon />} {...props} />
))(() => ({
padding: 0,
'.MuiAccordionSummary-content': {
margin: 0,
},
'& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
transform: 'rotate(180deg)',
},
'& .MuiCollapse-vertical': {
transitionDuration: '0.5s',
},
}));

const RewardHistoryGraph: React.FC<RewardHistoryGraphProps> = ({ graphData, onOpenRewardList }) => {
const strings = useStrings();
const { rewardsGraphData } = graphData;
const rewardList = rewardsGraphData.items?.perEpochRewards;
const title = strings.rewardHistoryLabel;

return (
<Box
p="24px"
sx={{
display: 'flex',
flexFlow: 'column',
justifyContent: 'space-between',
}}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
}}
>
<Typography component="div" variant="body1" fontWeight={500} color="ds.text_gray_medium">
{title}
</Typography>
<Button
// @ts-ignore
variant="primary"
size="medium"
onClick={onOpenRewardList}
sx={{ lineHeight: '21px' }}
>
{title}
</Button>
</Box>

{rewardsGraphData.error && !rewardsGraphData.items && (
<div>
<Typography variant="body2" color="ds.text_error">
{strings.errorLabel}
</Typography>
</div>
)}

{!Array.isArray(rewardList) ? (
<CircularProgress />
) : (
<Box ml="-50px">
<RewardGraphClean
epochTitle={strings.epochLabel}
stakepoolNameTitle={strings.stakepoolNameLabel}
xAxisLabel={strings.epochLabel}
yAxisLabel={strings.rewardValue}
primaryBarLabel={strings.rewardsLabel}
data={rewardList}
hideYAxis={rewardsGraphData.hideYAxis}
/>
</Box>
)}
</Box>
);
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe better to import these from another local components file, just to clean up a bit and make component smaller, nothing major

Copy link
Contributor Author

@SorinC6 SorinC6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/check

return;
}
return createWithdrawalTx();
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Governance participation check treats unknown as true

isParticipatingToGovernance uses stores.delegation.governanceStatus?.drepDelegation !== null, which becomes true when governanceStatus is null/undefined (because undefined !== null). This can incorrectly skip GovernanceParticipateDialog and proceed to withdrawal flow before governance status is actually available.

Fix in Cursor Fix in Web

@SorinC6 SorinC6 requested a review from Nebyt December 17, 2025 15:10
return;
}
return createWithdrawalTx();
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Withdraw uses stale governance status

isParticipatingToGovernance is derived from stores.delegation.governanceStatus inside WithdrawButton, but the component isn’t observer-wrapped and doesn’t subscribe to that observable via state. If governance status changes after render, the click handler can use a stale value and incorrectly open GovernanceParticipateDialog even when the user is already participating.

Fix in Cursor Fix in Web

delegationRequests,
isWalletWithNoFunds,
currentlyDelegating,
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Reward history button does nothing

RewardsSummaryCard consumes onOpenRewardList from useStaking, but StakingContextProvider never sets it, so it stays the default no-op from defaultStakingState. As a result, the “Reward History” action won’t open anything when clicked.

Additional Locations (1)

Fix in Cursor Fix in Web

{truncateToken(tokenInfo?.assetName || '', 12)}
</>
);
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Token label blank in summary

formatTokenEntry renders the token label using truncateToken(tokenInfo?.assetName || '', 12), but getTokenInfo returns a TokenRow where the display name/ticker isn’t exposed as assetName. This can render an empty token label (eg, missing “ADA”) in the rewards summary amounts.

Fix in Cursor Fix in Web

Copy link
Collaborator

@Nebyt Nebyt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/check

@Nebyt Nebyt merged commit 26fb657 into develop Dec 17, 2025
47 of 48 checks passed
@Nebyt Nebyt deleted the chore/YW-172/staking-revamp-layout branch December 17, 2025 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants