gamtest / resources /views /order.blade.php
veela4's picture
Upload folder using huggingface_hub
70ba896 verified
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<div>
<h1 class="heading-1 text-white mb-2">Order Management</h1>
<p class="text-blue-100">Manage all customer orders and transactions</p>
</div>
<div class="text-right text-white">
<div class="text-2xl font-bold">{{ $orders->count() }}</div>
<div class="text-blue-100">Total Orders</div>
</div>
</div>
</x-slot>
<div class="py-8">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@if (session('success'))
<div class="mb-6 p-4 bg-green-50 border border-green-200 rounded-lg">
<div class="flex items-center">
<i class="fas fa-check-circle text-green-600 mr-3"></i>
<span class="text-green-800 font-medium">{{ session('success') }}</span>
</div>
</div>
@endif
@if (session('error'))
<div class="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
<div class="flex items-center">
<i class="fas fa-exclamation-circle text-red-600 mr-3"></i>
<span class="text-red-800 font-medium">{{ session('error') }}</span>
</div>
</div>
@endif
<!-- Filter and Search Controls -->
<div class="card p-6 mb-6">
<div class="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4">
<div class="flex items-center space-x-4">
<h2 class="heading-3">
<i class="fas fa-list mr-2 text-blue-600"></i>All Orders
</h2>
<div class="text-base text-gray-700 dark:text-gray-300 font-medium">
<span id="orderCount">{{ $orders->count() }}</span> {{ $orders->count() === 1 ? 'order' : 'orders' }} total
</div>
</div>
<div class="flex flex-col sm:flex-row items-center space-y-3 sm:space-y-0 sm:space-x-4">
<!-- Search Box -->
<div class="relative">
<input type="text" id="searchInput" placeholder="Search orders..."
class="input-field pl-10 min-w-[250px]">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<i class="fas fa-search text-gray-400"></i>
</div>
</div>
<!-- Status Filter -->
<select id="statusFilter" class="input-field min-w-[150px]">
<option value="">All Status</option>
<option value="pending">PENDING</option>
<option value="completed">ACCEPTED</option>
<option value="cancelled">REJECTED</option>
</select>
<!-- Date Filter -->
<select id="dateFilter" class="input-field min-w-[150px]">
<option value="">All Dates</option>
<option value="today">Today</option>
<option value="week">This Week</option>
<option value="month">This Month</option>
</select>
</div>
</div>
</div>
@if($orders->isEmpty())
<div class="text-center py-20">
<div class="max-w-md mx-auto">
<div class="w-32 h-32 bg-gradient-to-r from-purple-500/20 to-blue-500/20 rounded-full flex items-center justify-center mx-auto mb-8 border border-purple-500/30">
<i class="fas fa-shopping-bag text-5xl text-purple-400"></i>
</div>
<h3 class="text-3xl font-bold text-white mb-4">No Orders Yet</h3>
<p class="text-white/70 mb-8 text-lg">No customer orders have been placed yet. Orders will appear here once customers start purchasing.</p>
<div class="flex flex-col sm:flex-row items-center justify-center gap-4">
<a href="{{ route('categories') }}" class="btn-primary">
<i class="fas fa-store mr-2"></i>Visit Store
</a>
<a href="{{ route('products.listOFproduct') }}" class="btn-secondary">
<i class="fas fa-cogs mr-2"></i>Manage Products
</a>
</div>
</div>
</div>
@else
<!-- Orders Grid -->
<div id="ordersGrid" class="space-y-4 max-w-full overflow-hidden">
@foreach ($orders as $order)
@php
$items = json_decode($order->cart_data, true);
$orderDate = $order->created_at;
@endphp
<div class="order-card glass-bg p-8 border border-white/10 hover:border-purple-500/30 transition-all duration-500 group {{ $loop->last ? '' : 'mb-8' }} max-w-full overflow-hidden"
data-customer="{{ strtolower($order->customer_name) }}"
data-phone="{{ $order->phone }}"
data-status="{{ $order->status ?? 'pending' }}"
data-date="{{ $orderDate->format('Y-m-d') }}"
data-date-category="{{ $orderDate->isToday() ? 'today' : ($orderDate->isCurrentWeek() ? 'week' : ($orderDate->isCurrentMonth() ? 'month' : 'older')) }}">
<div class="flex flex-col gap-10">
<!-- Enhanced Order Header -->
<div class="flex items-center justify-between mb-8">
<div class="flex items-center space-x-8">
<!-- Order Icon -->
<div class="w-20 h-20 bg-gradient-to-r from-purple-500 to-blue-500 rounded-2xl flex items-center justify-center shadow-lg group-hover:scale-110 transition-transform duration-300">
<i class="fas fa-receipt text-white text-2xl"></i>
</div>
<div>
<h3 class="text-3xl font-bold text-white mb-4">
Order #{{ str_pad($order->id, 4, '0', STR_PAD_LEFT) }}
</h3>
<!-- Enhanced Status Badge -->
<div class="flex items-center space-x-4">
<span class="px-5 py-3 rounded-xl text-sm font-semibold border {{ $order->status === 'completed' ? 'bg-green-500/20 text-green-300 border-green-500/30' : ($order->status === 'cancelled' ? 'bg-red-500/20 text-red-300 border-red-500/30' : 'bg-yellow-500/20 text-yellow-300 border-yellow-500/30') }}">
@if($order->status === 'completed')
<i class="fas fa-check-circle mr-2"></i>ACCEPTED
@elseif($order->status === 'cancelled')
<i class="fas fa-times-circle mr-2"></i>REJECTED
@else
<i class="fas fa-hourglass-half mr-2"></i>PENDING
@endif
</span>
<span class="text-white/60 text-base">
{{ $order->created_at->diffForHumans() }}
</span>
</div>
</div>
</div>
<!-- Enhanced Order Total -->
<div class="text-right">
<div class="text-base text-white/60 mb-2">Total Amount</div>
<div class="text-4xl font-bold text-green-400">
฿{{ number_format($order->total_amount ?? 0, 2) }}
</div>
</div>
</div>
<!-- Enhanced Customer Info -->
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6 mb-8">
<div class="glass-bg p-4 rounded-xl border border-white/10">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 bg-gradient-to-r from-blue-500 to-purple-500 rounded-lg flex items-center justify-center flex-shrink-0">
<i class="fas fa-user text-white"></i>
</div>
<div class="flex-1 min-w-0">
<div class="text-xs text-white/60 mb-1">Customer</div>
<div class="font-semibold text-white truncate text-sm">{{ $order->customer_name }}</div>
</div>
</div>
</div>
<div class="glass-bg p-4 rounded-xl border border-white/10">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 bg-gradient-to-r from-green-500 to-teal-500 rounded-lg flex items-center justify-center flex-shrink-0">
<i class="fas fa-phone text-white"></i>
</div>
<div class="flex-1 min-w-0">
<div class="text-xs text-white/60 mb-1">Phone</div>
<div class="font-semibold text-white truncate text-sm">{{ $order->phone }}</div>
</div>
</div>
</div>
<div class="glass-bg p-4 rounded-xl border border-white/10">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 bg-gradient-to-r from-purple-500 to-pink-500 rounded-lg flex items-center justify-center flex-shrink-0">
<i class="fas fa-calendar text-white"></i>
</div>
<div class="flex-1 min-w-0">
<div class="text-xs text-white/60 mb-1">Order Date</div>
<div class="font-semibold text-white text-sm">
{{ $order->created_at->format('M j, Y') }}
</div>
<div class="text-xs text-white/50">
{{ $order->created_at->format('g:i A') }}
</div>
</div>
</div>
</div>
<div class="glass-bg p-4 rounded-xl border border-white/10">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 bg-gradient-to-r from-orange-500 to-red-500 rounded-lg flex items-center justify-center flex-shrink-0">
<i class="fas fa-image text-white"></i>
</div>
<div class="flex-1 min-w-0">
<div class="text-xs text-white/60 mb-1">Payment Slip</div>
@if ($order->payment_slip_path)
<button onclick="showPaymentSlip('{{ asset('storage/' . $order->payment_slip_path) }}')"
class="text-blue-400 hover:text-blue-300 font-semibold transition-colors text-sm flex items-center">
<i class="fas fa-eye mr-1"></i>View Slip
</button>
@else
<span class="text-white/50 text-sm">No slip uploaded</span>
@endif
</div>
</div>
</div>
</div>
<!-- Enhanced Order Items with Images -->
@if (is_array($items))
<div class="border-t border-white/10 pt-6">
<h4 class="text-xl font-semibold text-white mb-6 flex items-center">
<i class="fas fa-shopping-cart mr-3 text-purple-400"></i>Order Items
<span class="ml-3 px-3 py-2 bg-purple-500/20 text-purple-300 text-sm rounded-full">
{{ count($items) }} {{ count($items) === 1 ? 'item' : 'items' }}
</span>
</h4>
<div class="space-y-6">
@foreach ($items as $item)
@php
// Get product details from database
$product = \App\Models\Product::find($item['id'] ?? null);
@endphp
<div class="glass-bg p-6 rounded-xl border border-white/10 hover:border-purple-500/30 transition-all duration-300">
<div class="flex items-center space-x-6">
<!-- Product Image -->
<div class="flex-shrink-0">
@if($product && $product->image)
<img src="{{ $product->image }}"
alt="{{ $item['name'] }}"
class="w-16 h-16 object-cover rounded-lg border border-white/20 shadow-lg">
@else
<div class="w-16 h-16 bg-gradient-to-r from-purple-500 to-blue-500 rounded-lg flex items-center justify-center">
<i class="fas fa-gamepad text-white text-xl"></i>
</div>
@endif
</div>
<!-- Product Details -->
<div class="flex-1 min-w-0">
<div class="flex items-start justify-between">
<div class="flex-1">
<h5 class="text-white font-semibold text-base mb-1 truncate">
{{ $item['name'] }}
</h5>
<!-- Game Category Badge -->
@if($product && $product->game)
<div class="mb-4">
<span class="px-3 py-2 rounded-full text-sm font-medium @switch($product->game) @case('Genshin') bg-yellow-500/20 text-yellow-300 border border-yellow-500/30 @break @case('Starrail') bg-purple-500/20 text-purple-300 border border-purple-500/30 @break @case('WutheringWave') bg-cyan-500/20 text-cyan-300 border border-cyan-500/30 @break @default bg-blue-500/20 text-blue-300 border border-blue-500/30 @endswitch">
@switch($product->game)
@case('Genshin')
<i class="fas fa-star mr-2"></i>Genshin Impact
@break
@case('Starrail')
<i class="fas fa-rocket mr-2"></i>Honkai: Star Rail
@break
@case('WutheringWave')
<i class="fas fa-wave-square mr-2"></i>Wuthering Waves
@break
@default
<i class="fas fa-gamepad mr-2"></i>{{ $product->game }}
@endswitch
</span>
</div>
@endif
<!-- Quantity and Price -->
<div class="flex items-center space-x-6 text-base">
<span class="flex items-center text-white/70">
<i class="fas fa-hashtag mr-2 text-blue-400"></i>
Qty: <span class="font-semibold ml-2">{{ $item['quantity'] }}</span>
</span>
<span class="flex items-center text-white/70">
<i class="fas fa-tag mr-2 text-green-400"></i>
฿{{ number_format($item['price'] ?? 0, 2) }} each
</span>
</div>
</div>
<!-- Item Total -->
<div class="text-right ml-6">
<div class="text-2xl font-bold text-green-400">
฿{{ number_format(($item['price'] ?? 0) * ($item['quantity'] ?? 1), 2) }}
</div>
<div class="text-sm text-white/50 mt-1">Total</div>
</div>
</div>
</div>
</div>
</div>
@endforeach
</div>
<!-- Order Summary -->
<div class="mt-6 p-4 bg-gradient-to-r from-purple-500/10 to-blue-500/10 rounded-xl border border-purple-500/20">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-2">
<i class="fas fa-calculator text-purple-400"></i>
<span class="text-white font-medium">Order Total</span>
</div>
<div class="text-2xl font-bold text-purple-400">
฿{{ number_format($order->total_amount ?? 0, 2) }}
</div>
</div>
</div>
</div>
@endif
</div>
<!-- Enhanced Actions -->
<div class="flex items-center justify-between pt-8 border-t border-white/10 mt-8">
<div class="flex items-center space-x-4">
<div class="text-base text-white/60">
<i class="fas fa-info-circle mr-2"></i>
Order created {{ $order->created_at->diffForHumans() }}
</div>
</div>
<div class="flex items-center space-x-4">
<a href="{{ route('orders.show', $order->id) }}" class="btn-secondary px-6 py-3">
<i class="fas fa-eye mr-2"></i>View Details
</a>
@if($order->status === 'pending')
<form action="{{ route('orders.complete', $order->id) }}" method="POST" class="inline-block">
@csrf
@method('PATCH')
<button type="submit" class="px-6 py-3 bg-gradient-to-r from-green-600 to-emerald-600 hover:from-green-500 hover:to-emerald-500 text-white rounded-xl font-bold transition-all duration-300 shadow-lg hover:shadow-green-500/40 transform hover:scale-105">
<i class="fas fa-check-circle mr-2"></i>ACCEPT
</button>
</form>
<form action="{{ route('orders.reject', $order->id) }}" method="POST"
class="inline-block"
onsubmit="return confirm('Are you sure you want to reject this order? The customer will see it as cancelled.');">
@csrf
@method('PATCH')
<button type="submit" class="px-6 py-3 bg-gradient-to-r from-red-600 to-rose-600 hover:from-red-500 hover:to-rose-500 text-white rounded-xl font-bold transition-all duration-300 shadow-lg hover:shadow-red-500/40 transform hover:scale-105">
<i class="fas fa-times-circle mr-2"></i>REJECT
</button>
</form>
@elseif($order->status === 'completed')
<span class="px-6 py-3 bg-green-500/20 text-green-300 rounded-xl font-bold border border-green-500/30">
<i class="fas fa-check-circle mr-2"></i>ACCEPTED
</span>
@elseif($order->status === 'cancelled')
<span class="px-6 py-3 bg-red-500/20 text-red-300 rounded-xl font-bold border border-red-500/30">
<i class="fas fa-times-circle mr-2"></i>REJECTED
</span>
@endif
</div>
</div>
</div>
</div>
@endforeach
</div>
<!-- No Results Message -->
<div id="noResults" class="hidden text-center py-12">
<div class="w-16 h-16 bg-gray-100 dark:bg-gray-800 rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fas fa-search text-gray-400 text-2xl"></i>
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">No orders found</h3>
<p class="text-gray-600 dark:text-gray-400">Try adjusting your search or filter criteria.</p>
</div>
@endif
</div>
</div>
<!-- Payment Slip Modal -->
<div id="paymentSlipModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm hidden items-center justify-center z-50 p-4">
<div class="bg-black/30 backdrop-filter backdrop-blur-20 border border-white/10 rounded-2xl max-w-4xl w-full max-h-[90vh] flex flex-col">
<div class="flex-shrink-0 flex items-center justify-between p-6 border-b border-white/10">
<h3 class="text-xl font-semibold text-white">Payment Slip</h3>
<button onclick="closePaymentSlip()" class="text-white/60 hover:text-white text-2xl transition-colors">
<i class="fas fa-times"></i>
</button>
</div>
<div class="flex-1 overflow-hidden p-6">
<div class="flex items-center justify-center h-full">
<img id="paymentSlipImage" src="" alt="Payment slip"
class="max-w-full max-h-full object-contain rounded-lg shadow-lg">
</div>
</div>
<div class="flex-shrink-0 p-6 border-t border-white/10">
<div class="flex justify-center space-x-4">
<button onclick="downloadPaymentSlip()" class="btn-secondary">
<i class="fas fa-download mr-2"></i>Download
</button>
<button onclick="closePaymentSlip()" class="btn-primary">
Close
</button>
</div>
</div>
</div>
</div>
</x-app-layout>
<script>
// Filtering functionality
const searchInput = document.getElementById('searchInput');
const statusFilter = document.getElementById('statusFilter');
const dateFilter = document.getElementById('dateFilter');
const orderCards = document.querySelectorAll('.order-card');
const noResults = document.getElementById('noResults');
const orderCount = document.getElementById('orderCount');
function filterOrders() {
const searchTerm = searchInput.value.toLowerCase();
const selectedStatus = statusFilter.value;
const selectedDate = dateFilter.value;
let visibleCount = 0;
orderCards.forEach(card => {
const customer = card.dataset.customer;
const phone = card.dataset.phone;
const status = card.dataset.status;
const dateCategory = card.dataset.dateCategory;
// Check search term
const matchesSearch = searchTerm === '' ||
customer.includes(searchTerm) ||
phone.includes(searchTerm);
// Check status filter
const matchesStatus = selectedStatus === '' || status === selectedStatus;
// Check date filter
const matchesDate = selectedDate === '' || dateCategory === selectedDate;
if (matchesSearch && matchesStatus && matchesDate) {
card.style.display = 'block';
visibleCount++;
} else {
card.style.display = 'none';
}
});
// Update order count
orderCount.textContent = visibleCount;
// Show/hide no results message
if (visibleCount === 0 && orderCards.length > 0) {
noResults.classList.remove('hidden');
} else {
noResults.classList.add('hidden');
}
}
// Add event listeners for filtering
searchInput.addEventListener('input', filterOrders);
statusFilter.addEventListener('change', filterOrders);
dateFilter.addEventListener('change', filterOrders);
// Enhanced delete confirmation
document.querySelectorAll('form[method="POST"]').forEach(form => {
form.addEventListener('submit', function(e) {
const button = this.querySelector('button[type="submit"]');
if (button && button.innerHTML.includes('Delete')) {
const originalText = button.innerHTML;
button.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>Deleting...';
button.disabled = true;
// Reset if there's an error (form doesn't submit)
setTimeout(() => {
if (button.disabled) {
button.innerHTML = originalText;
button.disabled = false;
}
}, 5000);
}
});
});
// Payment slip modal functions
function showPaymentSlip(imageSrc) {
const modal = document.getElementById('paymentSlipModal');
const image = document.getElementById('paymentSlipImage');
image.src = imageSrc;
modal.classList.remove('hidden');
modal.classList.add('flex');
// Prevent body scroll
document.body.style.overflow = 'hidden';
}
function closePaymentSlip() {
const modal = document.getElementById('paymentSlipModal');
const image = document.getElementById('paymentSlipImage');
modal.classList.add('hidden');
modal.classList.remove('flex');
image.src = '';
// Restore body scroll
document.body.style.overflow = 'auto';
}
function downloadPaymentSlip() {
const image = document.getElementById('paymentSlipImage');
const link = document.createElement('a');
link.href = image.src;
link.download = 'payment-slip.jpg';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// Close modal when clicking outside
document.getElementById('paymentSlipModal').addEventListener('click', function(e) {
if (e.target === e.currentTarget) {
closePaymentSlip();
}
});
// Close modal with Escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closePaymentSlip();
}
});
// Add smooth animations
document.addEventListener('DOMContentLoaded', function() {
// Animate cards on load
const cards = document.querySelectorAll('.order-card');
cards.forEach((card, index) => {
card.style.opacity = '0';
card.style.transform = 'translateY(20px)';
setTimeout(() => {
card.style.transition = 'all 0.5s ease';
card.style.opacity = '1';
card.style.transform = 'translateY(0)';
}, index * 100);
});
});
</script>
<style>
/* Enhanced Order Card Styling */
.order-card {
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
/* Ensure all child elements respect container width */
.order-card * {
max-width: 100%;
box-sizing: border-box;
}
.order-card::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), transparent);
transition: left 0.6s ease;
}
.order-card:hover::before {
left: 100%;
}
.order-card:hover {
transform: translateY(-8px) scale(1.02);
box-shadow:
0 25px 50px rgba(0, 0, 0, 0.4),
0 0 50px rgba(139, 92, 246, 0.2);
border-color: rgba(139, 92, 246, 0.5);
}
/* Product Image Hover Effects */
.order-card img {
transition: all 0.3s ease;
}
.order-card:hover img {
transform: scale(1.1);
box-shadow: 0 8px 25px rgba(139, 92, 246, 0.3);
}
/* Enhanced Glass Effect for Item Cards */
.glass-bg {
backdrop-filter: blur(20px);
background: rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
}
.glass-bg:hover {
background: rgba(0, 0, 0, 0.4);
transform: translateY(-2px);
}
/* Gradient Text Animation */
.bg-clip-text {
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Enhanced Payment Slip Modal */
#paymentSlipModal {
backdrop-filter: blur(20px);
}
#paymentSlipModal img {
transition: transform 0.3s ease;
max-height: 70vh;
}
#paymentSlipModal img:hover {
transform: scale(1.05);
}
/* Loading Animation for Delete Button */
.btn-danger:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* Smooth Fade In Animation */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.order-card {
animation: fadeInUp 0.6s ease-out;
}
/* Stagger Animation Delays */
.order-card:nth-child(1) { animation-delay: 0.1s; }
.order-card:nth-child(2) { animation-delay: 0.2s; }
.order-card:nth-child(3) { animation-delay: 0.3s; }
.order-card:nth-child(4) { animation-delay: 0.4s; }
.order-card:nth-child(5) { animation-delay: 0.5s; }
/* Custom Scrollbar */
.order-card::-webkit-scrollbar {
width: 8px;
}
.order-card::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
}
.order-card::-webkit-scrollbar-thumb {
background: rgba(139, 92, 246, 0.6);
border-radius: 4px;
}
.order-card::-webkit-scrollbar-thumb:hover {
background: rgba(139, 92, 246, 0.8);
}
/* Orders Grid Container */
#ordersGrid {
width: 100%;
max-width: 100%;
overflow-x: hidden;
contain: layout;
}
/* Force order cards to respect container bounds */
.order-card {
contain: layout;
min-width: 0;
}
/* Ensure grid items don't overflow */
.order-card .grid {
min-width: 0;
}
.order-card .grid > * {
min-width: 0;
max-width: 100%;
}
/* Ensure proper responsive behavior */
@media (max-width: 768px) {
.order-card {
margin-left: 0;
margin-right: 0;
}
.order-card .grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 1280px) {
.order-card .grid.xl\\:grid-cols-4 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
</style>