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.
143 lines
4.7 KiB
143 lines
4.7 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 - only Makerspace and Educator passes
|
|
const { data: products, error, pending } = await useFetch<Product[]>('/api/products', {
|
|
query: {
|
|
category: 'makerspace-annual-pass,educator-annual-pass',
|
|
},
|
|
})
|
|
|
|
// 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">
|
|
Makerspace Jahreskarten
|
|
</h1>
|
|
<p class="mx-auto max-w-2xl text-lg text-white/80">
|
|
Dein Zugang zum Makerspace. Nutze modernste Werkzeuge, 3D-Drucker, Lasercutter und vieles mehr.
|
|
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>
|
|
|