Files
portal-api/resources/views/livewire/cart/summary-addons.blade.php
T
2025-07-29 10:24:14 +07:00

248 lines
12 KiB
PHP

@php
$basePrice = $product->price_sale ?: $product->price;
@endphp
<div x-data="cartHandler({{ json_encode($addons) }}, {{ $basePrice }}, {{ $months }})" data-skeleton-id="addons-summary">
<div class="bg-white rounded-lg border border-gray-200 p-6 mb-3">
<h3 class="text-lg font-semibold text-gray-800 mb-4">{{ __('Thời hạn') }}</h3>
<div class="relative">
<!-- Alpine.js Dropdown -->
<div class="custom-dropdown" @click.away="open = false">
<!-- Dropdown Selected -->
<div class="dropdown-selected" :class="{ 'active': open }" @click="open = !open">
<span class="selected-text"
x-text="formatPrice(periodTotalPrice) + ' / ' + selectedPeriod + ' {{ __('tháng') }}'"></span>
<i class="dropdown-arrow" :class="{ 'rotate-180': open }">▼</i>
</div>
<!-- Dropdown Options -->
<div class="dropdown-options" :class="{ 'show': open }" x-show="open" x-transition>
<template x-for="period in periods" :key="period.value">
<div class="dropdown-option" :class="{ 'selected': period.months === selectedPeriod }"
@click="selectPeriod(period)">
<div class="flex justify-between items-center">
<span
x-text="formatPrice(basePrice * period.months - (period.months >= 12 ? Math.round(basePrice * period.months * 0.1) : 0)) + ' / ' + period.text"></span>
<span x-show="period.months >= 12"
class="text-xs text-green-600 bg-green-100 px-2 py-1 rounded">{{ __('Tiết kiệm 10%') }}</span>
</div>
</div>
</template>
</div>
</div>
<input type="hidden" name="payment_period" :value="selectedPeriod">
</div>
<!-- Total Price Display -->
<div class="mt-4 p-4 bg-gradient-to-r from-orange-50 to-indigo-50 rounded-lg border border-orange-200">
<div class="flex justify-between items-center">
<span class="text-lg font-semibold text-orange-800">{{ __('Tổng tiền:') }}</span>
<span class="text-2xl font-bold text-orange-900" x-text="formatPrice(periodTotalPrice)"></span>
</div>
<div class="text-sm text-orange-600 mt-1">
<span x-text="selectedPeriod + ' {{ __('tháng') }}'"></span> •
<span x-text="formatPrice(basePrice) + '/{{ __('tháng') }}'"></span>
</div>
<div class="mt-2 pt-2 border-t border-orange-200" x-show="discount > 0">
<div class="flex justify-between text-xs text-orange-700">
<span>{{ __('Giá gốc:') }}</span>
<span x-text="formatPrice(originalPrice)"></span>
</div>
<div class="flex justify-between text-xs text-green-600 font-medium">
<span>{{ __('Tiết kiệm:') }}</span>
<span x-text="formatPrice(discount)"></span>
</div>
</div>
</div>
</div>
<!-- Card chọn addon -->
<div class="bg-white rounded-lg border border-gray-200 p-6 mb-3">
<h3 class="text-lg font-semibold text-gray-800 mb-4">{{ __('Cấu hình tùy chọn') }}</h3>
<template x-if="loading">
<div class="space-y-4">
@for ($i = 0; $i < 3; $i++)
<div class="p-4 bg-gray-50 rounded-lg animate-pulse">
<div class="flex justify-between items-center mb-2">
<div class="h-4 bg-gray-200 rounded w-24"></div>
<div class="h-4 bg-gray-200 rounded w-20"></div>
</div>
<div class="flex items-center gap-3">
<div class="flex items-center border border-gray-300 rounded-lg overflow-hidden bg-white">
<div class="w-10 h-10 bg-gray-200"></div>
<div class="w-16 h-10 bg-gray-200"></div>
<div class="w-10 h-10 bg-gray-200"></div>
</div>
<div class="h-4 bg-gray-200 rounded w-16"></div>
</div>
</div>
@endfor
</div>
</template>
<template x-if="!loading">
<template x-for="(addon, key) in addons" :key="key">
<div class="p-4 bg-gray-50 rounded-lg hover:bg-gray-100 transition">
<div class="flex justify-between items-center mb-2">
<span class="font-bold" x-text="addon.name"></span>
<span class="text-gray-700" x-text="formatPrice(addon.price) + ' đ/' + addon.prefix"></span>
</div>
<div class="flex flex-row items-center gap-3">
<div class="flex items-center border border-gray-300 rounded-lg overflow-hidden bg-white">
<button type="button" @click="decrement(key)"
class="w-10 h-10 flex items-center justify-center bg-gray-50 hover:bg-orange-100 text-gray-600 hover:text-orange-600 transition-colors duration-200 border-r border-gray-300">
<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="M20 12H4">
</path>
</svg>
</button>
<input type="number" :min="addon.min" :max="addon.max"
:step="addon.step" x-model.number="addon.qty"
class="w-16 h-10 text-center border-0 focus:ring-0 focus:outline-none bg-white text-gray-800 font-medium">
<button type="button" @click="increment(key)"
class="w-10 h-10 flex items-center justify-center bg-gray-50 hover:bg-orange-100 text-gray-600 hover:text-orange-600 transition-colors duration-200 border-l border-gray-300">
<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="M12 4v16m8-8H4"></path>
</svg>
</button>
</div>
<span class="ml-auto font-medium text-orange-600"
x-text="formatPrice(addon.qty * addon.price) + ' đ'"></span>
<!-- Input hidden để gửi dữ liệu -->
<template x-if="addon.qty > 0">
<div>
<input type="hidden" :name="`addons[${addon.id}][qty]`" :value="addon.qty">
<input type="hidden" :name="`addons[${addon.id}][price]`" :value="addon.price">
</div>
</template>
</div>
</div>
</template>
</template>
</div>
<!-- Card tóm tắt đơn hàng -->
<x-card class="mb-4">
<x-card-header title="{{ __('Tóm tắt đơn hàng') }}" />
<x-card-content>
<table class="w-full text-sm">
<thead class="bg-gray-50 border-b border-gray-200">
<tr>
<th class="py-2 px-4 text-left font-medium text-gray-700">{{ __('Mục') }}</th>
<th class="py-2 px-4 text-center font-medium text-gray-700">{{ __('Số lượng') }}</th>
<th class="py-2 px-4 text-right font-medium text-gray-700">{{ __('Giá tiền') }}</th>
</tr>
</thead>
<tbody>
<!-- Sản phẩm chính -->
<tr class="border-b border-gray-100">
<td class="py-3 px-4 font-medium">{{ $product->name }} (<span x-text="selectedPeriod"></span> {{ __('tháng') }})</td>
<td class="py-3 px-4 text-center">1</td>
<td class="py-3 px-4 text-right" x-text="formatPrice(periodTotalPrice) + ' đ'"></td>
</tr>
<!-- Các addon được chọn -->
<template x-for="addon in addons.filter(a => a.qty > 0)" :key="addon.id">
<tr class="border-b border-gray-100">
<td class="py-3 px-4" x-text="addon.name + ' (' + selectedPeriod + ' {{ __('tháng') }})'"></td>
<td class="py-3 px-4 text-center" x-text="addon.qty + ' ' + addon.prefix"></td>
<td class="py-3 px-4 text-right"
x-text="formatPrice(addon.qty * addon.price * selectedPeriod) + ' đ'">
</td>
</tr>
</template>
<!-- Tổng cộng -->
<tr class="font-bold bg-green-50">
<td class="py-3 px-4" colspan="2">{{ __('Tổng cộng') }}</td>
<td class="py-3 px-4 text-right" x-text="formatPrice(totalPrice) + ' đ'"></td>
</tr>
</tbody>
</table>
</x-card-content>
</x-card>
<!-- Input hidden gửi tổng giá -->
<input type="hidden" name="totalPrice" :value="totalPrice">
<input type="hidden" name="selectedPeriod" :value="selectedPeriod">
</div>
<script>
function cartHandler(initialAddons, basePrice, initialMonths) {
return {
loading: true,
open: false,
selectedPeriod: initialMonths,
basePrice: basePrice,
addons: [],
periods: [
{value: 6, months: 6, text: '6 {{ __('tháng') }}'},
{value: 12, months: 12, text: '1 {{ __('năm') }}'},
{value: 24, months: 24, text: '2 {{ __('năm') }}'},
{value: 36, months: 36, text: '3 {{ __('năm') }}'},
],
formatPrice(val) {
return new Intl.NumberFormat('vi-VN').format(val);
},
get periodTotalPrice() {
const originalPrice = this.basePrice * this.selectedPeriod;
const discount = this.selectedPeriod >= 12 ? Math.round(originalPrice * 0.1) : 0;
return originalPrice - discount;
},
get originalPrice() {
return this.basePrice * this.selectedPeriod;
},
get discount() {
return this.selectedPeriod >= 12 ? Math.round(this.originalPrice * 0.1) : 0;
},
get totalPrice() {
const addonTotal = this.addons.reduce((sum, addon) => {
return sum + addon.qty * addon.price * this.selectedPeriod;
}, 0);
return this.periodTotalPrice + addonTotal;
},
selectPeriod(period) {
this.selectedPeriod = period.months;
this.open = false;
},
increment(key) {
const addon = this.addons[key];
if (addon.qty < addon.max) addon.qty += addon.step;
},
decrement(key) {
const addon = this.addons[key];
if (addon.qty > addon.min) addon.qty -= addon.step;
},
init() {
setTimeout(() => {
this.addons = initialAddons.map(addon => ({
...addon,
qty: 0,
min: addon.min || 0,
max: addon.max || 999,
step: addon.step || 1,
}));
this.loading = false;
}, 1500); // Sync with other components
}
};
}
</script>