fix: 1:1 prototype port – exact hms-* CSS, real logo, all components from app.js
This commit is contained in:
@@ -1,220 +1,103 @@
|
||||
<template>
|
||||
<div class="max-w-7xl mx-auto px-4 py-8">
|
||||
<!-- Breadcrumb -->
|
||||
<nav class="flex items-center gap-2 text-sm text-text-muted mb-6" aria-label="Breadcrumb">
|
||||
<NuxtLink to="/" class="hover:text-accent transition-colors duration-fast">Home</NuxtLink>
|
||||
<span class="text-secondary">/</span>
|
||||
<NuxtLink to="/mietkatalog" class="hover:text-accent transition-colors duration-fast">Mietkatalog</NuxtLink>
|
||||
<span class="text-secondary">/</span>
|
||||
<span class="text-text font-medium">{{ data?.name || 'Artikel' }}</span>
|
||||
</nav>
|
||||
|
||||
<!-- Loading State -->
|
||||
<div v-if="pending" class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
<div class="skeleton-shimmer w-full h-96 rounded-lg" />
|
||||
<div class="space-y-4">
|
||||
<div class="skeleton-shimmer h-8 w-3/4 rounded" />
|
||||
<div class="skeleton-shimmer h-6 w-1/2 rounded" />
|
||||
<div class="skeleton-shimmer h-4 w-full rounded" />
|
||||
<div class="skeleton-shimmer h-4 w-full rounded" />
|
||||
<div class="skeleton-shimmer h-4 w-2/3 rounded" />
|
||||
<div class="skeleton-shimmer h-32 w-full rounded-lg" />
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<nav class="text-sm mb-6" aria-label="Breadcrumb"><NuxtLink to="/mietkatalog" style="color: var(--secondary)">← Zurück zum Katalog</NuxtLink></nav>
|
||||
<div v-if="loading" class="grid lg:grid-cols-2 gap-8" aria-live="polite" aria-busy="true"><div class="hms-skeleton aspect-square rounded-lg"></div><div class="space-y-4"><div class="hms-skeleton h-8 w-3/4"></div><div class="hms-skeleton h-4 w-1/4"></div><div class="hms-skeleton h-24 w-full"></div><div class="hms-skeleton h-32 w-full"></div><div class="hms-skeleton h-12 w-full" style="border-radius:var(--radius-md)"></div></div></div>
|
||||
<ErrorState v-else-if="error" title="Gerät nicht gefunden" message="Das angeforderte Gerät konnte nicht gefunden werden." @retry="navigate('/mietkatalog')" />
|
||||
<div v-else-if="item">
|
||||
<div class="grid lg:grid-cols-2 gap-8 lg:gap-12">
|
||||
<div class="aspect-square rounded-lg flex items-center justify-center relative overflow-hidden border" :style="{ background: 'var(--surface)', borderColor: 'var(--border)' }">
|
||||
<img v-if="item.image" :src="item.image" :alt="item.name" class="absolute inset-0 w-full h-full object-cover" />
|
||||
<div v-else class="text-center"><div class="text-8xl mb-2" style="color: var(--secondary)">📦</div><div class="text-sm" style="color: var(--secondary)">Kein Bild verfügbar</div></div>
|
||||
<span class="hms-badge hms-badge-primary absolute top-4 left-4 text-sm">{{ item.category }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm mb-1" style="color: var(--secondary)">Artikelnummer: {{ item.code }}</div>
|
||||
<h1 class="text-2xl sm:text-3xl font-bold mb-2" style="color: var(--text)">{{ item.name }}</h1>
|
||||
<div class="text-sm mb-4" style="color: var(--text-muted)">Marke: <span class="font-medium" style="color: var(--text)">{{ item.brand }}</span></div>
|
||||
<p class="leading-relaxed mb-6" style="color: var(--text-muted)">{{ item.description }}</p>
|
||||
<div class="hms-card p-4 mb-6"><h2 class="text-sm font-semibold mb-3" style="color: var(--text)">Technische Daten</h2><dl class="divide-y" :style="{ borderColor: 'var(--border)' }"><div v-for="(value, key) in item.specs" :key="key" class="flex justify-between py-2 text-sm" :style="{ borderColor: 'var(--border)' }"><dt class="capitalize" style="color: var(--secondary)">{{ key.replace(/_/g, ' ') }}</dt><dd class="font-medium text-right" style="color: var(--text)">{{ value }}</dd></div></dl></div>
|
||||
<div class="hms-card p-6">
|
||||
<h2 class="text-sm font-semibold mb-4" style="color: var(--text)">Mietanfrage</h2>
|
||||
<div class="grid grid-cols-2 gap-3 mb-4"><div><label for="rental-start" class="block text-xs font-medium mb-1" style="color: var(--secondary)">Mietbeginn</label><input id="rental-start" v-model="rentalStart" type="date" class="hms-input text-sm" /></div><div><label for="rental-end" class="block text-xs font-medium mb-1" style="color: var(--secondary)">Mietende</label><input id="rental-end" v-model="rentalEnd" type="date" class="hms-input text-sm" /></div></div>
|
||||
<div class="mb-4"><label for="quantity" class="block text-xs font-medium mb-1" style="color: var(--secondary)">Anzahl</label><div class="flex items-center gap-3"><button @click="quantity = Math.max(1, quantity - 1)" class="hms-btn hms-btn-secondary px-3 py-2" aria-label="Anzahl verringern">−</button><input id="quantity" v-model.number="quantity" type="number" min="1" class="hms-input text-center w-20" aria-label="Anzahl" /><button @click="quantity = quantity + 1" class="hms-btn hms-btn-secondary px-3 py-2" aria-label="Anzahl erhöhen">+</button></div></div>
|
||||
<button @click="addToCart" class="hms-btn hms-btn-primary w-full py-3 text-base"><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"/></svg>Zur Mietanfrage hinzufügen</button>
|
||||
<p class="text-xs mt-3 text-center" style="color: var(--secondary)">Preise auf Anfrage – unverbindliche Mietanfrage</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section v-if="relatedItems.length" class="mt-16" aria-labelledby="related-title"><h2 id="related-title" class="text-xl font-semibold mb-6" style="color: var(--text)">Ähnliche Geräte</h2><div class="grid grid-cols-1 sm:grid-cols-3 gap-6"><EquipmentCard v-for="ri in relatedItems" :key="ri.id" :item="ri" @click="navigate('/mietkatalog/' + ri.id)" @add-to-cart="addToCartSimple" /></div></section>
|
||||
</div>
|
||||
|
||||
<!-- Error State (non-existent ID) -->
|
||||
<ErrorState
|
||||
v-else-if="error"
|
||||
title="Equipment nicht gefunden"
|
||||
message="Der angeforderte Artikel konnte nicht gefunden werden."
|
||||
retry-text="Zurück zum Mietkatalog"
|
||||
@retry="navigateTo('/mietkatalog')"
|
||||
/>
|
||||
|
||||
<!-- Detail Content -->
|
||||
<template v-else-if="data">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8" data-testid="equipment-detail">
|
||||
<!-- Image Section -->
|
||||
<div class="panel rounded-lg overflow-hidden">
|
||||
<div class="w-full h-96 bg-surface flex items-center justify-center">
|
||||
<img
|
||||
v-if="data.images && data.images.length > 0"
|
||||
:src="data.images[selectedImageIdx] || data.images[0]"
|
||||
:alt="data.name"
|
||||
class="w-full h-full object-cover"
|
||||
/>
|
||||
<svg v-else class="w-24 h-24 text-secondary" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909M3.75 3.75h16.5a1.5 1.5 0 011.5 1.5v12a1.5 1.5 0 01-1.5 1.5H3.75a1.5 1.5 0 01-1.5-1.5V5.25a1.5 1.5 0 011.5-1.5z" />
|
||||
</svg>
|
||||
</div>
|
||||
<!-- Thumbnail Gallery (if multiple images) -->
|
||||
<div v-if="data.images && data.images.length > 1" class="flex gap-2 p-3">
|
||||
<div
|
||||
v-for="(img, idx) in data.images"
|
||||
:key="idx"
|
||||
class="w-16 h-16 rounded-md overflow-hidden border-2 cursor-pointer"
|
||||
:class="selectedImageIdx === idx ? 'border-accent' : 'border-border-default'"
|
||||
@click="selectedImageIdx = idx"
|
||||
>
|
||||
<img :src="img" :alt="`${data.name} – Bild ${idx + 1}`" class="w-full h-full object-cover" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info Section -->
|
||||
<div class="flex flex-col">
|
||||
<!-- Category Badge -->
|
||||
<span
|
||||
v-if="data.category"
|
||||
class="self-start px-3 py-1 text-xs font-medium rounded-full bg-surface text-text-muted mb-3"
|
||||
>
|
||||
{{ data.category }}
|
||||
</span>
|
||||
|
||||
<h1 class="text-2xl font-bold text-text mb-2" data-testid="equipment-name">
|
||||
{{ data.name }}
|
||||
</h1>
|
||||
|
||||
<p v-if="data.brand" class="text-sm text-text-muted mb-4">
|
||||
Marke: <span class="text-text font-medium">{{ data.brand }}</span>
|
||||
</p>
|
||||
|
||||
<p class="text-text-muted mb-6" data-testid="equipment-description">
|
||||
{{ data.description || "Keine Beschreibung verfügbar" }}
|
||||
</p>
|
||||
|
||||
<!-- Specs Table -->
|
||||
<div class="panel rounded-lg p-4 mb-6" data-testid="equipment-specs">
|
||||
<h2 class="text-base font-bold text-text mb-3">Spezifikationen</h2>
|
||||
<table class="w-full text-sm">
|
||||
<tbody>
|
||||
<tr v-if="data.number">
|
||||
<td class="py-2 text-text-muted font-medium w-1/3">Artikelnummer</td>
|
||||
<td class="py-2 text-text">{{ data.number }}</td>
|
||||
</tr>
|
||||
<tr v-if="data.rentman_id">
|
||||
<td class="py-2 text-text-muted font-medium w-1/3">Rentman ID</td>
|
||||
<td class="py-2 text-text">{{ data.rentman_id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-2 text-text-muted font-medium w-1/3">Verfügbarkeit</td>
|
||||
<td class="py-2">
|
||||
<span :class="data.available ? 'text-success' : 'text-error'" class="font-medium">
|
||||
{{ data.available ? 'Verfügbar' : 'Nicht verfügbar' }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="(value, key) in data.specifications || {}"
|
||||
:key="String(key)"
|
||||
>
|
||||
<td class="py-2 text-text-muted font-medium w-1/3">{{ key }}</td>
|
||||
<td class="py-2 text-text">{{ value }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Price & Add to Cart -->
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div>
|
||||
<p class="text-sm text-text-muted">Mietpreis</p>
|
||||
<p class="text-2xl font-bold text-accent" data-testid="equipment-price">
|
||||
{{ data.rental_price != null ? formatPrice(data.rental_price) + ' €/Tag' : 'Preis auf Anfrage' }}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="btn-primary"
|
||||
data-testid="add-to-cart-detail"
|
||||
:disabled="!data.available"
|
||||
@click="onAddToCart"
|
||||
>
|
||||
Mietanfrage
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Related Items -->
|
||||
<section v-if="relatedItems.length > 0" class="mt-12">
|
||||
<h2 class="text-xl font-bold text-text mb-4">Ähnliche Artikel</h2>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<EquipmentCard
|
||||
v-for="item in relatedItems"
|
||||
:key="item.id"
|
||||
:equipment="item"
|
||||
@add-to-cart="onAddToCartRelated"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { EquipmentDetail, EquipmentItem, PaginatedEquipment } from "~/composables/useEquipment";
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useCart } from '~/composables/useCart'
|
||||
|
||||
const route = useRoute();
|
||||
const equipmentApi = useEquipment();
|
||||
const selectedImageIdx = ref(0);
|
||||
const route = useRoute()
|
||||
const { addItemByFields } = useCart()
|
||||
|
||||
const equipmentId = computed(() => route.params.id as string);
|
||||
const loading = ref(true)
|
||||
const error = ref(false)
|
||||
const quantity = ref(1)
|
||||
const rentalStart = ref('')
|
||||
const rentalEnd = ref('')
|
||||
const item = ref<any>(null)
|
||||
|
||||
// Fetch equipment detail (SSR)
|
||||
const { data, pending, error } = await useAsyncData<EquipmentDetail>(
|
||||
`equipment-detail-${equipmentId.value}`,
|
||||
() => equipmentApi.detail(equipmentId.value),
|
||||
);
|
||||
const equipmentData = [
|
||||
{ id: 1, code: 'LT-001', name: 'L-Acoustics K2', category: 'Tontechnik', description: 'Das L-Acoustics K2 ist das Flaggschiff der Line-Array-Serie und eignet sich für große Open-Air-Veranstaltungen und Hallenbeschallung.', brand: 'L-Acoustics', specs: { weight: '56 kg', power: '1440 W', freq_range: '35 Hz - 20 kHz', max_spl: '142 dB', coverage: '10°-110° variable' }, image: '', related: [2, 4, 3] },
|
||||
{ id: 2, code: 'LT-002', name: 'd&b audiotechnik KSL8', category: 'Tontechnik', description: 'Bi-amplified Column Array Loudspeaker mit 80° horizontaler Abstrahlung.', brand: 'd&b audiotechnik', specs: { weight: '32 kg', power: '1200 W', freq_range: '55 Hz - 18 kHz', max_spl: '138 dB', coverage: '80° horizontal' }, image: '', related: [1, 4, 18] },
|
||||
{ id: 3, code: 'LT-003', name: 'Shure SM58', category: 'Tontechnik', description: 'Das weltweit meistverkaufte dynamische Gesangsmikrofon.', brand: 'Shure', specs: { weight: '330 g', type: 'dynamisch', polar: 'Kardioid', freq_range: '50 Hz - 15 kHz', connector: 'XLR3' }, image: '', related: [4, 18, 1] },
|
||||
{ id: 4, code: 'LT-004', name: 'Allen & Heath dLive S5000', category: 'Tontechnik', description: 'Professionelles digitales Mischpult mit 96 Input Fadern und 64 Mix Buses.', brand: 'Allen & Heath', specs: { channels: '96', buses: '64', fx: '16 Effekt-Engines', screens: '2x 15" Touch', i_o: '128x128 Dante' }, image: '', related: [1, 2, 3] },
|
||||
{ id: 5, code: 'LL-001', name: 'Robe Pointe', category: 'Lichttechnik', description: '230W Moving Beam mit 5°-20° Zoom und 16-bit Dimming.', brand: 'Robe', specs: { power: '230 W', source: 'MSD 230', zoom: '5°-20°', dimming: '16-bit', pan: '540°', tilt: '270°' }, image: '', related: [6, 7, 8] },
|
||||
{ id: 6, code: 'LL-002', name: 'Mac Aura PXL', category: 'Lichttechnik', description: 'RGBW Wash-Light mit 18 einzelnen pixel-mappable Zellen.', brand: 'Martin', specs: { power: '700 W', cells: '18', zoom: '4°-60°', control: 'DMX 512, Art-Net', color: 'RGBW' }, image: '', related: [5, 7, 8] },
|
||||
{ id: 7, code: 'LL-003', name: 'Showtec Phantom 140', category: 'Lichttechnik', description: '140W LED Spot Moving Head mit 9 rotierenden und 9 festen Gobos.', brand: 'Showtec', specs: { power: '140 W', gobos: '9 rotierend + 9 fest', zoom: '12°-18°', color: '7+1 Farbrad', prism: '8-fach rotierend' }, image: '', related: [5, 6, 8] },
|
||||
{ id: 8, code: 'LL-004', name: 'Astera Titan Tube', category: 'Lichttechnik', description: 'Pixel Tube 1m Länge, batteriebetrieben mit 20 Std. Laufzeit.', brand: 'Astera', specs: { length: '1015 mm', battery: '20 Std', cells: '16 Pixel', control: 'DMX, CRMX, App', color: 'RGBW' }, image: '', related: [5, 6, 7] },
|
||||
{ id: 9, code: 'RG-001', name: 'Tomcat Truss 290', category: 'Rigging', description: 'Aluminium Traverse 4-Punkt, 290mm Profil, 2m Länge.', brand: 'Tomcat', specs: { profile: '290x290 mm', length: '2 m', load: '450 kg', material: 'Aluminium EN AW-6082' }, image: '', related: [10, 14, 15] },
|
||||
{ id: 10, code: 'RG-002', name: 'Chain Motor 1T', category: 'Rigging', description: 'Bühnen-Motor 1000kg Tragkraft, D8+ Plus geprüft.', brand: 'Verlinde', specs: { capacity: '1000 kg', speed: '4-8 m/min', control: 'Direct Control', certification: 'D8+ Plus' }, image: '', related: [9, 14, 13] },
|
||||
{ id: 11, code: 'VD-001', name: 'LED Video Wall P3.9', category: 'Video', description: 'Indoor LED Panel P3.9, 500x500mm, 3840Hz Refresh Rate.', brand: 'Absen', specs: { pixel_pitch: '3.9 mm', size: '500x500 mm', refresh: '3840 Hz', brightness: '1500 nits', ip: 'IP30 Indoor' }, image: '', related: [12, 5, 6] },
|
||||
{ id: 12, code: 'VD-002', name: 'Blackmagic ATEM Mini Extreme', category: 'Video', description: '8-Input HDMI Switcher mit ISO Recording und Multiview.', brand: 'Blackmagic', specs: { inputs: '8x HDMI', outputs: '2x HDMI', recording: 'ISO Recording', streaming: 'Direct Streaming', audio: '2x 3.5mm' }, image: '', related: [11, 5, 7] },
|
||||
{ id: 13, code: 'ST-001', name: 'WAGO 24V 40A Netzteilkasten', category: 'Strom', description: '24V DC 40A Netzteil in Flightcase mit 4x Schuko Ausgang.', brand: 'WAGO', specs: { output: '24V DC 40A', inputs: '4x Schuko', protection: 'IP54', cooling: 'Forced Air' }, image: '', related: [14, 10, 9] },
|
||||
{ id: 14, code: 'ST-002', name: 'Duraplex 32A Stromverteiler', category: 'Strom', description: '32A 5-polig auf 3x 16A + 3x Schuko mit FI-Schutzschalter.', brand: 'Duraplex', specs: { input: '32A 5-pol CEE', outputs: '3x 16A + 3x Schuko', protection: 'FI/A', cable: 'H07BQ-F 5G6' }, image: '', related: [13, 10, 9] },
|
||||
{ id: 15, code: 'ZB-001', name: 'Flightcase 19" 12HE', category: 'Zubehör', description: '19" Rack Flightcase 12HE mit Front- und Rücktür.', brand: 'Thon', specs: { rack_units: '12 HE', depth: '600 mm', wheels: '4x 100mm', material: 'Birkenholz + Alu-Kanten' }, image: '', related: [16, 4, 15] },
|
||||
{ id: 16, code: 'ZB-002', name: 'XLR Kabel 20m', category: 'Zubehör', description: 'XLR3 male/female Mikrofonkabel, 20m, Neutrik Stecker.', brand: 'Tasker', specs: { length: '20 m', connectors: 'XLR3 M/F', shielding: 'double', cable: 'Tasker C118' }, image: '', related: [3, 18, 4] },
|
||||
{ id: 17, code: 'ZB-003', name: 'DJ-Table Pro', category: 'Zubehör', description: 'Mobile DJ-Tisch mit Laptop-Ständer und LED-Beleuchtung.', brand: 'Stage Traps', specs: { width: '120 cm', height: '95 cm', features: 'LED, Laptop-Ständer', weight: '22 kg' }, image: '', related: [12, 5, 15] },
|
||||
{ id: 18, code: 'LT-005', name: 'Sennheiser EW-DX 835', category: 'Tontechnik', description: 'Digitales Funkmikrofon-Set mit Handheld und Empfänger.', brand: 'Sennheiser', specs: { type: 'Digital Wireless', range: '100 m', battery: '12 Std', freq_range: '563-608 MHz', channels: 'gleichzeitig 95' }, image: '', related: [3, 4, 16] }
|
||||
]
|
||||
|
||||
// Fetch related items (same category, excluding current item)
|
||||
const { data: relatedData } = await useAsyncData<PaginatedEquipment>(
|
||||
`equipment-related-${equipmentId.value}`,
|
||||
() => equipmentApi.list({
|
||||
category: data.value?.category || undefined,
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
}),
|
||||
{ watch: [data] }
|
||||
);
|
||||
const relatedItems = computed(() => {
|
||||
if (!item.value || !item.value.related) return []
|
||||
return item.value.related.map((id: number) => equipmentData.find(e => e.id === id)).filter(Boolean)
|
||||
})
|
||||
|
||||
const relatedItems = computed<EquipmentItem[]>(() => {
|
||||
if (!relatedData.value) return [];
|
||||
return relatedData.value.items.filter((item) => item.id !== Number(equipmentId.value)).slice(0, 4);
|
||||
});
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
const found = equipmentData.find(e => e.id === Number(route.params.id))
|
||||
if (found) { item.value = found } else { error.value = true }
|
||||
loading.value = false
|
||||
}, 800)
|
||||
})
|
||||
|
||||
function formatPrice(price: number | null): string {
|
||||
if (price == null) return "—";
|
||||
return new Intl.NumberFormat("de-DE", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
}).format(price);
|
||||
function navigate(route: string) {
|
||||
navigateTo(route)
|
||||
if (import.meta.client) window.scrollTo(0, 0)
|
||||
}
|
||||
|
||||
const { addItemByFields } = useCart();
|
||||
|
||||
function onAddToCart() {
|
||||
if (data.value) {
|
||||
addItemByFields({
|
||||
equipment_id: data.value.id,
|
||||
name: data.value.name,
|
||||
rental_price: data.value.rental_price,
|
||||
image_url: data.value.images && data.value.images.length > 0 ? data.value.images[0] : null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onAddToCartRelated(item: { id: number; name: string }) {
|
||||
const relatedItem = relatedItems.value.find((i) => i.id === item.id);
|
||||
function addToCart() {
|
||||
addItemByFields({
|
||||
equipment_id: item.id,
|
||||
name: item.name,
|
||||
rental_price: relatedItem?.rental_price ?? null,
|
||||
image_url: relatedItem?.image_url ?? null,
|
||||
});
|
||||
equipment_id: item.value.id,
|
||||
name: item.value.name,
|
||||
rental_price: null,
|
||||
image_url: item.value.image || null
|
||||
})
|
||||
navigate('/warenkorb')
|
||||
}
|
||||
function addToCartSimple(e: any) {
|
||||
addItemByFields({
|
||||
equipment_id: e.id,
|
||||
name: e.name,
|
||||
rental_price: null,
|
||||
image_url: e.image || null
|
||||
})
|
||||
}
|
||||
|
||||
useHead(() => ({
|
||||
title: data.value ? `${data.value.name} – Mietkatalog – HMS Licht & Ton` : "Artikel – Mietkatalog – HMS Licht & Ton",
|
||||
meta: [{ name: "robots", content: "noindex, nofollow, noarchive, nosnippet" }],
|
||||
}));
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user