File size: 7,194 Bytes
ea9ca44
 
 
 
 
01c8f1f
 
 
ea9ca44
 
 
 
 
01c8f1f
ea9ca44
 
 
 
 
 
 
 
 
 
 
 
 
01c8f1f
ea9ca44
 
 
 
 
 
01c8f1f
ea9ca44
01c8f1f
ea9ca44
01c8f1f
ea9ca44
01c8f1f
ea9ca44
 
 
01c8f1f
ea9ca44
 
01c8f1f
 
 
ea9ca44
01c8f1f
ea9ca44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9d6cc86
01c8f1f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ea9ca44
 
 
 
 
 
 
01c8f1f
ea9ca44
 
 
 
 
 
01c8f1f
ea9ca44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
01c8f1f
ea9ca44
 
 
 
 
 
 
 
 
 
 
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
import { supabase } from '../supabaseClient';
import React, { useState } from 'react';
import { motion } from 'framer-motion';

// --- SVG Icon Components ---
const UserIcon = () => (<svg style={{ width: '20px', height: '20px', color: 'rgba(255, 255, 255, 0.7)' }} viewBox="0 0 20 20" fill="currentColor"><path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" /></svg>);
const LockIcon = () => (<svg style={{ width: '20px', height: '20px', color: 'rgba(255, 255, 255, 0.7)' }} viewBox="0 0 20 20" fill="currentColor"><path fillRule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clipRule="evenodd" /></svg>);
const SpinnerIcon = () => <motion.svg animate={{ rotate: 360 }} transition={{ duration: 1, repeat: Infinity, ease: "linear" }} style={{ width: '20px', height: '20px' }} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 12a9 9 0 1 1-6.219-8.56" /></motion.svg>;

export default function AdminLogin({ onNavigate }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const handleAdminLogin = async (e) => {
    e.preventDefault();
    setError('');

    if (!email.trim() || !password) {
      setError('Email and password are required.');
      return;
    }

    setLoading(true);

    try {
      // 1. Authenticate
      const { data: { user }, error: authError } = await supabase.auth.signInWithPassword({
        email: email,
        password: password,
      });

      if (authError) throw authError;
      if (!user) throw new Error("Login failed.");

      // 2. Check Role
      const { data: roleData, error: roleError } = await supabase
        .from('user_roles')
        .select('role')
        .eq('user_id', user.id)
        .single();

      if (roleError && roleError.code !== 'PGRST116') {
        throw new Error("Could not verify user role.");
      }

      // 3. Admin Check
      // Accepts 'admin' or 'recruiter' based on your previous logic
      if (roleData && (roleData.role === 'admin' || roleData.role === 'recruiter')) {
        if (typeof onNavigate === 'function') {
          onNavigate('admin-dashboard');
        }
      } else {
        await supabase.auth.signOut();
        throw new Error("Access Denied. Authorized personnel only.");
      }

    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div style={{
      position: 'relative', minHeight: '100vh', width: '100%', display: 'flex',
      alignItems: 'center', justifyContent: 'center', overflow: 'hidden',
      backgroundColor: '#020617', color: 'white', fontFamily: "'Montserrat', sans-serif", padding: '1rem',
    }}>
      <style>{`@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus, input:-webkit-autofill:active { transition: background-color 5000s ease-in-out 0s; -webkit-text-fill-color: #fff !important; }`}</style>

      {/* --- 🔴 FIXED BACK BUTTON --- */}
      <button
        onClick={() => onNavigate('login')}
        style={{
          position: 'fixed', // Fixed to stay on top
          top: '20px',
          left: '20px',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          gap: '8px',
          padding: '12px 20px',
          backgroundColor: '#510000', // Red for Admin
          color: '#ffffffbe',
          border: '2px solid #510000',
          borderRadius: '10px',
          fontWeight: '700',
          cursor: 'pointer',
          zIndex: 9999, // High z-index
          boxShadow: '0 4px 10px rgba(0,0,0,0.3)'
        }}
      >
        <span></span> Back
      </button>

      {/* Background Shapes */}
      <>
        <div style={{ position: 'absolute', borderRadius: '50%', filter: 'blur(80px)', opacity: 0.4, width: '384px', height: '384px', backgroundColor: '#EF4444', top: '-50px', left: '-100px' }}></div>
        <div style={{ position: 'absolute', borderRadius: '50%', filter: 'blur(80px)', opacity: 0.4, width: '320px', height: '320px', backgroundColor: '#DC2626', bottom: '-80px', right: '-120px' }}></div>
      </>

      <motion.div
        initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, ease: "easeOut" }}
        style={{
          width: '100%', maxWidth: '512px', borderRadius: '1rem', backgroundColor: 'rgba(239, 68, 68, 0.1)',
          backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)', border: '1px solid rgba(239, 68, 68, 0.3)',
          padding: '2rem', zIndex: 10,
        }}>

        <div style={{ textAlign: 'center', marginBottom: '2rem' }}>
          <h2 style={{ fontSize: '1.875rem', fontWeight: 'bold' }}>Admin Portal</h2>
          <p style={{ color: '#d1d5db', marginTop: '0.25rem' }}>Manage CV submissions and applications</p>
        </div>

        <form onSubmit={handleAdminLogin}>
          <div style={{ marginBottom: '1.5rem' }}>
            <div style={{ position: 'relative' }}>
              <div style={{ position: 'absolute', left: '0.75rem', top: '50%', transform: 'translateY(-50%)', zIndex: 1 }}><UserIcon /></div>
              <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} disabled={loading} placeholder="admin@email.com" style={{ width: '100%', padding: '0.75rem 1rem 0.75rem 2.5rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid rgba(239, 68, 68, 0.3)`, borderRadius: '0.5rem', color: 'white', boxSizing: 'border-box' }} />
            </div>
          </div>
          <div style={{ marginBottom: '1.5rem' }}>
            <div style={{ position: 'relative' }}>
              <div style={{ position: 'absolute', left: '0.75rem', top: '50%', transform: 'translateY(-50%)', zIndex: 1 }}><LockIcon /></div>
              <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} disabled={loading} placeholder="Password" style={{ width: '100%', padding: '0.75rem 1rem 0.75rem 2.5rem', backgroundColor: 'rgba(255, 255, 255, 0.1)', border: `1px solid rgba(239, 68, 68, 0.3)`, borderRadius: '0.5rem', color: 'white', boxSizing: 'border-box' }} />
            </div>
          </div>

          {error && <p style={{ color: '#F87171', fontSize: '0.875rem', marginTop: '-0.5rem', marginBottom: '1.5rem', textAlign: 'center' }}>{error}</p>}

          <motion.button type="submit" disabled={loading} whileHover={{ scale: loading ? 1 : 1.03 }} whileTap={{ scale: loading ? 1 : 0.98 }} style={{ width: '100%', backgroundColor: '#EF4444', color: 'white', fontWeight: 'bold', padding: '0.75rem 0', borderRadius: '0.5rem', border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px', opacity: loading ? 0.7 : 1 }}>
            {loading && <SpinnerIcon />}
            {loading ? 'Verifying...' : 'Continue'}
          </motion.button>
        </form>
      </motion.div>
    </div>
  );
}