ai-hackaton-frontend/components/VacancyReports.tsx
2025-09-08 16:08:40 +03:00

172 lines
6.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from "react";
import { FileText, Award, AlertTriangle, CheckCircle2 } from "lucide-react";
export interface InterviewReport {
id: number;
interview_session_id: number;
technical_skills_score: number;
experience_relevance_score: number;
communication_score: number;
problem_solving_score: number;
cultural_fit_score: number;
overall_score: number;
recommendation: "strongly_recommend" | "recommend" | "consider" | "reject";
strengths: Record<string, any>;
weaknesses: Record<string, any>;
red_flags: Record<string, any>;
next_steps: string | null;
interviewer_notes: string | null;
pdf_report_url: string | null;
}
interface VacancyReportsProps {
reports: InterviewReport[];
}
const recommendationLabels: Record<
InterviewReport["recommendation"],
string
> = {
strongly_recommend: "сильно рекомендую",
recommend: "рекомендую",
consider: "рассмотреть",
reject: "не рекомендую",
};
const recommendationColors: Record<
InterviewReport["recommendation"],
string
> = {
strongly_recommend: "text-green-700 bg-green-100",
recommend: "text-blue-700 bg-blue-100",
consider: "text-yellow-700 bg-yellow-100",
reject: "text-red-700 bg-red-100",
};
const scoringLabels: Record<string, string> = {
technical_skills_score: "Технические навыки",
experience_relevance_score: "Релевантность опыта",
communication_score: "Коммуникация",
problem_solving_score: "Решение задач",
cultural_fit_score: "Культурная совместимость",
overall_score: "Общая оценка",
};
const renderJsonAsList = (data: Record<string, any>) => {
return (
<ul className="list-disc list-inside text-xs bg-gray-50 p-2 rounded">
{Object.entries(data).map(([key, value]) => (
<li key={key}>
<span className="font-medium">{key}:</span> {String(value)}
</li>
))}
</ul>
);
};
export default function VacancyReports({ reports }: VacancyReportsProps) {
return (
<div className="space-y-6">
<h1 className="text-xl font-bold text-gray-900">
Отчёты по собеседованиям
</h1>
{reports.length === 0 ? (
<p className="text-gray-600">Пока нет отчётов по этой вакансии.</p>
) : (
<div className="flex flex-col gap-6">
{reports.map((report) => (
<div
key={report.id}
className="bg-white rounded-lg shadow-md p-6 flex flex-col justify-between"
>
<div>
<h2 className="text-lg font-semibold text-gray-900 mb-2 flex items-center">
<Award className="h-5 w-5 mr-2 text-indigo-500" />
Отчёт #{report.id}
</h2>
<div
className={`inline-block px-3 py-1 rounded-full text-sm font-medium mb-4 ${
recommendationColors[report.recommendation]
}`}
>
{recommendationLabels[report.recommendation]}
</div>
<div className="space-y-2 text-gray-700 text-sm">
{Object.entries(scoringLabels).map(([key, label]) => {
const score = report[key as keyof InterviewReport] as number;
return (
<p key={key}>
<span className="font-medium">{label}:</span> {score}/10
</p>
);
})}
</div>
{report.strengths &&
Object.keys(report.strengths).length > 0 && (
<div className="mt-4">
<h3 className="text-sm font-medium text-gray-900 mb-1 flex items-center">
<CheckCircle2 className="h-4 w-4 mr-1 text-green-500" />
Сильные стороны
</h3>
{renderJsonAsList(report.strengths)}
</div>
)}
{report.weaknesses &&
Object.keys(report.weaknesses).length > 0 && (
<div className="mt-4">
<h3 className="text-sm font-medium text-gray-900 mb-1 flex items-center">
<AlertTriangle className="h-4 w-4 mr-1 text-yellow-500" />
Слабые стороны
</h3>
{renderJsonAsList(report.weaknesses)}
</div>
)}
{report.red_flags && Object.keys(report.red_flags).length > 0 && (
<div className="mt-4">
<h3 className="text-sm font-medium mb-1 flex items-center text-red-600">
🚩 Red flags
</h3>
{renderJsonAsList(report.red_flags)}
</div>
)}
{report.interviewer_notes && (
<div className="mt-4">
<h3 className="text-sm font-medium text-gray-900 mb-1">
Заметки интервьюера
</h3>
<p className="text-sm text-gray-700">
{report.interviewer_notes}
</p>
</div>
)}
</div>
{report.pdf_report_url && (
<div className="mt-6">
<a
href={report.pdf_report_url}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-lg shadow hover:bg-indigo-700 transition"
>
<FileText className="h-4 w-4 mr-2" />
Открыть PDF
</a>
</div>
)}
</div>
))}
</div>
)}
</div>
);
}