m
This commit is contained in:
@@ -38,15 +38,27 @@
|
||||
</x-stat-card>
|
||||
|
||||
|
||||
<x-stat-card
|
||||
title="Thứ hạng"
|
||||
value="#{{ $currentRank > 0 ? $currentRank : '-' }}"
|
||||
iconBgClass="bg-green-50"
|
||||
iconColorClass="text-green-500">
|
||||
<svg class="w-[26px] h-[26px]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
</x-stat-card>
|
||||
@if(Auth::check() && Auth::user()->role == config('constants.ROLE_ADMIN'))
|
||||
<x-stat-card
|
||||
title="Thứ hạng"
|
||||
value="#{{ $currentRank > 0 ? $currentRank : '-' }}"
|
||||
iconBgClass="bg-green-50"
|
||||
iconColorClass="text-green-500">
|
||||
<svg class="w-[26px] h-[26px]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
</x-stat-card>
|
||||
@else
|
||||
<x-stat-card
|
||||
title="Thứ hạng"
|
||||
value="Không có quyền xem"
|
||||
iconBgClass="bg-amber-50"
|
||||
iconColorClass="text-amber-500">
|
||||
<svg class="w-[26px] h-[26px]" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
||||
</svg>
|
||||
</x-stat-card>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-6 lg:flex-row lg:items-stretch lg:gap-8">
|
||||
@@ -96,39 +108,86 @@
|
||||
|
||||
<div class="w-full lg:w-[32%] lg:min-w-[340px] lg:max-w-[400px] flex flex-col gap-6">
|
||||
|
||||
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] p-6 flex flex-col h-full">
|
||||
<div class="bg-white rounded-[24px] shadow-[0_10px_30px_rgba(15,23,42,0.05)] p-6 flex flex-col h-full relative overflow-hidden">
|
||||
<div class="flex items-center justify-between mb-3 pl-1 pr-1">
|
||||
<h3 class="text-[17px] font-extrabold text-[#1a2b49]">Bảng xếp hạng</h3>
|
||||
<a href="{{ route('user.ranking') }}" class="text-[13px] font-bold text-[#3462f7] hover:text-blue-800">Xem tất cả</a>
|
||||
@if(Auth::check() && Auth::user()->role == config('constants.ROLE_ADMIN'))
|
||||
<a href="{{ route('user.ranking') }}" class="text-[13px] font-bold text-[#3462f7] hover:text-blue-800">Xem tất cả</a>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="inline-flex bg-[#F5F7FB] rounded-xl p-1 mb-4 w-fit space-x-2">
|
||||
<button id="tab-received" onclick="switchRankingTab('received')" class="cursor-pointer flex items-center justify-center gap-2 w-[120px] py-2 rounded-[10px] transition-all bg-white shadow-[0_2px_4px_rgba(0,0,0,0.04)] text-[#3462f7] font-bold text-[14px]">
|
||||
<svg class="w-[18px] h-[18px]" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M17.5 4h-11c-1.38 0-2.5 1.12-2.5 2.5V8c0 2.21 1.79 4 4 4h.34c1.17 2.19 3.52 3.56 6.16 3.56s4.99-1.37 6.16-3.56h.34c2.21 0 4-1.79 4-4v-1.5c0-1.38-1.12-2.5-2.5-2.5zm-11 6c-.55 0-1-.45-1-1V6.5c0-.28.22-.5.5-.5h2v4H6.5zm11 0h-2v-4h2c.28 0 .5.22.5.5V9c0 .55-.45 1-1 1zM11 16h2v4H-2v-4zm-2 4h6v2H9v-2z"/>
|
||||
<path fill="#ffffff" d="M12 11.5L10 7h4z"/>
|
||||
</svg>
|
||||
TOP Nhận
|
||||
</button>
|
||||
<button id="tab-sent" onclick="switchRankingTab('sent')" class="cursor-pointer flex items-center justify-center gap-2 w-[120px] py-2 rounded-[10px] transition-all text-[#64748b] hover:text-gray-800 font-bold text-[14px]">
|
||||
<svg class="w-[18px] h-[18px]" fill="none" stroke="currentColor" stroke-width="2.2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 2L11 13"></path>
|
||||
<path d="M22 2L15 22L11 13L2 9L22 2Z"></path>
|
||||
</svg>
|
||||
TOP Gửi
|
||||
</button>
|
||||
</div>
|
||||
@if(Auth::check() && Auth::user()->role == config('constants.ROLE_ADMIN'))
|
||||
<div class="inline-flex bg-[#F5F7FB] rounded-xl p-1 mb-4 w-fit space-x-2">
|
||||
<button id="tab-received" onclick="switchRankingTab('received')" class="cursor-pointer flex items-center justify-center gap-2 w-[120px] py-2 rounded-[10px] transition-all bg-white shadow-[0_2px_4px_rgba(0,0,0,0.04)] text-[#3462f7] font-bold text-[14px]">
|
||||
<svg class="w-[18px] h-[18px]" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M17.5 4h-11c-1.38 0-2.5 1.12-2.5 2.5V8c0 2.21 1.79 4 4 4h.34c1.17 2.19 3.52 3.56 6.16 3.56s4.99-1.37 6.16-3.56h.34c2.21 0 4-1.79 4-4v-1.5c0-1.38-1.12-2.5-2.5-2.5zm-11 6c-.55 0-1-.45-1-1V6.5c0-.28.22-.5.5-.5h2v4H6.5zm11 0h-2v-4h2c.28 0 .5.22.5.5V9c0 .55-.45 1-1 1zM11 16h2v4H-2v-4zm-2 4h6v2H9v-2z"/>
|
||||
<path fill="#ffffff" d="M12 11.5L10 7h4z"/>
|
||||
</svg>
|
||||
TOP Nhận
|
||||
</button>
|
||||
<button id="tab-sent" onclick="switchRankingTab('sent')" class="cursor-pointer flex items-center justify-center gap-2 w-[120px] py-2 rounded-[10px] transition-all text-[#64748b] hover:text-gray-800 font-bold text-[14px]">
|
||||
<svg class="w-[18px] h-[18px]" fill="none" stroke="currentColor" stroke-width="2.2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 2L11 13"></path>
|
||||
<path d="M22 2L15 22L11 13L2 9L22 2Z"></path>
|
||||
</svg>
|
||||
TOP Gửi
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="ranking-list-container" class="flex-1 flex flex-col mb-2">
|
||||
<!-- Pre-rendered ranking lists -->
|
||||
<div id="ranking-received-content" class="flex-1 flex flex-col">
|
||||
@include('user.partials.ranking_list', ['rankers' => array_slice($receivedRankers, 0, 4), 'currentUserRankItem' => $receivedCurrentUserRankItem])
|
||||
<div id="ranking-list-container" class="flex-1 flex flex-col mb-2">
|
||||
<!-- Pre-rendered ranking lists -->
|
||||
<div id="ranking-received-content" class="flex-1 flex flex-col">
|
||||
@include('user.partials.ranking_list', ['rankers' => array_slice($receivedRankers, 0, 4), 'currentUserRankItem' => $receivedCurrentUserRankItem])
|
||||
</div>
|
||||
<div id="ranking-sent-content" class="hidden flex-1 flex flex-col">
|
||||
@include('user.partials.ranking_list', ['rankers' => array_slice($sentRankers, 0, 4), 'currentUserRankItem' => $sentCurrentUserRankItem])
|
||||
</div>
|
||||
</div>
|
||||
<div id="ranking-sent-content" class="hidden flex-1 flex flex-col">
|
||||
@include('user.partials.ranking_list', ['rankers' => array_slice($sentRankers, 0, 4), 'currentUserRankItem' => $sentCurrentUserRankItem])
|
||||
@else
|
||||
<div class="relative flex-1 flex flex-col h-full min-h-[220px]">
|
||||
<!-- Blur container -->
|
||||
<div class="filter blur-[5px] select-none pointer-events-none opacity-40 flex-1 flex flex-col">
|
||||
<div class="inline-flex bg-[#F5F7FB] rounded-xl p-1 mb-4 w-fit space-x-2">
|
||||
<button class="flex items-center justify-center gap-2 w-[120px] py-2 rounded-[10px] bg-white text-[#3462f7] font-bold text-[14px]">TOP Nhận</button>
|
||||
<button class="flex items-center justify-center gap-2 w-[120px] py-2 rounded-[10px] text-[#64748b] font-bold text-[14px]">TOP Gửi</button>
|
||||
</div>
|
||||
<div class="space-y-3.5">
|
||||
<div class="flex items-center gap-3 p-3 rounded-2xl bg-gray-50/80 border border-gray-100">
|
||||
<div class="w-10 h-10 bg-gray-200 rounded-full"></div>
|
||||
<div class="flex-1 space-y-2">
|
||||
<div class="h-3.5 bg-gray-200 rounded w-24"></div>
|
||||
<div class="h-2.5 bg-gray-200 rounded w-16"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 p-3 rounded-2xl bg-gray-50/80 border border-gray-100">
|
||||
<div class="w-10 h-10 bg-gray-200 rounded-full"></div>
|
||||
<div class="flex-1 space-y-2">
|
||||
<div class="h-3.5 bg-gray-200 rounded w-28"></div>
|
||||
<div class="h-2.5 bg-gray-200 rounded w-12"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 p-3 rounded-2xl bg-gray-50/80 border border-gray-100">
|
||||
<div class="w-10 h-10 bg-gray-200 rounded-full"></div>
|
||||
<div class="flex-1 space-y-2">
|
||||
<div class="h-3.5 bg-gray-200 rounded w-20"></div>
|
||||
<div class="h-2.5 bg-gray-200 rounded w-14"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Overlay -->
|
||||
<div class="absolute inset-0 flex flex-col items-center justify-center bg-white/40 backdrop-blur-[1px] rounded-2xl z-10 p-4 text-center">
|
||||
<div class="w-14 h-14 bg-amber-500 text-white rounded-full flex items-center justify-center shadow-lg shadow-amber-500/30 mb-3.5 transform transition-transform hover:scale-105 duration-300">
|
||||
<svg class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h4 class="text-sm font-extrabold text-[#1a2b49] mb-1">Không có quyền xem</h4>
|
||||
<p class="text-[11px] text-gray-500 font-semibold max-w-[200px] leading-relaxed">Bảng xếp hạng đã bị ẩn với tài khoản thành viên.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -142,6 +201,8 @@
|
||||
const receivedContent = document.getElementById('ranking-received-content');
|
||||
const sentContent = document.getElementById('ranking-sent-content');
|
||||
|
||||
if (!receivedTab || !sentTab || !receivedContent || !sentContent) return;
|
||||
|
||||
const activeClass = 'flex items-center justify-center gap-2 w-[120px] py-2 rounded-[10px] transition-all bg-white shadow-[0_2px_4px_rgba(0,0,0,0.04)] text-[#3462f7] font-bold text-[14px]';
|
||||
const inactiveClass = 'flex items-center justify-center gap-2 w-[120px] py-2 rounded-[10px] transition-all text-[#64748b] hover:text-gray-800 font-bold text-[14px]';
|
||||
|
||||
|
||||
@@ -1,20 +1,31 @@
|
||||
@php
|
||||
$themes = config('card_themes');
|
||||
@endphp
|
||||
|
||||
@foreach ($cards as $c)
|
||||
<div class="bg-white rounded-[24px] border border-gray-100 p-6 shadow-sm hover:shadow-md hover:border-[#8b5cf6] hover:-translate-y-1 transition-all duration-300 flex flex-col justify-between h-full group">
|
||||
@php
|
||||
$themeId = $c->template_id ?? 1;
|
||||
$theme = $themes[$themeId] ?? $themes[1];
|
||||
@endphp
|
||||
<div class="rounded-[24px] border p-6 shadow-sm hover:shadow-md hover:-translate-y-1 transition-all duration-300 flex flex-col justify-between h-full group"
|
||||
style="background: {{ $theme['card_bg'] }}; border-color: {{ $theme['border_color'] }};">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<span class="text-xs font-bold text-gray-400 flex items-center gap-1.5">
|
||||
<span class="text-[14px]">💜</span> Từ
|
||||
<span class="text-[14px]">{{ $theme['icon'] }}</span> Từ
|
||||
</span>
|
||||
<span class="text-[11px] font-extrabold text-[#6d28d9] bg-[#f5f3ff] px-2 py-0.5 rounded-full">
|
||||
{{ $c->received }} Thẻ
|
||||
<span class="text-[11px] font-extrabold px-2.5 py-0.5 rounded-full"
|
||||
style="background-color: {{ $theme['badge_bg'] }}; color: {{ $theme['accent_color'] }};">
|
||||
{{ $c->received }} Thẻ ({{ $theme['name'] }})
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-start gap-3.5">
|
||||
<div class="relative shrink-0">
|
||||
@if($c->senderUser)
|
||||
<x-avatar :user="$c->senderUser" class="w-12 h-12 rounded-full object-cover border-2 border-purple-50" />
|
||||
<x-avatar :user="$c->senderUser" class="w-12 h-12 rounded-full object-cover border-2" style="border-color: {{ $theme['border_color'] }};" />
|
||||
@else
|
||||
<div class="w-12 h-12 rounded-full bg-gray-50 border border-gray-200 flex items-center justify-center font-bold text-gray-400">
|
||||
<div class="w-12 h-12 rounded-full bg-gray-50/50 border flex items-center justify-center font-bold text-gray-400"
|
||||
style="border-color: {{ $theme['border_color'] }};">
|
||||
{{ strtoupper(substr($c->sender ?? 'U', 0, 1)) }}
|
||||
</div>
|
||||
@endif
|
||||
@@ -33,9 +44,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between pt-4 border-t border-gray-50 text-[11px] font-semibold text-gray-400 mt-6">
|
||||
<div class="flex items-center justify-between pt-4 border-t text-[11px] font-semibold text-gray-400 mt-6"
|
||||
style="border-top-color: {{ $theme['footer_border'] }}; border-top-style: dashed;">
|
||||
<span>Ngày nhận:</span>
|
||||
<span>{{ \Carbon\Carbon::parse($c->date)->format('d/m/Y') }}</span>
|
||||
<span class="font-bold" style="color: {{ $theme['accent_color'] }};">{{ \Carbon\Carbon::parse($c->date)->format('d/m/Y') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@@ -1,20 +1,31 @@
|
||||
@php
|
||||
$themes = config('card_themes');
|
||||
@endphp
|
||||
|
||||
@foreach ($cards as $c)
|
||||
<div class="bg-white rounded-[24px] border border-gray-100 p-6 shadow-sm hover:shadow-md hover:border-[#3462f7] hover:-translate-y-1 transition-all duration-300 flex flex-col justify-between h-full group">
|
||||
@php
|
||||
$themeId = $c->template_id ?? 1;
|
||||
$theme = $themes[$themeId] ?? $themes[1];
|
||||
@endphp
|
||||
<div class="rounded-[24px] border p-6 shadow-sm hover:shadow-md hover:-translate-y-1 transition-all duration-300 flex flex-col justify-between h-full group"
|
||||
style="background: {{ $theme['card_bg'] }}; border-color: {{ $theme['border_color'] }};">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<span class="text-xs font-bold text-gray-400 flex items-center gap-1.5">
|
||||
<span class="text-[14px]">💌</span> Gửi tới
|
||||
<span class="text-[14px]">{{ $theme['icon'] }}</span> Gửi tới
|
||||
</span>
|
||||
<span class="text-[11px] font-extrabold text-blue-600 bg-blue-50 px-2 py-0.5 rounded-full">
|
||||
{{ $c->sent }} Thẻ
|
||||
<span class="text-[11px] font-extrabold px-2.5 py-0.5 rounded-full"
|
||||
style="background-color: {{ $theme['badge_bg'] }}; color: {{ $theme['accent_color'] }};">
|
||||
{{ $c->sent }} Thẻ ({{ $theme['name'] }})
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-start gap-3.5">
|
||||
<div class="relative shrink-0">
|
||||
@if($c->receiverUser)
|
||||
<x-avatar :user="$c->receiverUser" class="w-12 h-12 rounded-full object-cover border-2 border-blue-50" />
|
||||
<x-avatar :user="$c->receiverUser" class="w-12 h-12 rounded-full object-cover border-2" style="border-color: {{ $theme['border_color'] }};" />
|
||||
@else
|
||||
<div class="w-12 h-12 rounded-full bg-gray-50 border border-gray-200 flex items-center justify-center font-bold text-gray-400">
|
||||
<div class="w-12 h-12 rounded-full bg-gray-50/50 border flex items-center justify-center font-bold text-gray-400"
|
||||
style="border-color: {{ $theme['border_color'] }};">
|
||||
{{ strtoupper(substr($c->receiver ?? 'U', 0, 1)) }}
|
||||
</div>
|
||||
@endif
|
||||
@@ -33,9 +44,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between pt-4 border-t border-gray-50 text-[11px] font-semibold text-gray-400 mt-6">
|
||||
<div class="flex items-center justify-between pt-4 border-t text-[11px] font-semibold text-gray-400 mt-6"
|
||||
style="border-top-color: {{ $theme['footer_border'] }}; border-top-style: dashed;">
|
||||
<span>Ngày gửi:</span>
|
||||
<span>{{ \Carbon\Carbon::parse($c->date)->format('d/m/Y') }}</span>
|
||||
<span class="font-bold" style="color: {{ $theme['accent_color'] }};">{{ \Carbon\Carbon::parse($c->date)->format('d/m/Y') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<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>
|
||||
<img src="{{ asset('images/illustrations/trophy.svg') }}" alt="trophy" class="absolute right-4 bottom-0 w-40 h-40 md:w-56 md:h-56 opacity-20 pointer-events-none">
|
||||
</div>
|
||||
|
||||
<!-- Month Filter -->
|
||||
@@ -147,8 +146,13 @@
|
||||
|
||||
{{-- 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">
|
||||
@foreach($group as $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">
|
||||
@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">
|
||||
@@ -160,6 +164,30 @@
|
||||
</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
|
||||
@@ -274,8 +302,13 @@
|
||||
|
||||
{{-- 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">
|
||||
@foreach($group as $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">
|
||||
@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">
|
||||
@@ -287,6 +320,30 @@
|
||||
</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
|
||||
@@ -307,6 +364,12 @@
|
||||
.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
|
||||
@@ -344,5 +407,18 @@
|
||||
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
|
||||
|
||||
@@ -3,12 +3,7 @@
|
||||
|
||||
@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'],
|
||||
];
|
||||
$tpls = config('card_themes');
|
||||
@endphp
|
||||
|
||||
<div class="max-w-[760px] mx-auto w-full pb-12 px-4 lg:px-0">
|
||||
@@ -184,32 +179,25 @@ $tpls = [
|
||||
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'},
|
||||
};
|
||||
const cardThemesData = @json(config('card_themes'));
|
||||
const T = {};
|
||||
Object.keys(cardThemesData).forEach(id => {
|
||||
const item = cardThemesData[id];
|
||||
T[id] = {
|
||||
icon: item.icon,
|
||||
name: item.name,
|
||||
label: item.label,
|
||||
deco: item.deco_bg,
|
||||
card: item.card_bg,
|
||||
border: item.border_color,
|
||||
blob1: item.blob1,
|
||||
blob2: item.blob2,
|
||||
accent: item.accent_color,
|
||||
badgeBg: item.badge_bg,
|
||||
wave: item.wave,
|
||||
footerBorder: item.footer_border
|
||||
};
|
||||
});
|
||||
|
||||
// ── Theme slugs ──────────────────────────────────────────────────
|
||||
const templateSlugs = {
|
||||
@@ -541,7 +529,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
$.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}),
|
||||
data:JSON.stringify({
|
||||
receiver: msnv,
|
||||
amount: amount,
|
||||
template_id: parseInt(document.getElementById('template_id').value, 10)
|
||||
}),
|
||||
success:function(res){
|
||||
if(res.success){
|
||||
setButtonLoading(false);
|
||||
|
||||
Reference in New Issue
Block a user