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.
 
 
 

139 lines
4.5 KiB

<script setup lang="ts">
/**
* Products Listing Page
*
* Displays all available products (annual passes, etc.) using ProductCard and ProductGrid components.
* Fetches products from the database via API.
*/
// Page metadata
definePageMeta({
layout: 'default',
})
// Type definition for product
interface Product {
id: string
navProductId: string
name: string
description: string
price: string
stockQuantity: number
category: string
active: boolean
createdAt: Date
updatedAt: Date
}
// Fetch products from API
const { data: products, error, pending } = await useFetch<Product[]>('/api/products')
// Map product categories to badges
const getBadge = (category: string): string | undefined => {
const badges: Record<string, string> = {
'makerspace-annual-pass': 'Beliebt',
'educator-annual-pass': 'Neu',
}
return badges[category]
}
// Map product categories to discount percentages (for demo)
const getDiscount = (category: string): number | undefined => {
const discounts: Record<string, number> = {
'educator-annual-pass': 15,
}
return discounts[category]
}
</script>
<template>
<NuxtLayout name="default">
<div class="min-h-screen bg-gradient-primary px-4 py-12 md:px-6 lg:px-8">
<!-- Page Header -->
<div class="mx-auto mb-12 max-w-container-wide text-center">
<h1 class="mb-4 text-4xl font-bold text-white md:text-5xl">
Unsere Jahreskarten
</h1>
<p class="mx-auto max-w-2xl text-lg text-white/80">
Wähle die passende Jahreskarte für deine Bedürfnisse. Alle Karten sind 365 Tage gültig
und sofort einsetzbar.
</p>
</div>
<!-- Loading State -->
<div v-if="pending" class="mx-auto max-w-container-wide text-center">
<div class="card-glass inline-block">
<p class="text-white/80">Produkte werden geladen...</p>
</div>
</div>
<!-- Error State -->
<div v-else-if="error" class="mx-auto max-w-container-wide">
<div class="card-glass border-red/50 bg-red/10">
<h2 class="mb-2 text-xl font-semibold text-red">
Fehler beim Laden der Produkte
</h2>
<p class="text-white/80">
{{ error.message || 'Ein unbekannter Fehler ist aufgetreten.' }}
</p>
</div>
</div>
<!-- Products Grid -->
<div v-else-if="products && products.length > 0" class="mx-auto max-w-container-wide">
<ProductGrid :columns="3">
<ProductCard
v-for="product in products"
:key="product.id"
image="/img/makerspace-jk-2025.jpg"
:title="product.name"
:description="product.description"
:price="Number(product.price)"
:badge="getBadge(product.category)"
:discount-percentage="getDiscount(product.category)"
:product-id="product.id"
/>
</ProductGrid>
</div>
<!-- Empty State -->
<div v-else class="mx-auto max-w-container-wide text-center">
<div class="card-glass">
<h2 class="mb-2 text-xl font-semibold text-white">
Keine Produkte verfügbar
</h2>
<p class="text-white/80">
Aktuell sind keine Produkte verfügbar. Bitte schaue später noch einmal vorbei.
</p>
</div>
</div>
<!-- Info Card -->
<div class="mx-auto mt-12 max-w-container-wide">
<div class="card-info card-accent-border">
<h2 class="mb-3 text-xl font-semibold text-experimenta-accent">
Warum eine Jahreskarte?
</h2>
<ul class="space-y-2 text-white/90">
<li class="flex items-start gap-2">
<span class="mt-1 text-experimenta-accent">✓</span>
<span>365 Tage unbegrenzter Zugang zu deinen Lieblingsbereichen</span>
</li>
<li class="flex items-start gap-2">
<span class="mt-1 text-experimenta-accent">✓</span>
<span>Keine versteckten Kosten – ein Preis für das ganze Jahr</span>
</li>
<li class="flex items-start gap-2">
<span class="mt-1 text-experimenta-accent">✓</span>
<span>Exklusive Vorteile und Vergünstigungen für Jahreskarteninhaber</span>
</li>
<li class="flex items-start gap-2">
<span class="mt-1 text-experimenta-accent"></span>
<span>Flexible Nutzung komme so oft du möchtest</span>
</li>
</ul>
</div>
</div>
</div>
</NuxtLayout>
</template>