From 504191c005fdd85cf130be2ae9b842e88b7b285c Mon Sep 17 00:00:00 2001 From: rash Date: Mon, 9 Mar 2026 18:31:27 +0100 Subject: [PATCH] fix inconsistencies from automatic migration --- .../widget/src/components/AvailBox.vue | 7 +- .../widget/src/components/Button.vue | 33 +---- .../widget/src/components/Category.vue | 1 - .../widget/src/components/EventCalendar.vue | 10 +- .../src/components/EventCalendarCell.vue | 16 +-- .../src/components/EventCalendarEvent.vue | 8 +- .../src/components/EventCalendarRow.vue | 2 - .../widget/src/components/EventForm.vue | 93 +++----------- .../widget/src/components/EventList.vue | 19 ++- .../widget/src/components/EventListEntry.vue | 5 +- .../src/components/EventListFilterField.vue | 2 - .../src/components/EventListFilterForm.vue | 4 +- .../src/components/EventWeekCalendar.vue | 18 ++- .../widget/src/components/EventWeekCell.vue | 5 +- .../widget/src/components/Overlay.vue | 39 +++--- .../widget/src/components/Widget.vue | 6 +- .../pretixpresale/widget/src/sharedStore.ts | 118 ++++++++++-------- 17 files changed, 146 insertions(+), 240 deletions(-) diff --git a/src/pretix/static/pretixpresale/widget/src/components/AvailBox.vue b/src/pretix/static/pretixpresale/widget/src/components/AvailBox.vue index 6a81fb0d99..f8cff7104a 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/AvailBox.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/AvailBox.vue @@ -61,11 +61,8 @@ const waitingListUrl = computed(() => { if (store.subevent) { u += `&subevent=${store.subevent}` } - const widgetDataJson = JSON.stringify(store.widgetData) - u += `&widget_data=${encodeURIComponent(widgetDataJson)}` - if (store.widgetData.consent) { - u += `&consent=${encodeURIComponent(store.widgetData.consent)}` - } + u += `&widget_data=${encodeURIComponent(store.widgetDataJson)}` + u += store.consentParameter return u }) diff --git a/src/pretix/static/pretixpresale/widget/src/components/Button.vue b/src/pretix/static/pretixpresale/widget/src/components/Button.vue index c5774a4640..00140c0385 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/Button.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/Button.vue @@ -16,32 +16,6 @@ const formMethod = computed(() => { return 'post' }) -const formAction = computed(() => store.getFormAction()) - -const formTarget = computed(() => { - const isFirefox = navigator.userAgent.toLowerCase().includes('firefox') - const isAndroid = navigator.userAgent.toLowerCase().includes('android') - if (isAndroid && isFirefox) { - return '_top' - } - return '_blank' -}) - -const consentParameterValue = computed(() => { - if (store.widgetData.consent) { - return encodeURIComponent(store.widgetData.consent) - } - return '' -}) - -const widgetDataJson = computed(() => { - const clonedData = { ...store.widgetData } - if (clonedData.consent) { - delete clonedData.consent - } - return JSON.stringify(clonedData) -}) - function handleBuy (event: Event) { if (form.value) { const formData = new FormData(form.value) @@ -57,13 +31,13 @@ defineExpose({ - diff --git a/src/pretix/static/pretixpresale/widget/src/components/Category.vue b/src/pretix/static/pretixpresale/widget/src/components/Category.vue index deb99c1cbd..70b4c78be8 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/Category.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/Category.vue @@ -19,6 +19,5 @@ defineProps<{ :category="category" ) - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventCalendar.vue b/src/pretix/static/pretixpresale/widget/src/components/EventCalendar.vue index adfc05223b..b1ed41aa95 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventCalendar.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventCalendar.vue @@ -16,6 +16,7 @@ const calendar = ref() const displayEventInfo = computed(() => store.displayEventInfo || (store.displayEventInfo === null && store.parentStack.length > 0)) const monthname = computed(() => { + // TODO proper date formatting? if (!store.date) return '' const monthNum = store.date.substr(5, 2) const year = store.date.substr(0, 4) @@ -26,9 +27,8 @@ const id = computed(() => `${store.htmlId}-event-calendar-table`) const ariaLabelledby = computed(() => `${store.htmlId}-event-calendar-table-label`) -const showFilters = computed(() => !store.disableFilters && store.metaFilterFields.length > 0) - function backToList () { + // TODO should be in store store.weeks = null store.view = 'events' store.name = null @@ -63,7 +63,6 @@ function nextmonth () { store.reload({ focus: `#${id.value}` }) } - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventCalendarCell.vue b/src/pretix/static/pretixpresale/widget/src/components/EventCalendarCell.vue index cba2c3ac43..76bc4db1e1 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventCalendarCell.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventCalendarCell.vue @@ -26,9 +26,10 @@ const tabindex = computed(() => role.value === 'button' ? '0' : '-1') const classObject = computed(() => { const o: Record = {} if (props.day && props.day.events.length > 0) { - o['pretix-widget-has-events'] = true + o['pretix-widget-has-events'] = true // TODO static let best = 'red' let allLow = true + // TODO decopypasta for (const ev of props.day.events) { if (ev.availability.color === 'green') { best = 'green' @@ -47,11 +48,12 @@ const classObject = computed(() => { return o }) -function selectDay(e: Event) { +function selectDay (e: Event) { if (!props.day || !props.day.events.length || !props.mobile) return e.preventDefault() e.stopPropagation() + // TODO decopypasta if (props.day.events.length === 1) { const ev = props.day.events[0] store.parentStack.push(store.targetUrl) @@ -66,22 +68,23 @@ function selectDay(e: Event) { } } -function onKeyDown(e: KeyboardEvent) { +function onKeyDown (e: KeyboardEvent) { const keyDown = e.key ?? e.keyCode if (keyDown === 'Enter' || keyDown === 13 || ['Spacebar', ' '].includes(keyDown as string) || keyDown === 32) { + // (prevent default so the page doesn't scroll when pressing space) e.preventDefault() selectDay(e) } } -function attachListeners() { +function attachListeners () { if (role.value === 'button' && cellEl.value) { cellEl.value.addEventListener('click', selectDay) cellEl.value.addEventListener('keydown', onKeyDown) } } -function detachListeners() { +function detachListeners () { if (cellEl.value) { cellEl.value.removeEventListener('click', selectDay) cellEl.value.removeEventListener('keydown', onKeyDown) @@ -92,6 +95,7 @@ onMounted(() => { attachListeners() }) +// TODO why different from old version? watch(role, (newValue, oldValue) => { if (newValue === 'button' && oldValue !== 'button') { attachListeners() @@ -100,7 +104,6 @@ watch(role, (newValue, oldValue) => { } }) - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventCalendarEvent.vue b/src/pretix/static/pretixpresale/widget/src/components/EventCalendarEvent.vue index 6b978bebb5..e86ea140ba 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventCalendarEvent.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventCalendarEvent.vue @@ -21,7 +21,7 @@ const classObject = computed(() => { return o }) -function select() { +function select () { store.parentStack.push(store.targetUrl) store.targetUrl = props.event.event_url store.error = null @@ -30,18 +30,16 @@ function select() { store.reload() } - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventCalendarRow.vue b/src/pretix/static/pretixpresale/widget/src/components/EventCalendarRow.vue index 850f0d8b16..fc175d781d 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventCalendarRow.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventCalendarRow.vue @@ -7,11 +7,9 @@ defineProps<{ mobile: boolean }>() - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventForm.vue b/src/pretix/static/pretixpresale/widget/src/components/EventForm.vue index 5779a5e683..5b8a8f1b10 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventForm.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventForm.vue @@ -11,12 +11,9 @@ const voucherinput = ref() const isItemsSelected = ref(false) const localVoucher = ref('') -const displayEventInfo = computed(() => store.displayEventInfo || (store.displayEventInfo === null && (store.events || store.weeks || store.days))) - const idVoucherInput = computed(() => `${store.htmlId}-voucher-input`) - const ariaLabelledby = computed(() => `${store.htmlId}-voucher-headline`) - +const displayEventInfo = computed(() => store.displayEventInfo || (store.displayEventInfo === null && (store.events || store.weeks || store.days))) const idCartExistsMsg = computed(() => `${store.htmlId}-cart-exists`) const buyLabel = computed(() => { @@ -43,78 +40,16 @@ const hiddenParams = computed(() => { const params = new URL(store.getVoucherFormTarget()).searchParams params.delete('iframe') params.delete('take_cart_id') - return Array.from(params.entries()) + return [...params.entries()] }) const showVoucherForm = computed(() => store.vouchersExist && !store.disableVouchers && !store.voucherCode) -const consentParameterValue = computed(() => { - if (store.widgetData.consent) { - return encodeURIComponent(store.widgetData.consent) - } - return '' -}) - -const widgetDataJson = computed(() => { - const clonedData = { ...store.widgetData } - if (clonedData.consent) { - delete clonedData.consent - } - return JSON.stringify(clonedData) -}) - -const formAction = computed(() => { - const additionalParams = getAdditionalURLParams() - let checkoutUrl = `/${store.targetUrl.replace(/^[^\/]+:\/\/([^\/]+)\//, '')}w/${store.widgetId.replace('pretix-widget-', '')}/` - if (!store.cartExists) { - checkoutUrl += 'checkout/start' - } - if (additionalParams) { - checkoutUrl += `?${additionalParams}` - } - - const cookieName = `pretix_widget_${store.targetUrl.replace(/[^a-zA-Z0-9]+/g, '_')}` - const cartIdCookie = document.cookie - .split('; ') - .find((row) => row.startsWith(`${cookieName}=`)) - ?.split('=')[1] || null - - let formTarget = `${store.targetUrl}w/${store.widgetId.replace('pretix-widget-', '')}/cart/add?iframe=1&next=${encodeURIComponent(checkoutUrl)}` - if (cartIdCookie) { - formTarget += `&take_cart_id=${cartIdCookie}` - } - if (store.widgetData.consent) { - formTarget += `&consent=${encodeURIComponent(store.widgetData.consent)}` - } - return formTarget -}) - -const formTarget = computed(() => { - const isFirefox = navigator.userAgent.toLowerCase().includes('firefox') - const isAndroid = navigator.userAgent.toLowerCase().includes('android') - if (isAndroid && isFirefox) { - return '_top' - } - return '_blank' -}) - -function getAdditionalURLParams (): string { - if (!window.location.search.includes('utm_')) { - return '' - } - const params = new URLSearchParams(window.location.search) - for (const [key] of params.entries()) { - if (!key.startsWith('utm_')) { - params.delete(key) - } - } - return params.toString() -} - function backToList () { store.targetUrl = store.parentStack.pop() || store.targetUrl store.error = null if (!store.subevent) { + // reset if we are not in a series store.name = null store.frontpageText = null } @@ -123,13 +58,20 @@ function backToList () { store.appendEvents = false store.triggerLoadCallback() - if (store.events !== null) { + if (store.events !== undefined && store.events !== null) { store.view = 'events' - } else if (store.days !== null) { + } else if (store.days !== undefined && store.days !== null) { store.view = 'days' } else { store.view = 'weeks' } + + // TODO + // let $el = this.$root.$el + // this.$root.$nextTick(function () { + // // wait for redraw, then focus content element for better a11y + // $el.focus() + // }) } function calcItemsSelected () { @@ -208,14 +150,14 @@ watch(() => store.overlay?.frameShown, (newValue) => { form( ref="form", method="post", - :action="formAction", - :target="formTarget", + :action="store.formAction", + :target="store.formTarget", @submit="handleBuy" ) input(v-if="store.voucherCode", type="hidden", name="_voucher_code", :value="store.voucherCode") input(type="hidden", name="subevent", :value="store.subevent") - input(type="hidden", name="widget_data", :value="widgetDataJson") - input(v-if="consentParameterValue", type="hidden", name="consent", :value="consentParameterValue") + input(type="hidden", name="widget_data", :value="store.widgetDataJson") + input(v-if="store.consentParameterValue", type="hidden", name="consent", :value="store.consentParameterValue") //- Error message .pretix-widget-error-message(v-if="store.error") {{ store.error }} @@ -242,7 +184,7 @@ watch(() => store.overlay?.frameShown, (newValue) => { | {{ STRINGS.waiting_list }} .pretix-widget-clear - //- Product list + //- Actual Product list Category(v-for="category in store.categories", :key="category.id", :category="category") //- Buy button @@ -293,6 +235,5 @@ watch(() => store.overlay?.frameShown, (newValue) => { button(@click="handleRedeem") {{ STRINGS.redeem }} .pretix-widget-clear - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventList.vue b/src/pretix/static/pretixpresale/widget/src/components/EventList.vue index 991c056327..1f632f087b 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventList.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventList.vue @@ -9,11 +9,12 @@ const store = inject(StoreKey)! const displayEventInfo = computed(() => store.displayEventInfo || (store.displayEventInfo === null && store.parentStack.length > 0)) -const showBackButton = computed(() => store.weeks || store.parentStack.length > 0) - -const showFilters = computed(() => !store.disableFilters && store.metaFilterFields.length > 0) - -function backToCalendar() { +function backToCalendar () { + // TODO + // make sure to always focus content element + // this.$nextTick(function () { + // this.$root.$el.focus() + // }) store.offset = 0 store.appendEvents = false @@ -30,17 +31,16 @@ function backToCalendar() { } } -function loadMore() { +function loadMore () { store.appendEvents = true store.offset += 50 store.loading++ store.reload() } - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventListEntry.vue b/src/pretix/static/pretixpresale/widget/src/components/EventListEntry.vue index d99279c3ec..d200749177 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventListEntry.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventListEntry.vue @@ -22,7 +22,7 @@ const classObject = computed(() => { const location = computed(() => props.event.location.replace(/\s*\n\s*/g, ', ')) -function select() { +function select () { store.parentStack.push(store.targetUrl) store.targetUrl = props.event.event_url store.error = null @@ -31,15 +31,14 @@ function select() { store.reload() } - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventListFilterField.vue b/src/pretix/static/pretixpresale/widget/src/components/EventListFilterField.vue index b366eb8dfb..767c418c8a 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventListFilterField.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventListFilterField.vue @@ -16,13 +16,11 @@ const currentValue = computed(() => { return filterParams.get(props.field.key) || '' }) - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventListFilterForm.vue b/src/pretix/static/pretixpresale/widget/src/components/EventListFilterForm.vue index 5bc4987735..63068f3629 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventListFilterForm.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventListFilterForm.vue @@ -7,7 +7,7 @@ import EventListFilterField from './EventListFilterField.vue' const store = inject(StoreKey)! const filterform = ref() -function onSubmit(e: Event) { +function onSubmit (e: Event) { e.preventDefault() if (!filterform.value) return @@ -25,7 +25,6 @@ function onSubmit(e: Event) { store.reload() } - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventWeekCalendar.vue b/src/pretix/static/pretixpresale/widget/src/components/EventWeekCalendar.vue index 28e5ca11d4..ad0a2cdeb8 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventWeekCalendar.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventWeekCalendar.vue @@ -24,16 +24,14 @@ const weekname = computed(() => { const id = computed(() => `${store.htmlId}-event-week-table`) -const showFilters = computed(() => !store.disableFilters && store.metaFilterFields.length > 0) - -function backToList() { +function backToList () { store.weeks = null store.name = null store.frontpageText = null store.view = 'events' } -function prevweek() { +function prevweek () { if (!store.week) return let curWeek = store.week[1] let curYear = store.week[0] @@ -47,7 +45,7 @@ function prevweek() { store.reload({ focus: `#${id.value}` }) } -function nextweek() { +function nextweek () { if (!store.week) return let curWeek = store.week[1] let curYear = store.week[0] @@ -61,12 +59,11 @@ function nextweek() { store.reload({ focus: `#${id.value}` }) } - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/EventWeekCell.vue b/src/pretix/static/pretixpresale/widget/src/components/EventWeekCell.vue index 4da1e86151..241f654712 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/EventWeekCell.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/EventWeekCell.vue @@ -6,7 +6,7 @@ import EventCalendarEvent from './EventCalendarEvent.vue' const props = defineProps<{ day: DayEntry | null - mobile: boolean + mobile: boolean // TODO inject? }>() const store = inject(StoreKey)! @@ -47,6 +47,7 @@ function selectDay () { if (props.day.events.length === 1) { const ev = props.day.events[0] + // TODO store mutation bad store.parentStack.push(store.targetUrl) store.targetUrl = ev.event_url store.error = null @@ -59,7 +60,6 @@ function selectDay () { } } - - diff --git a/src/pretix/static/pretixpresale/widget/src/components/Overlay.vue b/src/pretix/static/pretixpresale/widget/src/components/Overlay.vue index f619c939fb..4f139fce74 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/Overlay.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/Overlay.vue @@ -69,8 +69,11 @@ function errorClose (e: Event) { store.overlay.errorUrlAfterNewTab = false } -function close () { +function close (e) { if (store.overlay.frameLoading) { + // Chrome does not allow blocking dialog.cancel event more than once + // => wiggle the loading-element and re-open the modal + cancel(e) frameDialog.value?.showModal() return } @@ -82,6 +85,7 @@ function close () { } function cancel (e: Event) { + // do not allow to cancel while frame is loading as we cannot abort the operation if (store.overlay.frameLoading) { e.preventDefault() const target = e.target as HTMLElement @@ -111,14 +115,14 @@ function triggerCloseCallback () { }) } +// TODO check if watchEffect is better for the following watchers watch(() => store.overlay.lightbox, (newValue, oldValue) => { - if (newValue) { - if (newValue.image !== oldValue?.image) { - newValue.loading = true - } - if (!oldValue) { - lightboxDialog.value?.showModal() - } + if (!newValue) return + if (newValue.image !== oldValue?.image) { + newValue.loading = true + } + if (!oldValue) { + lightboxDialog.value?.showModal() } }) @@ -128,19 +132,19 @@ watch(() => store.overlay.errorMessage, (newValue, oldValue) => { } }) -watch(() => store.overlay.frameShown, (newValue) => { - if (newValue) { - nextTick(() => { - closeButton.value?.focus() - }) - } +watch(() => store.overlay.frameShown, async (newValue) => { + if (!newValue) return + await nextTick() + closeButton.value?.focus() }) watch(() => store.overlay.frameSrc, (newValue, oldValue) => { + // show loading spinner only when previously no frame_src was set if (newValue && !oldValue) { store.overlay.frameLoading = true } if (iframe.value) { + // to close and unload the iframe, frame_src can be empty -> make it valid HTML with about:blank iframe.value.src = newValue || 'about:blank' } }) @@ -151,7 +155,7 @@ watch(() => store.overlay.frameLoading, (newValue) => { frameDialog.value.showModal() } } else { - if (!store.overlay.frameSrc && frameDialog.value?.open) { + if (!store.overlay.frameSrc && frameDialog.value?.open) { // finished loading, but no iframe to display => close frameDialog.value.close() } } @@ -169,7 +173,6 @@ onUnmounted(() => { - diff --git a/src/pretix/static/pretixpresale/widget/src/components/Widget.vue b/src/pretix/static/pretixpresale/widget/src/components/Widget.vue index 9751d41d6e..f3af0c817a 100644 --- a/src/pretix/static/pretixpresale/widget/src/components/Widget.vue +++ b/src/pretix/static/pretixpresale/widget/src/components/Widget.vue @@ -36,12 +36,14 @@ onMounted(() => { resizeObserver.observe(wrapper.value) } - store.reload() - emit('mounted') + store.reload() // TODO call earlier? + emit('mounted') // TODO where does this go? }) watch(() => store.view, (newValue, oldValue) => { if (oldValue && wrapper.value) { + // always make sure the widget is scrolled to the top + // as we only check top, we do not need to wait for a redraw const rect = wrapper.value.getBoundingClientRect() if (rect.top < 0) { wrapper.value.scrollIntoView() diff --git a/src/pretix/static/pretixpresale/widget/src/sharedStore.ts b/src/pretix/static/pretixpresale/widget/src/sharedStore.ts index 6d38ad32d8..8eb69466d5 100644 --- a/src/pretix/static/pretixpresale/widget/src/sharedStore.ts +++ b/src/pretix/static/pretixpresale/widget/src/sharedStore.ts @@ -125,22 +125,23 @@ export function createWidgetStore (config: { if ((window as any).crossOriginIsolated === true) return false return !this.disableIframe && (this.skipSsl || /https.*/.test(document.location.protocol)) }, - cookieName (): string { return `pretix_widget_${this.targetUrl.replace(/[^a-zA-Z0-9]+/g, '_')}` }, - cartIdFromCookie (): string | null { return getCookie(this.cookieName) ?? null }, - + widgetDataJson (): string { + const cloned = { ...this.widgetData } + delete cloned.consent + return JSON.stringify(cloned) + }, consentParameter (): string { if (this.widgetData.consent) { return `&consent=${encodeURIComponent(this.widgetData.consent)}` } return '' }, - additionalURLParams (): string { if (!window.location.search.includes('utm_')) { return '' @@ -153,12 +154,46 @@ export function createWidgetStore (config: { } return params.toString() }, - newTabTarget (): string { return this.subevent ? `${this.targetUrl}${this.subevent}/` : this.targetUrl }, - }, + formTarget (): string { + const isFirefox = navigator.userAgent.toLowerCase().includes('firefox') + const isAndroid = navigator.userAgent.toLowerCase().includes('android') + if (isAndroid && isFirefox) { + return '_top' + } + return '_blank' + }, + consentParameterValue (): string { + if (this.widgetData.consent) { + return encodeURIComponent(this.widgetData.consent) + } + return '' + }, + formAction (): string { + if (!this.useIframe && this.isButton && this.items.length === 0) { + if (this.voucherCode) return `${this.targetUrl}redeem` + if (this.subevent) return `${this.targetUrl}${this.subevent}/` + return this.targetUrl + } + let checkoutUrl = `/${this.targetUrl.replace(/^[^/]+:\/\/([^/]+)\//, '')}w/${globalWidgetId}/` + if (!this.cartExists) { + checkoutUrl += 'checkout/start' + } + if (this.additionalURLParams) { + checkoutUrl += `?${this.additionalURLParams}` + } + + let formTarget = `${this.targetUrl}w/${globalWidgetId}/cart/add?iframe=1&next=${encodeURIComponent(checkoutUrl)}` + if (this.cartIdFromCookie) { + formTarget += `&take_cart_id=${this.cartIdFromCookie}` + } + formTarget += this.consentParameter + return formTarget + }, + }, actions: { triggerLoadCallback () { nextTick(() => { @@ -167,7 +202,6 @@ export function createWidgetStore (config: { } }) }, - async reload (opt: { focus?: string } = {}) { if (this.isButton) return @@ -303,28 +337,6 @@ export function createWidgetStore (config: { } } }, - getFormAction (): string { - if (!this.useIframe && this.isButton && this.items.length === 0) { - if (this.voucherCode) return `${this.targetUrl}redeem` - if (this.subevent) return `${this.targetUrl}${this.subevent}/` - return this.targetUrl - } - - let checkoutUrl = `/${this.targetUrl.replace(/^[^/]+:\/\/([^/]+)\//, '')}w/${globalWidgetId}/` - if (!this.cartExists) { - checkoutUrl += 'checkout/start' - } - if (this.additionalURLParams) { - checkoutUrl += `?${this.additionalURLParams}` - } - - let formTarget = `${this.targetUrl}w/${globalWidgetId}/cart/add?iframe=1&next=${encodeURIComponent(checkoutUrl)}` - if (this.cartIdFromCookie) { - formTarget += `&take_cart_id=${this.cartIdFromCookie}` - } - formTarget += this.consentParameter - return formTarget - }, getVoucherFormTarget (): string { let formTarget = `${this.targetUrl}w/${globalWidgetId}/redeem?iframe=1&locale=${LANG}` if (this.cartIdFromCookie) { @@ -334,7 +346,7 @@ export function createWidgetStore (config: { formTarget += `&subevent=${this.subevent}` } if (this.widgetData) { - formTarget += `&widget_data=${encodeURIComponent(JSON.stringify(this.widgetData))}` + formTarget += `&widget_data=${encodeURIComponent(this.widgetDataJson)}` } formTarget += this.consentParameter if (this.additionalURLParams) { @@ -349,12 +361,11 @@ export function createWidgetStore (config: { setCookie(this.cookieName, data.cart_id, 30) } - let redirectUrl = data.redirect - if (redirectUrl.substring(0, 1) === '/') { - redirectUrl = `${this.targetUrl.replace(/^([^/]+:\/\/[^/]+)\/.*$/, '$1')}${redirectUrl}` + let url = data.redirect + if (url.substring(0, 1) === '/') { + url = `${this.targetUrl.replace(/^([^/]+:\/\/[^/]+)\/.*$/, '$1')}${url}` } - let url = redirectUrl if (url.includes('?')) { url = `${url}&iframe=1&locale=${LANG}&take_cart_id=${this.cartId}` } else { @@ -375,9 +386,11 @@ export function createWidgetStore (config: { } else { this.overlay.frameSrc = url } - } else if (data.async_id && data.check_url) { + } else { this.asyncTaskId = data.async_id - this.asyncTaskCheckUrl = `${this.targetUrl.replace(/^([^/]+:\/\/[^/]+)\/.*$/, '$1')}${data.check_url}` + if (data.check_url) { + this.asyncTaskCheckUrl = `${this.targetUrl.replace(/^([^/]+:\/\/[^/]+)\/.*$/, '$1')}${data.check_url}` + } this.asyncTaskTimeout = window.setTimeout(() => this.pollAsyncTask(), this.asyncTaskInterval) this.asyncTaskInterval = 250 } @@ -397,11 +410,8 @@ export function createWidgetStore (config: { } }, async buy (formData: FormData, event?: Event) { - if (this.useIframe) { - if (event) event.preventDefault() - } else { - return - } + if (!this.useIframe) return + if (event) event.preventDefault() if (this.isButton && this.items.length === 0) { if (this.voucherCode) { @@ -412,7 +422,7 @@ export function createWidgetStore (config: { return } - const url = `${this.getFormAction()}&locale=${LANG}&ajax=1` + const url = `${this.formAction}&locale=${LANG}&ajax=1` this.overlay.frameLoading = true this.asyncTaskInterval = 100 @@ -427,25 +437,24 @@ export function createWidgetStore (config: { this.overlay.errorUrlAfter = this.newTabTarget this.overlay.errorUrlAfterNewTab = true } else if (e.status === 405) { + // Likely a redirect! this.targetUrl = e.responseUrl.substring(0, e.responseUrl.indexOf('/cart/add') - 18) this.overlay.frameLoading = false - } else { - this.overlay.errorMessage = STRINGS.cart_error - this.overlay.frameLoading = false + this.buy(formData) + return } - } else { - this.overlay.errorMessage = STRINGS.cart_error - this.overlay.frameLoading = false } + this.overlay.errorMessage = STRINGS.cart_error + this.overlay.frameLoading = false } }, redeem (voucherCode: string, event?: Event) { - if (this.useIframe) { - if (event) event.preventDefault() - this.voucherOpen(voucherCode) - } + if (!this.useIframe) return + if (event) event.preventDefault() + this.voucherOpen(voucherCode) }, voucherOpen (voucherCode: string) { + // TODO just use https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams const redirectUrl = `${this.getVoucherFormTarget()}&voucher=${encodeURIComponent(voucherCode)}` if (this.useIframe) { this.overlay.frameSrc = redirectUrl @@ -456,6 +465,7 @@ export function createWidgetStore (config: { resume () { let redirectUrl = `${this.targetUrl}w/${globalWidgetId}/` if (this.subevent && !this.cartId) { + // button with subevent but no items redirectUrl += `${this.subevent}/` } redirectUrl += `?iframe=1&locale=${LANG}` @@ -463,7 +473,7 @@ export function createWidgetStore (config: { redirectUrl += `&take_cart_id=${this.cartId}` } if (this.widgetData) { - redirectUrl += `&widget_data=${encodeURIComponent(JSON.stringify(this.widgetData))}` + redirectUrl += `&widget_data=${encodeURIComponent(this.widgetDataJson)}` } redirectUrl += this.consentParameter if (this.additionalURLParams) { @@ -502,7 +512,7 @@ export function createWidgetStore (config: { redirectUrl += `&take_cart_id=${this.cartId}` } if (this.widgetData) { - redirectUrl += `&widget_data=${encodeURIComponent(JSON.stringify(this.widgetData))}` + redirectUrl += `&widget_data=${encodeURIComponent(this.widgetDataJson)}` } redirectUrl += this.consentParameter if (this.additionalURLParams) {