Some checks failed
Build and publish / build (push) Failing after 19s
Source moved verbatim from mp/shop/ on 2026-04-29; mp was the first concrete adapter consuming the libreshop toolkit. Builds and publishes git.librete.ch/libreshop/shop on every main / v* push via the standard .gitea/workflows/build.yml shared across libreshop components.
237 lines
7.5 KiB
Vue
237 lines
7.5 KiB
Vue
<template>
|
|
<main class="pt-4 lg:container mx-auto px-4">
|
|
<div v-if="displayState === 'loading'">
|
|
<div class="flex items-center justify-center h-[60vh]">
|
|
<div class="text-center">
|
|
<LoadingSpinner />
|
|
<p class="text-2xl mt-8 font-semibold">Bestellung wird geladen...</p>
|
|
<p class="text-lg">Bitte warte einen Moment, während wir deine Bestellung vorbereiten.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else-if="displayState === 'main-content'">
|
|
<Stepper :step="4" />
|
|
|
|
<div class="flex gap-12 relative max-w-screen-lg mx-auto my-8">
|
|
<div v-if="order && order.id" class="flex flex-col gap-8 w-full">
|
|
<ClientOnly>
|
|
<ConfettiExplosion :colors="['#2563eb', '#ec4899', '#16a34a']" />
|
|
</ClientOnly>
|
|
|
|
<div>
|
|
<Heading :level="1">Vielen Dank für deine Bestellung bei MUELLERPRINTS!</Heading>
|
|
|
|
<Heading :level="2">Deine Bestellnummer: {{ order.id }}</Heading>
|
|
</div>
|
|
|
|
<p class="text-lg lg:w-2/3">
|
|
In Kürze erhälst du von uns eine E-Mail mit allen Einzelheiten zu deiner Bestellung. Du kannst sie auch hier herunterladen, sobald sie erstellt
|
|
wurde.
|
|
</p>
|
|
|
|
<div>
|
|
<Button id="download-invoice" :is-pending="!hasReachedMaxFailedRequests && (!isReadyToDownload || isDownloadPending)" @click="downloadInvoice">
|
|
<span v-if="hasReachedMaxFailedRequests">Bald verfügbar</span>
|
|
<span v-else>Rechnung herunterladen</span>
|
|
</Button>
|
|
<div v-if="hasReachedMaxFailedRequests" class="text-sm mt-3">
|
|
Es konnte noch keine Rechnung ermittelt werden. Bitte prüfe deine E-Mails oder kontaktiere uns: order@muellerprints.de
|
|
</div>
|
|
</div>
|
|
|
|
<hr />
|
|
|
|
<div class="flex flex-col gap-8">
|
|
<ul class="divide-y divide-gray-300" data-e2e="order-products">
|
|
<li v-for="(position, index) in orderProducts" :key="index" class="py-6 gap-6">
|
|
<div v-if="position.product" class="flex items-center justify-between">
|
|
<img
|
|
v-if="position.product?.images?.images"
|
|
:src="position.product?.images?.images[0]?.formats?.thumbnail?.url"
|
|
:alt="position.product?.name"
|
|
class="w-16 lg:w-24 object-cover"
|
|
/>
|
|
<div v-else class="bg-black opacity-5 w-12 h-12"></div>
|
|
|
|
<a :href="`/details/${position.product?.slug}`" class="p-2 text-xl font-bold flex-grow">{{ position.product?.name }}</a>
|
|
|
|
<span
|
|
data-e2e="cart-products-item-count"
|
|
class="block appearance-none w-16 text-center bg-white border border-gray-300 hover:border-gray-500 px-4 py-2 rounded shadow leading-tight focus:outline-none focus:border-indigo-500 focus:shadow-outline"
|
|
>
|
|
{{ position?.count }}
|
|
</span>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else-if="displayState === 'terms-warning'">
|
|
<div class="bg-yellow-100 border-l-4 border-yellow-500 p-4 mb-8">
|
|
<p class="text-yellow-700 font-semibold">
|
|
Bitte, akzeptiere die
|
|
<a href="/agb" target="_blank" class="underline">AGB</a>
|
|
und
|
|
<a href="/datenschutz" target="_blank" class="underline">Datenschutzerklärung</a>, um fortzufahren.
|
|
</p>
|
|
<NuxtLink to="/checkout/1" class="text-yellow-700 hover:underline">Zurück zur Kasse</NuxtLink>
|
|
</div>
|
|
</div>
|
|
<div v-else-if="displayState === 'address-warning'">
|
|
<div class="bg-yellow-100 border-l-4 border-yellow-500 p-4 mb-8">
|
|
<p class="text-yellow-700 font-semibold">Bitte, gib deine Lieferadresse an, um fortzufahren.</p>
|
|
<NuxtLink to="/checkout/2" class="text-yellow-700 hover:underline">Zurück zur Kasse</NuxtLink>
|
|
</div>
|
|
</div>
|
|
<div v-else-if="displayState === 'payment-warning'">
|
|
<div class="bg-yellow-100 border-l-4 border-yellow-500 p-4 mb-8">
|
|
<p class="text-yellow-700 font-semibold">Bitte, gib eine Zahlungsart an, um fortzufahren.</p>
|
|
<NuxtLink to="/checkout/3" class="text-yellow-700 hover:underline">Zurück zur Kasse</NuxtLink>
|
|
</div>
|
|
</div>
|
|
<div v-else>
|
|
<div class="flex items-center justify-center h-[60vh]">
|
|
<div class="text-center">
|
|
<div class="w-20 h-20"></div>
|
|
<p class="text-2xl mt-8 font-semibold">Bestellung nicht gefunden...</p>
|
|
<p class="text-lg">Leider konnte deine Bestellung nicht unter dieser Adresse gefunden werden.</p>
|
|
<p class="text-lg mt-6">
|
|
Falls das Problem bestehen bleibt, <a href="/kontakt" class="underline">kontaktiere uns</a> bitte. Schicke deine Bestell-ID bitte an
|
|
paperwork@muellerprints.de
|
|
</p>
|
|
<pre class="mt-3 p-2 rounded-sm bg-gray-100">Bestell-ID: {{ uuid }}</pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { Order } from "~/types";
|
|
import { trackEvent } from "~/utils/trackEvent";
|
|
|
|
const route = useRoute();
|
|
const uuid = computed(() => route.params.uuid as string);
|
|
|
|
const shopApi = useShopApi();
|
|
|
|
const order = ref<Order | null>(null);
|
|
const isLoading = ref(true);
|
|
const isDownloadPending = ref(false);
|
|
const failedDownloadRequests = ref(0);
|
|
const hasReachedMaxFailedRequests = ref(false);
|
|
const displayState = ref("loading");
|
|
|
|
const maxFailedRequests = 20;
|
|
|
|
const orderProducts = computed(() => order.value?.cart ?? []);
|
|
const isReadyToDownload = computed(() => !!order.value?.invoice);
|
|
|
|
onMounted(async () => {
|
|
let hasTrackedConversion = false;
|
|
|
|
const fetchAndSetOrder = async () => {
|
|
try {
|
|
order.value = await shopApi.getOrder(uuid.value);
|
|
updateDisplayState();
|
|
|
|
if (!order.value?.acceptedTermsAndConditionsAt || !order.value?.invoiceAddress || !order.value?.paymentAuthorised) {
|
|
console.error("Unauthorised view");
|
|
isLoading.value = false;
|
|
return;
|
|
}
|
|
|
|
// Track order confirmation view (only once)
|
|
if (!hasTrackedConversion) {
|
|
hasTrackedConversion = true;
|
|
trackEvent("order-confirmation-viewed", {
|
|
orderId: order.value.id,
|
|
orderTotal: order.value.total,
|
|
itemCount: order.value.cart?.length ?? 0
|
|
});
|
|
}
|
|
|
|
if (order.value?.invoice?.url) {
|
|
console.log("Invoice fetched successfully");
|
|
isLoading.value = false;
|
|
return;
|
|
}
|
|
|
|
failedDownloadRequests.value++;
|
|
|
|
if (failedDownloadRequests.value < maxFailedRequests) {
|
|
console.log("Retrying to fetch invoice", failedDownloadRequests.value);
|
|
setTimeout(fetchAndSetOrder, 3000);
|
|
} else {
|
|
hasReachedMaxFailedRequests.value = true;
|
|
isLoading.value = false;
|
|
}
|
|
} catch (e) {
|
|
console.error("Error fetching order:", e);
|
|
isLoading.value = false;
|
|
updateDisplayState();
|
|
}
|
|
};
|
|
|
|
await fetchAndSetOrder();
|
|
});
|
|
|
|
function updateDisplayState() {
|
|
if (!order.value) {
|
|
displayState.value = "loading";
|
|
return;
|
|
}
|
|
|
|
if (!order.value.id) {
|
|
displayState.value = "not-found-error";
|
|
return;
|
|
}
|
|
|
|
if (!order.value.acceptedTermsAndConditionsAt) {
|
|
displayState.value = "terms-warning";
|
|
return;
|
|
}
|
|
|
|
if (!order.value.invoiceAddress) {
|
|
displayState.value = "address-warning";
|
|
return;
|
|
}
|
|
|
|
if (!order.value.paymentAuthorised) {
|
|
displayState.value = "payment-warning";
|
|
return;
|
|
}
|
|
|
|
displayState.value = "main-content";
|
|
}
|
|
|
|
function downloadInvoice() {
|
|
if (!isReadyToDownload.value) {
|
|
console.error("Invoice not ready to download");
|
|
return;
|
|
}
|
|
try {
|
|
isDownloadPending.value = true;
|
|
if (order.value.invoice) {
|
|
trackEvent("order-invoice-downloaded", {
|
|
orderId: order.value.id
|
|
});
|
|
window.open(order.value.invoice.url, "_blank");
|
|
} else {
|
|
console.error("Invoice URL not available");
|
|
}
|
|
} catch (e) {
|
|
console.error("Error downloading invoice:", e);
|
|
} finally {
|
|
isDownloadPending.value = false;
|
|
}
|
|
}
|
|
|
|
// SEO
|
|
useSeoMeta({
|
|
title: "Bestellbestätigung | MUELLERPRINTS"
|
|
});
|
|
</script>
|