{"version":3,"file":"chunk.5f47d8cc98bd0661d91e.js","mappings":"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","sources":["webpack:///../../../packages/pg-ui/src/base/Material/components/Radio.tsx","webpack:///./scripts/apps/promotions/components/InterestedParty.tsx","webpack:///./scripts/apps/promotions/components/PromotionCard.tsx","webpack:///./scripts/apps/promotions/lang/en-us.ts","webpack:///./scripts/apps/promotions/lang/index.ts","webpack:///../../../packages/domain/src/data/promotions/promotion.ts","webpack:///../../../packages/pg-util/src/StringUtils.ts","webpack:///../../../packages/react-final-form/src/Field.tsx"],"sourcesContent":["import * as React from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport MuiRadio from '@mui/material/Radio';\nimport {Field} from '@practicegenius/react-final-form/src/Field';\n\ntype RadioProps = {\n value: string | number;\n color?: 'primary' | 'secondary' | 'default';\n label: string | JSX.Element;\n labelProps?: {style: React.ComponentProps['style']};\n name: string;\n checked: boolean;\n onChange: React.ChangeEventHandler;\n};\n\nexport const Radio: React.FC = ({\n color = 'primary',\n label,\n labelProps = {style: {fontWeight: 600}},\n name,\n ...props\n}) => {\n const id = `${name}_${props.value}`;\n return (\n \n \n \n {label}\n \n \n );\n};\n\ntype RadioGroupProps = {\n options: Omit[];\n value: React.ReactNode;\n name: string;\n onChange: React.ChangeEventHandler;\n};\n\nexport const RadioGroup: React.FC = ({\n options,\n value,\n onChange,\n name,\n}) => (\n \n {options.map(option => (\n \n \n \n ))}\n \n);\n\nexport const RadioGroupField: React.FC = ({\n name,\n value,\n options,\n}) => (\n \n {({input}): React.ReactNode => }\n \n);\n","import {Radio} from '@practicegenius/pg-ui/src/base/Material/components/Radio';\nimport React from 'react';\n\nexport enum InterestedPartyType {\n myself = 'myself',\n myChild = 'myChild',\n}\n\ntype Props = {\n interestedParty: InterestedPartyType;\n langStrings: {\n [InterestedPartyType.myself]: string;\n [InterestedPartyType.myChild]: string;\n };\n onChange: React.ChangeEventHandler;\n};\n\nconst labelProps: {style: React.CSSProperties} = {style: {fontWeight: 400}};\n\nexport const InterestedParty: React.FC = ({\n interestedParty,\n langStrings,\n onChange,\n}) => {\n const isForChild = interestedParty === InterestedPartyType.myChild;\n return (\n <>\n \n \n \n );\n};\n","import React from 'react';\nimport CardMedia from '@mui/material/CardMedia';\nimport CardContent from '@mui/material/CardContent';\nimport Typography from '@mui/material/Typography';\nimport Box from '@mui/material/Box';\nimport {Link} from '@mui/material';\nimport {\n PromotionListItem,\n getPromotionFormattedDateRange,\n} from '@practicegenius/domain/src/data/promotions/promotion';\n\ntype Props = {\n promotion: PromotionListItem;\n cardSize?: 'small' | 'large';\n};\n\n/** Promotion card display\n * - promotion - the promotion to display\n * - cardSize - optional, the size of the card (small or large) defaults to small\n */\nexport const PromotionCard: React.FC = ({\n promotion,\n cardSize = 'small',\n}) => {\n // There should be no card displayed in the off chance that there is no url\n if (!promotion.url) return null;\n\n return (\n \n \n \n \n {getPromotionFormattedDateRange(promotion)}\n \n \n \n {promotion.title}\n \n \n \n \n );\n};\n","import {InterestedPartyType} from '../components/InterestedParty';\n\nexport default {\n promotionPage: {\n actionButton: {\n event: 'Share This Event',\n offer: 'Sign Up',\n giveaway: 'Enter Now',\n },\n // These strings are built for sharing the promotion. As such, HTML entities don't need to be escaped (I think ¯\\_(ツ)_/¯)\n shareSubject: {\n event: 'You are invited to {{{ title }}} by {{{ practiceName }}}',\n offer: 'Here are the details for {{{ title }}} at {{{ practiceName }}}',\n giveaway:\n 'Here are the details for {{{ title }}} at {{{ practiceName }}}',\n },\n shareMessage: {\n event: 'You are invited to {{{ title }}} by {{{ practiceName }}}',\n offer: 'Here are the details for {{{ title }}} at {{{ practiceName }}}',\n giveaway:\n 'Here are the details for {{{ title }}} at {{{ practiceName }}}',\n },\n timeTitle: {\n event: 'Date and Time',\n offer: 'Offer Valid Through',\n giveaway: 'Giveaway Entry Period',\n },\n locationTitle: 'Location',\n onlineEventTitle: 'Online Event',\n multipleLocationsLink: 'Multiple Locations',\n addToCalendar: {\n link: 'Add To Calendar',\n google: 'Google',\n iCal: 'iCal',\n outlook: 'Outlook',\n },\n viewMapLink: 'View Map',\n locationMap: {\n officeLocationList: {\n title: 'Locations',\n },\n error: {\n headline: 'Something went wrong!',\n message: `We're sorry, but we're having trouble loading the map. Please try again later.`,\n },\n },\n aboutUs: {\n contact: 'Contact Us',\n about: 'About Us',\n },\n image: {\n main: {\n alt: 'Promotion Image',\n },\n backdrop: {\n alt: 'Promotion Backdrop Image',\n },\n },\n giveaways: {\n enterGiveaway: {\n confirmEnter: 'Ok',\n title: \"You're entered! 🎉\",\n body: \"You're entered in the giveaway!\",\n },\n banner: {\n left: 'left',\n start: 'until start',\n totalEntries: 'total entries',\n userEntries: 'your entries',\n },\n bonusEntries: {\n title: 'Bonus ways to win!',\n subtitle: 'Total bonus entries',\n redeem: {\n current:\n 'You currently have {{ #strong }}{{{ points}}} points{{ /strong }} total.',\n confirm:\n 'Confirm that you want to redeem your points for bonus entries.',\n adornment: 'Entries',\n notEnough: \"You don't have enough points for this amount of entries.\",\n minError: 'The number of entries must be at least 1.',\n redeemButton: 'Redeem',\n },\n },\n workflow: {\n earnButton: 'Other ways to earn',\n revealButton: 'Reveal Winner',\n winnerMessage: 'Contact the office within 7 days to claim your prize',\n },\n error: 'Something went wrong. Please try again.',\n terms: {\n title: `NO PURCHASE NECESSARY TO ENTER OR WIN. A PURCHASE WILL NOT IMPROVE YOUR CHANCES OF WINNING. VOID WHERE PROHIBITED BY LAW.`,\n eligibility: `ELIGIBILITY: The {{practiceName}} Giveaway (the “Giveaway”) is open to all individuals who are at least 13 years old at the time of entry, and who have the consent of their parent or legal guardian to enter, except where prohibited or restricted by law. Individuals who are under 18 years old at the time of entry must have the consent of their parent or legal guardian to participate. Employees, officers, directors, and their immediate families (spouse, parents, siblings, and children) of {{practiceName}}, its affiliates, subsidiaries, advertising and promotion agencies, and other coordinating agencies involved in the promotion of this Giveaway (collectively, the “Giveaway Entities”) are not eligible to enter.`,\n giveawayPeriod: `GIVEAWAY PERIOD: The Giveaway begins on {{startDate}} and ends on {{endDate}} (the “Giveaway Period”).`,\n howToEnter: `HOW TO ENTER: To enter, visit the {{practiceName}} Giveaway entry page at {{{url}}} and follow the instructions provided to complete and submit the entry form. Only one entry per person is allowed. Entrants must provide their full name, email address, and telephone number. Incomplete entries or entries that do not comply with these Official Rules will be disqualified. All entries must be received by the end of the Giveaway Period.`,\n winnerSelection: `WINNER SELECTION: The winners of the Giveaway will be selected by random drawing from among all eligible entries received during the Giveaway Period. The drawing will be conducted within 7 days after the end of the Giveaway Period. The odds of winning depend on the number of eligible entries received.`,\n winnerNotification: `WINNER NOTIFICATION: The winners will be notified by email within 7 days after the drawing. {{practiceName}} is not responsible for any delays in notification due to technical issues or otherwise. If a potential winner cannot be contacted within 7 days after the first attempt to contact him/her, or if he/she fails to respond to the notification within 7 days, or if he/she fails to comply with these Official Rules, such potential winner will be disqualified and forfeit his/her prize. If a potential winner is disqualified for any reason, {{practiceName}} will award the applicable prize to an alternate winner by random drawing from among all remaining eligible entries.`,\n prize: `PRIZE: The prize for the Giveaway is {{prize}}. The prize is non-transferable and no substitution will be made except as provided herein at the sole discretion of {{practiceName}}. The prize is awarded “as is” with no warranty or guarantee, either express or implied by {{practiceName}}. {{practiceName}} reserves the right to substitute the prize with another prize of equal or greater value if the designated prize should become unavailable for any reason. The prize will be awarded within 7 days after the winner is selected.`,\n release: `RELEASE: By participating in the Giveaway, each entrant agrees to release and hold harmless the Giveaway Entities from and against any claim or cause of action arising out of participation in the Giveaway or receipt or use of the prize, including, but not limited to: (a) unauthorized human intervention in the Giveaway; (b) technical errors related to computers, servers, providers, or telephone or network lines; (c) printing errors; (d) lost, late, postage-due, misdirected, or undeliverable mail; (e) errors in the administration of the Giveaway or the processing of entries; or (f) injury or damage to persons or property which may be caused, directly or indirectly, in whole or in part, from entrant’s participation in the Giveaway or receipt of the prize. Entrant further agrees that in any cause of action, the Giveaway Entities’ liability will be limited to the cost of entering and participating in the Giveaway, and in no event shall the Giveaway Entities be liable for attorney’s fees. Entrant waives the right to claim any damages whatsoever, including, but not limited to, punitive, consequential, direct, or indirect damages.`,\n },\n },\n },\n dashboard: {\n title: 'Promotions',\n seeAll: 'See All',\n },\n contactInfoFields: {\n firstName: 'First Name',\n lastName: 'Last Name',\n phone: 'Mobile Phone',\n email: 'Email',\n childFirstName: 'Child First Name',\n childLastName: 'Child Last Name',\n isNotRealUser: 'Please leave this box unchecked',\n },\n contactInfoErrors: {\n required: '{{ fieldName }} is required.',\n },\n contactMe: {\n title: 'New Customer Inquiry',\n subtitle:\n 'Interested in our products or services? Enter your details, and we will contact you with more information.',\n postInfoFields: {\n [InterestedPartyType.myself]: 'Interested in services for myself',\n [InterestedPartyType.myChild]: 'Interested in services for my child',\n },\n buttonText: 'Contact Me',\n },\n\n signUp: {\n title: 'Sign Up For This Promotion',\n subtitle: 'We will contact you to set up your next steps',\n postInfoFields: {\n isMember: {\n label: 'Are you a current Member? *',\n options: {\n yes: 'Yes, I am a member',\n no: 'No, I am not a member',\n },\n requiredError: 'Please select whether or not you are a current member.',\n },\n [InterestedPartyType.myself]: 'Sign me up',\n [InterestedPartyType.myChild]: 'Sign my child up',\n },\n buttonText: 'Sign Up',\n },\n\n form: {\n catastrophicError:\n 'Something went wrong, please try submitting the form again.',\n },\n\n formConfirmation: {\n callUsNow: `Don't want to wait? Give us a call now.`,\n },\n\n // \"micro-site\"\n empty: {\n title: 'There are no promotions or events at this time.',\n subtitle:\n 'Scheduled promotions and events by {{{ name }}} will show here. Check back later.',\n logoAlt: '{{ name }} logo',\n },\n main: {\n highlighted: {\n actionButton: 'Learn More',\n },\n type: {\n events: 'Events',\n offers: 'Offers',\n giveaways: 'Giveaways',\n },\n showMore: 'Show {{ quantity }} {{ title }}',\n },\n};\n","import enUs from './en-us';\n\nexport default enUs;\n","import * as R from 'ramda';\nimport {parseISO} from 'date-fns';\nimport {camelCase} from '@practicegenius/pg-util/src/StringUtils';\nimport {UnknownServerData} from '@practicegenius/http-clients-js/src/types';\nimport {formatDateRange} from '@practicegenius/pg-util/src/DateUtils';\nimport {objectKeysToCamelCaseDeep} from '@practicegenius/pg-util/src/ObjectUtils';\nimport {setType} from '@practicegenius/pg-util/src/TypescriptUtils';\nimport {Address} from '../address';\nimport {RelativeSchedule} from '../relativeSchedule';\n\nexport enum PromotionStatus {\n needs_action = 'needs_action',\n published = 'published',\n scheduled = 'scheduled',\n draft = 'draft',\n past = 'past',\n}\n\n// TODO can should extend PromotionStatus?\nexport enum PromotionFilterStatus {\n needs_action = 'needs_action',\n published = 'published',\n scheduled = 'scheduled',\n draft = 'draft',\n past = 'past',\n all = 'all',\n}\n\nexport enum PromotionType {\n event = 'event',\n offer = 'offer',\n giveaway = 'giveaway',\n}\n\nexport enum PromotionField {\n name = 'name',\n title = 'title',\n location = 'location',\n locationData = 'locationData',\n locationType = 'locationType',\n locationDataLink = 'locationDataLink',\n locationDataName = 'locationDataName',\n locationDataAddressLine1 = 'locationDataAddressLine1',\n locationDataAddressLine2 = 'locationDataAddressLine2',\n locationDataCity = 'locationDataCity',\n locationDataState = 'locationDataState',\n locationDataZip = 'locationDataZip',\n locationDataCountry = 'locationDataCountry',\n locationDataIds = 'locationDataIds',\n startDate = 'startDate',\n endDate = 'endDate',\n audience = 'audience',\n userGroupIds = 'userGroupIds',\n image = 'image',\n shortDescription = 'shortDescription',\n longDescription = 'longDescription',\n publish = 'publish',\n relativeScheduleUnit = 'relativeScheduleUnit',\n relativeScheduleInterval = 'relativeScheduleInterval',\n giveawayRewardWinnerPoints = 'giveawayRewardWinnerPoints',\n giveawayRewardWinnerInHouseReward = 'giveawayRewardWinnerInHouseReward',\n giveawayRewardParticipantPoints = 'giveawayRewardParticipantPoints',\n giveawayEntryActionsRedeemForEntriesPoints = 'giveawayEntryActionsRedeemForEntriesPoints',\n giveawayEntryActionsRedeemForEntriesTitle = 'giveawayEntryActionsRedeemForEntriesTitle',\n giveawayEntryActionsDailyEntrySpinPossibleBonusEntries = 'giveawayEntryActionsDailyEntrySpinPossibleBonusEntries',\n giveawayEntryActionsDailyEntrySpinTitle = 'giveawayEntryActionsDailyEntrySpinTitle',\n}\n\nexport enum PromotionLocationType {\n venue = 'venue',\n office = 'office',\n online = 'online',\n toBeDetermined = 'toBeDetermined',\n none = 'none',\n}\n\nexport type Geometry = {\n location: google.maps.LatLng | google.maps.LatLngLiteral;\n viewport: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral;\n};\n\nexport enum PromotionAudienceType {\n public = 'public',\n members = 'members',\n}\n\nexport type PromotionAudience =\n | {audience: PromotionAudienceType.public}\n | {\n audience: PromotionAudienceType.members;\n userGroupIds: number[];\n };\n\nexport enum PromotionPublishType {\n now = 'now',\n startDate = 'startDate',\n relativeSchedule = 'relativeSchedule',\n}\n\nexport type PromotionPublish =\n | {\n publish: PromotionPublishType.now;\n }\n | {\n publish: PromotionPublishType.startDate;\n }\n | {\n publish: PromotionPublishType.relativeSchedule;\n relativeSchedule: RelativeSchedule;\n };\n\nexport type PromotionLocationVenue = {\n name: string;\n geometry?: Geometry;\n} & Address;\n\nexport type PromotionLocation =\n | {\n type: PromotionLocationType.venue;\n data: PromotionLocationVenue | null;\n }\n | {\n type: PromotionLocationType.office;\n data: {\n ids: number[];\n };\n }\n | {type: PromotionLocationType.online; data: {link: string}}\n | {type: PromotionLocationType.toBeDetermined; data: null}\n | {type: PromotionLocationType.none; data: null};\n\nexport type PromotionBonusEntrySettings =\n | {\n type: 'redeem_for_entries';\n title: string;\n points: number;\n }\n | {\n type: 'daily_entry_spin';\n title: string;\n possibleBonusEntries: number[];\n theme: string;\n };\n\ntype GiveawayHasWinner =\n | {\n hasWinner: true;\n winnerId: number;\n }\n | {\n hasWinner: false;\n };\n\nexport type GiveawayDetails = GiveawayHasWinner & {\n reward: PromotionRewardSettings;\n showTotalParticipantEntries: boolean;\n entryActions?: PromotionBonusEntrySettings[];\n winnerReveal: {type: 'spin_wheel'; theme: string};\n};\n\ntype BasePromotion = PromotionPublish &\n PromotionAudience & {\n id: number;\n name: string;\n title: string;\n image: string;\n startDate: Date;\n endDate: Date;\n shortDescription: string;\n longDescription: string;\n url: string;\n hashId: string;\n status: PromotionStatus;\n settings: PromotionSettings;\n };\n\nexport type PublishedPromotion = BasePromotion & {\n draft: false;\n} & (\n | {\n type: PromotionType.event;\n location: PromotionLocation;\n }\n | {type: PromotionType.offer}\n | {\n type: PromotionType.giveaway;\n giveaway: GiveawayDetails;\n participantsCount: number;\n winnerName?: string;\n }\n );\n\nexport type UnpublishedPromotion = BasePromotion & {\n draft: true;\n type: PromotionType;\n location?: PromotionLocation;\n giveaway?: GiveawayDetails;\n};\n\nexport type PromotionSettings = {\n colors: {\n bodyAccent: string;\n bodyBackground: string;\n bodyText: string;\n headlineBackground: string;\n headlineText: string;\n };\n startAndEndTimes: {\n showDates: boolean;\n // Technically, this is defined when PromotionType.Event and undefined when PromotionType.Offer,\n // but I don't think it's worth the effort to model that detail at this time.\n showTimes?: boolean;\n };\n};\n\nexport type PromotionParticipantTypes = 'winner' | 'participant';\nexport type PromotionRewardsWinner =\n | {\n type: 'points';\n points: number;\n }\n | {\n type: 'in_house_reward';\n inHouseReward: string;\n };\nexport type PromotionRewardsParticipant =\n | {\n type: 'points';\n points: number;\n }\n | {\n type: 'no_reward';\n };\n\nexport type PromotionRewardSettings = {\n winner: PromotionRewardsWinner;\n participant: PromotionRewardsParticipant;\n};\n\nexport type Promotion = PublishedPromotion | UnpublishedPromotion;\n\nexport type PromotionListItem = {\n id: number;\n type: PromotionType;\n status: PromotionStatus;\n name: string;\n title: string;\n shortDescription: string;\n longDescription: string;\n url: string | null;\n color: string | null;\n image: string;\n startDate: Date;\n endDate: Date;\n\n /** Location is undefined when type: Offer;\n * Location may be null when status: Draft */\n location?: PromotionLocation | null;\n settings: PromotionSettings;\n\n /** only present if promotion type is giveaway */\n participantsCount?: number;\n\n /** only present if audience === PromotionAudienceType.members, but\n * we don't have audience here */\n recipientsCount?: number;\n\n /** only present if promotion type is giveaway */\n giveaway?: GiveawayDetails;\n\n /** only present if promotion type is giveaway */\n winnerName?: string;\n};\n\nexport type DailySpinEntriesType =\n | {\n participated: false;\n }\n | {\n participated: true;\n spinResult: number;\n };\n\nexport type PromotionGiveawayEntries = {\n authUserEntries: {\n initialEntries: boolean;\n dailyActivity: {\n spinForEntries: DailySpinEntriesType;\n };\n totalEntriesPerActivity: {\n redeemForEntries: number;\n spinEntries: number;\n };\n };\n entriesCount: number;\n};\n\nexport type UserRevealStatus =\n | {\n type: 'unrevealed';\n }\n | {\n type: 'revealed';\n currentUserIsWinner: boolean;\n };\n\nexport type UserWinnerRevealedStatus = Extract<\n UserRevealStatus,\n {type: 'revealed'}\n>;\n\nconst renameKeys = R.curry((keysMap, obj) =>\n R.reduce(\n (acc, key) => R.assoc(keysMap[key] || key, obj[key], acc),\n {},\n R.keys(obj)\n )\n);\n\n/**\n * Camelcases the necessary values when transforming from server\n */\nconst camelcaseValues = R.evolve({\n location: {\n type: camelCase,\n },\n publish: camelCase,\n});\n\n/**\n * Transforms incoming entry actions to array from object\n */\nexport const transformIncomingEntryActions = R.evolve({\n giveaway: {\n entryActions: Object.values,\n },\n});\n\n/**\n * Transforms incoming participant reward to remove points if 'no_reward'\n */\nexport const transformIncomingParticipantReward = R.evolve({\n giveaway: {\n reward: {\n participant: R.when(R.propEq('no_reward', 'type'), R.dissoc('points')),\n },\n },\n});\n\n/**\n * Transforms incoming giveaway winner id\n */\nexport const transformIncomingGiveawayWinnerId = R.evolve({\n giveaway: renameKeys({winner: 'winnerId'}),\n});\n\n/**\n * Date-ifys incoming dates\n */\nexport const transformIncomingPromotionDates = R.evolve({\n startDate: R.unless(R.either(R.isNil, R.isEmpty), parseISO),\n endDate: R.unless(R.either(R.isNil, R.isEmpty), parseISO),\n});\n\nexport const transformIncomingPromotion = R.pipe(\n objectKeysToCamelCaseDeep,\n // @ts-ignore\n camelcaseValues,\n transformIncomingPromotionDates,\n transformIncomingEntryActions,\n transformIncomingParticipantReward,\n transformIncomingGiveawayWinnerId\n);\n\nexport const promotionsResponseToListItems: (\n data: UnknownServerData\n) => PromotionListItem[] = R.pipe(\n R.propOr([], 'items'),\n R.map(transformIncomingPromotion),\n setType()\n);\n\nexport const transformPromotionResponse: (\n data: UnknownServerData\n) => Promotion = R.pipe(\n R.propOr({}, 'item'),\n transformIncomingPromotion,\n setType()\n);\n\nexport const getPromotionFormattedDateRange = (\n promotion: Pick\n): string =>\n R.pathEq(true, ['settings', 'startAndEndTimes', 'showDates'], promotion)\n ? formatDateRange(promotion.startDate, promotion.endDate)\n : '';\n","import template from 'lodash/template';\nimport reduce from 'lodash/reduce';\nimport range from 'lodash/range';\nimport camelCase from 'lodash/camelCase';\nimport snakeCase from 'lodash/snakeCase';\nimport Mustache from 'mustache';\n\nexport {camelCase, snakeCase};\n\n/**\n * Concise shorthand for Mustache.render\n * IMT = Interpolate Mustache Template\n */\nexport const IMT = Mustache.render;\n\nexport type TemplateRenderFunction = (\n template: string,\n render: (t: string) => string\n) => string;\n\n/**\n * A web-specific text-bolding handler for mustache templates\n */\nexport const strongify =\n (): TemplateRenderFunction =>\n (template: string, render: (t: string) => string) =>\n `${render(template)}`;\n\n/**\n * Uppercase the first character.\n */\nexport const ucFirst = (str: string): string =>\n str.substr(0, 1).toUpperCase() + str.substr(1);\n\n/**\n * Stolen from https://locutus.io/php/strings/ucwords/\n *\n * @param str\n */\nexport const ucWords = (str: string): string =>\n str.replace(/^(.)|\\s+(.)/g, $1 => $1.toUpperCase());\n\nexport const nl2br = (str: string): string => str.replace(/\\n/g, '
');\nexport const br2nl = (str: string): string => str.replace(//g, '\\n');\n\nexport function replaceHyperlinks(\n str: string,\n newSubStr = '${content} (${href})'\n): string {\n return str.replace(\n /]*href=\"([^\"]*)\"[^>]*>([^<]+)<\\/a>/gi,\n (link, href, content) => template(newSubStr)({href, content})\n );\n}\n\nexport function stripHTMLTags(str: string, passes = 2): string {\n return range(passes).reduce(carry => {\n const container = document.implementation.createHTMLDocument('New').body;\n container.innerHTML = carry;\n return container.textContent || container.innerText || '';\n }, str);\n}\n\nexport function stripHTMLTag(str: string, tag: string): string {\n return str.replace(new RegExp(`(<\\/?[${tag}][^>]+>)`, 'ig'), '');\n}\n\n/**\n * Translates htmlspecialchars into their appropriate entities.\n */\nexport function replaceSpecialCharactersWithHtml(str: string): string {\n const map: Record = {\n '&': '&',\n '<': '<',\n '>': '>',\n '"': '\"',\n ''': \"'\",\n };\n\n return str.replace(\n new RegExp(Object.keys(map).join('|'), 'g'),\n symbol => map[symbol]\n );\n}\n\n/**\n * Translate an object to HTML attributes.\n */\nexport function objectToHtmlAttributes(object: Record): string {\n return reduce(\n object,\n (result: string, value: string, attribute: string): string => {\n return `${result} ${attribute}=\"${value}\"`.trim();\n },\n ''\n );\n}\n\n/**\n * Just a sugar function for helping with matching.\n * It is meant to be extended to specific use-cases like location matching.\n */\nexport function extractFrom(string: string, regex: RegExp): string | null {\n const match = string.match(regex);\n return match && match[1];\n}\n\n/**\n * @see https://stackoverflow.com/a/53472013/11882366\n */\nconst urlRegex = /[^\"](https?:\\/\\/\\S*)/g;\n\nexport function convertUrlsToLinks(string: string): string {\n function makeAnchor(url: string) {\n const anchor = document.createElement('a');\n anchor.setAttribute('href', url);\n anchor.textContent = url;\n return anchor;\n }\n\n return string.replace(urlRegex, url => {\n const anchor = makeAnchor(url.trim());\n\n /**\n * This is temporary. Negative lookbehind, which is what we were using previously to exclude urls that were part of an HTML attribute, don't work in Safari.\n * To get around this, we just don't match if the link is preceded by \". However, that also matches spaces. Check to see if the matched url is preceded with a space,\n * and if so make sure to preserve that space in the output.\n *\n * I imagine we will rethink the usage of this and have the backend send down urls already formatted with anchors.\n */\n if (url.startsWith(' ')) {\n // eslint-disable-next-line\n return ' ' + anchor.outerHTML;\n }\n\n return anchor.outerHTML;\n });\n}\n","import * as React from 'react';\nimport {\n FieldProps as FinalFormFieldProps,\n FieldRenderProps as FinalFormFieldRenderProps,\n Field as FinalFormField,\n} from 'react-final-form';\n\ntype FieldError = string;\n\nexport type FieldRenderProps = {\n input: FinalFormFieldRenderProps['input'];\n meta: FinalFormFieldRenderProps['meta'] & {\n /**\n * The relevant field error to display considering formState\n */\n displayError: FieldError | null | undefined;\n };\n};\n\n/**\n * Given FieldRenderProps which, if any, error should we display inline?\n */\nfunction fieldRPToError({\n meta: {touched, error, submitError, submitFailed, dirtySinceLastSubmit},\n}: FinalFormFieldRenderProps): FieldError | null | undefined {\n if ((touched || submitFailed) && error) {\n return error;\n }\n\n if (submitFailed && !dirtySinceLastSubmit && submitError) {\n return submitError;\n }\n}\n\ninterface FieldProps\n extends Omit, 'children'> {\n children: (arg0: FieldRenderProps) => React.ReactNode;\n}\n\n/**\n * Our own, slightly enhanced Field component\n * Use in place of react-final-form Field for consistent behavior\n */\nexport const Field: React.FC = ({children, ...otherProps}) => (\n \n {/* @ts-ignore */}\n {(fieldRP: FieldRenderProps): React.ReactNode => {\n const displayError = fieldRPToError(fieldRP);\n return children({\n input: fieldRP.input,\n meta: {\n ...fieldRP.meta,\n displayError,\n },\n });\n }}\n \n);\n"],"names":["color","label","labelProps","style","fontWeight","name","props","id","value","display","alignItems","Typography","variant","component","htmlFor","InterestedPartyType","InterestedParty","interestedParty","langStrings","onChange","isForChild","myChild","myself","checked","PromotionCard","promotion","cardSize","url","sx","height","border","textDecoration","href","paddingTop","image","gutterBottom","lineHeight","fontSize","width","py","overflow","textOverflow","WebkitLineClamp","title","promotionPage","actionButton","event","offer","giveaway","shareSubject","shareMessage","timeTitle","locationTitle","onlineEventTitle","multipleLocationsLink","addToCalendar","link","google","iCal","outlook","viewMapLink","locationMap","officeLocationList","error","headline","message","aboutUs","contact","about","main","alt","backdrop","giveaways","enterGiveaway","confirmEnter","body","banner","left","start","totalEntries","userEntries","bonusEntries","subtitle","redeem","current","confirm","adornment","notEnough","minError","redeemButton","workflow","earnButton","revealButton","winnerMessage","terms","eligibility","giveawayPeriod","howToEnter","winnerSelection","winnerNotification","prize","release","dashboard","seeAll","contactInfoFields","firstName","lastName","phone","email","childFirstName","childLastName","isNotRealUser","contactInfoErrors","required","contactMe","postInfoFields","buttonText","signUp","isMember","options","yes","no","requiredError","form","catastrophicError","formConfirmation","callUsNow","empty","logoAlt","highlighted","type","events","offers","showMore","PromotionStatus","PromotionFilterStatus","PromotionType","PromotionField","PromotionLocationType","PromotionAudienceType","PromotionPublishType","renameKeys","keysMap","obj","acc","key","camelcaseValues","location","publish","transformIncomingEntryActions","entryActions","Object","values","transformIncomingParticipantReward","reward","participant","transformIncomingGiveawayWinnerId","winner","transformIncomingPromotionDates","startDate","endDate","transformIncomingPromotion","promotionsResponseToListItems","getPromotionFormattedDateRange","IMT","strongify","render","ucFirst","str","substr","toUpperCase","ucWords","replace","$1","nl2br","stripHTMLTags","passes","reduce","carry","container","document","implementation","createHTMLDocument","innerHTML","textContent","innerText","Field","children","otherProps","fieldRP","displayError","meta","touched","submitError","submitFailed","dirtySinceLastSubmit","fieldRPToError","input"],"sourceRoot":""}