diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/Admin/AdminController.php similarity index 97% rename from app/Http/Controllers/AdminController.php rename to app/Http/Controllers/Admin/AdminController.php index d48343f..d1fb405 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/Admin/AdminController.php @@ -1,7 +1,8 @@ role == User::ROLE_MEMBER && Auth::user()->status == User::STATUS_ACTIVE) { + if (Auth::check() && in_array(Auth::user()->role, [User::ROLE_MEMBER, User::ROLE_ADMIN]) && Auth::user()->status == User::STATUS_ACTIVE) { return $next($request); } return redirect()->route('login'); diff --git a/app/Services/Auth/AuthService.php b/app/Services/Auth/AuthService.php index 47fe660..83a331a 100644 --- a/app/Services/Auth/AuthService.php +++ b/app/Services/Auth/AuthService.php @@ -40,10 +40,6 @@ class AuthService implements AuthServiceInterface return route('user.change_password'); } - if ($user->role == User::ROLE_ADMIN) { - return route('admin.dashboard'); - } - return route('user.dashboard'); } } \ No newline at end of file diff --git a/bootstrap/app.php b/bootstrap/app.php index 1d919d8..d664775 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -3,19 +3,24 @@ use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; +use Illuminate\Support\Facades\Route; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', commands: __DIR__.'/../routes/console.php', health: '/up', + then: function () { + Route::middleware('web') + ->group(base_path('routes/admin.php')); + }, ) ->withMiddleware(function (Middleware $middleware): void { $middleware->trustProxies(at: '*'); $middleware->alias([ - 'admin' => \App\Http\Middleware\AdminMiddleware::class, - 'member' => \App\Http\Middleware\MemberMiddleware::class, + 'admin' => \App\Http\Middleware\Admin\AdminMiddleware::class, + 'member' => \App\Http\Middleware\User\MemberMiddleware::class, 'force_change_password' => \App\Http\Middleware\ForceChangePasswordMiddleware::class, ]); }) diff --git a/public/images/hero_banner_illustration.png b/public/images/hero_banner_illustration.png new file mode 100644 index 0000000..c8fa38e Binary files /dev/null and b/public/images/hero_banner_illustration.png differ diff --git a/public/images/pic-woman-gmo.png b/public/images/pic-woman-gmo.png new file mode 100644 index 0000000..7caaf84 Binary files /dev/null and b/public/images/pic-woman-gmo.png differ diff --git a/public/images/sidebar_illustration.png b/public/images/sidebar_illustration.png new file mode 100644 index 0000000..3a99163 Binary files /dev/null and b/public/images/sidebar_illustration.png differ diff --git a/public/images/thanks_card_illustration.png b/public/images/thanks_card_illustration.png new file mode 100644 index 0000000..9620805 Binary files /dev/null and b/public/images/thanks_card_illustration.png differ diff --git a/resources/assets/icons/eye-slash.svg b/resources/assets/icons/eye-slash.svg new file mode 100644 index 0000000..f1d56a5 --- /dev/null +++ b/resources/assets/icons/eye-slash.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/assets/icons/eye.svg b/resources/assets/icons/eye.svg new file mode 100644 index 0000000..a69fcdb --- /dev/null +++ b/resources/assets/icons/eye.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/assets/icons/lock.svg b/resources/assets/icons/lock.svg new file mode 100644 index 0000000..6a41a3d --- /dev/null +++ b/resources/assets/icons/lock.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/assets/icons/mail.svg b/resources/assets/icons/mail.svg new file mode 100644 index 0000000..28871f6 --- /dev/null +++ b/resources/assets/icons/mail.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/css/app.css b/resources/css/app.css index 2b93ce1..7339476 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,3 +1,5 @@ +@import url('https://fonts.googleapis.com/css2?family=Caveat:wght@700&display=swap'); + @font-face { font-family: 'SVN-Poppins-Regular'; src: url('/fonts/FZ Poppins-Regular.ttf') format('truetype'); @@ -85,6 +87,10 @@ --color-calendar-header: #4b729f; + --color-terminal-bg: #263238; + --color-terminal-base: #b0bec5; + --color-terminal-accent: #90a4ae; + --shadow-card: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03); --shadow-sidebar: 0 4px 20px 0 rgba(0, 0, 0, 0.05); --shadow-header: 0 2px 4px 0 rgba(0, 0, 0, 0.02); @@ -261,3 +267,6 @@ select.form-input { .table-action-link { @apply hover:text-primary-hover font-semibold underline underline-offset-2; } + +@import "./login.css"; + diff --git a/resources/css/login.css b/resources/css/login.css new file mode 100644 index 0000000..6dccd5c --- /dev/null +++ b/resources/css/login.css @@ -0,0 +1,47 @@ +/* resources/css/login.css */ + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +.animate-fade-in { + animation: fadeIn 0.3s ease-in-out forwards; +} + +.floating-group { + @apply relative w-full; +} + +.floating-input { + @apply w-full h-[56px] pl-11 pr-12 text-sm text-text-dark bg-transparent border border-[#c4c4c4] rounded outline-none transition-all duration-200 ease-in-out; +} + +.floating-input:hover { + @apply border-text-medium; +} + +.floating-input:focus { + @apply border-2 border-primary pl-[43px]; +} + +.floating-label { + @apply absolute left-11 top-1/2 -translate-y-1/2 text-sm text-text-muted pointer-events-none transition-all duration-200 ease-in-out bg-transparent p-0; +} + +.floating-input:focus ~ .floating-label, +.floating-input:not(:placeholder-shown) ~ .floating-label { + @apply top-0 -translate-y-1/2 text-xs text-primary bg-white px-1.5 left-10; +} + +.floating-input:not(:focus):not(:placeholder-shown) ~ .floating-label { + @apply text-text-light; +} + +.floating-icon { + @apply absolute left-4 top-1/2 -translate-y-1/2 text-text-muted pointer-events-none transition-colors duration-200 ease-in-out flex items-center justify-center; +} + +.floating-input:focus ~ .floating-icon { + @apply text-primary; +} diff --git a/resources/js/app.js b/resources/js/app.js index 75f1282..edcbd0c 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -25,3 +25,51 @@ window.openDeleteModal = function(msnv, url) { window.openModal('deleteModal'); } }; + +window.togglePasswordVisibility = function(inputId, button) { + const input = document.getElementById(inputId); + if (!input) return; + + const eyeOpen = button.querySelector('.eye-icon-open'); + const eyeClosed = button.querySelector('.eye-icon-closed'); + + if (input.type === 'password') { + input.type = 'text'; + button.setAttribute('aria-label', 'Hide password'); + if (eyeOpen) eyeOpen.classList.remove('hidden'); + if (eyeClosed) eyeClosed.classList.add('hidden'); + } else { + input.type = 'password'; + button.setAttribute('aria-label', 'Show password'); + if (eyeOpen) eyeOpen.classList.add('hidden'); + if (eyeClosed) eyeClosed.classList.remove('hidden'); + } +}; + +document.addEventListener('DOMContentLoaded', () => { + const loginForm = document.querySelector('form[action$="/login"]'); + if (loginForm) { + loginForm.addEventListener('submit', (e) => { + const submitBtn = loginForm.querySelector('button[type="submit"]'); + if (submitBtn) { + if (submitBtn.disabled) { + e.preventDefault(); + return; + } + submitBtn.disabled = true; + + const originalText = submitBtn.textContent.trim(); + submitBtn.dataset.originalText = originalText; + + submitBtn.innerHTML = ` + + + + + ${originalText} + `; + } + }); + } +}); + diff --git a/resources/views/coming-soon.blade.php b/resources/views/coming-soon.blade.php new file mode 100644 index 0000000..e4105ae --- /dev/null +++ b/resources/views/coming-soon.blade.php @@ -0,0 +1,9 @@ +@extends('layouts.app') + +@section('title', 'Tính năng đang phát triển') + +@section('content') +
+ +
+@endsection diff --git a/resources/views/components/coming-soon.blade.php b/resources/views/components/coming-soon.blade.php new file mode 100644 index 0000000..dae0c93 --- /dev/null +++ b/resources/views/components/coming-soon.blade.php @@ -0,0 +1,53 @@ +
+ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+ + +
+
+
+
+ + +
+ +
+
+ + +

+ Tính năng đang phát triển +

+

+ Chúng tôi đang nỗ lực để mang đến trải nghiệm tốt nhất cho bạn. Vui lòng quay lại sau nhé! +

+ + + + + Quay về trang chủ + +
+ + diff --git a/resources/views/components/floating-input.blade.php b/resources/views/components/floating-input.blade.php new file mode 100644 index 0000000..e65c92f --- /dev/null +++ b/resources/views/components/floating-input.blade.php @@ -0,0 +1,56 @@ +@props([ + 'type' => 'text', + 'name', + 'id' => null, + 'label' => '', + 'required' => false, + 'value' => '', + 'autocomplete' => null, + 'icon' => null, + 'hasError' => false, +]) + +@php + $id = $id ?? $name; + $isPassword = $type === 'password'; +@endphp + +
+ merge(['class' => 'floating-input' . ($hasError ? ' border-red-500 focus:border-red-500 focus:ring-red-500/20' : '')]) }} + @if($hasError) + aria-invalid="true" + aria-describedby="login-errors" + @endif + /> + + @if($icon) + + + + @endif + + @if($isPassword) + + @endif +
diff --git a/resources/views/components/header.blade.php b/resources/views/components/header.blade.php new file mode 100644 index 0000000..b8a4b58 --- /dev/null +++ b/resources/views/components/header.blade.php @@ -0,0 +1,19 @@ +
+
+ + +
+ +
+ + + +
+
diff --git a/resources/views/components/hero-banner.blade.php b/resources/views/components/hero-banner.blade.php new file mode 100644 index 0000000..ee56fef --- /dev/null +++ b/resources/views/components/hero-banner.blade.php @@ -0,0 +1,33 @@ +
+ + +
+

+ Thanks Card + + + +

+

+ Một lời cảm ơn chân thành
có thể tạo nên ngày tuyệt vời của ai đó! +

+ + Gửi lời cảm ơn ngay + + + + +
+ + +
+ Illustration +
+ + +
+
+
+
+
+
diff --git a/resources/views/components/icon-arrow-left.blade.php b/resources/views/components/icon-arrow-left.blade.php new file mode 100644 index 0000000..5875f3a --- /dev/null +++ b/resources/views/components/icon-arrow-left.blade.php @@ -0,0 +1,3 @@ + + + diff --git a/resources/views/components/icon-rocket.blade.php b/resources/views/components/icon-rocket.blade.php new file mode 100644 index 0000000..f4a90c0 --- /dev/null +++ b/resources/views/components/icon-rocket.blade.php @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/views/components/icon-sparkle.blade.php b/resources/views/components/icon-sparkle.blade.php new file mode 100644 index 0000000..53c7b0f --- /dev/null +++ b/resources/views/components/icon-sparkle.blade.php @@ -0,0 +1,3 @@ + + + diff --git a/resources/views/components/icon-star.blade.php b/resources/views/components/icon-star.blade.php new file mode 100644 index 0000000..bc052d5 --- /dev/null +++ b/resources/views/components/icon-star.blade.php @@ -0,0 +1,3 @@ + + + diff --git a/resources/views/components/info-card.blade.php b/resources/views/components/info-card.blade.php new file mode 100644 index 0000000..c47c2fd --- /dev/null +++ b/resources/views/components/info-card.blade.php @@ -0,0 +1,11 @@ +
+
+

Bạn có biết?

+

+ Một lời cảm ơn chân thành có thể nhân đôi động lực làm việc của đồng nghiệp! +

+
+
+ 💡 +
+
diff --git a/resources/views/components/login-bg-decorations.blade.php b/resources/views/components/login-bg-decorations.blade.php new file mode 100644 index 0000000..aeea3fa --- /dev/null +++ b/resources/views/components/login-bg-decorations.blade.php @@ -0,0 +1,13 @@ +
+ + +
diff --git a/resources/views/components/login-illustration.blade.php b/resources/views/components/login-illustration.blade.php new file mode 100644 index 0000000..088eff4 --- /dev/null +++ b/resources/views/components/login-illustration.blade.php @@ -0,0 +1,68 @@ + diff --git a/resources/views/components/quick-send-card.blade.php b/resources/views/components/quick-send-card.blade.php new file mode 100644 index 0000000..bce6cb1 --- /dev/null +++ b/resources/views/components/quick-send-card.blade.php @@ -0,0 +1,45 @@ +
+
+
+

Gửi nhanh

+ +
+

Chọn thiệp và gửi lời cảm ơn đến đồng nghiệp

+ + +
+ + + + + + + + +
+
+ + + + Tạo thiệp của riêng bạn + + + + +
diff --git a/resources/views/components/ranking-item.blade.php b/resources/views/components/ranking-item.blade.php new file mode 100644 index 0000000..a54565c --- /dev/null +++ b/resources/views/components/ranking-item.blade.php @@ -0,0 +1,34 @@ +@props(['rank', 'name', 'team', 'avatar', 'score', 'isCurrent' => false, 'unit' => 'điểm']) + +
+
+ +
+ @if($rank == 1) + 👑 + 1 + @elseif($rank == 2) + 2 + @elseif($rank == 3) + 3 + @else + {{ $rank }} + @endif +
+ + +
+ {{ $name }} +
+ {{ $name }} + {{ $team }} +
+
+
+ + +
+ {{ number_format($score, 0, ',', '.') }} + {{ $unit }} +
+
diff --git a/resources/views/components/sidebar-item.blade.php b/resources/views/components/sidebar-item.blade.php new file mode 100644 index 0000000..ee2f9bf --- /dev/null +++ b/resources/views/components/sidebar-item.blade.php @@ -0,0 +1,49 @@ +@props(['active' => false, 'icon' => 'home', 'href' => '#']) + +@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 text-gray-500 hover:bg-gray-50 hover:text-gray-900 font-medium transition-all duration-200'; +@endphp + +merge(['class' => $classes]) }}> + @if($icon == 'home') + + + + @elseif($icon == 'paper-plane-send') + + + + @elseif($icon == 'heart') + + + + @elseif($icon == 'paper-plane-outline') + + + + @elseif($icon == 'trophy') + + + + @elseif($icon == 'folder') + + + + @elseif($icon == 'chart') + + + + @elseif($icon == 'users') + + + + @elseif($icon == 'gear') + + + + + @endif + {{ $slot }} + diff --git a/resources/views/components/sidebar.blade.php b/resources/views/components/sidebar.blade.php new file mode 100644 index 0000000..8c17a8a --- /dev/null +++ b/resources/views/components/sidebar.blade.php @@ -0,0 +1,68 @@ +@props(['active' => false]) + + diff --git a/resources/views/components/stat-card.blade.php b/resources/views/components/stat-card.blade.php index 6d2d976..be17a11 100644 --- a/resources/views/components/stat-card.blade.php +++ b/resources/views/components/stat-card.blade.php @@ -1,14 +1,34 @@ -@props(['title', 'user', 'value', 'bgClass' => 'bg-[#0f4c81]', 'valueLabel' => 'Tổng thẻ đã nhận']) +@props(['title' => '', 'value' => '', 'growth' => '', 'growthType' => 'up', 'iconBgClass' => '', 'iconColorClass' => '', 'subtitle' => '']) -
-
-
- {{ $title }} - {{ $user && $value > 0 ? $user : 'Chưa có' }} +
+
+ +
+
+ {{ $slot }} +
-
- {{ $valueLabel }} - {{ $value }} thẻ + + +
+ {{ $title }} +
+ {{ $value }} +
+ + @if($growth) +
+ + @if($growthType === 'up') + + @else + + @endif + {{ $growth }} + + {{ $subtitle }} +
+ @endif
diff --git a/resources/views/components/thank-card.blade.php b/resources/views/components/thank-card.blade.php new file mode 100644 index 0000000..b882304 --- /dev/null +++ b/resources/views/components/thank-card.blade.php @@ -0,0 +1,16 @@ +@props(['title', 'message', 'isLiked' => false, 'bgClass', 'titleColorClass', 'textColorClass']) + +
+

+ @if(str_contains($title, 'GREAT JOB')) + ✨ {{ $title }} ✨ + @elseif(str_contains($title, 'YOU ROCK')) + 🌟 {{ $title }} 🌟 + @else + 💖 {{ $title }} 💖 + @endif +

+

+ "{{ $message }}" +

+
diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php deleted file mode 100644 index 3eca797..0000000 --- a/resources/views/dashboard.blade.php +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - - GMO-Z.com RUNSYSTEM - Dashboard - @vite(['resources/css/app.css', 'resources/js/app.js']) - - -
- - -
-
- - -
- - -
-
- - - -
- TRẦN VĂN AN -
-
-
- -
- - -
-
-
-
- Ngày công chuẩn - 22 -
-
- Ngày công lễ - 0 -
-
-
- -
-
-
- Ngày công thực tế - 20 -
-
- Nghỉ phép - 0 -
-
-
- -
-
-
- Số lần đi muộn, về sớm - 0 -
-
- Số giờ đi muộn, về sớm - 0 -
-
-
- -
-
-
- Số giờ OT 150% - 0 -
-
- Số giờ OT 200% - 0 -
-
- Số giờ OT 300% - 0 -
-
-
-
- -
-
-
- - Tháng 06/2026 - -
- -
- - -
-
- -
-
-
Thứ 2
-
Thứ 3
-
Thứ 4
-
Thứ 5
-
Thứ 6
-
Thứ 7
-
CN
-
- -
-
-
- X - 1 -
-
-
07:45 - 17:13
-
+ 0:28
-
-
-
-
- X - 2 -
-
-
07:53 - 17:08
-
+ 0:15
-
-
-
-
- X - 3 -
-
-
07:54 - 17:16
-
+ 0:22
-
-
-
-
- X - 4 -
-
-
07:52 - 17:04
-
+ 0:12
-
-
-
-
- X - 5 -
-
-
07:50 - 17:20
-
+ 0:30
-
-
-
-
- 6 -
-
-
-
-
- 7 -
-
-
- -
-
- X - 8 -
-
-
07:54 - 17:05
-
+ 0:11
-
-
-
-
- X - 9 -
-
-
07:48 - 17:05
-
+ 0:17
-
-
-
-
- X - 10 -
-
-
07:51 - 17:05
-
+ 0:14
-
-
-
-
- X - 11 -
-
-
07:45 - 17:13
-
+ 0:28
-
-
-
-
- X - 12 -
-
-
07:45 - 17:37
-
+ 0:52
-
-
-
-
- 13 -
-
-
-
-
- 14 -
-
-
- -
-
- X - 15 -
-
-
07:47 - 17:04
-
+ 0:17
-
-
-
-
- X - 16 -
-
-
07:45 - 17:02
-
+ 0:17
-
-
-
-
- X - 17 -
-
-
07:54 - 17:02
-
+ 0:08
-
-
-
-
- X - 18 -
-
-
07:45 - 17:03
-
+ 0:18
-
-
-
-
- X - 19 -
-
-
07:45 - 17:04
-
+ 0:19
-
-
-
-
- 20 -
-
-
-
-
- 21 -
-
-
-
-
-
-
-
-
- - diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 23924d4..66d6129 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -12,93 +12,12 @@
- - -
-
-
- Thank Card System -
- -
-
-
- - - -
- {{ Auth::check() ? Auth::user()->mail : 'GUEST' }} - -
- @csrf - -
-
-
-
+
+ +
@if(session('success')) @@ -175,6 +94,32 @@ document.body.style.overflow = ''; }, 300); // 300ms matches Tailwind duration-300 }; + + // Mobile Sidebar Toggle Logic + document.addEventListener('DOMContentLoaded', function () { + const hamburger = document.getElementById('sidebar-hamburger'); + const closeBtn = document.getElementById('sidebar-close'); + const overlay = document.getElementById('sidebar-overlay'); + const sidebar = document.querySelector('.sidebar'); + + if (hamburger && sidebar && overlay && closeBtn) { + function openSidebar() { + sidebar.classList.remove('-translate-x-full'); + overlay.classList.remove('hidden'); + document.body.style.overflow = 'hidden'; + } + + function closeSidebar() { + sidebar.classList.add('-translate-x-full'); + overlay.classList.add('hidden'); + document.body.style.overflow = ''; + } + + hamburger.addEventListener('click', openSidebar); + closeBtn.addEventListener('click', closeSidebar); + overlay.addEventListener('click', closeSidebar); + } + }); @stack('scripts') diff --git a/resources/views/login.blade.php b/resources/views/login.blade.php index 7b0e0dd..bff6b2d 100644 --- a/resources/views/login.blade.php +++ b/resources/views/login.blade.php @@ -5,242 +5,180 @@ GMO-Z.com RUNSYSTEM - {{ __('auth.login') }} + @vite(['resources/css/app.css', 'resources/js/app.js']) - - + -
- - - - - - - - - - - -
- -
+ +
-
-
-
- -
- GMO-Z.com RUNSYSTEM -
- -
-

{{ __('auth.login') }}

- -
- @csrf - -
- @if($errors->any()) -
- - - - {{ $errors->first() }} -
- @else - - @endif -
- -
- - - - - - - -
- -
- - - - - - - -
- - -
-
- -
- © {{ __('auth.developed_by') }} -
-
-
- -
-
-
-
- -