set up trading rewards layout and data

This commit is contained in:
Aleka Cheung 2023-12-21 15:48:14 +08:00
parent b2234cb969
commit fc00e1d2a9
No known key found for this signature in database
GPG Key ID: 53E472E5EF4F4102
7 changed files with 233 additions and 56 deletions

View File

@ -119,6 +119,8 @@ export const InputSelectionOption = Abacus.exchange.dydx.abacus.output.input.Sel
// ------ Wallet ------ //
export type Wallet = Abacus.exchange.dydx.abacus.output.Wallet;
export type AccountBalance = Abacus.exchange.dydx.abacus.output.AccountBalance;
export type TradingRewards = Abacus.exchange.dydx.abacus.output.TradingRewards;
export type HistoricalTradingReward = Abacus.exchange.dydx.abacus.output.HistoricalTradingReward;
export type Subaccount = Abacus.exchange.dydx.abacus.output.Subaccount;
export type SubaccountPosition = Abacus.exchange.dydx.abacus.output.SubaccountPosition;
export type SubaccountOrder = Abacus.exchange.dydx.abacus.output.SubaccountOrder;

View File

@ -29,6 +29,7 @@ import {
setSubaccount,
setTransfers,
setWallet,
setTradingRewards,
} from '@/state/account';
import { setApiState } from '@/state/app';
@ -96,6 +97,12 @@ class AbacusStateNotifier implements AbacusStateNotificationProtocol {
}
}
if (changes.has(Changes.tradingRewards)) {
if (updatedState.account?.tradingRewards) {
dispatch(setTradingRewards(updatedState.account?.tradingRewards));
}
}
if (changes.has(Changes.configs)) {
dispatch(setConfigs(updatedState.configs));
}

View File

@ -26,7 +26,6 @@ import { useAccounts, useStringGetter, useTokenConfigs } from '@/hooks';
import { getOnboardingState } from '@/state/accountSelectors';
import { openDialog } from '@/state/dialogs';
import abacusStateManager from '@/lib/abacus';
import { isTruthy } from '@/lib/isTruthy';
import { truncateAddress } from '@/lib/wallet';

View File

@ -24,6 +24,7 @@ import { DYDXBalancePanel } from './DYDXBalancePanel';
import { MigratePanel } from './MigratePanel';
import { LaunchIncentivesPanel } from './LaunchIncentivesPanel';
import { RewardsHelpPanel } from './RewardsHelpPanel';
import { TradingRewardsSummaryPanel } from './TradingRewardsSummaryPanel';
const RewardsPage = () => {
const dispatch = useDispatch();
@ -50,50 +51,49 @@ const RewardsPage = () => {
{stringGetter({ key: STRING_KEYS.TRADING_REWARDS })}
</Styled.MobileHeader>
)}
{import.meta.env.VITE_V3_TOKEN_ADDRESS && isNotTablet && <MigratePanel />}
<Styled.GridLayout>
{import.meta.env.VITE_V3_TOKEN_ADDRESS && isNotTablet && <Styled.MigratePanel />}
{isTablet ? (
<LaunchIncentivesPanel />
) : (
<Styled.PanelRowIncentivesAndBalance>
<LaunchIncentivesPanel />
<DYDXBalancePanel />
</Styled.PanelRowIncentivesAndBalance>
)}
<Styled.TradingRewardsColumn>
<TradingRewardsSummaryPanel />
{isTablet && <Styled.HelpPanel slotHeader={<Styled.Title>Help</Styled.Title>} />}
<Styled.Panel slotHeader={<Styled.Title>Reward History</Styled.Title>} />
</Styled.TradingRewardsColumn>
<Styled.PanelRow>
<Styled.Panel
slotHeaderContent={
<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>
}
slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
<Link href={governanceLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
</Styled.Panel>
{isNotTablet && (
<Styled.OtherColumn>
<Styled.Panel
slotHeader={
<Styled.Title>{stringGetter({ key: STRING_KEYS.GOVERNANCE })}</Styled.Title>
}
slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
<Link href={governanceLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
</Styled.Panel>
<Styled.Panel
slotHeaderContent={
<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>
}
slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
<Link href={stakingLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
</Styled.Panel>
</Styled.PanelRow>
<Styled.Panel
slotHeader={<Styled.Title>{stringGetter({ key: STRING_KEYS.STAKING })}</Styled.Title>}
slotRight={panelArrow}
onClick={() => dispatch(openDialog({ type: DialogTypes.ExternalNavKeplr }))}
>
<Styled.Description>
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
<Link href={stakingLearnMore} onClick={(e) => e.stopPropagation()}>
{stringGetter({ key: STRING_KEYS.LEARN_MORE })}
</Link>
</Styled.Description>
</Styled.Panel>
<RewardsHelpPanel />
<Styled.Panel slotHeader={<Styled.Title>Help</Styled.Title>} />
</Styled.OtherColumn>
)}
</Styled.GridLayout>
</Styled.Page>
);
};
@ -104,7 +104,6 @@ const Styled: Record<string, AnyStyledComponent> = {};
Styled.Page = styled.div`
${layoutMixins.contentContainerPage}
gap: 1.5rem;
padding: 2rem;
align-items: center;
@ -138,6 +137,54 @@ Styled.MobileHeader = styled.header`
Styled.Panel = styled(Panel)`
height: fit-content;
font: var(--font-large-medium);
color: var(--color-text-2);
background-color: var(--color-layer-2);
`;
Styled.GridLayout = styled.div`
--gap: 1.5rem;
display: grid;
grid-template-columns: 2fr 1fr;
gap: var(--gap);
> * {
gap: var(--gap);
}
grid-template-areas:
'migrate migrate'
'incentives balance'
'rewards other';
@media ${breakpoints.tablet} {
--gap: 1rem;
grid-template-columns: 1fr;
grid-template-areas:
'incentives'
'rewards';
}
`;
Styled.MigratePanel = styled(MigratePanel)`
grid-area: migrate;
`;
Styled.LaunchIncentivesPanel = styled(LaunchIncentivesPanel)`
grid-area: incentives;
`;
Styled.DYDXBalancePanel = styled(DYDXBalancePanel)`
grid-area: balance;
`;
Styled.TradingRewardsColumn = styled.div`
grid-area: rewards;
${layoutMixins.flexColumn}
`;
Styled.OtherColumn = styled.div`
grid-area: other;
${layoutMixins.flexColumn}
`;
Styled.Title = styled.h3`
@ -158,20 +205,6 @@ Styled.Description = styled.div`
}
`;
Styled.PanelRow = styled.div`
${layoutMixins.gridEqualColumns}
gap: 1.5rem;
@media ${breakpoints.tablet} {
grid-auto-flow: row;
grid-template-columns: 1fr;
}
`;
Styled.PanelRowIncentivesAndBalance = styled(Styled.PanelRow)`
grid-template-columns: 2fr 1fr;
`;
Styled.IconButton = styled(IconButton)`
color: var(--color-text-0);
--color-border: var(--color-layer-6);

View File

@ -0,0 +1,119 @@
import styled, { AnyStyledComponent } from 'styled-components';
import { shallowEqual, useSelector } from 'react-redux';
import { STRING_KEYS } from '@/constants/localization';
import breakpoints from '@/styles/breakpoints';
import { layoutMixins } from '@/styles/layoutMixins';
import { useStringGetter, useTokenConfigs } from '@/hooks';
import { AssetIcon } from '@/components/AssetIcon';
import { Details } from '@/components/Details';
import { Output, OutputType } from '@/components/Output';
import { Panel } from '@/components/Panel';
import { getHistoricalTradingRewards } from '@/state/accountSelectors';
export const TradingRewardsSummaryPanel = () => {
const stringGetter = useStringGetter();
const historicalTradingRewards = useSelector(getHistoricalTradingRewards, shallowEqual);
const currentWeekTradingReward = historicalTradingRewards?.get('WEEKLY')?.firstOrNull()?.amount;
const { chainTokenLabel } = useTokenConfigs();
return (
<Styled.Panel
slotHeader={
<Styled.Header>
<Styled.Title>Trading Rewards Summary</Styled.Title>
</Styled.Header>
}
>
<Styled.Content>
<Styled.TradingRewardsDetails
layout="grid"
items={[
{
key: 'week',
label: (
<Styled.Label>
<h4>{stringGetter({ key: STRING_KEYS.THIS_WEEK })}</h4>
</Styled.Label>
),
value: (
<Output
slotRight={<AssetIcon symbol={chainTokenLabel} />}
type={OutputType.Asset}
value={currentWeekTradingReward}
/>
),
},
// TODO(@aforaleka): add all-time when supported
]}
/>
</Styled.Content>
</Styled.Panel>
);
};
const Styled: Record<string, AnyStyledComponent> = {};
Styled.Panel = styled(Panel)`
--panel-paddingX: 1.5rem;
--panel-paddingY: 1.25rem;
@media ${breakpoints.tablet} {
--panel-paddingY: 1.5rem;
}
`;
Styled.Header = styled.div`
${layoutMixins.spacedRow}
gap: 1rem;
padding: var(--panel-paddingY) var(--panel-paddingX) 0;
`;
Styled.Title = styled.h3`
${layoutMixins.inlineRow}
font: var(--font-medium-book);
color: var(--color-text-2);
img {
font-size: 1.5rem;
}
`;
Styled.Content = styled.div`
${layoutMixins.flexColumn}
gap: 0.75rem;
`;
Styled.TradingRewardsDetails = styled(Details)`
--details-item-backgroundColor: var(--color-layer-6);
grid-template-columns: 1fr; // TODO(@aforaleka): change to 1fr 1fr when all-time is supported
gap: 1rem;
> div {
gap: 1rem;
padding: 1rem;
border-radius: 0.75em;
background-color: var(--color-layer-5);
}
dt {
width: 100%;
}
output {
color: var(--color-text-2);
font: var(--font-large-book);
}
`;
Styled.Label = styled.div`
${layoutMixins.spacedRow}
font: var(--font-base-book);
color: var(--color-text-1);
`;

View File

@ -13,6 +13,7 @@ import type {
HistoricalPnlPeriods,
SubAccountHistoricalPNLs,
UsageRestriction,
TradingRewards,
} from '@/constants/abacus';
import { OnboardingGuard, OnboardingState } from '@/constants/account';
@ -24,6 +25,7 @@ import { getLocalStorage } from '@/lib/localStorage';
export type AccountState = {
balances?: Record<string, AccountBalance>;
stakingBalances?: Record<string, AccountBalance>;
tradingRewards?: TradingRewards;
wallet?: Nullable<Wallet>;
walletType?: WalletType;
@ -179,6 +181,9 @@ export const accountSlice = createSlice({
setStakingBalances: (state, action: PayloadAction<Record<string, AccountBalance>>) => {
state.stakingBalances = action.payload;
},
setTradingRewards: (state, action: PayloadAction<TradingRewards>) => {
state.tradingRewards = action.payload;
},
addUncommittedOrderClientId: (state, action: PayloadAction<number>) => {
state.uncommittedOrderClientIds.push(action.payload);
},
@ -206,6 +211,7 @@ export const {
viewedOrders,
setBalances,
setStakingBalances,
setTradingRewards,
addUncommittedOrderClientId,
removeUncommittedOrderClientId,
} = accountSlice.actions;

View File

@ -343,6 +343,17 @@ export const getBalances = (state: RootState) => state.account?.balances;
* */
export const getStakingBalances = (state: RootState) => state.account?.stakingBalances;
/**
* @returns account all time trading rewards
*/
export const getTotalTradingRewards = (state: RootState) => state.account?.tradingRewards?.total;
/**
* @returns account trading rewards aggregated by period
*/
export const getHistoricalTradingRewards = (state: RootState) =>
state.account?.tradingRewards?.historical;
/**
* @returns UsageRestriction of the current session
*/