|
1 | 1 | import DOMPurify from 'dompurify' |
2 | | -import { useMarketingBanner } from '../stores/marketingBanner' |
| 2 | +import { useMarketingConfigStore } from '../stores/marketingBanner' |
| 3 | +import JSPath from 'jspath' |
| 4 | +import { useUserPreferences } from 'src/stores/preferences' |
| 5 | +import { getAppVersion } from 'src/utils/Os' |
| 6 | +import { isWebOrExtensionVersion, isProduction, getBrowserName } from 'src/utils/Environment' |
| 7 | +import { useMemo, useState, useEffect } from 'react' |
| 8 | +import { Campaign, MarketingConfig } from '../types' |
| 9 | +import { useGetMarketingConfig } from '../api/getMarketingConfig' |
| 10 | +import { |
| 11 | + trackMarketingCampaignClose, |
| 12 | + trackMarketingCampaignView, |
| 13 | + trackMarketingCampaignOpen, |
| 14 | +} from 'src/lib/analytics' |
| 15 | +import { diffBetweenTwoDatesInDays } from 'src/utils/DateUtils' |
3 | 16 |
|
4 | | -type MarketingBannerProps = { |
5 | | - show: boolean |
6 | | - campaign_name: string |
7 | | - htmlContent: string |
8 | | -} |
9 | | -export const MarketingBanner = ({ campaign_name, show, htmlContent }: MarketingBannerProps) => { |
10 | | - const { setCampaignClosed, closedCampaigns } = useMarketingBanner() |
| 17 | +export const MarketingBanner = () => { |
| 18 | + const { setCampaignClosed, closedCampaigns } = useMarketingConfigStore() |
| 19 | + const { userSelectedTags, cards, firstSeenDate } = useUserPreferences() |
| 20 | + const [availableCampaigns, setAvailableCampaigns] = useState<Campaign[]>([]) |
| 21 | + const { data: marketingConfig } = useGetMarketingConfig({ |
| 22 | + config: { |
| 23 | + staleTime: 60000, |
| 24 | + cacheTime: 3600000, |
| 25 | + }, |
| 26 | + }) |
| 27 | + |
| 28 | + const userAtttributes = useMemo(() => { |
| 29 | + return { |
| 30 | + platform: isWebOrExtensionVersion(), |
| 31 | + browser: getBrowserName(), |
| 32 | + version: getAppVersion() || '0.0.0', |
| 33 | + environment: isProduction() ? 'prod' : 'dev', |
| 34 | + userTags: userSelectedTags.map((tag) => tag.label), |
| 35 | + cards: cards.map((card) => card.name), |
| 36 | + firstSeenDate, |
| 37 | + usageInDays: diffBetweenTwoDatesInDays(firstSeenDate, Date.now()), |
| 38 | + } |
| 39 | + }, [userSelectedTags, firstSeenDate, cards]) |
| 40 | + |
| 41 | + useEffect(() => { |
| 42 | + if (marketingConfig) { |
| 43 | + const availableCampaigns: Campaign[] = getAvailableCampaigns(marketingConfig) |
| 44 | + setAvailableCampaigns(availableCampaigns) |
| 45 | + } |
| 46 | + |
| 47 | + // eslint-disable-next-line react-hooks/exhaustive-deps |
| 48 | + }, [marketingConfig, closedCampaigns, userSelectedTags, cards]) |
| 49 | + |
| 50 | + useEffect(() => { |
| 51 | + if (availableCampaigns.length) { |
| 52 | + trackMarketingCampaignView(availableCampaigns[0].id) |
| 53 | + } |
| 54 | + }, [availableCampaigns]) |
| 55 | + |
| 56 | + if (!marketingConfig) { |
| 57 | + return null |
| 58 | + } |
| 59 | + |
| 60 | + const getAvailableCampaigns = (config: MarketingConfig) => { |
| 61 | + const campaignsWithUserAttr = config.campaigns.map((camp) => { |
| 62 | + return { ...camp, userAtttributes: userAtttributes } |
| 63 | + }) |
| 64 | + |
| 65 | + const lastVisibleAdDate = Math.max(...closedCampaigns.map((camp) => camp.date)) |
| 66 | + if (lastVisibleAdDate > Date.now() - config.campaigns_interval) { |
| 67 | + return [] |
| 68 | + } |
| 69 | + |
| 70 | + const closedCampaignsSet = new Set(closedCampaigns.map((closedCamp) => closedCamp.id)) |
| 71 | + const availableCampaigns = campaignsWithUserAttr |
| 72 | + .filter((camp) => camp.enabled && !closedCampaignsSet.has(camp.id)) |
| 73 | + .flatMap((camp) => JSPath.apply(camp.condition, camp)) |
| 74 | + .sort((a, b) => (a.priority || 0) - (b.priority || 0)) |
| 75 | + .reverse() |
11 | 76 |
|
12 | | - if (!show || closedCampaigns.includes(campaign_name)) { |
| 77 | + return availableCampaigns |
| 78 | + } |
| 79 | + |
| 80 | + if (!marketingConfig.enabled) { |
13 | 81 | return null |
14 | 82 | } |
15 | 83 |
|
16 | | - let cleanHtmlContent = DOMPurify.sanitize(htmlContent) |
| 84 | + if (!availableCampaigns.length) { |
| 85 | + return null |
| 86 | + } |
17 | 87 |
|
18 | | - const onBannerClick = (e: React.MouseEvent<HTMLElement>) => { |
| 88 | + const onBannerClick = (e: React.MouseEvent<HTMLElement>, campaign: Campaign) => { |
19 | 89 | if (e.target instanceof Element) { |
20 | 90 | const closeButton = e.target.closest('.close') |
| 91 | + const ctaButton = e.target.closest('.cta') |
21 | 92 | if (closeButton && e.currentTarget.contains(closeButton)) { |
22 | | - setCampaignClosed(campaign_name) |
| 93 | + setCampaignClosed(campaign.id) |
| 94 | + trackMarketingCampaignClose(campaign.id) |
| 95 | + } else if (ctaButton && e.currentTarget.contains(ctaButton)) { |
| 96 | + trackMarketingCampaignOpen(campaign.id) |
23 | 97 | } |
24 | 98 | } |
25 | 99 | } |
26 | 100 |
|
| 101 | + const currentCampaign = availableCampaigns[0] |
| 102 | + |
27 | 103 | return ( |
28 | | - <div onClick={(e) => onBannerClick(e)} dangerouslySetInnerHTML={{ __html: cleanHtmlContent }} /> |
| 104 | + <div |
| 105 | + id={currentCampaign.id} |
| 106 | + onClick={(e) => onBannerClick(e, currentCampaign)} |
| 107 | + dangerouslySetInnerHTML={{ |
| 108 | + __html: DOMPurify.sanitize(currentCampaign.htmlContent, { |
| 109 | + ADD_ATTR: ['target'], |
| 110 | + USE_PROFILES: { html: true, svg: true }, |
| 111 | + }), |
| 112 | + }} |
| 113 | + /> |
29 | 114 | ) |
30 | 115 | } |
0 commit comments