NIM_E31222518/resources/views/keranjang/checkout.blade.php

659 lines
31 KiB
PHP

@extends('layouts.dashboard')
@push('styles')
<style>
.modal {
display: none;
visibility: hidden;
position: fixed;
z-index: 9999;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
opacity: 0;
transition: opacity 0.3s ease;
}
.modal.show {
display: block;
visibility: visible;
opacity: 1;
}
.modal-content {
background-color: #fff;
margin: 10% auto;
padding: 20px;
border-radius: 8px;
width: 400px;
position: relative;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transform: translateY(-20px);
transition: transform 0.3s ease;
}
.modal.show .modal-content {
transform: translateY(0);
}
</style>
@endpush
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
const modal = document.getElementById('addressModal');
// Pastikan modal tersembunyi saat awal
modal.classList.remove('show');
// Fungsi untuk menampilkan modal
window.showModal = function() {
modal.classList.add('show');
document.body.style.overflow = 'hidden';
}
// Fungsi untuk menyembunyikan modal
window.hideModal = function() {
modal.classList.remove('show');
document.body.style.overflow = '';
}
// Event listener untuk tombol tambah alamat
const addAddressBtn = document.querySelector('.btn-add-address');
if (addAddressBtn) {
addAddressBtn.addEventListener('click', showModal);
}
// Event listener untuk tombol edit alamat
const editAddressBtn = document.querySelector('.btn-edit-address');
if (editAddressBtn) {
editAddressBtn.addEventListener('click', showModal);
}
// Event listener untuk tombol close modal
const closeModalBtn = document.querySelector('.btn-close-modal');
if (closeModalBtn) {
closeModalBtn.addEventListener('click', hideModal);
}
// Event listener untuk tombol cancel modal
const cancelModalBtn = document.querySelector('.btn-cancel-modal');
if (cancelModalBtn) {
cancelModalBtn.addEventListener('click', hideModal);
}
// Event listener untuk menutup modal ketika klik di luar modal
window.addEventListener('click', function(event) {
if (event.target === modal) {
hideModal();
}
});
// Event listener untuk menutup modal dengan tombol Escape
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && modal.classList.contains('show')) {
hideModal();
}
});
const addressForm = document.getElementById('addressForm');
const addressField = document.getElementById('alamat');
const editButton = document.getElementById('editButton');
const saveButton = document.getElementById('saveButton');
const cancelButton = document.getElementById('cancelButton');
if (editButton) {
editButton.addEventListener('click', function() {
addressField.removeAttribute('readonly');
addressField.classList.remove('bg-gray-50');
editButton.classList.add('hidden');
saveButton.classList.remove('hidden');
cancelButton.classList.remove('hidden');
});
}
if (cancelButton) {
cancelButton.addEventListener('click', function() {
addressField.setAttribute('readonly', true);
addressField.classList.add('bg-gray-50');
addressField.value = '{{ auth()->user()->alamat }}';
editButton.classList.remove('hidden');
saveButton.classList.add('hidden');
cancelButton.classList.add('hidden');
});
}
// Handle form submission with AJAX
addressForm.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch(this.action, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Show success message
const successAlert = document.createElement('div');
successAlert.className = 'relative px-4 py-3 mb-4 text-green-700 bg-green-100 border border-green-400 rounded';
successAlert.innerHTML = `
<span class="block sm:inline">${data.message}</span>
<button type="button" class="absolute top-0 right-0 px-4 py-3" onclick="this.parentElement.style.display='none'">
<i class="fas fa-times"></i>
</button>
`;
addressForm.parentElement.insertBefore(successAlert, addressForm);
// Reset form state
addressField.setAttribute('readonly', true);
addressField.classList.add('bg-gray-50');
if (editButton) editButton.classList.remove('hidden');
if (saveButton) saveButton.classList.add('hidden');
if (cancelButton) cancelButton.classList.add('hidden');
// Auto hide success message after 3 seconds
setTimeout(() => {
successAlert.style.display = 'none';
}, 3000);
} else {
// Show error message
const errorAlert = document.createElement('div');
errorAlert.className = 'relative px-4 py-3 mb-4 text-red-700 bg-red-100 border border-red-400 rounded';
errorAlert.innerHTML = `
<span class="block sm:inline">${data.message}</span>
<button type="button" class="absolute top-0 right-0 px-4 py-3" onclick="this.parentElement.style.display='none'">
<i class="fas fa-times"></i>
</button>
`;
addressForm.parentElement.insertBefore(errorAlert, addressForm);
// Auto hide error message after 3 seconds
setTimeout(() => {
errorAlert.style.display = 'none';
}, 3000);
}
})
.catch(error => {
console.error('Error:', error);
});
});
// Auto-hide alerts after 3 seconds
setTimeout(function() {
const errorAlert = document.getElementById('error-alert');
const successAlert = document.getElementById('success-alert');
if (errorAlert) errorAlert.style.display = 'none';
if (successAlert) successAlert.style.display = 'none';
}, 3000);
const provinceSelect = document.getElementById('province');
const citySelect = document.getElementById('city');
const courierSelect = document.getElementById('courier');
const calculateButton = document.getElementById('calculateShipping');
const shippingResult = document.getElementById('shippingResult');
const shippingOptions = document.getElementById('shippingOptions');
const submitButton = document.getElementById('submitOrder');
const shippingWarning = document.getElementById('shipping-warning');
let activeShippingOption = null;
// Nonaktifkan tombol submit di awal
submitButton.classList.add('opacity-50', 'cursor-not-allowed');
submitButton.setAttribute('disabled', 'disabled');
shippingWarning.style.display = 'block';
// Load provinces from database
fetch('{{ route("provinces") }}')
.then(response => response.json())
.then(data => {
data.forEach(province => {
const option = new Option(province.province_name, province.province_id);
provinceSelect.add(option);
});
})
.catch(error => {
console.error('Error loading provinces:', error);
alert('Gagal memuat data provinsi');
});
// Load cities when province is selected
provinceSelect.addEventListener('change', function() {
const provinceId = this.value;
citySelect.innerHTML = '<option value="">Pilih Kota</option>';
if (provinceId) {
fetch(`{{ route('cities') }}?province_id=${provinceId}`)
.then(response => response.json())
.then(data => {
data.forEach(city => {
const option = new Option(city.city_name, city.city_id);
citySelect.add(option);
});
})
.catch(error => {
console.error('Error loading cities:', error);
alert('Gagal memuat data kota');
});
}
});
// Calculate shipping cost
calculateButton.addEventListener('click', function() {
const provinceId = provinceSelect.value;
const cityId = citySelect.value;
const courier = courierSelect.value;
if (!provinceId || !cityId) {
alert('Silakan pilih provinsi dan kota tujuan');
return;
}
fetch('{{ route("calculate-cost") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify({
province_id: provinceId,
city_id: cityId,
courier: courier
})
})
.then(response => response.json())
.then(data => {
shippingOptions.innerHTML = '';
if (data.success) {
// Filter opsi berdasarkan kurir yang dipilih
const filteredOptions = data.options.filter(option => {
const service = option.service.toLowerCase();
if (courier === 'jne') {
return service.includes('jne');
} else if (courier === 'pos') {
return service.includes('pos');
} else if (courier === 'tiki') {
return service.includes('tiki');
}
return false;
});
if (filteredOptions.length === 0) {
shippingOptions.innerHTML = '<p class="text-gray-500 text-center py-4">Tidak ada opsi pengiriman yang tersedia untuk kurir ini</p>';
} else {
filteredOptions.forEach(option => {
const optionElement = document.createElement('div');
// Tambahkan class untuk highlight jika ini adalah opsi yang aktif
const isActive = activeShippingOption &&
activeShippingOption.service === option.service &&
activeShippingOption.cost === option.cost;
optionElement.className = `flex items-center justify-between p-3 border rounded-lg cursor-pointer hover:bg-gray-50 mb-2 ${
isActive ? 'bg-[#2C7A7B] bg-opacity-10 border-[#2C7A7B]' : ''
}`;
optionElement.innerHTML = `
<div>
<p class="font-medium ${isActive ? 'text-[#2C7A7B]' : ''}">${option.service}</p>
<p class="text-sm ${isActive ? 'text-[#2C7A7B]' : 'text-gray-500'}">${option.description}</p>
</div>
<div class="text-right">
<p class="font-medium ${isActive ? 'text-[#2C7A7B]' : ''}">Rp ${option.cost.toLocaleString('id-ID')}</p>
<p class="text-sm ${isActive ? 'text-[#2C7A7B]' : 'text-gray-500'}">${option.etd} hari</p>
</div>
`;
optionElement.addEventListener('click', () => {
// Hapus highlight dari opsi sebelumnya
const previousActive = document.querySelector('.shipping-option-active');
if (previousActive) {
previousActive.classList.remove('bg-[#2C7A7B]', 'bg-opacity-10', 'border-[#2C7A7B]', 'shipping-option-active');
previousActive.querySelectorAll('p').forEach(p => {
p.classList.remove('text-[#2C7A7B]');
if (p.classList.contains('text-gray-500')) {
p.classList.add('text-gray-500');
}
});
}
// Tambahkan highlight ke opsi yang dipilih
optionElement.classList.add('bg-[#2C7A7B]', 'bg-opacity-10', 'border-[#2C7A7B]', 'shipping-option-active');
optionElement.querySelectorAll('p').forEach(p => {
p.classList.add('text-[#2C7A7B]');
if (p.classList.contains('text-gray-500')) {
p.classList.remove('text-gray-500');
}
});
// Simpan opsi yang aktif
activeShippingOption = option;
// Panggil fungsi selectShipping
selectShipping(option.service, option.cost, option.etd);
});
shippingOptions.appendChild(optionElement);
});
}
shippingResult.classList.remove('hidden');
} else {
alert(data.message || 'Gagal menghitung ongkos kirim');
}
})
.catch(error => {
console.error('Error calculating shipping:', error);
alert('Gagal menghitung ongkos kirim');
});
});
// Reset active shipping option when courier changes
courierSelect.addEventListener('change', function() {
activeShippingOption = null;
shippingOptions.innerHTML = '';
shippingResult.classList.add('hidden');
// Nonaktifkan tombol submit
submitButton.classList.add('opacity-50', 'cursor-not-allowed');
submitButton.setAttribute('disabled', 'disabled');
submitButton.setAttribute('data-shipping-selected', 'false');
// Tampilkan pesan peringatan
shippingWarning.style.display = 'block';
// Hapus tampilan ongkir yang ada
const oldShippingInfo = document.querySelector('.shipping-info');
if (oldShippingInfo) {
oldShippingInfo.remove();
}
// Reset total ke subtotal
const subtotal = parseFloat({{ $total }});
document.querySelector('.total-price').textContent = `Rp ${subtotal.toLocaleString('id-ID')}`;
});
function selectShipping(service, cost, etd) {
// Update total price
const subtotal = parseFloat({{ $total }});
const shippingCost = parseFloat(cost);
const total = subtotal + shippingCost;
// Update display
document.querySelector('.total-price').textContent = `Rp ${total.toLocaleString('id-ID')}`;
// Tambahkan tampilan ongkir
const shippingInfo = document.createElement('div');
shippingInfo.className = 'flex justify-between mb-4';
shippingInfo.innerHTML = `
<p class="text-gray-600">Ongkos Kirim (${service})</p>
<p class="font-medium">Rp ${shippingCost.toLocaleString('id-ID')}</p>
`;
// Cari elemen subtotal
const subtotalElement = document.querySelector('.subtotal-info');
if (subtotalElement) {
// Hapus tampilan ongkir yang lama jika ada
const oldShippingInfo = document.querySelector('.shipping-info');
if (oldShippingInfo) {
oldShippingInfo.remove();
}
// Tambahkan tampilan ongkir baru
shippingInfo.classList.add('shipping-info');
subtotalElement.after(shippingInfo);
}
// Add shipping info to form
const shippingInfoInput = document.createElement('input');
shippingInfoInput.type = 'hidden';
shippingInfoInput.name = 'shipping_info';
shippingInfoInput.value = JSON.stringify({
service,
cost: shippingCost,
etd,
courier: courierSelect.value,
province_id: provinceSelect.value,
city_id: citySelect.value
});
document.querySelector('form[action="{{ route('pesanan.store-from-cart') }}"]').appendChild(shippingInfoInput);
// Aktifkan tombol submit
submitButton.classList.remove('opacity-50', 'cursor-not-allowed');
submitButton.removeAttribute('disabled');
submitButton.setAttribute('data-shipping-selected', 'true');
// Sembunyikan pesan peringatan
shippingWarning.style.display = 'none';
}
});
</script>
@endpush
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="max-w-4xl mx-auto">
<div class="mb-6">
<h1 class="text-2xl font-bold text-gray-800">Checkout</h1>
<p class="text-gray-600 mt-1">Selesaikan pesanan Anda.</p>
</div>
@if(session('error'))
<div class="relative px-4 py-3 mb-4 text-red-700 bg-red-100 border border-red-400 rounded" id="error-alert">
<span class="block sm:inline">{{ session('error') }}</span>
<button type="button" class="absolute top-0 right-0 px-4 py-3" onclick="this.parentElement.style.display='none'">
<i class="fas fa-times"></i>
</button>
</div>
@endif
@if(session('success'))
<div class="relative px-4 py-3 mb-4 text-green-700 bg-green-100 border border-green-400 rounded" id="success-alert">
<span class="block sm:inline">{{ session('success') }}</span>
<button type="button" class="absolute top-0 right-0 px-4 py-3" onclick="this.parentElement.style.display='none'">
<i class="fas fa-times"></i>
</button>
</div>
@endif
@if(!auth()->user()->alamat)
<div class="bg-yellow-50 border-l-4 border-yellow-400 p-4 mb-6">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-exclamation-triangle text-yellow-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-yellow-700">
Anda belum memiliki alamat. Silakan tambahkan alamat Anda terlebih dahulu.
</p>
</div>
</div>
</div>
@endif
<!-- Modal Tambah/Ubah Alamat -->
<div id="addressModal" class="modal" style="display: none;">
<div class="modal-content">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium leading-6 text-gray-900">Tambah/Ubah Alamat</h3>
</div>
<form id="addressForm" action="{{ route('user.update-address') }}" method="POST">
@csrf
<div class="mb-4">
<textarea name="alamat" id="alamat" rows="3" required
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-[#2C7A7B] {{ auth()->user()->alamat ? 'bg-gray-50' : '' }}"
placeholder="Masukkan alamat lengkap Anda"
{{ auth()->user()->alamat ? 'readonly' : '' }}>{{ auth()->user()->alamat }}</textarea>
@error('alamat')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
<div class="flex justify-end space-x-3">
@if(auth()->user()->alamat)
<button type="button" id="editButton" class="px-4 py-2 text-sm font-medium text-white bg-[#2C7A7B] hover:bg-[#1C6B6B] rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#2C7A7B]">
<i class="fas fa-edit mr-2"></i>
Edit Alamat
</button>
<button type="submit" id="saveButton" class="hidden px-4 py-2 text-sm font-medium text-white bg-[#2C7A7B] hover:bg-[#1C6B6B] rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#2C7A7B]">
<i class="fas fa-save mr-2"></i>
Simpan
</button>
<button type="button" id="cancelButton" class="hidden px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">
Batal
</button>
@else
<button type="submit" class="px-4 py-2 text-sm font-medium text-white bg-[#2C7A7B] hover:bg-[#1C6B6B] rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#2C7A7B]">
<i class="fas fa-save mr-2"></i>
Simpan
</button>
@endif
</div>
</form>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-5 gap-6 mt-6">
<!-- Daftar Item Keranjang -->
<div class="md:col-span-3">
<div class="bg-white rounded-xl shadow-md overflow-hidden mb-6">
<div class="p-6">
<h2 class="text-lg font-semibold mb-4">Item Pesanan ({{ count($items) }})</h2>
<div class="flow-root">
<ul class="-my-6 divide-y divide-gray-200">
@foreach($items as $item)
<li class="py-6 flex">
<div class="flex-shrink-0 w-20 h-20 rounded-md overflow-hidden border border-gray-200">
@if($item->barang->gambar)
<img src="{{ Storage::url($item->barang->gambar) }}" alt="{{ $item->barang->nama_barang }}" class="w-full h-full object-cover">
@else
<div class="w-full h-full bg-gray-200 flex items-center justify-center">
<span class="text-gray-400">No Image</span>
</div>
@endif
</div>
<div class="ml-4 flex-1 flex flex-col">
<div>
<div class="flex justify-between text-base font-medium text-gray-900">
<h3>{{ $item->barang->nama_barang }}</h3>
<p class="ml-4">Rp {{ number_format($item->total_harga, 0, ',', '.') }}</p>
</div>
<p class="mt-1 text-sm text-gray-500">Jumlah: {{ $item->jumlah }} x Rp {{ number_format($item->barang->harga, 0, ',', '.') }}</p>
</div>
</div>
</li>
@endforeach
</ul>
</div>
</div>
</div>
<!-- Alamat Pengiriman -->
<div class="bg-white rounded-xl shadow-md overflow-hidden mb-6">
<div class="p-6">
<h2 class="text-lg font-semibold mb-4">Alamat Pengiriman</h2>
<!-- Form Alamat -->
<form id="shippingForm" class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="province" class="block text-sm font-medium text-gray-700">Provinsi</label>
<select id="province" name="province" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-[#2C7A7B] focus:ring-[#2C7A7B]">
<option value="">Pilih Provinsi</option>
</select>
</div>
<div>
<label for="city" class="block text-sm font-medium text-gray-700">Kota/Kabupaten</label>
<select id="city" name="city" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-[#2C7A7B] focus:ring-[#2C7A7B]">
<option value="">Pilih Kota</option>
</select>
</div>
</div>
<div>
<label for="address" class="block text-sm font-medium text-gray-700">Alamat Lengkap</label>
<textarea id="address" name="address" rows="3" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-[#2C7A7B] focus:ring-[#2C7A7B]">{{ auth()->user()->alamat }}</textarea>
</div>
<div>
<label for="courier" class="block text-sm font-medium text-gray-700">Kurir</label>
<select id="courier" name="courier" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-[#2C7A7B] focus:ring-[#2C7A7B]">
<option value="jne">JNE</option>
<option value="pos">POS Indonesia</option>
<option value="tiki">TIKI</option>
</select>
</div>
<div>
<button type="button" id="calculateShipping" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-[#2C7A7B] hover:bg-[#1C6B6B] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#2C7A7B]">
Hitung Ongkir
</button>
</div>
</form>
<!-- Hasil Perhitungan Ongkir -->
<div id="shippingResult" class="mt-4 hidden">
<h3 class="text-lg font-medium text-gray-900 mb-2">Opsi Pengiriman</h3>
<div id="shippingOptions" class="space-y-2">
<!-- Opsi pengiriman akan ditampilkan di sini -->
</div>
</div>
</div>
</div>
</div>
<!-- Ringkasan Pesanan -->
<div class="md:col-span-2">
<div class="bg-white rounded-xl shadow-md overflow-hidden sticky top-6">
<div class="p-6">
<h2 class="text-lg font-semibold mb-4">Ringkasan Pesanan</h2>
<div class="space-y-4">
<div class="flex justify-between subtotal-info">
<p class="text-gray-600">Subtotal</p>
<p class="font-medium">Rp {{ number_format($total, 0, ',', '.') }}</p>
</div>
<div class="border-t border-gray-200 pt-4 mt-6">
<div class="flex justify-between mb-4">
<p class="text-lg font-semibold">Total</p>
<p class="text-lg font-bold text-[#2C7A7B] total-price">Rp {{ number_format($total, 0, ',', '.') }}</p>
</div>
</div>
<form action="{{ route('pesanan.store-from-cart') }}" method="POST">
@csrf
<div class="mb-4">
<label for="catatan" class="block text-sm font-medium text-gray-700 mb-1">Catatan (Opsional)</label>
<textarea name="catatan" id="catatan" rows="3"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-[#2C7A7B]"></textarea>
</div>
@if(isset($selectedIds))
@foreach($selectedIds as $id)
<input type="hidden" name="selected_items[]" value="{{ $id }}">
@endforeach
@endif
<button type="submit" id="submitOrder" class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-[#2C7A7B] hover:bg-[#1C6B6B] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#2C7A7B] {{ !auth()->user()->alamat ? 'opacity-50 cursor-not-allowed' : '' }}" {{ !auth()->user()->alamat ? 'disabled' : '' }} data-shipping-selected="false">
Buat Pesanan
</button>
<div id="shipping-warning" class="mt-2 text-sm text-red-600 text-center">
Silakan pilih opsi pengiriman terlebih dahulu
</div>
</form>
<div class="mt-4">
<a href="{{ route('keranjang.index') }}" class="text-[#2C7A7B] hover:text-[#1C6B6B] text-sm font-medium flex items-center justify-center">
<i class="fas fa-arrow-left mr-2"></i>
Kembali ke Keranjang
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection