diff --git a/blocks/event-editor/event-editor.css b/blocks/event-editor/event-editor.css deleted file mode 100644 index dc4a4aae..00000000 --- a/blocks/event-editor/event-editor.css +++ /dev/null @@ -1,88 +0,0 @@ -.event-editor { - display: grid; - grid-template-columns: 1fr; - gap: var(--spacing-s); - padding: var(--spacing-m); -} - -.event-editor form { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: var(--spacing-m); - background-color: var(--background-color); - border: 1px solid var(--color-gray-300); - box-shadow: 0 2px 4px var(--color-gray-100); - border-radius: 4px; - padding: var(--spacing-m); -} - -.event-editor form > div.sub-grid { - grid-column: 1 / -1; - display: grid; -} - -.event-editor fieldset { - grid-column: 1 / -1; /* Make fieldsets span all columns */ - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: var(--spacing-s); - border: 1px solid var(--color-gray-300); - border-radius: 4px; - padding: var(--spacing-m); -} - -.event-editor legend { - grid-column: 1 / -1; - font-weight: bold; - color: var(--link-color); -} - -.event-editor label { - display: block; - margin-bottom: var(--spacing-xs); - color: var(--color-gray-600); -} - -.event-editor input[type="text"][name="url"] { - grid-column: 1 / 3; -} - -.event-editor input[type="text"], -.event-editor input[type="file"], -.event-editor textarea, -.event-editor button { - width: 100%; - padding: var(--spacing-xs); - border: 1px solid var(--color-gray-300); - border-radius: 4px; - box-sizing: border-box; -} - -.event-editor button, -.event-editor.add-participant-btn, -.event-editor .remove-participant-btn { - width: max-content; - box-sizing: border-box; - margin: 8px; - height: max-content; - background-color: var(--color-accent); - color: var(--color-white); - border: none; - padding: var(--spacing-xs); - cursor: pointer; - align-self: end; -} - -.event-editor .button[type="submit"] { - align-self: end; -} - -.event-editor button:hover { - opacity: 0.8; -} - -@media (min-width: 900px) { - .event-editor form { - grid-template-columns: repeat(2, 1fr); /* Two columns for larger screens */ - } -} diff --git a/blocks/event-editor/event-editor.js b/blocks/event-editor/event-editor.js deleted file mode 100644 index 6c8545c5..00000000 --- a/blocks/event-editor/event-editor.js +++ /dev/null @@ -1,153 +0,0 @@ -import { getLibs } from '../../scripts/utils.js'; - -const { html, render, useRef, useState } = await import(`${getLibs()}/deps/htm-preact.js`); - -export default function init(el) { - // Mock search function - const mockSearch = () => new Promise((resolve) => { - setTimeout(() => { - resolve({ - id: '6c0ce564-3335-5d20-95f6-cb35ccee571b', - styles: { - typeOverride: 'event', - backgroundImage: 'https://summit.adobe.com/_assets/images/home/speakers-promo@2x.jpg', - mnemonic: '', - }, - arbitrary: [ - { key: 'promoId', value: 'splash-that|458926431' }, - { key: 'timezone', value: 'America/Los_Angeles' }, - { key: 'venue', value: 'La Costa Resort and Spa' }, - ], - contentArea: { - detailText: 'detail', - title: 'TestTier3Event1', - url: 'https://main--events-milo--adobecom.hlx.page/t3/event/03-12-2024/chicago/il/adobe-events-seminar', - description: 'TestTier3Event1', - }, - footer: [{ - divider: false, - left: [], - center: [], - right: [{ - type: 'button', - style: '', - text: 'Read now', - href: 'https://main--events-milo--adobecom.hlx.page/t3/event/03-12-2024/chicago/il/adobe-events-seminar', - }], - }], - }); - }, 1000); - }); - - // DynamicForm Component - const DynamicForm = ({ data }) => { - // Updating state to handle both speakers and hosts - const [participants, setParticipants] = useState([]); - - const handleSubmit = (event) => { - event.preventDefault(); - // Prepare and log the data to be submitted - const formData = new FormData(event.target); - // Example of handling form data here - console.log(formData, 'Form submitted with updated data'); - alert('Check the console for submitted data.'); - }; - - const addParticipant = (type) => { - setParticipants([ - ...participants, - { id: Math.random().toString(16).slice(2), type }, - ]); - }; - - const removeParticipant = (id) => { - setParticipants((current) => current.filter((p) => p.id !== id)); - }; - - const renderInputField = (name, value, label) => html` -
- - -
- `; - - const renderParticipantInputs = (participant) => html` -
- ${participant.type.charAt(0).toUpperCase() + participant.type.slice(1)} Details -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
- -
- `; - - return html` -
- ${Object.entries(data).map(([key, value]) => { - if (typeof value === 'object' && !Array.isArray(value) && value !== null) { - return Object.entries(value).map(([subKey, subValue]) => renderInputField(`${key}.${subKey}`, subValue, `${subKey.charAt(0).toUpperCase() + subKey.slice(1)}`)); - } if (typeof value === 'string') { - return renderInputField(key, value, `${key.charAt(0).toUpperCase() + key.slice(1)}`); - } - return null; - })} -
- ${participants.map(renderParticipantInputs)} -
- - -
-
- -
- `; - }; - - // App Component - const App = () => { - const [data, setData] = useState(null); - const inputRef = useRef(null); - - const handleSubmit = async (event) => { - event.preventDefault(); - const url = inputRef.current.value; - const result = await mockSearch(url); - setData(result); - }; - - return html` -
- ${!data ? html` -
- - -
- ` : html` - <${DynamicForm} data=${data} /> - `} -
- `; - }; - - // Render the App - render(html`<${App} />`, el); -} diff --git a/blocks/event-map/event-map.css b/blocks/event-map/event-map.css deleted file mode 100644 index b4a5c339..00000000 --- a/blocks/event-map/event-map.css +++ /dev/null @@ -1,30 +0,0 @@ -.event-map { - display: flex; - flex-direction: column; - gap: 24px; - margin: 0 auto; -} - -.event-map > div:first-of-type { - width: var(--grid-container-width); - margin: 0 auto; -} - -.event-map .mapbox-container { - height: 300px; - min-width: calc(100vw - 20px); -} - -@media (min-width: 900px) { - .event-map { - flex: 1 1 0; - flex-direction: row; - max-width: var(--grid-container-width); - justify-content: center; - align-items: center; - } - - .event-map .mapbox-container { - min-width: 50%; - } -} diff --git a/blocks/event-map/event-map.js b/blocks/event-map/event-map.js deleted file mode 100644 index f317775a..00000000 --- a/blocks/event-map/event-map.js +++ /dev/null @@ -1,53 +0,0 @@ -/* global mapboxgl */ - -import { getLibs } from '../../scripts/utils.js'; - -const { loadScript, loadStyle } = await import(`${getLibs()}/utils/utils.js`); - -const MAPBOX_API_TOKEN = 'cGsuZXlKMUlqb2ljV2w1ZFc1a1lXa2lMQ0poSWpvaVkydHJOSEp3ZVdsMk1XczRaVEp2YjNSck5IcDBiVFl5WVNKOS5QZ25PR0NWcVluU3VnUlBYb2ZKYWtR'; - -function loadMapboxConfigs(el) { - const configs = {}; - const configsDiv = el.querySelector(':scope > div:last-of-type'); - - if (!configsDiv) return null; - - Array.from(configsDiv.children).forEach((col, i) => { - if (i === 0) configs.mapStyle = col.textContent.trim(); - if (i === 1) configs.coordinates = col.textContent.split(','); - if (i === 2) configs.zoom = parseInt(col.textContent.trim(), 10); - }); - - configs.mapContainer = configsDiv; - return configs; -} - -function decorateMapContainer(configs) { - const { mapContainer } = configs; - mapContainer.innerHTML = ''; - mapContainer.classList.add('mapbox-container'); - mapContainer.id = 'mapbox-container'; -} - -export default async function init(el) { - const configs = loadMapboxConfigs(el); - if (!configs) return; - - decorateMapContainer(configs); - loadStyle('https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.css'); - loadScript('https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.js', 'module').then(() => { - window.mapboxgl.accessToken = window.atob(MAPBOX_API_TOKEN); - const map = new mapboxgl.Map({ - container: 'mapbox-container', - style: configs.mapStyle, - center: configs.coordinates, - zoom: configs.zoom, - }); - - const marker1 = new mapboxgl.Marker() - .setLngLat(configs.coordinates) - .addTo(map); - - console.log(marker1); - }); -} diff --git a/blocks/event-tags/event-tags.css b/blocks/event-tags/event-tags.css deleted file mode 100644 index 2100b0e5..00000000 --- a/blocks/event-tags/event-tags.css +++ /dev/null @@ -1,38 +0,0 @@ -.event-tags { - margin: 20px auto; - overflow: auto; -} - -.event-tags .tags-wrapper { - margin: auto; - padding: 8px 16px; - width: max-content; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px; -} - -.event-tags .tag { - display: flex; - align-items: center; - box-sizing: border-box; - padding: 4px 12px; - background: var(--color-gray-200); - font-size: 14px; - font-weight: 700; - border-radius: 50px; - white-space: nowrap; -} - -.event-tags .tag img { - margin-right: 8px; - height: 18px; -} - -@media (min-width: 900px) { - .event-tags .tags-wrapper { - display: flex; - } - - -} diff --git a/blocks/event-tags/event-tags.js b/blocks/event-tags/event-tags.js deleted file mode 100644 index 9e54c03b..00000000 --- a/blocks/event-tags/event-tags.js +++ /dev/null @@ -1,46 +0,0 @@ -import { getLibs } from '../../scripts/utils.js'; - -const { createTag } = await import(`${getLibs()}/utils/utils.js`); - -function handlize(str) { - return str.toLowerCase().trim().replace(' ', '-'); -} - -function getTagIcon(tag) { - const availableIcons = [ - 'illustrator', - 'graphic-design', - 'photography', - 'social', - '3d-ar', - ]; - - const img = createTag('img', { class: 'icon icon-label', src: '/blocks/event-tags/icons/label.svg', alt: tag }); - - if (availableIcons.includes(tag)) { - img.className = `icon icon-${tag}`; - img.src = `/blocks/event-tags/icons/${tag}.svg`; - img.alt = tag; - } - - return img; -} - -export default function init(el) { - const tags = el.textContent.split(','); - el.innerHTML = ''; - const tagsWrapper = createTag('div', { class: 'tags-wrapper' }); - - tags.forEach((tag) => { - const tagEl = createTag('div', { class: 'tag' }); - // TODO: use localized text - const text = tag; - const icon = getTagIcon(handlize(tag)); - - tagEl.append(icon, text); - - tagsWrapper.append(tagEl); - }); - - el.append(tagsWrapper); -} diff --git a/blocks/event-tags/icons/3d-ar.svg b/blocks/event-tags/icons/3d-ar.svg deleted file mode 100644 index 23f2af6e..00000000 --- a/blocks/event-tags/icons/3d-ar.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - S 3DMaterials 18 N - - - - diff --git a/blocks/event-tags/icons/graphic-design.svg b/blocks/event-tags/icons/graphic-design.svg deleted file mode 100644 index 1827deb7..00000000 --- a/blocks/event-tags/icons/graphic-design.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - S Graphic 18 N - - diff --git a/blocks/event-tags/icons/illustrator.svg b/blocks/event-tags/icons/illustrator.svg deleted file mode 100644 index 70c782fc..00000000 --- a/blocks/event-tags/icons/illustrator.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - S Actions 18 N - - - - diff --git a/blocks/event-tags/icons/label.svg b/blocks/event-tags/icons/label.svg deleted file mode 100644 index 02ddcbe8..00000000 --- a/blocks/event-tags/icons/label.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - S Label 18 N - - diff --git a/blocks/event-tags/icons/photography.svg b/blocks/event-tags/icons/photography.svg deleted file mode 100644 index 7bf7d91f..00000000 --- a/blocks/event-tags/icons/photography.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - S Camera 18 N - - - diff --git a/blocks/event-tags/icons/social.svg b/blocks/event-tags/icons/social.svg deleted file mode 100644 index d9d0aa05..00000000 --- a/blocks/event-tags/icons/social.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - S SocialNetwork 18 N - - diff --git a/blocks/events-form/events-form.css b/blocks/events-form/events-form.css deleted file mode 100644 index 5672514b..00000000 --- a/blocks/events-form/events-form.css +++ /dev/null @@ -1,330 +0,0 @@ -.events-form { - --input-border-radius: 4px; - - padding: var(--spacing-xl); - border-radius: var(--card-border-radius-l); - filter: var(--image-filter-drop-shadow-small); - border: solid 1px var(--bg-color-grey); - box-sizing: border-box; - max-width: 800px; - margin: 0 auto; - color: #2C2C2C; - transition: opacity 0.4s; -} - -.events-form.loading { - opacity: 0; -} - -.events-form .event-form-hero { - display: flex; - flex-direction: column-reverse; - align-items: center; - gap: 16px; -} - -.events-form .event-form-hero > div { - flex: 1 1 0; -} - -.events-form .event-form-hero img { - display: block; -} - -.events-form form { - width: 100%; - display: flex; - flex-wrap: wrap; - padding-top: 24px; -} - -.events-form form .first-form-section { - display: flex; - align-items: center; - flex-direction: column; - gap: 24px; -} - -.events-form h2 { - margin: 0; - padding: var(--spacing-s) 0; - font-size: var(--type-heading-l-lh); -} - -.events-form h3 { - padding-top: var(--spacing-s); - font-size: var(--type-heading-m-size); -} - -.events-form :is(input, textarea, select) { - border: solid 1px var(--color-gray-500); - padding: var(--spacing-xxs) var(--spacing-xs); - width: 100%; - box-sizing: border-box; - border-radius: var(--input-border-radius); - font-size: var(--type-body-xs-size); - line-height: var(--type-body-xs-lh); -} - -.events-form textarea { - min-height: 100px; - resize: vertical; -} - -.events-form :is(input, textarea, select):hover { - border-color: var(--color-gray-600); -} - -.events-form :is(input, textarea, select):is(:focus, :focus-visible, :focus-within, :active) { - border-color: var(--color-gray-700); - outline-color: var(--color-accent); - outline-offset: 4px; -} - -.events-form select { - appearance: none; - background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii01OCAyOSAzMiAzNCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAtNTggMjkgMzIgMzQiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGQ9Im0tNTYgNDMgNi0xMiA2IDEyaC0xMnpNLTQ0IDQ5bC02IDEyLTYtMTJoMTJ6IiBmaWxsPSIjNTM1MzUzIi8+PC9zdmc+') no-repeat 128% 54%; - background-color: var(--color-white); - background-position: 98% 50%; - background-size: 1em 1em; -} - -.events-form label { - display: block; - padding-bottom: var(--spacing-xxs); - box-sizing: border-box; - font-size: var(--type-body-s-size); - line-height: var(--type-body-s-lh); - font-weight: 600; -} - -.events-form label.required::after { - content: "*"; - color: var(--color-black); - padding-left: var(--spacing-xxxs); -} - -.events-form .field-wrapper { - margin-bottom: var(--spacing-xxs); - width: 100%; - display: flex; - flex-wrap: wrap; - padding: var(--spacing-xs) 0; -} - -.events-form .field-group-wrapper { - flex-direction: column; -} - -.events-form .events-form-heading-wrapper { - justify-content: center; - margin: 0; -} - -.events-form .field-wrapper.hidden { - display: none; -} - -.events-form .check-item-wrap { - position: relative; - display: inline-flex; - align-items: center; - width: 100%; -} - -.events-form .check-item-input { - opacity: 0; - position: absolute; - inset: 0; - cursor: pointer; - z-index: 1; -} - -.events-form .check-item-button { - position: relative; - inline-size: 14px; - block-size: 14px; -} - -.events-form .check-item-button::before { - content: ''; - display: block; - background-color: var(--color-white); - box-sizing: border-box; - border-style: solid; - border-width: 2px; - border-color: var(--color-font-grey); - block-size: 14px; - inline-size: 14px; - position: absolute; - transition: border 0.13s ease-in-out, box-shadow 0.13s ease-in-out; -} - -.events-form .radio-button::before { - border-radius: 50%; -} - -.events-form .checkbox-button::before { - border-radius: 2px; -} - -.events-form .checkbox-button::after { - content: ''; - display: block; - position: absolute; - box-sizing: border-box; - block-size: 10px; - inline-size: 10px; - inset: 0; - margin: auto; - scale: 0; - opacity: 0; - transition: scale 0.13s ease-in-out, opacity 0.13s; -} - -.events-form .checkbox-input:checked + .checkbox-button::after { - opacity: 1; - scale: 1; - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI2LjUuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHBhdGggZD0iTTMuNSA5LjVhLjk5OS45OTkgMCAwMS0uNzc0LS4zNjhsLTIuNDUtM2ExIDEgMCAxMTEuNTQ4LTEuMjY0bDEuNjU3IDIuMDI4IDQuNjgtNi4wMUExIDEgMCAwMTkuNzQgMi4xMTRsLTUuNDUgN2ExIDEgMCAwMS0uNzc3LjM4NnoiIGZpbGw9IiNmZmYiPjwvcGF0aD4KPC9zdmc+Cg=="); - background-size: contain; -} - -.events-form .radio-input:checked + .radio-button::before { - border-width: 5px; - border-color: var(--color-gray-700); -} - -.events-form .checkbox-input:checked + .checkbox-button::before { - border-width: 7px; - border-color: var(--color-gray-700); -} - -.events-form .check-item-label { - font-size: var(--type-body-xs-size); - font-weight: normal; - margin-left: var(--spacing-xxs); - padding-bottom: 0; -} - -.events-form .events-form-legal-wrapper p { - font-size: var(--type-body-xxs-size); - line-height: var(--type-body-xxs-lh); - font-style: italic; -} - -.events-form .field-button-wrapper { - margin-bottom: 0; -} - -.events-form button { - font-size: var(--type-body-s-size); - background-color: var(--link-color); - min-width: 114px; - height: 40px; - line-height: 20px; - padding: 9px 16px; - border: 0; - border-radius: 24px; - color: #fff; - font-weight: 700; - width: 100%; - box-shadow: none; - margin: 0 auto; - cursor: pointer; - transition: background-color 0.13s, color 0.13s; -} - -.events-form button:disabled { - background-color: var(--color-gray-200); - color: var(--color-gray-400); - cursor: progress; -} - -.events-form button.outline { - background-color: transparent; - border: 2px solid var(--link-color); - color: var(--link-color); -} - -.events-form .divider { - border-top: 1px var(--color-gray-200) solid; - margin: 16px 0; - padding: 0; -} - -.events-form .thank-you { - text-align: center; -} - -.events-form .rsvp-status-label { - padding: 16px; - border-radius: 8px; - background: var(--color-gray-200); -} - -@media screen and (min-width: 600px) { - .events-form form { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 0 var(--spacing-l); - align-items: start; - } - - .events-form form .first-form-section { - flex-direction: row; - width: 100%; - } - - .events-form form .first-form-section .first-form-section-input-wrapper { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 0 var(--spacing-l); - align-items: start; - width: 100%; - } - - .events-form :is(.events-form-submit-wrapper:last-child, .events-form-heading-wrapper, .thank-you, .events-form-full-width) { - grid-column: 1 / 3; - justify-self: center; - } - - .events-form .events-form-checkbox-group-wrapper.events-form-full-width .group-container.checkbox-group-container { - display: flex; - gap: 24px; - flex-wrap: wrap; - } - - .events-form .events-form-checkbox-group-wrapper.events-form-full-width .group-container.checkbox-group-container .check-item-wrap.checkbox-input-wrap { - width: auto; - } - - .events-form .field-button-wrapper { - grid-column: 1; - justify-self: self-end; - width: auto; - margin-top: var(--spacing-s); - } - - .events-form .field-button-wrapper + .field-button-wrapper { - grid-column: 2; - justify-self: self-start; - } - - .events-form button { - width: initial; - } -} - -@media screen and (min-width: 900px) { - .events-form .event-form-hero { - flex-direction: row; - } - - .events-form .field-wrapper { - display: flex; - } - - .events-form label { - width: 72%; - } -} diff --git a/blocks/events-form/events-form.js b/blocks/events-form/events-form.js deleted file mode 100644 index 58a40fcd..00000000 --- a/blocks/events-form/events-form.js +++ /dev/null @@ -1,416 +0,0 @@ -import { getLibs } from '../../scripts/utils.js'; -import { getAttendeeData, getProfile, getEventId, submitToSplashThat } from '../../utils/event-apis.js'; - -const { createTag } = await import(`${getLibs()}/utils/utils.js`); -const { default: sanitizeComment } = await import(`${getLibs()}/utils/sanitizeComment.js`); - -const RULE_OPERATORS = { - equal: '=', - notEqual: '!=', - lessThan: '<', - lessThanOrEqual: '<=', - greaterThan: '>', - greaterThanOrEqual: '>=', - includes: 'inc', - excludes: 'exc', -}; - -function snakeToCamel(str) { - return str - .split('_') - .map((word, index) => (index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1))) - .join(''); -} - -function createSelect({ field, placeholder, options, defval, required }) { - const select = createTag('select', { id: field }); - if (placeholder) select.append(createTag('option', { selected: '', disabled: '' }, placeholder)); - options.split(',').forEach((o) => { - const text = o.trim(); - const option = createTag('option', { value: text }, text); - select.append(option); - if (defval === text) select.value = text; - }); - if (required === 'x') select.setAttribute('required', 'required'); - return select; -} - -function constructPayload(form) { - const payload = {}; - [...form.elements].filter((el) => el.tagName !== 'BUTTON').forEach((fe) => { - if (fe.type.match(/(?:checkbox|radio)/)) { - if (fe.checked) { - payload[fe.name] = payload[fe.name] ? `${fe.value}, ${payload[fe.name]}` : fe.value; - } else { - payload[fe.name] = payload[fe.name] || ''; - } - return; - } - payload[fe.id] = fe.value; - }); - return payload; -} - -async function submitForm(form) { - const payload = constructPayload(form); - payload.timestamp = new Date().toJSON(); - Object.keys(payload).forEach((key) => { - const field = form.querySelector(`[data-field-id=${key}]`); - if (!payload[key] && field.querySelector('.group-container.required')) { - const el = form.querySelector(`input[name="${key}"]`); - el.setCustomValidity('A selection is required'); - el.reportValidity(); - const cb = () => { - el.setCustomValidity(''); - el.reportValidity(); - field.removeEventListener('input', cb); - }; - field.addEventListener('input', cb); - return false; - } - payload[key] = sanitizeComment(payload[key]); - return true; - }); - - const response = await submitToSplashThat(payload); - - return response; -} - -function clearForm(form) { - [...form.elements].forEach((fe) => { - if (fe.type.match(/(?:checkbox|radio)/)) { - fe.checked = false; - } else { - fe.value = ''; - } - }); -} - -function createButton({ type, label }, thankYou) { - const button = createTag('button', { class: 'button' }, label); - if (type === 'submit') { - button.addEventListener('click', async (event) => { - const form = button.closest('form'); - if (form.checkValidity()) { - event.preventDefault(); - button.setAttribute('disabled', ''); - const submission = await submitForm(form); - button.removeAttribute('disabled'); - if (!submission) return; - clearForm(form); - const handleThankYou = thankYou.querySelector('a') ? thankYou.querySelector('a').href : thankYou.innerHTML; - if (!thankYou.innerHTML.includes('href')) { - const thanksText = createTag('h4', { class: 'thank-you' }, handleThankYou); - form.append(thanksText); - setTimeout(() => thanksText.remove(), 2000); - /* c8 ignore next 3 */ - } else { - window.location.href = handleThankYou; - } - } - }); - } - if (type === 'clear') { - button.classList.add('outline'); - button.addEventListener('click', (e) => { - e.preventDefault(); - const form = button.closest('form'); - clearForm(form); - }); - } - return button; -} - -function createHeading({ label }, el) { - return createTag(el, {}, label); -} - -function createInput({ type, field, placeholder, required, defval }) { - const input = createTag('input', { type, id: field, placeholder, value: defval }); - if (required === 'x') input.setAttribute('required', 'required'); - return input; -} - -function createTextArea({ field, placeholder, required, defval }) { - const input = createTag('textarea', { id: field, placeholder, value: defval }); - if (required === 'x') input.setAttribute('required', 'required'); - return input; -} - -function createlabel({ field, label, required }) { - return createTag('label', { for: field, class: required ? 'required' : '' }, label); -} - -function createCheckItem(item, type, id, def) { - const itemKebab = item.toLowerCase().replaceAll(' ', '-'); - const defList = def.split(',').map((defItem) => defItem.trim()); - const pseudoEl = createTag('span', { class: `check-item-button ${type}-button` }); - const label = createTag('label', { class: `check-item-label ${type}-label`, for: `${id}-${itemKebab}` }, item); - const input = createTag( - 'input', - { type, name: id, value: item, class: `check-item-input ${type}-input`, id: `${id}-${itemKebab}` }, - ); - if (item && defList.includes(item)) input.setAttribute('checked', ''); - return createTag('div', { class: `check-item-wrap ${type}-input-wrap` }, [input, pseudoEl, label]); -} - -function createCheckGroup({ options, field, defval, required }, type) { - const optionsMap = options.split(',').map((item) => createCheckItem(item.trim(), type, field, defval)); - return createTag( - 'div', - { class: `group-container ${type}-group-container${required === 'x' ? ' required' : ''}` }, - optionsMap, - ); -} - -function createDivider() { - return ''; -} - -function processNumRule(tf, operator, a, b) { - /* c8 ignore next 3 */ - if (!tf.dataset.type.match(/(?:number|date)/)) { - throw new Error(`Comparison field must be of type number or date for ${operator} rules`); - } - const { type } = tf.dataset; - const a2 = type === 'number' ? parseInt(a, 10) : Date.parse(a); - const b2 = type === 'number' ? parseInt(b, 10) : Date.parse(b); - return [a2, b2]; -} - -function processRule(tf, operator, payloadKey, value, comparisonFunction) { - if (payloadKey === '') return true; - try { - const [a, b] = processNumRule(tf, operator, payloadKey, value); - return comparisonFunction(a, b); - /* c8 ignore next 5 */ - } catch (e) { - // eslint-disable-next-line no-console - console.warn(`Invalid rule, ${e}`); - return false; - } -} - -function applyRules(form, rules) { - const payload = constructPayload(form); - rules.forEach((field) => { - const { type, condition: { key, operator, value } } = field.rule; - const fw = form.querySelector(`[data-field-id=${field.fieldId}]`); - const tf = form.querySelector(`[data-field-id=${key}]`); - let force = false; - switch (operator) { - case RULE_OPERATORS.equal: - force = (payload[key] === value); - break; - case RULE_OPERATORS.notEqual: - force = (payload[key] !== value); - break; - case RULE_OPERATORS.includes: - force = (payload[key].split(',').map((s) => s.trim()).includes(value)); - break; - case RULE_OPERATORS.excludes: - force = (!payload[key].split(',').map((s) => s.trim()).includes(value)); - break; - case RULE_OPERATORS.lessThan: - force = processRule(tf, operator, payload[key], value, (a, b) => a < b); - break; - case RULE_OPERATORS.lessThanOrEqual: - force = processRule(tf, operator, payload[key], value, (a, b) => a <= b); - break; - case RULE_OPERATORS.greaterThan: - force = processRule(tf, operator, payload[key], value, (a, b) => a > b); - break; - case RULE_OPERATORS.greaterThanOrEqual: - force = processRule(tf, operator, payload[key], value, (a, b) => a >= b); - break; - default: - // eslint-disable-next-line no-console - console.warn(`Unsupported operator ${operator}`); - return false; - } - fw.classList.toggle(type, force); - return false; - }); -} - -function lowercaseKeys(obj) { - return Object.keys(obj).reduce((acc, key) => { - acc[key.toLowerCase() === 'default' ? 'defval' : key.toLowerCase()] = obj[key]; - return acc; - }, {}); -} - -function insertAvatar(form, avatar) { - if (!avatar) return; - - const firstFormDivider = form.querySelector('.divider'); - const oldAvatarCont = avatar.parentElement; - if (!firstFormDivider) { - form.append(avatar); - } else { - const firstSec = createTag('div', { class: 'first-form-section events-form-full-width' }); - const inputsWrapper = createTag('div', { class: 'first-form-section-input-wrapper' }); - const firstFormSecEls = []; - let previousNode = firstFormDivider.previousElementSibling; - - while (previousNode && firstFormSecEls.length <= 4) { - if (['text', 'email', 'phone'].includes(previousNode.querySelector('input')?.type)) firstFormSecEls.push(previousNode); - previousNode = previousNode.previousElementSibling; - } - - firstFormSecEls.forEach((el) => { - inputsWrapper.prepend(el); - }); - - form.prepend(firstSec); - firstSec.append(avatar, inputsWrapper); - } - - if (!oldAvatarCont?.innerHTML?.trim() && !oldAvatarCont?.className) oldAvatarCont.remove(); -} - -async function createForm(formURL, thankYou, formData, avatar, actionUrl = '') { - const { pathname } = new URL(formURL); - let json = formData; - /* c8 ignore next 4 */ - if (!formData) { - const resp = await fetch(pathname); - json = await resp.json(); - } - json.data = json.data.map((obj) => lowercaseKeys(obj)); - const form = createTag('form'); - const rules = []; - const [action] = pathname.split('.json'); - form.dataset.action = actionUrl || action; - - const typeToElement = { - select: { fn: createSelect, params: [], label: true, classes: [] }, - heading: { fn: createHeading, params: ['h3'], label: false, classes: [] }, - legal: { fn: createHeading, params: ['p'], label: false, classes: [] }, - checkbox: { fn: createCheckGroup, params: ['checkbox'], label: true, classes: ['field-group-wrapper'] }, - 'checkbox-group': { fn: createCheckGroup, params: ['checkbox'], label: true, classes: ['field-group-wrapper'] }, - 'radio-group': { fn: createCheckGroup, params: ['radio'], label: true, classes: ['field-group-wrapper'] }, - 'text-area': { fn: createTextArea, params: [], label: true, classes: [] }, - submit: { fn: createButton, params: [thankYou], label: false, classes: ['field-button-wrapper'] }, - clear: { fn: createButton, params: [thankYou], label: false, classes: ['field-button-wrapper'] }, - divider: { fn: createDivider, params: [], label: false, classes: ['divider'] }, - default: { fn: createInput, params: [], label: true, classes: [] }, - }; - - json.data.forEach((fd) => { - fd.type = fd.type || 'text'; - const style = fd.extra ? ` events-form-${fd.extra}` : ''; - const fieldWrapper = createTag( - 'div', - { class: `field-wrapper events-form-${fd.type}-wrapper${style}`, 'data-field-id': fd.field, 'data-type': fd.type }, - ); - - const elParams = typeToElement[fd.type] || typeToElement.default; - if (elParams.label) fieldWrapper.append(createlabel(fd)); - fieldWrapper.append(elParams.fn(fd, ...elParams.params)); - fieldWrapper.classList.add(...elParams.classes); - - if (fd.rules?.length) { - try { - rules.push({ fieldId: fd.field, rule: JSON.parse(fd.rules) }); - /* c8 ignore next 4 */ - } catch (e) { - // eslint-disable-next-line no-console - console.warn(`Invalid Rule ${fd.rules}: ${e}`); - } - } - form.append(fieldWrapper); - }); - - form.addEventListener('input', () => applyRules(form, rules)); - applyRules(form, rules); - - insertAvatar(form, avatar); - return form; -} - -function personalizeForm(form, resp) { - if (!resp || !form) return; - - Object.entries(resp).forEach(([key, value]) => { - const matchedInput = form.querySelector(`#${snakeToCamel(key)}`); - if (matchedInput) matchedInput.value = value; - }); -} - -function decorateHero(heroEl) { - heroEl.classList.add('event-form-hero'); -} - -async function decorateRSVPStatus(bp, profile) { - const data = await getAttendeeData(profile.email, getEventId()); - if (!data) return; - - if (data.registered) { - const successLabel = createTag('div', { class: 'rsvp-status-label' }, 'You have previously registered for this event. Feel free to use the form below to RSVP for another guest.'); - bp.formContainer.before(successLabel); - } -} - -async function updateDynamicContent(bp) { - const { block, eventHero } = bp; - await Promise.all([ - import(`${getLibs()}/utils/getUuid.js`), - import('../../utils/event-apis.js'), - import('../../utils/utils.js'), - ]).then(async ([{ default: getUuid }, caasApiMod, { autoUpdateContent }]) => { - const hash = await getUuid(window.location.pathname); - let profile; - - try { - profile = await getProfile(); - } catch (e) { - eventHero.querySelectorAll('p')?.forEach((p) => p.remove()); - } - - if (profile) { - await decorateRSVPStatus(bp, profile); - } - - autoUpdateContent(block, { ...await caasApiMod.default(hash), ...profile }); - eventHero.classList.remove('loading'); - personalizeForm(block, profile); - }); -} - -async function buildEventform(bp, formData) { - if (!bp.formContainer || !bp.form) return; - bp.formContainer.classList.add('form-container'); - const avatar = bp.formContainer.querySelector('div:first-of-type > picture'); - const constructedForm = await createForm( - bp.form.href, - bp.thankYou, - formData, - avatar, - bp.eventAction?.href, - ); - if (constructedForm) bp.form.replaceWith(constructedForm); -} - -export default async function decorate(block, formData = null) { - block.style.opacity = 0; - const bp = { - block, - eventHero: block.querySelector(':scope > div:nth-of-type(1)'), - formContainer: block.querySelector(':scope > div:nth-of-type(2)'), - form: block.querySelector(':scope > div:nth-of-type(2) a[href$=".json"]'), - thankYou: block.querySelector(':scope > div:nth-of-type(3) > div'), - eventAction: block.querySelector(':scope > div:last-of-type > div > a'), - }; - - bp.thankYou?.remove(); - decorateHero(bp.eventHero); - buildEventform(bp, formData) - .then(async () => { await updateDynamicContent(bp); }) - .then(() => { - block.style.opacity = 1; - }).catch(() => { - block.innerHTML = 'Failed to load registration form. Please refresh the page.'; - }); -}