public/src/components/linkTracking/MediumSelector.tsx (237 lines of code) (raw):

import { FormControl, MenuItem, Select, Theme } from '@mui/material'; import React from 'react'; import { Control, Controller } from 'react-hook-form'; import { makeStyles } from '@mui/styles'; interface Option { value: string; label: string; } interface OptionGroup { group: string; options: Option[]; } const OPTIONS: OptionGroup[] = [ { group: 'AFFILIATES', options: [{ value: 'awin', label: 'Affiliates Window (awin)' }], }, { group: 'APPLE_NEWS', options: [ { value: 'ACQUISITIONS_ARTICLE_EMBED', label: 'ACQUISITIONS_ARTICLE_EMBED' }, { value: 'ACQUISITIONS_EPIC', label: 'ACQUISITIONS_EPIC' }, { value: 'ACQUISITIONS_HOUSE_ADS', label: 'ACQUISITIONS_HOUSE_ADS' }, { value: 'DISPLAY_AD', label: 'DISPLAY_AD' }, ], }, { group: 'AUDIO', options: [ { value: 'acastrec', label: 'Acast recommends (acastrec)' }, { value: 'dyn', label: 'Dynamic (dyn)' }, { value: 'hstrd', label: 'Host reads (hstrd)' }, { value: 'description', label: 'Podcast description (description)' }, { value: 'spot', label: 'Spotify (spot)' }, ], }, { group: 'DISPLAY', options: [ { value: 'dispad', label: 'Display ad (dispad)' }, { value: 'pgmtc', label: 'Programmatic (pgmtc)' }, ], }, { group: 'EMAIL', options: [ { value: 'email_editorial', label: 'Editorial (email_editorial)' }, { value: 'email_marketing', label: 'Marketing (email_marketing)' }, { value: 'email_service', label: 'Service (email_service)' }, { value: 'email_other', label: 'Other (email_other)' }, ], }, { group: 'GUARDIAN_APP', options: [{ value: 'push', label: 'Push notification (push)' }], }, { group: 'GUARDIAN_WEB', options: [ { value: 'ACQUISITIONS_BUTTON', label: 'ACQUISITIONS_BUTTON' }, { value: 'ACQUISITIONS_EDITORIAL_LINK', label: 'ACQUISITIONS_EDITORIAL_LINK' }, { value: 'ACQUISITIONS_ENGAGEMENT_BANNER', label: 'ACQUISITIONS_ENGAGEMENT_BANNER' }, { value: 'ACQUISITIONS_EPIC', label: 'ACQUISITIONS_EPIC' }, { value: 'ACQUISITIONS_FOOTER', label: 'ACQUISITIONS_FOOTER' }, { value: 'ACQUISITIONS_HEADER', label: 'ACQUISITIONS_HEADER' }, { value: 'ACQUISITIONS_HOUSE_ADS', label: 'ACQUISITIONS_HOUSE_ADS' }, { value: 'ACQUISITIONS_INTERACTIVE_SLICE', label: 'ACQUISITIONS_INTERACTIVE_SLICE' }, { value: 'ACQUISITIONS_MANAGE_MY_ACCOUNT', label: 'ACQUISITIONS_MANAGE_MY_ACCOUNT' }, { value: 'ACQUISITIONS_MERCHANDISING', label: 'ACQUISITIONS_MERCHANDISING' }, { value: 'ACQUISITIONS_NUGGET', label: 'ACQUISITIONS_NUGGET' }, { value: 'ACQUISITIONS_OTHER', label: 'ACQUISITIONS_OTHER' }, { value: 'ACQUISITIONS_STANDFIRST', label: 'ACQUISITIONS_STANDFIRST' }, { value: 'ACQUISITIONS_SUBSCRIPTIONS_BANNER', label: 'ACQUISITIONS_SUBSCRIPTIONS_BANNER' }, { value: 'ACQUISITIONS_SUPPORT_SITE', label: 'ACQUISITIONS_SUPPORT_SITE' }, { value: 'ACQUISITIONS_THANK_YOU_EPIC', label: 'ACQUISITIONS_THANK_YOU_EPIC' }, { value: 'ACQUISITIONS_THRASHER', label: 'ACQUISITIONS_THRASHER' }, { value: 'AUDIO_ATOM', label: 'AUDIO_ATOM' }, { value: 'CHART_ATOM', label: 'CHART_ATOM' }, { value: 'GUIDE_ATOM', label: 'GUIDE_ATOM' }, { value: 'HELP_CENTER', label: 'Help Center' }, { value: 'IDENTITY_AUTHENTICATION', label: 'IDENTITY_AUTHENTICATION' }, { value: 'MOBILE_STICKY_AD', label: 'MOBILE_STICKY_AD' }, { value: 'NEWSLETTER_SUBSCRIPTION', label: 'NEWSLETTER_SUBSCRIPTION' }, { value: 'PROFILE_ATOM', label: 'PROFILE_ATOM' }, { value: 'QANDA_ATOM', label: 'QANDA_ATOM' }, { value: 'READERS_QUESTIONS_ATOM', label: 'READERS_QUESTIONS_ATOM' }, { value: 'RETENTION_BANNER', label: 'RETENTION_BANNER' }, { value: 'RETENTION_ENGAGEMENT_BANNER', label: 'RETENTION_ENGAGEMENT_BANNER' }, { value: 'RETENTION_EPIC', label: 'RETENTION_EPIC' }, { value: 'SIGN_IN_GATE', label: 'SIGN_IN_GATE' }, { value: 'SURVEYS_QUESTIONS', label: 'SURVEYS_QUESTIONS' }, { value: 'TIMELINE_ATOM', label: 'TIMELINE_ATOM' }, { value: 'housead', label: 'Housead' }, { value: 'merchhgh', label: 'Merchandising high (merchhgh)' }, { value: 'merchin', label: 'Merchandising inline (merchin)' }, { value: 'merchlow', label: 'Merchandising low (merchlow)' }, { value: 'navbar', label: 'Navbar' }, ], }, { group: 'ORGANIC_SOCIAL', options: [ { value: 'sfbk', label: 'Social Facebook (sfbk)' }, { value: 'sisgm', label: 'Social Instagram (sisgm)' }, { value: 'slkn', label: 'Social Linkedin (slkn)' }, { value: 'spint', label: 'Social Pinterest (spint)' }, { value: 'quora', label: 'Social Quora (quora)' }, { value: 'reddit', label: 'Social Reddit (reddit)' }, { value: 'stik', label: 'Social TikTok (stik)' }, { value: 'stwr', label: 'Social Twitter (stwr)' }, { value: 'sytb', label: 'Social YouTube (sytb)' }, { value: 'sbsky', label: 'Social Bluesky (sbsky)' }, { value: 'sother', label: 'Other (osother)' }, ], }, { group: 'OUTDOOR', options: [ { value: 'dooh', label: 'Digital OOH (dooh)' }, { value: 'pos', label: 'Point of Sale (pos)' }, { value: 'tcp', label: 'Tube Card Panels (tcp)' }, { value: 'tvis', label: 'Transvision (tvis)' }, ], }, { group: 'PAID_SOCIAL', options: [ { value: 'sfbk', label: 'Social Facebook (sfbk)' }, { value: 'sisgm', label: 'Social Instagram (sisgm)' }, { value: 'slkn', label: 'Social Linkedin (slkn)' }, { value: 'spint', label: 'Social Pinterest (spint)' }, { value: 'quora', label: 'Social Quora (quora)' }, { value: 'reddit', label: 'Social Reddit (reddit)' }, { value: 'stik', label: 'Social TikTok (stik)' }, { value: 'stwr', label: 'Social Twitter (stwr)' }, { value: 'sytb', label: 'Social YouTube (sytb)' }, { value: 'sbsky', label: 'Social Bluesky (sbsky)' }, { value: 'sother', label: 'Other (osother)' }, ], }, { group: 'PPC', options: [ { value: 'pdsbg', label: 'Paid search Bing (pdsbg)' }, { value: 'pdsge', label: 'Paid search Google (pdsge)' }, { value: 'pmax', label: 'Performance Max (pmax)' }, ], }, { group: 'PRINT', options: [ { value: 'dirm', label: 'Direct Mail (dirm)' }, { value: 'inpaper-g', label: 'Inpaper (inpaper-g)' }, { value: 'insr', label: 'Inserts (insr)' }, { value: 'prsctrlm', label: 'Press Control Message (prsctrlm)' }, { value: 'prssupm', label: 'Press Supporting Message (prssupm)' }, { value: 'smpbr', label: 'Sampling Brochure (smpbr)' }, ], }, { group: 'RETAIL', options: [{ value: 'urtr', label: 'Unknown retail (urtr)' }], }, { group: 'TELEMARKETING', options: [{ value: 'ctcter', label: 'Contact Center (ctcter)' }], }, { group: 'UNKNOWN', options: [{ value: 'other', label: 'other (other)' }], }, { group: 'VIDEO', options: [ { value: 'a4', label: 'All4 (a4)' }, { value: 'itvh', label: 'ITVHub (itvh)' }, { value: 'preroll', label: 'Preroll (preroll)' }, { value: 'sky', label: 'Sky (sky)' }, ], }, ]; const useStyles = makeStyles(({ spacing }: Theme) => ({ groupHeading: { fontWeight: 700, }, item: { marginLeft: spacing(2), }, })); interface Props { control: Control; onUpdate: () => void; } /** * A selector for choosing a medium. The value is the source and medium separated by a double underscore. * This is because the link tracking should contain both, but the source should not be chosen directly by the user. */ export const MediumSelector: React.FC<Props> = ({ control, onUpdate }: Props) => { const classes = useStyles(); return ( <FormControl> <Controller name="sourceAndMedium" rules={{ required: true }} render={({ onChange, value }) => ( <Select value={value} onChange={e => { onUpdate(); onChange(e); }} error={!!control.formState.errors?.medium} > {OPTIONS.map(group => { const groupItem = ( <MenuItem className={classes.groupHeading} value={group.group} key={group.group} disabled > {group.group} </MenuItem> ); const items = group.options.map(medium => ( <MenuItem className={classes.item} value={`${group.group}__${medium.value}`} key={`${group.group}-${medium.value}`} > {medium.label} </MenuItem> )); return [groupItem].concat(items); })} </Select> )} control={control} defaultValue={''} /> </FormControl> ); };