Files
thankcard-system/resources/views/login.blade.php
T
2026-07-06 21:02:52 +07:00

271 lines
17 KiB
PHP

<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>GMO-Z.com RUNSYSTEM - {{ __('auth.login') }}</title>
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@700&display=swap" rel="stylesheet">
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="min-h-screen flex items-center justify-center font-sans antialiased overflow-hidden relative bg-[#f0f4f9] p-4 sm:p-6 lg:p-10">
<!-- Main Card -->
<div class="w-full max-w-[1100px] bg-white rounded-[24px] shadow-2xl flex flex-col lg:flex-row overflow-hidden min-h-[650px] relative z-10">
<!-- LEFT COLUMN: Login Form -->
<div class="w-full lg:w-[50%] p-8 sm:p-12 lg:p-16 flex flex-col relative bg-white">
<!-- Decorative Elements Left -->
<!-- Heart icon -->
<div class="absolute top-12 left-10 w-10 h-10 opacity-90 hidden sm:block">
<svg viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M50 88C50 88 15 62 15 35C15 20 28 10 40 15C45 17 50 24 50 24C50 24 55 17 60 15C72 10 85 20 85 35C85 62 50 88 50 88Z" fill="#ff4d6d"/>
<path d="M50 88C50 88 15 62 15 35C15 20 28 10 40 15C45 17 50 24 50 24C50 24 55 17 60 15C72 10 85 20 85 35C85 62 50 88 50 88Z" fill="url(#paint0_linear)" opacity="0.3"/>
<defs>
<linearGradient id="paint0_linear" x1="15" y1="35" x2="85" y2="35" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>
</div>
<!-- Star bottom left -->
<div class="absolute bottom-16 left-12 w-6 h-6 hidden sm:block">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 0L14.59 9.41L24 12L14.59 14.59L12 24L9.41 14.59L0 12L9.41 9.41L12 0Z" fill="#ffb703"/>
</svg>
</div>
<!-- Squiggle middle left -->
<div class="absolute top-1/2 -mt-10 left-6 w-5 h-12 hidden sm:block">
<svg viewBox="0 0 20 50" fill="none" stroke="#a78bfa" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
<path d="M10,5 C18,10 2,20 10,25 C18,30 2,40 10,45" />
</svg>
</div>
<!-- Blue dot top right (left col) -->
<div class="absolute top-20 right-12 w-4 h-4 hidden sm:block">
<svg viewBox="0 0 24 24" fill="#3b82f6" xmlns="http://www.w3.org/2000/svg">
<path d="M12 0L15.5 8.5L24 12L15.5 15.5L12 24L8.5 15.5L0 12L8.5 8.5L12 0Z" />
</svg>
</div>
<!-- Logo -->
<div class="flex justify-start mb-10 relative z-10">
<img src="{{ asset('images/logo.png') }}" alt="GMO-Z.com RUNSYSTEM" class="h-6 sm:h-8 w-auto object-contain">
</div>
<!-- Header -->
<div class="text-center mb-8 relative z-10">
<h1 class="text-3xl font-bold text-[#1e293b] mb-3 flex items-center justify-center gap-2">
Welcome back! <span class="text-2xl origin-bottom-right hover:animate-bounce">👋</span>
</h1>
<p class="text-[13px] text-gray-500 font-medium max-w-[320px] mx-auto leading-relaxed">
Đăng nhập để tiếp tục lan tỏa những lời cảm ơn tạo nên môi trường làm việc tích cực.
</p>
</div>
<!-- Form -->
<div class="w-full max-w-[380px] mx-auto flex-1 relative z-10">
<form action="{{ route('login') }}" method="POST" class="space-y-5" novalidate>
@csrf
<div class="min-h-[40px] flex items-center justify-center transition-all duration-300" aria-live="polite">
@if($errors->any())
<div id="login-errors" class="w-full bg-red-50 text-red-600 text-[13px] font-semibold p-2.5 rounded-lg border border-red-200 flex items-start gap-2" role="alert">
<svg class="h-4 w-4 shrink-0 mt-0.5 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
<span>{{ $errors->first() }}</span>
</div>
@endif
</div>
<!-- Email Field -->
<div class="space-y-1.5">
<label for="mail" class="block text-[13px] font-bold text-gray-700">Email</label>
<div class="relative">
<span class="absolute left-3.5 top-1/2 -translate-y-1/2 text-gray-400">
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" /></svg>
</span>
<input type="email" name="mail" id="mail" placeholder="Nhập email của bạn" required value="{{ old('mail') }}" autocomplete="email" class="w-full h-[46px] pl-[42px] pr-4 bg-white border border-gray-200 rounded-lg text-sm text-gray-800 focus:border-[#2563eb] focus:ring-1 focus:ring-[#2563eb] outline-none transition-all shadow-sm placeholder:text-gray-400 @error('mail') border-red-500 @enderror" @error('mail') aria-invalid="true" aria-describedby="login-errors" @enderror />
</div>
</div>
<!-- Password Field -->
<div class="space-y-1.5">
<label for="password" class="block text-[13px] font-bold text-gray-700">Mật khẩu</label>
<div class="relative">
<span class="absolute left-3.5 top-1/2 -translate-y-1/2 text-gray-400">
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0V10.5m-2.812 10.5h14.625c.621 0 1.125-.504 1.125-1.125V11.25c0-.621-.504-1.125-1.125-1.125H3.75c-.621 0-1.125.504-1.125 1.125v7.875c0 .621.504 1.125 1.125 1.125z" /></svg>
</span>
<input type="password" name="password" id="password" placeholder="Nhập mật khẩu" required autocomplete="current-password" class="w-full h-[46px] pl-[42px] pr-12 bg-white border border-gray-200 rounded-lg text-sm text-gray-800 focus:border-[#2563eb] focus:ring-1 focus:ring-[#2563eb] outline-none transition-all shadow-sm placeholder:text-gray-400 @error('password') border-red-500 @enderror" @error('password') aria-invalid="true" aria-describedby="login-errors" @enderror />
<button type="button" onclick="togglePasswordVisibility('password', this)" class="absolute right-3.5 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 focus:outline-none" aria-label="Show password">
<!-- Eye Closed (Default) -->
<svg class="w-5 h-5 eye-icon-closed" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" /></svg>
<!-- Eye Open -->
<svg class="w-5 h-5 eye-icon-open hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
</button>
</div>
</div>
<div class="pt-4">
<button type="submit" class="w-full h-[46px] bg-[#1d4ed8] hover:bg-[#1e40af] text-white font-bold rounded-lg shadow-md hover:shadow-lg transition-all duration-200 text-[14px]">
Đăng nhập
</button>
</div>
</form>
</div>
<div class="text-center mt-auto pt-8 relative z-10">
<span class="text-[11px] font-medium text-gray-400">&copy; 2026 GMO-Z.com RUNSYSTEM. All rights reserved.</span>
</div>
</div>
<!-- RIGHT COLUMN: Illustration Side -->
<div class="hidden lg:flex w-[50%] bg-[#f8faff] relative flex-col items-center justify-center p-12 overflow-hidden border-l border-gray-100">
<!-- Right Column Decorations -->
<div class="absolute inset-0 pointer-events-none">
<!-- Top left blue strokes -->
<svg class="absolute top-16 left-16 w-10 h-10 text-blue-500" viewBox="0 0 50 50" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round">
<path d="M10,20 L25,10" />
<path d="M15,35 L30,25" />
<path d="M30,40 L40,30" />
</svg>
<!-- Heart icon top right -->
<div class="absolute top-20 right-20 w-12 h-12 flex items-center justify-center">
<svg viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M50 88C50 88 15 62 15 35C15 20 28 10 40 15C45 17 50 24 50 24C50 24 55 17 60 15C72 10 85 20 85 35C85 62 50 88 50 88Z" stroke="#3b82f6" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<!-- Sparkle top right -->
<svg class="absolute top-12 right-12 w-6 h-6 text-purple-400" viewBox="0 0 24 24" fill="none">
<path d="M12 0L14.59 9.41L24 12L14.59 14.59L12 24L9.41 14.59L0 12L9.41 9.41L12 0Z" fill="currentColor"/>
</svg>
<!-- Thumbs up bottom right -->
<div class="absolute bottom-32 right-16 w-14 h-14 bg-white rounded-lg flex items-center justify-center shadow-lg transform rotate-12 z-20">
<span class="text-3xl">👍</span>
</div>
<!-- Paper plane -->
<div class="absolute top-1/3 left-10 w-10 h-10 transform -rotate-12 z-20">
<svg viewBox="0 0 24 24" fill="#3b82f6" xmlns="http://www.w3.org/2000/svg">
<path d="M2 12L22 2L15 22L11 15L2 12Z"/>
</svg>
<!-- Dashed trail -->
<svg class="absolute top-full left-0 w-24 h-24 text-gray-300" style="transform: translate(-90%, -30%);" viewBox="0 0 100 100" fill="none" stroke="currentColor" stroke-width="2" stroke-dasharray="4 4">
<path d="M100,0 Q50,50 0,100" />
</svg>
</div>
<!-- Purple squiggle bottom right -->
<svg class="absolute bottom-24 right-10 w-8 h-16 text-purple-400" viewBox="0 0 30 60" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
<path d="M20,10 C5,20 25,30 10,40 C25,50 5,60 20,70" />
</svg>
</div>
<!-- Header Content -->
<div class="text-center mb-6 relative z-10 pt-4">
<h2 class="text-[40px] font-extrabold text-[#1e293b] flex items-center justify-center gap-3 mb-2">
Thanks <span class="text-[#ff7eb3] font-bold text-[48px] leading-none tracking-wider" style="font-family: 'Caveat', cursive;">card</span>
<svg class="w-8 h-8 text-[#3b82f6] transform -rotate-12" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg>
</h2>
<p class="text-gray-700 font-medium text-[14px] max-w-[300px] mx-auto leading-relaxed">
Gửi lời cảm ơn chân thành đến đồng nghiệp cùng nhau xây dựng văn hóa tích cực!
</p>
</div>
<!-- Illustration (Image) -->
<div class="relative w-full max-w-[460px] flex-1 flex items-end justify-center z-10 mt-4">
<img src="{{ asset('images/thanks_card_illustration.png') }}" alt="Thanks card illustration" class="w-full h-auto object-contain drop-shadow-xl hover:scale-[1.05] transition-transform duration-500 rounded-3xl" style="mix-blend-mode: multiply;">
</div>
</div>
</div>
<!-- Dialogs -->
@if(session('dialog_error_permission'))
<x-error-dialog id="modal-error-permission" title="Truy cập bị từ chối" message="{{ session('dialog_error_permission') }}" buttonText="Đồng ý" />
@endif
@if(session('session_expired'))
<x-warning-dialog id="modal-session-expired" title="Phiên làm việc hết hạn" message="Phiên đăng nhập đã hết hạn. Vui lòng đăng nhập lại." buttonText="OK" onclick="handleSessionExpiredOk()" />
@endif
@if(session('dialog_first_login'))
<x-info-dialog id="modal-first-login" title="Yêu cầu đổi mật khẩu" message="Vui lòng đổi mật khẩu trước khi tiếp tục sử dụng hệ thống." buttonText="OK" onclick="handleFirstLoginOk()" />
@endif
@if(session('dialog_error_brute_force'))
<x-error-dialog id="modal-error-brute-force" title="Tài khoản bị khóa" message="{{ session('dialog_error_brute_force') }}" buttonText="Đồng ý" />
@endif
<script>
window.openModal = function(id) {
const modal = document.getElementById(id);
if (!modal) return;
document.body.style.overflow = 'hidden';
modal.classList.remove('hidden');
modal.classList.add('flex');
requestAnimationFrame(() => {
modal.classList.remove('opacity-0');
modal.classList.add('opacity-100');
const panel = modal.querySelector('.modal-panel');
if (panel) {
panel.classList.remove('scale-95', 'translate-y-4');
panel.classList.add('scale-100', 'translate-y-0');
}
});
modal.setAttribute('tabindex', '-1');
modal.focus();
const escHandler = function(e) {
if (e.key === 'Escape') {
closeModal(id);
modal.removeEventListener('keydown', escHandler);
}
};
modal.addEventListener('keydown', escHandler);
};
window.closeModal = function(id) {
const modal = document.getElementById(id);
if (!modal) return;
modal.classList.remove('opacity-100');
modal.classList.add('opacity-0');
const panel = modal.querySelector('.modal-panel');
if (panel) {
panel.classList.remove('scale-100', 'translate-y-0');
panel.classList.add('scale-95', 'translate-y-4');
}
setTimeout(() => {
modal.classList.add('hidden');
modal.classList.remove('flex');
document.body.style.overflow = '';
}, 300);
};
window.handleSessionExpiredOk = function() {
closeModal('modal-session-expired');
window.location.href = "{{ route('login') }}";
};
window.handleFirstLoginOk = function() {
closeModal('modal-first-login');
window.location.href = "{{ route('user.change_password') }}";
};
document.addEventListener('DOMContentLoaded', () => {
@if(session('dialog_error_permission'))
openModal('modal-error-permission');
@endif
@if(session('session_expired'))
openModal('modal-session-expired');
@endif
@if(session('dialog_first_login'))
openModal('modal-first-login');
@endif
@if(session('dialog_error_brute_force'))
openModal('modal-error-brute-force');
@endif
});
</script>
</body>
</html>