diff --git a/ecc/blocks/ecc-dashboard/ecc-dashboard.js b/ecc/blocks/ecc-dashboard/ecc-dashboard.js
index c8244530..d2a70d6b 100644
--- a/ecc/blocks/ecc-dashboard/ecc-dashboard.js
+++ b/ecc/blocks/ecc-dashboard/ecc-dashboard.js
@@ -209,7 +209,7 @@ function sortData(props, config, options = {}) {
let valA;
let valB;
- if ((field === 'title' || field === 'venueId')) {
+ if ((field === 'title')) {
valA = a[field]?.toLowerCase() || '';
valB = b[field]?.toLowerCase() || '';
return sortAscending ? valA.localeCompare(valB) : valB.localeCompare(valA);
@@ -221,6 +221,18 @@ function sortData(props, config, options = {}) {
return sortAscending ? valA - valB : valB - valA;
}
+ if (field === 'venueName') {
+ valA = a.venue?.venueName?.toLowerCase() || '';
+ valB = b.venue?.venueName?.toLowerCase() || '';
+ return sortAscending ? valA.localeCompare(valB) : valB.localeCompare(valA);
+ }
+
+ if (typeof a[field] === typeof b[field] && typeof a[field] === 'number') {
+ valA = a[field] || 0;
+ valB = b[field] || 0;
+ return sortAscending ? valA - valB : valB - valA;
+ }
+
valA = a[field]?.toString().toLowerCase() || '';
valB = b[field]?.toString().toLowerCase() || '';
return sortAscending ? valA.localeCompare(valB) : valB.localeCompare(valA);
@@ -538,9 +550,9 @@ function initSorting(props, config) {
published: 'PUBLISH STATUS',
startDate: 'DATE RUN',
modificationTime: 'LAST MODIFIED',
- venueId: 'VENUE NAME',
+ venueName: 'VENUE NAME',
timezone: 'GEO',
- externalEventId: 'RSVP DATA',
+ attendeeCount: 'RSVP DATA',
manage: 'MANAGE',
};
diff --git a/ecc/blocks/form-handler/controllers/product-promotion-component-controller.js b/ecc/blocks/form-handler/controllers/product-promotion-component-controller.js
index 42b7b24b..4e415a1d 100644
--- a/ecc/blocks/form-handler/controllers/product-promotion-component-controller.js
+++ b/ecc/blocks/form-handler/controllers/product-promotion-component-controller.js
@@ -10,11 +10,14 @@ export function onSubmit(component, props) {
const selectedProducts = productGroup?.getSelectedProducts();
if (selectedProducts) {
- const relatedProducts = selectedProducts.map((p) => ({
- name: p.title,
- showProductBlade: !!p.showProductBlade,
- tags: p.tags.map((t) => t.tagID).join(','),
- }));
+ const topicsVal = props.payload.fullTopicsValue?.map((x) => JSON.parse(x));
+ const relatedProducts = selectedProducts
+ .filter((p) => topicsVal.find((t) => p.tagID.includes(t.tagID)))
+ .map((p) => ({
+ name: p.title,
+ showProductBlade: !!p.showProductBlade,
+ tags: p.tags.map((t) => t.tagID).join(','),
+ }));
props.payload = { ...props.payload, relatedProducts };
}
@@ -68,12 +71,22 @@ async function updateProductSelector(component, props) {
(p) => topicsVal.find((t) => p.tagID.includes(t.tagID)) && supportedProducts.includes(p.title),
);
- productGroups.forEach((p) => {
- p.setAttribute('data-products', JSON.stringify(products));
- p.setAttribute('data-selected-topics', JSON.stringify(topicsVal));
- p.requestUpdate();
+ productGroups.forEach((pg) => {
+ pg.setAttribute('data-products', JSON.stringify(products));
+ pg.setAttribute('data-selected-topics', JSON.stringify(topicsVal));
+ pg.requestUpdate();
+
+ const selectedProducts = pg.getSelectedProducts();
+
+ selectedProducts.forEach((sp, i) => {
+ const isProductAvailable = products.find((p) => p.name === sp.name);
+
+ if (!isProductAvailable) {
+ pg.deleteProduct(i);
+ }
+ });
- p.shadowRoot.querySelectorAll('product-selector').forEach((ps) => {
+ pg.shadowRoot.querySelectorAll('product-selector').forEach((ps) => {
ps.dispatchEvent(new CustomEvent('update-product', {
detail: { product: ps.selectedProduct },
bubbles: true,
diff --git a/ecc/blocks/form-handler/controllers/registration-details-component-controller.js b/ecc/blocks/form-handler/controllers/registration-details-component-controller.js
index 780d21e7..39f11415 100644
--- a/ecc/blocks/form-handler/controllers/registration-details-component-controller.js
+++ b/ecc/blocks/form-handler/controllers/registration-details-component-controller.js
@@ -1,35 +1,5 @@
/* eslint-disable no-unused-vars */
-export function onSubmit(component, props) {
- if (component.closest('.fragment')?.classList.contains('hidden')) return;
-
- const attendeeLimitVal = component.querySelector('#attendee-count-input')?.value;
- const allowWaitlisting = component.querySelector('#registration-allow-waitlist')?.checked;
- const contactHost = component.querySelector('#registration-contact-host')?.checked;
- const hostEmail = component.querySelector('#event-host-email-input')?.value;
- const rsvpDescription = component.querySelector('#rsvp-form-detail-description')?.value;
-
- const attendeeLimit = Number.isNaN(+attendeeLimitVal) ? null : +attendeeLimitVal;
-
- const rsvpData = {};
-
- if (rsvpDescription) rsvpData.rsvpDescription = rsvpDescription;
- if (contactHost && hostEmail) rsvpData.hostEmail = hostEmail;
- if (attendeeLimit) rsvpData.attendeeLimit = attendeeLimit;
- if (allowWaitlisting) rsvpData.allowWaitlisting = allowWaitlisting;
-
- props.payload = { ...props.payload, ...rsvpData };
-}
-
-export async function onUpdate(component, props) {
- if (!props.eventDataResp) return;
-
- if (props.eventDataResp.cloudType === 'CreativeCloud') {
- component.querySelector('.attendee-count-wrapper')?.classList.add('hidden');
- component.querySelector('#registration-allow-waitlist')?.classList.add('hidden');
- }
-}
-
-export default function init(component, props) {
+function prefillFields(component, props) {
const contactHostEl = component.querySelector('#registration-contact-host');
const hostEmailEl = component.querySelector('#event-host-email-input');
const attendeeLimitEl = component.querySelector('#attendee-count-input');
@@ -66,3 +36,39 @@ export default function init(component, props) {
});
}
}
+
+export function onSubmit(component, props) {
+ if (component.closest('.fragment')?.classList.contains('hidden')) return;
+
+ const attendeeLimitVal = component.querySelector('#attendee-count-input')?.value;
+ const allowWaitlisting = component.querySelector('#registration-allow-waitlist')?.checked;
+ const contactHost = component.querySelector('#registration-contact-host')?.checked;
+ const hostEmail = component.querySelector('#event-host-email-input')?.value;
+ const rsvpDescription = component.querySelector('#rsvp-form-detail-description')?.value;
+
+ const attendeeLimit = Number.isNaN(+attendeeLimitVal) ? null : +attendeeLimitVal;
+
+ const rsvpData = {};
+
+ if (rsvpDescription) rsvpData.rsvpDescription = rsvpDescription;
+ if (contactHost && hostEmail) rsvpData.hostEmail = hostEmail;
+ if (attendeeLimit) rsvpData.attendeeLimit = attendeeLimit;
+ if (allowWaitlisting) rsvpData.allowWaitlisting = allowWaitlisting;
+
+ props.payload = { ...props.payload, ...rsvpData };
+}
+
+export async function onUpdate(component, props) {
+ if (!props.eventDataResp) return;
+
+ if (props.eventDataResp.cloudType === 'CreativeCloud') {
+ component.querySelector('.attendee-count-wrapper')?.classList.add('hidden');
+ component.querySelector('#registration-allow-waitlist')?.classList.add('hidden');
+ }
+
+ prefillFields(component, props);
+}
+
+export default function init(component, props) {
+ prefillFields(component, props);
+}
diff --git a/ecc/blocks/form-handler/controllers/registration-fields-component-controller.js b/ecc/blocks/form-handler/controllers/registration-fields-component-controller.js
index 27425fb0..437d2440 100644
--- a/ecc/blocks/form-handler/controllers/registration-fields-component-controller.js
+++ b/ecc/blocks/form-handler/controllers/registration-fields-component-controller.js
@@ -2,7 +2,7 @@
export function onSubmit(component, props) {
if (component.closest('.fragment')?.classList.contains('hidden')) return;
- const defaultFields = ['firstName', 'lastName', 'email', 'jobTitle'];
+ const defaultFields = component.dataset.mandatedfields?.split(',');
const rsvpFormFields = {
visible: [...defaultFields, ...Array.from(component.querySelectorAll('sp-checkbox.check-appear[checked]')).map((f) => f.name)],
diff --git a/ecc/blocks/form-handler/controllers/terms-conditions-component-controller.js b/ecc/blocks/form-handler/controllers/terms-conditions-component-controller.js
index 7d1d1782..c0dcd5e8 100644
--- a/ecc/blocks/form-handler/controllers/terms-conditions-component-controller.js
+++ b/ecc/blocks/form-handler/controllers/terms-conditions-component-controller.js
@@ -31,6 +31,10 @@ function buildTerms(terms) {
}
async function loadPreview(component, templateId) {
+ const existingPreview = component.querySelector('.terms-conditions-preview');
+
+ if (existingPreview) return;
+
let host;
if (window.location.href.includes('.hlx.')) {
host = window.location.origin.replace(window.location.hostname, `${ECC_ENV}--events-milo--adobecom.hlx.page`);
@@ -39,23 +43,24 @@ async function loadPreview(component, templateId) {
}
const rsvpFormLocation = `${host}${templateId.substring(0, templateId.lastIndexOf('/'))}/rsvp-form`;
- const text = await fetchThrottledMemoizedText(`${rsvpFormLocation}.plain.html`).catch(() => ({}))
- .catch(() => ({}));
+ const resp = await fetchThrottledMemoizedText(`${rsvpFormLocation}.plain.html`);
- if (!text) {
+ if (!resp) {
component.remove();
return;
}
- const doc = new DOMParser().parseFromString(text, 'text/html');
- const termsConditionsRow = doc.querySelector('.events-form > div:nth-of-type(3)');
+ if (typeof resp === 'string') {
+ const doc = new DOMParser().parseFromString(resp, 'text/html');
+ const termsConditionsRow = doc.querySelector('.events-form > div:nth-of-type(3)');
- if (!termsConditionsRow) {
- component.remove();
- return;
- }
+ if (!termsConditionsRow) {
+ component.remove();
+ return;
+ }
- component.append(buildTerms(termsConditionsRow));
+ component.append(buildTerms(termsConditionsRow));
+ }
}
export async function onUpdate(component, props) {
diff --git a/ecc/blocks/form-handler/form-handler.css b/ecc/blocks/form-handler/form-handler.css
index 431f42cd..14f230c9 100644
--- a/ecc/blocks/form-handler/form-handler.css
+++ b/ecc/blocks/form-handler/form-handler.css
@@ -234,8 +234,14 @@
cursor: pointer;
}
+.form-handler .side-menu .nav-item:disabled {
+ pointer-events: none;
+ cursor: unset;
+}
+
.form-handler .side-menu .nav-item.disabled {
pointer-events: none;
+ cursor: unset;
opacity: 0.5;
}
@@ -289,11 +295,24 @@
color: var(--color-red);
}
+.form-handler .main-frame .section:first-of-type .step-heading-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+}
+
+.form-handler .main-frame .section:first-of-type .step-heading-wrapper .event-status-tag {
+ padding: 0 8px;
+ background-color: var(--color-white);
+ border-radius: 4px;
+}
+
.form-handler .main-frame .section:not(:first-of-type) {
padding: 24px 56px;
border-radius: 10px;
margin: 24px;
box-shadow: 0 3px 6px 0 rgb(0 0 0 / 16%);
+ background-color: var(--color-white);
}
.form-handler .fragment.hidden {
@@ -368,6 +387,10 @@
width: 20px;
}
+.form-handler .main-frame .section:first-of-type .step-heading-wrapper .event-status-tag .icon {
+ margin-right: 4px;
+}
+
.form-handler .form-handler-ctas-panel .form-handler-forward-wrapper > div:first-of-type {
padding-right: 64px;
border-right: 1px solid var(--color-black);
diff --git a/ecc/blocks/form-handler/form-handler.js b/ecc/blocks/form-handler/form-handler.js
index 74b0d56b..47436534 100644
--- a/ecc/blocks/form-handler/form-handler.js
+++ b/ecc/blocks/form-handler/form-handler.js
@@ -584,12 +584,15 @@ function initFormCtas(props) {
});
backBtn.addEventListener('click', async () => {
+ toggleBtnsSubmittingState(true);
const resp = await saveEvent(props);
if (resp?.error) {
buildErrorMessage(props, resp);
} else {
props.currentStep -= 1;
}
+
+ toggleBtnsSubmittingState(false);
});
}
@@ -605,6 +608,20 @@ function updateCtas(props) {
a.classList.remove('preview-not-ready');
}
}
+
+ if (a.classList.contains('next-button')) {
+ if (props.currentStep === props.maxStep) {
+ if (props.eventDataResp.published) {
+ a.textContent = a.dataset.republishStateText;
+ } else {
+ a.textContent = a.dataset.finalStateText;
+ }
+ a.prepend(getIcon('golden-rocket'));
+ } else {
+ a.textContent = a.dataset.nextStateText;
+ a.append(getIcon('chev-right-white'));
+ }
+ }
});
}
@@ -666,6 +683,29 @@ function initDeepLink(props) {
}
}
+function updateStatusTag(props) {
+ const { eventDataResp } = props;
+
+ if (eventDataResp?.published === undefined) return;
+
+ const currentFragment = getCurrentFragment(props);
+
+ const headingSection = currentFragment.querySelector(':scope > .section:first-child');
+
+ const eixstingStatusTag = headingSection.querySelector('.event-status-tag');
+ if (eixstingStatusTag) eixstingStatusTag.remove();
+
+ const heading = headingSection.querySelector('h2', 'h3', 'h3', 'h4');
+ const headingWrapper = createTag('div', { class: 'step-heading-wrapper' });
+ const dot = eventDataResp.published ? getIcon('dot-purple') : getIcon('dot-green');
+ const text = eventDataResp.published ? 'Published' : 'Draft';
+ const statusTag = createTag('span', { class: 'event-status-tag' });
+
+ statusTag.append(dot, text);
+ heading.parentElement?.replaceChild(headingWrapper, heading);
+ headingWrapper.append(heading, statusTag);
+}
+
async function buildECCForm(el) {
const props = {
el,
@@ -691,6 +731,7 @@ async function buildECCForm(el) {
renderFormNavigation(target, oldValue, value);
updateSideNav(target);
initRequiredFieldsValidation(target);
+ updateStatusTag(target);
break;
}
@@ -746,6 +787,8 @@ async function buildECCForm(el) {
updateRequiredFields(proxyProps);
enableSideNavForEditFlow(proxyProps);
initDeepLink(proxyProps);
+ updateStatusTag(proxyProps);
+
el.addEventListener('show-error-toast', (e) => {
e.stopPropagation();
e.preventDefault();
diff --git a/ecc/blocks/registration-fields-component/registration-fields-component.js b/ecc/blocks/registration-fields-component/registration-fields-component.js
index 18eb4599..8abe7554 100644
--- a/ecc/blocks/registration-fields-component/registration-fields-component.js
+++ b/ecc/blocks/registration-fields-component/registration-fields-component.js
@@ -10,7 +10,11 @@ function convertString(input) {
return result;
}
-async function decorateRSVPFields(row) {
+async function decorateRSVPFields(el) {
+ const row = el.querySelector(':scope > div:last-of-type');
+
+ if (!row) return;
+
row.classList.add('rsvp-checkboxes');
const configSheetLocation = row.querySelector('a')?.href;
const config = await fetch(configSheetLocation)
@@ -30,6 +34,8 @@ async function decorateRSVPFields(row) {
row.innerHTML = '';
row.append(fieldConfigTable);
+ el.dataset.mandatedfields = config.data.filter((f) => f.Required === 'x').map((f) => f.Field);
+
config.data.filter((f) => f.Required !== 'x' && f.Type !== 'submit').forEach((field) => {
const fieldRow = createTag('tr', { class: 'field-row' }, '', { parent: tbody });
const tds = [];
@@ -46,5 +52,5 @@ async function decorateRSVPFields(row) {
export default async function init(el) {
el.classList.add('form-component');
generateToolTip(el.querySelector(':scope > div:first-of-type'));
- await decorateRSVPFields(el.querySelector(':scope > div:last-of-type'));
+ await decorateRSVPFields(el);
}
diff --git a/ecc/components/product-selector-group/product-selector-group.js b/ecc/components/product-selector-group/product-selector-group.js
index 00e2f058..f6acff37 100644
--- a/ecc/components/product-selector-group/product-selector-group.js
+++ b/ecc/components/product-selector-group/product-selector-group.js
@@ -103,7 +103,8 @@ export default class ProductSelectorGroup extends LitElement {
`)}
-
+ ${this.selectedProducts.length < uniqueProducts.length ? html`` : nothing}
+
`;
}
}
diff --git a/ecc/components/profile-container/profile-container.css.js b/ecc/components/profile-container/profile-container.css.js
index 8a90abe6..05cbb6fb 100644
--- a/ecc/components/profile-container/profile-container.css.js
+++ b/ecc/components/profile-container/profile-container.css.js
@@ -17,6 +17,7 @@ export const style = css`
margin: 24px;
box-shadow: 0 3px 6px 0 rgb(0 0 0 / 16%);
display: flex;
+ background-color: var(--color-white);
}
profile-ui {
diff --git a/ecc/scripts/esp-controller.js b/ecc/scripts/esp-controller.js
index 3c562e9b..5cc7e759 100644
--- a/ecc/scripts/esp-controller.js
+++ b/ecc/scripts/esp-controller.js
@@ -549,7 +549,7 @@ export async function updateEvent(eventId, payload) {
export async function publishEvent(eventId, payload) {
const { host } = getAPIConfig().esp[ECC_ENV];
- const raw = JSON.stringify({ ...payload, published: true });
+ const raw = JSON.stringify({ ...payload, published: true, liveUpdate: true });
const options = await constructRequestOptions('PUT', raw);
try {
@@ -570,7 +570,7 @@ export async function publishEvent(eventId, payload) {
export async function unpublishEvent(eventId, payload) {
const { host } = getAPIConfig().esp[ECC_ENV];
- const raw = JSON.stringify({ ...payload, published: false });
+ const raw = JSON.stringify({ ...payload, published: false, liveUpdate: true });
const options = await constructRequestOptions('PUT', raw);
try {