-
Notifications
You must be signed in to change notification settings - Fork 52
feat(minipay): redirect to Account page and hide Governance tab until staked #480
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
base: main
Are you sure you want to change the base?
Changes from 11 commits
b7e0634
e1d8318
ba7b915
ea1f253
c6b57f4
00caac7
8b48726
496abbb
436424e
63eaf37
920befe
3ee8a13
333b3ff
165e3c4
b100d05
c466ad9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,16 +43,21 @@ import StakingIcon from 'src/images/icons/staking.svg'; | |
| import UnlockIcon from 'src/images/icons/unlock.svg'; | ||
| import WithdrawIcon from 'src/images/icons/withdraw.svg'; | ||
| import { shortenAddress } from 'src/utils/addresses'; | ||
| import { useAddressParam } from 'src/utils/useAddressParam'; | ||
| import { usePageInvariant } from 'src/utils/navigation'; | ||
| import { useIsMiniPay } from 'src/utils/useIsMiniPay'; | ||
| import { StakingMode, useStakingMode } from 'src/utils/useStakingMode'; | ||
| import useTabs from 'src/utils/useTabs'; | ||
| import { Address } from 'viem'; | ||
| import { useAccount } from 'wagmi'; | ||
|
|
||
| export default function Page() { | ||
| const account = useAccount(); | ||
| const address = account?.address; | ||
| usePageInvariant(!!address, '/'); | ||
| const addressOverride = useAddressParam(); | ||
| const address = addressOverride || account?.address; | ||
| const isReadOnly = !!addressOverride; | ||
| const isMiniPay = useIsMiniPay(); | ||
| usePageInvariant(!!address || isMiniPay, '/'); | ||
|
|
||
| const { signingFor, isVoteSigner } = useVoteSignerToAccount(address); | ||
| const { balance: walletBalance } = useBalance(signingFor); | ||
|
|
@@ -94,7 +99,13 @@ export default function Page() { | |
| <h2>Total Balance</h2> | ||
| <Amount valueWei={totalBalance} className="-mt-1 text-3xl md:text-4xl" /> | ||
| </div> | ||
| {isVoteSigner ? ( | ||
| {isReadOnly ? ( | ||
| <div className="align-right flex flex-col items-end"> | ||
| <h2 className="font-medium text-sm text-taupe-600">Viewing account</h2> | ||
| <span className="hidden font-mono text-sm md:flex">{address}</span> | ||
| <span className="font-mono text-sm md:hidden">{shortenAddress(address!)}</span> | ||
| </div> | ||
| ) : isVoteSigner ? ( | ||
| <div className="align-right flex flex-col items-end"> | ||
| <h2 className="font-medium">Vote Signer For</h2> | ||
| <span className="hidden font-mono text-sm md:flex">{signingFor}</span> | ||
|
|
@@ -104,6 +115,7 @@ export default function Page() { | |
| <LockButtons className="hidden md:flex" mode={mode} /> | ||
| )} | ||
| </div> | ||
| {isMiniPay && !isReadOnly && totalLocked === 0n && <StakeCeloCta />} | ||
| {mode === 'CELO' ? ( | ||
| <AccountStats | ||
| walletBalance={walletBalance} | ||
|
|
@@ -119,7 +131,9 @@ export default function Page() { | |
| scheduledWithdrawalAmount={withdrawals.scheduledWithdrawalAmount} | ||
| /> | ||
| )} | ||
| {isVoteSigner || <LockButtons className="flex justify-between md:hidden" mode={mode} />} | ||
| {!isReadOnly && !isVoteSigner && ( | ||
| <LockButtons className="flex justify-between md:hidden" mode={mode} /> | ||
| )} | ||
|
Comment on lines
+134
to
+136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In read-only mode ( Useful? React with 👍 / 👎. |
||
| <TableTabs | ||
| groupToStake={groupToStake} | ||
| addressToGroup={addressToGroup} | ||
|
|
@@ -405,6 +419,32 @@ function TableTabs({ | |
| ); | ||
| } | ||
|
|
||
| function StakeCeloCta() { | ||
| const showTxModal = useTransactionModal(); | ||
|
|
||
| return ( | ||
| <div className="space-y-3 border border-taupe-300 bg-white px-3 py-4 md:px-5 md:py-5"> | ||
| <h3 className="font-serif text-xl sm:text-2xl">Stake your CELO</h3> | ||
| <p className="text-sm sm:text-base"> | ||
| Earn ~2% annually in exchange for agreeing to a three-day lockup. Staked CELO also gives you | ||
| access to participate in Celo Governance decisions so you can help shape the future of Celo, | ||
| the network powering MiniPay. | ||
| </p> | ||
| <SolidButton | ||
| onClick={() => | ||
| showTxModal(TransactionFlowType.StakeStCELO, { action: StakeActionType.Stake }) | ||
| } | ||
|
Comment on lines
+434
to
+436
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new Useful? React with 👍 / 👎. |
||
| className="bg-purple-300 text-white" | ||
| > | ||
| <div className="flex items-center space-x-1.5"> | ||
| <Image src={StakingIcon} width={12} height={12} alt="" /> | ||
| <span>Stake</span> | ||
| </div> | ||
| </SolidButton> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| function AccountPageSkeleton() { | ||
| return ( | ||
| <> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| 'use client'; | ||
| import { useMemo } from 'react'; | ||
| import { useRouter } from 'next/navigation'; | ||
| import { useEffect, useMemo } from 'react'; | ||
| import { Fade } from 'src/components/animation/Fade'; | ||
| import { SkeletonBlock } from 'src/components/animation/Skeleton'; | ||
| import { SolidButton } from 'src/components/buttons/SolidButton'; | ||
|
|
@@ -17,6 +18,21 @@ import { useIsMiniPay } from 'src/utils/useIsMiniPay'; | |
| import { useStakingMode } from 'src/utils/useStakingMode'; | ||
|
|
||
| export default function Page() { | ||
| const isMiniPay = useIsMiniPay(); | ||
| const router = useRouter(); | ||
|
|
||
| useEffect(() => { | ||
| if (isMiniPay) { | ||
| router.replace('/account'); | ||
|
Comment on lines
+25
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This redirect is unconditional for MiniPay, so it also runs when no wallet address is connected (or before wagmi finishes hydrating). In that state, Useful? React with 👍 / 👎. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The home redirect drops the current query string, so a session opened at Useful? React with 👍 / 👎. |
||
| } | ||
| }, [isMiniPay, router]); | ||
|
|
||
| if (isMiniPay) return null; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
MiniPay now redirects away from Useful? React with 👍 / 👎. |
||
|
|
||
| return <StakingPage />; | ||
| } | ||
|
|
||
| function StakingPage() { | ||
| const { groups, totalVotes } = useValidatorGroups(); | ||
|
|
||
| return ( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ import { useCallback } from 'react'; | |
| import { ChevronIcon } from 'src/components/icons/Chevron'; | ||
| import { CeloGlyph } from 'src/components/logos/Celo'; | ||
| import { DropdownMenu } from 'src/components/menus/Dropdown'; | ||
| import { useLockedBalance } from 'src/features/account/hooks'; | ||
| import Bridge from 'src/images/icons/bridge.svg'; | ||
| import Dashboard from 'src/images/icons/dashboard.svg'; | ||
| import Delegate from 'src/images/icons/delegate.svg'; | ||
|
|
@@ -18,7 +19,7 @@ import { useAccount } from 'wagmi'; | |
|
|
||
| const LINKS = (isWalletConnected?: boolean) => [ | ||
| { label: 'Staking', to: '/', icon: Staking }, | ||
| { label: 'Governance', to: '/governance', icon: Governance }, | ||
| { label: 'Governance', to: '/governance', icon: Governance, hideInMiniPayUntilStaked: true }, | ||
| { label: 'Delegate', to: '/delegate', icon: Delegate, hideInMiniPay: true }, | ||
| { label: 'Bridge', to: '/bridge', icon: Bridge, hideInMiniPay: true }, | ||
| { label: 'Names', to: 'https://names.celo.org', icon: ENS, hideInMiniPay: true }, | ||
|
|
@@ -30,6 +31,8 @@ export function NavBar({ collapsed }: { collapsed?: boolean }) { | |
| const { address } = useAccount(); | ||
| const trackEvent = useTrackEvent(); | ||
| const isMiniPay = useIsMiniPay(); | ||
| const { lockedBalance } = useLockedBalance(address); | ||
| const hasStaked = lockedBalance > 0n; | ||
|
Comment on lines
+34
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The navbar now calls Useful? React with 👍 / 👎.
Comment on lines
+34
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The MiniPay Governance gate is based on Useful? React with 👍 / 👎. |
||
|
|
||
| const handleNavClick = useCallback( | ||
| (item: string) => { | ||
|
|
@@ -43,6 +46,7 @@ export function NavBar({ collapsed }: { collapsed?: boolean }) { | |
| <ul className="flex list-none items-center justify-center space-x-6 overflow-hidden"> | ||
| {LINKS(!!address) | ||
| .filter((l) => !(isMiniPay && l.hideInMiniPay)) | ||
| .filter((l) => !(isMiniPay && l.hideInMiniPayUntilStaked && !hasStaked)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new MiniPay Governance filter depends on Useful? React with 👍 / 👎. |
||
| .map((l) => { | ||
| const isSelected = l.to === pathname || (l.to !== '/' && pathname?.startsWith(l.to)); | ||
|
|
||
|
|
@@ -77,6 +81,8 @@ export function MobileNavDropdown({ className }: { className?: string }) { | |
| const { address } = useAccount(); | ||
| const trackEvent = useTrackEvent(); | ||
| const isMiniPay = useIsMiniPay(); | ||
| const { lockedBalance } = useLockedBalance(address); | ||
| const hasStaked = lockedBalance > 0n; | ||
|
|
||
| const handleNavClick = useCallback( | ||
| (item: string) => { | ||
|
|
@@ -97,6 +103,7 @@ export function MobileNavDropdown({ className }: { className?: string }) { | |
| menuClasses="space-y-8 py-6 px-8" | ||
| menuItems={LINKS(!!address) | ||
| .filter((l) => !(isMiniPay && l.hideInMiniPay)) | ||
| .filter((l) => !(isMiniPay && l.hideInMiniPayUntilStaked && !hasStaked)) | ||
| .map((l) => { | ||
| return ( | ||
| <Link | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -66,6 +66,10 @@ export function TransactionFlow<FormDefaults extends {}>({ | |
| votingPower.isLoading | ||
| ) { | ||
| Component = <SpinnerWithLabel className="py-20">Loading account data...</SpinnerWithLabel>; | ||
| } else if (confirmationDetails) { | ||
| Component = ( | ||
| <TransactionConfirmation confirmation={confirmationDetails} closeModal={closeModal} /> | ||
| ); | ||
| } else if (!isRegistered && !isVoteSigner && !requiresStCelo && mode === 'CELO') { | ||
| Component = <AccountRegisterForm refetchAccountDetails={refetchAccountDetails} />; | ||
| } else if ( | ||
|
|
@@ -74,10 +78,11 @@ export function TransactionFlow<FormDefaults extends {}>({ | |
| !isVoteSigner && | ||
| !willVoteAndHasVotingPower | ||
| ) { | ||
| Component = <LockForm showTip={true} />; | ||
| header = 'Lock CELO'; | ||
| Component = <LockForm showTip={true} onConfirmed={onConfirmed} />; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Passing Useful? React with 👍 / 👎. |
||
| } else if (requiresStCelo && stCELOBalances.total <= 0n) { | ||
| Component = <StakeStCeloForm showTip={true} />; | ||
| } else if (!confirmationDetails) { | ||
| } else { | ||
| const action = (defaultFormValues as any).action as string; | ||
| if (action) { | ||
| if (action === DelegateActionType.Transfer) { | ||
|
|
@@ -92,10 +97,6 @@ export function TransactionFlow<FormDefaults extends {}>({ | |
| } | ||
|
|
||
| Component = <FormComponent defaultFormValues={defaultFormValues} onConfirmed={onConfirmed} />; | ||
| } else { | ||
| Component = ( | ||
| <TransactionConfirmation confirmation={confirmationDetails} closeModal={closeModal} /> | ||
| ); | ||
| } | ||
|
|
||
| return ( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import { useState } from 'react'; | ||
| import { isAddress } from 'viem'; | ||
|
|
||
| export function useAddressParam(): Address | undefined { | ||
| const [address] = useState(() => { | ||
| if (typeof window === 'undefined') return undefined; | ||
| const param = new URLSearchParams(window.location.search).get('address'); | ||
| if (param && isAddress(param)) return param as Address; | ||
|
Comment on lines
+5
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||
| return undefined; | ||
| }); | ||
| return address; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,12 @@ | ||
| import { useState } from 'react'; | ||
|
|
||
| export function useIsMiniPay() { | ||
| // @ts-ignore | ||
| const [isMiniPay] = useState(() => typeof window !== 'undefined' && !!window.ethereum?.isMiniPay); | ||
| const [isMiniPay] = useState(() => { | ||
| if (typeof window === 'undefined') return false; | ||
| const params = new URLSearchParams(window.location.search); | ||
| if (params.has('minipay')) return params.get('minipay') !== 'false'; | ||
|
Comment on lines
+4
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This hook snapshots Useful? React with 👍 / 👎. |
||
| // @ts-ignore | ||
| return !!window.ethereum?.isMiniPay; | ||
| }); | ||
| return isMiniPay; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new
isReadOnlybranch masks the existing vote-signer UI path, so/?address=<vote-signer>now shows “Viewing account ” even though most balances and tables are still derived fromsigningFor(viauseBalance(signingFor),useLockedStatus(signingFor), etc.). In that scenario the page labels one account while rendering another account’s staking/governance data, which is misleading for shared read-only links. Preserve the vote-signer context (or align data sourcing with the displayed address) in read-only mode.Useful? React with 👍 / 👎.