const { useEffect: useEffectSR, useRef: useRefSR, useState: useStateSR } = React; const ALL_COMPETITORS_ID = '__all_competitors__'; const FOREPLAY_PUBLISHER_OPTIONS = [ ['facebook', 'Facebook'], ['instagram', 'Instagram'], ['tiktok', 'TikTok'], ['youtube', 'YouTube'], ]; const FOREPLAY_LANGUAGE_OPTIONS = [ ['en', 'English'], ['es', 'Spanish'], ['fr', 'French'], ['de', 'German'], ['pt', 'Portuguese'], ['it', 'Italian'], ['nl', 'Dutch'], ['ar', 'Arabic'], ['hi', 'Hindi'], ]; const ADSPY_CTA_OPTIONS = [ 'Learn More', 'Shop Now', 'Sign Up', 'Send Message', ]; const splitFilterList = (value) => String(value || '').split(',').map(s => s.trim()).filter(Boolean); const selectedValues = (event) => Array.from(event.target.selectedOptions || []).map(o => o.value).filter(Boolean); const joinFilterList = (values) => [...new Set((values || []).map(v => String(v || '').trim()).filter(Boolean))].join(', '); const ADSPY_COUNTRY_OPTIONS = ['US', 'UK', 'CA', 'AU', 'DE', 'FR', 'ES', 'IT', 'NL', 'BR']; const ADSPY_LANGUAGE_OPTIONS = [ ['eng', 'English'], ['spa', 'Spanish'], ['fre', 'French'], ['ger', 'German'], ['por', 'Portuguese'], ['ita', 'Italian'], ['dut', 'Dutch'], ]; const ADSPY_DROPDOWN_LABELS = [ 'siteType', 'gender', 'ages', 'dailyLikes', 'totalLikes', 'mediaType', 'createdBetween', 'seenBetween', 'networks', 'affiliate', 'advertiser', 'technologies', 'countries', 'language', 'buttons', ]; const adspyFilterIsActive = (filters, id) => { if (id === 'siteType') return !!filters.adspySiteType; if (id === 'mediaType') return !!filters.adspyMediaType; if (id === 'gender') return !!filters.adspyGender; if (id === 'ages') return !!(filters.adspyAgeMin || filters.adspyAgeMax); if (id === 'dailyLikes') return !!(filters.minDailyLikes || filters.maxDailyLikes); if (id === 'totalLikes') return !!(filters.minLikes || filters.maxLikes); if (id === 'createdBetween') return !!(filters.adspyCreatedFrom || filters.adspyCreatedTo); if (id === 'seenBetween') return !!(filters.adspySeenFrom || filters.adspySeenTo); if (id === 'networks') return !!filters.adspyAffNetwork; if (id === 'affiliate') return !!(filters.adspyAffId || filters.adspyOfferId); if (id === 'advertiser') return !!(filters.adspyUsername || filters.adspyUserId); if (id === 'technologies') return !!filters.adspyTech; if (id === 'countries') return !!filters.adspyCountries; if (id === 'language') return !!filters.adspyLang; if (id === 'buttons') return filters.adspyCtaMode === 'custom' || !!filters.adspyButtons; return false; }; const optionLabel = (options, value) => { const match = (options || []).find(option => { const optionValue = Array.isArray(option) ? option[0] : option; return String(optionValue) === String(value); }); if (!match) return value ? String(value) : ''; return Array.isArray(match) ? match[1] : match; }; const compactListPreview = (value, options, maxItems = 2) => { const values = splitFilterList(value); if (!values.length) return ''; const labels = values.map(item => optionLabel(options, item)).filter(Boolean); if (labels.length <= maxItems) return labels.join(', '); return `${labels.slice(0, maxItems).join(', ')} +${labels.length - maxItems}`; }; const rangePreview = (minValue, maxValue, { defaultMin = '', defaultMax = '', suffix = '' } = {}) => { const minText = minValue || defaultMin; const maxText = maxValue || defaultMax; if (!minValue && !maxValue) return ''; if (minText && maxText) return `${minText}-${maxText}${suffix}`; if (minText) return `Min ${minText}${suffix}`; return `Max ${maxText}${suffix}`; }; const numberPreview = (value) => { const parsed = Number(value); return Number.isFinite(parsed) ? parsed.toLocaleString() : String(value || ''); }; const AdspyDropdown = ({ id, label, preview, active, open, onToggle, onClose, onReset, children }) => { const dropdownRef = useRefSR(null); useEffectSR(() => { if (!open) return undefined; const onMouseDown = (event) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { onClose?.(); } }; const onKeyDown = (event) => { if (event.key === 'Escape') onClose?.(); }; document.addEventListener('mousedown', onMouseDown); document.addEventListener('keydown', onKeyDown); return () => { document.removeEventListener('mousedown', onMouseDown); document.removeEventListener('keydown', onKeyDown); }; }, [open, onClose]); return (
{open && (
{children}
)}
); }; const AdspyRadio = ({ name, value, options, onChange }) => (
{options.map(([optionValue, label]) => ( ))}
); const AdspyChecks = ({ values, options, onChange }) => { const selected = new Set(splitFilterList(values)); const toggle = (value) => { const next = new Set(selected); next.has(value) ? next.delete(value) : next.add(value); onChange(joinFilterList([...next])); }; return (
{options.map(option => { const value = Array.isArray(option) ? option[0] : option; const label = Array.isArray(option) ? option[1] : option; return ( ); })}
); }; const RANGE_UI_MAX = 1000; const LARGE_RANGE_CURVE = 2.4; const curvedRangeEnabled = (min, max) => min === 0 && max > 100; const valueToSliderPosition = (value, max) => Math.round( Math.pow(Math.max(0, Math.min(max, value)) / max, 1 / LARGE_RANGE_CURVE) * RANGE_UI_MAX, ); const sliderPositionToValue = (position, max) => Math.round( max * Math.pow(Math.max(0, Math.min(RANGE_UI_MAX, position)) / RANGE_UI_MAX, LARGE_RANGE_CURVE), ); const AdspyRange = ({ label, min, max, value, onChange }) => { const numeric = Math.max(min, Math.min(max, parseInt(value, 10) || min)); const useCurvedScale = curvedRangeEnabled(min, max); const sliderValue = useCurvedScale ? valueToSliderPosition(numeric, max) : numeric; const sliderMax = useCurvedScale ? RANGE_UI_MAX : max; const displayValue = numeric.toLocaleString(); return ( ); }; const AdspyText = ({ label, value, onChange, type = 'text' }) => ( ); window.PlatformFilterSections = function PlatformFilterSections({ filters = {}, platforms = {}, onFilterChange, onFiltersChange, idPrefix = 'filters', }) { const [openForeplayFilter, setOpenForeplayFilter] = useStateSR(null); const [openAdspyFilter, setOpenAdspyFilter] = useStateSR(null); const [openBrandFilter, setOpenBrandFilter] = useStateSR(null); const foreplayEnabled = !!platforms?.foreplay; const adspyEnabled = !!platforms?.adspy; const brandsearchEnabled = !!platforms?.brandsearch; const setFilter = (key, value) => onFilterChange?.(key, value); const setFilters = (patch) => { if (onFiltersChange) onFiltersChange(patch); else Object.entries(patch || {}).forEach(([key, value]) => setFilter(key, value)); }; const ctaOptionSet = new Set(ADSPY_CTA_OPTIONS); const adspyCtaMode = filters.adspyCtaMode || (filters.adspyButtons ? 'custom' : 'all'); const adspyButtons = splitFilterList(filters.adspyButtons); const selectedAdspyButtons = adspyButtons.length ? adspyButtons.filter(value => ctaOptionSet.has(value)) : ADSPY_CTA_OPTIONS; const customAdspyButtons = adspyButtons.filter(value => !ctaOptionSet.has(value)); const setAdspyCtaMode = (mode) => { if (mode === 'custom') { setFilters({ adspyCtaMode: 'custom', adspyButtons: filters.adspyButtons || joinFilterList(ADSPY_CTA_OPTIONS), }); return; } setFilters({ adspyCtaMode: 'all', adspyButtons: '' }); }; const setAdspyButtons = (selected, customText) => { setFilters({ adspyCtaMode: 'custom', adspyButtons: joinFilterList([ ...(selected || []), ...splitFilterList(customText), ]), }); }; const resetAdspyFilter = (id) => { const resets = { siteType: { adspySiteType: '' }, gender: { adspyGender: '' }, ages: { adspyAgeMin: '', adspyAgeMax: '' }, dailyLikes: { minDailyLikes: '', maxDailyLikes: '' }, totalLikes: { minLikes: '', maxLikes: '' }, mediaType: { adspyMediaType: '' }, createdBetween: { adspyCreatedFrom: '', adspyCreatedTo: '' }, seenBetween: { adspySeenFrom: '', adspySeenTo: '' }, networks: { adspyAffNetwork: '' }, affiliate: { adspyAffId: '', adspyOfferId: '' }, advertiser: { adspyUsername: '', adspyUserId: '' }, technologies: { adspyTech: '' }, countries: { adspyCountries: '' }, language: { adspyLang: '' }, buttons: { adspyCtaMode: 'all', adspyButtons: '' }, }; setFilters(resets[id] || {}); }; const adspyFilterPreview = (id) => { if (id === 'siteType') return optionLabel([['facebook', 'Facebook'], ['instagram', 'Instagram']], filters.adspySiteType); if (id === 'mediaType') return optionLabel([['video', 'Video'], ['photo', 'Photo']], filters.adspyMediaType); if (id === 'gender') return optionLabel([['female', 'Female'], ['male', 'Male']], filters.adspyGender); if (id === 'ages') return rangePreview(filters.adspyAgeMin, filters.adspyAgeMax, { defaultMin: '18', defaultMax: '65' }); if (id === 'dailyLikes') return rangePreview(filters.minDailyLikes, filters.maxDailyLikes, { suffix: '/day' }); if (id === 'totalLikes') return rangePreview(filters.minLikes, filters.maxLikes, { suffix: ' likes' }); if (id === 'createdBetween') return rangePreview(filters.adspyCreatedFrom, filters.adspyCreatedTo); if (id === 'seenBetween') return rangePreview(filters.adspySeenFrom, filters.adspySeenTo); if (id === 'networks') return filters.adspyAffNetwork ? `ID ${filters.adspyAffNetwork}` : ''; if (id === 'affiliate') { return [filters.adspyAffId && `Aff ${filters.adspyAffId}`, filters.adspyOfferId && `Offer ${filters.adspyOfferId}`] .filter(Boolean) .join(', '); } if (id === 'advertiser') { return [filters.adspyUsername, filters.adspyUserId && `Page ${filters.adspyUserId}`] .filter(Boolean) .join(', '); } if (id === 'technologies') return compactListPreview(filters.adspyTech, []); if (id === 'countries') return compactListPreview(filters.adspyCountries, ADSPY_COUNTRY_OPTIONS); if (id === 'language') return optionLabel(ADSPY_LANGUAGE_OPTIONS, filters.adspyLang); if (id === 'buttons') { if (adspyCtaMode !== 'custom' && !filters.adspyButtons) return ''; return compactListPreview(filters.adspyButtons || joinFilterList(ADSPY_CTA_OPTIONS), ADSPY_CTA_OPTIONS); } return ''; }; const renderAdspyFilter = (id) => { const labels = { siteType: 'Site type', gender: 'Gender', ages: 'Ages', dailyLikes: 'Daily likes', totalLikes: 'Total likes', mediaType: 'Media type', createdBetween: 'Created Between', seenBetween: 'Seen Between', networks: 'Networks', affiliate: 'Affiliate', advertiser: 'Advertiser', technologies: 'Technologies', countries: 'Countries', language: 'Language', buttons: 'Buttons', }; let body = null; if (id === 'siteType') { body = ( setFilter('adspySiteType', value)} options={[['', 'Facebook or Instagram'], ['facebook', 'Facebook'], ['instagram', 'Instagram']]} /> ); } else if (id === 'gender') { body = ( setFilter('adspyGender', value)} options={[['', 'Any gender'], ['female', 'Female'], ['male', 'Male']]} /> ); } else if (id === 'ages') { const minAge = filters.adspyAgeMin || '18'; const maxAge = filters.adspyAgeMax || '65'; body = ( <>
From {minAge} to {maxAge}{Number(maxAge) >= 65 ? ' +' : ''}
setFilter('adspyAgeMin', value)} /> setFilter('adspyAgeMax', value)} /> ); } else if (id === 'dailyLikes') { body = ( <> setFilter('minDailyLikes', value)} /> setFilter('maxDailyLikes', value)} /> ); } else if (id === 'totalLikes') { body = ( <> setFilter('minLikes', value)} /> setFilter('maxLikes', value)} /> ); } else if (id === 'mediaType') { body = ( setFilter('adspyMediaType', value)} options={[['', 'Any media type'], ['video', 'Video'], ['photo', 'Photo']]} /> ); } else if (id === 'createdBetween') { body = ( <> setFilter('adspyCreatedFrom', value)} /> setFilter('adspyCreatedTo', value)} /> ); } else if (id === 'seenBetween') { body = ( <> setFilter('adspySeenFrom', value)} /> setFilter('adspySeenTo', value)} /> ); } else if (id === 'networks') { body = ( setFilter('adspyAffNetwork', value)} /> ); } else if (id === 'affiliate') { body = ( <> setFilter('adspyAffId', value)} /> setFilter('adspyOfferId', value)} /> ); } else if (id === 'advertiser') { body = ( <> setFilter('adspyUsername', value)} /> setFilter('adspyUserId', value)} /> ); } else if (id === 'technologies') { body = ( setFilter('adspyTech', value)} /> ); } else if (id === 'countries') { body = setFilter('adspyCountries', value)} />; } else if (id === 'language') { body = setFilter('adspyLang', value)} options={[['', 'Any language'], ...ADSPY_LANGUAGE_OPTIONS]} />; } else if (id === 'buttons') { body = ( <> {adspyCtaMode === 'custom' && ( <> setAdspyButtons(splitFilterList(value), customAdspyButtons.join(', '))} /> setAdspyButtons(selectedAdspyButtons, value)} /> )} ); } return ( setOpenAdspyFilter(openAdspyFilter === id ? null : id)} onClose={() => setOpenAdspyFilter(null)} onReset={() => resetAdspyFilter(id)} > {body} ); }; const brandSlider = ({ id, label, filterKey, max, suffix = '' }) => ( setOpenBrandFilter(openBrandFilter === id ? null : id)} onClose={() => setOpenBrandFilter(null)} onReset={() => setFilter(filterKey, '')} > setFilter(filterKey, value)} /> {suffix &&
Value is sent as minimum {suffix}.
}
); return ( <> {foreplayEnabled && (