import { useState, useMemo } from 'react'
import { useNavigate } from 'react-router-dom'
import { COMPANIES } from '../lib/companies'
import VoiceSettings from './VoiceSettings'
import { buildInterviewUrl, buildWatchUrl } from '../lib/sessionConfig'
import { VX_SERVER } from '../lib/webrtc'
const DEFAULT_KEY = 'vk_Qg95CQBuNFuiiHMCVtgo9bh9kx0N1ACnaj8zdJyg5qsBDWTjxt2ZoegM2UCdKfCY'
export default function InterviewSetup() {
const navigate = useNavigate()
const sessionId = useMemo(() => crypto.randomUUID(), [])
const [phase, setPhase] = useState('setup') // 'setup' | 'ready'
const [name, setName] = useState('')
const [company, setCompany] = useState(null)
const [error, setError] = useState('')
const [voiceSettings, setVoiceSettings] = useState({})
// Generated URLs — only set after clicking Create
const [interviewUrl, setInterviewUrl] = useState('')
const [watchUrl, setWatchUrl] = useState('')
// Copy states per link
const [copiedInterview, setCopiedInterview] = useState(false)
const [copiedWatch, setCopiedWatch] = useState(false)
function copy(text, setDone) {
navigator.clipboard.writeText(text).then(() => {
setDone(true)
setTimeout(() => setDone(false), 2000)
})
}
function handleCreate() {
if (!name.trim()) return setError('Enter the candidate name')
if (!company) return setError('Choose a company')
setError('')
const config = {
candidateName: name.trim(),
company,
apiKey: DEFAULT_KEY,
server: VX_SERVER,
voiceSettings: Object.keys(voiceSettings).length ? voiceSettings : null,
}
setInterviewUrl(buildInterviewUrl(sessionId, config))
setWatchUrl(buildWatchUrl(sessionId))
setPhase('ready')
}
if (phase === 'ready') {
return (
Interview ready
Send the link,
then watch.
Share the interview link with {name}.
Open the watch link on your device to follow the conversation live.
{/* Interview link */}
Interview link
Send this to the candidate
{interviewUrl}
{/* Watch link */}
Watch link
Your observer view
{watchUrl}
The candidate opens their link and the interview starts automatically.
You'll see the full transcript here as it happens.
)
}
return (
AI-powered mock interview
Configure &
send the link.
{/* Candidate name */}
setName(e.target.value)}
onKeyDown={e => e.key === 'Enter' && handleCreate()}
placeholder="e.g. Ayush"
autoComplete="off"
/>
{/* Company picker */}
{Object.values(COMPANIES).map(c => (
{ setCompany(c.id); setError('') }}
/>
))}
{error &&
{error}
}
Generates a unique link for the candidate and a watch link for you.
)
}
function CompanyCard({ company, selected, onSelect }) {
return (
)
}
const s = {
page: {
minHeight: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '40px 20px',
position: 'relative',
overflowY: 'auto',
overflowX: 'hidden',
},
glow1: {
position: 'fixed', inset: 0,
background: 'radial-gradient(ellipse 60% 50% at 20% 80%, rgba(200,240,96,.05) 0%, transparent 70%)',
pointerEvents: 'none',
},
glow2: {
position: 'fixed', inset: 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',
position: 'relative',
zIndex: 1,
},
back: {
alignSelf: 'flex-start',
fontFamily: 'var(--mono)',
fontSize: 11,
color: 'var(--muted)',
background: 'none',
border: 'none',
cursor: 'pointer',
letterSpacing: '.08em',
padding: 0,
marginBottom: 28,
},
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(34px, 6vw, 56px)',
fontWeight: 800,
lineHeight: .95,
letterSpacing: '-.03em',
marginBottom: 16,
},
subtitle: {
fontFamily: 'var(--mono)',
fontSize: 11,
color: 'var(--muted)',
lineHeight: 1.7,
marginBottom: 32,
letterSpacing: '.04em',
},
linkCard: {
background: 'var(--surface)',
border: '1px solid var(--border2)',
borderRadius: 10,
padding: '14px 16px',
marginBottom: 14,
display: 'flex',
flexDirection: 'column',
gap: 10,
},
linkCardHeader: {
display: 'flex',
alignItems: 'baseline',
gap: 10,
},
linkCardLabel: {
fontFamily: 'var(--mono)',
fontSize: 9,
letterSpacing: '.2em',
textTransform: 'uppercase',
color: 'var(--accent)',
},
linkCardHint: {
fontFamily: 'var(--mono)',
fontSize: 9,
color: 'var(--muted)',
letterSpacing: '.08em',
},
linkRow: {
display: 'flex',
alignItems: 'center',
gap: 10,
},
linkText: {
fontFamily: 'var(--mono)',
fontSize: 10,
color: 'var(--muted)',
flex: 1,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
copyBtn: {
fontFamily: 'var(--mono)',
fontSize: 10,
letterSpacing: '.1em',
padding: '5px 12px',
borderRadius: 6,
border: '1px solid var(--border2)',
background: 'transparent',
color: 'var(--text)',
cursor: 'pointer',
flexShrink: 0,
transition: 'border-color .15s, color .15s',
},
copyBtnDone: {
color: 'var(--accent)',
borderColor: 'var(--accent)',
},
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',
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,
cursor: 'pointer',
marginTop: 4,
marginBottom: 16,
},
watchBtn: {
background: 'transparent',
color: 'var(--text)',
border: '1.5px solid var(--border2)',
fontFamily: 'var(--sans)',
fontSize: 14,
fontWeight: 600,
letterSpacing: '.04em',
padding: '14px 24px',
borderRadius: 8,
cursor: 'pointer',
marginBottom: 20,
transition: 'border-color .15s',
},
fine: {
fontFamily: 'var(--mono)',
fontSize: 10,
color: 'var(--muted)',
letterSpacing: '.1em',
textAlign: 'center',
lineHeight: 1.6,
},
}