import { useEffect, useMemo, useState } from 'react'; import { ArrowLeft, ArrowRight, Briefcase, ChevronDown, CheckCircle2, Clock3, Code2, Filter, Globe, Lightbulb, Mic, MoreHorizontal, PauseCircle, Play, PlayCircle, Radio, StopCircle, Target, UserRound, } from 'lucide-react'; import { SimulatorViewModel, type SimulatorInterviewItem } from '../../../mvvm/viewmodels/SimulatorViewModel'; import type { JobsListItem } from '../../../mvvm/viewmodels/JobsPageViewModel'; import { DashboardSidebar, type DashboardNavKey } from '../../dashboard/components/DashboardSidebar'; import { DashboardTopbar } from '../../dashboard/components/DashboardTopbar'; import '../../dashboard/pages/dashboard.css'; import './simulator.css'; interface SimulatorPageProps { onLogout: () => void; onNavigate: (target: DashboardNavKey) => void; onOpenEvaluation: (selection: SimulatorEvaluationSelection) => void; onToggleTheme: () => void; theme: 'light' | 'dark'; } interface InterviewCard { id: string; title: string; companyName: string; completed: boolean; durationMinutes: number; personality: string; dateLabel: string; } export interface SimulatorEvaluationSelection { interviewId: string; title: string; companyName: string; dateLabel: string; } const FALLBACK_INTERVIEWS: InterviewCard[] = [ { id: 'sim-1', title: 'Senior Frontend-udvikler', companyName: 'Lunar', completed: true, durationMinutes: 15, personality: 'Professionel', dateLabel: '12. okt 2023', }, { id: 'sim-2', title: 'Fullstack Developer', companyName: 'Pleo', completed: false, durationMinutes: 20, personality: 'Afslappet', dateLabel: '10. okt 2023', }, { id: 'sim-3', title: 'UX Designer', companyName: 'Trustpilot', completed: true, durationMinutes: 10, personality: 'Sarkastisk', dateLabel: '05. okt 2023', }, { id: 'sim-4', title: 'Product Manager', companyName: 'Danske Bank', completed: true, durationMinutes: 5, personality: 'Stress-test', dateLabel: '01. okt 2023', }, ]; function toInterviewCard(item: SimulatorInterviewItem): InterviewCard { return { id: item.id, title: item.title, companyName: item.companyName, completed: item.completed, durationMinutes: item.durationMinutes ?? 15, personality: item.personality || 'Professionel', dateLabel: item.dateLabel || 'Nyligt', }; } function jobLabel(job: JobsListItem): string { return `${job.title || 'Stilling'}${job.companyName ? ` · ${job.companyName}` : ''}`; } export function SimulatorPage({ onLogout, onNavigate, onOpenEvaluation, onToggleTheme, theme }: SimulatorPageProps) { const viewModel = useMemo(() => new SimulatorViewModel(), []); const [name, setName] = useState('Lasse'); const [imageUrl, setImageUrl] = useState(undefined); const [jobs, setJobs] = useState([]); const [interviews, setInterviews] = useState([]); const [personalities, setPersonalities] = useState>([]); const [isLoading, setIsLoading] = useState(true); const [selectedJobId, setSelectedJobId] = useState(''); const [selectedPersonalityId, setSelectedPersonalityId] = useState(''); const [selectedLanguage, setSelectedLanguage] = useState('Dansk'); const [selectedDuration, setSelectedDuration] = useState('15'); const [isLiveSession, setIsLiveSession] = useState(false); useEffect(() => { let active = true; async function load() { setIsLoading(true); const [profile, jobsData, interviewData, personalityData] = await Promise.all([ viewModel.getCandidateProfile(), viewModel.getJobs(), viewModel.getInterviews(), viewModel.getPersonalities(), ]); if (!active) { return; } setName(profile.name); setImageUrl(profile.imageUrl); setJobs(jobsData); setInterviews(interviewData.map(toInterviewCard)); setPersonalities(personalityData.map((item) => ({ id: item.id, name: item.name }))); if (jobsData.length > 0) { setSelectedJobId((current) => current || jobsData[0].id); } if (personalityData.length > 0) { setSelectedPersonalityId((current) => current || String(personalityData[0].id)); } setIsLoading(false); } void load(); return () => { active = false; }; }, [viewModel]); const cards = interviews.length > 0 ? interviews : FALLBACK_INTERVIEWS; const fallbackJob = { id: 'fallback-job', title: 'Senior Frontend-udvikler', companyName: 'Lunar' } as JobsListItem; const jobOptions = jobs.length > 0 ? jobs : [fallbackJob]; const activeJob = jobOptions.find((job) => job.id === selectedJobId) || jobOptions[0]; const activePersonality = personalities.find((item) => String(item.id) === selectedPersonalityId)?.name || 'Professionel & Grundig'; const liveMessages = [ { id: 'ai-1', sender: 'ai', text: 'Hej Lasse, og velkommen til! Vi er rigtig glade for at have dig til samtalen omkring rollen som ' + `${activeJob.title || 'Senior Frontend-udvikler'}. Kan du fortælle om et nyligt projekt, ` + 'hvor din erfaring med React gjorde en stor forskel for slutresultatet?', }, { id: 'me-1', sender: 'me', text: 'I mit seneste projekt migrerede vi en stor dashboard-løsning til Next.js. ' + 'Jeg implementerede virtualisering og strammere state management med Zustand, ' + 'hvilket reducerede load-tid med over 60%.', }, { id: 'ai-2', sender: 'ai', text: 'Det lyder som en rigtig solid forbedring. Når du nævner Zustand frem for Redux, ' + 'hvad var overvejelserne bag det valg i jeres use-case?', }, ] as const; return (
setIsLiveSession(false)}> Forlad simulering ) : undefined} /> {isLiveSession ? (

Live Jobsamtale

Du er i øjeblikket i en simuleret teknisk samtale. Brug mikrofonen til at svare.

Sarah (AI Interviewer)

Venter på dit svar...

{liveMessages.map((message) => (
{message.sender === 'ai' ? : (imageUrl ? {name} : {name.slice(0, 1).toUpperCase()})}

{message.text}

))}
Tid gået 04:23
{Array.from({ length: 7 }).map((_, index) => ( ))}
Tilbage 10:37

Optager dit svar...

) : (

Job Interview Simulator

Ov dig pa jobsamtaler med vores AI-drevne simulator. Du far skraeddersyede sporgsmal baseret pa den jobtype, du soger, og modtager detaljeret feedback pa dine svar.

  • Personaliserede interviewsporgsmal
  • Ojeblikkelig AI-feedback pa dine svar
  • Detaljeret evaluering efter interviewet
  • Gem og gennemga tidligere interviews

Simuleringsindstillinger

Vaelg dine praeferencer for start

Tidligere simuleringer

{isLoading ?

Indlaeser simuleringer...

: null}
{cards.map((item) => (

{item.title}

{item.companyName}

{item.completed ? 'Faerdig' : 'Ikke faerdig'}
{item.durationMinutes} min {item.personality}
{item.dateLabel} {item.completed ? ( ) : ( )}
))}
)}
); }