shared-features 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"useCampaigns-BKGqKAUo.cjs","sources":["../src/hooks/useCampaigns.ts"],"sourcesContent":["/**\n * useCampaigns Hook\n *\n * React hook for fetching and displaying campaigns in consumer projects.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { fetchActiveCampaigns, clearCampaignsCache } from '../services/campaigns';\nimport {\n trackImpression,\n trackClick,\n trackClose,\n isEligibleForCampaign,\n} from '../services/analytics';\nimport { isInitialized } from '../firebase/config';\nimport type {\n CampaignWithProduct,\n AdPlacement,\n SmallPanelVariant,\n LargePanelVariant,\n} from '../types/campaigns';\n\nexport interface UseCampaignsOptions {\n /** Placement to fetch campaigns for */\n placement: AdPlacement;\n /** Maximum number of campaigns to fetch */\n maxCampaigns?: number;\n /** Whether to auto-fetch on mount (default: true) */\n autoFetch?: boolean;\n /** Default variant for small placements */\n defaultSmallVariant?: SmallPanelVariant;\n /** Default variant for large placements */\n defaultLargeVariant?: LargePanelVariant;\n}\n\nexport interface UseCampaignsResult {\n /** List of eligible campaigns with product data */\n campaigns: CampaignWithProduct[];\n /** Single campaign (first eligible) - convenience accessor */\n campaign: CampaignWithProduct | null;\n /** Whether campaigns are being fetched */\n loading: boolean;\n /** Error message if fetch failed */\n error: string | null;\n /** Refetch campaigns */\n refetch: () => Promise<void>;\n /** Record impression for a campaign */\n recordImpression: (campaign: CampaignWithProduct) => Promise<void>;\n /** Record click for a campaign */\n recordClick: (campaign: CampaignWithProduct) => Promise<void>;\n /** Record close/dismiss for a campaign */\n recordClose: (campaign: CampaignWithProduct) => Promise<void>;\n}\n\n/**\n * Hook to fetch and manage campaigns for a specific placement\n *\n * @example\n * ```tsx\n * const { campaigns, loading, recordImpression, recordClick } = useCampaigns({\n * placement: 'footer_slider',\n * maxCampaigns: 5,\n * });\n *\n * if (loading) return <Spinner />;\n *\n * return (\n * <AdSlider\n * campaigns={campaigns}\n * onImpression={recordImpression}\n * onClick={recordClick}\n * />\n * );\n * ```\n */\nexport function useCampaigns(options: UseCampaignsOptions): UseCampaignsResult {\n const {\n placement,\n maxCampaigns = 5,\n autoFetch = true,\n defaultSmallVariant = 'small_panel_2',\n defaultLargeVariant: _defaultLargeVariant = 'large_slider_1',\n } = options;\n // Note: _defaultLargeVariant reserved for large variant components\n\n const [campaigns, setCampaigns] = useState<CampaignWithProduct[]>([]);\n const [loading, setLoading] = useState(autoFetch);\n const [error, setError] = useState<string | null>(null);\n\n const fetchCampaigns = useCallback(async () => {\n if (!isInitialized()) {\n setError('shared-features not initialized');\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const allCampaigns = await fetchActiveCampaigns(placement);\n\n // Filter by frequency capping\n const eligibleCampaigns: CampaignWithProduct[] = [];\n\n for (const campaign of allCampaigns) {\n const eligible = await isEligibleForCampaign(\n campaign.id,\n campaign.frequencyDays\n );\n if (eligible) {\n eligibleCampaigns.push(campaign);\n if (eligibleCampaigns.length >= maxCampaigns) break;\n }\n }\n\n setCampaigns(eligibleCampaigns);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to fetch campaigns';\n setError(message);\n console.error('[shared-features] Error fetching campaigns:', err);\n } finally {\n setLoading(false);\n }\n }, [placement, maxCampaigns]);\n\n // Auto-fetch on mount\n useEffect(() => {\n if (autoFetch) {\n fetchCampaigns();\n }\n }, [autoFetch, fetchCampaigns]);\n\n // Record impression\n const handleRecordImpression = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant.startsWith('small_')\n ? campaign.variant\n : campaign.variant.startsWith('large_')\n ? campaign.variant\n : defaultSmallVariant;\n\n await trackImpression(\n campaign.id,\n campaign.productId,\n placement,\n variant,\n campaign.frequencyDays\n );\n },\n [placement, defaultSmallVariant]\n );\n\n // Record click\n const handleRecordClick = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant;\n await trackClick(campaign.id, campaign.productId, placement, variant);\n },\n [placement]\n );\n\n // Record close\n const handleRecordClose = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant;\n await trackClose(campaign.id, campaign.productId, placement, variant);\n },\n [placement]\n );\n\n // Refetch with cache clear\n const refetch = useCallback(async () => {\n clearCampaignsCache();\n await fetchCampaigns();\n }, [fetchCampaigns]);\n\n return {\n campaigns,\n campaign: campaigns[0] || null,\n loading,\n error,\n refetch,\n recordImpression: handleRecordImpression,\n recordClick: handleRecordClick,\n recordClose: handleRecordClose,\n };\n}\n\n/**\n * Hook to fetch a single campaign for a placement\n * Convenience wrapper around useCampaigns\n */\nexport function useCampaign(options: Omit<UseCampaignsOptions, 'maxCampaigns'>) {\n return useCampaigns({ ...options, maxCampaigns: 1 });\n}\n\n// Storage keys for modal hooks\nconst STORAGE_KEYS = {\n oneTimeShown: 'shared_features_onetime_ad_shown',\n appVersion: 'shared_features_app_version',\n} as const;\n\n/**\n * Hook to manage one-time ad modal visibility\n * Shows modal on first visit, then remembers user has seen it\n *\n * @example\n * ```tsx\n * const { shouldShow, markAsShown } = useOneTimeAdModal();\n *\n * if (shouldShow) {\n * return <AdModal onClose={markAsShown} />;\n * }\n * ```\n */\nexport function useOneTimeAdModal() {\n const [hasShown, setHasShown] = useState(false);\n const [shouldShow, setShouldShow] = useState(false);\n\n useEffect(() => {\n // Check if modal has been shown before\n const hasSeenModal = localStorage.getItem(STORAGE_KEYS.oneTimeShown);\n if (!hasSeenModal) {\n setShouldShow(true);\n }\n }, []);\n\n const markAsShown = useCallback(() => {\n localStorage.setItem(STORAGE_KEYS.oneTimeShown, 'true');\n setHasShown(true);\n setShouldShow(false);\n }, []);\n\n return {\n /** Whether the modal should be displayed */\n shouldShow: shouldShow && !hasShown,\n /** Mark the modal as shown (call when user dismisses) */\n markAsShown,\n };\n}\n\n/**\n * Hook to manage update ad modal visibility\n * Shows modal when app version changes\n *\n * @param currentVersion - Current app version (defaults to VITE_APP_VERSION env var or '1.0.0')\n *\n * @example\n * ```tsx\n * const { shouldShow, currentVersion, markAsShown } = useUpdateAdModal();\n *\n * if (shouldShow) {\n * return <AdUpdateModal version={currentVersion} onClose={markAsShown} />;\n * }\n * ```\n */\nexport function useUpdateAdModal(currentVersion?: string) {\n const version = currentVersion || import.meta.env.VITE_APP_VERSION || '1.0.0';\n const [shouldShow, setShouldShow] = useState(false);\n const [previousVersion, setPreviousVersion] = useState<string | null>(null);\n\n useEffect(() => {\n const storedVersion = localStorage.getItem(STORAGE_KEYS.appVersion);\n\n if (!storedVersion) {\n // First time user - store version but don't show update modal\n localStorage.setItem(STORAGE_KEYS.appVersion, version);\n } else if (storedVersion !== version) {\n // Version changed - show update modal\n setShouldShow(true);\n setPreviousVersion(storedVersion);\n }\n }, [version]);\n\n const markAsShown = useCallback(() => {\n localStorage.setItem(STORAGE_KEYS.appVersion, version);\n setShouldShow(false);\n }, [version]);\n\n return {\n /** Whether the modal should be displayed */\n shouldShow,\n /** Previous app version (before update) */\n previousVersion,\n /** Current app version */\n currentVersion: version,\n /** Mark the modal as shown (call when user dismisses) */\n markAsShown,\n };\n}\n"],"names":["useState","useCallback","isInitialized","fetchActiveCampaigns","isEligibleForCampaign","useEffect","trackImpression","trackClick","trackClose","clearCampaignsCache"],"mappings":"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"}
1
+ {"version":3,"file":"useCampaigns-Dltisb9N.cjs","sources":["../src/hooks/useCampaigns.ts"],"sourcesContent":["/**\n * useCampaigns Hook\n *\n * React hook for fetching and displaying campaigns in consumer projects.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { fetchActiveCampaigns, clearCampaignsCache } from '../services/campaigns';\nimport {\n trackImpression,\n trackClick,\n trackClose,\n isEligibleForCampaign,\n} from '../services/analytics';\nimport { isInitialized } from '../firebase/config';\nimport type {\n CampaignWithProduct,\n AdPlacement,\n SmallPanelVariant,\n LargePanelVariant,\n} from '../types/campaigns';\n\nexport interface UseCampaignsOptions {\n /** Placement to fetch campaigns for */\n placement: AdPlacement;\n /** Maximum number of campaigns to fetch */\n maxCampaigns?: number;\n /** Whether to auto-fetch on mount (default: true) */\n autoFetch?: boolean;\n /** Default variant for small placements */\n defaultSmallVariant?: SmallPanelVariant;\n /** Default variant for large placements */\n defaultLargeVariant?: LargePanelVariant;\n}\n\nexport interface UseCampaignsResult {\n /** List of eligible campaigns with product data */\n campaigns: CampaignWithProduct[];\n /** Single campaign (first eligible) - convenience accessor */\n campaign: CampaignWithProduct | null;\n /** Whether campaigns are being fetched */\n loading: boolean;\n /** Error message if fetch failed */\n error: string | null;\n /** Refetch campaigns */\n refetch: () => Promise<void>;\n /** Record impression for a campaign */\n recordImpression: (campaign: CampaignWithProduct) => Promise<void>;\n /** Record click for a campaign */\n recordClick: (campaign: CampaignWithProduct) => Promise<void>;\n /** Record close/dismiss for a campaign */\n recordClose: (campaign: CampaignWithProduct) => Promise<void>;\n}\n\n/**\n * Hook to fetch and manage campaigns for a specific placement\n *\n * @example\n * ```tsx\n * const { campaigns, loading, recordImpression, recordClick } = useCampaigns({\n * placement: 'footer_slider',\n * maxCampaigns: 5,\n * });\n *\n * if (loading) return <Spinner />;\n *\n * return (\n * <AdSlider\n * campaigns={campaigns}\n * onImpression={recordImpression}\n * onClick={recordClick}\n * />\n * );\n * ```\n */\nexport function useCampaigns(options: UseCampaignsOptions): UseCampaignsResult {\n const {\n placement,\n maxCampaigns = 5,\n autoFetch = true,\n defaultSmallVariant = 'small_panel_2',\n defaultLargeVariant: _defaultLargeVariant = 'large_slider_1',\n } = options;\n // Note: _defaultLargeVariant reserved for large variant components\n\n const [campaigns, setCampaigns] = useState<CampaignWithProduct[]>([]);\n const [loading, setLoading] = useState(autoFetch);\n const [error, setError] = useState<string | null>(null);\n\n const fetchCampaigns = useCallback(async () => {\n if (!isInitialized()) {\n setError('shared-features not initialized');\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const allCampaigns = await fetchActiveCampaigns(placement);\n\n // Filter by frequency capping\n const eligibleCampaigns: CampaignWithProduct[] = [];\n\n for (const campaign of allCampaigns) {\n const eligible = await isEligibleForCampaign(\n campaign.id,\n campaign.frequencyDays\n );\n if (eligible) {\n eligibleCampaigns.push(campaign);\n if (eligibleCampaigns.length >= maxCampaigns) break;\n }\n }\n\n setCampaigns(eligibleCampaigns);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to fetch campaigns';\n setError(message);\n console.error('[shared-features] Error fetching campaigns:', err);\n } finally {\n setLoading(false);\n }\n }, [placement, maxCampaigns]);\n\n // Auto-fetch on mount\n useEffect(() => {\n if (autoFetch) {\n fetchCampaigns();\n }\n }, [autoFetch, fetchCampaigns]);\n\n // Record impression\n const handleRecordImpression = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant.startsWith('small_')\n ? campaign.variant\n : campaign.variant.startsWith('large_')\n ? campaign.variant\n : defaultSmallVariant;\n\n await trackImpression(\n campaign.id,\n campaign.productId,\n placement,\n variant,\n campaign.frequencyDays\n );\n },\n [placement, defaultSmallVariant]\n );\n\n // Record click\n const handleRecordClick = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant;\n await trackClick(campaign.id, campaign.productId, placement, variant);\n },\n [placement]\n );\n\n // Record close\n const handleRecordClose = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant;\n await trackClose(campaign.id, campaign.productId, placement, variant);\n },\n [placement]\n );\n\n // Refetch with cache clear\n const refetch = useCallback(async () => {\n clearCampaignsCache();\n await fetchCampaigns();\n }, [fetchCampaigns]);\n\n return {\n campaigns,\n campaign: campaigns[0] || null,\n loading,\n error,\n refetch,\n recordImpression: handleRecordImpression,\n recordClick: handleRecordClick,\n recordClose: handleRecordClose,\n };\n}\n\n/**\n * Hook to fetch a single campaign for a placement\n * Convenience wrapper around useCampaigns\n */\nexport function useCampaign(options: Omit<UseCampaignsOptions, 'maxCampaigns'>) {\n return useCampaigns({ ...options, maxCampaigns: 1 });\n}\n\n// Storage keys for modal hooks\nconst STORAGE_KEYS = {\n oneTimeShown: 'shared_features_onetime_ad_shown',\n appVersion: 'shared_features_app_version',\n} as const;\n\n/**\n * Hook to manage one-time ad modal visibility\n * Shows modal on first visit, then remembers user has seen it\n *\n * @example\n * ```tsx\n * const { shouldShow, markAsShown } = useOneTimeAdModal();\n *\n * if (shouldShow) {\n * return <AdModal onClose={markAsShown} />;\n * }\n * ```\n */\nexport function useOneTimeAdModal() {\n const [hasShown, setHasShown] = useState(false);\n const [shouldShow, setShouldShow] = useState(false);\n\n useEffect(() => {\n // Check if modal has been shown before\n const hasSeenModal = localStorage.getItem(STORAGE_KEYS.oneTimeShown);\n if (!hasSeenModal) {\n setShouldShow(true);\n }\n }, []);\n\n const markAsShown = useCallback(() => {\n localStorage.setItem(STORAGE_KEYS.oneTimeShown, 'true');\n setHasShown(true);\n setShouldShow(false);\n }, []);\n\n return {\n /** Whether the modal should be displayed */\n shouldShow: shouldShow && !hasShown,\n /** Mark the modal as shown (call when user dismisses) */\n markAsShown,\n };\n}\n\n/**\n * Hook to manage update ad modal visibility\n * Shows modal when app version changes\n *\n * @param currentVersion - Current app version (defaults to VITE_APP_VERSION env var or '1.0.0')\n *\n * @example\n * ```tsx\n * const { shouldShow, currentVersion, markAsShown } = useUpdateAdModal();\n *\n * if (shouldShow) {\n * return <AdUpdateModal version={currentVersion} onClose={markAsShown} />;\n * }\n * ```\n */\nexport function useUpdateAdModal(currentVersion?: string) {\n const version = currentVersion || import.meta.env.VITE_APP_VERSION || '1.0.0';\n const [shouldShow, setShouldShow] = useState(false);\n const [previousVersion, setPreviousVersion] = useState<string | null>(null);\n\n useEffect(() => {\n const storedVersion = localStorage.getItem(STORAGE_KEYS.appVersion);\n\n if (!storedVersion) {\n // First time user - store version but don't show update modal\n localStorage.setItem(STORAGE_KEYS.appVersion, version);\n } else if (storedVersion !== version) {\n // Version changed - show update modal\n setShouldShow(true);\n setPreviousVersion(storedVersion);\n }\n }, [version]);\n\n const markAsShown = useCallback(() => {\n localStorage.setItem(STORAGE_KEYS.appVersion, version);\n setShouldShow(false);\n }, [version]);\n\n return {\n /** Whether the modal should be displayed */\n shouldShow,\n /** Previous app version (before update) */\n previousVersion,\n /** Current app version */\n currentVersion: version,\n /** Mark the modal as shown (call when user dismisses) */\n markAsShown,\n };\n}\n"],"names":["useState","useCallback","isInitialized","fetchActiveCampaigns","isEligibleForCampaign","useEffect","trackImpression","trackClick","trackClose","clearCampaignsCache"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { useState, useCallback, useEffect } from "react";
2
- import { e as isInitialized, h as fetchActiveCampaigns, q as isEligibleForCampaign, t as trackImpression, o as trackClick, p as trackClose, m as clearCampaignsCache } from "./analytics-Bbmodnm_.js";
2
+ import { e as isInitialized, h as fetchActiveCampaigns, q as isEligibleForCampaign, t as trackImpression, o as trackClick, p as trackClose, m as clearCampaignsCache } from "./analytics-CdpCtTpu.js";
3
3
  function useCampaigns(options) {
4
4
  const {
5
5
  placement,
@@ -150,4 +150,4 @@ export {
150
150
  useUpdateAdModal as c,
151
151
  useCampaigns as u
152
152
  };
153
- //# sourceMappingURL=useCampaigns-osYDc6WC.js.map
153
+ //# sourceMappingURL=useCampaigns-nwfsALsN.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCampaigns-osYDc6WC.js","sources":["../src/hooks/useCampaigns.ts"],"sourcesContent":["/**\n * useCampaigns Hook\n *\n * React hook for fetching and displaying campaigns in consumer projects.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { fetchActiveCampaigns, clearCampaignsCache } from '../services/campaigns';\nimport {\n trackImpression,\n trackClick,\n trackClose,\n isEligibleForCampaign,\n} from '../services/analytics';\nimport { isInitialized } from '../firebase/config';\nimport type {\n CampaignWithProduct,\n AdPlacement,\n SmallPanelVariant,\n LargePanelVariant,\n} from '../types/campaigns';\n\nexport interface UseCampaignsOptions {\n /** Placement to fetch campaigns for */\n placement: AdPlacement;\n /** Maximum number of campaigns to fetch */\n maxCampaigns?: number;\n /** Whether to auto-fetch on mount (default: true) */\n autoFetch?: boolean;\n /** Default variant for small placements */\n defaultSmallVariant?: SmallPanelVariant;\n /** Default variant for large placements */\n defaultLargeVariant?: LargePanelVariant;\n}\n\nexport interface UseCampaignsResult {\n /** List of eligible campaigns with product data */\n campaigns: CampaignWithProduct[];\n /** Single campaign (first eligible) - convenience accessor */\n campaign: CampaignWithProduct | null;\n /** Whether campaigns are being fetched */\n loading: boolean;\n /** Error message if fetch failed */\n error: string | null;\n /** Refetch campaigns */\n refetch: () => Promise<void>;\n /** Record impression for a campaign */\n recordImpression: (campaign: CampaignWithProduct) => Promise<void>;\n /** Record click for a campaign */\n recordClick: (campaign: CampaignWithProduct) => Promise<void>;\n /** Record close/dismiss for a campaign */\n recordClose: (campaign: CampaignWithProduct) => Promise<void>;\n}\n\n/**\n * Hook to fetch and manage campaigns for a specific placement\n *\n * @example\n * ```tsx\n * const { campaigns, loading, recordImpression, recordClick } = useCampaigns({\n * placement: 'footer_slider',\n * maxCampaigns: 5,\n * });\n *\n * if (loading) return <Spinner />;\n *\n * return (\n * <AdSlider\n * campaigns={campaigns}\n * onImpression={recordImpression}\n * onClick={recordClick}\n * />\n * );\n * ```\n */\nexport function useCampaigns(options: UseCampaignsOptions): UseCampaignsResult {\n const {\n placement,\n maxCampaigns = 5,\n autoFetch = true,\n defaultSmallVariant = 'small_panel_2',\n defaultLargeVariant: _defaultLargeVariant = 'large_slider_1',\n } = options;\n // Note: _defaultLargeVariant reserved for large variant components\n\n const [campaigns, setCampaigns] = useState<CampaignWithProduct[]>([]);\n const [loading, setLoading] = useState(autoFetch);\n const [error, setError] = useState<string | null>(null);\n\n const fetchCampaigns = useCallback(async () => {\n if (!isInitialized()) {\n setError('shared-features not initialized');\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const allCampaigns = await fetchActiveCampaigns(placement);\n\n // Filter by frequency capping\n const eligibleCampaigns: CampaignWithProduct[] = [];\n\n for (const campaign of allCampaigns) {\n const eligible = await isEligibleForCampaign(\n campaign.id,\n campaign.frequencyDays\n );\n if (eligible) {\n eligibleCampaigns.push(campaign);\n if (eligibleCampaigns.length >= maxCampaigns) break;\n }\n }\n\n setCampaigns(eligibleCampaigns);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to fetch campaigns';\n setError(message);\n console.error('[shared-features] Error fetching campaigns:', err);\n } finally {\n setLoading(false);\n }\n }, [placement, maxCampaigns]);\n\n // Auto-fetch on mount\n useEffect(() => {\n if (autoFetch) {\n fetchCampaigns();\n }\n }, [autoFetch, fetchCampaigns]);\n\n // Record impression\n const handleRecordImpression = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant.startsWith('small_')\n ? campaign.variant\n : campaign.variant.startsWith('large_')\n ? campaign.variant\n : defaultSmallVariant;\n\n await trackImpression(\n campaign.id,\n campaign.productId,\n placement,\n variant,\n campaign.frequencyDays\n );\n },\n [placement, defaultSmallVariant]\n );\n\n // Record click\n const handleRecordClick = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant;\n await trackClick(campaign.id, campaign.productId, placement, variant);\n },\n [placement]\n );\n\n // Record close\n const handleRecordClose = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant;\n await trackClose(campaign.id, campaign.productId, placement, variant);\n },\n [placement]\n );\n\n // Refetch with cache clear\n const refetch = useCallback(async () => {\n clearCampaignsCache();\n await fetchCampaigns();\n }, [fetchCampaigns]);\n\n return {\n campaigns,\n campaign: campaigns[0] || null,\n loading,\n error,\n refetch,\n recordImpression: handleRecordImpression,\n recordClick: handleRecordClick,\n recordClose: handleRecordClose,\n };\n}\n\n/**\n * Hook to fetch a single campaign for a placement\n * Convenience wrapper around useCampaigns\n */\nexport function useCampaign(options: Omit<UseCampaignsOptions, 'maxCampaigns'>) {\n return useCampaigns({ ...options, maxCampaigns: 1 });\n}\n\n// Storage keys for modal hooks\nconst STORAGE_KEYS = {\n oneTimeShown: 'shared_features_onetime_ad_shown',\n appVersion: 'shared_features_app_version',\n} as const;\n\n/**\n * Hook to manage one-time ad modal visibility\n * Shows modal on first visit, then remembers user has seen it\n *\n * @example\n * ```tsx\n * const { shouldShow, markAsShown } = useOneTimeAdModal();\n *\n * if (shouldShow) {\n * return <AdModal onClose={markAsShown} />;\n * }\n * ```\n */\nexport function useOneTimeAdModal() {\n const [hasShown, setHasShown] = useState(false);\n const [shouldShow, setShouldShow] = useState(false);\n\n useEffect(() => {\n // Check if modal has been shown before\n const hasSeenModal = localStorage.getItem(STORAGE_KEYS.oneTimeShown);\n if (!hasSeenModal) {\n setShouldShow(true);\n }\n }, []);\n\n const markAsShown = useCallback(() => {\n localStorage.setItem(STORAGE_KEYS.oneTimeShown, 'true');\n setHasShown(true);\n setShouldShow(false);\n }, []);\n\n return {\n /** Whether the modal should be displayed */\n shouldShow: shouldShow && !hasShown,\n /** Mark the modal as shown (call when user dismisses) */\n markAsShown,\n };\n}\n\n/**\n * Hook to manage update ad modal visibility\n * Shows modal when app version changes\n *\n * @param currentVersion - Current app version (defaults to VITE_APP_VERSION env var or '1.0.0')\n *\n * @example\n * ```tsx\n * const { shouldShow, currentVersion, markAsShown } = useUpdateAdModal();\n *\n * if (shouldShow) {\n * return <AdUpdateModal version={currentVersion} onClose={markAsShown} />;\n * }\n * ```\n */\nexport function useUpdateAdModal(currentVersion?: string) {\n const version = currentVersion || import.meta.env.VITE_APP_VERSION || '1.0.0';\n const [shouldShow, setShouldShow] = useState(false);\n const [previousVersion, setPreviousVersion] = useState<string | null>(null);\n\n useEffect(() => {\n const storedVersion = localStorage.getItem(STORAGE_KEYS.appVersion);\n\n if (!storedVersion) {\n // First time user - store version but don't show update modal\n localStorage.setItem(STORAGE_KEYS.appVersion, version);\n } else if (storedVersion !== version) {\n // Version changed - show update modal\n setShouldShow(true);\n setPreviousVersion(storedVersion);\n }\n }, [version]);\n\n const markAsShown = useCallback(() => {\n localStorage.setItem(STORAGE_KEYS.appVersion, version);\n setShouldShow(false);\n }, [version]);\n\n return {\n /** Whether the modal should be displayed */\n shouldShow,\n /** Previous app version (before update) */\n previousVersion,\n /** Current app version */\n currentVersion: version,\n /** Mark the modal as shown (call when user dismisses) */\n markAsShown,\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useCampaigns-nwfsALsN.js","sources":["../src/hooks/useCampaigns.ts"],"sourcesContent":["/**\n * useCampaigns Hook\n *\n * React hook for fetching and displaying campaigns in consumer projects.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { fetchActiveCampaigns, clearCampaignsCache } from '../services/campaigns';\nimport {\n trackImpression,\n trackClick,\n trackClose,\n isEligibleForCampaign,\n} from '../services/analytics';\nimport { isInitialized } from '../firebase/config';\nimport type {\n CampaignWithProduct,\n AdPlacement,\n SmallPanelVariant,\n LargePanelVariant,\n} from '../types/campaigns';\n\nexport interface UseCampaignsOptions {\n /** Placement to fetch campaigns for */\n placement: AdPlacement;\n /** Maximum number of campaigns to fetch */\n maxCampaigns?: number;\n /** Whether to auto-fetch on mount (default: true) */\n autoFetch?: boolean;\n /** Default variant for small placements */\n defaultSmallVariant?: SmallPanelVariant;\n /** Default variant for large placements */\n defaultLargeVariant?: LargePanelVariant;\n}\n\nexport interface UseCampaignsResult {\n /** List of eligible campaigns with product data */\n campaigns: CampaignWithProduct[];\n /** Single campaign (first eligible) - convenience accessor */\n campaign: CampaignWithProduct | null;\n /** Whether campaigns are being fetched */\n loading: boolean;\n /** Error message if fetch failed */\n error: string | null;\n /** Refetch campaigns */\n refetch: () => Promise<void>;\n /** Record impression for a campaign */\n recordImpression: (campaign: CampaignWithProduct) => Promise<void>;\n /** Record click for a campaign */\n recordClick: (campaign: CampaignWithProduct) => Promise<void>;\n /** Record close/dismiss for a campaign */\n recordClose: (campaign: CampaignWithProduct) => Promise<void>;\n}\n\n/**\n * Hook to fetch and manage campaigns for a specific placement\n *\n * @example\n * ```tsx\n * const { campaigns, loading, recordImpression, recordClick } = useCampaigns({\n * placement: 'footer_slider',\n * maxCampaigns: 5,\n * });\n *\n * if (loading) return <Spinner />;\n *\n * return (\n * <AdSlider\n * campaigns={campaigns}\n * onImpression={recordImpression}\n * onClick={recordClick}\n * />\n * );\n * ```\n */\nexport function useCampaigns(options: UseCampaignsOptions): UseCampaignsResult {\n const {\n placement,\n maxCampaigns = 5,\n autoFetch = true,\n defaultSmallVariant = 'small_panel_2',\n defaultLargeVariant: _defaultLargeVariant = 'large_slider_1',\n } = options;\n // Note: _defaultLargeVariant reserved for large variant components\n\n const [campaigns, setCampaigns] = useState<CampaignWithProduct[]>([]);\n const [loading, setLoading] = useState(autoFetch);\n const [error, setError] = useState<string | null>(null);\n\n const fetchCampaigns = useCallback(async () => {\n if (!isInitialized()) {\n setError('shared-features not initialized');\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const allCampaigns = await fetchActiveCampaigns(placement);\n\n // Filter by frequency capping\n const eligibleCampaigns: CampaignWithProduct[] = [];\n\n for (const campaign of allCampaigns) {\n const eligible = await isEligibleForCampaign(\n campaign.id,\n campaign.frequencyDays\n );\n if (eligible) {\n eligibleCampaigns.push(campaign);\n if (eligibleCampaigns.length >= maxCampaigns) break;\n }\n }\n\n setCampaigns(eligibleCampaigns);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to fetch campaigns';\n setError(message);\n console.error('[shared-features] Error fetching campaigns:', err);\n } finally {\n setLoading(false);\n }\n }, [placement, maxCampaigns]);\n\n // Auto-fetch on mount\n useEffect(() => {\n if (autoFetch) {\n fetchCampaigns();\n }\n }, [autoFetch, fetchCampaigns]);\n\n // Record impression\n const handleRecordImpression = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant.startsWith('small_')\n ? campaign.variant\n : campaign.variant.startsWith('large_')\n ? campaign.variant\n : defaultSmallVariant;\n\n await trackImpression(\n campaign.id,\n campaign.productId,\n placement,\n variant,\n campaign.frequencyDays\n );\n },\n [placement, defaultSmallVariant]\n );\n\n // Record click\n const handleRecordClick = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant;\n await trackClick(campaign.id, campaign.productId, placement, variant);\n },\n [placement]\n );\n\n // Record close\n const handleRecordClose = useCallback(\n async (campaign: CampaignWithProduct) => {\n const variant = campaign.variant;\n await trackClose(campaign.id, campaign.productId, placement, variant);\n },\n [placement]\n );\n\n // Refetch with cache clear\n const refetch = useCallback(async () => {\n clearCampaignsCache();\n await fetchCampaigns();\n }, [fetchCampaigns]);\n\n return {\n campaigns,\n campaign: campaigns[0] || null,\n loading,\n error,\n refetch,\n recordImpression: handleRecordImpression,\n recordClick: handleRecordClick,\n recordClose: handleRecordClose,\n };\n}\n\n/**\n * Hook to fetch a single campaign for a placement\n * Convenience wrapper around useCampaigns\n */\nexport function useCampaign(options: Omit<UseCampaignsOptions, 'maxCampaigns'>) {\n return useCampaigns({ ...options, maxCampaigns: 1 });\n}\n\n// Storage keys for modal hooks\nconst STORAGE_KEYS = {\n oneTimeShown: 'shared_features_onetime_ad_shown',\n appVersion: 'shared_features_app_version',\n} as const;\n\n/**\n * Hook to manage one-time ad modal visibility\n * Shows modal on first visit, then remembers user has seen it\n *\n * @example\n * ```tsx\n * const { shouldShow, markAsShown } = useOneTimeAdModal();\n *\n * if (shouldShow) {\n * return <AdModal onClose={markAsShown} />;\n * }\n * ```\n */\nexport function useOneTimeAdModal() {\n const [hasShown, setHasShown] = useState(false);\n const [shouldShow, setShouldShow] = useState(false);\n\n useEffect(() => {\n // Check if modal has been shown before\n const hasSeenModal = localStorage.getItem(STORAGE_KEYS.oneTimeShown);\n if (!hasSeenModal) {\n setShouldShow(true);\n }\n }, []);\n\n const markAsShown = useCallback(() => {\n localStorage.setItem(STORAGE_KEYS.oneTimeShown, 'true');\n setHasShown(true);\n setShouldShow(false);\n }, []);\n\n return {\n /** Whether the modal should be displayed */\n shouldShow: shouldShow && !hasShown,\n /** Mark the modal as shown (call when user dismisses) */\n markAsShown,\n };\n}\n\n/**\n * Hook to manage update ad modal visibility\n * Shows modal when app version changes\n *\n * @param currentVersion - Current app version (defaults to VITE_APP_VERSION env var or '1.0.0')\n *\n * @example\n * ```tsx\n * const { shouldShow, currentVersion, markAsShown } = useUpdateAdModal();\n *\n * if (shouldShow) {\n * return <AdUpdateModal version={currentVersion} onClose={markAsShown} />;\n * }\n * ```\n */\nexport function useUpdateAdModal(currentVersion?: string) {\n const version = currentVersion || import.meta.env.VITE_APP_VERSION || '1.0.0';\n const [shouldShow, setShouldShow] = useState(false);\n const [previousVersion, setPreviousVersion] = useState<string | null>(null);\n\n useEffect(() => {\n const storedVersion = localStorage.getItem(STORAGE_KEYS.appVersion);\n\n if (!storedVersion) {\n // First time user - store version but don't show update modal\n localStorage.setItem(STORAGE_KEYS.appVersion, version);\n } else if (storedVersion !== version) {\n // Version changed - show update modal\n setShouldShow(true);\n setPreviousVersion(storedVersion);\n }\n }, [version]);\n\n const markAsShown = useCallback(() => {\n localStorage.setItem(STORAGE_KEYS.appVersion, version);\n setShouldShow(false);\n }, [version]);\n\n return {\n /** Whether the modal should be displayed */\n shouldShow,\n /** Previous app version (before update) */\n previousVersion,\n /** Current app version */\n currentVersion: version,\n /** Mark the modal as shown (call when user dismisses) */\n markAsShown,\n };\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shared-features",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Shared features for Zaions projects - centralized ads, contacts, feature requests, and more",
5
5
  "author": "Ahsan Mahmood <aoneahsan@gmail.com>",
6
6
  "license": "MIT",
@@ -80,9 +80,9 @@
80
80
  "@radix-ui/themes": "^3.2.1",
81
81
  "@types/react": "^19.2.8",
82
82
  "@types/react-dom": "^19.2.3",
83
- "@vitejs/plugin-react": "^4.7.0",
83
+ "@vitejs/plugin-react": "^5.1.2",
84
84
  "firebase": "^12.8.0",
85
- "lucide-react": "^0.511.0",
85
+ "lucide-react": "^0.562.0",
86
86
  "typescript": "^5.9.3",
87
87
  "vite": "^7.3.1",
88
88
  "vite-plugin-dts": "^4.5.4",
@@ -1 +0,0 @@
1
- {"version":3,"file":"AdBanner-B9918Vst.cjs","sources":["../src/components/ads/AdPanel.tsx","../src/components/ads/variants/SmallPanelVariants.tsx","../src/components/ads/AdSlider.tsx","../src/components/ads/AdModal.tsx","../src/components/ads/variants/LargePanelVariants.tsx","../src/components/ads/AdUpdateModal.tsx","../src/components/ads/AdBanner.tsx"],"sourcesContent":["/**\n * AdPanel Component\n *\n * A simple ad panel component that displays a single campaign.\n * Can be placed in sidebars, footers, or other static locations.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useEffect, useRef } from 'react';\nimport { Box, Flex, Text, Button, IconButton } from '@radix-ui/themes';\nimport { Cross2Icon } from '@radix-ui/react-icons';\nimport { useCampaign } from '../../hooks/useCampaigns';\nimport type { AdPanelProps } from '../../types/campaigns';\n\n/**\n * AdPanel displays a single campaign in a compact panel format.\n *\n * @example\n * ```tsx\n * <AdPanel placement=\"sidebar_panel\" variant=\"small_panel_2\" />\n * ```\n */\nexport function AdPanel({\n placement,\n variant: _variant = 'small_panel_2',\n className,\n}: AdPanelProps) {\n // TODO: variant will be used for different display styles in future variants\n const { campaign, loading, error, recordImpression, recordClick, recordClose } =\n useCampaign({ placement });\n\n const hasRecordedImpression = useRef(false);\n\n // Record impression when campaign is first displayed\n useEffect(() => {\n if (campaign && !hasRecordedImpression.current) {\n hasRecordedImpression.current = true;\n recordImpression(campaign);\n }\n }, [campaign, recordImpression]);\n\n if (loading || error || !campaign) {\n return null;\n }\n\n const handleClick = () => {\n recordClick(campaign);\n const url = campaign.customCtaUrl || campaign.product.url;\n window.open(url, '_blank', 'noopener,noreferrer');\n };\n\n const handleClose = () => {\n recordClose(campaign);\n // Hide the panel (could use state or CSS)\n };\n\n const title = campaign.customTitle || campaign.product.name;\n const tagline = campaign.customTagline || campaign.product.tagline;\n const ctaText = campaign.customCta || 'Learn More';\n const color = campaign.customProductColor || campaign.product.color;\n\n return (\n <Box\n className={className}\n style={{\n border: `1px solid ${color}`,\n borderRadius: '8px',\n padding: '12px',\n backgroundColor: `${color}10`,\n position: 'relative',\n }}\n >\n <IconButton\n size=\"1\"\n variant=\"ghost\"\n onClick={handleClose}\n style={{\n position: 'absolute',\n top: '4px',\n right: '4px',\n }}\n >\n <Cross2Icon />\n </IconButton>\n\n <Flex direction=\"column\" gap=\"2\">\n <Flex align=\"center\" gap=\"2\">\n {campaign.product.icon64 && (\n <Box\n dangerouslySetInnerHTML={{ __html: campaign.product.icon64 }}\n style={{ width: 32, height: 32 }}\n />\n )}\n <Text weight=\"bold\" size=\"3\" style={{ color }}>\n {title}\n </Text>\n </Flex>\n\n <Text size=\"2\" color=\"gray\">\n {tagline}\n </Text>\n\n <Button\n size=\"2\"\n onClick={handleClick}\n style={{ backgroundColor: color }}\n >\n {ctaText}\n </Button>\n </Flex>\n </Box>\n );\n}\n\nexport default AdPanel;\n","/**\n * Small Panel Variants for Advertising\n *\n * 5 variants for small promotional panels:\n * 1. Minimal - Icon + Name + Link\n * 2. Tagline - Icon + Name + Tagline + CTA\n * 3. Features - Icon + Name + Feature pills + CTA\n * 4. Gradient - Full gradient background\n * 5. Card - Elevated card with shadow\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { Box, Flex, Text, Button, Link, Card, Badge } from '@radix-ui/themes';\nimport { ExternalLink, Check, X, Sparkles } from 'lucide-react';\nimport type { CampaignWithProduct, SmallPanelProps } from '../../../types/campaigns';\n\n/**\n * Helper to get display values from campaign\n */\nfunction getDisplayValues(campaign: CampaignWithProduct) {\n const isCustomProduct = !campaign.product.icon64 && campaign.customIcon;\n\n return {\n displayTitle: campaign.customTitle || campaign.product.name,\n displayTagline: campaign.customTagline || campaign.product.tagline,\n displayCta: campaign.customCta || 'Learn More',\n displayUrl: campaign.customCtaUrl || campaign.product.url,\n displayIcon: campaign.customIcon || campaign.product.icon64 || '',\n displayColor: campaign.customProductColor || campaign.product.color || '#3B82F6',\n displayFeatures: campaign.customFeatures || campaign.product.features || [],\n isCustomProduct,\n };\n}\n\n/**\n * Variant 1: Minimal - Icon + Name + Link\n */\nexport function MinimalVariant({ campaign, onCTAClick, onClose }: SmallPanelProps) {\n const { displayTitle, displayCta, displayUrl, displayIcon, displayColor } = getDisplayValues(campaign);\n\n return (\n <Card size=\"1\">\n <Flex align=\"center\" justify=\"between\" gap=\"3\" p=\"2\">\n <Flex align=\"center\" gap=\"3\">\n <Box\n style={{\n width: 32,\n height: 32,\n borderRadius: 'var(--radius-2)',\n background: `color-mix(in srgb, ${displayColor} 15%, transparent)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon }}\n />\n <Text size=\"2\" weight=\"medium\">\n {displayTitle}\n </Text>\n </Flex>\n <Flex align=\"center\" gap=\"2\">\n <Link\n href={displayUrl}\n target=\"_blank\"\n onClick={onCTAClick}\n style={{ textDecoration: 'none' }}\n >\n <Flex align=\"center\" gap=\"1\">\n <Text size=\"2\" color=\"blue\">\n {displayCta}\n </Text>\n <ExternalLink size={14} />\n </Flex>\n </Link>\n <Button variant=\"ghost\" size=\"1\" color=\"gray\" onClick={onClose}>\n <X size={14} />\n </Button>\n </Flex>\n </Flex>\n </Card>\n );\n}\n\n/**\n * Variant 2: Tagline - Icon + Name + Tagline + CTA Button\n */\nexport function TaglineVariant({ campaign, onCTAClick, onClose }: SmallPanelProps) {\n const { displayTitle, displayTagline, displayCta, displayUrl, displayIcon, displayColor } = getDisplayValues(campaign);\n\n return (\n <Card size=\"1\">\n <Flex align=\"center\" justify=\"between\" gap=\"3\" p=\"3\">\n <Flex align=\"center\" gap=\"3\">\n <Box\n style={{\n width: 40,\n height: 40,\n borderRadius: 'var(--radius-2)',\n background: `color-mix(in srgb, ${displayColor} 15%, transparent)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon }}\n />\n <Box>\n <Text size=\"2\" weight=\"bold\">\n {displayTitle}\n </Text>\n <Text size=\"1\" color=\"gray\">\n {displayTagline}\n </Text>\n </Box>\n </Flex>\n <Flex align=\"center\" gap=\"2\">\n <Button\n size=\"1\"\n style={{ background: displayColor }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n {displayCta}\n </Button>\n <Button variant=\"ghost\" size=\"1\" color=\"gray\" onClick={onClose}>\n <X size={14} />\n </Button>\n </Flex>\n </Flex>\n </Card>\n );\n}\n\n/**\n * Variant 3: Features - Icon + Name + Feature pills + CTA\n */\nexport function FeaturesVariant({ campaign, onCTAClick, onClose }: SmallPanelProps) {\n const { displayTitle, displayCta, displayUrl, displayIcon, displayColor, displayFeatures } = getDisplayValues(campaign);\n const features = displayFeatures.slice(0, 2);\n\n return (\n <Card size=\"1\">\n <Flex align=\"center\" justify=\"between\" gap=\"3\" p=\"3\">\n <Flex align=\"center\" gap=\"3\">\n <Box\n style={{\n width: 40,\n height: 40,\n borderRadius: 'var(--radius-2)',\n background: `color-mix(in srgb, ${displayColor} 15%, transparent)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon }}\n />\n <Box>\n <Text size=\"2\" weight=\"bold\" mb=\"1\">\n {displayTitle}\n </Text>\n <Flex gap=\"1\" wrap=\"wrap\">\n {features.map((feature, i) => (\n <Badge key={i} size=\"1\" variant=\"soft\" color=\"gray\">\n <Check size={10} style={{ marginRight: 2 }} />\n {feature}\n </Badge>\n ))}\n </Flex>\n </Box>\n </Flex>\n <Flex align=\"center\" gap=\"2\">\n <Button\n size=\"1\"\n style={{ background: displayColor }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n {displayCta}\n </Button>\n <Button variant=\"ghost\" size=\"1\" color=\"gray\" onClick={onClose}>\n <X size={14} />\n </Button>\n </Flex>\n </Flex>\n </Card>\n );\n}\n\n/**\n * Variant 4: Gradient - Full gradient background\n */\nexport function GradientVariant({ campaign, onCTAClick, onClose }: SmallPanelProps) {\n const { displayTitle, displayTagline, displayCta, displayUrl, displayIcon, displayColor } = getDisplayValues(campaign);\n\n return (\n <Box\n style={{\n background: `linear-gradient(135deg, ${displayColor} 0%, color-mix(in srgb, ${displayColor} 80%, black) 100%)`,\n borderRadius: 'var(--radius-3)',\n padding: 'var(--space-3)',\n color: 'white',\n }}\n >\n <Flex align=\"center\" justify=\"between\" gap=\"3\">\n <Flex align=\"center\" gap=\"3\">\n <Box\n style={{\n width: 40,\n height: 40,\n borderRadius: 'var(--radius-2)',\n background: 'rgba(255, 255, 255, 0.2)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n >\n <Box\n dangerouslySetInnerHTML={{ __html: displayIcon }}\n style={{\n color: 'white',\n }}\n />\n </Box>\n <Box>\n <Text size=\"2\" weight=\"bold\" style={{ color: 'white' }}>\n {displayTitle}\n </Text>\n <Text size=\"1\" style={{ color: 'rgba(255, 255, 255, 0.8)' }}>\n {displayTagline}\n </Text>\n </Box>\n </Flex>\n <Flex align=\"center\" gap=\"2\">\n <Button\n size=\"1\"\n variant=\"soft\"\n style={{\n background: 'white',\n color: displayColor,\n }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n {displayCta}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"1\"\n onClick={onClose}\n style={{ color: 'rgba(255, 255, 255, 0.8)' }}\n >\n <X size={14} />\n </Button>\n </Flex>\n </Flex>\n </Box>\n );\n}\n\n/**\n * Variant 5: Card - Elevated card with shadow and animation\n */\nexport function CardVariant({ campaign, onCTAClick, onClose }: SmallPanelProps) {\n const { displayTitle, displayTagline, displayCta, displayUrl, displayIcon, displayColor } = getDisplayValues(campaign);\n\n return (\n <Card\n size=\"2\"\n style={{\n boxShadow: '0 4px 20px rgba(0, 0, 0, 0.1)',\n transition: 'all 0.2s ease',\n border: `1px solid ${displayColor}20`,\n }}\n >\n <Flex direction=\"column\" gap=\"3\" p=\"1\">\n <Flex align=\"center\" justify=\"between\">\n <Flex align=\"center\" gap=\"1\">\n <Sparkles size={14} color={displayColor} />\n <Text size=\"1\" color=\"gray\" weight=\"medium\">\n RECOMMENDED\n </Text>\n </Flex>\n <Button variant=\"ghost\" size=\"1\" color=\"gray\" onClick={onClose}>\n <X size={14} />\n </Button>\n </Flex>\n\n <Flex align=\"center\" gap=\"3\">\n <Box\n style={{\n width: 48,\n height: 48,\n borderRadius: 'var(--radius-3)',\n background: `color-mix(in srgb, ${displayColor} 15%, transparent)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon }}\n />\n <Box style={{ flex: 1 }}>\n <Text size=\"2\" weight=\"bold\">\n {displayTitle}\n </Text>\n <Text size=\"1\" color=\"gray\">\n {displayTagline}\n </Text>\n </Box>\n </Flex>\n\n <Button\n size=\"2\"\n style={{ background: displayColor, width: '100%' }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n {displayCta}\n <ExternalLink size={14} />\n </Button>\n </Flex>\n </Card>\n );\n}\n\n/**\n * Get variant component by name\n */\nexport const SMALL_PANEL_VARIANTS = {\n small_panel_1: MinimalVariant,\n small_panel_2: TaglineVariant,\n small_panel_3: FeaturesVariant,\n small_panel_4: GradientVariant,\n small_panel_5: CardVariant,\n};\n\nexport type SmallPanelVariantName = keyof typeof SMALL_PANEL_VARIANTS;\n\nexport function getSmallPanelVariant(variantName: string) {\n return SMALL_PANEL_VARIANTS[variantName as SmallPanelVariantName] || TaglineVariant;\n}\n","/**\n * AdSlider Component\n *\n * Small promotional slider panel for consumer apps.\n * Displays eligible ad campaigns using 5 small panel variants.\n *\n * Placement: Footer, sidebar, between sections\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useEffect, useCallback, useRef } from 'react';\nimport { Box } from '@radix-ui/themes';\nimport { useCampaign } from '../../hooks/useCampaigns';\nimport { getSmallPanelVariant } from './variants/SmallPanelVariants';\nimport type { AdPlacement } from '../../types/campaigns';\n\nexport interface AdSliderProps {\n /** Ad placement (defaults to footer_slider) */\n placement?: AdPlacement;\n /** Custom CSS class */\n className?: string;\n /** Custom styles */\n style?: React.CSSProperties;\n}\n\n/**\n * AdSlider - Small promotional panel\n *\n * @example\n * ```tsx\n * <AdSlider placement=\"footer_slider\" />\n * <AdSlider placement=\"sidebar_panel\" className=\"my-ad\" />\n * ```\n */\nexport function AdSlider({\n placement = 'footer_slider',\n className,\n style,\n}: AdSliderProps) {\n const hasTrackedImpression = useRef(false);\n\n const {\n campaign,\n loading,\n recordImpression,\n recordClick,\n recordClose,\n } = useCampaign({ placement });\n\n // Track impression on mount when campaign is available\n useEffect(() => {\n if (campaign && !hasTrackedImpression.current) {\n hasTrackedImpression.current = true;\n recordImpression(campaign);\n }\n }, [campaign, recordImpression]);\n\n // Handle CTA click\n const handleCTAClick = useCallback(() => {\n if (!campaign) return;\n recordClick(campaign);\n }, [campaign, recordClick]);\n\n // Handle close\n const handleClose = useCallback(() => {\n if (!campaign) return;\n recordClose(campaign);\n }, [campaign, recordClose]);\n\n // Don't render if loading or no campaign\n if (loading || !campaign) {\n return null;\n }\n\n // Get variant component\n const variantName = campaign.variant || 'small_panel_2';\n const VariantComponent = getSmallPanelVariant(variantName);\n\n return (\n <Box className={className} style={style}>\n <VariantComponent\n campaign={campaign}\n onCTAClick={handleCTAClick}\n onClose={handleClose}\n />\n </Box>\n );\n}\n\nexport default AdSlider;\n","/**\n * AdModal Component\n *\n * One-time promotional modal for consumer apps.\n * Displays on first visit to promote products.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useEffect, useCallback, useState, useRef } from 'react';\nimport { Box, Flex, Text, Heading, Button, Dialog, Checkbox } from '@radix-ui/themes';\nimport { ExternalLink, X, Gift } from 'lucide-react';\nimport { useCampaign, useOneTimeAdModal } from '../../hooks/useCampaigns';\nimport type { AdPlacement } from '../../types/campaigns';\nimport { getConfig } from '../../firebase/config';\n\nexport interface AdModalProps {\n /** Ad placement (defaults to onetime_modal) */\n placement?: AdPlacement;\n /** Callback when modal closes */\n onClose?: () => void;\n /** Custom welcome title (when no campaign) */\n welcomeTitle?: string;\n /** Custom welcome description (when no campaign) */\n welcomeDescription?: string;\n}\n\n/**\n * AdModal - One-time promotional modal\n *\n * @example\n * ```tsx\n * <AdModal />\n * <AdModal\n * placement=\"onetime_modal\"\n * welcomeTitle=\"Welcome to My App!\"\n * welcomeDescription=\"Discover amazing features...\"\n * />\n * ```\n */\nexport function AdModal({\n placement = 'onetime_modal',\n onClose,\n welcomeTitle,\n welcomeDescription,\n}: AdModalProps) {\n const [dontShowAgain, setDontShowAgain] = useState(false);\n const hasTrackedImpression = useRef(false);\n const config = getConfig();\n\n const { shouldShow, markAsShown } = useOneTimeAdModal();\n\n const {\n campaign,\n loading,\n recordImpression,\n recordClick,\n recordClose,\n } = useCampaign({ placement });\n\n // Track impression when modal shows\n useEffect(() => {\n if (shouldShow && campaign && !hasTrackedImpression.current) {\n hasTrackedImpression.current = true;\n recordImpression(campaign);\n }\n }, [shouldShow, campaign, recordImpression]);\n\n // Handle CTA click\n const handleCTAClick = useCallback(() => {\n if (!campaign) return;\n recordClick(campaign);\n const targetUrl = campaign.customCtaUrl || campaign.product.url;\n window.open(targetUrl, '_blank');\n }, [campaign, recordClick]);\n\n // Handle close\n const handleClose = useCallback(() => {\n if (campaign) {\n recordClose(campaign);\n }\n markAsShown();\n onClose?.();\n }, [campaign, recordClose, markAsShown, onClose]);\n\n // Don't show if not eligible or loading\n if (!shouldShow || loading) {\n return null;\n }\n\n // Show welcome modal without campaign\n if (!campaign) {\n const defaultTitle = welcomeTitle || `Welcome to ${config.projectName}!`;\n const defaultDesc = welcomeDescription || 'Discover amazing features and tools at your fingertips.';\n\n return (\n <Dialog.Root open={true} onOpenChange={(open) => !open && handleClose()}>\n <Dialog.Content style={{ maxWidth: 450 }}>\n <Dialog.Title>\n <Flex align=\"center\" gap=\"2\">\n <Gift size={24} />\n {defaultTitle}\n </Flex>\n </Dialog.Title>\n <Dialog.Description size=\"2\" mb=\"4\">\n {defaultDesc}\n </Dialog.Description>\n\n <Flex gap=\"3\" mt=\"4\" justify=\"end\">\n <Dialog.Close>\n <Button variant=\"soft\" color=\"gray\">\n Start Exploring\n </Button>\n </Dialog.Close>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n }\n\n const { product } = campaign;\n const displayTitle = campaign.customTitle || product.name;\n const displayTagline = campaign.customTagline || product.tagline;\n const displayDescription = campaign.customDescription || product.description;\n const displayCta = campaign.customCta || 'Learn More';\n const displayIcon = campaign.customIcon || product.icon128 || product.icon64 || '';\n const displayColor = campaign.customProductColor || product.color || '#3B82F6';\n const displayFeatures = campaign.customFeatures || product.features || [];\n\n return (\n <Dialog.Root open={true} onOpenChange={(open) => !open && handleClose()}>\n <Dialog.Content style={{ maxWidth: 500 }}>\n <Flex justify=\"end\" mb=\"2\">\n <Dialog.Close>\n <Button variant=\"ghost\" size=\"1\" color=\"gray\">\n <X size={16} />\n </Button>\n </Dialog.Close>\n </Flex>\n\n <Flex direction=\"column\" align=\"center\" gap=\"4\" p=\"4\" style={{ textAlign: 'center' }}>\n <Box\n style={{\n width: 96,\n height: 96,\n borderRadius: 'var(--radius-4)',\n background: `color-mix(in srgb, ${displayColor} 15%, transparent)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon }}\n />\n\n <Box>\n <Heading size=\"5\" weight=\"bold\" mb=\"2\">\n {displayTitle}\n </Heading>\n <Text size=\"3\" color=\"gray\">\n {displayTagline}\n </Text>\n </Box>\n\n <Text size=\"2\" color=\"gray\" style={{ maxWidth: 350, lineHeight: 1.6 }}>\n {displayDescription}\n </Text>\n\n <Flex wrap=\"wrap\" gap=\"2\" justify=\"center\">\n {displayFeatures.slice(0, 4).map((feature, i) => (\n <Box\n key={i}\n style={{\n padding: 'var(--space-1) var(--space-2)',\n borderRadius: 'var(--radius-2)',\n background: 'var(--gray-a3)',\n fontSize: 'var(--font-size-1)',\n }}\n >\n {feature}\n </Box>\n ))}\n </Flex>\n\n <Button\n size=\"3\"\n style={{ background: displayColor, marginTop: 'var(--space-2)' }}\n onClick={handleCTAClick}\n >\n {displayCta}\n <ExternalLink size={16} />\n </Button>\n\n <Flex align=\"center\" gap=\"2\" mt=\"2\">\n <Checkbox\n checked={dontShowAgain}\n onCheckedChange={(checked) => setDontShowAgain(checked === true)}\n />\n <Text size=\"1\" color=\"gray\">\n Don&apos;t show this again\n </Text>\n </Flex>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nexport default AdModal;\n","/**\n * Large Panel Variants for Advertising\n *\n * 5 variants for large promotional panels (modals, sliders):\n * 1. Hero - Large icon + description + CTA\n * 2. Feature Grid - 2x2 grid of features\n * 3. Testimonial - Quote + product info\n * 4. Comparison - Before/After comparison\n * 5. Video - Animated preview + play button\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { Box, Flex, Text, Heading, Button, Card, Grid } from '@radix-ui/themes';\nimport { ExternalLink, Check, X, Play, Quote } from 'lucide-react';\nimport type { CampaignWithProduct, LargePanelProps } from '../../../types/campaigns';\n\n/**\n * Helper to get display values from campaign\n */\nfunction getDisplayValues(campaign: CampaignWithProduct) {\n const isCustomProduct = !campaign.product.icon64 && campaign.customIcon;\n\n return {\n displayTitle: campaign.customTitle || campaign.product.name,\n displayTagline: campaign.customTagline || campaign.product.tagline,\n displayDescription: campaign.customDescription || campaign.product.description,\n displayCta: campaign.customCta || 'Learn More',\n displayUrl: campaign.customCtaUrl || campaign.product.url,\n displayIcon64: campaign.customIcon || campaign.product.icon64 || '',\n displayIcon128: campaign.customIcon || campaign.product.icon128 || campaign.product.icon64 || '',\n displayColor: campaign.customProductColor || campaign.product.color || '#3B82F6',\n displayFeatures: campaign.customFeatures || campaign.product.features || [],\n isCustomProduct,\n };\n}\n\n// Default testimonial quotes (can be overridden by campaign data)\nconst DEFAULT_TESTIMONIALS: Record<string, string> = {\n 'video-controls-plus':\n '\"Finally, I have complete control over video playback. The keyboard shortcuts save me so much time!\"',\n 'ztools-web':\n '\"300+ tools in one place. I use it daily for encoding, formatting, and data conversion tasks.\"',\n 'ztools-extension': '\"Quick access to all my favorite tools right from the browser. Super convenient!\"',\n 'pregnancy-pal-android':\n '\"The weekly updates and kick counter are amazing. Best pregnancy tracking app!\"',\n 'pregnancy-pal-web':\n '\"Love being able to access my pregnancy data from any device. The sync is seamless.\"',\n 'lab-system-web': '\"Streamlined our entire lab workflow. Sample tracking has never been easier.\"',\n};\n\n// Default comparison data (can be overridden by campaign data)\nconst DEFAULT_COMPARISONS: Record<string, { before: string[]; after: string[] }> = {\n 'video-controls-plus': {\n before: ['Limited playback control', 'No keyboard shortcuts', 'Manual ad skipping', 'No speed control'],\n after: ['Full playback control', 'Custom shortcuts', 'Auto ad skip', '0.1x - 16x speed'],\n },\n 'ztools-web': {\n before: ['Multiple websites', 'Scattered tools', 'No offline access', 'Ads everywhere'],\n after: ['One destination', '300+ tools', 'Works offline', 'Ad-free experience'],\n },\n 'ztools-extension': {\n before: ['Open new tabs', 'Search for tools', 'Copy/paste repeatedly', 'Time wasted'],\n after: ['Instant access', 'Quick search', 'One-click actions', 'Time saved'],\n },\n 'pregnancy-pal-android': {\n before: ['Paper tracking', 'Forget updates', 'Manual counting', 'Scattered info'],\n after: ['Digital diary', 'Weekly reminders', 'Auto tracking', 'All in one app'],\n },\n 'pregnancy-pal-web': {\n before: ['Phone only', 'No backup', 'Limited access', 'Data silos'],\n after: ['Any device', 'Cloud sync', 'Always available', 'Unified data'],\n },\n 'lab-system-web': {\n before: ['Paper records', 'Manual tracking', 'Error prone', 'Slow reports'],\n after: ['Digital records', 'Auto tracking', 'Accurate data', 'Instant reports'],\n },\n};\n\n/**\n * Variant 1: Hero - Large icon + description + CTA\n */\nexport function HeroVariant({\n campaign,\n onCTAClick,\n showIndicator,\n currentIndex,\n totalCount,\n}: LargePanelProps) {\n const { displayTitle, displayTagline, displayDescription, displayCta, displayUrl, displayIcon128, displayColor } = getDisplayValues(campaign);\n\n return (\n <Flex direction=\"column\" align=\"center\" gap=\"4\" p=\"5\" style={{ textAlign: 'center' }}>\n {showIndicator && currentIndex !== undefined && totalCount !== undefined && (\n <Text size=\"1\" color=\"gray\" style={{ position: 'absolute', top: 16, right: 16 }}>\n {currentIndex + 1} / {totalCount}\n </Text>\n )}\n\n <Box\n style={{\n width: 80,\n height: 80,\n borderRadius: 'var(--radius-4)',\n background: `color-mix(in srgb, ${displayColor} 15%, transparent)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon128 }}\n />\n\n <Heading size=\"5\" weight=\"bold\">\n {displayTitle}\n </Heading>\n\n <Text size=\"3\" color=\"gray\">\n {displayTagline}\n </Text>\n\n <Text size=\"2\" color=\"gray\" style={{ maxWidth: 300, lineHeight: 1.6 }}>\n {displayDescription}\n </Text>\n\n <Button\n size=\"3\"\n style={{ background: displayColor, marginTop: 'var(--space-2)' }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n {displayCta}\n <ExternalLink size={16} />\n </Button>\n </Flex>\n );\n}\n\n/**\n * Variant 2: Feature Grid - 2x2 grid of features\n */\nexport function FeatureGridVariant({\n campaign,\n onCTAClick,\n showIndicator,\n currentIndex,\n totalCount,\n}: LargePanelProps) {\n const { displayTitle, displayCta, displayUrl, displayIcon64, displayColor, displayFeatures } = getDisplayValues(campaign);\n const features = displayFeatures.slice(0, 4);\n\n return (\n <Flex direction=\"column\" gap=\"4\" p=\"5\">\n {showIndicator && currentIndex !== undefined && totalCount !== undefined && (\n <Text size=\"1\" color=\"gray\" style={{ position: 'absolute', top: 16, right: 16 }}>\n {currentIndex + 1} / {totalCount}\n </Text>\n )}\n\n <Flex align=\"center\" gap=\"3\">\n <Box\n style={{\n width: 48,\n height: 48,\n borderRadius: 'var(--radius-3)',\n background: `color-mix(in srgb, ${displayColor} 15%, transparent)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon64 }}\n />\n <Heading size=\"4\" weight=\"bold\">\n {displayTitle}\n </Heading>\n </Flex>\n\n <Grid columns=\"2\" gap=\"3\">\n {features.map((feature, i) => (\n <Card key={i} size=\"1\" style={{ background: 'var(--gray-a2)' }}>\n <Flex align=\"center\" gap=\"2\" p=\"2\">\n <Flex\n align=\"center\"\n justify=\"center\"\n style={{\n width: 24,\n height: 24,\n borderRadius: '50%',\n background: displayColor,\n color: 'white',\n fontSize: 12,\n fontWeight: 'bold',\n flexShrink: 0,\n }}\n >\n {i + 1}\n </Flex>\n <Text size=\"2\">{feature}</Text>\n </Flex>\n </Card>\n ))}\n </Grid>\n\n <Button\n size=\"3\"\n style={{ background: displayColor, width: '100%' }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n {displayCta}\n <ExternalLink size={16} />\n </Button>\n </Flex>\n );\n}\n\n/**\n * Variant 3: Testimonial - Quote + product info\n */\nexport function TestimonialVariant({\n campaign,\n onCTAClick,\n showIndicator,\n currentIndex,\n totalCount,\n}: LargePanelProps) {\n const { product } = campaign;\n const { displayTitle, displayTagline, displayCta, displayUrl, displayIcon64, displayColor } = getDisplayValues(campaign);\n const quote = DEFAULT_TESTIMONIALS[product.id] || '\"An amazing tool that makes my work easier every day.\"';\n\n return (\n <Flex direction=\"column\" gap=\"4\" p=\"5\" style={{ background: 'var(--gray-a2)', borderRadius: 'var(--radius-3)' }}>\n {showIndicator && currentIndex !== undefined && totalCount !== undefined && (\n <Text size=\"1\" color=\"gray\" style={{ position: 'absolute', top: 16, right: 16 }}>\n {currentIndex + 1} / {totalCount}\n </Text>\n )}\n\n <Box style={{ position: 'relative', padding: 'var(--space-3)' }}>\n <Quote\n size={32}\n style={{\n position: 'absolute',\n top: 0,\n left: '50%',\n transform: 'translateX(-50%)',\n opacity: 0.15,\n color: displayColor,\n }}\n />\n <Text size=\"3\" style={{ fontStyle: 'italic', textAlign: 'center', lineHeight: 1.6 }}>\n {quote}\n </Text>\n <Text size=\"2\" color=\"gray\" style={{ textAlign: 'center', marginTop: 'var(--space-2)' }}>\n — Happy User\n </Text>\n </Box>\n\n <Card size=\"1\">\n <Flex align=\"center\" gap=\"3\" p=\"3\">\n <Box\n style={{\n width: 48,\n height: 48,\n borderRadius: 'var(--radius-3)',\n background: `color-mix(in srgb, ${displayColor} 15%, transparent)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon64 }}\n />\n <Box>\n <Text size=\"2\" weight=\"bold\">\n {displayTitle}\n </Text>\n <Text size=\"1\" color=\"gray\">\n {displayTagline}\n </Text>\n </Box>\n </Flex>\n </Card>\n\n <Button\n size=\"3\"\n style={{ background: displayColor, width: '100%' }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n {displayCta}\n <ExternalLink size={16} />\n </Button>\n </Flex>\n );\n}\n\n/**\n * Variant 4: Comparison - Before/After comparison\n */\nexport function ComparisonVariant({\n campaign,\n onCTAClick,\n showIndicator,\n currentIndex,\n totalCount,\n}: LargePanelProps) {\n const { product } = campaign;\n const { displayTitle, displayCta, displayUrl, displayIcon64, displayColor } = getDisplayValues(campaign);\n const comparison = DEFAULT_COMPARISONS[product.id] || {\n before: ['Old way', 'Manual process', 'Time consuming', 'Limited features'],\n after: ['Better way', 'Automated', 'Fast & easy', 'Full features'],\n };\n\n return (\n <Flex direction=\"column\" gap=\"4\" p=\"5\">\n {showIndicator && currentIndex !== undefined && totalCount !== undefined && (\n <Text size=\"1\" color=\"gray\" style={{ position: 'absolute', top: 16, right: 16 }}>\n {currentIndex + 1} / {totalCount}\n </Text>\n )}\n\n <Flex align=\"center\" gap=\"3\">\n <Box\n style={{\n width: 48,\n height: 48,\n borderRadius: 'var(--radius-3)',\n background: `color-mix(in srgb, ${displayColor} 15%, transparent)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon64 }}\n />\n <Heading size=\"4\" weight=\"bold\">\n {displayTitle}\n </Heading>\n </Flex>\n\n <Flex gap=\"3\">\n <Box\n style={{\n flex: 1,\n padding: 'var(--space-3)',\n borderRadius: 'var(--radius-2)',\n background: 'rgba(239, 68, 68, 0.1)',\n }}\n >\n <Text size=\"1\" weight=\"bold\" color=\"red\" mb=\"2\" style={{ textTransform: 'uppercase' }}>\n Before\n </Text>\n {comparison.before.map((item, i) => (\n <Flex key={i} align=\"center\" gap=\"2\" mb=\"1\">\n <X size={12} color=\"var(--red-9)\" />\n <Text size=\"1\">{item}</Text>\n </Flex>\n ))}\n </Box>\n\n <Box\n style={{\n flex: 1,\n padding: 'var(--space-3)',\n borderRadius: 'var(--radius-2)',\n background: 'rgba(16, 185, 129, 0.1)',\n }}\n >\n <Text size=\"1\" weight=\"bold\" color=\"green\" mb=\"2\" style={{ textTransform: 'uppercase' }}>\n After\n </Text>\n {comparison.after.map((item, i) => (\n <Flex key={i} align=\"center\" gap=\"2\" mb=\"1\">\n <Check size={12} color=\"var(--green-9)\" />\n <Text size=\"1\">{item}</Text>\n </Flex>\n ))}\n </Box>\n </Flex>\n\n <Button\n size=\"3\"\n style={{ background: displayColor, width: '100%' }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n {displayCta}\n <ExternalLink size={16} />\n </Button>\n </Flex>\n );\n}\n\n/**\n * Variant 5: Video - Animated preview + play button\n */\nexport function VideoVariant({\n campaign,\n onCTAClick,\n showIndicator,\n currentIndex,\n totalCount,\n}: LargePanelProps) {\n const { displayTitle, displayTagline, displayCta, displayUrl, displayIcon128, displayColor } = getDisplayValues(campaign);\n\n return (\n <Flex direction=\"column\" align=\"center\" gap=\"4\" p=\"5\" style={{ textAlign: 'center' }}>\n {showIndicator && currentIndex !== undefined && totalCount !== undefined && (\n <Text size=\"1\" color=\"gray\" style={{ position: 'absolute', top: 16, right: 16 }}>\n {currentIndex + 1} / {totalCount}\n </Text>\n )}\n\n <Box\n style={{\n position: 'relative',\n width: 140,\n height: 140,\n borderRadius: 'var(--radius-4)',\n background: `linear-gradient(135deg, color-mix(in srgb, ${displayColor} 20%, transparent), color-mix(in srgb, ${displayColor} 40%, transparent))`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n overflow: 'hidden',\n }}\n >\n <Box\n style={{\n animation: 'shared-features-pulse 2s ease-in-out infinite',\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon128 }}\n />\n <Flex\n align=\"center\"\n justify=\"center\"\n style={{\n position: 'absolute',\n width: 56,\n height: 56,\n borderRadius: '50%',\n background: 'rgba(255, 255, 255, 0.95)',\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.2)',\n cursor: 'pointer',\n transition: 'transform 0.2s ease',\n }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n <Play size={24} fill={displayColor} color={displayColor} />\n </Flex>\n </Box>\n\n <Heading size=\"5\" weight=\"bold\">\n {displayTitle}\n </Heading>\n\n <Text size=\"2\" color=\"gray\">\n {displayTagline}\n </Text>\n\n <Button\n size=\"3\"\n style={{ background: displayColor, marginTop: 'var(--space-2)' }}\n onClick={() => {\n onCTAClick?.();\n window.open(displayUrl, '_blank');\n }}\n >\n {displayCta}\n <ExternalLink size={16} />\n </Button>\n\n <style>{`\n @keyframes shared-features-pulse {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.1); }\n }\n `}</style>\n </Flex>\n );\n}\n\n/**\n * Get variant component by name\n */\nexport const LARGE_PANEL_VARIANTS = {\n large_slider_1: HeroVariant,\n large_slider_2: FeatureGridVariant,\n large_slider_3: TestimonialVariant,\n large_slider_4: ComparisonVariant,\n large_slider_5: VideoVariant,\n};\n\nexport type LargePanelVariantName = keyof typeof LARGE_PANEL_VARIANTS;\n\nexport function getLargePanelVariant(variantName: string) {\n return LARGE_PANEL_VARIANTS[variantName as LargePanelVariantName] || HeroVariant;\n}\n","/**\n * AdUpdateModal Component\n *\n * Big slider modal shown when the app updates.\n * Displays a carousel of promotional campaigns with 5 large variants.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useEffect, useCallback, useState, useRef } from 'react';\nimport { Box, Flex, Text, Button, Dialog, IconButton } from '@radix-ui/themes';\nimport { ChevronLeft, ChevronRight, X } from 'lucide-react';\nimport { useCampaigns, useUpdateAdModal } from '../../hooks/useCampaigns';\nimport { getLargePanelVariant } from './variants/LargePanelVariants';\nimport type { AdPlacement } from '../../types/campaigns';\n\nexport interface AdUpdateModalProps {\n /** Ad placement (defaults to update_modal) */\n placement?: AdPlacement;\n /** Maximum number of campaigns to show */\n maxCampaigns?: number;\n /** Auto-advance interval in ms (0 to disable) */\n autoAdvanceInterval?: number;\n /** Callback when modal closes */\n onClose?: () => void;\n}\n\n/**\n * AdUpdateModal - Big slider promotional modal\n *\n * @example\n * ```tsx\n * <AdUpdateModal />\n * <AdUpdateModal\n * placement=\"update_modal\"\n * maxCampaigns={5}\n * autoAdvanceInterval={5000}\n * />\n * ```\n */\nexport function AdUpdateModal({\n placement = 'update_modal',\n maxCampaigns = 5,\n autoAdvanceInterval = 5000,\n onClose,\n}: AdUpdateModalProps) {\n const [currentIndex, setCurrentIndex] = useState(0);\n const autoAdvanceRef = useRef<NodeJS.Timeout | null>(null);\n const trackedImpressions = useRef<Set<string>>(new Set());\n\n const { shouldShow, currentVersion, markAsShown } = useUpdateAdModal();\n\n const {\n campaigns,\n loading,\n recordImpression,\n recordClick,\n recordClose,\n } = useCampaigns({ placement, maxCampaigns });\n\n // Track impression for current campaign\n useEffect(() => {\n if (shouldShow && campaigns.length > 0 && currentIndex < campaigns.length) {\n const campaign = campaigns[currentIndex];\n if (campaign && !trackedImpressions.current.has(campaign.id)) {\n trackedImpressions.current.add(campaign.id);\n recordImpression(campaign);\n }\n }\n }, [shouldShow, campaigns, currentIndex, recordImpression]);\n\n // Auto-advance carousel\n useEffect(() => {\n if (!shouldShow || campaigns.length <= 1 || autoAdvanceInterval <= 0) return;\n\n autoAdvanceRef.current = setInterval(() => {\n setCurrentIndex((prev) => (prev + 1) % campaigns.length);\n }, autoAdvanceInterval);\n\n return () => {\n if (autoAdvanceRef.current) {\n clearInterval(autoAdvanceRef.current);\n }\n };\n }, [shouldShow, campaigns.length, autoAdvanceInterval]);\n\n // Reset auto-advance on manual navigation\n const resetAutoAdvance = useCallback(() => {\n if (autoAdvanceRef.current) {\n clearInterval(autoAdvanceRef.current);\n }\n if (autoAdvanceInterval > 0 && campaigns.length > 1) {\n autoAdvanceRef.current = setInterval(() => {\n setCurrentIndex((prev) => (prev + 1) % campaigns.length);\n }, autoAdvanceInterval);\n }\n }, [autoAdvanceInterval, campaigns.length]);\n\n // Navigate to previous slide\n const goToPrevious = useCallback(() => {\n setCurrentIndex((prev) => (prev - 1 + campaigns.length) % campaigns.length);\n resetAutoAdvance();\n }, [campaigns.length, resetAutoAdvance]);\n\n // Navigate to next slide\n const goToNext = useCallback(() => {\n setCurrentIndex((prev) => (prev + 1) % campaigns.length);\n resetAutoAdvance();\n }, [campaigns.length, resetAutoAdvance]);\n\n // Navigate to specific slide\n const goToSlide = useCallback(\n (index: number) => {\n setCurrentIndex(index);\n resetAutoAdvance();\n },\n [resetAutoAdvance]\n );\n\n // Handle keyboard navigation\n useEffect(() => {\n if (!shouldShow) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'ArrowLeft') {\n goToPrevious();\n } else if (e.key === 'ArrowRight') {\n goToNext();\n } else if (e.key === 'Escape') {\n handleClose();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [shouldShow, goToPrevious, goToNext]);\n\n // Handle CTA click\n const handleCTAClick = useCallback(() => {\n const campaign = campaigns[currentIndex];\n if (!campaign) return;\n recordClick(campaign);\n }, [campaigns, currentIndex, recordClick]);\n\n // Handle close\n const handleClose = useCallback(() => {\n campaigns.forEach((campaign) => {\n recordClose(campaign);\n });\n markAsShown();\n onClose?.();\n }, [campaigns, recordClose, markAsShown, onClose]);\n\n // Don't show if not eligible or loading\n if (!shouldShow || loading || campaigns.length === 0) {\n return null;\n }\n\n const currentCampaign = campaigns[currentIndex];\n if (!currentCampaign) return null;\n\n const variantName = currentCampaign.variant || 'large_slider_1';\n const VariantComponent = getLargePanelVariant(variantName);\n\n return (\n <Dialog.Root open={true} onOpenChange={(open) => !open && handleClose()}>\n <Dialog.Content\n style={{\n maxWidth: 550,\n padding: 0,\n overflow: 'hidden',\n }}\n >\n {/* Header */}\n <Flex\n align=\"center\"\n justify=\"between\"\n p=\"3\"\n style={{\n borderBottom: '1px solid var(--gray-a5)',\n }}\n >\n <Text size=\"2\" color=\"gray\">\n What&apos;s New in v{currentVersion}\n </Text>\n <Dialog.Close>\n <IconButton variant=\"ghost\" size=\"1\" color=\"gray\">\n <X size={16} />\n </IconButton>\n </Dialog.Close>\n </Flex>\n\n {/* Slider Content */}\n <Box style={{ position: 'relative', minHeight: 350 }}>\n <VariantComponent\n campaign={currentCampaign}\n onCTAClick={handleCTAClick}\n showIndicator={campaigns.length > 1}\n currentIndex={currentIndex}\n totalCount={campaigns.length}\n />\n\n {/* Navigation Arrows */}\n {campaigns.length > 1 && (\n <>\n <IconButton\n variant=\"soft\"\n size=\"2\"\n style={{\n position: 'absolute',\n left: 8,\n top: '50%',\n transform: 'translateY(-50%)',\n opacity: 0.8,\n }}\n onClick={goToPrevious}\n >\n <ChevronLeft size={20} />\n </IconButton>\n <IconButton\n variant=\"soft\"\n size=\"2\"\n style={{\n position: 'absolute',\n right: 8,\n top: '50%',\n transform: 'translateY(-50%)',\n opacity: 0.8,\n }}\n onClick={goToNext}\n >\n <ChevronRight size={20} />\n </IconButton>\n </>\n )}\n </Box>\n\n {/* Footer with Dots */}\n {campaigns.length > 1 && (\n <Flex\n align=\"center\"\n justify=\"center\"\n gap=\"2\"\n p=\"3\"\n style={{\n borderTop: '1px solid var(--gray-a5)',\n }}\n >\n {campaigns.map((_, index) => (\n <Box\n key={index}\n onClick={() => goToSlide(index)}\n style={{\n width: 8,\n height: 8,\n borderRadius: '50%',\n background:\n index === currentIndex ? 'var(--accent-9)' : 'var(--gray-a6)',\n cursor: 'pointer',\n transition: 'all 0.2s ease',\n }}\n />\n ))}\n </Flex>\n )}\n\n {/* Skip All Button */}\n <Flex justify=\"center\" pb=\"3\">\n <Button variant=\"ghost\" size=\"1\" color=\"gray\" onClick={handleClose}>\n Skip All\n </Button>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nexport default AdUpdateModal;\n","/**\n * AdBanner Component (Permanent)\n *\n * A sleek, modern advertising banner that showcases products.\n * Clean design with smooth animations and auto-rotation.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useEffect, useState, useCallback, useRef } from 'react';\nimport { Box, Flex, Text, Button, Badge } from '@radix-ui/themes';\nimport { ExternalLink, Sparkles, Check } from 'lucide-react';\nimport { useCampaigns } from '../../hooks/useCampaigns';\nimport type { AdPlacement, CampaignWithProduct } from '../../types/campaigns';\n\nexport interface AdBannerProps {\n /** Ad placement (defaults to home_banner) */\n placement?: AdPlacement;\n /** Rotation interval in ms (default: 10000 = 10 seconds) */\n rotationInterval?: number;\n /** Maximum number of campaigns to fetch */\n maxCampaigns?: number;\n /** Custom CSS class */\n className?: string;\n /** Custom styles */\n style?: React.CSSProperties;\n}\n\n/**\n * AdBanner - Permanent promotional banner with rotation\n *\n * @example\n * ```tsx\n * <AdBanner />\n * <AdBanner placement=\"home_banner\" rotationInterval={5000} />\n * ```\n */\nexport function AdBanner({\n placement = 'home_banner',\n rotationInterval = 10000,\n maxCampaigns = 5,\n className,\n style,\n}: AdBannerProps) {\n const [currentIndex, setCurrentIndex] = useState(0);\n const [isAnimating, setIsAnimating] = useState(false);\n const [progress, setProgress] = useState(0);\n const trackedImpressions = useRef<Set<string>>(new Set());\n\n const {\n campaigns,\n loading,\n recordImpression,\n recordClick,\n } = useCampaigns({ placement, maxCampaigns });\n\n // Track impression for current campaign\n useEffect(() => {\n if (campaigns.length === 0) return;\n const campaign = campaigns[currentIndex];\n if (!campaign || trackedImpressions.current.has(campaign.id)) return;\n\n trackedImpressions.current.add(campaign.id);\n recordImpression(campaign);\n }, [currentIndex, campaigns, recordImpression]);\n\n // Progress bar animation\n useEffect(() => {\n if (campaigns.length <= 1) return;\n\n setProgress(0);\n const progressInterval = 50;\n const steps = rotationInterval / progressInterval;\n let currentStep = 0;\n\n const progressTimer = setInterval(() => {\n currentStep++;\n setProgress((currentStep / steps) * 100);\n\n if (currentStep >= steps) {\n setIsAnimating(true);\n setTimeout(() => {\n setCurrentIndex((prev) => (prev + 1) % campaigns.length);\n setProgress(0);\n currentStep = 0;\n setTimeout(() => setIsAnimating(false), 50);\n }, 200);\n }\n }, progressInterval);\n\n return () => clearInterval(progressTimer);\n }, [campaigns.length, rotationInterval, currentIndex]);\n\n // Handle click\n const handleClick = useCallback(\n (campaign: CampaignWithProduct) => {\n recordClick(campaign);\n const targetUrl = campaign.customCtaUrl || campaign.product.url;\n window.open(targetUrl, '_blank');\n },\n [recordClick]\n );\n\n // Go to specific slide\n const goToSlide = useCallback((index: number) => {\n if (index === currentIndex) return;\n setIsAnimating(true);\n setTimeout(() => {\n setCurrentIndex(index);\n setProgress(0);\n setTimeout(() => setIsAnimating(false), 50);\n }, 200);\n }, [currentIndex]);\n\n if (loading || campaigns.length === 0) return null;\n\n const campaign = campaigns[currentIndex];\n if (!campaign) return null;\n\n const { product } = campaign;\n const displayTitle = campaign.customTitle || product.name;\n const displayTagline = campaign.customTagline || product.tagline;\n const displayCta = campaign.customCta || 'Learn More';\n const displayColor = campaign.customProductColor || product.color || '#3B82F6';\n const displayIcon = campaign.customIcon || product.icon64 || '';\n const displayFeatures = campaign.customFeatures || product.features || [];\n\n return (\n <Box\n className={className}\n style={{\n background: 'var(--color-background)',\n borderBottom: '1px solid var(--gray-a4)',\n position: 'relative',\n ...style,\n }}\n >\n {/* Colored accent bar */}\n <Box style={{ height: 3, background: displayColor }} />\n\n {/* Main content wrapper */}\n <Box\n style={{\n background: `linear-gradient(90deg, ${displayColor}08 0%, ${displayColor}12 50%, ${displayColor}08 100%)`,\n }}\n >\n {/* Label */}\n <Flex align=\"center\" justify=\"center\" gap=\"2\" py=\"2\">\n <Sparkles size={12} color={displayColor} />\n <Text\n size=\"1\"\n weight=\"medium\"\n style={{\n color: displayColor,\n fontSize: '11px',\n letterSpacing: '1.5px',\n textTransform: 'uppercase',\n }}\n >\n Discover Our Products\n </Text>\n <Sparkles size={12} color={displayColor} />\n </Flex>\n\n {/* Content */}\n <Box px=\"4\" py=\"3\">\n <Flex\n direction={{ initial: 'column', sm: 'row' }}\n align=\"center\"\n justify=\"between\"\n gap={{ initial: '3', sm: '4' }}\n style={{\n opacity: isAnimating ? 0 : 1,\n transform: isAnimating ? 'translateX(-10px)' : 'translateX(0)',\n transition: 'all 0.2s ease-out',\n }}\n >\n {/* Left: Product Info */}\n <Flex align=\"center\" gap=\"3\" style={{ flex: 1, minWidth: 0 }}>\n {/* Icon */}\n <Box\n style={{\n width: 56,\n height: 56,\n borderRadius: 12,\n background: `${displayColor}15`,\n border: `1.5px solid ${displayColor}30`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n }}\n dangerouslySetInnerHTML={{ __html: displayIcon }}\n />\n\n {/* Text */}\n <Flex direction=\"column\" gap=\"0\" style={{ minWidth: 0 }}>\n <Flex align=\"center\" gap=\"2\">\n <Text size=\"3\" weight=\"bold\">\n {displayTitle}\n </Text>\n <Badge\n size=\"1\"\n style={{\n background: `${displayColor}18`,\n color: displayColor,\n fontSize: '11px',\n fontWeight: 600,\n padding: '3px 8px',\n }}\n >\n {product.type === 'extension' ? 'Extension' : product.type === 'android' ? 'App' : 'Web'}\n </Badge>\n </Flex>\n\n <Text\n size=\"2\"\n color=\"gray\"\n style={{\n marginTop: 4,\n display: '-webkit-box',\n WebkitLineClamp: 1,\n WebkitBoxOrient: 'vertical',\n overflow: 'hidden',\n }}\n >\n {displayTagline}\n </Text>\n\n {/* Features - Desktop */}\n <Flex gap=\"4\" mt=\"2\" display={{ initial: 'none', md: 'flex' }}>\n {displayFeatures.slice(0, 3).map((feature, i) => (\n <Flex key={i} align=\"center\" gap=\"1\">\n <Check size={12} color={displayColor} strokeWidth={3} />\n <Text size=\"2\" style={{ color: 'var(--gray-10)' }}>\n {feature}\n </Text>\n </Flex>\n ))}\n </Flex>\n </Flex>\n </Flex>\n\n {/* Right: CTA Button */}\n <Flex align=\"center\" style={{ flexShrink: 0 }}>\n <Button\n size=\"2\"\n onClick={() => handleClick(campaign)}\n style={{\n background: displayColor,\n color: 'white',\n fontWeight: 600,\n fontSize: '14px',\n padding: '0 20px',\n height: 38,\n boxShadow: `0 2px 8px ${displayColor}40`,\n }}\n >\n {displayCta}\n <ExternalLink size={14} style={{ marginLeft: 6 }} />\n </Button>\n </Flex>\n </Flex>\n </Box>\n\n {/* Progress dots with progress bar */}\n {campaigns.length > 1 && (\n <Flex justify=\"center\" align=\"center\" gap=\"2\" py=\"3\">\n {campaigns.map((c, i) => (\n <Box\n key={i}\n onClick={() => goToSlide(i)}\n style={{\n width: 40,\n height: 4,\n borderRadius: 2,\n background: 'var(--gray-a4)',\n cursor: 'pointer',\n overflow: 'hidden',\n position: 'relative',\n }}\n >\n {/* Progress fill */}\n <Box\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n height: '100%',\n width: i === currentIndex ? `${progress}%` : i < currentIndex ? '100%' : '0%',\n background: c.product?.color || displayColor,\n borderRadius: 2,\n transition: i === currentIndex ? 'none' : 'width 0.3s ease',\n }}\n />\n </Box>\n ))}\n </Flex>\n )}\n </Box>\n </Box>\n );\n}\n\nexport default AdBanner;\n"],"names":["useCampaign","useRef","useEffect","jsxs","Box","jsx","IconButton","Cross2Icon","Flex","Text","Button","getDisplayValues","Card","Link","ExternalLink","X","Badge","Check","Sparkles","useCallback","useState","getConfig","useOneTimeAdModal","Dialog","Gift","Heading","Checkbox","Grid","Quote","Play","useUpdateAdModal","useCampaigns","Fragment","ChevronLeft","ChevronRight","campaign"],"mappings":"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"}