Adweek Agencies Advantage: Publicis Groupe Takes a Major Shot to Grab Sports Spend - Adweek

SUBSCRIPTION ONLY ADWEEK Advantage ADWEEK Creativity Advantage: A Sports Marketing Renaissance Opens the Playing Field to New Brands As sports become increasingly valuable for marketers, brands are shaking up their creative playbooks By Brittaney Kiefer --> ADWEEK House: Advertising HQ brings the people shaping advertising, commerce, and media together for four days of unscripted conversations and after-hours connections. Meet us in Midtown, Oct. 5–8. Now that brands have woken up to the value of sports, more are shaking up their creative playbooks to stand out on a crowded field. One recent example is Always Discreet, the Procter & Gamble-owned adult incontinence brand. Ahead of football season kickoff, Always Discreet teamed up with the NFL to shine a light on bladder leaks. Its ad starred real moms of NFL players talking candidly about their experiences to erase the stigma around incontinence, which affects 60% of women ages 45 and older. The campaign had a few elements that demonstrated a fresh approach to sports partnerships that’s playing out at brands across sectors. (function () { 'use strict'; /** @returns {void} */ function noop() {} /** * @template T * @template S * @param {T} tar * @param {S} src * @returns {T & S} */ function assign(tar, src) { // @ts-ignore for (const k in src) tar[k] = src[k]; return /** @type {T & S} */ (tar); } function run(fn) { return fn(); } function blank_object() { return Object.create(null); } /** * @param {Function[]} fns * @returns {void} */ function run_all(fns) { fns.forEach(run); } /** * @param {any} thing * @returns {thing is Function} */ function is_function(thing) { return typeof thing === 'function'; } /** @returns {boolean} */ function safe_not_equal(a, b) { return a != a ? b == b : a !== b || (a && typeof a === 'object') || typeof a === 'function'; } let src_url_equal_anchor; /** * @param {string} element_src * @param {string} url * @returns {boolean} */ function src_url_equal(element_src, url) { if (element_src === url) return true; if (!src_url_equal_anchor) { src_url_equal_anchor = document.createElement('a'); } // This is actually faster than doing URL(..).href src_url_equal_anchor.href = url; return element_src === src_url_equal_anchor.href; } /** @returns {boolean} */ function is_empty(obj) { return Object.keys(obj).length === 0; } function create_slot(definition, ctx, $scope, fn) { if (definition) { const slot_ctx = get_slot_context(definition, ctx, $scope, fn); return definition[0](slot_ctx); } } function get_slot_context(definition, ctx, $scope, fn) { return definition[1] && fn ? assign($scope.ctx.slice(), definition[1](fn(ctx))) : $scope.ctx; } function get_slot_changes(definition, $scope, dirty, fn) { if (definition[2] && fn) { const lets = definition[2](fn(dirty)); if ($scope.dirty === undefined) { return lets; } if (typeof lets === 'object') { const merged = []; const len = Math.max($scope.dirty.length, lets.length); for (let i = 0; i 32) { const dirty = []; const length = $scope.ctx.length / 32; for (let i = 0; i void} */ function listen(node, event, handler, options) { node.addEventListener(event, handler, options); return () => node.removeEventListener(event, handler, options); } /** * @returns {(event: any) => any} */ function prevent_default(fn) { return function (event) { event.preventDefault(); // @ts-ignore return fn.call(this, event); }; } /** * @returns {(event: any) => void} */ function self(fn) { return function (event) { // @ts-ignore if (event.target === this) fn.call(this, event); }; } /** * @param {Element} node * @param {string} attribute * @param {string} [value] * @returns {void} */ function attr(node, attribute, value) { if (value == null) node.removeAttribute(attribute); else if (node.getAttribute(attribute) !== value) node.setAttribute(attribute, value); } /** * List of attributes that should always be set through the attr method, * because updating them through the property setter doesn't work reliably. * In the example of `width`/`height`, the problem is that the setter only * accepts numeric values, but the attribute can also be set to a string like `50%`. * If this list becomes too big, rethink this approach. */ const always_set_through_set_attribute = ['width', 'height']; /** * @param {Element & ElementCSSInlineStyle} node * @param {{ [x: string]: string }} attributes * @returns {void} */ function set_attributes(node, attributes) { // @ts-ignore const descriptors = Object.getOwnPropertyDescriptors(node.__proto__); for (const key in attributes) { if (attributes[key] == null) { node.removeAttribute(key); } else if (key === 'style') { node.style.cssText = attributes[key]; } else if (key === '__value') { /** @type {any} */ (node).value = node[key] = attributes[key]; } else if ( descriptors[key] && descriptors[key].set && always_set_through_set_attribute.indexOf(key) === -1 ) { node[key] = attributes[key]; } else { attr(node, key, attributes[key]); } } } /** * @param {Element} element * @returns {ChildNode[]} */ function children(element) { return Array.from(element.childNodes); } /** * @param {Text} text * @param {unknown} data * @returns {void} */ function set_data(text, data) { data = '' + data; if (text.data === data) return; text.data = /** @type {string} */ (data); } /** * @returns {void} */ function set_input_value(input, value) { input.value = value == null ? '' : value; } /** * @returns {void} */ function set_style(node, key, value, important) { if (value == null) { node.style.removeProperty(key); } else { node.style.setProperty(key, value, important ? 'important' : ''); } } /** * @returns {void} */ function select_option(select, value, mounting) { for (let i = 0; i } */ function custom_event(type, detail, { bubbles = false, cancelable = false } = {}) { return new CustomEvent(type, { detail, bubbles, cancelable }); } function construct_svelte_component(component, props) { return new component(props); } /** * @typedef {Node & { * claim_order?: number; * hydrate_init?: true; * actual_end_child?: NodeEx; * childNodes: NodeListOf ; * }} NodeEx */ /** @typedef {ChildNode & NodeEx} ChildNodeEx */ /** @typedef {NodeEx & { claim_order: number }} NodeEx2 */ /** * @typedef {ChildNodeEx[] & { * claim_info?: { * last_index: number; * total_claimed: number; * }; * }} ChildNodeArray */ let current_component; /** @returns {void} */ function set_current_component(component) { current_component = component; } function get_current_component() { if (!current_component) throw new Error('Function called outside component initialization'); return current_component; } /** * The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM. * It must be called during the component's initialisation (but doesn't need to live *inside* the component; * it can be called from an external module). * * If a function is returned _synchronously_ from `onMount`, it will be called when the component is unmounted. * * `onMount` does not run inside a [server-side component](https://svelte.dev/docs#run-time-server-side-component-api). * * https://svelte.dev/docs/svelte#onmount * @template T * @param {() => import('./private.js').NotFunction | Promise > | (() => any)} fn * @returns {void} */ function onMount(fn) { get_current_component().$.on_mount.push(fn); } /** * Schedules a callback to run immediately after the component has been updated. * * The first time the callback runs will be after the initial `onMount` * * https://svelte.dev/docs/svelte#afterupdate * @param {() => any} fn * @returns {void} */ function afterUpdate(fn) { get_current_component().$.after_update.push(fn); } /** * Schedules a callback to run immediately before the component is unmounted. * * Out of `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`, this is the * only one that runs inside a server-side component. * * https://svelte.dev/docs/svelte#ondestroy * @param {() => any} fn * @returns {void} */ function onDestroy(fn) { get_current_component().$.on_destroy.push(fn); } /** * Creates an event dispatcher that can be used to dispatch [component events](https://svelte.dev/docs#template-syntax-component-directives-on-eventname). * Event dispatchers are functions that can take two arguments: `name` and `detail`. * * Component events created with `createEventDispatcher` create a * [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). * These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture). * The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) * property and can contain any type of data. * * The event dispatcher can be typed to narrow the allowed event names and the type of the `detail` argument: * ```ts * const dispatch = createEventDispatcher (); * ``` * * https://svelte.dev/docs/svelte#createeventdispatcher * @template {Record } [EventMap=any] * @returns {import('./public.js').EventDispatcher } */ function createEventDispatcher() { const component = get_current_component(); return (type, detail, { cancelable = false } = {}) => { const callbacks = component.$.callbacks[type]; if (callbacks) { // TODO are there situations where events could be dispatched // in a server (non-DOM) environment? const event = custom_event(/** @type {string} */ (type), detail, { cancelable }); callbacks.slice().forEach((fn) => { fn.call(component, event); }); return !event.defaultPrevented; } return true; }; } const dirty_components = []; const binding_callbacks = []; let render_callbacks = []; const flush_callbacks = []; const resolved_promise = /* @__PURE__ */ Promise.resolve(); let update_scheduled = false; /** @returns {void} */ function schedule_update() { if (!update_scheduled) { update_scheduled = true; resolved_promise.then(flush); } } /** @returns {void} */ function add_render_callback(fn) { render_callbacks.push(fn); } // flush() calls callbacks in this order: // 1. All beforeUpdate callbacks, in order: parents before children // 2. All bind:this callbacks, in reverse order: children before parents. // 3. All afterUpdate callbacks, in order: parents before children. EXCEPT // for afterUpdates called during the initial onMount, which are called in // reverse order: children before parents. // Since callbacks might update component values, which could trigger another // call to flush(), the following steps guard against this: // 1. During beforeUpdate, any updated components will be added to the // dirty_components array and will cause a reentrant call to flush(). Because // the flush index is kept outside the function, the reentrant call will pick // up where the earlier call left off and go through all dirty components. The // current_component value is saved and restored so that the reentrant call will // not interfere with the "parent" flush() call. // 2. bind:this callbacks cannot trigger new flush() calls. // 3. During afterUpdate, any updated components will NOT have their afterUpdate // callback called a second time; the seen_callbacks set, outside the flush() // function, guarantees this behavior. const seen_callbacks = new Set(); let flushidx = 0; // Do *not* move this inside the flush() function /** @returns {void} */ function flush() { // Do not reenter flush while dirty components are updated, as this can // result in an infinite loop. Instead, let the inner flush handle it. // Reentrancy is ok afterwards for bindings etc. if (flushidx !== 0) { return; } const saved_component = current_component; do { // first, call beforeUpdate functions // and update components try { while (flushidx (fns.indexOf(c) === -1 ? filtered.push(c) : targets.push(c))); targets.forEach((c) => c()); render_callbacks = filtered; } const outroing = new Set(); /** * @type {Outro} */ let outros; /** * @returns {void} */ function group_outros() { outros = { r: 0, c: [], p: outros // parent group }; } /** * @returns {void} */ function check_outros() { if (!outros.r) { run_all(outros.c); } outros = outros.p; } /** * @param {import('./private.js').Fragment} block * @param {0 | 1} [local] * @returns {void} */ function transition_in(block, local) { if (block && block.i) { outroing.delete(block); block.i(local); } } /** * @param {import('./private.js').Fragment} block * @param {0 | 1} local * @param {0 | 1} [detach] * @param {() => void} [callback] * @returns {void} */ function transition_out(block, local, detach, callback) { if (block && block.o) { if (outroing.has(block)) return; outroing.add(block); outros.c.push(() => { outroing.delete(block); if (callback) { if (detach) block.d(1); callback(); } }); block.o(local); } else if (callback) { callback(); } } /** @typedef {1} INTRO */ /** @typedef {0} OUTRO */ /** @typedef {{ direction: 'in' | 'out' | 'both' }} TransitionOptions */ /** @typedef {(node: Element, params: any, options: TransitionOptions) => import('../transition/public.js').TransitionConfig} TransitionFn */ /** * @typedef {Object} Outro * @property {number} r * @property {Function[]} c * @property {Object} p */ /** * @typedef {Object} PendingProgram * @property {number} start * @property {INTRO|OUTRO} b * @property {Outro} [group] */ /** * @typedef {Object} Program * @property {number} a * @property {INTRO|OUTRO} b * @property {1|-1} d * @property {number} duration * @property {number} start * @property {number} end * @property {Outro} [group] */ // general each functions: function ensure_array_like(array_like_or_iterator) { return array_like_or_iterator?.length !== undefined ? array_like_or_iterator : Array.from(array_like_or_iterator); } /** @returns {{}} */ function get_spread_update(levels, updates) { const update = {}; const to_null_out = {}; const accounted_for = { $scope: 1 }; let i = levels.length; while (i--) { const o = levels[i]; const n = updates[i]; if (n) { for (const key in o) { if (!(key in n)) to_null_out[key] = 1; } for (const key in n) { if (!accounted_for[key]) { update[key] = n[key]; accounted_for[key] = 1; } } levels[i] = n; } else { for (const key in o) { accounted_for[key] = 1; } } } for (const key in to_null_out) { if (!(key in update)) update[key] = undefined; } return update; } function get_spread_object(spread_props) { return typeof spread_props === 'object' && spread_props !== null ? spread_props : {}; } /** @returns {void} */ function create_component(block) { block && block.c(); } /** @returns {void} */ function mount_component(component, target, anchor) { const { fragment, after_update } = component.$; fragment && fragment.m(target, anchor); // onMount happens before the initial afterUpdate add_render_callback(() => { const new_on_destroy = component.$.on_mount.map(run).filter(is_function); // if the component was destroyed immediately // it will update the `$.on_destroy` reference to `null`. // the destructured on_destroy may still reference to the old array if (component.$.on_destroy) { component.$.on_destroy.push(...new_on_destroy); } else { // Edge case - component was destroyed immediately, // most likely as a result of a binding initialising run_all(new_on_destroy); } component.$.on_mount = []; }); after_update.forEach(add_render_callback); } /** @returns {void} */ function destroy_component(component, detaching) { const $ = component.$; if ($.fragment !== null) { flush_render_callbacks($.after_update); run_all($.on_destroy); $.fragment && $.fragment.d(detaching); // TODO null out other refs, including component.$ (but need to // preserve final state?) $.on_destroy = $.fragment = null; $.ctx = []; } } /** @returns {void} */ function make_dirty(component, i) { if (component.$.dirty[0] === -1) { dirty_components.push(component); schedule_update(); component.$.dirty.fill(0); } component.$.dirty[(i / 31) | 0] |= 1 void} [append_styles] Function that appends styles to the DOM when the component is first initialised. * This will be the `add_css` function from the compiled component. * * @returns {void} */ function init( component, options, instance, create_fragment, not_equal, props, append_styles = null, dirty = [-1] ) { const parent_component = current_component; set_current_component(component); /** @type {import('./private.js').T$} */ const $ = (component.$ = { fragment: null, ctx: [], // state props, update: noop, not_equal, bound: blank_object(), // lifecycle on_mount: [], on_destroy: [], on_disconnect: [], before_update: [], after_update: [], context: new Map(options.context || (parent_component ? parent_component.$.context : [])), // everything else callbacks: blank_object(), dirty, skip_bound: false, root: options.target || parent_component.$.root }); append_styles && append_styles($.root); let ready = false; $.ctx = instance ? instance(component, options.props || {}, (i, ret, ...rest) => { const value = rest.length ? rest[0] : ret; if ($.ctx && not_equal($.ctx[i], ($.ctx[i] = value))) { if (!$.skip_bound && $.bound[i]) $.bound[i](value); if (ready) make_dirty(component, i); } return ret; }) : []; $.update(); ready = true; run_all($.before_update); // `false` as a special case of no DOM component $.fragment = create_fragment ? create_fragment($.ctx) : false; if (options.target) { if (options.hydrate) { // TODO: what is the correct type here? // @ts-expect-error const nodes = children(options.target); $.fragment && $.fragment.l(nodes); nodes.forEach(detach); } else { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion $.fragment && $.fragment.c(); } if (options.intro) transition_in(component.$.fragment); mount_component(component, options.target, options.anchor); flush(); } set_current_component(parent_component); } /** * Base class for Svelte components. Used when dev=false. * * @template {Record } [Props=any] * @template {Record } [Events=any] */ class SvelteComponent { /** * ### PRIVATE API * * Do not use, may change at any time * * @type {any} */ $ = undefined; /** * ### PRIVATE API * * Do not use, may change at any time * * @type {any} */ $set = undefined; /** @returns {void} */ $destroy() { destroy_component(this, 1); this.$destroy = noop; } /** * @template {Extract } K * @param {K} type * @param {((e: Events[K]) => void) | null | undefined} callback * @returns {() => void} */ $on(type, callback) { if (!is_function(callback)) { return noop; } const callbacks = this.$.callbacks[type] || (this.$.callbacks[type] = []); callbacks.push(callback); return () => { const index = callbacks.indexOf(callback); if (index !== -1) callbacks.splice(index, 1); }; } /** * @param {Partial } props * @returns {void} */ $set(props) { if (this.$set && !is_empty(props)) { this.$.skip_bound = true; this.$set(props); this.$.skip_bound = false; } } } /** * @typedef {Object} CustomElementPropDefinition * @property {string} [attribute] * @property {boolean} [reflect] * @property {'String'|'Boolean'|'Number'|'Array'|'Object'} [type] */ // generated during release, do not modify const PUBLIC_VERSION = '4'; if (typeof window !== 'undefined') // @ts-ignore (window.__svelte || (window.__svelte = { v: new Set() })).v.add(PUBLIC_VERSION); // Some height larger than whats resonable expected, // but not so large as to infulence the transition time const TRANSITION_OPEN_HEIGHT = '700px'; // Absolute max height const MAX_OPEN_HEIGHT = '10000px'; const CLOSED_HEIGHT = '0px'; const DURATION_MS = 500; function accordion(node, isOpen) { let currentState = isOpen; node.style.maxHeight = isOpen ? MAX_OPEN_HEIGHT : CLOSED_HEIGHT; node.style.overflow = isOpen ? "unset" : "hidden"; const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)'); const animationsDisabled = mediaQuery.matches; if (animationsDisabled) { node.style.display = isOpen ? 'unset' : 'none'; } return { update(isOpen) { if (animationsDisabled) { node.style.display = isOpen ? 'unset' : 'none'; return; } if (isOpen === currentState) { return; } currentState = isOpen; const toHeight = isOpen ? TRANSITION_OPEN_HEIGHT : CLOSED_HEIGHT; const fromHeight = isOpen ? CLOSED_HEIGHT : TRANSITION_OPEN_HEIGHT; node.animate([ { maxHeight: fromHeight, overflow: 'hidden' }, { maxHeight: toHeight, overflow: 'hidden' }, ], { duration: DURATION_MS, fill: 'both', }).addEventListener("finish", () => { // After the opening transition, unset the max height so if it's larger than OPEN_HEIGHT the content // will be shown, but via a quick jump if (!isOpen) { return; } node.animate([ { maxHeight: toHeight, overflow: 'hidden' }, { maxHeight: MAX_OPEN_HEIGHT, overflow: 'hidden' }, ], { duration: 100, fill: 'both', }); }); } }; } const elementTypes = { PROGRESS_BAR: 'progress_bar', PAYMENT_OPTION_SELECTION: 'payment_option_selection', PASSWORD: 'password', VERIFICATION_CODE: 'otp_code', BUTTON: 'button', PAYMENT: 'payment', PAYMENT_PRE_LOADER: 'payment-pre-loader', EMAIL_ADDRESS: 'email_address', SUCCESS_MESSAGE: 'success_message', TEXT: 'text', USER_ATTRIBUTE: 'user_attribute', RESET_PASSWORD_LINK: 'link', RESEND_LOGIN_LINK: 'resend_login_link', SOCIAL_SIGNIN: 'social_sign_in', PAYMENT_SUMMARY: 'payment_summary', DIVIDER: 'divider', LOGIN_LINK: 'show_login_link', ACCOUNT_MEMBERSHIP_CODE: 'account_code', MOBILE_PAYMENT: 'mobile_payment', INVITATION: 'invitation', TEMPLATE_COMPONENT: 'template_component', SUBSCRIPTION_SELECT: 'subscription_select', EVENT_LINK: 'event_link', SUBSCRIPTIONS_LIST: 'subscriptions_list', PAST_SUBSCRIPTIONS_LINK: 'past_subscriptions_link', BILLING_HISTORY: 'billing_history', CHNAGE_PAYMENT_METHOD_BUTTON: 'change_payment_method_button', READ_ONLY_EMAIL_ADDRESS: 'read_only_email_address', READ_ONLY_PASSWORD: 'read_only_password', READ_ONLY_USER_ATTRIBUTE: 'read_only_user_attribute', CHNAGE_PAYMENT_METHOD: 'change_payment_method', DEVICES_SESSIONS_LIST: 'devices_list', SIGN_OUT_ALL_OTHER_DEVICES: 'sign_out_of_devices_button', TABLINK: 'tablink', BUTTON_GROUP: 'button_group', LINK_BUTTON: 'link_button', RECIPIENT_NAME: 'recipient_name', RECIPIENT_EMAIL: 'recipient_email', RECIPIENT_ADDRESS: 'recipient_address', RECIPIENT_MESSAGE: 'recipient_message', GIFT_CODE: 'gift_code', GIFT_SUBSCRIPTIONS_LIST: 'gift_subscriptions_list', GIFT_TOGGLE: 'gift_toggle', GIFT_FUTURE_DATE_TOGGLE: 'gift_future_date_toggle', GIFT_FUTURE_DATE_INPUT: 'gift_future_date_input', PAYMENT_AUTO_RENEW_TOGGLE: 'payment_auto_renew_toggle', SUSPEND_RESUME_SUBSCRIPTION: 'suspend_resume_subscription', SUBSCRIPTION_CUSTOM_FIELDS_UPDATE: 'subscription_custom_fields_update', SUBSCRIPTION_CUSTOM_FIELDS_LIST: 'subscription_custom_fields_list', BILL_TO_CONTACT: 'bill_to_contact', BILLING_COUNTRY: 'billing_country', BILLING_STATE: 'billing_state', CATALOG_PAYMENT_OPTION_SELECTION: 'catalog_payment_option_selection', RECAPTCHA: 'recaptcha', }; var FormEvent; (function (FormEvent) { FormEvent["FORM_START"] = "FORM_START"; FormEvent["LOGIN_REGISTRATION_COMPLETE"] = "LOGIN_REGISTRATION_COMPLETE"; FormEvent["SECTION_EMAIL_COMPLETE"] = "SECTION_EMAIL_COMPLETE"; FormEvent["SECTION_PASSWORD_RESET_COMPLETE"] = "SECTION_PASSWORD_RESET_COMPLETE"; FormEvent["SECTION_FORGOT_PASSWORD_COMPLETE"] = "SECTION_FORGOT_PASSWORD_COMPLETE"; FormEvent["PART_PLAN_SELECT_COMPLETE"] = "PART_PLAN_SELECT_COMPLETE"; FormEvent["PART_ACCOUNT_VERIFICATION_COMPLETE"] = "PART_ACCOUNT_VERIFICATION_COMPLETE"; FormEvent["PART_GIFT_RECIPIENT_COMPLETE"] = "PART_GIFT_RECIPIENT_COMPLETE"; FormEvent["PART_PAYMENT_COMPLETE"] = "PART_PAYMENT_COMPLETE"; FormEvent["PART_SUCCESS_COMPLETE"] = "PART_SUCCESS_COMPLETE"; FormEvent["PART_CONTACT_VERIFICATION_COMPLETE"] = "PART_CONTACT_VERIFICATION_COMPLETE"; FormEvent["PART_PROFILE_UPDATE_COMPLETE"] = "PART_PROFILE_UPDATE_COMPLETE"; FormEvent["PART_EMAIL_UPDATE_COMPLETE"] = "PART_EMAIL_UPDATE_COMPLETE"; FormEvent["PART_EMAIL_UPDATE_OTP_COMPLETE"] = "PART_EMAIL_UPDATE_OTP_COMPLETE"; FormEvent["PART_EMAIL_UPDATE_CONFIRMATION_COMPLETE"] = "PART_EMAIL_UPDATE_CONFIRMATION_COMPLETE"; FormEvent["PART_PASSWORD_UPDATE_COMPLETE"] = "PART_PASSWORD_UPDATE_COMPLETE"; FormEvent["PART_PASSWORD_UPDATE_OTP_COMPLETE"] = "PART_PASSWORD_UPDATE_OTP_COMPLETE"; FormEvent["PART_ATTRIBUTES_UPDATE_COMPLETE"] = "PART_ATTRIBUTES_UPDATE_COMPLETE"; FormEvent["REGISTRATION_CUSTOM_COMPLETE"] = "REGISTRATION_CUSTOM_COMPLETE"; FormEvent["SELECT_SUBSCRIPTION_COMPLETE"] = "SELECT_SUBSCRIPTION_COMPLETE"; FormEvent["UPDATE"] = "UPDATE"; FormEvent["GO_BACK"] = "GO_BACK"; FormEvent["VERIFY_EMAIL_UPDATE_OTP"] = "VERIFY_EMAIL_UPDATE_OTP"; FormEvent["VERIFY_PASSWORD_UPDATE_OTP"] = "VERIFY_PASSWORD_UPDATE_OTP"; FormEvent["PART_CHANGE_PAYMENT_COMPLETE"] = "PART_CHANGE_PAYMENT_COMPLETE"; FormEvent["LIST_DEVICES_SESSIONS"] = "LIST_DEVICES_SESSIONS"; FormEvent["SIGN_OUT_ALL_DEVICES"] = "SIGN_OUT_ALL_DEVICES"; FormEvent["SIGN_OUT_SINGLE_DEVICE"] = "SIGN_OUT_SINGLE_DEVICE"; FormEvent["GIFT_REDEMPTION_COMPLETE"] = "GIFT_REDEMPTION_COMPLETE"; FormEvent["SUSPEND_RESUME_SUBSCRIPTION_COMPLETE"] = "SUSPEND_RESUME_SUBSCRIPTION_COMPLETE"; FormEvent["BILL_TO_CONTACT_COMPLETE"] = "BILL_TO_CONTACT_COMPLETE"; })(FormEvent || (FormEvent = {})); const partTypes = { PLAN_SELECT: { type: 'plan-select', order: 0, completionEvent: FormEvent.PART_PLAN_SELECT_COMPLETE }, ACCOUNT_VERIFICATION: { type: 'account-verification', order: 1, completionEvent: FormEvent.PART_ACCOUNT_VERIFICATION_COMPLETE }, GIFT_RECIPIENT: { type: 'gift-recipient', order: 1, completionEvent: FormEvent.PART_GIFT_RECIPIENT_COMPLETE }, PAYMENT: { type: 'payment', order: 2, completionEvent: FormEvent.PART_PAYMENT_COMPLETE }, SUCCESS: { type: 'success', order: 3, completionEvent: FormEvent.PART_SUCCESS_COMPLETE }, CONTACT_VERIFICATION: { type: 'contact-verification', order: 1, completionEvent: FormEvent.PART_CONTACT_VERIFICATION_COMPLETE }, PROFILE_UPDATE: { type: 'profile-update', order: 0, completionEvent: FormEvent.PART_PROFILE_UPDATE_COMPLETE }, SELECT_SUBSCRIPTION: { type: 'select-subscription', order: 0, completionEvent: FormEvent.SELECT_SUBSCRIPTION_COMPLETE }, EMAIL_UPDATE: { type: 'email-update', order: 0, completionEvent: FormEvent.PART_EMAIL_UPDATE_COMPLETE }, EMAIL_UPDATE_OTP: { type: 'email-update-otp', order: 0, completionEvent: FormEvent.PART_EMAIL_UPDATE_OTP_COMPLETE }, EMAIL_UPDATE_CONFIRMATION: { type: 'email-update-confirmation', order: 0, completionEvent: FormEvent.PART_EMAIL_UPDATE_CONFIRMATION_COMPLETE }, PASSWORD_UPDATE: { type: 'password-update', order: 0, completionEvent: FormEvent.PART_PASSWORD_UPDATE_COMPLETE }, PASSWORD_UPDATE_OTP: { type: 'password-update-otp', order: 0, completionEvent: FormEvent.PART_PASSWORD_UPDATE_OTP_COMPLETE }, ATTRIBUTES_UPDATE: { type: 'attributes-update', order: 0, completionEvent: FormEvent.PART_ATTRIBUTES_UPDATE_COMPLETE }, LIST_SUBSCRIPTIONS: { type: 'list-subscriptions', order: 0, }, BILLING_HISTORY: { type: 'billing-history', order: 0, }, PAST_SUBSCRIPTIONS: { type: 'past-subscriptions', order: 0, }, CHANGE_PAYMENT: { type: 'change-payment', order: 2, completionEvent: FormEvent.PART_CHANGE_PAYMENT_COMPLETE }, DEVICES_SESSIONS: { type: 'devices-sessions', order: 0, completionEvent: FormEvent.LIST_DEVICES_SESSIONS }, CANCEL_SUCCESS: { type: 'cancel-success', order: 3, }, GIFT_REDEMPTION: { type: 'gift_redemption', order: 4 }, GIFT_DETAILS: { type: 'gift-details', order: 1 }, SUSPEND_RESUME_SUBSCRIPTION: { type: 'suspend-resume-subscription', order: 0, completionEvent: FormEvent.SUSPEND_RESUME_SUBSCRIPTION_COMPLETE }, SUBSCRIPTION_CUSTOM_FIELDS: { type: 'subscription-custom-fields', order: 0, }, BILL_TO_CONTACT: { type: 'bill-to-contact', order: 0, completionEvent: FormEvent.BILL_TO_CONTACT_COMPLETE } }; const partTypeFor = (type) => Object.values(partTypes).find(p => p.type == type) || (() => { throw `No part ${type} found`; })(); var ServerError; (function (ServerError) { ServerError[ServerError["USER_DOES_NOT_EXIST"] = 0] = "USER_DOES_NOT_EXIST"; ServerError[ServerError["USER_ALREADY_EXISTS"] = 1] = "USER_ALREADY_EXISTS"; ServerError[ServerError["PASSWORD_NOT_STRONG_ENOUGH"] = 2] = "PASSWORD_NOT_STRONG_ENOUGH"; ServerError[ServerError["EMAIL_VERIFICATION_REQUIRED"] = 3] = "EMAIL_VERIFICATION_REQUIRED"; ServerError[ServerError["VERIFICATION_CODE_OR_PASSWORD_INCORRECT"] = 4] = "VERIFICATION_CODE_OR_PASSWORD_INCORRECT"; ServerError[ServerError["VERIFICATION_CODE_INCORRECT"] = 5] = "VERIFICATION_CODE_INCORRECT"; ServerError[ServerError["LOGIN_FAILED"] = 6] = "LOGIN_FAILED"; ServerError[ServerError["UNKNOWN_LOGIN_REGISTER_ERROR"] = 7] = "UNKNOWN_LOGIN_REGISTER_ERROR"; ServerError[ServerError["NO_COOKIE_FROM_LOGIN_REGISTER_ERROR"] = 8] = "NO_COOKIE_FROM_LOGIN_REGISTER_ERROR"; ServerError[ServerError["NO_ACCOUNT_ACCESS"] = 9] = "NO_ACCOUNT_ACCESS"; ServerError[ServerError["ACCOUNT_NOT_FOUND"] = 10] = "ACCOUNT_NOT_FOUND"; ServerError[ServerError["PAYMENT_PROCESSING_ERROR"] = 11] = "PAYMENT_PROCESSING_ERROR"; ServerError[ServerError["MOBILE_PAYMENT_PROCESSING_ERROR"] = 12] = "MOBILE_PAYMENT_PROCESSING_ERROR"; ServerError[ServerError["PASSWORD_RESET_LINK_SEND_ERROR"] = 13] = "PASSWORD_RESET_LINK_SEND_ERROR"; ServerError[ServerError["PASSWORD_RESET_ERROR"] = 14] = "PASSWORD_RESET_ERROR"; ServerError[ServerError["VERIFICATION_CODE_SEND_ERROR"] = 15] = "VERIFICATION_CODE_SEND_ERROR"; ServerError[ServerError["SOCIAL_SIGNIN_REGISTRATION_LOGIN_ERROR"] = 16] = "SOCIAL_SIGNIN_REGISTRATION_LOGIN_ERROR"; ServerError[ServerError["PROMO_CODE_EXPIRED_ERROR"] = 17] = "PROMO_CODE_EXPIRED_ERROR"; ServerError[ServerError["PROMO_CODE_INVALID_ERROR"] = 18] = "PROMO_CODE_INVALID_ERROR"; ServerError[ServerError["PROMO_CODE_NOT_VALID_FOR_PLAN_ERROR"] = 19] = "PROMO_CODE_NOT_VALID_FOR_PLAN_ERROR"; ServerError[ServerError["INVITATION_FAILED_LIMIT_REACHED"] = 20] = "INVITATION_FAILED_LIMIT_REACHED"; ServerError[ServerError["INVITATION_FAILED_DUPLICATE_EMAIL"] = 21] = "INVITATION_FAILED_DUPLICATE_EMAIL"; ServerError[ServerError["INVITATION_FAILED_INVALID_EMAIL"] = 22] = "INVITATION_FAILED_INVALID_EMAIL"; ServerError[ServerError["INVITATION_FAILED_NO_PRODUCT_ACCESS"] = 23] = "INVITATION_FAILED_NO_PRODUCT_ACCESS"; ServerError[ServerError["INVITATION_FAILED_UNKNOWN"]

Curated by Taleb Kabbara · Source: www.adweek.com