Server : Apache/2.4.18 (Ubuntu) System : Linux canvaswebdesign 3.13.0-71-generic #114-Ubuntu SMP Tue Dec 1 02:34:22 UTC 2015 x86_64 User : oppastar ( 1041) PHP Version : 7.0.33-0ubuntu0.16.04.15 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority, Directory : /var/www/laciasmara.com/public_html/shop/application/views/admin_new/customers/ |
Upload File : |
<main class="flex-1 py-4 px-4 bg-purple-50"> <?php if ($this->session->flashdata('message')): ?> <div class="alert flex items-center justify-between bg-<?php echo $this->session->flashdata('message_type') === 'success' ? 'green' : 'red'; ?>-100 border-l-4 border-<?php echo $this->session->flashdata('message_type') === 'success' ? 'green' : 'red'; ?>-500 text-<?php echo $this->session->flashdata('message_type') === 'success' ? 'green' : 'red'; ?>-800 px-6 py-4 rounded-lg shadow-lg transition transform duration-300"> <div class="flex items-center"> <i data-feather="<?php echo $this->session->flashdata('message_type') === 'success' ? 'check-circle' : 'x-circle'; ?>" class="h-6 w-6 mr-3"></i> <span class="font-semibold"><?php echo $this->session->flashdata('message'); ?></span> </div> <button class="ml-4 text-<?php echo $this->session->flashdata('message_type') === 'success' ? 'green' : 'red'; ?>-500 hover:text-<?php echo $this->session->flashdata('message_type') === 'success' ? 'green' : 'red'; ?>-700 focus:outline-none" onclick="this.parentElement.style.display='none'"> <i data-feather="x" class="h-5 w-5"></i> </button> </div> <script> feather.replace(); </script> <?php endif; ?> <form action="<?= base_url('admin/customers/update_customer/' . $customer->id_customers) ?>" method="POST" class="mx-auto space-y-4" id="customerForm"> <input type="hidden" name="<?= $this->security->get_csrf_token_name() ?>" value="<?= $this->security->get_csrf_hash() ?>" class="csrf_token"> <!-- Header --> <div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6"> <div class="flex items-center justify-between"> <div> <h1 class="text-2xl font-bold text-gray-900">Edit Data Pelanggan</h1> <p class="text-gray-600 mt-1">Perbarui informasi pelanggan dengan teliti</p> </div> <div class="flex items-center space-x-2"> <div class="w-3 h-3 bg-green-400 rounded-full"></div> <span class="text-sm text-gray-600">Data Aktif</span> </div> </div> </div> <!-- Personal Information Section --> <div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden"> <div class="bg-gradient-to-r from-blue-50 to-indigo-50 px-6 py-4 border-b border-gray-200"> <div class="flex items-center space-x-3"> <div class="w-8 h-8 bg-blue-500 rounded-lg flex items-center justify-center"> <svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path> </svg> </div> <h2 class="text-lg font-semibold text-gray-900">Informasi Personal</h2> </div> </div> <div class="p-6 space-y-6"> <!-- Name and Email Row --> <div class="grid md:grid-cols-2 gap-6"> <!-- Customer Name --> <div class="space-y-2"> <label for="customer_name" class="flex items-center text-sm font-medium text-gray-700"> Nama Lengkap <span class="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800"> Wajib </span> </label> <input id="customer_name" type="text" name="customer_name" value="<?= $customer->name ?>" placeholder="Masukkan nama lengkap pelanggan" autocomplete="off" required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-1 focus:ring-purple-500 focus:border-purple-500 transition-colors text-gray-900 placeholder-gray-500" /> <p class="text-xs text-gray-500">Pastikan nama diisi dengan benar dan lengkap</p> </div> <!-- Customer Email --> <div class="space-y-2"> <label for="customer_email" class="flex items-center text-sm font-medium text-gray-700"> Alamat Email <span class="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800"> Wajib </span> </label> <input id="customer_email" type="email" name="customer_email" value="<?= $customer->email ?>" placeholder="contoh@email.com" autocomplete="off" required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-1 focus:ring-purple-500 focus:border-purple-500 transition-colors text-gray-900 placeholder-gray-500" /> <p class="text-xs text-gray-500">Email akan digunakan untuk notifikasi dan komunikasi</p> </div> </div> <!-- Phone and Birthdate Row --> <div class="grid md:grid-cols-2 gap-6"> <!-- Customer Phone --> <div class="space-y-2"> <label for="customer_phone" class="flex items-center text-sm font-medium text-gray-700"> Nomor Telepon <span class="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800"> Wajib </span> </label> <div class="relative"> <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> <span class="text-gray-500 text-sm">+62</span> </div> <input id="customer_phone" type="tel" name="customer_phone" value="<?= $customer->shipping_phone ?>" placeholder="812345678901" autocomplete="off" pattern="[8][0-9]{9,11}" required class="w-full pl-12 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-1 focus:ring-purple-500 focus:border-purple-500 transition-colors text-gray-900 placeholder-gray-500" /> </div> <p class="text-xs text-gray-500">Format: 8xxxxxxxxxx (dimulai dari 8, tanpa 0)</p> </div> <!-- Customer Birthdate --> <div class="space-y-2"> <label for="customer_birthdate" class="flex items-center text-sm font-medium text-gray-700"> Tanggal Lahir <span class="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800"> Wajib </span> </label> <div class="relative"> <input id="customer_birthdate" type="date" name="customer_birthdate" value="<?= $customer->birthday ?>" autocomplete="off" required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-1 focus:ring-purple-500 focus:border-purple-500 transition-colors text-gray-900" /> <div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none"> <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path> </svg> </div> </div> <p class="text-xs text-gray-500">Masukkan tanggal lahir yang valid</p> </div> </div> <!-- Gender and Password Row --> <div class="grid md:grid-cols-2 gap-6"> <!-- Customer Gender --> <div class="space-y-2"> <label for="customer_gender" class="flex items-center text-sm font-medium text-gray-700"> Jenis Kelamin <span class="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800"> Wajib </span> </label> <div class="relative"> <select id="customer_gender" name="customer_gender" required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-1 focus:ring-purple-500 focus:border-purple-500 transition-colors text-gray-900 appearance-none bg-white"> <option value="" disabled>Pilih jenis kelamin</option> <option value="male" <?= $customer->sex_type == 'male' ? 'selected' : '' ?>>👨 Laki-laki</option> <option value="female" <?= $customer->sex_type == 'female' ? 'selected' : '' ?>>👩 Perempuan</option> <option value="others" <?= $customer->sex_type == 'others' ? 'selected' : '' ?>>🥸 Lainnya</option> </select> <div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none"> <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path> </svg> </div> </div> <p class="text-xs text-gray-500">Informasi ini membantu personalisasi layanan</p> </div> <!-- Customer Password --> <div class="space-y-2"> <label for="customer_password" class="flex items-center text-sm font-medium text-gray-700"> Kata Sandi Baru <span class="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-600"> Opsional </span> </label> <div class="relative"> <input id="customer_password" type="password" name="customer_password" placeholder="Kosongkan jika tidak ingin mengubah" autocomplete="new-password" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-1 focus:ring-purple-500 focus:border-purple-500 transition-colors text-gray-900 placeholder-gray-500" /> <button type="button" class="absolute inset-y-0 right-0 pr-3 flex items-center" onclick="togglePassword()"> <svg id="eye-icon" class="w-5 h-5 text-gray-400 hover:text-gray-600 cursor-pointer" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path> </svg> </button> </div> <p class="text-xs text-gray-500">Minimal 8 karakter untuk keamanan yang baik</p> </div> </div> <input type="hidden" id="id_customers" value="<?= $customer->id_customers ?>"> </div> </div> <!-- Shipping Information Section --> <div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden"> <div class="bg-gradient-to-r from-green-50 to-emerald-50 px-6 py-4 border-b border-gray-200"> <div class="flex items-center justify-between"> <div class="flex items-center space-x-3"> <div class="w-8 h-8 bg-green-500 rounded-lg flex items-center justify-center"> <svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path> </svg> </div> <div> <h2 class="text-lg font-semibold text-gray-900">Alamat Pengiriman</h2> <p class="text-sm text-gray-600"> <?= count($customer_addresses) ?> alamat tersimpan </p> </div> </div> <button type="button" class="inline-flex items-center px-3 py-2 text-sm font-medium text-green-700 bg-green-100 rounded-lg hover:bg-green-200 transition-colors" onclick="openAddressModal()"> <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> Tambah Alamat </button> </div> </div> <div class="p-6"> <?php if (empty($customer_addresses)): ?> <div class="text-center py-12"> <svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path> </svg> <h3 class="text-lg font-medium text-gray-900 mb-2">Belum ada alamat tersimpan</h3> <p class="text-gray-500 mb-4">Tambahkan alamat pengiriman untuk pelanggan ini</p> <button type="button" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-green-600 rounded-lg hover:bg-green-700 transition-colors" onclick="openAddressModal()"> <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path> </svg> Tambah Alamat Pertama </button> </div> <?php else: ?> <div class="space-y-4"> <?php foreach ($customer_addresses as $index => $address): ?> <div class="relative border border-gray-200 rounded-lg p-4 hover:border-gray-300 transition-colors <?= $address->is_default ? 'ring-2 ring-green-500 border-green-500 bg-green-50' : 'bg-gray-50' ?>"> <!-- Default Badge --> <?php if ($address->is_default): ?> <div class="absolute -top-2 -right-2"> <span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-600 text-white"> <svg class="w-3 h-3 mr-1" 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> Utama </span> </div> <?php endif; ?> <div class="flex items-start justify-between"> <!-- Address Content --> <div class="flex-1 min-w-0"> <!-- Header --> <div class="flex items-center space-x-3 mb-3"> <div class="flex items-center space-x-2"> <!-- Label Icon --> <div class="w-6 h-6 bg-blue-100 rounded-full flex items-center justify-center"> <?php $label = strtolower($address->label); switch ($label) { case 'rumah': case 'home': $icon = '🏠'; break; case 'kantor': case 'office': $icon = '🏢'; break; case 'apartment': case 'apartemen': $icon = '🏬'; break; case 'kos': case 'kost': $icon = '🏘️'; break; default: $icon = '📍'; break; } echo $icon; ?> </div> <h3 class="text-sm font-semibold text-gray-900"><?= htmlspecialchars($address->label) ?></h3> </div> <!-- Location --> <div class="flex items-center text-xs text-gray-500"> <svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path> </svg> <?= htmlspecialchars($address->city) ?> </div> </div> <!-- Recipient Info --> <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-3"> <div class="flex items-center space-x-2"> <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path> </svg> <span class="text-sm font-medium text-gray-700"><?= htmlspecialchars($address->recipient_name) ?></span> </div> <div class="flex items-center space-x-2"> <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"></path> </svg> <span class="text-sm text-gray-600"><?= htmlspecialchars($address->phone) ?></span> </div> </div> <!-- Full Address --> <div class="mb-2"> <p class="text-sm text-gray-700 leading-relaxed"> <?= htmlspecialchars($address->address) ?> </p> </div> <!-- Notes --> <?php if (!empty($address->notes)): ?> <div class="flex items-center space-x-2 mb-3"> <svg class="w-4 h-4 text-amber-500 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"></path> </svg> <span class="text-sm text-amber-700 bg-amber-50 px-2 py-1 rounded"> Catatan: <?= htmlspecialchars($address->notes) ?> </span> </div> <?php endif; ?> <!-- Location Details --> <div class="flex flex-wrap gap-2 text-xs"> <span class="inline-flex items-center px-2 py-1 bg-gray-100 text-gray-600 rounded"> <?= htmlspecialchars($address->province) ?> </span> <span class="inline-flex items-center px-2 py-1 bg-gray-100 text-gray-600 rounded"> <?= htmlspecialchars($address->district) ?> </span> <span class="inline-flex items-center px-2 py-1 bg-gray-100 text-gray-600 rounded"> <?= htmlspecialchars($address->subdistrict) ?> </span> <span class="inline-flex items-center px-2 py-1 bg-blue-100 text-blue-700 rounded font-medium"> <?= htmlspecialchars($address->postal_code) ?> </span> </div> </div> <!-- Action Buttons --> <div class="flex flex-col space-y-2 ml-4"> <div class="flex items-center space-x-1"> <!-- Edit Button --> <button type="button" class="p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-colors" title="Edit alamat" onclick="openAddressModal(<?= $address->id ?>)"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path> </svg> </button> <!-- Set Default Button --> <?php if (!$address->is_default): ?> <button type="button" class="p-2 text-gray-400 hover:text-green-600 hover:bg-green-50 rounded-lg transition-colors" title="Jadikan alamat utama" onclick="setDefaultAddress(<?= $address->id ?>)"> <svg class="w-4 h-4" 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> </button> <?php endif; ?> <!-- Delete Button --> <button type="button" class="p-2 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors" title="Hapus alamat" onclick="deleteAddress(<?= $address->id ?>)"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path> </svg> </button> </div> <!-- Map View Button --> <?php if (!empty($address->latitude) && !empty($address->longitude)): ?> <button type="button" class="text-xs text-blue-600 hover:text-blue-800 hover:bg-blue-50 px-2 py-1 rounded transition-colors" onclick="viewOnMap(<?= $address->latitude ?>, <?= $address->longitude ?>, '<?= htmlspecialchars($address->label, ENT_QUOTES) ?>')"> <svg class="w-3 h-3 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7"></path> </svg> Lihat di Peta </button> <?php endif; ?> </div> </div> </div> <?php endforeach; ?> </div> <!-- Summary Info --> <div class="mt-6 p-4 bg-blue-50 rounded-lg border border-blue-200"> <div class="flex items-start space-x-3"> <svg class="w-5 h-5 text-blue-600 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path> </svg> <div> <h4 class="text-sm font-medium text-blue-900">Informasi Alamat</h4> <p class="text-sm text-blue-700 mt-1"> Pelanggan memiliki <strong><?= count($customer_addresses) ?> alamat</strong> tersimpan. Alamat yang ditandai "Utama" akan digunakan sebagai default untuk pengiriman. </p> </div> </div> </div> <?php endif; ?> </div> </div> <!-- Referral Code Section --> <div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden"> <div class="bg-gradient-to-r from-orange-50 to-purple-50 px-6 py-4 border-b border-gray-200"> <div class="flex items-center space-x-3"> <div class="w-8 h-8 bg-purple-500 rounded-lg flex items-center justify-center"> <svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v13m0-13V6a2 2 0 112 2h-2zm0 0V5.5A2.5 2.5 0 109.5 8H12zm-7 4h14M5 12a2 2 0 110-4h14a2 2 0 110 4M5 12v7a2 2 0 002 2h10a2 2 0 002-2v-7"></path> </svg> </div> <h2 class="text-lg font-semibold text-gray-900">Kode Referral</h2> </div> </div> <div class="p-6"> <!-- Referral Code --> <div class="space-y-2"> <label for="customer_ref" class="flex items-center text-sm font-medium text-gray-700"> Kode Referral <span class="ml-2 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-600"> Opsional </span> </label> <input id="customer_ref" type="text" name="customer_ref" value="<?= $customer->refferal ?>" placeholder="Masukkan kode referral (contoh: WELCOME2024)" autocomplete="off" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-1 focus:ring-purple-500 focus:border-purple-500 transition-colors text-gray-900 placeholder-gray-500 uppercase" /> <p class="text-xs text-gray-500">Kode referral memberikan benefit khusus untuk pelanggan</p> </div> </div> </div> <input type="hidden" id="customer_id" name="customer_id" value="<?= $customer->id_customers ?>"> <!-- Action Buttons --> <div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6"> <div class="flex flex-col sm:flex-row justify-end gap-4"> <button type="button" class="w-full sm:w-auto px-6 py-3 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 hover:border-gray-400 transition-all duration-200 font-medium" onclick="window.location.href='<?= base_url('admin/customers/manage') ?>'"> <svg class="w-4 h-4 inline mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> Batal </button> <button type="submit" class="w-full sm:w-auto px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-all duration-200 font-medium shadow-sm hover:shadow-md"> <svg class="w-4 h-4 inline 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> Simpan Perubahan </button> </div> </div> </form> <!-- Address Modal --> <style> .modal-overlay { border: 0; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px); opacity: 0; visibility: hidden; } .modal-overlay.active { opacity: 1; visibility: visible; } .modal-container { max-height: 90vh; overflow-y: auto; } .progress-line { position: relative; height: 2px; background: #e5e7eb; border-radius: 1px; } .progress-fill { height: 100%; background: linear-gradient(90deg, #3b82f6, #1d4ed8); border-radius: 1px; transition: width 0.3s ease; } .step-circle { width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 14px; transition: all 0.3s ease; position: relative; z-index: 99; } .step-circle.active { background: #7A4397; color: white; box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.2); } .step-circle.inactive { background: #e5e7eb; color: #6b7280; } .step-circle.completed { background: #10b981; color: white; } #map { height: 350px; border-radius: 12px; border: 2px solid #e5e7eb; } .search-container { position: relative; } .search-input { padding-left: 48px; padding-right: 48px; } .floating-button { position: absolute; bottom: 16px; right: 16px; background: white; border: 2px solid #e5e7eb; border-radius: 12px; padding: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); cursor: pointer; transition: all 0.2s ease; } .floating-button:hover { background: #f3f4f6; transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2); } .step-content { display: none; } .step-content.active { display: block; border: 0; } .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } @media (max-width: 640px) { .form-row { grid-template-columns: 1fr; } } .checkbox-wrapper { display: flex; align-items: center; gap: 8px; padding: 12px; border: 1px solid #e5e7eb; border-radius: 8px; cursor: pointer; transition: all 0.2s ease; } .checkbox-wrapper:hover { background: #f9fafb; border-color: #3b82f6; } .checkbox-wrapper.checked { background: #eff6ff; border-color: #3b82f6; } </style> <div class="modal-overlay fixed inset-0 z-[99] flex items-center justify-center p-4" id="addressModal"> <div class="modal-container bg-white rounded-2xl shadow-2xl w-full max-w-4xl"> <!-- Modal Header --> <div class="flex items-center justify-between p-6 border-b border-gray-200"> <div> <h2 class="text-2xl font-bold text-gray-900" id="modalTitle">Tambah Alamat Baru</h2> <p class="text-gray-600 mt-1" id="modalSubtitle">Tambahkan alamat pengiriman untuk pelanggan</p> </div> <button class="p-2 hover:bg-gray-100 rounded-lg transition-colors" onclick="closeModal()"> <i class="fas fa-times text-gray-500 text-xl"></i> </button> </div> <!-- Progress Bar --> <div class="px-6 py-4 border-b border-gray-100"> <div class="flex items-center justify-between mb-4"> <div class="flex items-center space-x-4"> <div class="step-circle active" id="step1"> <i class="fas fa-map-marker-alt"></i> </div> <div> <div class="text-sm font-semibold text-gray-900" id="stepLabel1">Pilih Lokasi</div> <div class="text-xs text-gray-500">Cari dan tentukan lokasi di peta</div> </div> </div> <div class="flex-1 mx-8"> <div class="progress-line"> <div class="progress-fill" id="progressFill" style="width: 50%"></div> </div> </div> <div class="flex items-center space-x-4"> <div class="step-circle inactive" id="step2"> <i class="fas fa-edit"></i> </div> <div> <div class="text-sm font-medium text-gray-500" id="stepLabel2">Detail Alamat</div> <div class="text-xs text-gray-400">Lengkapi informasi alamat</div> </div> </div> </div> </div> <!-- Modal Content --> <div class="p-6"> <!-- Step 1: Location Selection --> <div class="step-content active" id="content1"> <div class="grid lg:grid-cols-2 gap-6"> <!-- Search Panel --> <div class="space-y-4"> <div> <h3 class="text-lg font-semibold text-gray-900 mb-3">Cari Lokasi</h3> <!-- Search Input --> <div class="search-container"> <div class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none z-10"> <i class="fas fa-search text-gray-400"></i> </div> <input type="text" id="addressSearch" placeholder="Masukkan nama jalan, gedung, atau area..." class="search-input w-full py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors text-gray-900"> <button class="absolute inset-y-0 right-0 pr-4 flex items-center" onclick="clearSearch()" id="clearBtn" style="display: none;"> <i class="fas fa-times text-gray-400 hover:text-gray-600"></i> </button> </div> </div> <!-- Current Location Button --> <button class="w-full flex items-center justify-center space-x-3 py-3 px-4 border border-blue-300 text-blue-700 rounded-lg hover:bg-blue-50 transition-colors" onclick="getCurrentLocation()"> <i class="fas fa-location-crosshairs"></i> <span>Gunakan Lokasi Saat Ini</span> </button> <!-- Location Info Panel --> <div class="bg-gray-50 rounded-lg p-4" id="locationInfo" style="display: none;"> <h4 class="font-medium text-gray-900 mb-2">Lokasi Terpilih:</h4> <div class="space-y-2 text-sm text-gray-600"> <div class="flex items-center space-x-2"> <i class="fas fa-map-marker-alt text-red-500"></i> <span id="selectedAddress">-</span> </div> <div class="flex items-center space-x-2"> <i class="fas fa-globe text-blue-500"></i> <span id="coordinates">-</span> </div> </div> </div> <!-- Instructions --> <div class="bg-blue-50 border border-blue-200 rounded-lg p-4"> <div class="flex items-start space-x-3"> <i class="fas fa-info-circle text-blue-600 mt-0.5"></i> <div class="text-sm text-blue-800"> <p class="font-medium mb-1">Cara menggunakan:</p> <ul class="space-y-1 text-blue-700"> <li>• Ketik alamat di kotak pencarian</li> <li>• Atau klik "Gunakan Lokasi Saat Ini"</li> <li>• Drag pin di peta untuk menyesuaikan lokasi</li> <li>• Klik di peta untuk memindahkan pin</li> </ul> </div> </div> </div> </div> <!-- Map Panel --> <div class="space-y-4"> <div> <h3 class="text-lg font-semibold text-gray-900 mb-3">Peta Lokasi</h3> <div class="relative"> <div id="map"></div> <!-- Floating Controls --> <div class="floating-button" onclick="centerMap()" title="Kembali ke lokasi"> <i class="fas fa-crosshairs text-gray-600"></i> </div> </div> </div> <!-- Map Status --> <div class="text-center"> <div class="inline-flex items-center space-x-2 px-3 py-2 bg-gray-100 rounded-full text-sm text-gray-600"> <div class="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div> <span>Drag pin untuk memilih lokasi yang tepat</span> </div> </div> </div> </div> </div> <!-- Step 2: Address Details --> <div class="step-content" id="content2"> <div class="max-w-2xl mx-auto"> <h3 class="text-xl font-semibold text-gray-900 mb-6">Lengkapi Detail Alamat</h3> <form id="addressForm" class="space-y-6"> <!-- Address Label --> <div> <label for="addressLabel" class="block text-sm font-medium text-gray-700 mb-2"> Label Alamat <span class="text-red-500">*</span> </label> <input type="text" id="addressLabel" placeholder="Contoh: Rumah, Kantor, Apartemen, Kos" required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"> </div> <!-- Full Address --> <div> <label for="fullAddress" class="block text-sm font-medium text-gray-700 mb-2"> Alamat Lengkap <span class="text-red-500">*</span> </label> <textarea id="fullAddress" rows="3" placeholder="Alamat lengkap akan diisi otomatis berdasarkan lokasi yang dipilih" required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors resize-none"></textarea> </div> <!-- Address Notes --> <div> <label for="addressNotes" class="block text-sm font-medium text-gray-700 mb-2"> Catatan Alamat </label> <textarea id="addressNotes" rows="2" placeholder="Contoh: Rumah cat hijau, sebelah warung Pak Budi, lantai 3, pagar hitam" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors resize-none"></textarea> </div> <!-- Recipient Details --> <div class="form-row"> <div> <label for="receiverName" class="block text-sm font-medium text-gray-700 mb-2"> Nama Penerima <span class="text-red-500">*</span> </label> <input type="text" id="receiverName" placeholder="Nama lengkap penerima" required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"> </div> <div> <label for="receiverPhone" class="block text-sm font-medium text-gray-700 mb-2"> Nomor HP <span class="text-red-500">*</span> </label> <div class="relative"> <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> <span class="text-gray-500 text-sm">+62</span> </div> <input type="tel" id="receiverPhone" placeholder="8xxxxxxxxxx" pattern="[8][0-9]{9,11}" required class="w-full pl-12 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"> </div> </div> </div> <!-- Main Address Checkbox --> <div class="checkbox-wrapper" onclick="toggleMainAddress()"> <input type="checkbox" id="isMainAddress" class="text-blue-600 focus:ring-blue-500 rounded"> <div class="flex-1"> <label for="isMainAddress" class="text-sm font-medium text-gray-900 cursor-pointer"> Jadikan sebagai alamat utama </label> <p class="text-xs text-gray-500 mt-1">Alamat ini akan digunakan sebagai default untuk pengiriman</p> </div> </div> <!-- Hidden Fields --> <input type="hidden" id="latitude"> <input type="hidden" id="longitude"> <input type="hidden" id="province"> <input type="hidden" id="city"> <input type="hidden" id="district"> <input type="hidden" id="subdistrict"> <input type="hidden" id="postal-code"> </form> </div> </div> </div> <!-- Modal Footer --> <div class="flex items-center justify-between p-6 border-t border-gray-200 bg-gray-50"> <button class="px-6 py-3 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-100 transition-colors font-medium" id="backBtn" onclick="prevStep()" style="display: none;"> <i class="fas fa-arrow-left mr-2"></i> Kembali </button> <div class="flex-1"></div> <div class="flex items-center space-x-3"> <button class="px-6 py-3 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-100 transition-colors font-medium" onclick="closeModal()"> Batal </button> <button class="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium" id="nextBtn" onclick="nextStep()"> <span id="nextBtnText">Lanjutkan</span> <i class="fas fa-arrow-right ml-2" id="nextBtnIcon"></i> </button> </div> </div> </div> </div> </main> <script async src="https://maps.googleapis.com/maps/api/js?key=<?php echo $this->config->item('google_maps_api_key'); ?>&loading=async&libraries=places,marker&callback=initMap&language=id®ion=ID&v=beta" defer></script> <script> let currentStep = 1; let totalSteps = 2; let map, marker, geocoder, autocomplete; let selectedPlace = null; let isEditMode = false; let isUpdatingFromMap = false; let selectedEditAddressId = null; const modalTitle = document.getElementById('modalTitle'); const modalSubtitle = document.getElementById('modalSubtitle'); const defaultLat = -6.194985; const defaultLng = 106.823070; const saveAddressUrl = '<?= base_url('admin/customers/save_address'); ?>'; function saveAddress() { if (!validateForm()) return; // Collect address data const addressData = { customerId: document.getElementById('customer_id').value, label: document.getElementById('addressLabel').value, fullAddress: document.getElementById('fullAddress').value, notes: document.getElementById('addressNotes').value, receiverName: document.getElementById('receiverName').value, receiverPhone: document.getElementById('receiverPhone').value, isMainAddress: document.getElementById('isMainAddress').checked, latitude: document.getElementById('latitude').value, longitude: document.getElementById('longitude').value, province: document.getElementById('province') ? document.getElementById('province').value : '', city: document.getElementById('city') ? document.getElementById('city').value : '', district: document.getElementById('district') ? document.getElementById('district').value : '', subdistrict: document.getElementById('subdistrict') ? document.getElementById('subdistrict').value : '', postalCode: document.getElementById('postal-code') ? document.getElementById('postal-code').value : '' }; // Show loading state const saveButton = document.getElementById('nextBtn'); if (saveButton) { saveButton.disabled = true; saveButton.innerHTML = 'Menyimpan...'; } // Create form data for POST request const formData = new FormData(); Object.keys(addressData).forEach(key => { formData.append(key, addressData[key]); }); const csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>'; const csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>'; if (csrfName && csrfHash) { formData.append(csrfName, csrfHash); } let url = isEditMode ? `<?= base_url('admin/customers/update_address/') ?>${selectedEditAddressId}` : saveAddressUrl; // Send POST request fetch(url, { method: 'POST', body: formData, headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { if (data.success) { notyf.success(data.message || 'Alamat berhasil disimpan!'); closeModal(); setTimeout(() => { location.reload(); }, 1000); } else { notyf.error(data.message || 'Gagal menyimpan alamat. Silakan coba lagi.'); } }) .catch(error => { notyf.error('Terjadi kesalahan. Silakan coba lagi.'); }) .finally(() => { if (saveButton) { saveButton.disabled = false; saveButton.innerHTML = 'Simpan Alamat <i class="fas fa-save"></i>'; } }); } function setDefaultAddress(addressId) { const csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>'; const csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>'; const formData = new FormData(); formData.append(csrfName, csrfHash); formData.append('customer_id', document.getElementById('customer_id').value); fetch(`<?= base_url('admin/customers/set_default_address/') ?>${addressId}`, { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.status === 'success') { notyf.success(data.message); setTimeout(() => location.reload(), 1000); } else { notyf.error(data.message); } }) .catch(error => { console.error('Error:', error); notyf.error('Terjadi kesalahan saat mengubah alamat utama'); }); } function closeModal() { document.getElementById('addressModal').classList.remove('active'); document.body.style.overflow = 'auto'; resetModal(); } function resetModal() { currentStep = 1; updateStepDisplay(); document.getElementById('addressForm').reset(); document.getElementById('addressSearch').value = ''; document.getElementById('locationInfo').style.display = 'none'; modalTitle.textContent = 'Tambah Alamat Baru'; modalSubtitle.textContent = 'Tambahkan alamat pengiriman untuk pelanggan'; selectedPlace = null; isUpdatingFromMap = false; } function nextStep() { if (currentStep === 1) { // Validate location selection if (!document.getElementById('latitude').value || !document.getElementById('longitude').value) { alert('Silakan pilih lokasi terlebih dahulu'); return; } currentStep = 2; updateStepDisplay(); } else if (currentStep === 2) { // Validate and save address if (validateForm()) { saveAddress(); } } } function prevStep() { if (currentStep > 1) { currentStep--; updateStepDisplay(); } } function updateStepDisplay() { // Update progress const progressPercent = (currentStep / totalSteps) * 100; document.getElementById('progressFill').style.width = progressPercent + '%'; // Update step indicators for (let i = 1; i <= totalSteps; i++) { const stepCircle = document.getElementById(`step${i}`); const stepLabel = document.getElementById(`stepLabel${i}`); if (i < currentStep) { stepCircle.className = 'step-circle completed'; } else if (i === currentStep) { stepCircle.className = 'step-circle active'; } else { stepCircle.className = 'step-circle inactive'; } } // Update content visibility for (let i = 1; i <= totalSteps; i++) { const content = document.getElementById(`content${i}`); if (i === currentStep) { content.classList.add('active'); } else { content.classList.remove('active'); } } // Update buttons const backBtn = document.getElementById('backBtn'); const nextBtn = document.getElementById('nextBtn'); const nextBtnText = document.getElementById('nextBtnText'); const nextBtnIcon = document.getElementById('nextBtnIcon'); if (!backBtn || !nextBtn || !nextBtnText || !nextBtnIcon) { return; } else if (currentStep === 1) { backBtn.style.display = 'none'; nextBtnText.textContent = 'Lanjutkan'; nextBtnIcon.className = 'fas fa-arrow-right ml-2'; } else if (currentStep === 2) { backBtn.style.display = 'block'; nextBtnText.textContent = 'Simpan Alamat'; nextBtnIcon.className = 'fas fa-save ml-2'; } } // Search functions function clearSearch() { document.getElementById('addressSearch').value = ''; document.getElementById('clearBtn').style.display = 'none'; document.getElementById('locationInfo').style.display = 'none'; // Reset marker ke posisi default const defaultLocation = { lat: -6.2088, lng: 106.8456 }; updateMarkerPosition(defaultLocation); } document.getElementById('addressSearch').addEventListener('input', function() { const clearBtn = document.getElementById('clearBtn'); if (this.value.length > 0) { clearBtn.style.display = 'block'; } else { clearBtn.style.display = 'none'; } }); // Main address checkbox toggle function toggleMainAddress() { const checkbox = document.getElementById('isMainAddress'); const wrapper = checkbox.closest('.checkbox-wrapper'); checkbox.checked = !checkbox.checked; if (checkbox.checked) { wrapper.classList.add('checked'); } else { wrapper.classList.remove('checked'); } } // Map functions // Map functions function centerMap() { if (map && marker) { const position = marker.getPosition(); map.setCenter(position); map.setZoom(16); } } function openAddressModal(addressId = null) { isEditMode = addressId !== null; selectedEditAddressId = addressId; document.getElementById('addressModal').classList.add('active'); document.body.style.overflow = 'hidden'; if (!isEditMode) { setTimeout(() => { if (typeof google !== 'undefined' && google.maps) { initMap(); } else { console.log('Google Maps not loaded yet'); } }, 300); } else { fetch(`<?= site_url('admin/customers/get_address/') ?>${addressId}`, { method: 'GET', headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => response.json()) .then(data => { if (data.success && data.address) { const addr = data.address; let lat = parseFloat(addr.latitude); let lng = parseFloat(addr.longitude); if (isNaN(lat) || isNaN(lng) || !isFinite(lat) || !isFinite(lng)) { console.warn('Invalid coordinates from address data, using default'); lat = defaultLat; lng = defaultLng; } modalTitle.textContent = 'Edit Alamat'; modalSubtitle.textContent = 'Ubah informasi alamat pengiriman pelanggan'; const searchInput = document.getElementById('addressSearch'); searchInput.value = addr.address; setTimeout(() => { if (typeof google !== 'undefined' && google.maps) { initMap(lat, lng); } }, 300); } else { notyf.error('Gagal memuat data alamat.'); setTimeout(() => { if (typeof google !== 'undefined' && google.maps) { initMap(); } }, 300); } }) .catch(error => { console.error(error); notyf.error('Terjadi kesalahan saat mengambil data alamat.'); setTimeout(() => { if (typeof google !== 'undefined' && google.maps) { initMap(); } }, 300); }); } } function getMarkerPosition() { if (!marker) return null; if (marker.position && typeof marker.position.lat === 'function') { return { lat: marker.position.lat(), lng: marker.position.lng() }; } else if (marker.getPosition && typeof marker.getPosition === 'function') { const pos = marker.getPosition(); return { lat: pos.lat(), lng: pos.lng() }; } else if (marker.position && typeof marker.position.lat === 'number') { return marker.position; } return null; } function updateMarkerPosition(position) { if (!marker) return; if (typeof google.maps.marker !== 'undefined' && marker instanceof google.maps.marker.AdvancedMarkerElement) { marker.position = new google.maps.LatLng(position.lat, position.lng); } else if (marker.setPosition && typeof marker.setPosition === 'function') { marker.setPosition(position); } if (map && map.setCenter) { map.setCenter(position); } } async function initMap(latitude = null, longitude = null) { try { const { Map } = await google.maps.importLibrary("maps"); const { AdvancedMarkerElement } = await google.maps.importLibrary("marker"); // Validasi dan set koordinat default let lat = defaultLat; let lng = defaultLng; // Jika parameter diberikan, validasi dulu if (latitude !== null && longitude !== null) { const parsedLat = typeof latitude === 'number' ? latitude : parseFloat(latitude); const parsedLng = typeof longitude === 'number' ? longitude : parseFloat(longitude); // Hanya gunakan jika valid if (!isNaN(parsedLat) && !isNaN(parsedLng) && isFinite(parsedLat) && isFinite(parsedLng) && parsedLat >= -90 && parsedLat <= 90 && parsedLng >= -180 && parsedLng <= 180) { lat = parsedLat; lng = parsedLng; } else { console.warn('Invalid coordinates provided:', latitude, longitude, 'Using default instead'); } } const defaultLocation = { lat: lat, lng: lng }; map = new Map(document.getElementById('map'), { center: defaultLocation, zoom: 16, mapId: '1873c42fd77c25f9fad736e6', mapTypeControl: false, streetViewControl: false, fullscreenControl: false }); marker = new AdvancedMarkerElement({ map: map, position: defaultLocation, gmpDraggable: true, title: 'Drag untuk memilih lokasi' }); geocoder = new google.maps.Geocoder(); setupAutocomplete(); setupEventListeners(); } catch (error) { console.error('Error initializing map:', error); // Fallback dengan koordinat yang sudah divalidasi let fallbackLat = defaultLat; let fallbackLng = defaultLng; if (latitude !== null && longitude !== null) { const parsedLat = parseFloat(latitude); const parsedLng = parseFloat(longitude); if (!isNaN(parsedLat) && !isNaN(parsedLng) && isFinite(parsedLat) && isFinite(parsedLng)) { fallbackLat = parsedLat; fallbackLng = parsedLng; } } initMapFallback(fallbackLat, fallbackLng); } } function initMapFallback(latitude = null, longitude = null) { // Validasi koordinat untuk fallback juga let lat = defaultLat; let lng = defaultLng; if (latitude !== null && longitude !== null) { const parsedLat = typeof latitude === 'number' ? latitude : parseFloat(latitude); const parsedLng = typeof longitude === 'number' ? longitude : parseFloat(longitude); if (!isNaN(parsedLat) && !isNaN(parsedLng) && isFinite(parsedLat) && isFinite(parsedLng)) { lat = parsedLat; lng = parsedLng; } } const defaultLocation = { lat: lat, lng: lng }; map = new google.maps.Map(document.getElementById('map'), { center: defaultLocation, zoom: 16, mapTypeControl: true, streetViewControl: false, fullscreenControl: false }); marker = new google.maps.Marker({ position: defaultLocation, map: map, draggable: true, title: 'Drag untuk memilih lokasi' }); geocoder = new google.maps.Geocoder(); setupAutocomplete(); setupEventListeners(); } function setupAutocomplete() { const searchInput = document.getElementById('addressSearch'); if (!searchInput) return; autocomplete = new google.maps.places.Autocomplete(searchInput, { componentRestrictions: { country: 'ID' }, fields: ['formatted_address', 'geometry', 'address_components', 'name'], }); autocomplete.addListener('place_changed', function() { if (isUpdatingFromMap) return; const place = autocomplete.getPlace(); if (!place.geometry) { alert('Alamat tidak ditemukan'); return; } selectedPlace = place; // Update marker position ke lokasi yang dipilih const location = { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }; updateMarkerPosition(location); // Update form data reverseGeocode(location, false); // false = tidak update search input }); } function setupEventListeners() { // Event untuk drag marker if (marker.addListener) { marker.addListener('dragend', function() { const position = getMarkerPosition(); if (position) { reverseGeocode(position, true); } }); } // Event untuk click di map if (map.addListener) { map.addListener('click', function(event) { const position = { lat: event.latLng.lat(), lng: event.latLng.lng() }; updateMarkerPosition(position); reverseGeocode(position, true); }); } } function getCurrentLocation() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( function(position) { const userLocation = { lat: position.coords.latitude, lng: position.coords.longitude }; // Update marker position updateMarkerPosition(userLocation); // Update form data dan search input reverseGeocode(userLocation, true); }, function(error) { console.error('Geolocation error:', error); alert('Tidak dapat mengakses lokasi saat ini'); } ); } else { alert('Geolocation tidak didukung oleh browser ini'); } } function reverseGeocode(location, updateSearchInput = false) { geocoder.geocode({ location: location }, function(results, status) { if (status === 'OK' && results[0]) { // Update search input jika diminta (dari drag/click map) if (updateSearchInput) { isUpdatingFromMap = true; document.getElementById('addressSearch').value = results[0].formatted_address; setTimeout(() => { isUpdatingFromMap = false; }, 100); } // Update location info panel updateLocationInfo(results[0].formatted_address, location); // Parse address components const components = results[0].address_components; let addressData = { province: '', city: '', district: '', subdistrict: '', postal_code: '' }; if (components) { components.forEach(function(component) { const types = component.types; if (types.includes('administrative_area_level_1')) { addressData.province = component.long_name; } else if (types.includes('administrative_area_level_2')) { addressData.city = component.long_name; } else if (types.includes('administrative_area_level_3')) { addressData.district = component.long_name; } else if (types.includes('administrative_area_level_4')) { addressData.subdistrict = component.long_name; } else if (types.includes('postal_code')) { addressData.postal_code = component.long_name; } }); } // Fill form fields document.getElementById('fullAddress').value = results[0].formatted_address; // Set coordinates - Fixed coordinate handling let lat, lng; if (typeof location.lat === 'function' && typeof location.lng === 'function') { lat = location.lat(); lng = location.lng(); } else if (typeof location.lat === 'number' && typeof location.lng === 'number') { lat = location.lat; lng = location.lng; } else { console.error('Unknown location format:', location); return; } document.getElementById('latitude').value = lat; document.getElementById('longitude').value = lng; // Fill other address components const fieldsToUpdate = { 'province': addressData.province, 'city': addressData.city, 'district': addressData.district, 'subdistrict': addressData.subdistrict, 'postal-code': addressData.postal_code }; Object.keys(fieldsToUpdate).forEach(fieldId => { const field = document.getElementById(fieldId); if (field) { field.value = fieldsToUpdate[fieldId]; } }); console.log('Location updated successfully:', { lat, lng, address: results[0].formatted_address, addressData }); } else { console.error('Geocoding failed:', status); alert('Gagal mendapatkan informasi alamat'); } }); } function updateLocationInfo(address, coordinates) { const locationInfo = document.getElementById('locationInfo'); const selectedAddress = document.getElementById('selectedAddress'); const coordinatesDisplay = document.getElementById('coordinates'); if (locationInfo && selectedAddress && coordinatesDisplay) { selectedAddress.textContent = address; let lat, lng; if (typeof coordinates.lat === 'function') { lat = coordinates.lat(); lng = coordinates.lng(); } else { lat = coordinates.lat; lng = coordinates.lng; } coordinatesDisplay.textContent = `${lat.toFixed(6)}, ${lng.toFixed(6)}`; locationInfo.style.display = 'block'; } } // Form validation function validateForm() { const requiredFields = ['addressLabel', 'fullAddress', 'receiverName', 'receiverPhone']; let isValid = true; requiredFields.forEach(fieldId => { const field = document.getElementById(fieldId); if (!field.value.trim()) { field.classList.add('border-red-500'); field.classList.remove('border-gray-300'); isValid = false; } else { field.classList.remove('border-red-500'); field.classList.add('border-gray-300'); } }); if (!isValid) { alert('Mohon lengkapi semua field yang wajib diisi'); } return isValid; } // Form function togglePassword() { const passwordInput = document.getElementById('customer_password'); const eyeIcon = document.getElementById('eye-icon'); if (passwordInput.type === 'password') { passwordInput.type = 'text'; eyeIcon.innerHTML = ` <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21"></path> `; } else { passwordInput.type = 'password'; eyeIcon.innerHTML = ` <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path> `; } } // Auto-format phone number document.getElementById('customer_phone').addEventListener('input', function(e) { let value = e.target.value.replace(/\D/g, ''); if (value.startsWith('0')) { value = value.substring(1); } if (!value.startsWith('8') && value.length > 0) { value = '8' + value; } e.target.value = value; }); // Auto-uppercase referral code document.getElementById('customer_ref').addEventListener('input', function(e) { e.target.value = e.target.value.toUpperCase(); }); // View address on map function viewOnMap(latitude, longitude, label) { const googleMapsUrl = `https://www.google.com/maps?q=${latitude},${longitude}&z=16&t=m`; window.open(googleMapsUrl, '_blank'); } function deleteAddress(addressId) { if (confirm('Beneran dihapus?')) { const csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>'; const csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>'; const formData = new FormData(); formData.append(csrfName, csrfHash); fetch(`<?= base_url('admin/customers/delete_address/'); ?>${addressId}`, { method: 'POST', body: formData, headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(response => response.json()) .then(data => { if (data.success) { notyf.success(data.message || 'Alamat berhasil dihapus!'); setTimeout(() => { location.reload(); }, 1000); } else { notyf.error(data.message || 'Gagal menghapus alamat.'); } }) .catch(error => { console.error('Error:', error); notyf.error('Terjadi kesalahan. Silakan coba lagi.'); }); } } // Form validation feedback document.getElementById('customerForm').addEventListener('submit', function(e) { const requiredFields = ['customer_name', 'customer_email', 'customer_phone', 'customer_birthdate', 'customer_gender', 'customer_address']; let isValid = true; requiredFields.forEach(fieldId => { const field = document.getElementById(fieldId); if (!field.value.trim()) { field.classList.add('border-red-500', 'focus:ring-red-500', 'focus:border-red-500'); field.classList.remove('border-gray-300', 'focus:ring-blue-500', 'focus:border-blue-500'); isValid = false; } else { field.classList.remove('border-red-500', 'focus:ring-red-500', 'focus:border-red-500'); field.classList.add('border-gray-300', 'focus:ring-blue-500', 'focus:border-blue-500'); } }); if (!isValid) { e.preventDefault(); alert('Mohon lengkapi semua field yang wajib diisi.'); } }); document.addEventListener('DOMContentLoaded', function() { updateStepDisplay(); }); </script>