-
Couldn't load subscription status.
- Fork 452
feat: improve banner logic #2693
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 1 commit
7637fee
ce96b40
d314847
d77ee89
fcad203
33af445
b2f5f50
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 | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,21 +3,55 @@ import { Box } from '@mui/material'; | |||||||||||||||||
| import { useRouter } from 'next/router'; | ||||||||||||||||||
| import React, { ReactNode } from 'react'; | ||||||||||||||||||
| import AnalyticsConsent from 'src/components/Analytics/AnalyticsConsent'; | ||||||||||||||||||
| // import { useModalContext } from 'src/hooks/useModal'; | ||||||||||||||||||
| import { useModalContext } from 'src/hooks/useModal'; | ||||||||||||||||||
| import { SupportModal } from 'src/layouts/SupportModal'; | ||||||||||||||||||
| import { useRootStore } from 'src/store/root'; | ||||||||||||||||||
| import { CustomMarket } from 'src/ui-config/marketsConfig'; | ||||||||||||||||||
| import { getQueryParameter } from 'src/store/utils/queryParams'; | ||||||||||||||||||
| import { CustomMarket, marketsData } from 'src/ui-config/marketsConfig'; | ||||||||||||||||||
| import { FORK_ENABLED } from 'src/utils/marketsAndNetworksConfig'; | ||||||||||||||||||
| import { useShallow } from 'zustand/shallow'; | ||||||||||||||||||
|
|
||||||||||||||||||
| import { AppFooter } from './AppFooter'; | ||||||||||||||||||
| import { AppHeader } from './AppHeader'; | ||||||||||||||||||
| import TopBarNotify from './TopBarNotify'; | ||||||||||||||||||
| import TopBarNotify, { ButtonAction } from './TopBarNotify'; | ||||||||||||||||||
|
|
||||||||||||||||||
| interface CampaignConfig { | ||||||||||||||||||
| notifyText: string; | ||||||||||||||||||
| buttonText: string; | ||||||||||||||||||
| buttonAction: ButtonAction; | ||||||||||||||||||
| bannerVersion: string; | ||||||||||||||||||
| icon: string; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| type CampaignChainId = ChainId.base | ChainId.mainnet | ChainId.arbitrum_one; | ||||||||||||||||||
|
||||||||||||||||||
|
|
||||||||||||||||||
| type CampaignConfigs = Partial<Record<CampaignChainId, CampaignConfig>>; | ||||||||||||||||||
|
|
||||||||||||||||||
| type NetworkCampaigns = { [chainId: number]: CampaignConfig }; | ||||||||||||||||||
|
|
||||||||||||||||||
| const getIntendedChainId = (): ChainId => { | ||||||||||||||||||
| if (typeof window !== 'undefined') { | ||||||||||||||||||
| // Priority 1: localStorage selectedMarket | ||||||||||||||||||
| const selectedMarket = localStorage.getItem('selectedMarket'); | ||||||||||||||||||
| if (selectedMarket && marketsData[selectedMarket as CustomMarket]) { | ||||||||||||||||||
| return marketsData[selectedMarket as CustomMarket].chainId; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Priority 2: URL params marketName | ||||||||||||||||||
| const urlMarket = getQueryParameter('marketName'); | ||||||||||||||||||
| if (urlMarket && marketsData[urlMarket as CustomMarket]) { | ||||||||||||||||||
| return marketsData[urlMarket as CustomMarket].chainId; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Priority 3: Default to mainnet | ||||||||||||||||||
| return ChainId.mainnet; | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
| const getCampaignConfigs = ( | ||||||||||||||||||
| // openSwitch: (underlyingAsset: string) => void, | ||||||||||||||||||
| openSwitch: (underlyingAsset: string, chainId: ChainId) => void, | ||||||||||||||||||
| openMarket: (market: CustomMarket) => void | ||||||||||||||||||
| ) => ({ | ||||||||||||||||||
| ): CampaignConfigs => ({ | ||||||||||||||||||
| [ChainId.base]: { | ||||||||||||||||||
|
||||||||||||||||||
| notifyText: 'A new incentives campaign is live on the Base market', | ||||||||||||||||||
| buttonText: 'Explore Base', | ||||||||||||||||||
|
|
@@ -73,16 +107,16 @@ const getCampaignConfigs = ( | |||||||||||||||||
| // icon: '/icons/networks/avalanche.svg', | ||||||||||||||||||
| // }, | ||||||||||||||||||
|
|
||||||||||||||||||
| // [ChainId.arbitrum_one]: { | ||||||||||||||||||
| // notifyText: 'Swap tokens directly in the Aave App', | ||||||||||||||||||
| // buttonText: 'Swap Now', | ||||||||||||||||||
| // buttonAction: { | ||||||||||||||||||
| // type: 'function' as const, | ||||||||||||||||||
| // value: () => openSwitch('', ChainId.arbitrum_one), | ||||||||||||||||||
| // }, | ||||||||||||||||||
| // bannerVersion: 'arbitrum-swap-v1', | ||||||||||||||||||
| // icon: '/icons/networks/arbitrum.svg', | ||||||||||||||||||
| // }, | ||||||||||||||||||
| [ChainId.arbitrum_one]: { | ||||||||||||||||||
| notifyText: 'Limit orders are now live on Arbitrum', | ||||||||||||||||||
|
||||||||||||||||||
| buttonText: 'Swap Now', | ||||||||||||||||||
| buttonAction: { | ||||||||||||||||||
| type: 'function' as const, | ||||||||||||||||||
| value: () => openSwitch('', ChainId.arbitrum_one), | ||||||||||||||||||
| }, | ||||||||||||||||||
| bannerVersion: 'arbitrum-swap-v1', | ||||||||||||||||||
| icon: '/icons/networks/arbitrum.svg', | ||||||||||||||||||
| }, | ||||||||||||||||||
|
|
||||||||||||||||||
| // [ChainId.optimism]: { | ||||||||||||||||||
| // notifyText: 'Swap tokens directly in the Aave App', | ||||||||||||||||||
|
|
@@ -121,17 +155,28 @@ const getCampaignConfigs = ( | |||||||||||||||||
| export function MainLayout({ children }: { children: ReactNode }) { | ||||||||||||||||||
| const router = useRouter(); | ||||||||||||||||||
| const setCurrentMarket = useRootStore(useShallow((store) => store.setCurrentMarket)); | ||||||||||||||||||
| const { openSwitch } = useModalContext(); | ||||||||||||||||||
|
|
||||||||||||||||||
| const openMarket = (market: CustomMarket) => { | ||||||||||||||||||
| setCurrentMarket(market); | ||||||||||||||||||
| router.push(`/markets/?marketName=${market}`); | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
| const campaignConfigs = getCampaignConfigs(openMarket); | ||||||||||||||||||
| const campaignConfigs = getCampaignConfigs(openSwitch, openMarket); | ||||||||||||||||||
|
||||||||||||||||||
|
|
||||||||||||||||||
| const intendedChainId = getIntendedChainId(); | ||||||||||||||||||
|
|
||||||||||||||||||
| const isCampaignChainId = (chainId: ChainId): chainId is CampaignChainId => { | ||||||||||||||||||
| return chainId in campaignConfigs; | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
| const filteredCampaigns: NetworkCampaigns = isCampaignChainId(intendedChainId) | ||||||||||||||||||
| ? { [intendedChainId]: campaignConfigs[intendedChainId]! } | ||||||||||||||||||
| : {}; | ||||||||||||||||||
|
||||||||||||||||||
| const filteredCampaigns: NetworkCampaigns = isCampaignChainId(intendedChainId) | |
| ? { [intendedChainId]: campaignConfigs[intendedChainId]! } | |
| : {}; | |
| const campaign = campaignConfigs[intendedChainId]; | |
| const filteredCampaigns: NetworkCampaigns = | |
| isCampaignChainId(intendedChainId) && campaign !== undefined | |
| ? { [intendedChainId]: campaign } | |
| : {}; |
Outdated
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.
Keep banner campaigns in sync with market changes
The new filteredCampaigns is derived from getIntendedChainId() using only localStorage/URL and is computed once in MainLayout. Because this component subscribes only to setCurrentMarket, it never re-renders when the user switches markets or when a marketName query param overrides a stale localStorage value. Meanwhile TopBarNotify now shows the first entry it receives, so after the initial render the banner stays locked to whatever chain was chosen at load time (e.g. start on mainnet, switch to Base, but the mainnet campaign continues to display). The banner logic therefore regresses compared to before. Consider deriving the campaign from the store’s currentChainId or recomputing filteredCampaigns when the selected market changes.
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. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -46,16 +46,23 @@ export default function TopBarNotify({ campaigns }: TopBarNotifyProps) { | |||||||||||||||||||
| const mobileDrawerOpen = useRootStore((state) => state.mobileDrawerOpen); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const getCurrentCampaign = (): CampaignConfig | null => { | ||||||||||||||||||||
| return campaigns[currentChainId] || null; | ||||||||||||||||||||
| const chainIds = Object.keys(campaigns).map(Number); | ||||||||||||||||||||
| const firstChainId = chainIds[0]; | ||||||||||||||||||||
| return firstChainId ? campaigns[firstChainId] || null : null; | ||||||||||||||||||||
|
||||||||||||||||||||
| const firstChainId = chainIds[0]; | |
| return firstChainId ? campaigns[firstChainId] || null : null; | |
| if (chainIds.length === 0) return null; | |
| if (currentChainId && campaigns[currentChainId]) { | |
| return campaigns[currentChainId]; | |
| } | |
| // fallback: select the campaign with the lowest chainId | |
| const minChainId = Math.min(...chainIds); | |
| return campaigns[minChainId] || null; |

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.
does it make sense to make the icon optional for future solo-text campaings
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.
yes 33af445