Files
thankcard-system/resources/views/components/user-page.blade.php
T
2026-07-10 08:16:20 +07:00

391 lines
24 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@props(['mode', 'user' => null, 'administrations' => null, 'selectedMonth' => null, 'addCards' => null, 'admins' => null])
@if($mode === 'self' && $user)
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6">
<div class="flex items-center gap-4">
<h2 class="text-xl font-bold text-text-dark flex items-center gap-2">
My Page
</h2>
<div class="px-4 py-1.5 bg-orange-100 border border-orange-200 rounded-full text-orange-800 font-bold text-sm flex items-center gap-2 shadow-sm">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 text-orange-500">
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 8.25h19.5M2.25 9h19.5m-16.5 5.25h6m-6 2.25h3m-3.75 3h15a2.25 2.25 0 002.25-2.25V6.75A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25v10.5A2.25 2.25 0 004.5 19.5z" />
</svg>
Thẻ hiện : <span class="text-lg">{{ $user->card }}</span>
</div>
</div>
</div>
@endif
@if($mode === 'edit' && $user)
<!-- 1. USER SUMMARY CARD -->
<div class="mb-6 bg-white rounded-2xl border border-gray-100 shadow-[0_8px_30px_rgb(0,0,0,0.03)] p-6 flex flex-col sm:flex-row sm:items-center justify-between gap-6 relative overflow-hidden">
<div class="absolute right-0 top-0 w-36 h-36 bg-blue-50/30 rounded-bl-full pointer-events-none -mr-6 -mt-6"></div>
<div class="flex items-center gap-5 relative z-10">
<div class="w-16 h-16 rounded-2xl bg-gradient-to-tr from-blue-500 to-indigo-600 text-white flex items-center justify-center text-2xl font-black shadow-md shadow-blue-500/20">
{{ strtoupper(substr($user->name ?? $user->msnv, 0, 1)) }}
</div>
<div>
<h2 class="text-xl font-black text-[#1a2b49] tracking-tight">{{ $user->name }}</h2>
<p class="text-gray-500 text-sm font-semibold mt-0.5">{{ $user->mail }}</p>
<div class="flex flex-wrap gap-2 mt-3">
@if($user->role == config('constants.ROLE_ADMIN'))
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-bold bg-blue-50 text-blue-700 border border-blue-100">Admin</span>
@else
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-bold bg-slate-50 text-slate-700 border border-slate-100">Member</span>
@endif
@if($user->status == config('constants.STATUS_ACTIVE'))
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-bold bg-green-50 text-green-700 border border-green-100">Đang làm việc</span>
@else
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-bold bg-red-50 text-red-700 border border-red-100">Đã nghỉ việc</span>
@endif
</div>
</div>
</div>
<div class="flex items-center gap-4 bg-slate-50 border border-slate-100 rounded-2xl p-4 relative z-10 min-w-[200px] shadow-sm">
<div class="w-11 h-11 bg-white rounded-xl shadow-sm flex items-center justify-center text-xl">
🎫
</div>
<div>
<span class="text-[10px] font-bold text-gray-500 uppercase tracking-wider block">Số thẻ hiện </span>
<span id="user-card-balance" class="text-xl font-black text-[#1a2b49]">{{ $user->card }}</span>
</div>
</div>
</div>
<!-- 2. USER FORM (FULL WIDTH) -->
<div class="mb-8">
<x-user-form :mode="$mode" :user="$user" />
</div>
<!-- 3. HISTORY SECTION -->
@if($administrations)
<div class="mb-6">
<h4 class="text-lg font-black text-[#1a2b49] mb-4 flex items-center gap-2">
<span class="w-1.5 h-6 bg-[#3462f7] rounded-full inline-block"></span>
Lịch sử hoạt động
</h4>
<div id="history-lists-container" class="grid grid-cols-1 lg:grid-cols-2 gap-6 items-stretch">
<!-- Card Allocation History: Lịch sử cấp phát thẻ -->
@if(isset($addCards))
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] border border-white overflow-hidden flex flex-col h-full">
<div class="px-6 py-5 border-b border-gray-100 bg-white flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<h3 class="text-[17px] font-extrabold text-[#1a2b49] leading-tight">
Lịch sử cấp phát thẻ
</h3>
<x-month-filter :mode="$mode" :user="$user" :selectedMonth="$selectedMonth" />
</div>
<div class="flex-1 overflow-y-auto max-h-[600px]">
<table class="min-w-full divide-y divide-gray-100 text-sm">
<thead class="bg-gray-50/50 sticky top-0 z-10">
<tr>
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Ngày cấp</th>
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Người cấp (Admin)</th>
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Số lượng thẻ</th>
<th class="px-6 py-4 text-center text-xs font-bold text-text-light uppercase tracking-wider w-24">Hành động</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-100">
@forelse($addCards as $addCard)
@php
$isCurrentMonth = Carbon\Carbon::parse($addCard->date)->format('Y-m') === Carbon\Carbon::now()->format('Y-m');
@endphp
<tr class="hover:bg-slate-50/60 transition-colors">
<td class="px-6 py-3.5 whitespace-nowrap text-text-medium font-medium">{{ Carbon\Carbon::parse($addCard->date)->format('d/m/Y') }}</td>
<td class="px-6 py-3.5 whitespace-nowrap font-bold text-[#1a2b49]">
@if($addCard->sellerUser)
<span class="text-[#3462f7]">{{ $addCard->sellerUser->name }}</span>
<div class="text-[11px] text-gray-400 font-medium mt-1.5 leading-none">
MSNV: {{ $addCard->sellerUser->msnv }} {{ $addCard->sellerUser->mail }}
</div>
@else
MSNV: {{ $addCard->seller }}
@endif
</td>
<td class="px-6 py-3.5 whitespace-nowrap font-extrabold text-base text-green-600">+{{ $addCard->num_card }}</td>
<td class="px-6 py-3.5 whitespace-nowrap text-center">
@if($isCurrentMonth)
<button type="button" onclick="openEditAddCardModal({{ json_encode($addCard) }})" class="text-blue-600 hover:text-blue-900 font-bold transition-colors">Sửa</button>
@else
<span class="text-gray-400 font-semibold text-xs cursor-not-allowed" title="Không thể chỉnh sửa giao dịch tháng trước">Tháng trước</span>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="4" class="px-6 py-12 text-center text-text-light font-medium text-base">
Chưa dữ liệu
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="px-6 py-4 bg-slate-50 border-t border-gray-100 flex justify-end">
<button type="button" onclick="openAddCardModal()" class="inline-flex items-center gap-2 bg-[#3462f7] hover:bg-blue-700 text-white font-bold text-sm px-5 py-2.5 rounded-xl shadow-md shadow-blue-500/10 transition-all">
Thêm thẻ
</button>
</div>
</div>
@endif
<!-- Transaction History: Lịch sử nhận/gửi -->
<div class="flex flex-col">
<x-transaction-history :mode="$mode" :user="$user" :administrations="$administrations" :selectedMonth="$selectedMonth" />
</div>
</div>
</div>
@endif
@else
<div class="grid grid-cols-1 {{ in_array($mode, ['edit', 'delete']) ? 'lg:grid-cols-3' : '' }} gap-6 items-start">
<!-- LEFT PANEL: User Profile & Actions / Form -->
<div class="{{ in_array($mode, ['edit', 'delete']) ? 'col-span-1' : 'col-span-full' }}">
@if($mode === 'create')
<div class="max-w-2xl mx-auto w-full">
<x-user-form :mode="$mode" :user="$user" />
</div>
@else
<x-user-form :mode="$mode" :user="$user" />
@endif
</div>
<!-- RIGHT PANEL: Transaction History & Add Card History -->
@if(in_array($mode, ['edit', 'delete', 'self']) && $user && $administrations)
<div id="history-lists-container" class="col-span-1 lg:col-span-2 flex flex-col gap-6">
<x-transaction-history :mode="$mode" :user="$user" :administrations="$administrations" :selectedMonth="$selectedMonth" />
@if($mode === 'edit' && isset($addCards))
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] border border-white overflow-hidden flex flex-col">
<div class="px-6 py-5 border-b border-gray-100 bg-white flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<h3 class="text-[17px] font-extrabold text-[#1a2b49] leading-tight">
Lịch sử cấp phát thẻ
</h3>
<x-month-filter :mode="$mode" :user="$user" :selectedMonth="$selectedMonth" />
</div>
<div class="p-0 overflow-y-auto max-h-[600px]">
<table class="min-w-full divide-y divide-gray-100 text-sm">
<thead class="bg-gray-50/50 sticky top-0">
<tr>
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Ngày cấp</th>
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Người cấp (Admin)</th>
<th class="px-6 py-4 text-left text-xs font-bold text-text-light uppercase tracking-wider">Số lượng thẻ</th>
<th class="px-6 py-4 text-center text-xs font-bold text-text-light uppercase tracking-wider w-24">Hành động</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-100">
@forelse($addCards as $addCard)
@php
$isCurrentMonth = Carbon\Carbon::parse($addCard->date)->format('Y-m') === Carbon\Carbon::now()->format('Y-m');
@endphp
<tr class="hover:bg-slate-50/60 transition-colors">
<td class="px-6 py-3.5 whitespace-nowrap text-text-medium font-medium">{{ Carbon\Carbon::parse($addCard->date)->format('d/m/Y') }}</td>
<td class="px-6 py-3.5 whitespace-nowrap font-bold text-[#1a2b49]">
@if($addCard->sellerUser)
<span class="text-[#3462f7]">{{ $addCard->sellerUser->name }}</span>
<div class="text-[11px] text-gray-400 font-medium mt-1.5 leading-none">
MSNV: {{ $addCard->sellerUser->msnv }} {{ $addCard->sellerUser->mail }}
</div>
@else
MSNV: {{ $addCard->seller }}
@endif
</td>
<td class="px-6 py-3.5 whitespace-nowrap font-extrabold text-base text-green-600">+{{ $addCard->num_card }}</td>
<td class="px-6 py-3.5 whitespace-nowrap text-center">
@if($isCurrentMonth)
<button type="button" onclick="openEditAddCardModal({{ json_encode($addCard) }})" class="text-blue-600 hover:text-blue-900 font-bold transition-colors">Sửa</button>
@else
<span class="text-gray-400 font-semibold text-xs cursor-not-allowed" title="Không thể chỉnh sửa giao dịch tháng trước">Tháng trước</span>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="4" class="px-6 py-12 text-center text-text-light font-medium text-base">
Chưa lịch sử cấp phát thẻ nào.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="px-6 py-4 bg-slate-50 border-t border-gray-100 flex justify-end">
<button type="button" onclick="openAddCardModal()" class="inline-flex items-center gap-2 bg-[#3462f7] hover:bg-blue-700 text-white font-bold text-sm px-5 py-2.5 rounded-xl shadow-md shadow-blue-500/10 transition-all">
Thêm thẻ
</button>
</div>
</div>
@endif
</div>
@endif
</div>
@endif
@if($mode === 'edit' && isset($addCards) && isset($admins))
<x-modal id="editAddCardModal" title="Chỉnh sửa giao dịch cấp phát thẻ">
<form id="editAddCardForm" method="POST" action="">
@csrf
@method('PUT')
<div class="mb-5">
<label for="modal_num_card" class="block text-sm font-bold text-[#1a2b49] mb-2">Số lượng card</label>
<input type="number" id="modal_num_card" name="num_card" min="1" required class="w-full border border-[#d9dfe7] rounded-xl px-4 py-2.5 text-sm focus:border-[#3462f7] focus:ring focus:ring-[#3462f7]/20 outline-none transition-all">
</div>
<div class="mb-5">
<label for="modal_seller" class="block text-sm font-bold text-[#1a2b49] mb-2">Người cấp (Admin)</label>
<select id="modal_seller" name="seller" required class="w-full border border-[#d9dfe7] bg-white rounded-xl px-4 py-2.5 text-sm focus:border-[#3462f7] focus:ring focus:ring-[#3462f7]/20 outline-none transition-all">
@foreach($admins as $admin)
<option value="{{ $admin->msnv }}">{{ $admin->name }} (MSNV: {{ $admin->msnv }})</option>
@endforeach
</select>
</div>
<div class="mb-6">
<label for="modal_date" class="block text-sm font-bold text-[#1a2b49] mb-2">Ngày cấp</label>
<input type="date" id="modal_date" name="date" required min="{{ Carbon\Carbon::now()->startOfMonth()->format('Y-m-d') }}" max="{{ Carbon\Carbon::now()->endOfMonth()->format('Y-m-d') }}" class="w-full border border-[#d9dfe7] rounded-xl px-4 py-2.5 text-sm focus:border-[#3462f7] focus:ring focus:ring-[#3462f7]/20 outline-none transition-all">
</div>
<div class="flex justify-end gap-3 pt-4 border-t border-gray-100">
<button type="button" onclick="closeModal('editAddCardModal')" class="inline-flex items-center justify-center bg-white border border-[#d9dfe7] hover:bg-gray-50 text-[#1a2b49] font-bold py-2.5 px-6 rounded-xl text-sm transition-colors shadow-sm min-w-[120px] h-[42px]">Hủy bỏ</button>
<button type="submit" class="inline-flex items-center justify-center bg-[#3462f7] hover:bg-blue-700 text-white font-bold py-2.5 px-6 rounded-xl text-sm transition-colors shadow-md shadow-blue-500/10 min-w-[120px] h-[42px]">Lưu thay đổi</button>
</div>
</form>
</x-modal>
<x-modal id="addCardModal" title="Cấp phát thêm thẻ cho user">
<form id="addCardForm" method="POST" action="{{ route('admin.users.update', $user->msnv) }}">
@csrf
@method('PUT')
<div class="mb-6">
<label for="add_modal_num_card" class="block text-sm font-bold text-[#1a2b49] mb-2">Số lượng card cấp phát thêm</label>
<input type="number" id="add_modal_num_card" name="num_card" min="1" required class="w-full border border-[#d9dfe7] rounded-xl px-4 py-2.5 text-sm focus:border-[#3462f7] focus:ring focus:ring-[#3462f7]/20 outline-none transition-all" placeholder="VD: 5">
</div>
<div class="flex justify-end gap-3 pt-4 border-t border-gray-100">
<button type="button" onclick="closeModal('addCardModal')" class="inline-flex items-center justify-center bg-white border border-[#d9dfe7] hover:bg-gray-50 text-[#1a2b49] font-bold py-2.5 px-6 rounded-xl text-sm transition-colors shadow-sm min-w-[120px] h-[42px]">Hủy bỏ</button>
<button type="submit" class="inline-flex items-center justify-center bg-[#3462f7] hover:bg-blue-700 text-white font-bold py-2.5 px-6 rounded-xl text-sm transition-colors shadow-md shadow-blue-500/10 min-w-[120px] h-[42px]">Xác nhận</button>
</div>
</form>
</x-modal>
<script>
function openEditAddCardModal(record) {
const form = document.getElementById('editAddCardForm');
form.action = `/admin/add-cards/${record.id}`;
document.getElementById('modal_num_card').value = record.num_card;
document.getElementById('modal_seller').value = record.seller;
if (record.date) {
document.getElementById('modal_date').value = record.date.substring(0, 10);
}
openModal('editAddCardModal');
}
function openAddCardModal() {
document.getElementById('add_modal_num_card').value = '';
openModal('addCardModal');
}
async function submitModalForm(e, formId, modalId) {
e.preventDefault();
const form = document.getElementById(formId);
const submitBtn = form.querySelector('button[type="submit"]');
if (submitBtn) submitBtn.disabled = true;
try {
const formData = new FormData(form);
const response = await fetch(form.action, {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: formData
});
const result = await response.json();
if (response.ok && result.success) {
closeModal(modalId);
if (window.showToast) {
window.showToast(result.message || 'Thành công!');
}
if (result.card_balance !== undefined) {
const balanceEl = document.getElementById('user-card-balance');
if (balanceEl) {
balanceEl.textContent = result.card_balance;
}
}
await reloadListsSection();
} else {
alert(result.message || 'Đã xảy ra lỗi. Vui lòng thử lại.');
}
} catch (err) {
console.error(err);
alert('Đã xảy ra lỗi kết nối.');
} finally {
if (submitBtn) submitBtn.disabled = false;
}
}
async function reloadListsSection() {
try {
const response = await fetch(window.location.href, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const newLists = doc.getElementById('history-lists-container');
const currentLists = document.getElementById('history-lists-container');
if (newLists && currentLists) {
currentLists.innerHTML = newLists.innerHTML;
}
const newBalance = doc.getElementById('user-card-balance');
const currentBalance = document.getElementById('user-card-balance');
if (newBalance && currentBalance) {
currentBalance.textContent = newBalance.textContent;
}
}
} catch (err) {
console.error('Failed to reload list section:', err);
}
}
function bindFormEvents() {
const addForm = document.getElementById('addCardForm');
if (addForm) {
addForm.addEventListener('submit', (e) => submitModalForm(e, 'addCardForm', 'addCardModal'));
}
const editForm = document.getElementById('editAddCardForm');
if (editForm) {
editForm.addEventListener('submit', (e) => submitModalForm(e, 'editAddCardForm', 'editAddCardModal'));
}
}
if (document.readyState !== 'loading') {
bindFormEvents();
} else {
document.addEventListener('DOMContentLoaded', bindFormEvents);
}
</script>
@endif