Files
my2/app/pages/order/success/[orderId].vue
Bastian Masanek 782bd6cdd7 Enhance CheckoutForm and Order components with user data integration
- Refactored CheckoutForm.vue to utilize an extended user type, incorporating additional address fields for improved user data handling.
- Updated OrderSummary.vue to conditionally display salutation based on user input.
- Standardized error alert styling across multiple pages, changing variant from 'destructive' to 'error' for consistency.
- Adjusted button styles in various components to align with the new 'experimenta' variant.

These changes aim to improve user experience by ensuring accurate data representation and consistent UI elements across the checkout and order processes.
2025-11-03 17:00:22 +01:00

239 lines
7.4 KiB
Vue

<script setup lang="ts">
/**
* Order Success Page (/order/success/[orderId])
*
* Features:
* - Requires authentication (middleware: auth)
* - Fetches order details from /api/orders/[orderId]
* - Validates order belongs to user (server-side)
* - Validates order status is 'completed'
* - Shows success message and animation
* - Shows order number
* - Shows OrderSummary component (read-only)
* - Links to homepage and product pages
*/
definePageMeta({
middleware: 'auth',
layout: 'default',
})
const route = useRoute()
const orderId = computed(() => route.params.orderId as string)
// Get cart composable to refresh cart state
const { fetchCart } = useCart()
// Order data
const order = ref<any>(null)
const isLoading = ref(false)
const error = ref<string | null>(null)
// Fetch order details
async function fetchOrder() {
if (!orderId.value) return
isLoading.value = true
error.value = null
try {
order.value = await $fetch(`/api/orders/${orderId.value}`)
// Check order status
if (order.value.status !== 'completed') {
error.value = `Diese Bestellung wurde noch nicht abgeschlossen. Status: ${order.value.status}`
// Redirect to confirmation page if still pending
if (order.value.status === 'pending') {
setTimeout(() => {
navigateTo(`/order/confirm/${orderId.value}`)
}, 2000)
}
} else {
// Order completed successfully - refresh cart to show it's empty
await fetchCart()
}
} catch (err: any) {
console.error('Failed to fetch order:', err)
if (err.statusCode === 404) {
error.value = 'Bestellung nicht gefunden'
} else if (err.statusCode === 403) {
error.value = 'Du hast keine Berechtigung, diese Bestellung zu sehen'
} else {
error.value = 'Fehler beim Laden der Bestellung'
}
// Redirect to homepage after 3 seconds
setTimeout(() => {
navigateTo('/')
}, 3000)
} finally {
isLoading.value = false
}
}
// Fetch order on mount
onMounted(() => {
fetchOrder()
})
</script>
<template>
<div>
<CommonHeader />
<div class="container mx-auto px-4 py-8 max-w-4xl">
<!-- Error Alert -->
<Alert v-if="error" variant="error" class="mb-6">
<AlertTitle>Fehler</AlertTitle>
<AlertDescription>{{ error }}</AlertDescription>
</Alert>
<!-- Loading State -->
<div v-if="isLoading" class="text-center py-12">
<div
class="animate-spin rounded-full h-12 w-12 border-4 border-white/20 border-t-white mx-auto mb-4"
/>
<p class="text-white/60">Lade Bestellung...</p>
</div>
<!-- Success Content -->
<div v-else-if="order && order.status === 'completed'" class="space-y-8">
<!-- Success Header with Animation -->
<div class="text-center space-y-4 py-8">
<!-- Success Icon (animated checkmark) -->
<div class="flex justify-center mb-6">
<div
class="rounded-full bg-green-500/20 p-6 border-4 border-green-500/50 animate-pulse"
>
<svg
class="w-16 h-16 text-green-500"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 13l4 4L19 7"
></path>
</svg>
</div>
</div>
<!-- Success Message -->
<h1 class="text-4xl font-bold text-white mb-2">
Vielen Dank für deine Bestellung!
</h1>
<p class="text-xl text-white/70">Deine Bestellung wurde erfolgreich abgeschlossen.</p>
<!-- Order Number -->
<div class="inline-block mt-4 px-6 py-3 bg-white/5 rounded-lg border border-white/10">
<p class="text-sm text-white/60">Bestellnummer</p>
<p class="text-2xl font-mono font-bold text-experimenta-accent">
{{ order.orderNumber }}
</p>
</div>
</div>
<!-- Next Steps Info -->
<Alert class="border-blue-500/50 bg-blue-500/10">
<div class="flex items-start gap-3">
<svg
class="w-5 h-5 text-blue-400 mt-0.5 flex-shrink-0"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<div>
<AlertTitle class="text-blue-400">Wie geht es weiter?</AlertTitle>
<AlertDescription class="text-blue-100/90 space-y-2">
<p>
Du erhältst in Kürze eine Bestätigungs-E-Mail mit allen Details zu deiner
Bestellung.
</p>
<p>
Deine Makerspace-Jahreskarte wird bearbeitet und steht dir bald zur
Verfügung.
</p>
</AlertDescription>
</div>
</div>
</Alert>
<!-- Order Summary Card -->
<Card class="p-6">
<OrderSummary :order="order" :show-address="true" />
</Card>
<!-- Action Buttons -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<NuxtLink to="/" class="w-full">
<Button variant="secondary" size="experimenta" class="w-full">
<svg
class="w-5 h-5 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
></path>
</svg>
Zurück zur Startseite
</Button>
</NuxtLink>
<NuxtLink to="/experimenta" class="w-full">
<Button variant="experimenta" size="experimenta" class="w-full">
<svg
class="w-5 h-5 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"
></path>
</svg>
Weitere Produkte kaufen
</Button>
</NuxtLink>
</div>
<!-- Support Info -->
<div class="text-center pt-4 space-y-2">
<p class="text-sm text-white/60">
Fragen zu deiner Bestellung? Kontaktiere uns gerne:
</p>
<a
href="mailto:info@experimenta.science"
class="text-sm text-experimenta-accent hover:underline"
>
info@experimenta.science
</a>
</div>
</div>
</div>
</div>
</template>