diff --git a/src/constants/dialogs.ts b/src/constants/dialogs.ts index ed20d3f..1ab8e47 100644 --- a/src/constants/dialogs.ts +++ b/src/constants/dialogs.ts @@ -5,6 +5,7 @@ export enum DialogTypes { ExchangeOffline = 'ExchangeOffline', FillDetails = 'FillDetails', Help = 'Help', + Keplr = 'Keplr', MnemonicExport = 'MnemonicExport', MobileSignIn = 'MobileSignIn', Onboarding = 'Onboarding', diff --git a/src/hooks/useAccountBalance.ts b/src/hooks/useAccountBalance.ts index 88a6858..64f8334 100644 --- a/src/hooks/useAccountBalance.ts +++ b/src/hooks/useAccountBalance.ts @@ -14,7 +14,7 @@ import { EvmAddress } from '@/constants/wallets'; import { convertBech32Address } from '@/lib/addressUtils'; import { MustBigNumber } from '@/lib/numbers'; -import { getBalances } from '@/state/accountSelectors'; +import { getBalances, getStakingBalances } from '@/state/accountSelectors'; import { getSelectedNetwork } from '@/state/appSelectors'; import { useAccounts } from './useAccounts'; @@ -53,6 +53,7 @@ export const useAccountBalance = ({ const selectedNetwork = useSelector(getSelectedNetwork); const balances = useSelector(getBalances, shallowEqual); const evmChainId = Number(ENVIRONMENT_CONFIG_MAP[selectedNetwork].ethereumChainId); + const stakingBalances = useSelector(getStakingBalances, shallowEqual); const evmQuery = useBalance({ enabled: Boolean(!isCosmosChain && addressOrDenom?.startsWith('0x')), @@ -100,9 +101,15 @@ export const useAccountBalance = ({ const usdcCoinBalance = balances?.[USDC_DENOM]; const usdcBalance = MustBigNumber(usdcCoinBalance?.amount).div(QUANTUM_MULTIPLIER).toNumber(); + const nativeStakingCoinBalanace = stakingBalances?.[DYDX_DENOM]; + const nativeStakingBalance = MustBigNumber(nativeStakingCoinBalanace?.amount) + .div(QUANTUM_MULTIPLIER) + .toNumber(); + return { balance, nativeTokenBalance, + nativeStakingBalance, usdcBalance, queryStatus: isCosmosChain ? cosmosQuery.status : evmQuery.status, isQueryFetching: isCosmosChain ? cosmosQuery.isFetching : evmQuery.fetchStatus === 'fetching', diff --git a/src/layout/DialogManager.tsx b/src/layout/DialogManager.tsx index e647bc2..904a02d 100644 --- a/src/layout/DialogManager.tsx +++ b/src/layout/DialogManager.tsx @@ -11,6 +11,7 @@ import { DepositDialog } from '@/views/dialogs/DepositDialog'; import { DisconnectDialog } from '@/views/dialogs/DisconnectDialog'; import { ExchangeOfflineDialog } from '@/views/dialogs/ExchangeOfflineDialog'; import { HelpDialog } from '@/views/dialogs/HelpDialog'; +import { KeplrDialog } from '@/views/dialogs/KeplrDialog'; import { MnemonicExportDialog } from '@/views/dialogs/MnemonicExportDialog'; import { MobileSignInDialog } from '@/views/dialogs/MobileSignInDialog'; import { OnboardingDialog } from '@/views/dialogs/OnboardingDialog'; @@ -47,6 +48,7 @@ export const DialogManager = () => { [DialogTypes.ExchangeOffline]: , [DialogTypes.FillDetails]: , [DialogTypes.Help]: , + [DialogTypes.Keplr]: , [DialogTypes.MnemonicExport]: , [DialogTypes.MobileSignIn]: , [DialogTypes.Onboarding]: , diff --git a/src/lib/abacus/stateNotification.ts b/src/lib/abacus/stateNotification.ts index 573a9f2..6f9d92e 100644 --- a/src/lib/abacus/stateNotification.ts +++ b/src/lib/abacus/stateNotification.ts @@ -20,6 +20,7 @@ import type { RootStore } from '@/state/_store'; import { setBalances, + setStakingBalances, setFills, setFundingPayments, setHistoricalPnl, @@ -82,6 +83,13 @@ class AbacusStateNotifier implements AbacusStateNotificationProtocol { } dispatch(setBalances(balances)); } + if (updatedState.account?.stakingBalances) { + const stakingBalances: Record = {} + for (const { k, v } of updatedState.account.stakingBalances.toArray()) { + stakingBalances[k] = v; + } + dispatch(setStakingBalances(stakingBalances)); + } } if (changes.has(Changes.configs)) { diff --git a/src/pages/rewards/DYDXBalancePanel.tsx b/src/pages/rewards/DYDXBalancePanel.tsx index ebaf31a..94acd64 100644 --- a/src/pages/rewards/DYDXBalancePanel.tsx +++ b/src/pages/rewards/DYDXBalancePanel.tsx @@ -29,7 +29,7 @@ export const DYDXBalancePanel = () => { const { walletType } = useAccounts(); const canAccountTrade = useSelector(calculateCanAccountTrade, shallowEqual); - const { nativeTokenBalance } = useAccountBalance(); + const { nativeTokenBalance, nativeStakingBalance } = useAccountBalance(); return ( { ), - value: , + value: , }, ]} /> @@ -106,7 +106,7 @@ export const DYDXBalancePanel = () => { { key: 'totalBalance', label: 'Total balance', - value: , + value: , }, ]} /> diff --git a/src/pages/rewards/RewardsPage.tsx b/src/pages/rewards/RewardsPage.tsx index a8cede9..0f232bb 100644 --- a/src/pages/rewards/RewardsPage.tsx +++ b/src/pages/rewards/RewardsPage.tsx @@ -1,9 +1,11 @@ import styled, { AnyStyledComponent } from 'styled-components'; +import { useDispatch } from 'react-redux'; import { STRING_KEYS } from '@/constants/localization'; import { ButtonAction, ButtonSize } from '@/constants/buttons'; +import { DialogTypes } from '@/constants/dialogs'; -import { useAccounts, useBreakpoints, useStringGetter } from '@/hooks'; +import { useStringGetter } from '@/hooks'; import { layoutMixins } from '@/styles/layoutMixins'; @@ -11,9 +13,12 @@ import { Panel } from '@/components/Panel'; import { IconName } from '@/components/Icon'; import { IconButton } from '@/components/IconButton'; +import { openDialog } from '@/state/dialogs'; + import { DYDXBalancePanel } from './DYDXBalancePanel'; export const RewardsPage = () => { + const dispatch = useDispatch(); const stringGetter = useStringGetter(); return ( @@ -23,20 +28,26 @@ export const RewardsPage = () => { slotHeader={{stringGetter({ key: STRING_KEYS.GOVERNANCE })}} > -
- {stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })} -
- +
{stringGetter({ key: STRING_KEYS.GOVERNANCE_DESCRIPTION })}
+ dispatch(openDialog({ type: DialogTypes.Keplr }))} + size={ButtonSize.Small} + />
{stringGetter({ key: STRING_KEYS.STAKING })}} > -
- {stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })} -
- +
{stringGetter({ key: STRING_KEYS.STAKING_DESCRIPTION })}
+ dispatch(openDialog({ type: DialogTypes.Keplr }))} + size={ButtonSize.Small} + />
@@ -78,4 +89,4 @@ Styled.Title = styled.h3` Styled.Panel = styled(Panel)` padding: 0 1.5rem 1rem; -` +`; diff --git a/src/state/account.ts b/src/state/account.ts index 467774f..e3178d8 100644 --- a/src/state/account.ts +++ b/src/state/account.ts @@ -37,6 +37,7 @@ export type AccountState = { walletType?: WalletType; historicalPnlPeriod?: HistoricalPnlPeriods; balances?: Record; + stakingBalances?: Record; }; const initialState: AccountState = { @@ -154,6 +155,9 @@ export const accountSlice = createSlice({ setBalances: (state, action: PayloadAction>) => { state.balances = action.payload; }, + setStakingBalances: (state, action: PayloadAction>) => { + state.stakingBalances = action.payload; + }, addUncommittedOrderClientId: (state, action: PayloadAction) => { state.uncommittedOrderClientIds.push(action.payload); }, @@ -179,6 +183,7 @@ export const { viewedFills, viewedOrders, setBalances, + setStakingBalances, addUncommittedOrderClientId, removeUncommittedOrderClientId, } = accountSlice.actions; diff --git a/src/state/accountSelectors.ts b/src/state/accountSelectors.ts index 8054dc3..4a81a5b 100644 --- a/src/state/accountSelectors.ts +++ b/src/state/accountSelectors.ts @@ -337,3 +337,8 @@ export const getUserStats = (state: RootState) => ({ * @returns user wallet balances */ export const getBalances = (state: RootState) => state.account?.balances; + +/** + * @returns user wallet staking balances + * */ +export const getStakingBalances = (state: RootState) => state.account?.stakingBalances; diff --git a/src/views/dialogs/KeplrDialog.tsx b/src/views/dialogs/KeplrDialog.tsx new file mode 100644 index 0000000..86f54df --- /dev/null +++ b/src/views/dialogs/KeplrDialog.tsx @@ -0,0 +1,56 @@ +import styled, { type AnyStyledComponent } from 'styled-components'; + +import { STRING_KEYS } from '@/constants/localization'; +import { useBreakpoints, useStringGetter } from '@/hooks'; + +import { Dialog, DialogPlacement } from '@/components/Dialog'; + +import { WithdrawForm } from '@/views/forms/AccountManagementForms/WithdrawForm'; + +import { layoutMixins } from '@/styles/layoutMixins'; + +type ElementProps = { + setIsOpen: (open: boolean) => void; +}; + +export const KeplrDialog = ({ setIsOpen }: ElementProps) => { + const stringGetter = useStringGetter(); + const { isTablet } = useBreakpoints(); + + return ( + + + TEST + + + ); +}; + +const Styled: Record = {}; + +Styled.TextToggle = styled.div` + ${layoutMixins.stickyFooter} + color: var(--color-accent); + cursor: pointer; + + margin-top: auto; + + &:hover { + text-decoration: underline; + } +`; + +Styled.Content = styled.div` + ${layoutMixins.stickyArea0} + --stickyArea0-bottomHeight: 2rem; + --stickyArea0-bottomGap: 1rem; + --stickyArea0-totalInsetBottom: 0.5rem; + + ${layoutMixins.flexColumn} + gap: 1rem; +`;