Spaces:
Sleeping
Sleeping
| import React, { useState, useEffect } from 'react'; | |
| import { motion } from 'framer-motion'; | |
| // --- Icons --- | |
| const CalendarIcon = () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>; | |
| const ClockIcon = () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>; | |
| const VideoIcon = () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="23 7 16 12 23 17 23 7"></polygon><rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect></svg>; | |
| const MapPinIcon = () => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>; | |
| // NEW ICON | |
| const ChevronDownIcon = () => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>; | |
| export default function ScheduleInterviewModal({ isOpen, onClose, onConfirm, candidateName }) { | |
| // --- State --- | |
| const [date, setDate] = useState(''); | |
| const [time, setTime] = useState('10:00'); | |
| const [interviewType, setInterviewType] = useState('Technical'); | |
| const [mode, setMode] = useState('Online'); | |
| const [details, setDetails] = useState(''); | |
| const [interviewerName, setInterviewerName] = useState('Hiring Manager'); | |
| const [interviewerRole, setInterviewerRole] = useState('Technical Lead'); | |
| // Auto-fill Link for Online | |
| // Auto-fill Link for Online | |
| useEffect(() => { | |
| if (mode === 'Online' && !details) { | |
| const randomId = Math.random().toString(36).substring(7); | |
| // OLD (Fake): setDetails(`https://meet.google.com/${randomId}-intv`); | |
| // NEW (Working Real Video Call): | |
| setDetails(`https://meet.jit.si/IRIS-Interview-${candidateName.replace(/\s+/g, '')}-${randomId}`); | |
| } else if (mode === 'Offline' && details.includes('meet')) { | |
| setDetails(''); | |
| } | |
| }, [mode]); | |
| const handleSubmit = () => { | |
| if (!date || !time || !details) { | |
| alert('Please fill in Date, Time, and Location/Link.'); | |
| return; | |
| } | |
| onConfirm({ date, time, interviewType, mode, details, interviewerName, interviewerRole }); | |
| }; | |
| if (!isOpen) return null; | |
| // --- Styles --- | |
| const overlayStyle = { | |
| position: 'fixed', inset: 0, backgroundColor: 'rgba(0,0,0,0.85)', | |
| backdropFilter: 'blur(8px)', display: 'flex', alignItems: 'center', | |
| justifyContent: 'center', zIndex: 9999 | |
| }; | |
| // Modal Background: Dark Gray (#111827) | |
| const modalStyle = { | |
| width: '100%', maxWidth: '600px', backgroundColor: '#111827', | |
| border: '1px solid #374151', borderRadius: '1.5rem', padding: '2.5rem', | |
| boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.9)' | |
| }; | |
| const labelStyle = { | |
| display: 'flex', alignItems: 'center', gap: '6px', color: '#9ca3af', | |
| fontSize: '0.85rem', fontWeight: '700', marginBottom: '0.6rem', | |
| textTransform: 'uppercase', letterSpacing: '0.05em' | |
| }; | |
| // Black Background (#000000) for high contrast | |
| const inputStyle = { | |
| width: '100%', padding: '0.875rem', borderRadius: '0.75rem', | |
| border: '1px solid #4B5563', backgroundColor: '#5b0e1aa1', | |
| color: '#FFFFFF', outline: 'none', fontSize: '1rem', | |
| transition: 'all 0.2s', colorScheme: 'dark' | |
| }; | |
| return ( | |
| <div style={overlayStyle}> | |
| <style> | |
| {` | |
| /* FORCE ICONS TO BE BRIGHT WHITE */ | |
| input[type="date"]::-webkit-calendar-picker-indicator, | |
| input[type="time"]::-webkit-calendar-picker-indicator { | |
| filter: invert(1) brightness(200%); /* Invert black to white & double brightness */ | |
| cursor: pointer; | |
| opacity: 1; /* Maximum visibility */ | |
| } | |
| /* Hover Effect */ | |
| input[type="date"]::-webkit-calendar-picker-indicator:hover, | |
| input[type="time"]::-webkit-calendar-picker-indicator:hover { | |
| opacity: 0.8; | |
| transform: scale(1.1); /* Slight zoom on hover */ | |
| } | |
| /* Dropdown Options Background */ | |
| select option { | |
| background-color: #000000; | |
| color: white; | |
| padding: 10px; | |
| } | |
| /* Focus States - Red Glow */ | |
| input:focus, select:focus { | |
| border-color: #EF4444 ; | |
| box-shadow: 0 0 0 1px #EF4444; | |
| background-color: #0a0a0a; /* Slightly lighter black on focus */ | |
| } | |
| `} | |
| </style> | |
| <motion.div initial={{ scale: 0.95, opacity: 0 }} animate={{ scale: 1, opacity: 1 }} style={modalStyle}> | |
| {/* Header */} | |
| <div style={{ marginBottom: '2rem', borderBottom: '1px solid #374151', paddingBottom: '1.5rem' }}> | |
| <h2 style={{ fontSize: '1.75rem', fontWeight: 'bold', color: 'white', marginBottom: '0.25rem' }}>Schedule Interview</h2> | |
| <p style={{ color: '#9ca3af', fontSize: '0.95rem' }}>Coordinate session with <span style={{ color: '#EF4444', fontWeight: 'bold' }}>{candidateName}</span></p> | |
| </div> | |
| <div style={{ display: 'grid', gap: '1.5rem' }}> | |
| {/* 1. Date & Time */} | |
| <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem' }}> | |
| <div> | |
| <label style={labelStyle}><CalendarIcon /> Date</label> | |
| <input type="date" value={date} onChange={e => setDate(e.target.value)} style={inputStyle} /> | |
| </div> | |
| <div> | |
| <label style={labelStyle}><ClockIcon /> Time</label> | |
| <input type="time" value={time} onChange={e => setTime(e.target.value)} style={inputStyle} /> | |
| </div> | |
| </div> | |
| {/* 2. Type & Mode */} | |
| <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem' }}> | |
| <div> | |
| <label style={labelStyle}>Interview Type</label> | |
| <div style={{ position: 'relative' }}> | |
| <select value={interviewType} onChange={e => setInterviewType(e.target.value)} style={{...inputStyle, appearance: 'none', cursor: 'pointer'}}> | |
| <option>Technical</option> | |
| <option>HR Round</option> | |
| <option>Managerial</option> | |
| <option>Coding Test</option> | |
| </select> | |
| {/* UPDATED ICON HERE */} | |
| <div style={{ position: 'absolute', right: '12px', top: '50%', transform: 'translateY(-50%)', pointerEvents: 'none', color: '#9ca3af' }}> | |
| <ChevronDownIcon /> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <label style={labelStyle}>Mode</label> | |
| <div style={{ display: 'flex', borderRadius: '0.75rem', overflow: 'hidden', border: '1px solid #4B5563', backgroundColor: '#000000' }}> | |
| <button onClick={() => setMode('Online')} style={{ flex: 1, padding: '0.875rem', background: mode === 'Online' ? '#EF4444' : 'transparent', color: 'white', border: 'none', cursor: 'pointer', display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '0.5rem', fontWeight: mode === 'Online' ? 'bold' : 'normal', transition: 'background 0.2s' }}> | |
| <VideoIcon /> Online | |
| </button> | |
| <button onClick={() => setMode('Offline')} style={{ flex: 1, padding: '0.875rem', background: mode === 'Offline' ? '#D97706' : 'transparent', color: 'white', border: 'none', cursor: 'pointer', display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '0.5rem', fontWeight: mode === 'Offline' ? 'bold' : 'normal', transition: 'background 0.2s' }}> | |
| <MapPinIcon /> In-Person | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| {/* 3. Location / Link */} | |
| <div> | |
| <label style={labelStyle}>{mode === 'Online' ? 'Meeting Link' : 'Office Address'}</label> | |
| <input | |
| type="text" | |
| value={details} | |
| onChange={e => setDetails(e.target.value)} | |
| placeholder={mode === 'Online' ? "https://meet.google.com/..." : "e.g., Conf Room A, 5th Floor"} | |
| style={inputStyle} | |
| /> | |
| </div> | |
| {/* 4. Interviewer Details */} | |
| <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem' }}> | |
| <div> | |
| <label style={labelStyle}>Interviewer Name</label> | |
| <input type="text" value={interviewerName} onChange={e => setInterviewerName(e.target.value)} style={inputStyle} /> | |
| </div> | |
| <div> | |
| <label style={labelStyle}>Role</label> | |
| <input type="text" value={interviewerRole} onChange={e => setInterviewerRole(e.target.value)} style={inputStyle} /> | |
| </div> | |
| </div> | |
| </div> | |
| {/* Footer Buttons */} | |
| <div style={{ display: 'flex', justifyContent: 'flex-end', gap: '1rem', marginTop: '3rem', borderTop: '1px solid #374151', paddingTop: '1.5rem' }}> | |
| <button onClick={onClose} style={{ padding: '0.75rem 1.5rem', borderRadius: '0.5rem', background: 'transparent', color: '#9ca3af', border: '1px solid #4B5563', cursor: 'pointer', fontSize: '0.95rem', fontWeight: '600', transition: 'all 0.2s' }} | |
| onMouseOver={(e) => {e.target.style.color = 'white'; e.target.style.borderColor = 'white'}} | |
| onMouseOut={(e) => {e.target.style.color = '#9ca3af'; e.target.style.borderColor = '#4B5563'}}> | |
| Cancel | |
| </button> | |
| <button onClick={handleSubmit} style={{ padding: '0.75rem 2.5rem', borderRadius: '0.5rem', background: '#EF4444', color: 'white', border: 'none', fontWeight: 'bold', cursor: 'pointer', boxShadow: '0 4px 12px rgba(220, 38, 38, 0.4)', fontSize: '0.95rem', transform: 'translateY(0)', transition: 'transform 0.1s' }} | |
| onMouseDown={(e) => e.target.style.transform = 'translateY(1px)'} | |
| onMouseUp={(e) => e.target.style.transform = 'translateY(0)'}> | |
| Confirm Schedule | |
| </button> | |
| </div> | |
| </motion.div> | |
| </div> | |
| ); | |
| } |