425 lines
30 KiB
PHP
425 lines
30 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', 'Bảng xếp hạng')
|
|
|
|
@section('content')
|
|
<div class="max-w-[1280px] mx-auto w-full pb-16 px-4 lg:px-8">
|
|
|
|
<div class="relative overflow-hidden rounded-[32px] mb-10 shadow-[0_8px_32px_rgba(0,0,0,0.04)]" style="background: linear-gradient(135deg, #f5f7ff 0%, #e0e7ff 100%);">
|
|
<x-hero-banner>
|
|
<h2 class="text-[32px] md:text-[42px] font-extrabold text-[#1a2b49] mb-3 drop-shadow-sm">🏆 Bảng xếp hạng</h2>
|
|
<p class="text-[16px] md:text-[18px] text-gray-700 mb-4 max-w-2xl">Tôn vinh những cá nhân lan tỏa văn hóa cảm ơn và ghi nhận trong tổ chức.</p>
|
|
</x-hero-banner>
|
|
</div>
|
|
|
|
<!-- Month Filter -->
|
|
<div class="flex justify-start mb-8">
|
|
<form method="GET" class="flex items-center gap-4 bg-white p-3 md:p-4 pr-6 rounded-[24px] shadow-[0_4px_12px_rgba(0,0,0,0.03)] border border-gray-100 transition-all hover:shadow-md">
|
|
<div class="w-12 h-12 rounded-full bg-blue-50 flex items-center justify-center text-[#3462f7]">
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<label for="month" class="block text-xs font-extrabold text-gray-400 uppercase tracking-wider mb-1">Lọc theo tháng</label>
|
|
<input type="month" id="month" name="month" class="block w-full border-0 bg-transparent p-0 text-lg font-bold text-[#1a2b49] focus:ring-0 cursor-pointer" value="{{ $selectedMonth }}" onchange="this.form.submit()" />
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="flex justify-center mb-10">
|
|
<div class="inline-flex bg-[#F5F7FB] rounded-[20px] p-1.5 shadow-inner border border-gray-100">
|
|
<button id="tab-btn-received" onclick="switchRankingTab('received')" class="tab-btn bg-white shadow-[0_4px_12px_rgba(0,0,0,0.05)] text-primary px-10 py-4 rounded-[20px] font-bold text-[18px] transition-all duration-300 flex items-center gap-2">
|
|
<span class="text-xl">📥</span> TOP Nhận
|
|
</button>
|
|
<button id="tab-btn-sent" onclick="switchRankingTab('sent')" class="tab-btn text-gray-500 hover:text-gray-800 hover:bg-gray-50 px-10 py-4 rounded-[20px] font-bold text-[18px] transition-all duration-300 flex items-center gap-2">
|
|
<span class="text-xl">📤</span> TOP Gửi
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div id="ranking-content-container">
|
|
|
|
|
|
<div id="content-received" class="tab-content block animate-fade-in">
|
|
|
|
@if(!empty($receivedRankers) && count($receivedRankers) >= 3)
|
|
<div class="flex justify-center items-end gap-4 md:gap-10 mb-12 pt-8">
|
|
|
|
<div class="flex flex-col items-center group relative z-10">
|
|
<div class="relative w-24 h-24 md:w-28 md:h-28 mb-4 transition-transform duration-300 group-hover:-translate-y-2">
|
|
<div class="absolute inset-0 bg-gray-200 rounded-full animate-pulse opacity-20"></div>
|
|
<img src="{{ $receivedRankers[1]->avatar ?? asset('images/avatar.png') }}" class="w-full h-full object-cover rounded-full shadow-[0_8px_24px_rgba(0,0,0,0.12)] border-4 border-white">
|
|
<div class="absolute -bottom-3 left-1/2 transform -translate-x-1/2 bg-gradient-to-r from-gray-100 to-gray-300 rounded-full px-3 py-0.5 shadow-md border border-gray-200 flex items-center gap-1 text-sm font-bold text-gray-700">
|
|
🥈 #2
|
|
</div>
|
|
</div>
|
|
<span class="font-bold text-[#1a2b49] text-center text-sm md:text-base">{{ $receivedRankers[1]->name ?? '---' }}</span>
|
|
<span class="text-xs md:text-sm text-gray-500 text-center">{{ $receivedRankers[1]->department ?? '' }}</span>
|
|
<span class="text-sm font-extrabold text-primary mt-1">{{ $receivedRankers[1]->score ?? 0 }} thẻ</span>
|
|
</div>
|
|
|
|
|
|
<div class="flex flex-col items-center group relative z-20">
|
|
<div class="absolute -top-10 text-4xl animate-bounce">👑</div>
|
|
<div class="relative w-32 h-32 md:w-40 md:h-40 mb-4 transition-transform duration-300 group-hover:-translate-y-3">
|
|
<div class="absolute inset-0 bg-yellow-300 rounded-full animate-pulse opacity-20"></div>
|
|
<img src="{{ $receivedRankers[0]->avatar ?? asset('images/avatar.png') }}" class="w-full h-full object-cover rounded-full shadow-[0_12px_32px_rgba(250,204,21,0.3)] border-4 border-yellow-400">
|
|
<div class="absolute -bottom-4 left-1/2 transform -translate-x-1/2 bg-gradient-to-r from-yellow-300 to-yellow-500 rounded-full px-4 py-1 shadow-lg border border-yellow-200 flex items-center gap-1 text-base font-extrabold text-yellow-900">
|
|
🥇 #1
|
|
</div>
|
|
</div>
|
|
<span class="font-extrabold text-[#1a2b49] text-center text-lg md:text-xl">{{ $receivedRankers[0]->name ?? '---' }}</span>
|
|
<span class="text-sm text-gray-500 text-center">{{ $receivedRankers[0]->department ?? '' }}</span>
|
|
<span class="text-lg font-extrabold text-yellow-500 mt-1">{{ $receivedRankers[0]->score ?? 0 }} thẻ</span>
|
|
</div>
|
|
|
|
|
|
<div class="flex flex-col items-center group relative z-10">
|
|
<div class="relative w-24 h-24 md:w-28 md:h-28 mb-4 transition-transform duration-300 group-hover:-translate-y-2">
|
|
<div class="absolute inset-0 bg-orange-200 rounded-full animate-pulse opacity-20"></div>
|
|
<img src="{{ $receivedRankers[2]->avatar ?? asset('images/avatar.png') }}" class="w-full h-full object-cover rounded-full shadow-[0_8px_24px_rgba(0,0,0,0.12)] border-4 border-white">
|
|
<div class="absolute -bottom-3 left-1/2 transform -translate-x-1/2 bg-gradient-to-r from-orange-200 to-orange-400 rounded-full px-3 py-0.5 shadow-md border border-orange-200 flex items-center gap-1 text-sm font-bold text-orange-900">
|
|
🥉 #3
|
|
</div>
|
|
</div>
|
|
<span class="font-bold text-[#1a2b49] text-center text-sm md:text-base">{{ $receivedRankers[2]->name ?? '---' }}</span>
|
|
<span class="text-xs md:text-sm text-gray-500 text-center">{{ $receivedRankers[2]->department ?? '' }}</span>
|
|
<span class="text-sm font-extrabold text-primary mt-1">{{ $receivedRankers[2]->score ?? 0 }} thẻ</span>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
|
|
@if($receivedCurrentUserRankItem)
|
|
<div class="max-w-xl mx-auto mb-12 bg-white rounded-[24px] p-5 shadow-[0_8px_24px_rgba(52,98,247,0.08)] border border-blue-100 flex items-center justify-between transform transition-all hover:scale-[1.02]">
|
|
<div class="flex items-center gap-4">
|
|
<div class="relative">
|
|
<x-avatar :user="$receivedCurrentUserRankItem" class="w-16 h-16" />
|
|
<div class="absolute -bottom-2 -right-2 bg-primary w-8 h-8 rounded-full flex items-center justify-center text-white text-xs font-bold border-2 border-white shadow-sm">
|
|
#{{ $receivedCurrentUserRankItem->rank }}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-bold tracking-wider text-gray-400 uppercase mb-1">Thành tích của bạn (Nhận)</p>
|
|
<p class="font-extrabold text-[#1a2b49] text-xl">{{ $receivedCurrentUserRankItem->name }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="text-right">
|
|
<p class="text-xl font-black text-primary">{{ $receivedCurrentUserRankItem->score }}</p>
|
|
<p class="text-xs font-medium text-gray-500 uppercase">Thẻ</p>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- 6. ĐỒNG HẠNG & LEADERBOARD CARDS --}}
|
|
<div class="space-y-6">
|
|
@php
|
|
$groupedReceived = collect($receivedRankers ?? [])->groupBy('rank');
|
|
@endphp
|
|
@if($groupedReceived->count() > 0)
|
|
@foreach($groupedReceived as $rank => $group)
|
|
<div class="bg-white rounded-[24px] shadow-[0_4px_20px_rgba(0,0,0,0.03)] border border-gray-50 overflow-hidden">
|
|
{{-- Group Header --}}
|
|
<div class="bg-[#F8FAFC] px-6 py-4 flex items-center justify-between border-b border-gray-100">
|
|
<div class="flex items-center gap-3">
|
|
@if($rank == 1)
|
|
<span class="text-3xl filter drop-shadow-sm">🥇</span>
|
|
@elseif($rank == 2)
|
|
<span class="text-3xl filter drop-shadow-sm">🥈</span>
|
|
@elseif($rank == 3)
|
|
<span class="text-3xl filter drop-shadow-sm">🥉</span>
|
|
@else
|
|
<div class="w-10 h-10 bg-white rounded-full flex items-center justify-center font-bold text-gray-500 shadow-sm border border-gray-100">#{{ $rank }}</div>
|
|
@endif
|
|
<div>
|
|
<h3 class="text-lg font-extrabold text-[#1a2b49]">Hạng #{{ $rank }}</h3>
|
|
<p class="text-sm text-gray-500">{{ $group->count() }} người đồng hạng</p>
|
|
</div>
|
|
</div>
|
|
<div class="text-right">
|
|
<span class="text-primary font-black text-lg">{{ $group->first()->score }}</span>
|
|
<span class="text-sm font-bold text-gray-400">thẻ</span>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Users in Group --}}
|
|
<div class="p-6 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
|
@php
|
|
$total = $group->count();
|
|
$desktopLimit = $total > 12 ? 11 : 12;
|
|
$mobileLimit = $total > 4 ? 3 : 4;
|
|
@endphp
|
|
@foreach($group as $index => $user)
|
|
<div class="group user-card bg-white rounded-[16px] p-4 flex items-center gap-4 transition-all duration-300 hover:-translate-y-1 hover:shadow-[0_12px_24px_rgba(0,0,0,0.06)] border border-gray-100 cursor-default relative overflow-hidden @if($index >= $desktopLimit) hide-all @elseif($index >= $mobileLimit) hide-mobile @endif">
|
|
<div class="absolute inset-0 bg-gradient-to-r from-blue-50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
|
<x-avatar :user="$user" class="w-12 h-12" />
|
|
<div class="flex-1 min-w-0 relative z-10">
|
|
<p class="font-bold text-[#1a2b49] leading-tight line-clamp-2 group-hover:text-primary transition-colors">{{ $user->name }}</p>
|
|
<div class="mt-1 flex flex-col gap-0.5">
|
|
<p class="text-[11px] font-medium text-gray-500 uppercase tracking-wide">MSNV: {{ $user->msnv ?? '---' }}</p>
|
|
<p class="text-[11px] text-gray-400 truncate">{{ $user->department ?? $user->mail ?? '---' }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
|
|
@if($total > 4)
|
|
{{-- Mobile Xem Them Button --}}
|
|
<button type="button" class="xem-them-btn-mobile md:hidden flex flex-col items-center justify-center bg-white rounded-[16px] border border-gray-200 border-dashed hover:border-primary hover:bg-blue-50 transition-all p-4 text-primary font-bold min-h-[80px]" onclick="expandGroup(this)">
|
|
<div class="flex items-center gap-1 mb-1 text-lg">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path></svg>
|
|
<span>+{{ $total - 3 }}</span>
|
|
</div>
|
|
<span class="text-xs">Xem thêm</span>
|
|
</button>
|
|
@endif
|
|
|
|
@if($total > 12)
|
|
{{-- Desktop Xem Them Button --}}
|
|
<button type="button" class="xem-them-btn-desktop hidden md:flex flex-col items-center justify-center bg-white rounded-[16px] border border-gray-200 border-dashed hover:border-primary hover:bg-blue-50 transition-all p-4 text-primary font-bold min-h-[80px]" onclick="expandGroup(this)">
|
|
<div class="flex items-center gap-1 mb-1 text-lg">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path></svg>
|
|
<span>+{{ $total - 11 }}</span>
|
|
</div>
|
|
<span class="text-xs">Xem thêm</span>
|
|
</button>
|
|
@endif
|
|
|
|
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
@else
|
|
<x-empty-state title="Chưa có dữ liệu" description="Chưa có dữ liệu Bảng xếp hạng Nhận." icon="hero"/>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div id="content-sent" class="tab-content hidden animate-fade-in">
|
|
|
|
@if(!empty($sentRankers) && count($sentRankers) >= 3)
|
|
<div class="flex justify-center items-end gap-4 md:gap-10 mb-12 pt-8">
|
|
|
|
<div class="flex flex-col items-center group relative z-10">
|
|
<div class="relative w-24 h-24 md:w-28 md:h-28 mb-4 transition-transform duration-300 group-hover:-translate-y-2">
|
|
<div class="absolute inset-0 bg-gray-200 rounded-full animate-pulse opacity-20"></div>
|
|
<img src="{{ $sentRankers[1]->avatar ?? asset('images/avatar.png') }}" class="w-full h-full object-cover rounded-full shadow-[0_8px_24px_rgba(0,0,0,0.12)] border-4 border-white">
|
|
<div class="absolute -bottom-3 left-1/2 transform -translate-x-1/2 bg-gradient-to-r from-gray-100 to-gray-300 rounded-full px-3 py-0.5 shadow-md border border-gray-200 flex items-center gap-1 text-sm font-bold text-gray-700">
|
|
🥈 #2
|
|
</div>
|
|
</div>
|
|
<span class="font-bold text-[#1a2b49] text-center text-sm md:text-base">{{ $sentRankers[1]->name ?? '---' }}</span>
|
|
<span class="text-xs md:text-sm text-gray-500 text-center">{{ $sentRankers[1]->department ?? '' }}</span>
|
|
<span class="text-sm font-extrabold text-primary mt-1">{{ $sentRankers[1]->score ?? 0 }} thẻ</span>
|
|
</div>
|
|
|
|
|
|
<div class="flex flex-col items-center group relative z-20">
|
|
<div class="absolute -top-10 text-4xl animate-bounce">👑</div>
|
|
<div class="relative w-32 h-32 md:w-40 md:h-40 mb-4 transition-transform duration-300 group-hover:-translate-y-3">
|
|
<div class="absolute inset-0 bg-yellow-300 rounded-full animate-pulse opacity-20"></div>
|
|
<img src="{{ $sentRankers[0]->avatar ?? asset('images/avatar.png') }}" class="w-full h-full object-cover rounded-full shadow-[0_12px_32px_rgba(250,204,21,0.3)] border-4 border-yellow-400">
|
|
<div class="absolute -bottom-4 left-1/2 transform -translate-x-1/2 bg-gradient-to-r from-yellow-300 to-yellow-500 rounded-full px-4 py-1 shadow-lg border border-yellow-200 flex items-center gap-1 text-base font-extrabold text-yellow-900">
|
|
🥇 #1
|
|
</div>
|
|
</div>
|
|
<span class="font-extrabold text-[#1a2b49] text-center text-lg md:text-xl">{{ $sentRankers[0]->name ?? '---' }}</span>
|
|
<span class="text-sm text-gray-500 text-center">{{ $sentRankers[0]->department ?? '' }}</span>
|
|
<span class="text-lg font-extrabold text-yellow-500 mt-1">{{ $sentRankers[0]->score ?? 0 }} thẻ</span>
|
|
</div>
|
|
|
|
|
|
<div class="flex flex-col items-center group relative z-10">
|
|
<div class="relative w-24 h-24 md:w-28 md:h-28 mb-4 transition-transform duration-300 group-hover:-translate-y-2">
|
|
<div class="absolute inset-0 bg-orange-200 rounded-full animate-pulse opacity-20"></div>
|
|
<img src="{{ $sentRankers[2]->avatar ?? asset('images/avatar.png') }}" class="w-full h-full object-cover rounded-full shadow-[0_8px_24px_rgba(0,0,0,0.12)] border-4 border-white">
|
|
<div class="absolute -bottom-3 left-1/2 transform -translate-x-1/2 bg-gradient-to-r from-orange-200 to-orange-400 rounded-full px-3 py-0.5 shadow-md border border-orange-200 flex items-center gap-1 text-sm font-bold text-orange-900">
|
|
🥉 #3
|
|
</div>
|
|
</div>
|
|
<span class="font-bold text-[#1a2b49] text-center text-sm md:text-base">{{ $sentRankers[2]->name ?? '---' }}</span>
|
|
<span class="text-xs md:text-sm text-gray-500 text-center">{{ $sentRankers[2]->department ?? '' }}</span>
|
|
<span class="text-sm font-extrabold text-primary mt-1">{{ $sentRankers[2]->score ?? 0 }} thẻ</span>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
|
|
@if($sentCurrentUserRankItem)
|
|
<div class="max-w-xl mx-auto mb-12 bg-white rounded-[24px] p-5 shadow-[0_8px_24px_rgba(52,98,247,0.08)] border border-blue-100 flex items-center justify-between transform transition-all hover:scale-[1.02]">
|
|
<div class="flex items-center gap-4">
|
|
<div class="relative">
|
|
<x-avatar :user="$sentCurrentUserRankItem" class="w-16 h-16" />
|
|
<div class="absolute -bottom-2 -right-2 bg-primary w-8 h-8 rounded-full flex items-center justify-center text-white text-xs font-bold border-2 border-white shadow-sm">
|
|
#{{ $sentCurrentUserRankItem->rank }}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs font-bold tracking-wider text-gray-400 uppercase mb-1">Thành tích của bạn (Gửi)</p>
|
|
<p class="font-extrabold text-[#1a2b49] text-xl">{{ $sentCurrentUserRankItem->name }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="text-right">
|
|
<p class="text-xl font-black text-primary">{{ $sentCurrentUserRankItem->score }}</p>
|
|
<p class="text-xs font-medium text-gray-500 uppercase">Thẻ</p>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- 6. ĐỒNG HẠNG & LEADERBOARD CARDS --}}
|
|
<div class="space-y-6">
|
|
@php
|
|
$groupedSent = collect($sentRankers ?? [])->groupBy('rank');
|
|
@endphp
|
|
@if($groupedSent->count() > 0)
|
|
@foreach($groupedSent as $rank => $group)
|
|
<div class="bg-white rounded-[24px] shadow-[0_4px_20px_rgba(0,0,0,0.03)] border border-gray-50 overflow-hidden">
|
|
{{-- Group Header --}}
|
|
<div class="bg-[#F8FAFC] px-6 py-4 flex items-center justify-between border-b border-gray-100">
|
|
<div class="flex items-center gap-3">
|
|
@if($rank == 1)
|
|
<span class="text-3xl filter drop-shadow-sm">🥇</span>
|
|
@elseif($rank == 2)
|
|
<span class="text-3xl filter drop-shadow-sm">🥈</span>
|
|
@elseif($rank == 3)
|
|
<span class="text-3xl filter drop-shadow-sm">🥉</span>
|
|
@else
|
|
<div class="w-10 h-10 bg-white rounded-full flex items-center justify-center font-bold text-gray-500 shadow-sm border border-gray-100">#{{ $rank }}</div>
|
|
@endif
|
|
<div>
|
|
<h3 class="text-lg font-extrabold text-[#1a2b49]">Hạng #{{ $rank }}</h3>
|
|
<p class="text-sm text-gray-500">{{ $group->count() }} người đồng hạng</p>
|
|
</div>
|
|
</div>
|
|
<div class="text-right">
|
|
<span class="text-primary font-black text-lg">{{ $group->first()->score }}</span>
|
|
<span class="text-sm font-bold text-gray-400">thẻ</span>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Users in Group --}}
|
|
<div class="p-6 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
|
@php
|
|
$total = $group->count();
|
|
$desktopLimit = $total > 12 ? 11 : 12;
|
|
$mobileLimit = $total > 4 ? 3 : 4;
|
|
@endphp
|
|
@foreach($group as $index => $user)
|
|
<div class="group bg-white rounded-[16px] p-4 flex items-center gap-4 transition-all duration-300 hover:-translate-y-1 hover:shadow-[0_12px_24px_rgba(0,0,0,0.06)] border border-gray-100 cursor-default relative overflow-hidden @if($index >= $desktopLimit) hide-all @elseif($index >= $mobileLimit) hide-mobile @endif">
|
|
<div class="absolute inset-0 bg-gradient-to-r from-purple-50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
|
<x-avatar :user="$user" class="w-12 h-12" />
|
|
<div class="flex-1 min-w-0 relative z-10">
|
|
<p class="font-bold text-[#1a2b49] leading-tight line-clamp-2 group-hover:text-primary transition-colors">{{ $user->name }}</p>
|
|
<div class="mt-1 flex flex-col gap-0.5">
|
|
<p class="text-[11px] font-medium text-gray-500 uppercase tracking-wide">MSNV: {{ $user->msnv ?? '---' }}</p>
|
|
<p class="text-[11px] text-gray-400 truncate">{{ $user->department ?? $user->mail ?? '---' }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
|
|
@if($total > 4)
|
|
{{-- Mobile Xem Them Button --}}
|
|
<button type="button" class="xem-them-btn-mobile md:hidden flex flex-col items-center justify-center bg-white rounded-[16px] border border-gray-200 border-dashed hover:border-primary hover:bg-blue-50 transition-all p-4 text-primary font-bold min-h-[80px]" onclick="expandGroup(this)">
|
|
<div class="flex items-center gap-1 mb-1 text-lg">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path></svg>
|
|
<span>+{{ $total - 3 }}</span>
|
|
</div>
|
|
<span class="text-xs">Xem thêm</span>
|
|
</button>
|
|
@endif
|
|
|
|
@if($total > 12)
|
|
{{-- Desktop Xem Them Button --}}
|
|
<button type="button" class="xem-them-btn-desktop hidden md:flex flex-col items-center justify-center bg-white rounded-[16px] border border-gray-200 border-dashed hover:border-primary hover:bg-blue-50 transition-all p-4 text-primary font-bold min-h-[80px]" onclick="expandGroup(this)">
|
|
<div class="flex items-center gap-1 mb-1 text-lg">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path></svg>
|
|
<span>+{{ $total - 11 }}</span>
|
|
</div>
|
|
<span class="text-xs">Xem thêm</span>
|
|
</button>
|
|
@endif
|
|
|
|
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
@else
|
|
<x-empty-state title="Chưa có dữ liệu" description="Chưa có dữ liệu Bảng xếp hạng Gửi." icon="hero"/>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(10px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
.animate-fade-in {
|
|
animation: fadeIn 0.4s ease-out forwards;
|
|
}
|
|
|
|
/* Custom classes for hiding excess items */
|
|
.hide-all { display: none !important; }
|
|
@media (max-width: 767px) {
|
|
.hide-mobile { display: none !important; }
|
|
}
|
|
</style>
|
|
|
|
@endsection
|
|
|
|
@push('scripts')
|
|
<script>
|
|
function switchRankingTab(tab) {
|
|
const btnReceived = document.getElementById('tab-btn-received');
|
|
const btnSent = document.getElementById('tab-btn-sent');
|
|
const contentReceived = document.getElementById('content-received');
|
|
const contentSent = document.getElementById('content-sent');
|
|
|
|
const activeClasses = ['bg-white', 'shadow-[0_4px_12px_rgba(0,0,0,0.05)]', 'text-primary'];
|
|
const inactiveClasses = ['text-gray-500', 'hover:text-gray-800', 'hover:bg-gray-50'];
|
|
|
|
if (tab === 'received') {
|
|
btnReceived.classList.add(...activeClasses);
|
|
btnReceived.classList.remove(...inactiveClasses);
|
|
btnSent.classList.add(...inactiveClasses);
|
|
btnSent.classList.remove(...activeClasses);
|
|
|
|
contentReceived.classList.remove('hidden');
|
|
contentReceived.classList.add('block');
|
|
contentSent.classList.remove('block');
|
|
contentSent.classList.add('hidden');
|
|
} else {
|
|
btnSent.classList.add(...activeClasses);
|
|
btnSent.classList.remove(...inactiveClasses);
|
|
btnReceived.classList.add(...inactiveClasses);
|
|
btnReceived.classList.remove(...activeClasses);
|
|
|
|
contentSent.classList.remove('hidden');
|
|
contentSent.classList.add('block');
|
|
contentReceived.classList.remove('block');
|
|
contentReceived.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
function expandGroup(btn) {
|
|
const container = btn.closest('.grid');
|
|
const hiddenItems = container.querySelectorAll('.hide-all, .hide-mobile');
|
|
|
|
hiddenItems.forEach(el => {
|
|
el.classList.remove('hide-all', 'hide-mobile');
|
|
});
|
|
|
|
// Hide all xem-them buttons in this container
|
|
const btns = container.querySelectorAll('.xem-them-btn-mobile, .xem-them-btn-desktop');
|
|
btns.forEach(b => b.style.display = 'none');
|
|
}
|
|
</script>
|
|
@endpush
|