You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
5.5 KiB
186 lines
5.5 KiB
<script setup lang="ts">
|
|
/**
|
|
* Payment Mock Page (/payment)
|
|
*
|
|
* Features:
|
|
* - Requires authentication (middleware: auth)
|
|
* - Shows order total
|
|
* - Shows MockPayPalButton component
|
|
* - Redirects to order confirmation after "payment" success
|
|
* - Query param: orderId (required)
|
|
*/
|
|
|
|
definePageMeta({
|
|
middleware: 'auth',
|
|
layout: 'default',
|
|
})
|
|
|
|
const route = useRoute()
|
|
|
|
// Get order ID from query params
|
|
const orderId = computed(() => route.query.orderId as string | undefined)
|
|
|
|
// Order data
|
|
const order = ref<any>(null)
|
|
const isLoading = ref(false)
|
|
const error = ref<string | null>(null)
|
|
|
|
// Redirect to cart if no order ID
|
|
watchEffect(() => {
|
|
if (!orderId.value) {
|
|
navigateTo('/cart')
|
|
}
|
|
})
|
|
|
|
// Fetch order details
|
|
onMounted(async () => {
|
|
if (!orderId.value) return
|
|
|
|
isLoading.value = true
|
|
error.value = null
|
|
|
|
try {
|
|
order.value = await $fetch(`/api/orders/${orderId.value}`)
|
|
} catch (err: any) {
|
|
console.error('Failed to fetch order:', err)
|
|
error.value = 'Bestellung nicht gefunden'
|
|
|
|
// Redirect to cart after 3 seconds
|
|
setTimeout(() => {
|
|
navigateTo('/cart')
|
|
}, 3000)
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
})
|
|
|
|
// Handle payment success
|
|
function handlePaymentSuccess() {
|
|
if (!orderId.value) return
|
|
|
|
// Redirect to order confirmation page
|
|
navigateTo(`/order/confirm/${orderId.value}`)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<CommonHeader />
|
|
|
|
<div class="container mx-auto px-4 py-8 max-w-2xl">
|
|
<!-- Page Header -->
|
|
<div class="mb-8 text-center">
|
|
<h1 class="text-4xl font-bold text-white mb-2">Zahlung</h1>
|
|
<p class="text-white/70">Schließe deine Bestellung mit PayPal ab</p>
|
|
</div>
|
|
|
|
<!-- Error Alert -->
|
|
<Alert v-if="error" variant="error" class="mb-6">
|
|
<AlertTitle>Fehler</AlertTitle>
|
|
<AlertDescription>
|
|
{{ error }}. Du wirst zum Warenkorb weitergeleitet...
|
|
</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>
|
|
|
|
<!-- Payment Content -->
|
|
<div v-else-if="order" class="space-y-6">
|
|
<!-- Order Summary Card -->
|
|
<Card class="p-6">
|
|
<div class="space-y-4">
|
|
<div class="flex items-center justify-between pb-4 border-b border-white/20">
|
|
<div>
|
|
<h2 class="text-lg font-semibold text-white">Bestellnummer</h2>
|
|
<p class="text-sm font-mono text-white/80">{{ order.orderNumber }}</p>
|
|
</div>
|
|
<div class="text-right">
|
|
<p class="text-sm text-white/60">Zu zahlen</p>
|
|
<p class="text-2xl font-bold text-experimenta-accent">
|
|
{{
|
|
new Intl.NumberFormat('de-DE', {
|
|
style: 'currency',
|
|
currency: 'EUR',
|
|
}).format(Number.parseFloat(order.totalAmount))
|
|
}}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Order Items Summary -->
|
|
<div class="space-y-2">
|
|
<h3 class="text-sm font-medium text-white/80">Artikel in dieser Bestellung:</h3>
|
|
<div class="space-y-1">
|
|
<div
|
|
v-for="item in order.items"
|
|
:key="item.id"
|
|
class="flex items-center justify-between text-sm"
|
|
>
|
|
<span class="text-white/70">
|
|
{{ item.quantity }}x
|
|
{{ item.productSnapshot?.name || item.product?.name }}
|
|
</span>
|
|
<span class="text-white/80 font-medium">
|
|
{{
|
|
new Intl.NumberFormat('de-DE', {
|
|
style: 'currency',
|
|
currency: 'EUR',
|
|
}).format(item.subtotal)
|
|
}}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
|
|
<!-- Payment Button Card -->
|
|
<Card class="p-6">
|
|
<h2 class="text-lg font-semibold text-white mb-4">Zahlungsmethode</h2>
|
|
<MockPayPalButton
|
|
:order-id="orderId!"
|
|
:amount="Number.parseFloat(order.totalAmount)"
|
|
@success="handlePaymentSuccess"
|
|
/>
|
|
</Card>
|
|
|
|
<!-- Security Note -->
|
|
<div class="text-center space-y-2 pt-4">
|
|
<div class="flex items-center justify-center gap-2 text-sm text-white/60">
|
|
<svg
|
|
class="w-4 h-4"
|
|
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="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
|
|
></path>
|
|
</svg>
|
|
<span>Sichere Verbindung</span>
|
|
</div>
|
|
<p class="text-xs text-white/40">
|
|
Deine Zahlung wird über eine sichere SSL-Verbindung verarbeitet.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Back Link -->
|
|
<div class="text-center pt-4">
|
|
<NuxtLink to="/checkout" class="text-sm text-experimenta-accent hover:underline">
|
|
← Zurück zur Kasse
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|