update form

This commit is contained in:
Farhaan4 2025-09-18 16:16:25 +07:00
parent 3dbd356d2f
commit 961fb7724e
5 changed files with 335 additions and 203 deletions

View File

@ -21,7 +21,8 @@
<input :value="form.nama_template" type="text" placeholder="Nama Template" class="input-readonly" readonly />
<input :value="form.kategori" type="text" placeholder="Kategori" class="input-readonly" readonly />
<input :value="form.harga" type="text" placeholder="Harga" class="input-readonly" readonly />
<input :value="form.tanggal_pemesanan" type="text" placeholder="Tanggal Pemesanan" class="input-readonly" readonly />
<input :value="form.tanggal_pemesanan" type="text" placeholder="Tanggal Pemesanan" class="input-readonly"
readonly />
</div>
</section>
@ -44,7 +45,8 @@
<h2 class="text-lg font-bold text-gray-800 mb-4">Detail Khitan</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<input v-model="form.nama_lengkap_anak" type="text" placeholder="Nama Lengkap Anak" class="input" required />
<input v-model="form.nama_panggilan_anak" type="text" placeholder="Nama Panggilan Anak" class="input" required />
<input v-model="form.nama_panggilan_anak" type="text" placeholder="Nama Panggilan Anak" class="input"
required />
<input v-model="form.bapak_anak" type="text" placeholder="Nama Bapak" class="input" />
<input v-model="form.ibu_anak" type="text" placeholder="Nama Ibu" class="input" />
</div>
@ -79,33 +81,61 @@
<h2 class="text-lg font-bold text-gray-800 mb-4">Galeri (max 5 gambar)</h2>
<input type="file" multiple accept="image/*" @change="handleFileUpload" class="hidden" id="gallery-upload" />
<div class="grid grid-cols-2 md:grid-cols-3 gap-3">
<div v-for="(img, i) in previewImages" :key="i" class="relative w-full aspect-square rounded-lg overflow-hidden shadow-sm group">
<div v-for="(img, i) in previewImages" :key="i"
class="relative w-full aspect-square rounded-lg overflow-hidden shadow-sm group">
<img :src="img" alt="Preview" class="object-cover w-full h-full" />
<button
type="button"
@click="removeImage(i)"
<button type="button" @click="removeImage(i)"
class="absolute top-1 right-1 bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity font-bold"
aria-label="Hapus gambar"
>
aria-label="Hapus gambar">
&times;
</button>
</div>
<label v-if="previewImages.length < 5" for="gallery-upload" class="flex items-center justify-center w-full aspect-square bg-gray-50 border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:bg-gray-100 transition">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<label v-if="previewImages.length < 5" for="gallery-upload"
class="flex items-center justify-center w-full aspect-square bg-gray-50 border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:bg-gray-100 transition">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-gray-400" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
</svg>
</label>
</div>
</div>
</div>
</section>
</form>
<!-- Pilihan Fitur -->
<section v-for="kategori in kategoriFiturs" :key="kategori.id"
class="p-6 bg-white rounded-xl shadow-sm border border-gray-200 mb-6">
<h2 class="text-lg font-bold text-gray-800 mb-4">{{ kategori.nama }}</h2>
<!-- Radio -->
<div v-if="kategori.tipe === 'radio'" class="space-y-2">
<label v-for="fitur in kategori.fiturs" :key="fitur.id" class="flex items-center gap-2">
<input type="radio" :name="'fitur_' + kategori.id" :value="fitur.id"
v-model="form.selectedFiturs[kategori.id]" />
{{ fitur.deskripsi }}
</label>
</div>
<!-- Checkbox -->
<div v-else class="space-y-2">
<label v-for="fitur in kategori.fiturs" :key="fitur.id" class="flex items-center gap-2">
<input type="checkbox" :value="fitur.id" v-model="form.selectedFiturs[kategori.id]" />
{{ fitur.deskripsi }}
</label>
</div>
</section>
<!-- Submit -->
<div class="mt-10 text-center">
<button @click="submitForm" class="bg-blue-600 text-white px-10 py-3 rounded-xl font-semibold shadow-md hover:bg-blue-700 hover:shadow-lg transition" :disabled="loading">
<button @click="submitForm"
class="bg-blue-600 text-white px-10 py-3 rounded-xl font-semibold shadow-md hover:bg-blue-700 hover:shadow-lg transition"
:disabled="loading">
{{ loading ? "Mengirim..." : "Kirim & Konfirmasi Admin" }}
</button>
</div>
@ -151,6 +181,8 @@ const form = ref({
no_rekening2: "",
link_musik: "",
galeri: [],
selectedFiturs: {}, // { kategori_id: [fitur_id] }
});
const previewImages = ref([]);
@ -167,13 +199,16 @@ onMounted(async () => {
form.value.kategori_id = template.kategori_id;
form.value.kategori = template.kategori?.nama || "-";
form.value.harga = template.harga;
form.value.fiturs = template.fiturs.map(f => f.deskripsi);
// simpan kategori fitur
kategoriFiturs.value = template.kategori_fiturs || [];
} catch (err) {
console.error("Gagal ambil template", err);
}
}
});
// FUNGSI UNTUK MENAMBAH GAMBAR
const handleFileUpload = (event) => {
const newFiles = Array.from(event.target.files);
@ -212,11 +247,19 @@ const submitForm = async () => {
for (const key in form.value) {
if (key === "galeri") {
form.value.galeri.forEach((file) => body.append("galeri[]", file));
} else {
} else if (key !== "selectedFiturs") {
body.append(key, form.value[key]);
}
}
// kirim fitur sebagai array fitur_id
for (const kategoriId in form.value.selectedFiturs) {
const fiturs = Array.isArray(form.value.selectedFiturs[kategoriId])
? form.value.selectedFiturs[kategoriId]
: [form.value.selectedFiturs[kategoriId]];
fiturs.forEach(fiturId => body.append("fiturs[]", fiturId));
}
await $fetch("http://localhost:8000/api/form/khitan", {
method: "POST",
body,
@ -224,45 +267,18 @@ const submitForm = async () => {
success.value = true;
// WA notif (biar tetap jalan)
const adminNumber = "62895602603247";
// Susun pesan otomatis
const message = `
Halo Admin, ada pemesanan undangan khitan baru 🎉
📌 Data Pemesan:
Nama Pemesan: ${form.value.nama_pemesan}
No WA: ${form.value.no_hp}
Email: ${form.value.email}
👦 Data Anak:
Nama Lengkap: ${form.value.nama_lengkap_anak}
Nama Panggilan: ${form.value.nama_panggilan_anak}
Ayah: ${form.value.bapak_anak || "-"}
Ibu: ${form.value.ibu_anak || "-"}
📅 Jadwal Acara:
Tanggal: ${form.value.hari_tanggal_acara}
Waktu: ${form.value.waktu_acara}
Alamat: ${form.value.alamat_acara}
Google Maps: ${form.value.maps_acara || "-"}
💳 Informasi Tambahan:
Rekening 1: ${form.value.no_rekening1 || "-"}
Rekening 2: ${form.value.no_rekening2 || "-"}
Musik: ${form.value.link_musik || "-"}
🎨 Template & Order:
Template: ${form.value.nama_template} (${form.value.kategori})
Harga: ${form.value.harga}
Tanggal Pemesanan: ${form.value.tanggal_pemesanan}
`;
// Redirect ke WhatsApp
const waUrl = `https://wa.me/${adminNumber}?text=${encodeURIComponent(message)}`;
window.location.href = waUrl;
`;
window.location.href = `https://wa.me/${adminNumber}?text=${encodeURIComponent(message)}`;
} catch (err) {
console.error(err);
error.value = true;
@ -271,4 +287,3 @@ Tanggal Pemesanan: ${form.value.tanggal_pemesanan}
}
};
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="max-w-5xl mx-auto p-8 bg-gradient-to-b from-pink-50 to-red-50 shadow-lg rounded-xl">
<div class="max-w-5xl mx-auto p-8 bg-gradient-to-b from-pink-50 to-red-50 shadow-lg rounded-xl">
<!-- Judul Form -->
<div class="text-center mb-10">
<h1 class="text-3xl md:text-4xl font-extrabold text-red-700 drop-shadow-sm">
@ -21,7 +21,8 @@
<input :value="form.nama_template" type="text" placeholder="Nama Template" class="input-readonly" readonly />
<input :value="form.kategori" type="text" placeholder="Kategori" class="input-readonly" readonly />
<input :value="form.harga" type="text" placeholder="Harga" class="input-readonly" readonly />
<input :value="form.tanggal_pemesanan" type="text" placeholder="Tanggal Pemesanan" class="input-readonly" readonly />
<input :value="form.tanggal_pemesanan" type="text" placeholder="Tanggal Pemesanan" class="input-readonly"
readonly />
</div>
</section>
@ -66,13 +67,9 @@
<!-- Cerita Kita -->
<section class="p-6 bg-white rounded-xl shadow-sm border border-gray-200">
<h2 class="text-lg font-bold text-gray-800 mb-10">Cerita Kita</h2>
<textarea
v-model="form.cerita_kita"
placeholder="Tuliskan cerita indah kalian di sini..."
rows="1"
<textarea v-model="form.cerita_kita" placeholder="Tuliskan cerita indah kalian di sini..." rows="1"
class="w-full border border-gray-300 rounded-md px-3 py-3 focus:ring-2 focus:ring-blue-500 focus:outline-none transition resize-none"
@input="e => { e.target.style.height = 'auto'; e.target.style.height = e.target.scrollHeight + 'px' }"
/>
@input="e => { e.target.style.height = 'auto'; e.target.style.height = e.target.scrollHeight + 'px' }" />
</section>
@ -112,37 +109,67 @@
<h2 class="text-lg font-bold text-gray-800 mb-4">Galeri (max 5 gambar)</h2>
<input type="file" multiple accept="image/*" @change="handleFileUpload" class="hidden" id="gallery-upload" />
<div class="grid grid-cols-2 md:grid-cols-3 gap-3">
<div v-for="(img, i) in previewImages" :key="i" class="relative w-full aspect-square rounded-lg overflow-hidden shadow-sm group">
<div v-for="(img, i) in previewImages" :key="i"
class="relative w-full aspect-square rounded-lg overflow-hidden shadow-sm group">
<img :src="img" alt="Preview" class="object-cover w-full h-full" />
<button
type="button"
@click="removeImage(i)"
<button type="button" @click="removeImage(i)"
class="absolute top-1 right-1 bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity font-bold"
aria-label="Hapus gambar"
>
aria-label="Hapus gambar">
&times;
</button>
</div>
<label v-if="previewImages.length < 5" for="gallery-upload" class="flex items-center justify-center w-full aspect-square bg-gray-50 border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:bg-gray-100 transition">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<label v-if="previewImages.length < 5" for="gallery-upload"
class="flex items-center justify-center w-full aspect-square bg-gray-50 border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:bg-gray-100 transition">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-gray-400" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
</svg>
</label>
</label>
</div>
</div>
</section>
</form>
<!-- Kategori & Fitur -->
<section v-for="kategori in kategoriFiturs" :key="kategori.id"
class="p-6 bg-white rounded-xl shadow-sm border border-gray-200">
<h2 class="text-lg font-bold text-gray-800 mb-4">
{{ kategori.nama }}
</h2>
<!-- Radio -->
<div v-if="kategori.tipe === 'radio'">
<label v-for="fitur in kategori.fiturs" :key="fitur.id" class="flex items-center gap-2 mb-2">
<input type="radio" :name="'kategori_' + kategori.id" :value="fitur.id"
v-model="form.selectedFiturs[kategori.id]" />
{{ fitur.deskripsi }}
</label>
</div>
<!-- Checkbox -->
<div v-else>
<label v-for="fitur in kategori.fiturs" :key="fitur.id" class="flex items-center gap-2 mb-2">
<input type="checkbox" :value="fitur.id" v-model="form.selectedFiturs[kategori.id]" />
{{ fitur.deskripsi }}
</label>
</div>
</section>
<!-- Submit -->
<div class="mt-10 text-center">
<button @click="submitForm" class="bg-blue-600 text-white px-10 py-3 rounded-xl font-semibold shadow-md hover:bg-blue-700 hover:shadow-lg transition" :disabled="loading">
<button @click="submitForm"
class="bg-blue-600 text-white px-10 py-3 rounded-xl font-semibold shadow-md hover:bg-blue-700 hover:shadow-lg transition"
:disabled="loading">
{{ loading ? "Mengirim..." : "Kirim & Konfirmasi Admin" }}
</button>
</div>
<!-- Alert -->
<div v-if="success" class="mt-6 p-4 text-green-800 bg-green-100 rounded-lg text-center font-medium"> Form berhasil dikirim! Silakan tunggu konfirmasi dari admin.</div>
<div v-if="error" class="mt-6 p-4 text-red-800 bg-red-100 rounded-lg text-center font-medium"> Gagal mengirim form. Pastikan semua data yang wajib diisi sudah lengkap.</div>
<div v-if="success" class="mt-6 p-4 text-green-800 bg-green-100 rounded-lg text-center font-medium"> Form berhasil
dikirim! Silakan tunggu konfirmasi dari admin.</div>
<div v-if="error" class="mt-6 p-4 text-red-800 bg-red-100 rounded-lg text-center font-medium"> Gagal mengirim form.
Pastikan semua data yang wajib diisi sudah lengkap.</div>
</div>
</template>
@ -152,13 +179,16 @@ import { useRoute } from "vue-router";
const route = useRoute();
// 1. STRUKTUR DATA DISESUAIKAN DENGAN BACKEND
const form = ref({
template_id: "",
nama_template: "",
kategori: "",
harga: "",
tanggal_pemesanan: new Date().toLocaleDateString('id-ID', { year: 'numeric', month: 'long', day: 'numeric' }),
tanggal_pemesanan: new Date().toLocaleDateString("id-ID", {
year: "numeric",
month: "long",
day: "numeric",
}),
nama_pemesan: "",
no_hp: "",
@ -196,8 +226,12 @@ const form = ref({
no_rekening2: "",
link_musik: "",
galeri: [],
selectedFiturs: {}, // { kategori_id: [fitur_id] }
});
const kategoriFiturs = ref([]); // 🆕 simpan kategori fitur
const previewImages = ref([]);
const loading = ref(false);
const success = ref(false);
@ -206,11 +240,20 @@ const error = ref(false);
onMounted(async () => {
if (route.query.template_id) {
try {
const template = await $fetch(`http://localhost:8000/api/templates/${route.query.template_id}`);
const template = await $fetch(
`http://localhost:8000/api/templates/${route.query.template_id}`
);
form.value.template_id = template.id;
form.value.nama_template = template.nama_template;
form.value.kategori = template.kategori?.nama || "-";
form.value.harga = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR' }).format(template.harga);
form.value.harga = new Intl.NumberFormat("id-ID", {
style: "currency",
currency: "IDR",
}).format(template.harga);
// 🆕 simpan kategori fitur
kategoriFiturs.value = template.kategori_fiturs || [];
} catch (err) {
console.error("Gagal ambil template", err);
}
@ -222,12 +265,10 @@ const handleFileUpload = (event) => {
const newFiles = Array.from(event.target.files);
const combinedFiles = [...form.value.galeri, ...newFiles];
// Batasi total file menjadi 5
form.value.galeri = combinedFiles.slice(0, 5);
// Buat ulang array preview berdasarkan data file yang sudah final
previewImages.value = [];
form.value.galeri.forEach(file => {
form.value.galeri.forEach((file) => {
const reader = new FileReader();
reader.onload = (e) => {
previewImages.value.push(e.target.result);
@ -235,11 +276,10 @@ const handleFileUpload = (event) => {
reader.readAsDataURL(file);
});
// Reset input agar bisa memilih file yang sama lagi
event.target.value = null;
};
// FUNGSI UNTUK MENGHAPUS GAMBAR (SEKARANG DI LUAR)
// FUNGSI UNTUK MENGHAPUS GAMBAR
const removeImage = (index) => {
form.value.galeri.splice(index, 1);
previewImages.value.splice(index, 1);
@ -252,15 +292,27 @@ const submitForm = async () => {
try {
const body = new FormData();
// field umum
for (const key in form.value) {
if (key === "galeri") {
form.value.galeri.forEach((file) => body.append("galeri[]", file));
} else if (form.value[key] !== null && form.value[key] !== undefined) {
if (key === "galeri" || key === "selectedFiturs") continue;
if (form.value[key] !== null && form.value[key] !== undefined) {
body.append(key, form.value[key]);
}
}
// 2. ENDPOINT API SUDAH BENAR
// galeri
form.value.galeri.forEach((file) => body.append("galeri[]", file));
// 🆕 fiturs
for (const kategoriId in form.value.selectedFiturs) {
const fiturs = Array.isArray(form.value.selectedFiturs[kategoriId])
? form.value.selectedFiturs[kategoriId]
: [form.value.selectedFiturs[kategoriId]];
fiturs.forEach((fiturId) => body.append("fiturs[]", fiturId));
}
await $fetch("http://localhost:8000/api/form/pernikahan", {
method: "POST",
body,
@ -268,10 +320,7 @@ const submitForm = async () => {
success.value = true;
const adminNumber = "62895602603247";
// Susun pesan otomatis
const message = `
Halo Admin, ada pemesanan undangan pernikahan baru 🎉
@ -293,13 +342,9 @@ Harga: ${form.value.harga}
Tanggal Pemesanan: ${form.value.tanggal_pemesanan}
`;
// Redirect ke WhatsApp
const waUrl = `https://wa.me/${adminNumber}?text=${encodeURIComponent(message)}`;
window.location.href = waUrl;
// Optional: Reset form after success
// Object.keys(form.value).forEach(key => form.value[key] = '');
window.location.href = `https://wa.me/${adminNumber}?text=${encodeURIComponent(
message
)}`;
} catch (err) {
console.error(err);
error.value = true;

View File

@ -8,7 +8,7 @@
<div class="footer-column">
<h4>Layanan</h4>
<ul class="footer-links">
<li><a href="#">Template Undangan Pernikahan</a></li>
<li><a href="/template/Pernikahan">Template Undangan Pernikahan</a></li>
<li><a href="#">Template Undangan Khitan</a></li>
<li><a href="#">Template Undangan Ulang Tahun</a></li>
</ul>
@ -19,19 +19,42 @@
<ul class="footer-contact-list">
<li>
<a href="#" class="social-link">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v2.385z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v2.385z" />
</svg>
<span>ABBAUF TECH</span>
</a>
</li>
<li>
<a href="#" class="social-link">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.85s-.011 3.584-.069 4.85c-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07s-3.584-.012-4.85-.07c-3.252-.148-4.771-1.691-4.919-4.919-.058-1.265-.069-1.645-.069-4.85s.011-3.584.069-4.85c.149-3.225 1.664-4.771 4.919-4.919 1.266-.057 1.644-.069 4.85-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948s.014 3.667.072 4.947c.2 4.359 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072s3.667-.014 4.947-.072c4.359-.2 6.78-2.618 6.98-6.98.058-1.281.072-1.689.072-4.948s-.014-3.667-.072-4.947c-.2-4.359-2.618-6.78-6.98-6.98-1.281-.058-1.689-.072-4.948-.072zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.162 6.162 6.162 6.162-2.759 6.162-6.162-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4s1.791-4 4-4 4 1.79 4 4-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.441 1.441 1.441 1.441-.645 1.441-1.441-.645-1.44-1.441-1.44z"/></svg>
<span>@abbauf_tech</span>
<a href="https://instagram.com/abbauftech" target="_blank" class="inline-flex items-center gap-2 font-medium
bg-gradient-to-r from-purple-500 via-pink-500 to-orange-500
bg-clip-text text-transparent
hover:scale-110 transition-all duration-300">
<!-- Ikon Instagram -->
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"
fill="url(#igGradient)">
<defs>
<linearGradient id="igGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#8a3ab9" />
<stop offset="50%" style="stop-color:#e95950" />
<stop offset="100%" style="stop-color:#fccc63" />
</linearGradient>
</defs>
<path d="M7.75 2h8.5A5.75 5.75 0 0 1 22 7.75v8.5A5.75 5.75 0 0 1 16.25 22h-8.5A5.75 5.75 0 0 1 2 16.25v-8.5A5.75 5.75 0 0 1 7.75 2zm0 1.5A4.25 4.25 0 0 0 3.5 7.75v8.5A4.25 4.25 0 0 0 7.75 20.5h8.5a4.25 4.25 0 0 0 4.25-4.25v-8.5A4.25 4.25 0 0 0 16.25 3.5h-8.5zm4.25 3a5.75 5.75 0 1 1 0 11.5 5.75 5.75 0 0 1 0-11.5zm0 1.5a4.25 4.25 0 1 0 0 8.5 4.25 4.25 0 0 0 0-8.5zm5-2.25a1 1 0 1 1 0 2 1 1 0 0 1 0-2z" />
</svg>
<!-- Nama IG -->
<span>@abbauftech</span>
</a>
</li>
<li>
<a href="#" class="social-link">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M4.98 3.5c0 1.381-1.11 2.5-2.48 2.5s-2.48-1.119-2.48-2.5c0-1.38 1.11-2.5 2.48-2.5s2.48 1.12 2.48 2.5zm.02 4.5h-5v16h5v-16zm7.982 0h-4.968v16h4.969v-8.399c0-4.67 6.029-5.052 6.029 0v8.399h4.988v-10.131c0-7.88-8.922-7.593-11.018-3.714v-2.155z"/></svg>
<a href="https://www.linkedin.com/posts/abbauf-tech_abbauftech-digitalstrategy-itconsulting-activity-7277021563982340099-8Byg" class="social-link">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M4.98 3.5c0 1.381-1.11 2.5-2.48 2.5s-2.48-1.119-2.48-2.5c0-1.38 1.11-2.5 2.48-2.5s2.48 1.12 2.48 2.5zm.02 4.5h-5v16h5v-16zm7.982 0h-4.968v16h4.969v-8.399c0-4.67 6.029-5.052 6.029 0v8.399h4.988v-10.131c0-7.88-8.922-7.593-11.018-3.714v-2.155z" />
</svg>
<span>ABBAUF TECH</span>
</a>
</li>
@ -42,26 +65,41 @@
<h4>Kontak Kami</h4>
<ul class="footer-contact-list">
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M0 3v18h24v-18h-24zm21.518 2l-9.518 7.713-9.518-7.713h19.036zm-19.518 14v-11.817l10 8.104 10-8.104v11.817h-20z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M0 3v18h24v-18h-24zm21.518 2l-9.518 7.713-9.518-7.713h19.036zm-19.518 14v-11.817l10 8.104 10-8.104v11.817h-20z" />
</svg>
<a href="mailto:contact@abbauf.com">contact@abbauf.com</a>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M20 22.621l-3.521-6.795c-.008.004-1.974.97-2.064 1.011-2.24 1.086-6.799-3.473-5.712-5.713.041-.09 1.011-2.064 1.011-2.064l-6.795-3.521-2.918 2.918c-1.603 1.603-1.425 4.933 1.011 7.37 4.301 4.301 9.962 3.593 12.301.954l2.688-2.355-2.356-2.688z"/></svg>
<a href="tel:02127617679">(021) 2761-7679</a>
<a :href="waUrl" target="_blank"
class="inline-flex items-center gap-2 hover:text-green-600 transition-colors">
<!-- Ikon WhatsApp -->
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M.057 24l1.687-6.163c-1.041-1.804-1.588-3.849-1.587-5.946.003-6.556 5.338-11.891 11.893-11.891 3.181.001 6.167 1.24 8.413 3.488 2.245 2.248 3.481 5.236 3.48 8.414-.003 6.557-5.338 11.892-11.894 11.892-1.99-.001-3.951-.5-5.688-1.448l-6.305 1.654zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884-.001 2.225.651 3.891 1.746 5.634l-.999 3.648 3.742-.981zm11.387-5.464c-.074-.124-.272-.198 -.57-.347-.297-.149-1.758-.868-2.031-.967-.272-.099-.47-.149-.669.149-.198.297-.768.967-.941 1.165-.173.198-.347.223-.644.074-.297-.14-1.255-.462-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.521.151-.172.2-.296.3-.495.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579 -.487-.5-.669-.51-.173-.008-.371-.01-.57-.01s-.52.074-.792.372 c-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.626.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.695.248-1.29 .173-1.414z" />
</svg>
<!-- Nomor WA -->
<span>+62 878-7711-7847</span>
</a>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M.057 24l1.687-6.163c-1.041-1.804-1.588-3.849-1.587-5.946.003-6.556 5.338-11.891 11.893-11.891 3.181.001 6.167 1.24 8.413 3.488 2.245 2.248 3.481 5.236 3.48 8.414-.003 6.557-5.338 11.892-11.894 11.892-1.99-.001-3.951-.5-5.688-1.448l-6.305 1.654zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884-.001 2.225.651 3.891 1.746 5.634l-.999 3.648 3.742-.981zm11.387-5.464c-.074-.124-.272-.198-.57-.347-.297-.149-1.758-.868-2.031-.967-.272-.099-.47-.149-.669.149-.198.297-.768.967-.941 1.165-.173.198-.347.223-.644.074-.297-.149-1.255-.462-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.297-.347.446-.521.151-.172.2-.296.3-.495.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01s-.52.074-.792.372c-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.626.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.695.248-1.29.173-1.414z"/></svg>
<a href="#">+62 878-7711-7847</a>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-4.198 0-8 3.403-8 7.602 0 4.198 3.469 9.21 8 16.398 4.531-7.188 8-12.2 8-16.398 0-4.199-3.801-7.602-8-7.602zm0 11c-1.657 0-3-1.343-3-3s1.343-3 3-3 3 1.343 3 3-1.343 3-3 3z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 0c-4.198 0-8 3.403-8 7.602 0 4.198 3.469 9.21 8 16.398 4.531-7.188 8-12.2 8-16.398 0-4.199-3.801-7.602-8-7.602zm0 11c-1.657 0-3-1.343-3-3s1.343-3 3-3 3 1.343 3 3-1.343 3-3 3z" />
</svg>
<div>
<strong>Alamat Kantor Pusat</strong>
<p>APL Tower Central Park Lantai 19 Unit T7, Jalan Letjen S. Parman, Kavling 28, RT. 012/006, Kel. Tanjung Duren, Kec. Grogol Petamburan, Jakarta Barat, DKI Jakarta 11470, ID</p>
<p>APL Tower Central Park Lantai 19 Unit T7, Jalan Letjen S. Parman, Kavling 28, RT. 012/006, Kel. Tanjung
Duren, Kec. Grogol Petamburan, Jakarta Barat, DKI Jakarta 11470, ID</p>
</div>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-4.198 0-8 3.403-8 7.602 0 4.198 3.469 9.21 8 16.398 4.531-7.188 8-12.2 8-16.398 0-4.199-3.801-7.602-8-7.602zm0 11c-1.657 0-3-1.343-3-3s1.343-3 3-3 3 1.343 3 3-1.343 3-3 3z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 0c-4.198 0-8 3.403-8 7.602 0 4.198 3.469 9.21 8 16.398 4.531-7.188 8-12.2 8-16.398 0-4.199-3.801-7.602-8-7.602zm0 11c-1.657 0-3-1.343-3-3s1.343-3 3-3 3 1.343 3 3-1.343 3-3 3z" />
</svg>
<div>
<strong>Alamat Studio</strong>
<p>Jl. Adhi Karya No. 57 RT 003 RW 015, Kel. Depok, Kec. Pancoran Mas, Depok 16431</p>
@ -78,7 +116,11 @@
</template>
<script setup>
// Tidak ada script yang dibutuhkan untuk footer statis ini
const adminNumber = "62895602603247";
const defaultMessage = "Halo Admin, saya mau tanya tentang undangan digital 🙏";
const waUrl = `https://wa.me/${adminNumber}?text=${encodeURIComponent(defaultMessage)}`;
</script>
<style scoped>
@ -98,7 +140,8 @@
.footer-content {
display: grid;
grid-template-columns: 2fr 1.5fr 1.5fr 2.5fr; /* Mengatur lebar kolom */
grid-template-columns: 2fr 1.5fr 1.5fr 2.5fr;
/* Mengatur lebar kolom */
gap: 40px;
padding-bottom: 30px;
border-bottom: 1px solid #d9dce1;
@ -116,7 +159,8 @@
color: #111;
}
.footer-links, .footer-contact-list {
.footer-links,
.footer-contact-list {
list-style: none;
padding: 0;
margin: 0;
@ -126,14 +170,17 @@
margin-bottom: 12px;
}
.footer-links a, .social-link {
.footer-links a,
.social-link {
text-decoration: none;
color: #555;
transition: color 0.3s ease;
}
.footer-links a:hover, .social-link:hover {
color: #0d6efd; /* Biru Primer */
.footer-links a:hover,
.social-link:hover {
color: #0d6efd;
/* Biru Primer */
}
.footer-contact-list li {
@ -153,6 +200,7 @@
text-decoration: none;
color: #555;
}
.footer-contact-list a:hover {
text-decoration: underline;
}
@ -185,21 +233,27 @@
/* Penyesuaian untuk layar kecil (Mobile) */
@media (max-width: 992px) {
.footer-content {
grid-template-columns: 1fr 1fr; /* 2 kolom di tablet */
grid-template-columns: 1fr 1fr;
/* 2 kolom di tablet */
}
}
@media (max-width: 768px) {
.footer-content {
grid-template-columns: 1fr; /* 1 kolom di mobile */
grid-template-columns: 1fr;
/* 1 kolom di mobile */
text-align: center;
}
.footer-brand {
margin-bottom: 20px;
}
.footer-logo {
margin: 0 auto; /* Logo di tengah */
margin: 0 auto;
/* Logo di tengah */
}
.footer-contact-list li {
align-items: center;
text-align: left;

View File

@ -1,8 +1,13 @@
<template>
<div>
<div class="flex items-center mb-8">
<button @click="$emit('back')" class="text-blue-600 hover:text-blue-800 font-semibold inline-flex items-center mr-4">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" /></svg>
<button @click="$emit('back')"
class="text-blue-600 hover:text-blue-800 font-semibold inline-flex items-center mr-4">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
clip-rule="evenodd" />
</svg>
Kembali
</button>
<h1 class="text-3xl md:text-4xl font-bold text-gray-800">
@ -10,12 +15,18 @@
</h1>
</div>
<div v-if="isLoading" class="text-center py-10"><p>Memuat template...</p></div>
<div v-else-if="error" class="text-center py-10 text-red-600"><p>Gagal memuat template.</p></div>
<div v-if="isLoading" class="text-center py-10">
<p>Memuat template...</p>
</div>
<div v-else-if="error" class="text-center py-10 text-red-600">
<p>Gagal memuat template.</p>
</div>
<div v-else-if="templates && templates.length > 0" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 items-start">
<div v-else-if="templates && templates.length > 0"
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 items-start">
<div v-for="tpl in templates" :key="tpl.id" class="bg-white border rounded-lg overflow-hidden shadow-md hover:shadow-xl transition-shadow duration-300">
<div v-for="tpl in templates" :key="tpl.id"
class="bg-white border rounded-lg overflow-hidden shadow-md hover:shadow-xl transition-shadow duration-300">
<img :src="`http://localhost:8000${tpl.foto}`" :alt="tpl.nama" class="w-full h-48 object-cover">
<div class="p-5 text-center">
@ -25,15 +36,23 @@
</p>
<div v-if="tpl.fitur && tpl.fitur.length > 0" class="relative mb-4">
<button @click="toggleDropdown(tpl.id)" class="w-full bg-white border border-gray-300 rounded-md shadow-sm px-4 py-2 inline-flex justify-between items-center text-center">
<button @click="toggleDropdown(tpl.id)"
class="w-full bg-white border border-gray-300 rounded-md shadow-sm px-4 py-2 inline-flex justify-between items-center text-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>
<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>
<div v-if="openDropdownId === tpl.id">
<ul class="mt-4 space-y-2 text-gray-600 text-left">
<li v-for="item_fitur in tpl.fitur" :key="item_fitur.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"></path></svg>
<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"></path>
</svg>
{{ item_fitur.deskripsi }}
</li>
@ -44,23 +63,22 @@
<div class="mt-6">
<div class="flex items-center gap-3">
<!-- Tombol Preview (masih sama) -->
<button
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"
>
<a :href="tpl.id === 1 ? 'https://www.figma.com/proto/T3EQf6Ip0dZIBZMvaKiefE/Mockup-Ivitation?node-id=272-1270&t=bbfeDM0cefEB4xRt-0&scaling=scale-down&content-scaling=fixed&page-id=272%3A228&starting-point-node-id=285%3A273&show-proto-sidebar=1' :
'https://www.figma.com/proto/T3EQf6Ip0dZIBZMvaKiefE/Mockup-Ivitation?node-id=285-273&t=bbfeDM0cefEB4xRt-0&scaling=scale-down&content-scaling=fixed&page-id=272%3A228&starting-point-node-id=285%3A273&show-proto-sidebar=1'"
target="_blank"
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 text-center block">
Preview
</button>
</a>
<!-- Tombol Order langsung ke form Khitan -->
<NuxtLink
:to="`/form/${tpl.kategori.nama.toLowerCase().replace(/ /g, '-')}` + `?template_id=${tpl.id}`"
class="w-full bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg hover:bg-blue-700 transition-colors text-center"
>
<NuxtLink :to="`/form/${tpl.kategori.nama.toLowerCase().replace(/ /g, '-')}` + `?template_id=${tpl.id}`"
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>
</NuxtLink>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-else class="text-center py-10 text-gray-500">