Skip to content

Commit

Permalink
Merge pull request #5224 from cowprotocol/release/2024-12-17
Browse files Browse the repository at this point in the history
Release/2024 12 17
  • Loading branch information
anxolin authored Dec 18, 2024
2 parents 25d30bb + 21e8c57 commit d39a42b
Show file tree
Hide file tree
Showing 67 changed files with 847 additions and 380 deletions.
Binary file not shown.
61 changes: 61 additions & 0 deletions apps/cowswap-frontend/src/common/hooks/useAnnouncements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useAtomValue } from 'jotai'
import { useMemo } from 'react'

import { isProdLike } from '@cowprotocol/common-utils'
import { Announcement, Announcements, announcementsAtom } from '@cowprotocol/core'
import { CowEnv, SupportedChainId } from '@cowprotocol/cow-sdk'

function getAnnouncementSpecificity(chainId: SupportedChainId, env: CowEnv, announcement: Announcement): number {
let specificity = 0

const matchesChain = announcement.chainIds.some((announcementChain) => announcementChain === chainId)
const matchesEnv = announcement.envs.some((announcementEnv) => announcementEnv === env)
const matchesEveryChain = announcement.chainIds.length === 0
const matchesEveryEnv = announcement.envs.length === 0

if (matchesChain) specificity += 2
if (matchesEnv) specificity += 2
if (matchesEveryChain) specificity += 1
if (matchesEveryEnv) specificity += 1

return specificity
}

function useAnnouncements(chainId: SupportedChainId): Announcements {
const allAnnouncements = useAtomValue(announcementsAtom)

return useMemo(() => {
const env = isProdLike ? 'prod' : 'staging'

const filtered = allAnnouncements
.filter((announcement) => {
const showForEveryChain = announcement.chainIds.length === 0
const showForEveryEnv = announcement.envs.length === 0

const matchesChainId = announcement.chainIds.some((announcementChain) => announcementChain === chainId)
const matchesEnv = announcement.envs.some((announcementEnv) => announcementEnv === env)

return (showForEveryChain || matchesChainId) && (showForEveryEnv || matchesEnv)
})
.sort((a, b) => {
const specificityA = getAnnouncementSpecificity(chainId, env, a)
const specificityB = getAnnouncementSpecificity(chainId, env, b)

return specificityB - specificityA
})

return filtered
}, [chainId, allAnnouncements])
}

export function useCriticalAnnouncements(chainId: SupportedChainId): Announcements {
const announcements = useAnnouncements(chainId)

return announcements.filter(({ isCritical }) => isCritical)
}

export function useNonCriticalAnnouncements(chainId: SupportedChainId): Announcements {
const announcements = useAnnouncements(chainId)

return announcements.filter(({ isCritical }) => !isCritical)
}
19 changes: 19 additions & 0 deletions apps/cowswap-frontend/src/common/hooks/useCmsAnnouncements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { CmsAnnouncements, getAnnouncements } from '@cowprotocol/core'

import ms from 'ms.macro'
import useSWR, { SWRConfiguration } from 'swr'

const ANNOUNCEMENTS_SWR_CONFIG: SWRConfiguration = {
refreshInterval: ms`5min`, // we do need to show this sort of ASAP
refreshWhenHidden: false,
refreshWhenOffline: false,
revalidateOnFocus: false,
}

const EMPTY_VALUE: CmsAnnouncements = []

export function useCmsAnnouncements() {
const { data } = useSWR<CmsAnnouncements, Error, string>('/announcements', getAnnouncements, ANNOUNCEMENTS_SWR_CONFIG)

return data || EMPTY_VALUE
}
4 changes: 3 additions & 1 deletion apps/cowswap-frontend/src/common/hooks/useCmsSolversInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ const SOLVERS_INFO_SWR_CONFIG: SWRConfiguration = {
revalidateOnFocus: false,
}

const EMPTY_VALUE: CmsSolversInfo = []

export function useCmsSolversInfo() {
const { data } = useSWR<CmsSolversInfo, Error, string>('/solvers', getSolversInfo, SOLVERS_INFO_SWR_CONFIG)

return data || []
return data || EMPTY_VALUE
}
20 changes: 20 additions & 0 deletions apps/cowswap-frontend/src/common/updaters/AnnouncementsUpdater.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useSetAtom } from 'jotai'
import { useEffect } from 'react'

import { announcementsAtom, mapCmsAnnouncementsToAnnouncements } from '@cowprotocol/core'

import { useCmsAnnouncements } from 'common/hooks/useCmsAnnouncements'

export function AnnouncementsUpdater() {
const setAnnouncements = useSetAtom(announcementsAtom)

const cmsAnnouncements = useCmsAnnouncements()

useEffect(() => {
const announcements = mapCmsAnnouncementsToAnnouncements(cmsAnnouncements)

announcements && setAnnouncements(announcements)
}, [cmsAnnouncements, setAnnouncements])

return null
}
Original file line number Diff line number Diff line change
@@ -1,54 +1,41 @@
import { useFetchFile } from '@cowprotocol/common-hooks'
import { hashCode } from '@cowprotocol/common-utils'
import { environmentName } from '@cowprotocol/common-utils'
import { hashCode, isInjectedWidget } from '@cowprotocol/common-utils'
import { SupportedChainId as ChainId } from '@cowprotocol/cow-sdk'
import { ClosableBanner } from '@cowprotocol/ui'
import { useWalletInfo } from '@cowprotocol/wallet'

import ReactMarkdown, { Components } from 'react-markdown'

import { useCriticalAnnouncements, useNonCriticalAnnouncements } from 'common/hooks/useAnnouncements'
import { GlobalWarning } from 'common/pure/GlobalWarning'

import { markdownComponents } from '../../Markdown/components'

// Announcement content: Modify this repository to edit the announcement
const ANNOUNCEMENTS_MARKDOWN_BASE_URL = 'https://raw.githubusercontent.com/cowprotocol/cowswap-banner/main'

const BANNER_STORAGE_KEY = 'announcementBannerClosed/'

const PRODUCTION_ENVS: (typeof environmentName)[] = ['production', 'staging', 'ens']

function getAnnouncementUrl(chainId: number, env?: 'production' | 'barn') {
return `${ANNOUNCEMENTS_MARKDOWN_BASE_URL}${env ? `/${env}` : ''}/announcements-${chainId}.md`
}

function useGetAnnouncement(chainId: number): string | undefined {
const env = PRODUCTION_ENVS.includes(environmentName) ? 'production' : 'barn'

// Fetches global announcement
const { file, error } = useFetchFile(getAnnouncementUrl(chainId))
// Fetches env announcement
const { file: envFile, error: envError } = useFetchFile(getAnnouncementUrl(chainId, env))

const announcementText = error ? undefined : file?.trim()

if (error) {
console.error('[URLWarning] Error getting the announcement text: ', error)
}
function useGetCmsAnnouncement(chainId: number): string | undefined {
const critical = useCriticalAnnouncements(chainId)
const nonCritical = useNonCriticalAnnouncements(chainId)

const envAnnouncementText = envError ? undefined : envFile?.trim()
const isWidget = isInjectedWidget()

if (envError) {
console.error(`[URLWarning] Error getting the env ${env} announcement text: `, envError)
// Critical takes priority
if (critical.length) {
// Assume only one announcement can be displayed for now
return critical[0].text
} else if (!isWidget && nonCritical.length) {
// Non-critical can only be displayed when not in the widget
return nonCritical[0].text
}

return announcementText || envAnnouncementText
return
}

export function URLWarning() {
const { chainId = ChainId.MAINNET } = useWalletInfo()

const announcementText = useGetAnnouncement(chainId)
const announcementText = useGetCmsAnnouncement(chainId)
const contentHash = announcementText ? hashCode(announcementText).toString() : undefined

if (!announcementText) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
useHideReceiverWalletBanner,
useIsReceiverWalletBannerHidden,
} from 'common/state/receiverWalletBannerVisibility'
import { getIsCustomRecipient } from 'utils/orderUtils/getIsCustomRecipient'
import { getUiOrderType } from 'utils/orderUtils/getUiOrderType'

import { StatusDetails } from './StatusDetails'
Expand Down Expand Up @@ -298,7 +299,7 @@ export function ActivityDetails(props: {
outputToken = COW[chainId as SupportedChainId]
}

const isCustomRecipient = Boolean(order?.receiver && order.owner !== order.receiver)
const isCustomRecipient = !!order && getIsCustomRecipient(order)

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import { EthFlowDeadlineUpdater } from 'modules/swap/state/EthFlow/updaters'
import { useOnTokenListAddingError } from 'modules/tokensList'
import { TradeType, useTradeTypeInfo } from 'modules/trade'
import { UsdPricesUpdater } from 'modules/usdAmount'
import { TaxFreeAssetsUpdater } from 'modules/volumeFee'
import { LpTokensWithBalancesUpdater, PoolsInfoUpdater, VampireAttackUpdater } from 'modules/yield/shared'

import { ProgressBarV2ExecutingOrdersUpdater } from 'common/hooks/orderProgressBarV2'
import { TotalSurplusUpdater } from 'common/state/totalSurplusState'
import { AnnouncementsUpdater } from 'common/updaters/AnnouncementsUpdater'
import { FeatureFlagsUpdater } from 'common/updaters/FeatureFlagsUpdater'
import { FeesUpdater } from 'common/updaters/FeesUpdater'
import { GasUpdater } from 'common/updaters/GasUpdater'
Expand Down Expand Up @@ -70,6 +72,7 @@ export function Updaters() {
<OrdersNotificationsUpdater />
<ProgressBarV2ExecutingOrdersUpdater />
<SolversInfoUpdater />
<AnnouncementsUpdater />

<TokensListsUpdater
chainId={chainId}
Expand All @@ -92,6 +95,7 @@ export function Updaters() {
<LpTokensWithBalancesUpdater />
<VampireAttackUpdater />
<BalancesCombinedUpdater />
<TaxFreeAssetsUpdater />
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { ACTIVE_CUSTOM_THEME, CustomTheme } from '@cowprotocol/common-const'
import { useMediaQuery } from '@cowprotocol/common-hooks'
import { useFeatureFlags } from '@cowprotocol/common-hooks'
import { isInjectedWidget } from '@cowprotocol/common-utils'
import { Color, Footer, GlobalCoWDAOStyles, Media, MenuBar, CowSwapTheme } from '@cowprotocol/ui'
import { Color, Footer, GlobalCoWDAOStyles, Media, MenuBar } from '@cowprotocol/ui'

import SVG from 'react-inlinesvg'
import { NavLink } from 'react-router-dom'
import Snowfall from 'react-snowfall'
import { ThemeProvider } from 'theme'

import ErrorBoundary from 'legacy/components/ErrorBoundary'
Expand Down Expand Up @@ -53,8 +54,7 @@ export function App() {
useAnalyticsReporterCowSwap()
useInitializeUtm()

const featureFlags = useFeatureFlags()
const { isYieldEnabled } = featureFlags
const { isYieldEnabled, isChristmasEnabled, isHalloweenEnabled } = useFeatureFlags()

const isInjectedWidgetMode = isInjectedWidget()
const menuItems = useMenuItems()
Expand Down Expand Up @@ -97,11 +97,14 @@ export function App() {
const { pendingActivity } = useCategorizeRecentActivity()
const isMobile = useMediaQuery(Media.upToMedium(false))
const customTheme = useMemo(() => {
if (ACTIVE_CUSTOM_THEME === CustomTheme.HALLOWEEN && darkMode && featureFlags.isHalloweenEnabled) {
return 'darkHalloween' as CowSwapTheme
if (ACTIVE_CUSTOM_THEME === CustomTheme.HALLOWEEN && darkMode && isHalloweenEnabled) {
return 'darkHalloween'
}
if (ACTIVE_CUSTOM_THEME === CustomTheme.CHRISTMAS && isChristmasEnabled) {
return darkMode ? 'darkChristmas' : 'lightChristmas'
}
return undefined
}, [darkMode, featureFlags.isHalloweenEnabled])
}, [darkMode, isHalloweenEnabled, isChristmasEnabled])

const persistentAdditionalContent = (
<HeaderControls>
Expand All @@ -112,6 +115,8 @@ export function App() {
</HeaderControls>
)

const isChristmasTheme = ACTIVE_CUSTOM_THEME === CustomTheme.CHRISTMAS && isChristmasEnabled

return (
<ErrorBoundary>
<Suspense fallback={<LoadingApp />}>
Expand Down Expand Up @@ -151,12 +156,28 @@ export function App() {

<styledEl.BodyWrapper customTheme={customTheme}>
<TopLevelModals />

<RoutesApp />

<styledEl.Marginer />
</styledEl.BodyWrapper>

{!isInjectedWidgetMode && isChristmasTheme && (
<Snowfall
style={{
position: 'fixed',
width: '100vw',
height: '100vh',
zIndex: 3,
pointerEvents: 'none',
top: 0,
left: 0,
}}
snowflakeCount={isMobile ? 25 : darkMode ? 75 : 200}
radius={[0.5, 2.0]}
speed={[0.5, 2.0]}
wind={[-0.5, 1.0]}
/>
)}

{!isInjectedWidgetMode && (
<Footer
productVariant={PRODUCT_VARIANT}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import IMAGE_BACKGROUND_DARK_CHRISTMAS_MEDIUM from '@cowprotocol/assets/images/background-cowswap-christmas-dark-medium.svg'
import IMAGE_BACKGROUND_DARK_CHRISTMAS_SMALL from '@cowprotocol/assets/images/background-cowswap-christmas-dark-small.svg'
import IMAGE_BACKGROUND_DARK_CHRISTMAS from '@cowprotocol/assets/images/background-cowswap-christmas-dark.svg'
import IMAGE_BACKGROUND_LIGHT_CHRISTMAS_MEDIUM from '@cowprotocol/assets/images/background-cowswap-christmas-light-medium.svg'
import IMAGE_BACKGROUND_LIGHT_CHRISTMAS_SMALL from '@cowprotocol/assets/images/background-cowswap-christmas-light-small.svg'
import IMAGE_BACKGROUND_LIGHT_CHRISTMAS from '@cowprotocol/assets/images/background-cowswap-christmas-light.svg'
import IMAGE_BACKGROUND_DARK from '@cowprotocol/assets/images/background-cowswap-darkmode.svg'
import IMAGE_BACKGROUND_DARK_HALLOWEEN_MEDIUM from '@cowprotocol/assets/images/background-cowswap-halloween-dark-medium.svg'
import IMAGE_BACKGROUND_DARK_HALLOWEEN_SMALL from '@cowprotocol/assets/images/background-cowswap-halloween-dark-small.svg'
Expand All @@ -8,6 +14,14 @@ import { CowSwapTheme, Media } from '@cowprotocol/ui'
import * as CSS from 'csstype'
import styled from 'styled-components/macro'

function isChristmasTheme(theme?: CowSwapTheme) {
if (!theme) {
return false
}

return ['darkChristmas', 'lightChristmas'].includes(theme)
}

export const AppWrapper = styled.div<Partial<CSS.Properties>>`
display: flex;
flex-flow: column;
Expand Down Expand Up @@ -42,8 +56,12 @@ export const BodyWrapper = styled.div<{ customTheme?: CowSwapTheme }>`
const backgroundColor = theme.darkMode ? '#0E0F2D' : '#65D9FF'
let backgroundImage
if (customTheme === ('darkHalloween' as CowSwapTheme)) {
if (customTheme === 'darkHalloween') {
backgroundImage = `url(${IMAGE_BACKGROUND_DARK_HALLOWEEN})`
} else if (isChristmasTheme(customTheme)) {
backgroundImage = theme.darkMode
? `url(${IMAGE_BACKGROUND_DARK_CHRISTMAS})`
: `url(${IMAGE_BACKGROUND_LIGHT_CHRISTMAS})`
} else {
backgroundImage = theme.darkMode ? `url(${IMAGE_BACKGROUND_DARK})` : `url(${IMAGE_BACKGROUND_LIGHT})`
}
Expand All @@ -59,20 +77,32 @@ export const BodyWrapper = styled.div<{ customTheme?: CowSwapTheme }>`
background-size: auto;
${({ customTheme }) =>
customTheme === ('darkHalloween' as CowSwapTheme) &&
customTheme === 'darkHalloween' &&
`
background-image: url(${IMAGE_BACKGROUND_DARK_HALLOWEEN_MEDIUM});
`}
${({ customTheme, theme }) =>
isChristmasTheme(customTheme) &&
`
background-image: url(${theme.darkMode ? IMAGE_BACKGROUND_DARK_CHRISTMAS_MEDIUM : IMAGE_BACKGROUND_LIGHT_CHRISTMAS_MEDIUM});
`}
}
${Media.upToSmall()} {
padding: ${({ theme }) => (theme.isInjectedWidgetMode ? '0 0 16px' : '90px 16px 76px')};
min-height: ${({ theme }) => (theme.isInjectedWidgetMode ? 'initial' : 'calc(100vh - 100px)')};
${({ customTheme }) =>
customTheme === ('darkHalloween' as CowSwapTheme) &&
customTheme === 'darkHalloween' &&
`
background-image: url(${IMAGE_BACKGROUND_DARK_HALLOWEEN_SMALL});
`}
${({ customTheme, theme }) =>
isChristmasTheme(customTheme) &&
`
background-image: url(${theme.darkMode ? IMAGE_BACKGROUND_DARK_CHRISTMAS_SMALL : IMAGE_BACKGROUND_LIGHT_CHRISTMAS_SMALL});
`}
}
`
Loading

0 comments on commit d39a42b

Please sign in to comment.