File size: 7,625 Bytes
191b322
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import React, { useState, useEffect } from 'react';
import { UserRole } from '../types';
import { LogIn, ShieldCheck, Construction, Calculator, Briefcase, User as UserIcon, Mail, Lock } from 'lucide-react';

interface AuthProps {
  onUserChange: (user: any | null) => void;
}

const Auth: React.FC<AuthProps> = ({ onUserChange }) => {
  const [isSignup, setIsSignup] = useState(false);
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [role, setRole] = useState<UserRole>('DIRECTOR');
  const [error, setError] = useState<string | null>(null);
  
  // Auto-login if token exists
  useEffect(() => {
    const token = localStorage.getItem('auth_token');
    if (token) {
      fetch('/api/auth/me', {
        headers: { 'Authorization': `Bearer ${token}` }
      })
        .then(res => {
          if (!res.ok) throw new Error("Invalid token");
          return res.json();
        })
        .then(data => onUserChange(data.user))
        .catch(err => {
          console.error("Auto-login failed:", err);
          localStorage.removeItem('auth_token');
          localStorage.removeItem('local_user_uid');
        });
    }
  }, [onUserChange]);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError(null);
    
    try {
      const endpoint = isSignup ? '/api/auth/signup' : '/api/auth/login';
      const body = isSignup 
        ? { name, email, password, role }
        : { email, password };
        
      const res = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body)
      });
      
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || (isSignup ? "Signup failed" : "Login failed"));

      if (!isSignup) {
        if (data.token && data.user) {
          localStorage.setItem('auth_token', data.token);
          localStorage.setItem('local_user_uid', data.user.uid);
          onUserChange(data.user);
        }
      } else {
        setIsSignup(false);
        alert("Signup successful! Please login.");
      }
    } catch (e: any) {
      setError(e.message);
    }
  };

  return (
    <div className="min-h-screen flex flex-col items-center justify-center bg-slate-50 p-4 font-sans">
      <div className="bg-white rounded-2xl shadow-xl w-full max-w-md overflow-hidden border border-slate-200">
        <div className="p-8">
          <div className="text-center mb-8">
            <div className="w-16 h-16 bg-blue-600 text-white rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-lg rotate-3">
              <Construction className="w-8 h-8" />
            </div>
            <h1 className="text-2xl font-bold text-slate-900 mb-2 leading-tight font-heading">BuildTrack</h1>
            <p className="text-slate-500 text-sm">{isSignup ? 'Create an account to begin' : 'Welcome back'}</p>
          </div>
          
          {error && <div className="mb-4 p-3 bg-red-50 text-red-600 text-sm rounded-lg">{error}</div>}

          <form onSubmit={handleSubmit} className="space-y-4">
            {isSignup && (
              <div className="space-y-1">
                <label className="text-xs font-bold text-slate-700 uppercase tracking-wider ml-1">Your Name</label>
                <div className="relative">
                  <UserIcon className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
                  <input
                    type="text"
                    required
                    value={name}
                    onChange={(e) => setName(e.target.value)}
                    className="w-full pl-10 pr-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:ring-2 focus:ring-blue-600 outline-none text-sm transition-all"
                    placeholder="Enter your name"
                  />
                </div>
              </div>
            )}
            
            <div className="space-y-1">
              <label className="text-xs font-bold text-slate-700 uppercase tracking-wider ml-1">Email</label>
              <div className="relative">
                <Mail className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
                <input
                  type="email"
                  required
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  className="w-full pl-10 pr-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:ring-2 focus:ring-blue-600 outline-none text-sm transition-all"
                  placeholder="Enter email"
                />
              </div>
            </div>

            <div className="space-y-1">
              <label className="text-xs font-bold text-slate-700 uppercase tracking-wider ml-1">Password</label>
              <div className="relative">
                <Lock className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
                <input
                  type="password"
                  required
                  value={password}
                  onChange={(e) => setPassword(e.target.value)}
                  className="w-full pl-10 pr-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:ring-2 focus:ring-blue-600 outline-none text-sm transition-all"
                  placeholder="Enter password"
                />
              </div>
            </div>

            {isSignup && (
              <div className="space-y-1 mt-4">
                <label className="text-xs font-bold text-slate-700 uppercase tracking-wider ml-1">Select Role</label>
                <div className="grid grid-cols-2 gap-2 mt-2">
                  {[
                    { r: 'DIRECTOR', icon: <ShieldCheck className="w-4 h-4" /> },
                    { r: 'MANAGER', icon: <Briefcase className="w-4 h-4" /> },
                    { r: 'ENGINEER', icon: <Construction className="w-4 h-4" /> },
                    { r: 'ACCOUNTANT', icon: <Calculator className="w-4 h-4" /> }
                  ].map((item) => (
                    <button
                      key={item.r}
                      type="button"
                      onClick={() => setRole(item.r as UserRole)}
                      className={`flex items-center gap-2 p-3 rounded-xl border text-xs font-bold transition-all ${
                        role === item.r 
                          ? 'bg-blue-50 border-blue-600 text-blue-700' 
                          : 'bg-white border-slate-200 text-slate-600 hover:bg-slate-50'
                      }`}
                    >
                      {item.icon}
                      {item.r}
                    </button>
                  ))}
                </div>
              </div>
            )}

            <button
              type="submit"
              className="w-full flex items-center justify-center gap-2 bg-slate-900 text-white font-bold py-3 px-4 rounded-xl hover:bg-slate-800 transition-all shadow-lg active:scale-95 mt-6"
            >
              <LogIn className="w-4 h-4" />
              {isSignup ? 'Create Account' : 'Enter Workspace'}
            </button>
            <button
                type="button"
                onClick={() => setIsSignup(!isSignup)}
                className="w-full text-slate-500 py-3 text-sm hover:underline mt-2"
            >
                {isSignup ? 'Already have an account? Login' : 'Need an account? Sign up'}
            </button>
          </form>
        </div>
      </div>
    </div>
  );
};
export default Auth;