Auth.tsx 5.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import * as React from 'react';
  2. import { authService } from '../services/authService';
  3. import { Icon } from './ui/Icon';
  4. import { useTranslation } from '../hooks/useI18n';
  5. interface AuthProps {
  6. onAuthSuccess: () => void;
  7. }
  8. const Auth: React.FC<AuthProps> = ({ onAuthSuccess }) => {
  9. const { t } = useTranslation();
  10. const [isLogin, setIsLogin] = React.useState(true);
  11. const [email, setEmail] = React.useState('');
  12. const [password, setPassword] = React.useState('');
  13. const [error, setError] = React.useState('');
  14. const [isLoading, setIsLoading] = React.useState(false);
  15. const handleSubmit = async (e: React.FormEvent) => {
  16. e.preventDefault();
  17. setError('');
  18. setIsLoading(true);
  19. const action = isLogin ? authService.login : authService.register;
  20. const result = action(email, password);
  21. if (result.success) {
  22. onAuthSuccess();
  23. } else {
  24. setError(result.message);
  25. }
  26. setIsLoading(false);
  27. };
  28. return (
  29. <div className="w-full h-screen flex items-center justify-center bg-gray-100 dark:bg-gray-900 p-4">
  30. <div className="w-full max-w-sm mx-auto bg-white dark:bg-gray-800 rounded-2xl shadow-xl p-8 border border-gray-200 dark:border-gray-700">
  31. <div className="text-center mb-8">
  32. <div className="inline-flex items-center justify-center gap-3 mb-4">
  33. <div className="bg-gradient-to-r from-green-400 to-blue-500 p-2 rounded-lg">
  34. <Icon className="h-8 w-8 text-white">
  35. <path strokeLinecap="round" strokeLinejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
  36. </Icon>
  37. </div>
  38. <h1 className="text-3xl font-bold text-gray-900 dark:text-white">GreenPage AI</h1>
  39. </div>
  40. <h2 className="text-2xl font-semibold text-gray-800 dark:text-gray-200">{isLogin ? t('auth.welcome_back') : t('auth.create_account')}</h2>
  41. <p className="text-gray-500 dark:text-gray-400 mt-1">
  42. {isLogin ? t('auth.signin_prompt') : t('auth.signup_prompt')}
  43. </p>
  44. </div>
  45. <form onSubmit={handleSubmit} className="space-y-6">
  46. <div>
  47. <label htmlFor="email" className="block text-sm font-medium text-gray-700 dark:text-gray-300">{t('auth.email')}</label>
  48. <input
  49. id="email"
  50. type="email"
  51. value={email}
  52. onChange={(e) => setEmail(e.target.value)}
  53. required
  54. className="mt-1 block w-full px-3 py-2 bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-brand-primary focus:border-brand-primary sm:text-sm"
  55. />
  56. </div>
  57. <div>
  58. <label htmlFor="password" className="block text-sm font-medium text-gray-700 dark:text-gray-300">{t('auth.password')}</label>
  59. <input
  60. id="password"
  61. type="password"
  62. value={password}
  63. onChange={(e) => setPassword(e.target.value)}
  64. required
  65. className="mt-1 block w-full px-3 py-2 bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-brand-primary focus:border-brand-primary sm:text-sm"
  66. />
  67. </div>
  68. {error && <p className="text-sm text-red-500">{error}</p>}
  69. <div>
  70. <button
  71. type="submit"
  72. disabled={isLoading}
  73. className="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-brand-primary hover:bg-brand-secondary focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brand-primary disabled:bg-gray-500"
  74. >
  75. {isLoading ? t('auth.processing') : (isLogin ? t('auth.signin') : t('auth.signup'))}
  76. </button>
  77. </div>
  78. </form>
  79. <div className="mt-6 text-center">
  80. <p className="text-sm text-gray-600 dark:text-gray-400">
  81. {isLogin ? t('auth.no_account') : t('auth.has_account')}
  82. <button onClick={() => { setIsLogin(!isLogin); setError(''); }} className="ml-1 font-medium text-brand-primary hover:text-brand-secondary">
  83. {isLogin ? t('auth.signup') : t('auth.signin')}
  84. </button>
  85. </p>
  86. </div>
  87. </div>
  88. </div>
  89. );
  90. };
  91. export default Auth;