diff --git a/app/Http/Controllers/User/UserController.php b/app/Http/Controllers/User/UserController.php
index e4daa62..cd5c596 100644
--- a/app/Http/Controllers/User/UserController.php
+++ b/app/Http/Controllers/User/UserController.php
@@ -31,22 +31,52 @@ class UserController extends Controller
$user = Auth::user();
$administrations = $this->userService->getDashboard($user, $selectedMonth);
- $stats = $this->userService->getPersonalStats($user, $selectedMonth);
- $receivedRanking = $this->userService->getRankingList('received', $selectedMonth, $user);
- $sentRanking = $this->userService->getRankingList('sent', $selectedMonth, $user);
+ $isAdmin = $user->role == config('constants.ROLE_ADMIN');
+
+ if ($isAdmin) {
+ $stats = $this->userService->getPersonalStats($user, $selectedMonth);
+ $receivedRanking = $this->userService->getRankingList('received', $selectedMonth, $user);
+ $sentRanking = $this->userService->getRankingList('sent', $selectedMonth, $user);
+
+ $receivedCount = (int) $stats['receivedCount'];
+ $sentCount = (int) $stats['sentCount'];
+ $currentRank = (int) $stats['currentRank'];
+ $receivedRankers = $receivedRanking['rankers'];
+ $receivedCurrentUserRankItem = $receivedRanking['currentUserRankItem'];
+ $sentRankers = $sentRanking['rankers'];
+ $sentCurrentUserRankItem = $sentRanking['currentUserRankItem'];
+ } else {
+ // For member, do NOT fetch ranking lists or calculate rank to ensure security and improve DB performance
+ $startOfMonth = Carbon::parse($selectedMonth)->startOfMonth();
+ $endOfMonth = Carbon::parse($selectedMonth)->endOfMonth();
+
+ $receivedCount = (int) \App\Models\Administration::where('msnv', $user->msnv)
+ ->whereBetween('date', [$startOfMonth, $endOfMonth])
+ ->sum('received');
+
+ $sentCount = (int) \App\Models\Administration::where('msnv', $user->msnv)
+ ->whereBetween('date', [$startOfMonth, $endOfMonth])
+ ->sum('sent');
+
+ $currentRank = 0;
+ $receivedRankers = [];
+ $receivedCurrentUserRankItem = null;
+ $sentRankers = [];
+ $sentCurrentUserRankItem = null;
+ }
$dashboardData = new DashboardDataDto(
administrations: $administrations,
selectedMonth: $selectedMonth,
user: $user,
- receivedRankers: $receivedRanking['rankers'],
- receivedCurrentUserRankItem: $receivedRanking['currentUserRankItem'],
- sentRankers: $sentRanking['rankers'],
- sentCurrentUserRankItem: $sentRanking['currentUserRankItem'],
- receivedCount: (int) $stats['receivedCount'],
- sentCount: (int) $stats['sentCount'],
- currentRank: (int) $stats['currentRank']
+ receivedRankers: $receivedRankers,
+ receivedCurrentUserRankItem: $receivedCurrentUserRankItem,
+ sentRankers: $sentRankers,
+ sentCurrentUserRankItem: $sentCurrentUserRankItem,
+ receivedCount: $receivedCount,
+ sentCount: $sentCount,
+ currentRank: $currentRank
);
return view('user.dashboard', $dashboardData->toArray());
@@ -86,7 +116,8 @@ class UserController extends Controller
$this->userService->sendThankcards(
Auth::user(),
(string) $request->input('receiver'),
- (int) $request->input('amount')
+ (int) $request->input('amount'),
+ (int) $request->input('template_id', 1)
);
} catch (ThankCardException $e) {
return response()->json(['success' => false, 'message' => $e->getMessage()], 422);
@@ -175,8 +206,12 @@ class UserController extends Controller
}
// New page: ranking (both received and sent) with tabs
- public function ranking(Request $request): View
+ public function ranking(Request $request): \Illuminate\View\View
{
+ if (Auth::user()->role !== config('constants.ROLE_ADMIN')) {
+ abort(404);
+ }
+
$selectedMonth = $request->input('month', Carbon::now()->format('Y-m'));
$user = Auth::user();
$receivedRanking = $this->userService->getRankingList('received', $selectedMonth, $user);
diff --git a/app/Http/Requests/User/SendThankCardRequest.php b/app/Http/Requests/User/SendThankCardRequest.php
index 2d5c7c4..6248722 100644
--- a/app/Http/Requests/User/SendThankCardRequest.php
+++ b/app/Http/Requests/User/SendThankCardRequest.php
@@ -27,6 +27,7 @@ class SendThankCardRequest extends FormRequest
Rule::exists('user', 'msnv')->where('status', config('constants.STATUS_ACTIVE'))
],
'amount' => 'required|integer|min:1|max:' . Administration::MAX_SEND_CARD_PER_MONTH,
+ 'template_id' => 'nullable|integer|in:1,2,3,4',
];
}
diff --git a/app/Models/Administration.php b/app/Models/Administration.php
index 361407d..4a47026 100644
--- a/app/Models/Administration.php
+++ b/app/Models/Administration.php
@@ -22,6 +22,7 @@ class Administration extends Model
'sent',
'receiver',
'date',
+ 'template_id',
];
public function senderUser()
diff --git a/app/Services/User/Contracts/UserServiceInterface.php b/app/Services/User/Contracts/UserServiceInterface.php
index 25680f7..16c4820 100644
--- a/app/Services/User/Contracts/UserServiceInterface.php
+++ b/app/Services/User/Contracts/UserServiceInterface.php
@@ -11,7 +11,7 @@ interface UserServiceInterface
public function getOtherActiveUsers(User $currentUser): \Illuminate\Database\Eloquent\Collection;
- public function sendThankcards(User $sender, string $receiverMsnv, int $amount): void;
+ public function sendThankcards(User $sender, string $receiverMsnv, int $amount, ?int $templateId = 1): void;
public function updatePassword(User $user, string $newPassword): void;
diff --git a/app/Services/User/UserService.php b/app/Services/User/UserService.php
index ee8876f..b3e84b4 100644
--- a/app/Services/User/UserService.php
+++ b/app/Services/User/UserService.php
@@ -33,7 +33,7 @@ class UserService implements UserServiceInterface
->get();
}
- public function sendThankcards(User $sender, string $receiverMsnv, int $amount): void
+ public function sendThankcards(User $sender, string $receiverMsnv, int $amount, ?int $templateId = 1): void
{
if ($sender->flag_send == config('constants.FLAG_SEND_DISABLED')) {
throw new \App\Exceptions\ThankCardException(__('messages.error.no_send_permission'));
@@ -47,7 +47,7 @@ class UserService implements UserServiceInterface
$startOfMonth = Carbon::now()->startOfMonth();
$endOfMonth = Carbon::now()->endOfMonth();
- DB::transaction(function () use ($sender, $receiverMsnv, $amount, $startOfMonth, $endOfMonth) {
+ DB::transaction(function () use ($sender, $receiverMsnv, $amount, $startOfMonth, $endOfMonth, $templateId) {
// Lock sender record to prevent concurrent transaction modifications
$lockedSender = User::where('id', $sender->id)->lockForUpdate()->first();
@@ -76,21 +76,23 @@ class UserService implements UserServiceInterface
}
Administration::create([
- 'msnv' => $receiverMsnv,
- 'received' => $amount,
- 'sender' => $lockedSender->msnv,
- 'sent' => 0,
- 'receiver' => null,
- 'date' => Carbon::today(),
+ 'msnv' => $receiverMsnv,
+ 'received' => $amount,
+ 'sender' => $lockedSender->msnv,
+ 'sent' => 0,
+ 'receiver' => null,
+ 'date' => Carbon::today(),
+ 'template_id' => $templateId,
]);
Administration::create([
- 'msnv' => $lockedSender->msnv,
- 'received' => 0,
- 'sender' => null,
- 'sent' => $amount,
- 'receiver' => $receiverMsnv,
- 'date' => Carbon::today(),
+ 'msnv' => $lockedSender->msnv,
+ 'received' => 0,
+ 'sender' => null,
+ 'sent' => $amount,
+ 'receiver' => $receiverMsnv,
+ 'date' => Carbon::today(),
+ 'template_id' => $templateId,
]);
$lockedSender->card -= $amount;
diff --git a/config/card_themes.php b/config/card_themes.php
new file mode 100644
index 0000000..dc751d5
--- /dev/null
+++ b/config/card_themes.php
@@ -0,0 +1,76 @@
+ [
+ 'id' => 1,
+ 'slug' => 'thu_cam_on',
+ 'name' => 'Thư cảm ơn',
+ 'label' => 'THANK CARD',
+ 'icon' => '💌',
+ 'deco_bg' => 'linear-gradient(135deg,#FFF5CC,#FFE8A0)',
+ 'card_bg' => 'linear-gradient(145deg,#FFF9EC,#FFFDF7)',
+ 'border_color' => '#FFE4A0',
+ 'blob1' => '#FFD066',
+ 'blob2' => '#FFAD00',
+ 'accent_color' => '#B8860B',
+ 'badge_bg' => 'rgba(255,176,0,0.15)',
+ 'wave' => 'white',
+ 'footer_border' => '#FFE4A0',
+ 'thumb' => 'from-[#FFF9EC] to-[#FFF5DD]',
+ 'thumb_accent' => '#FFD066',
+ ],
+ 2 => [
+ 'id' => 2,
+ 'slug' => 'sakura',
+ 'name' => 'Sakura',
+ 'label' => 'SAKURA CARD',
+ 'icon' => '🌸',
+ 'deco_bg' => 'linear-gradient(135deg,#FFE8F4,#FFD6EC)',
+ 'card_bg' => 'linear-gradient(145deg,#FFF8FB,#FFF3F8)',
+ 'border_color' => '#FFBCD9',
+ 'blob1' => '#F9A8D4',
+ 'blob2' => '#F472B6',
+ 'accent_color' => '#be185d',
+ 'badge_bg' => 'rgba(244,114,182,0.12)',
+ 'wave' => 'white',
+ 'footer_border' => '#FFBCD9',
+ 'thumb' => 'from-[#FFF5F9] to-[#FFECF4]',
+ 'thumb_accent' => '#F9A8D4',
+ ],
+ 3 => [
+ 'id' => 3,
+ 'slug' => 'appreciation',
+ 'name' => 'Appreciation',
+ 'label' => 'APPRECIATION',
+ 'icon' => '⭐',
+ 'deco_bg' => 'linear-gradient(135deg,#DBEAFE,#BFDBFE)',
+ 'card_bg' => 'linear-gradient(145deg,#F0F8FF,#EAF3FF)',
+ 'border_color' => '#BFDBFE',
+ 'blob1' => '#93C5FD',
+ 'blob2' => '#60A5FA',
+ 'accent_color' => '#1d4ed8',
+ 'badge_bg' => 'rgba(96,165,250,0.12)',
+ 'wave' => 'white',
+ 'footer_border' => '#BFDBFE',
+ 'thumb' => 'from-[#EFF8FF] to-[#DBEAFE]',
+ 'thumb_accent' => '#93C5FD',
+ ],
+ 4 => [
+ 'id' => 4,
+ 'slug' => 'celebration',
+ 'name' => 'Celebration',
+ 'label' => 'CELEBRATION',
+ 'icon' => '🎉',
+ 'deco_bg' => 'linear-gradient(135deg,#EDE9FE,#DDD6FE)',
+ 'card_bg' => 'linear-gradient(145deg,#F8F5FF,#F3EFFF)',
+ 'border_color' => '#DDD6FE',
+ 'blob1' => '#C4B5FD',
+ 'blob2' => '#A78BFA',
+ 'accent_color' => '#6d28d9',
+ 'badge_bg' => 'rgba(167,139,250,0.12)',
+ 'wave' => 'white',
+ 'footer_border' => '#DDD6FE',
+ 'thumb' => 'from-[#F5F0FF] to-[#EDE9FE]',
+ 'thumb_accent' => '#C4B5FD',
+ ]
+];
diff --git a/config/constants.php b/config/constants.php
index d7cfa5c..989e45f 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -13,6 +13,11 @@ return [
'FIRST_LOGIN_FALSE' => 0,
'FIRST_LOGIN_TRUE' => 1,
+ 'TEMPLATE_THU_CAM_ON' => 1,
+ 'TEMPLATE_SAKURA' => 2,
+ 'TEMPLATE_APPRECIATION' => 3,
+ 'TEMPLATE_CELEBRATION' => 4,
+
'DEPARTMENTS' => [
'BIZ-IID - Internet Infra Business Division / BIZ-IID - Sales Enterprise Team (HCM)',
'BIZ-ITOVN - Vietnam Business Division / BIZ-ITOVN - Ho Chi Minh',
diff --git a/database/migrations/2026_07_20_095829_add_template_id_to_administration_table.php b/database/migrations/2026_07_20_095829_add_template_id_to_administration_table.php
new file mode 100644
index 0000000..6ea50cf
--- /dev/null
+++ b/database/migrations/2026_07_20_095829_add_template_id_to_administration_table.php
@@ -0,0 +1,28 @@
+integer('template_id')->nullable()->default(1)->after('date');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('administration', function (Blueprint $table) {
+ $table->dropColumn('template_id');
+ });
+ }
+};
diff --git a/resources/views/components/sidebar-item.blade.php b/resources/views/components/sidebar-item.blade.php
index 1eb8831..6af8754 100644
--- a/resources/views/components/sidebar-item.blade.php
+++ b/resources/views/components/sidebar-item.blade.php
@@ -2,7 +2,7 @@
@php
$classes = $active
- ? 'flex items-center gap-4 px-4 py-3 rounded-xl bg-[#eff4ff] text-[#3462f7] font-semibold transition-all duration-200'
+ ? 'flex items-center gap-4 px-4 py-3 rounded-xl bg-[#eff4ff] text-[#3462f7] font-medium transition-all duration-200'
: 'flex items-center gap-4 px-4 py-3 rounded-xl text-gray-500 hover:bg-gray-50 hover:text-gray-900 font-medium transition-all duration-200';
@endphp
diff --git a/resources/views/components/sidebar.blade.php b/resources/views/components/sidebar.blade.php
index 86e8cb5..5210913 100644
--- a/resources/views/components/sidebar.blade.php
+++ b/resources/views/components/sidebar.blade.php
@@ -29,9 +29,11 @@
Thanks đã gửi
-
Bảng xếp hạng đã bị ẩn với tài khoản thành viên.
+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.
-