Files
thankcard-system/resources/views/user/send.blade.php
T
2026-07-14 16:23:04 +07:00

319 lines
18 KiB
PHP

@extends('layouts.app')
@section('title', 'Gửi Thank Card')
@section('content')
@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="max-w-[760px] mx-auto w-full pb-12 px-4 lg:px-0">
{{-- 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>
</x-modal>
@endsection
@push('scripts')
<script src="{{ asset('js/jquery.min.js') }}"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// ── 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'},
};
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');
$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;
}
// ── 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