Login.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import { useState } from 'react';
  2. import { Link, useNavigate } from 'react-router-dom';
  3. import { useAuth } from '@/hooks/useAuth';
  4. import { Eye, EyeOff, Shield } from 'lucide-react';
  5. export default function Login() {
  6. const [email, setEmail] = useState('');
  7. const [password, setPassword] = useState('');
  8. const [showPassword, setShowPassword] = useState(false);
  9. const { login, loginLoading } = useAuth();
  10. const navigate = useNavigate();
  11. const handleSubmit = async (e: React.FormEvent) => {
  12. e.preventDefault();
  13. try {
  14. await login({ email, password });
  15. } catch (error) {
  16. // Error is handled by useAuth hook
  17. }
  18. };
  19. return (
  20. <div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
  21. <div className="max-w-md w-full space-y-8">
  22. {/* Header */}
  23. <div className="text-center">
  24. <div className="mx-auto h-16 w-16 rounded-full bg-primary-100 flex items-center justify-center">
  25. <Shield className="h-8 w-8 text-primary-600" />
  26. </div>
  27. <h2 className="mt-6 text-3xl font-extrabold text-gray-900">
  28. SaaS Platform
  29. </h2>
  30. <p className="mt-2 text-sm text-gray-600">
  31. Sign in to manage your platform
  32. </p>
  33. </div>
  34. {/* Login Form */}
  35. <div className="bg-white py-8 px-6 shadow-xl rounded-xl">
  36. <form className="space-y-6" onSubmit={handleSubmit}>
  37. {/* Email */}
  38. <div>
  39. <label htmlFor="email" className="block text-sm font-medium text-gray-700">
  40. Email address
  41. </label>
  42. <input
  43. id="email"
  44. name="email"
  45. type="email"
  46. autoComplete="email"
  47. required
  48. value={email}
  49. onChange={(e) => setEmail(e.target.value)}
  50. className="mt-1 input-field"
  51. placeholder="Enter your email"
  52. />
  53. </div>
  54. {/* Password */}
  55. <div>
  56. <label htmlFor="password" className="block text-sm font-medium text-gray-700">
  57. Password
  58. </label>
  59. <div className="mt-1 relative">
  60. <input
  61. id="password"
  62. name="password"
  63. type={showPassword ? 'text' : 'password'}
  64. autoComplete="current-password"
  65. required
  66. value={password}
  67. onChange={(e) => setPassword(e.target.value)}
  68. className="input-field pr-10"
  69. placeholder="Enter your password"
  70. />
  71. <button
  72. type="button"
  73. className="absolute inset-y-0 right-0 pr-3 flex items-center"
  74. onClick={() => setShowPassword(!showPassword)}
  75. >
  76. {showPassword ? (
  77. <EyeOff className="h-5 w-5 text-gray-400" />
  78. ) : (
  79. <Eye className="h-5 w-5 text-gray-400" />
  80. )}
  81. </button>
  82. </div>
  83. </div>
  84. {/* Submit Button */}
  85. <div>
  86. <button
  87. type="submit"
  88. disabled={loginLoading}
  89. className="w-full btn-primary flex items-center justify-center"
  90. >
  91. {loginLoading ? (
  92. <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
  93. ) : (
  94. 'Sign in'
  95. )}
  96. </button>
  97. </div>
  98. </form>
  99. {/* Demo Credentials */}
  100. <div className="mt-6 border-t border-gray-200 pt-6">
  101. <p className="text-center text-sm text-gray-600">
  102. Demo Credentials:
  103. </p>
  104. <div className="mt-2 text-xs text-gray-500 text-center">
  105. <p>Email: admin@example.com</p>
  106. <p>Password: demo_password</p>
  107. </div>
  108. </div>
  109. </div>
  110. {/* Footer */}
  111. <div className="text-center">
  112. <p className="text-sm text-gray-500">
  113. Don't have an account?{' '}
  114. <Link
  115. to="/register"
  116. className="font-medium text-primary-600 hover:text-primary-500"
  117. >
  118. Contact administrator
  119. </Link>
  120. </p>
  121. </div>
  122. </div>
  123. </div>
  124. );
  125. }