login.html

12.78 KB
04/08/2025 06:48
HTML
<!DOCTYPE html>
<html lang="th">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Admin Login - E-commerce Store</title>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Prompt:wght@300;400;500;600;700&display=swap" rel="stylesheet">
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    :root {
      --primary-color: #2563eb;
      --danger-color: #dc2626;
      --success-color: #16a34a;
      --warning-color: #d97706;
      --dark-color: #1e293b;
      --light-color: #f8fafc;
      --border-color: #e2e8f0;
      --text-primary: #1e293b;
      --text-secondary: #64748b;
    }

    body {
      font-family: 'Prompt', 'Inter', Tahoma, Geneva, Verdana, sans-serif;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 1rem;
    }

    .login-container {
      background: white;
      border-radius: 1rem;
      box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
      padding: 2rem;
      width: 100%;
      max-width: 400px;
    }

    .login-header {
      text-align: center;
      margin-bottom: 2rem;
    }

    .login-header h1 {
      font-size: 1.875rem;
      font-weight: 700;
      color: var(--text-primary);
      margin-bottom: 0.5rem;
    }

    .login-header p {
      color: var(--text-secondary);
      font-size: 0.875rem;
    }

    .form-group {
      margin-bottom: 1.5rem;
    }

    .form-label {
      display: block;
      font-size: 0.875rem;
      font-weight: 500;
      color: var(--text-primary);
      margin-bottom: 0.5rem;
    }

    .form-input {
      width: 100%;
      padding: 0.75rem 1rem;
      border: 1px solid var(--border-color);
      border-radius: 0.5rem;
      font-size: 1rem;
      transition: all 0.2s;
    }

    .form-input:focus {
      outline: none;
      border-color: var(--primary-color);
      box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
    }

    .input-group {
      position: relative;
    }

    .input-icon {
      position: absolute;
      left: 1rem;
      top: 50%;
      transform: translateY(-50%);
      color: var(--text-secondary);
    }

    .input-icon+.form-input {
      padding-left: 2.5rem;
    }

    .password-toggle {
      position: absolute;
      right: 1rem;
      top: 50%;
      transform: translateY(-50%);
      background: none;
      border: none;
      color: var(--text-secondary);
      cursor: pointer;
      padding: 0;
    }

    .btn {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      padding: 0.75rem 1rem;
      border: none;
      border-radius: 0.5rem;
      font-size: 1rem;
      font-weight: 500;
      text-decoration: none;
      cursor: pointer;
      transition: all 0.2s;
      gap: 0.5rem;
    }

    .btn-primary {
      background: var(--primary-color);
      color: white;
    }

    .btn-primary:hover {
      background: #1d4ed8;
      transform: translateY(-1px);
    }

    .btn-primary:disabled {
      background: var(--text-secondary);
      cursor: not-allowed;
      transform: none;
    }

    .alert {
      padding: 0.75rem 1rem;
      border-radius: 0.5rem;
      margin-bottom: 1rem;
      border-left: 4px solid;
      font-size: 0.875rem;
    }

    .alert-danger {
      background: rgba(220, 38, 38, 0.1);
      border-left-color: var(--danger-color);
      color: var(--danger-color);
    }

    .alert-success {
      background: rgba(22, 163, 74, 0.1);
      border-left-color: var(--success-color);
      color: var(--success-color);
    }

    .alert-info {
      background: rgba(37, 99, 235, 0.1);
      border-left-color: var(--primary-color);
      color: var(--primary-color);
    }

    .loading-spinner {
      width: 20px;
      height: 20px;
      border: 2px solid transparent;
      border-top: 2px solid currentColor;
      border-radius: 50%;
      animation: spin 1s linear infinite;
    }

    @keyframes spin {
      0% {
        transform: rotate(0deg);
      }

      100% {
        transform: rotate(360deg);
      }
    }

    .login-footer {
      text-align: center;
      margin-top: 2rem;
      padding-top: 1.5rem;
      border-top: 1px solid var(--border-color);
    }

    .login-footer a {
      color: var(--primary-color);
      text-decoration: none;
      font-size: 0.875rem;
    }

    .login-footer a:hover {
      text-decoration: underline;
    }

    .demo-credentials {
      background: var(--light-color);
      border: 1px solid var(--border-color);
      border-radius: 0.5rem;
      padding: 1rem;
      margin-bottom: 1.5rem;
    }

    .demo-credentials h4 {
      font-size: 0.875rem;
      font-weight: 600;
      color: var(--text-primary);
      margin-bottom: 0.5rem;
    }

    .demo-credentials p {
      font-size: 0.75rem;
      color: var(--text-secondary);
      margin: 0.25rem 0;
    }

    .demo-credentials code {
      background: white;
      padding: 0.125rem 0.25rem;
      border-radius: 0.25rem;
      font-family: monospace;
      border: 1px solid var(--border-color);
    }

    @media (max-width: 480px) {
      .login-container {
        padding: 1.5rem;
        margin: 0.5rem;
      }
    }
  </style>
</head>

<body>
  <div class="login-container">
    <div class="login-header">
      <h1><i class="fas fa-store"></i> Admin Login</h1>
      <p>เข้าสู่ระบบจัดการร้านค้า</p>
    </div>

    <!-- Demo Credentials -->
    <div class="demo-credentials">
      <h4><i class="fas fa-info-circle"></i> Demo Credentials</h4>
      <p>Email: <code>admin@example.com</code></p>
      <p>Password: <code>admin123</code></p>
    </div>

    <!-- Alert Container -->
    <div id="alertContainer"></div>

    <!-- Login Form -->
    <form id="loginForm">
      <div class="form-group">
        <label for="email" class="form-label">Email Address</label>
        <div class="input-group">
          <i class="fas fa-envelope input-icon"></i>
          <input type="email" id="email" name="email" class="form-input" placeholder="Enter your email address" required>
        </div>
      </div>

      <div class="form-group">
        <label for="password" class="form-label">Password</label>
        <div class="input-group">
          <i class="fas fa-lock input-icon"></i>
          <input type="password" id="password" name="password" class="form-input" placeholder="Enter your password" required>
          <button type="button" class="password-toggle" onclick="togglePassword()">
            <i class="fas fa-eye" id="passwordToggleIcon"></i>
          </button>
        </div>
      </div>

      <button type="submit" class="btn btn-primary" id="loginButton">
        <span id="loginButtonText">
          <i class="fas fa-sign-in-alt"></i>
          Sign In
        </span>
        <div class="loading-spinner" id="loginSpinner" style="display: none;"></div>
      </button>
    </form>

    <div class="login-footer">
      <a href="#" onclick="goBackToStore()">← Back to Store</a>
    </div>
  </div>

  <script>
    // DOM Elements
    const loginForm = document.getElementById('loginForm');
    const emailInput = document.getElementById('email');
    const passwordInput = document.getElementById('password');
    const loginButton = document.getElementById('loginButton');
    const loginButtonText = document.getElementById('loginButtonText');
    const loginSpinner = document.getElementById('loginSpinner');
    const alertContainer = document.getElementById('alertContainer');

    // Dynamic path detection
    const BASE_PATH = (() => {
      const path = window.location.pathname;
      const pathParts = path.split('/');

      // Find admin folder index
      const adminIndex = pathParts.indexOf('admin');
      if (adminIndex > 0) {
        // Return base path up to admin folder (excluding admin)
        return pathParts.slice(0, adminIndex).join('/');
      }

      // Default to root if admin not found in path
      return '';
    })();

    const ADMIN_BASE_PATH = BASE_PATH + '/admin';

    // API Base URL
    const API_BASE = BASE_PATH + '/api';

    // Check if already logged in
    document.addEventListener('DOMContentLoaded', function() {
      const token = localStorage.getItem('adminToken');
      if (token) {
        // Verify token is still valid
        fetch(`${API_BASE}/auth/me`, {
          headers: {
            'Authorization': `Bearer ${token}`
          }
        })
          .then(response => response.json())
          .then(data => {
            if (data.success && data.data.user.role === 'admin') {
              window.location.href = ADMIN_BASE_PATH + '/';
            } else {
              localStorage.removeItem('adminToken');
            }
          })
          .catch(() => {
            localStorage.removeItem('adminToken');
          });
      }
    });

    // Form submission
    loginForm.addEventListener('submit', async function(e) {
      e.preventDefault();

      const email = emailInput.value.trim();
      const password = passwordInput.value;

      if (!email || !password) {
        showAlert('Please fill in all fields', 'danger');
        return;
      }

      setLoading(true);
      clearAlerts();

      try {
        const response = await fetch(`${API_BASE}/auth/login`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            email: email,
            password: password
          })
        });

        const data = await response.json();

        if (response.ok && data.success) {
          // Check if user is admin
          if (data.data.user.role !== 'admin') {
            showAlert('Access denied. Admin privileges required.', 'danger');
            setLoading(false);
            return;
          }

          // Store token and redirect
          localStorage.setItem('adminToken', data.data.access_token);

          showAlert('Login successful! Redirecting...', 'success');

          setTimeout(() => {
            window.location.href = ADMIN_BASE_PATH + '/';
          }, 1000);
        } else {
          showAlert(data.error || 'Login failed. Please try again.', 'danger');
          setLoading(false);
        }
      } catch (error) {
        console.error('Login error:', error);
        showAlert('Network error. Please check your connection and try again.', 'danger');
        setLoading(false);
      }
    });

    // Set loading state
    function setLoading(loading) {
      loginButton.disabled = loading;

      if (loading) {
        loginButtonText.style.display = 'none';
        loginSpinner.style.display = 'block';
      } else {
        loginButtonText.style.display = 'flex';
        loginSpinner.style.display = 'none';
      }
    }

    // Show alert
    function showAlert(message, type = 'info') {
      const alert = document.createElement('div');
      alert.className = `alert alert-${type}`;
      alert.innerHTML = `
                <i class="fas fa-${getAlertIcon(type)}"></i>
                ${message}
            `;

      alertContainer.appendChild(alert);

      // Auto remove after 5 seconds
      setTimeout(() => {
        if (alert.parentNode) {
          alert.remove();
        }
      }, 5000);
    }

    // Clear all alerts
    function clearAlerts() {
      alertContainer.innerHTML = '';
    }

    // Get alert icon
    function getAlertIcon(type) {
      const icons = {
        'success': 'check-circle',
        'danger': 'exclamation-circle',
        'warning': 'exclamation-triangle',
        'info': 'info-circle'
      };
      return icons[type] || 'info-circle';
    }

    // Toggle password visibility
    function togglePassword() {
      const passwordField = document.getElementById('password');
      const toggleIcon = document.getElementById('passwordToggleIcon');

      if (passwordField.type === 'password') {
        passwordField.type = 'text';
        toggleIcon.className = 'fas fa-eye-slash';
      } else {
        passwordField.type = 'password';
        toggleIcon.className = 'fas fa-eye';
      }
    }

    // Auto-fill demo credentials (for development)
    document.addEventListener('keydown', function(e) {
      if (e.ctrlKey && e.key === 'd') {
        e.preventDefault();
        emailInput.value = 'admin@example.com';
        passwordInput.value = 'admin123';
        showAlert('Demo credentials filled. Press Ctrl+Enter to login quickly.', 'info');
      }

      if (e.ctrlKey && e.key === 'Enter') {
        e.preventDefault();
        loginForm.dispatchEvent(new Event('submit'));
      }
    });

    // Go back to store function
    function goBackToStore() {
      window.location.href = BASE_PATH + '/';
    }
  </script>
</body>

</html>