From 5f7c976cb413c44bb5aba9549efa72f8b0655484 Mon Sep 17 00:00:00 2001 From: Baghaztra Date: Thu, 9 Oct 2025 14:17:57 +0700 Subject: [PATCH] [feat] Link undangan frontend --- .../Api/PelangganApiController.php | 3 +- .../database/factories/PelangganFactory.php | 116 +++++++++ .../database/seeders/PelangganSeeder.php | 92 ++++---- .../undangan/undangan-minimalis.vue | 222 ++++++++++++++---- proyek-frontend/app/pages/p/[code].vue | 103 ++++++-- 5 files changed, 424 insertions(+), 112 deletions(-) create mode 100644 backend-baru/database/factories/PelangganFactory.php diff --git a/backend-baru/app/Http/Controllers/Api/PelangganApiController.php b/backend-baru/app/Http/Controllers/Api/PelangganApiController.php index 4534f13..537f1cf 100644 --- a/backend-baru/app/Http/Controllers/Api/PelangganApiController.php +++ b/backend-baru/app/Http/Controllers/Api/PelangganApiController.php @@ -82,12 +82,13 @@ class PelangganApiController extends Controller { $pelanggan = Pelanggan::with('template') ->where('invitation_code', $code) + ->where('status', 'diterima') ->first(); if (!$pelanggan) { return response()->json([ 'success' => false, - 'message' => 'Data pelanggan dengan kode undangan tidak ditemukan.', + 'message' => 'Data undangan tidak ditemukan.', ], 404); } diff --git a/backend-baru/database/factories/PelangganFactory.php b/backend-baru/database/factories/PelangganFactory.php new file mode 100644 index 0000000..f1d8341 --- /dev/null +++ b/backend-baru/database/factories/PelangganFactory.php @@ -0,0 +1,116 @@ + + */ +class PelangganFactory extends Factory +{ + protected $model = Pelanggan::class; + + public function definition(): array + { + // Get a random template + $template = Template::inRandomOrder()->first() ?? Template::factory()->create(); + + // Generate form data based on template's form fields + $formData = $this->generateFormData($template->form['fields'] ?? []); + + // Generate unique invitation code + $invitationCode = 'INV-' . strtoupper(Str::random(6)); + while (Pelanggan::where('invitation_code', $invitationCode)->exists()) { + $invitationCode = 'INV-' . strtoupper(Str::random(6)); + } + + return [ + 'nama_pemesan' => $this->faker->name(), + 'email' => $this->faker->unique()->safeEmail(), + 'no_tlpn' => $this->faker->phoneNumber(), + 'template_id' => $template->id, + 'form' => $formData, + 'harga' => $template->harga, + 'status' => $this->faker->randomElement(['menunggu', 'diterima', 'ditolak']), + 'invitation_code' => $invitationCode, + ]; + } + + /** + * Generate form data based on template fields + * + * @param array $fields + * @return array + */ + private function generateFormData(array $fields): array + { + $formData = []; + + foreach ($fields as $field) { + $name = $field['name']; + $type = $field['type'] ?? 'text'; + + switch ($type) { + case 'text': + $formData[$name] = $this->generateTextField($name); + break; + case 'email': + $formData[$name] = $this->faker->safeEmail(); + break; + case 'date': + $formData[$name] = $this->faker->date('Y-m-d', 'now +1 month'); + break; + case 'number': + $formData[$name] = $this->faker->numberBetween(1, 100); + break; + case 'textarea': + $formData[$name] = $this->faker->paragraph(); + break; + case 'file': + $formData[$name] = 'files/' . $this->faker->uuid() . '.jpg'; + break; + default: + $formData[$name] = $this->faker->word(); + } + } + + return $formData; + } + + /** + * Generate text field data based on field name + * + * @param string $name + * @return string + */ + private function generateTextField(string $name): string + { + if (str_contains($name, 'nama_')) { + return $this->faker->name(); + } + if (str_contains($name, 'alamat')) { + return $this->faker->address(); + } + if (str_contains($name, 'link_gmaps')) { + return 'https://maps.google.com/?q=' . $this->faker->latitude() . ',' . $this->faker->longitude(); + } + if (str_contains($name, 'instagram') || str_contains($name, 'facebook') || str_contains($name, 'twitter')) { + return 'https://' . str_replace('_', '.', $name) . '/' . $this->faker->userName(); + } + if (str_contains($name, 'waktu')) { + return $this->faker->time('H:i'); + } + if (str_contains($name, 'rekening')) { + return $this->faker->bankAccountNumber(); + } + if (str_contains($name, 'link_music')) { + return 'https://music.example.com/' . $this->faker->uuid(); + } + + return $this->faker->word(); + } +} \ No newline at end of file diff --git a/backend-baru/database/seeders/PelangganSeeder.php b/backend-baru/database/seeders/PelangganSeeder.php index 5d0cf07..0a64516 100644 --- a/backend-baru/database/seeders/PelangganSeeder.php +++ b/backend-baru/database/seeders/PelangganSeeder.php @@ -10,52 +10,52 @@ class PelangganSeeder extends Seeder { public function run(): void { - // contoh beberapa pelanggan - $pelanggans = [ - [ - 'nama_pemesan' => 'Arief Dwi Wicaksono', - 'email' => 'arief@example.com', - 'no_tlpn' => '081234567890', - 'template_id' => 1, // pastikan ada template_id valid - 'form' => json_encode([ - 'nama_pria' => 'Arief', - 'nama_wanita' => 'Nisa', - 'alamat' => 'Malang', - ]), - 'harga' => 150000, - 'status' => 'menunggu', - ], - [ - 'nama_pemesan' => 'Rizky Ramadhan', - 'email' => 'rizky@example.com', - 'no_tlpn' => '081298765432', - 'template_id' => 2, - 'form' => json_encode([ - 'nama_pria' => 'Rizky', - 'nama_wanita' => 'Dinda', - 'alamat' => 'Surabaya', - ]), - 'harga' => 250000, - 'status' => 'diterima', - ], - [ - 'nama_pemesan' => 'Siti Rahmawati', - 'email' => 'siti@example.com', - 'no_tlpn' => '081212341234', - 'template_id' => 3, - 'form' => json_encode([ - 'nama_pria' => 'Andi', - 'nama_wanita' => 'Siti', - 'alamat' => 'Jakarta', - ]), - 'harga' => 300000, - 'status' => 'menunggu', - ], - ]; + Pelanggan::factory()->count(100)->create(); + // $pelanggans = [ + // [ + // 'nama_pemesan' => 'Arief Dwi Wicaksono', + // 'email' => 'arief@example.com', + // 'no_tlpn' => '081234567890', + // 'template_id' => 1, // pastikan ada template_id valid + // 'form' => json_encode([ + // 'nama_pria' => 'Arief', + // 'nama_wanita' => 'Nisa', + // 'alamat' => 'Malang', + // ]), + // 'harga' => 150000, + // 'status' => 'menunggu', + // ], + // [ + // 'nama_pemesan' => 'Rizky Ramadhan', + // 'email' => 'rizky@example.com', + // 'no_tlpn' => '081298765432', + // 'template_id' => 2, + // 'form' => json_encode([ + // 'nama_pria' => 'Rizky', + // 'nama_wanita' => 'Dinda', + // 'alamat' => 'Surabaya', + // ]), + // 'harga' => 250000, + // 'status' => 'diterima', + // ], + // [ + // 'nama_pemesan' => 'Siti Rahmawati', + // 'email' => 'siti@example.com', + // 'no_tlpn' => '081212341234', + // 'template_id' => 3, + // 'form' => json_encode([ + // 'nama_pria' => 'Andi', + // 'nama_wanita' => 'Siti', + // 'alamat' => 'Jakarta', + // ]), + // 'harga' => 300000, + // 'status' => 'menunggu', + // ], + // ]; - foreach ($pelanggans as $data) { - $data['invitation_code'] = 'INV-' . strtoupper(Str::random(6)); // 🟢 generate code unik - Pelanggan::create($data); - } + // foreach ($pelanggans as $data) { + // $data['invitation_code'] = 'INV-' . strtoupper(Str::random(6)); // 🟢 generate code unik + // Pelanggan::create($data); + // } } } diff --git a/proyek-frontend/app/components/undangan/undangan-minimalis.vue b/proyek-frontend/app/components/undangan/undangan-minimalis.vue index 2bd6674..8aba5e2 100644 --- a/proyek-frontend/app/components/undangan/undangan-minimalis.vue +++ b/proyek-frontend/app/components/undangan/undangan-minimalis.vue @@ -1,36 +1,110 @@ @@ -43,27 +117,93 @@ const props = defineProps({ data: { type: Object, required: true, - validator: (data) => 'template' in data && 'slug' in data.template, + validator: (data) => { + return data && typeof data === 'object' && 'template' in data + }, }, }) const config = useRuntimeConfig() const backendUrl = config.public.apiBaseUrl +const formData = computed(() => props.data.form || {}) + const imageUrl = computed(() => { - return props.data.template.foto - ? `${backendUrl}/storage/${props.data.template.foto}` - : 'https://via.placeholder.com/400x600' + const foto = props.data.template?.foto + return foto + ? `${backendUrl}/storage/${foto}` + : 'https://images.unsplash.com/photo-1519741497674-611481863552?w=800&h=600&fit=crop' }) const formatDate = (dateString) => { if (!dateString) return null - const date = new Date(dateString) - return date.toLocaleDateString('id-ID', { - weekday: 'long', - year: 'numeric', - month: 'long', - day: 'numeric', - }) + try { + const date = new Date(dateString) + if (isNaN(date.getTime())) return null + + return date.toLocaleDateString('id-ID', { + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric', + }) + } catch (error) { + console.error('Error formatting date:', error) + return null + } } + + diff --git a/proyek-frontend/app/pages/p/[code].vue b/proyek-frontend/app/pages/p/[code].vue index 06c3e86..2a93276 100644 --- a/proyek-frontend/app/pages/p/[code].vue +++ b/proyek-frontend/app/pages/p/[code].vue @@ -1,19 +1,32 @@