frontendt / src /components /Lobby.jsx
ayushsinghal1510's picture
Added coaching and hotel
252a04f
Raw
History Blame Contribute Delete
7.88 kB
import { useState } from 'react'
import { COMPANIES } from '../lib/companies'
import { VX_SERVER } from '../lib/webrtc'
const DEFAULT_KEY = 'vk_Qg95CQBuNFuiiHMCVtgo9bh9kx0N1ACnaj8zdJyg5qsBDWTjxt2ZoegM2UCdKfCY'
export default function Lobby({ onJoin }) {
const [name, setName] = useState('Ayush')
const [company, setCompany] = useState(null)
const [apiKey] = useState(DEFAULT_KEY)
const [server] = useState(VX_SERVER)
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
async function handleStart() {
if (!name.trim()) return setError('Enter your name')
if (!company) return setError('Choose a company to interview for')
if (!apiKey.trim()) return setError('Enter your API key')
if (!server.trim()) return setError('Enter the server address')
setError('')
setLoading(true)
await onJoin({ name: name.trim(), company: COMPANIES[company], apiKey: apiKey.trim(), server: server.trim() })
setLoading(false)
}
function handleKey(e) {
if (e.key === 'Enter' && !loading) handleStart()
}
return (
<div style={styles.page}>
<div style={styles.glow1} />
<div style={styles.glow2} />
<div style={styles.inner}>
<p style={styles.pill}>AI-powered mock interview</p>
<h1 style={styles.title}>
Practice like it's<br />
<span style={{ color: 'var(--accent)' }}>the real thing.</span>
</h1>
<p style={styles.subtitle}>
Pick a company. Start talking. Get honest feedback — on your answers <em>and</em> your presence.
</p>
{/* name */}
<div style={styles.fieldGroup}>
<label style={styles.label}>Your name</label>
<input
style={styles.input}
value={name}
onChange={e => setName(e.target.value)}
onKeyDown={handleKey}
placeholder="e.g. Ayush"
autoComplete="off"
/>
</div>
{/* company picker */}
<div style={styles.fieldGroup}>
<label style={styles.label}>Interview for</label>
<div style={styles.companyGrid}>
{Object.values(COMPANIES).map(c => (
<CompanyCard
key={c.id}
company={c}
selected={company === c.id}
onSelect={() => { setCompany(c.id); setError('') }}
/>
))}
</div>
</div>
{error && <p style={styles.error}>{error}</p>}
<button
style={{ ...styles.startBtn, opacity: loading ? 0.5 : 1, cursor: loading ? 'not-allowed' : 'pointer' }}
onClick={handleStart}
disabled={loading}
>
{loading ? 'Starting…' : 'Start interview →'}
</button>
<p style={styles.fine}>
Your camera and microphone will be used. Everything stays in session.
</p>
</div>
</div>
)
}
function CompanyCard({ company, selected, onSelect }) {
return (
<button
onClick={onSelect}
style={{
...styles.companyCard,
borderColor: selected ? company.accent : 'var(--border2)',
background: selected ? `${company.accent}10` : 'var(--surface)',
}}
>
<span style={{ ...styles.companyIcon, background: `${company.accent}20`, color: company.accent }}>
{company.icon}
</span>
<div style={styles.companyInfo}>
<span style={styles.companyName}>{company.name}</span>
<span style={styles.companyTag}>{company.tagline}</span>
<div style={styles.companyPills}>
{company.questionStyle.map(s => (
<span key={s} style={styles.qpill}>{s}</span>
))}
</div>
</div>
{selected && (
<span style={{ ...styles.checkmark, color: company.accent }}></span>
)}
</button>
)
}
const styles = {
page: {
minHeight: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '40px 20px',
position: 'relative',
overflowY: 'auto',
overflowX: 'hidden',
},
glow1: {
position: 'fixed',
top: 0, left: 0, right: 0, bottom: 0,
background: 'radial-gradient(ellipse 60% 50% at 20% 80%, rgba(200,240,96,.05) 0%, transparent 70%)',
pointerEvents: 'none',
},
glow2: {
position: 'fixed',
top: 0, left: 0, right: 0, bottom: 0,
background: 'radial-gradient(ellipse 50% 50% at 80% 20%, rgba(96,208,240,.04) 0%, transparent 70%)',
pointerEvents: 'none',
},
inner: {
width: '100%',
maxWidth: 560,
display: 'flex',
flexDirection: 'column',
gap: 0,
animation: 'slide-up .4s ease',
position: 'relative',
zIndex: 1,
},
pill: {
display: 'inline-block',
alignSelf: 'flex-start',
fontFamily: 'var(--mono)',
fontSize: 10,
letterSpacing: '.2em',
textTransform: 'uppercase',
color: 'var(--accent)',
border: '1px solid rgba(200,240,96,.25)',
padding: '4px 10px',
borderRadius: 20,
marginBottom: 20,
},
title: {
fontSize: 'clamp(38px, 6vw, 64px)',
fontWeight: 800,
lineHeight: .95,
letterSpacing: '-.03em',
marginBottom: 16,
},
subtitle: {
fontFamily: 'var(--mono)',
fontSize: 13,
color: 'var(--muted)',
lineHeight: 1.6,
marginBottom: 36,
},
fieldGroup: {
display: 'flex',
flexDirection: 'column',
gap: 8,
marginBottom: 20,
},
label: {
fontFamily: 'var(--mono)',
fontSize: 10,
letterSpacing: '.18em',
color: 'var(--muted)',
textTransform: 'uppercase',
},
input: {
background: 'var(--surface)',
border: '1px solid var(--border2)',
color: 'var(--text)',
fontFamily: 'var(--mono)',
fontSize: 13,
padding: '12px 14px',
borderRadius: 8,
outline: 'none',
transition: 'border-color .2s',
width: '100%',
},
companyGrid: {
display: 'flex',
flexDirection: 'column',
gap: 10,
},
companyCard: {
display: 'flex',
alignItems: 'flex-start',
gap: 14,
padding: '14px 16px',
borderRadius: 10,
border: '1.5px solid',
cursor: 'pointer',
textAlign: 'left',
transition: 'border-color .15s, background .15s',
fontFamily: 'var(--sans)',
width: '100%',
position: 'relative',
},
companyIcon: {
width: 40,
height: 40,
borderRadius: 10,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 18,
fontWeight: 800,
flexShrink: 0,
},
companyInfo: {
display: 'flex',
flexDirection: 'column',
gap: 3,
flex: 1,
},
companyName: {
fontSize: 15,
fontWeight: 700,
color: 'var(--text)',
},
companyTag: {
fontFamily: 'var(--mono)',
fontSize: 10,
color: 'var(--muted)',
letterSpacing: '.12em',
},
companyPills: {
display: 'flex',
flexWrap: 'wrap',
gap: 4,
marginTop: 6,
},
qpill: {
fontFamily: 'var(--mono)',
fontSize: 9,
letterSpacing: '.1em',
color: 'var(--muted)',
border: '1px solid var(--border)',
padding: '2px 7px',
borderRadius: 20,
},
checkmark: {
position: 'absolute',
top: 12,
right: 14,
fontSize: 16,
fontWeight: 700,
},
error: {
fontFamily: 'var(--mono)',
fontSize: 11,
color: 'var(--danger)',
marginBottom: 12,
},
startBtn: {
background: 'var(--accent)',
color: '#0a0a0a',
border: 'none',
fontFamily: 'var(--sans)',
fontSize: 14,
fontWeight: 700,
letterSpacing: '.06em',
padding: '16px 24px',
borderRadius: 8,
transition: 'opacity .15s, transform .1s',
marginTop: 4,
marginBottom: 16,
},
fine: {
fontFamily: 'var(--mono)',
fontSize: 10,
color: 'var(--muted)',
letterSpacing: '.1em',
textAlign: 'center',
},
}