feature: send thankscard page

This commit is contained in:
antv
2026-07-14 16:23:04 +07:00
parent 3aa9e04bd7
commit 05605ed1eb
28 changed files with 536 additions and 297 deletions
+296 -168
View File
@@ -2,189 +2,317 @@
@section('title', 'Gửi Thank Card')
@section('content')
<div class="max-w-[640px] mx-auto w-full pb-10">
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] border border-white overflow-hidden">
<div class="bg-gradient-to-r from-[#eff4ff] to-[#faeffa] px-8 py-8 flex flex-col relative overflow-hidden">
<div class="absolute -top-10 -right-10 w-32 h-32 bg-white/30 rounded-full blur-xl"></div>
<div class="absolute -bottom-10 -left-10 w-24 h-24 bg-white/20 rounded-full blur-lg"></div>
<div class="relative z-10 flex items-center gap-3">
<h3 class="text-[22px] font-extrabold text-[#1a2b49] tracking-tight">Gửi Thank Card</h3>
<span class="text-xl animate-pulse">💌</span>
</div>
<p class="text-[13px] text-gray-500 font-medium mt-1.5 relative z-10">
Gửi gắm lời cảm ơn chân thành đến người đồng nghiệp tuyệt vời của bạn!
</p>
</div>
<form id="sendCardForm">
@csrf
<div class="p-8 space-y-6">
<div class="flex flex-col gap-2">
<label class="text-[14px] font-bold text-text-dark" for="receiver">
Chọn người nhận <span class="text-red-500">*</span>
</label>
<select name="receiver" id="receiver" class="form-input rounded-xl border-[#d9dfe7]" required>
<option value="" disabled selected>-- Chọn đồng nghiệp --</option>
@foreach($users as $u)
<option value="{{ $u->msnv }}">{{ $u->name }} - {{ $u->msnv }} ({{ $u->mail }})</option>
@endforeach
</select>
</div>
@php
$tpls = [
1=>['icon'=>'💌','name'=>'Thư cảm ơn', 'thumb'=>'from-[#FFF9EC] to-[#FFF5DD]','thumbAccent'=>'#FFD066'],
2=>['icon'=>'🌸','name'=>'Sakura', 'thumb'=>'from-[#FFF5F9] to-[#FFECF4]','thumbAccent'=>'#F9A8D4'],
3=>['icon'=>'⭐','name'=>'Appreciation','thumb'=>'from-[#EFF8FF] to-[#DBEAFE]','thumbAccent'=>'#93C5FD'],
4=>['icon'=>'🎉','name'=>'Celebration', 'thumb'=>'from-[#F5F0FF] to-[#EDE9FE]','thumbAccent'=>'#C4B5FD'],
];
@endphp
<div class="flex flex-col gap-2">
<label class="text-[14px] font-bold text-text-dark" for="amount">
Số lượng thẻ <span class="text-red-500">*</span>
</label>
<select name="amount" id="amount" class="form-input rounded-xl border-[#d9dfe7]" required>
<option value="1">1 Thẻ</option>
<option value="2">2 Thẻ</option>
<option value="3">3 Thẻ</option>
<option value="4">4 Thẻ</option>
<option value="{{ \App\Models\Administration::MAX_SEND_CARD_PER_MONTH }}">{{ \App\Models\Administration::MAX_SEND_CARD_PER_MONTH }} Thẻ (Tối đa)</option>
</select>
<div class="mt-1 flex items-start gap-2 bg-[#eff4ff] p-3.5 rounded-xl border border-blue-50">
<svg class="w-5 h-5 text-[#3462f7] shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<p class="text-[12px] text-gray-600 font-medium leading-relaxed">
Lưu ý: Chỉ được gửi tối đa {{ \App\Models\Administration::MAX_SEND_CARD_PER_MONTH }} thẻ cho cùng 1 người trong 1 tháng để đảm bảo tính công bằng.
</p>
</div>
</div>
<div class="max-w-[760px] mx-auto w-full pb-12 px-4 lg:px-0">
<div class="flex flex-col gap-2 pt-2">
<div class="flex items-center gap-3 bg-gray-50/50 p-4 rounded-xl border border-[#d9dfe7]/60 hover:bg-gray-50 transition-colors">
<input type="checkbox" name="confirm_written" id="confirm_written" value="1" class="w-5 h-5 text-[#3462f7] border-[#d9dfe7] rounded-md focus:ring-[#3462f7]/20 transition-all cursor-pointer" required>
<label for="confirm_written" class="text-[13px] font-medium text-gray-700 cursor-pointer select-none">
Xác nhận đã viết card <span class="text-red-500">*</span>
</label>
</div>
</div>
</div>
<div class="px-8 py-5 border-t border-[#d9dfe7]/50 bg-gray-50/50 flex flex-col sm:flex-row justify-end gap-3">
<a href="{{ route('user.dashboard') }}" class="btn-secondary rounded-xl font-bold">Hủy bỏ</a>
<button type="button" id="btnSubmitSend" class="btn-primary rounded-xl font-bold !bg-[#3462f7] hover:!bg-blue-700 shadow-md shadow-blue-500/10">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor" class="w-4 h-4 mr-2">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5" />
</svg>
Gửi Card
</button>
</div>
</form>
{{-- Header --}}
<div class="relative bg-gradient-to-r from-[#eff4ff] to-[#faeffa] rounded-[24px] p-7 md:p-10 mb-7 overflow-hidden border border-white shadow-[0_10px_30px_rgba(15,23,42,0.05)]">
<div class="absolute -top-10 -right-10 w-44 h-44 bg-white/25 rounded-full blur-2xl"></div>
<div class="absolute -bottom-8 -left-8 w-32 h-32 bg-white/20 rounded-full blur-xl"></div>
<div class="relative z-10 flex items-center gap-4">
<div class="w-14 h-14 rounded-2xl bg-white/80 shadow-sm flex items-center justify-center text-3xl shrink-0">💌</div>
<div>
<h1 class="text-[26px] md:text-[30px] font-extrabold text-[#1a2b49] tracking-tight leading-tight">Gửi Thank Card</h1>
<p class="text-[14px] text-gray-500 font-medium mt-1 max-w-[380px] leading-relaxed">Gửi lời cảm ơn chân thành đến đồng nghiệp lan tỏa văn hóa ghi nhận trong tổ chức.</p>
</div>
</div>
</div>
<form id="sendCardForm">
@csrf
<input type="hidden" name="template_id" id="template_id" value="1">
{{-- Template Gallery --}}
<div class="bg-white rounded-[20px] shadow-[0_4px_20px_rgba(15,23,42,0.06)] border border-[#f0f4fa] p-6 mb-5">
<p class="text-[13px] font-bold text-gray-400 uppercase tracking-widest mb-4">Chọn mẫu thiệp <span class="text-[#3462f7]">*</span></p>
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3">
@foreach($tpls as $id => $t)
<button type="button" onclick="selectTpl(this,{{$id}})"
data-tpl="{{$id}}"
class="tpl-btn relative group flex flex-col items-center gap-2 p-4 rounded-2xl border-2 transition-all duration-200 bg-gradient-to-br {{$t['thumb']}} cursor-pointer
{{$loop->first ? 'border-[#3462f7] ring-2 ring-[#3462f7]/20 shadow-md' : 'border-[#e8edf4] hover:border-[#3462f7]/40 hover:shadow-md'}}">
<span class="tpl-check absolute top-2 right-2 w-5 h-5 rounded-full bg-[#3462f7] flex items-center justify-center {{$loop->first ? 'opacity-100':'opacity-0'}} transition-opacity duration-200">
<svg class="w-3 h-3 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="3"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg>
</span>
<span class="text-3xl group-hover:scale-110 transition-transform duration-200 select-none">{{$t['icon']}}</span>
<span class="text-[12px] font-bold text-[#1a2b49] text-center leading-tight">{{$t['name']}}</span>
</button>
@endforeach
</div>
</div>
{{-- e-Card (form inside the card) --}}
<div id="eCard" class="relative rounded-[24px] overflow-hidden shadow-[0_20px_60px_rgba(15,23,42,0.12)] border-2 mb-5 transition-all duration-500"
style="background:linear-gradient(145deg,#FFF9EC,#FFFDF7);border-color:#FFE4A0;">
{{-- Decorative SVG top --}}
<div id="cardDeco" class="relative overflow-hidden" style="height:140px;background:linear-gradient(135deg,#FFF5CC,#FFE8A0);">
{{-- blob 1 --}}
<div class="absolute -top-8 -left-8 w-36 h-36 rounded-full opacity-40 blur-2xl" id="blob1" style="background:#FFD066;"></div>
<div class="absolute -bottom-6 -right-6 w-28 h-28 rounded-full opacity-30 blur-xl" id="blob2" style="background:#FFAD00;"></div>
{{-- SVG decoration --}}
<div id="decoSvg" class="absolute inset-0 flex items-center justify-center select-none pointer-events-none">
{{-- Template 1 default: envelope --}}
<div class="flex flex-col items-center gap-1 z-10">
<span id="cardBigIcon" class="text-[72px] leading-none drop-shadow-lg" style="filter:drop-shadow(0 4px 16px rgba(0,0,0,0.10))">💌</span>
<span id="cardLabel" class="text-[13px] font-bold uppercase tracking-[0.2em] mt-1" style="color:#B8860B;">Thank Card</span>
</div>
</div>
{{-- wavy bottom --}}
<svg class="absolute bottom-0 left-0 w-full" viewBox="0 0 760 30" preserveAspectRatio="none" style="height:30px;">
<path id="wavePath" d="M0,20 Q190,0 380,20 Q570,40 760,20 L760,30 L0,30 Z" fill="white" opacity="0.8"/>
</svg>
</div>
{{-- Card body: form fields ON the card --}}
<div class="px-8 py-7 bg-white/0">
{{-- To: Người nhận --}}
<div class="mb-6">
<label class="block text-[11px] font-bold uppercase tracking-widest mb-2" id="labelTo" style="color:#B8860B;"> Gửi đến</label>
<select name="receiver" id="receiver" class="form-input rounded-xl border-[#e8edf4] bg-white/90" required>
<option value="" disabled selected></option>
@foreach($users as $u)
@php $dept=$u->department_name??'Team'; @endphp
<option value="{{$u->msnv}}">{{$u->name}} - {{$u->msnv}} ({{$u->mail}}) - {{$dept}}</option>
@endforeach
</select>
</div>
{{-- Số lượng --}}
<div class="mb-6">
<label class="block text-[11px] font-bold uppercase tracking-widest mb-2" id="labelQty" style="color:#B8860B;">🎴 Số lượng thẻ</label>
<div class="flex items-center gap-3">
<select name="amount" id="amount" class="form-input rounded-xl border-[#e8edf4] bg-white/90 !w-auto !px-5" required>
<option value="1">1 Thẻ</option>
<option value="2">2 Thẻ</option>
<option value="3">3 Thẻ</option>
<option value="4">4 Thẻ</option>
<option value="{{App\Models\Administration::MAX_SEND_CARD_PER_MONTH}}">{{App\Models\Administration::MAX_SEND_CARD_PER_MONTH}} Thẻ (Tối đa)</option>
</select>
<span class="text-[12px] text-gray-400 font-medium">/ tháng</span>
</div>
</div>
{{-- Confirm checkbox --}}
<label class="flex items-start gap-3 p-4 rounded-2xl border border-[#e8edf4] bg-white/70 hover:bg-white/90 transition-colors cursor-pointer mb-2">
<input type="checkbox" name="confirm_written" id="confirm_written" value="1"
class="w-4 h-4 mt-0.5 text-[#3462f7] border-[#d9dfe7] rounded focus:ring-[#3462f7]/20 cursor-pointer shrink-0" required>
<span class="text-[13px] font-medium text-gray-600 leading-relaxed select-none">
Tôi xác nhận đã viết nội dung trên ThankCard sẵn sàng gửi đến người nhận. <span class="text-[#3462f7] font-bold">*</span>
</span>
</label>
{{-- Card footer line --}}
<div class="mt-6 pt-4 border-t border-dashed" id="cardFooterLine" style="border-color:#FFE4A0;">
<div class="flex items-center justify-between">
<span class="text-[11px] text-gray-400 font-medium">Từ: <span class="font-bold text-gray-500">{{ Auth::user()->name ?? 'Bạn' }}</span></span>
<span id="cardFooterBadge" class="text-[10px] font-bold px-2.5 py-1 rounded-full" style="background:rgba(255,176,0,0.15);color:#B8860B;">Thư cảm ơn</span>
</div>
</div>
</div>
</div>
{{-- Info note --}}
<div class="flex items-start gap-3 bg-gradient-to-r from-[#eff4ff] to-[#f5f0ff] p-4 rounded-2xl border border-[#dce7ff] mb-5">
<div class="w-8 h-8 rounded-xl bg-white flex items-center justify-center shrink-0 shadow-sm">
<svg class="w-4 h-4 text-[#3462f7]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
</div>
<div>
<p class="text-[12px] font-bold text-[#3462f7] mb-0.5">Lưu ý</p>
<p class="text-[13px] text-gray-600 font-medium leading-relaxed">Chỉ được gửi tối đa <strong>{{ App\Models\Administration::MAX_SEND_CARD_PER_MONTH }} thẻ</strong> cho cùng một người trong tháng để đảm bảo tính công bằng.</p>
</div>
</div>
{{-- Actions --}}
<div class="flex flex-col sm:flex-row justify-end gap-3">
<a href="{{ route('user.dashboard') }}" class="btn-secondary rounded-xl font-bold flex items-center justify-center gap-2 order-2 sm:order-1">
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18"/></svg>Hủy bỏ
</a>
<button type="button" id="btnSubmitSend" class="btn-primary rounded-xl font-bold !bg-[#3462f7] hover:!bg-blue-700 shadow-md shadow-blue-500/15 flex items-center justify-center gap-2 order-1 sm:order-2">
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5"/></svg>Gửi Card
</button>
</div>
</form>
</div>
<x-modal id="customModal" title="Thông báo" maxWidth="md">
<p id="modalMessage" class="text-sm text-gray-600 leading-relaxed"></p>
<x-slot name="footer">
<div id="modalActions" class="w-full flex flex-col sm:flex-row-reverse gap-3">
</div>
</x-slot>
<p id="modalMessage" class="text-sm text-gray-600 leading-relaxed"></p>
<x-slot name="footer">
<div id="modalActions" class="w-full flex flex-col sm:flex-row-reverse gap-3"></div>
</x-slot>
</x-modal>
@endsection
@push('scripts')
<script src="{{ asset('js/jquery.min.js') }}"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
new TomSelect("#receiver", {
create: false,
sortField: {
field: "text",
direction: "asc"
},
placeholder: "🔍 Nhập tên, mã NV hoặc email...",
render: {
no_results: function(data, escape) {
return '<div class="no-results p-3 text-gray-500">Không tìm thấy nhân viên nào</div>';
}
}
});
document.addEventListener('DOMContentLoaded', function() {
const btnSubmit = document.getElementById('btnSubmitSend');
const form = document.getElementById('sendCardForm');
const modalTitle = document.getElementById('modal-title-customModal');
const modalMessage = document.getElementById('modalMessage');
const modalActions = document.getElementById('modalActions');
// ── Theme data ───────────────────────────────────────────────────
const T = {
1:{icon:'💌',name:'Thư cảm ơn', label:'THANK CARD',
deco:'linear-gradient(135deg,#FFF5CC,#FFE8A0)',
card:'linear-gradient(145deg,#FFF9EC,#FFFDF7)',
border:'#FFE4A0', blob1:'#FFD066', blob2:'#FFAD00',
accent:'#B8860B', badgeBg:'rgba(255,176,0,0.15)', wave:'white',
footerBorder:'#FFE4A0'},
2:{icon:'🌸',name:'Sakura', label:'SAKURA CARD',
deco:'linear-gradient(135deg,#FFE8F4,#FFD6EC)',
card:'linear-gradient(145deg,#FFF8FB,#FFF3F8)',
border:'#FFBCD9', blob1:'#F9A8D4', blob2:'#F472B6',
accent:'#be185d', badgeBg:'rgba(244,114,182,0.12)', wave:'white',
footerBorder:'#FFBCD9'},
3:{icon:'⭐',name:'Appreciation',label:'APPRECIATION',
deco:'linear-gradient(135deg,#DBEAFE,#BFDBFE)',
card:'linear-gradient(145deg,#F0F8FF,#EAF3FF)',
border:'#BFDBFE', blob1:'#93C5FD', blob2:'#60A5FA',
accent:'#1d4ed8', badgeBg:'rgba(96,165,250,0.12)', wave:'white',
footerBorder:'#BFDBFE'},
4:{icon:'🎉',name:'Celebration', label:'CELEBRATION',
deco:'linear-gradient(135deg,#EDE9FE,#DDD6FE)',
card:'linear-gradient(145deg,#F8F5FF,#F3EFFF)',
border:'#DDD6FE', blob1:'#C4B5FD', blob2:'#A78BFA',
accent:'#6d28d9', badgeBg:'rgba(167,139,250,0.12)', wave:'white',
footerBorder:'#DDD6FE'},
};
const showModal = (title, message, isConfirm, confirmCallback) => {
modalTitle.textContent = title;
modalMessage.innerHTML = message;
if(isConfirm) {
modalTitle.className = "text-lg font-bold text-primary";
modalActions.innerHTML = `
<button id="btnConfirmOk" class="w-full sm:w-auto btn-primary !px-6 shadow-sm rounded-xl font-bold">Xác nhận gửi</button>
<button id="btnCancel" class="w-full sm:w-auto btn-secondary !px-6 shadow-sm rounded-xl font-bold">Hủy</button>
`;
document.getElementById('btnCancel').addEventListener('click', () => window.closeModal('customModal'));
document.getElementById('btnConfirmOk').addEventListener('click', function() {
this.disabled = true;
this.innerHTML = '<span class="flex items-center gap-2"><svg class="animate-spin h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Đang xử lý...</span>';
confirmCallback();
});
} else {
modalTitle.className = "text-lg font-bold text-red-600";
modalActions.innerHTML = `
<button id="btnOkOnly" class="w-full sm:w-auto btn-secondary !px-6 shadow-sm rounded-xl font-bold">Đóng</button>
`;
document.getElementById('btnOkOnly').addEventListener('click', () => window.closeModal('customModal'));
}
window.openModal('customModal');
};
function applyTheme(id) {
const t = T[id]; if (!t) return;
const $card = document.getElementById('eCard');
const $deco = document.getElementById('cardDeco');
const $b1 = document.getElementById('blob1');
const $b2 = document.getElementById('blob2');
const $bigIcon = document.getElementById('cardBigIcon');
const $label = document.getElementById('cardLabel');
const $wave = document.getElementById('wavePath');
const $lTo = document.getElementById('labelTo');
const $lQty = document.getElementById('labelQty');
const $badge = document.getElementById('cardFooterBadge');
const $footerL = document.getElementById('cardFooterLine');
btnSubmit.addEventListener('click', function() {
if(!form.checkValidity()) {
form.reportValidity();
return;
}
$card.style.background = t.card;
$card.style.borderColor = t.border;
$deco.style.background = t.deco;
$b1.style.background = t.blob1;
$b2.style.background = t.blob2;
$bigIcon.textContent = t.icon;
$label.textContent = t.label;
$label.style.color = t.accent;
$wave.setAttribute('fill', t.wave);
$lTo.style.color = t.accent;
$lQty.style.color = t.accent;
$badge.textContent = t.name;
$badge.style.background = t.badgeBg;
$badge.style.color = t.accent;
$footerL.style.borderColor = t.footerBorder;
}
const receiver = document.getElementById('receiver').value;
const amount = document.getElementById('amount').value;
showModal(
'Xác nhận gửi Thank Card',
`Bạn có chắc chắn muốn gửi <b>${amount} thẻ</b> cho nhân viên <span class="font-bold text-primary">${receiver}</span> không? <br><br><span class="text-xs text-text-light">Hành động này không thể hoàn tác, tin nhắn CO sẽ được gửi đi!</span>`,
true,
() => {
fetch('{{ route('user.store_send') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({
receiver: receiver,
amount: amount
})
})
.then(response => response.json().then(data => ({status: response.status, body: data})))
.then(res => {
if (res.status === 200 && res.body.success) {
alert(res.body.message);
window.location.href = '{{ route('user.dashboard') }}';
} else {
window.closeModal('customModal');
setTimeout(() => {
showModal('Lỗi Giao Dịch', res.body.message || 'Có lỗi xảy ra, vui lòng thử lại.', false, null);
}, 350);
}
})
.catch(err => {
window.closeModal('customModal');
setTimeout(() => {
showModal('Lỗi Hệ Thống', 'Không thể kết nối đến máy chủ.', false, null);
}, 350);
});
}
);
});
// ── Template picker ──────────────────────────────────────────────
window.selectTpl = function(el, id) {
document.querySelectorAll('.tpl-btn').forEach(b => {
b.classList.remove('border-[#3462f7]','ring-2','ring-[#3462f7]/20','shadow-md');
b.classList.add('border-[#e8edf4]');
b.querySelector('.tpl-check').classList.replace('opacity-100','opacity-0');
});
el.classList.remove('border-[#e8edf4]');
el.classList.add('border-[#3462f7]','ring-2','ring-[#3462f7]/20','shadow-md');
el.querySelector('.tpl-check').classList.replace('opacity-0','opacity-100');
document.getElementById('template_id').value = id;
applyTheme(id);
};
applyTheme(1);
// ── TomSelect ────────────────────────────────────────────────────
new TomSelect('#receiver', {
create:false, searchField:['text','value'], maxOptions:10,
sortField:{field:'text',direction:'asc'},
placeholder:'Nhập tên hoặc mã nhân viên...',
render:{
option:function(d,e){
const p=d.text.split(' - '),n=p[0]||'',i=p.slice(1).join(' · ')||'';
return`<div class="px-3 py-2.5 flex flex-col gap-0.5 hover:bg-[#eff4ff] cursor-pointer transition-colors">
<span class="font-bold text-[14px] text-[#1a2b49]">${e(n)}</span>
<span class="text-[11px] text-gray-400">${e(i)}</span></div>`;
},
item:function(d,e){
const n=d.text.split(' - ')[0]||'';
return`<div class="font-semibold text-[14px] text-[#1a2b49]">${e(n)} <span class="text-gray-400 font-normal text-[12px]">(${e(d.value)})</span></div>`;
},
no_results:()=>'<div class="p-3 text-[13px] text-gray-400 text-center">Không tìm thấy nhân viên nào</div>'
}
});
// ── Modal ────────────────────────────────────────────────────────
const $mTitle = document.getElementById('modal-title-customModal');
const $mMsg = document.getElementById('modalMessage');
const $mAct = document.getElementById('modalActions');
const showModal = (title, msg, confirm, cb) => {
$mTitle.textContent = title;
$mMsg.innerHTML = msg.replace(/\n/g,'<br>');
if (confirm) {
$mTitle.className = 'text-lg font-bold text-primary';
$mAct.innerHTML = `<button id="btnOk" class="w-full sm:w-auto btn-primary !px-6 rounded-xl font-bold">Xác nhận gửi</button>
<button id="btnCancel" class="w-full sm:w-auto btn-secondary !px-6 rounded-xl font-bold">Hủy</button>`;
document.getElementById('btnCancel').onclick = () => window.closeModal('customModal');
document.getElementById('btnOk').addEventListener('click', function(){
this.disabled=true;
this.innerHTML='<span class="flex items-center gap-2"><svg class="animate-spin h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg> Đang xử lý...</span>';
cb();
});
} else {
$mTitle.className = 'text-lg font-bold text-[#1a2b49]';
$mAct.innerHTML = `<button id="btnClose" class="w-full sm:w-auto btn-secondary !px-6 rounded-xl font-bold">Đóng</button>`;
document.getElementById('btnClose').onclick = () => window.closeModal('customModal');
}
window.openModal('customModal');
};
// ── Submit ───────────────────────────────────────────────────────
document.getElementById('btnSubmitSend').addEventListener('click', function(){
const form = document.getElementById('sendCardForm');
if (!form.checkValidity()) { form.reportValidity(); return; }
const msnv = document.getElementById('receiver').value;
const amount = document.getElementById('amount').value;
showModal('Xác nhận gửi Thank Card',
'Đừng quên hoàn thành Thank Card của bạn nhé! Chúng mình sẽ gửi thông báo đến người nhận để họ đến khu vực nhận thư.',
true, () => {
$.ajax({
url:'{{ route("user.store_send") }}', method:'POST', contentType:'application/json',
headers:{'X-CSRF-TOKEN':$('meta[name="csrf-token"]').attr('content')},
data:JSON.stringify({receiver:msnv,amount:amount}),
success:function(res){
if(res.success){
var email=res.receiver_email; email="antv@runsystem.net";
$.ajax({
url:'{{ config("constants.CHATOPS_API_URL") }}', method:'POST', contentType:'application/json',
data:JSON.stringify({message:"💌 Bạn nhận được một Thank Card mới!\nNhanh chân đến khu vực nhận thư để nhận ngay nhé!",userEmail:email,token:'{{ config("constants.CHATOPS_API_TOKEN") }}'}),
complete:function(){localStorage.setItem('flash_success',res.message);window.location.href='{{ route("user.dashboard") }}';}
});
} else {
window.closeModal('customModal');
setTimeout(()=>showModal('Lỗi Giao Dịch',res.message||'Có lỗi xảy ra.',false,null),350);
}
},
error:function(xhr){
window.closeModal('customModal');
setTimeout(()=>showModal('Lỗi Hệ Thống',xhr.responseJSON?.message||'Không thể kết nối đến máy chủ.',false,null),350);
}
});
}
);
});
});
</script>
@endpush