Feat/BOOK-424 campaign banner
Approved-by: Bianca Widstam
This commit is contained in:
130
apps/scandic-web/components/CampaignBanner/index.tsx
Normal file
130
apps/scandic-web/components/CampaignBanner/index.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
"use client"
|
||||
|
||||
import { usePathname } from "next/navigation"
|
||||
import { useCallback, useEffect, useRef, useState } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
import { useMediaQuery } from "usehooks-ts"
|
||||
|
||||
import { debounce } from "@scandic-hotels/common/utils/debounce"
|
||||
import { IconButton } from "@scandic-hotels/design-system/IconButton"
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { trackClick } from "@scandic-hotels/tracking/base"
|
||||
import { trpc } from "@scandic-hotels/trpc/client"
|
||||
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import { DesktopCampaignBanner } from "./Desktop"
|
||||
import { MobileCampaignBanner } from "./Mobile"
|
||||
import { shouldShowCampaignBanner } from "./utils"
|
||||
|
||||
import styles from "./campaignBanner.module.css"
|
||||
|
||||
export default function CampaignBanner() {
|
||||
const lang = useLang()
|
||||
const intl = useIntl()
|
||||
const pathname = usePathname()
|
||||
const campaignBannerRef = useRef<HTMLDivElement>(null)
|
||||
const isMobile = useMediaQuery("(max-width: 767px)")
|
||||
const [closedPaths, setClosedPaths] = useState<Set<string>>(new Set())
|
||||
const [
|
||||
{ data: siteConfig, isLoading: siteConfigLoading },
|
||||
{ data: campaignBanner, isLoading: campaignBannerLoading },
|
||||
] = trpc.useQueries((t) => [
|
||||
t.contentstack.base.siteConfig({ lang }, { refetchInterval: 60_000 }),
|
||||
t.contentstack.base.sitewideCampaignBanner.get(
|
||||
{ lang },
|
||||
{ refetchInterval: 360_000 }
|
||||
),
|
||||
])
|
||||
const isOnSamePage = pathname === campaignBanner?.link?.url
|
||||
const sitewideAlertType = siteConfig?.sitewideAlert?.type || null
|
||||
const shouldShowBanner = shouldShowCampaignBanner(
|
||||
pathname,
|
||||
lang,
|
||||
closedPaths,
|
||||
sitewideAlertType
|
||||
)
|
||||
const isVisible =
|
||||
!siteConfigLoading &&
|
||||
!campaignBannerLoading &&
|
||||
!!campaignBanner &&
|
||||
shouldShowBanner
|
||||
|
||||
const updateHeightRefCallback = useCallback((node: HTMLDivElement | null) => {
|
||||
if (node) {
|
||||
const debouncedUpdate = debounce(([entry]) => {
|
||||
const height = entry.contentRect.height
|
||||
|
||||
document.documentElement.style.setProperty(
|
||||
"--campaign-banner-height",
|
||||
`${height}px`
|
||||
)
|
||||
}, 100)
|
||||
|
||||
const observer = new ResizeObserver(debouncedUpdate)
|
||||
observer.observe(node)
|
||||
|
||||
return () => {
|
||||
if (node) {
|
||||
observer.unobserve(node)
|
||||
}
|
||||
observer.disconnect()
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isVisible) {
|
||||
document.documentElement.style.removeProperty("--campaign-banner-height")
|
||||
}
|
||||
}, [isVisible])
|
||||
|
||||
if (!isVisible) {
|
||||
return null
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
trackClick("BW close")
|
||||
setClosedPaths((prev) => new Set(prev).add(pathname))
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.campaignBanner}
|
||||
ref={(node) => {
|
||||
campaignBannerRef.current = node
|
||||
return updateHeightRefCallback(node)
|
||||
}}
|
||||
>
|
||||
<div className={styles.content}>
|
||||
{isMobile ? (
|
||||
<MobileCampaignBanner
|
||||
tag={campaignBanner.tag}
|
||||
text={campaignBanner.text}
|
||||
link={isOnSamePage ? null : campaignBanner.link}
|
||||
bookingCode={campaignBanner.booking_code}
|
||||
/>
|
||||
) : (
|
||||
<DesktopCampaignBanner
|
||||
tag={campaignBanner.tag}
|
||||
text={campaignBanner.text}
|
||||
link={isOnSamePage ? null : campaignBanner.link}
|
||||
bookingCode={campaignBanner.booking_code}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
className={styles.closeButton}
|
||||
theme="Inverted"
|
||||
style="Muted"
|
||||
onPress={handleClose}
|
||||
aria-label={intl.formatMessage({
|
||||
id: "campaignBanner.dismissBanner",
|
||||
defaultMessage: "Dismiss banner",
|
||||
})}
|
||||
>
|
||||
<MaterialIcon color="CurrentColor" icon="close" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user