128 lines
6.9 KiB
TypeScript
128 lines
6.9 KiB
TypeScript
import React from 'react';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { ClipboardList } from 'lucide-react';
|
|
|
|
interface QuestionnaireResponseViewProps {
|
|
application: any;
|
|
}
|
|
|
|
const QuestionnaireResponseView: React.FC<QuestionnaireResponseViewProps> = ({ application }) => {
|
|
// If no responses or empty array
|
|
if (!application.questionnaireResponses || application.questionnaireResponses.length === 0) {
|
|
return (
|
|
<div
|
|
className="flex flex-col items-center justify-center py-12 text-slate-500 bg-slate-50 rounded-lg border border-dashed border-slate-300"
|
|
data-testid="onboarding-questionnaire-empty"
|
|
>
|
|
<ClipboardList className="w-12 h-12 mb-3 text-slate-300" />
|
|
<h3 className="text-lg font-medium text-slate-700">Response is Pending</h3>
|
|
<p className="text-sm">The applicant has not submitted the questionnaire yet.</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Sort responses by question order if possible, or just index
|
|
// Assuming backend returns them in some order, better to sort by question.order if available
|
|
const responses = [...application.questionnaireResponses].sort((a, b) => {
|
|
return (a.question?.order || 0) - (b.question?.order || 0);
|
|
});
|
|
|
|
const totalScore = application.score || application.questionnaireMarks || 0; // Fallback mapping
|
|
|
|
return (
|
|
<div className="space-y-6" data-testid="onboarding-questionnaire-view">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center gap-3">
|
|
<ClipboardList className="w-5 h-5 text-amber-600" />
|
|
<h3 className="text-slate-900">Questionnaire Responses</h3>
|
|
</div>
|
|
{totalScore !== undefined && (
|
|
<Badge className="bg-amber-600" data-testid="onboarding-questionnaire-total-score">Score: {totalScore}/100</Badge>
|
|
)}
|
|
</div>
|
|
|
|
<div className="space-y-6">
|
|
{responses.map((resp: any, index: number) => {
|
|
const question = resp.question;
|
|
const questionText = question?.questionText || 'Unknown Question';
|
|
const answer = resp.responseValue || 'No Answer';
|
|
const section = question?.sectionName || 'General';
|
|
|
|
const options = question?.questionOptions || [];
|
|
|
|
// Match answer to find score
|
|
// Note: This relies on exact string match.
|
|
const matchedOption = options.find((opt: any) => opt.optionText === answer);
|
|
const score = matchedOption ? matchedOption.score : 0;
|
|
const maxScore = Math.max(...options.map((o: any) => o.score || 0), 0);
|
|
|
|
const isFile = typeof answer === 'string' && answer.startsWith('data:');
|
|
const isImage = isFile && answer.startsWith('data:image');
|
|
|
|
return (
|
|
<div
|
|
key={resp.id}
|
|
className="border border-slate-200 rounded-lg p-5 hover:border-amber-300 transition-colors"
|
|
data-testid={`onboarding-questionnaire-item-${index}`}
|
|
>
|
|
<div className="flex items-start gap-3 mb-3">
|
|
<div className="w-8 h-8 rounded-full bg-amber-100 flex items-center justify-center flex-shrink-0">
|
|
<span className="text-amber-600">{index + 1}</span>
|
|
</div>
|
|
<div className="flex-1">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Badge variant="outline" className="text-slate-600 bg-slate-50" data-testid={`onboarding-questionnaire-item-section-${index}`}>
|
|
{section}
|
|
</Badge>
|
|
{(options.length > 0 && maxScore > 0) && (
|
|
<Badge
|
|
className={score > 0 ? "bg-green-600" : "bg-slate-400"}
|
|
data-testid={`onboarding-questionnaire-item-score-${index}`}
|
|
>
|
|
{score}/{maxScore}
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
<h4 className="text-slate-900 font-medium" data-testid={`onboarding-questionnaire-item-text-${index}`}>{questionText}</h4>
|
|
</div>
|
|
</div>
|
|
<div className="ml-11">
|
|
{isImage ? (
|
|
<div className="mt-2" data-testid={`onboarding-questionnaire-item-image-${index}`}>
|
|
<img
|
|
src={answer}
|
|
alt="Response Attachment"
|
|
className="max-w-full h-auto max-h-64 rounded border p-1 object-contain"
|
|
/>
|
|
</div>
|
|
) : isFile ? (
|
|
<a
|
|
href={answer}
|
|
download={`upload_${index}.pdf`}
|
|
className="text-blue-600 underline text-sm break-all"
|
|
data-testid={`onboarding-questionnaire-item-download-${index}`}
|
|
>
|
|
Download Attachment
|
|
</a>
|
|
) : (
|
|
<div className="text-slate-600 leading-relaxed break-words whitespace-pre-wrap" data-testid={`onboarding-questionnaire-item-answer-${index}`}>
|
|
{resp.attachmentUrl ? (
|
|
<a href={resp.attachmentUrl} target="_blank" rel="noreferrer" className="text-blue-600 underline" data-testid={`onboarding-questionnaire-item-attachment-${index}`}>
|
|
View Attachment
|
|
</a>
|
|
) : (
|
|
answer
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default QuestionnaireResponseView;
|