Undangan/proyek-frontend/app/components/landing-page/featuredtemplates.vue
2025-10-13 15:57:24 +07:00

221 lines
6.9 KiB
Vue

<script setup>
import { ref, computed } from 'vue'
// ID template yang mau ditampilkan
const selectedIds = [3, 5, 7]
// State dropdown
const openDropdownId = ref(null)
const toggleDropdown = (templateId) => {
openDropdownId.value = openDropdownId.value === templateId ? null : templateId
}
const paketData = [
// Paket Starter (Undangan Minimalis / Pernikahan Starter)
{
paket: 'starter',
fiturs: [
'1x Acara',
'Masa Aktif 3 Bulan',
'Nama Tamu Personal',
'Maks. 100 Tamu',
'Request Musik'
]
},
// Paket Premium Pernikahan
{
paket: 'premium',
fiturs: [
'Maksimal 3x Acara (Akad, Resepsi, Syukuran)',
'Unlimited Galeri Foto',
'Timeline Story',
'Google Maps',
'Reminder Google Calendar',
'Link Instagram Live Streaming',
'Amplop Digital',
'Placement Video Cinematic',
'Bonus Undangan Image Post Story',
'Masa Aktif 12 Bulan',
'Nama Tamu Personal Unlimited Tamu',
'Request Musik'
]
},
// Paket Premium Ulang Tahun
{
paket: 'premium',
fiturs: [
'1x Acara',
'Unlimited Galeri Foto',
'Timeline Story',
'Google Maps',
'Reminder Google Calendar',
'Amplop Digital',
'Placement Video Cinematic',
'Masa Aktif 12 Bulan',
'Nama Tamu Personal Unlimited Tamu',
'Request Musik'
]
},
// Paket Premium Khitan
{
paket: 'premium',
fiturs: [
'1x Acara',
'Unlimited Galeri Foto',
'Timeline Story',
'Google Maps',
'Reminder Google Calendar',
'Amplop Digital',
'Placement Video Cinematic',
'Masa Aktif 12 Bulan',
'Nama Tamu Personal Unlimited Tamu',
'Request Musik'
]
}
]
// 🔥 Mapping nama_template ke form path (cukup tambah di sini kalau ada form baru)
const formMapping = {
'Undangan Pernikahan Premium': '/form/pernikahan/b',
'Undangan Minimalis': '/form/pernikahan/a',
'Undangan Ulang Tahun Premium': '/form/ulang-tahun/a',
'Undangan Khitan Premium': '/form/khitan/a',
}
// Fetch data template dari backend (nama_template, harga, kategori, foto)
const { data: templatesData, error } = await useFetch('http://localhost:8000/api/templates')
// Mapping template: gabungkan backend + paket & fitur hardcode
const paketMapping = {
'Undangan Minimalis': 'starter',
'Undangan Pernikahan Premium': 'premium',
'Undangan Ulang Tahun Premium': 'premium',
'Undangan Khitan Premium': 'premium'
}
const templates = computed(() =>
(templatesData.value || [])
.filter(t => selectedIds.includes(t.id))
.map((t) => {
const paketKey = paketMapping[t.nama_template] || 'starter';
const paketInfo = paketData.find(p => p.paket.toLowerCase() === paketKey.toLowerCase()) || paketData[0];
return {
id: t.id,
nama_template: t.nama_template,
harga: t.harga,
foto: t.foto || '/default.jpg',
paket: paketInfo.paket,
fiturs: paketInfo.fiturs.map((f, i) => ({ id: i + 1, deskripsi: f })),
kategori: t.kategori,
formPath: t.slug
}
})
)
</script>
<template>
<section id="template" class="py-16 px-5 text-center">
<!-- Header -->
<div class="mb-10">
<h2 class="text-[2.9rem] font-bold mb-6">Templat Unggulan</h2>
<p class="text-gray-600 text-lg mb-10">
"Tersedia berbagai desain undangan pernikahan, khitan, ulang tahun, dan lainnya."
</p>
</div>
<!-- Grid Template -->
<div v-if="templates.length" class="grid gap-8 max-w-[1100px] mx-auto grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
<div v-for="t in templates" :key="t.id"
class="bg-white border rounded-lg overflow-hidden shadow-md hover:shadow-xl transition-shadow duration-300">
<!-- Gambar -->
<img :src="`http://localhost:8000${t.foto}`" :alt="t.nama_template" class="w-full h-48 object-cover" />
<!-- Body -->
<div class="p-5 text-center">
<h4 class="text-xl font-bold text-gray-800 mb-2">{{ t.nama_template }}</h4>
<p class="text-green-600 font-semibold text-xl mb-1">
Rp {{ Number(t.harga).toLocaleString('id-ID') }}
</p>
<p class="text-gray-500 mb-4 font-medium">Paket: {{ t.paket }}</p>
<!-- Dropdown fitur -->
<div v-if="t.fiturs && t.fiturs.length > 0" class="relative mb-4">
<button @click="toggleDropdown(t.id)"
class="w-full bg-white border border-gray-300 rounded-md shadow-sm px-4 py-2 inline-flex justify-between items-center">
<span class="mx-auto text-gray-700 font-semibold">FITUR YANG TERSEDIA</span>
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor">
<path fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd" />
</svg>
</button>
<transition name="fade">
<div v-if="openDropdownId === t.id" class="mt-4">
<ul
class="space-y-2 text-gray-600 text-left max-h-60 overflow-y-auto px-3 py-2 border border-gray-200 rounded-md shadow-inner bg-gray-50">
<li v-for="f in t.fiturs" :key="f.id" class="flex items-center">
<svg class="h-4 w-4 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
{{ f.deskripsi }}
</li>
</ul>
</div>
</transition>
</div>
<!-- Tombol -->
<div class="flex items-center gap-3 mt-6">
<button
@click="$router.push(`/preview/${t.id}`)"
class="w-full bg-white border border-gray-300 text-gray-800 font-semibold py-2 px-4 rounded-lg hover:bg-gray-100 transition-colors">
Preview
</button>
<NuxtLink :to="`form/${t.formPath}`"
class="w-full bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg hover:bg-blue-700 transition-colors text-center">
Order
</NuxtLink>
</div>
</div>
</div>
</div>
<!-- Jika error atau kosong -->
<div v-else class="text-gray-500">Tidak ada template yang bisa ditampilkan</div>
<!-- See more -->
<div class="mt-8 text-right max-w-[1100px] mx-auto">
<NuxtLink to="/template" class="text-blue-600 font-medium hover:underline">
Lihat Selengkapnya...
</NuxtLink>
</div>
</section>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(-5px);
}
.fade-enter-to,
.fade-leave-from {
opacity: 1;
transform: translateY(0);
}
</style>