EduLab / frontend /components /AnswerCard.tsx
rinogeek's picture
first commit
fafd0bb
import React, { useState } from 'react';
import { ArrowUp, CheckCircle2 } from 'lucide-react';
import { Answer } from '../types';
import { useAuth } from '../context/AuthContext';
import { forumService } from '../services/forum';
import MarkdownContent from './MarkdownContent';
interface Props {
answer: Answer;
isQuestionAuthor: boolean;
onAccept?: () => void;
}
const AnswerCard: React.FC<Props> = ({ answer, isQuestionAuthor, onAccept }) => {
const [votes, setVotes] = useState(answer.votes);
const [hasVoted, setHasVoted] = useState(answer.userVote === 1);
const [isVoting, setIsVoting] = useState(false);
const [isAccepted, setIsAccepted] = useState(answer.isAccepted);
const { isAuthenticated } = useAuth();
const handleVote = async () => {
if (!isAuthenticated) return;
if (isVoting) return;
setIsVoting(true);
try {
const result = await forumService.voteAnswer(answer.id, 1);
setVotes(result.votes);
setHasVoted(!hasVoted);
} catch (err) {
console.error('Failed to vote:', err);
} finally {
setIsVoting(false);
}
};
const handleAccept = async () => {
if (!isQuestionAuthor) return;
try {
await forumService.acceptAnswer(answer.id);
setIsAccepted(true);
if (onAccept) onAccept();
} catch (err) {
console.error('Failed to accept answer:', err);
}
};
return (
<div className={`bg-white dark:bg-gray-800 rounded-xl p-6 shadow-sm border ${isAccepted ? 'border-green-500 ring-1 ring-green-500' : 'border-gray-100 dark:border-gray-700'}`}>
<div className="flex items-start gap-4">
{/* Vote Section */}
<div className="flex flex-col items-center space-y-1 text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-gray-700/50 p-2 rounded-lg min-w-[3rem]">
<button
onClick={handleVote}
disabled={isVoting}
className={`hover:text-edu-accent transition-colors ${hasVoted ? 'text-edu-secondary' : ''} ${isVoting ? 'opacity-50 cursor-not-allowed' : ''}`}
>
<ArrowUp size={20} className={hasVoted ? 'fill-current' : ''} />
</button>
<span className="font-bold text-lg">{votes}</span>
{isAccepted && (
<div className="mt-2 text-green-500" title="Réponse acceptée">
<CheckCircle2 size={24} className="fill-green-100" />
</div>
)}
</div>
{/* Content */}
<div className="flex-grow">
<div className="mb-4 text-gray-800 dark:text-gray-200">
<MarkdownContent content={answer.content} />
</div>
<div className="flex justify-between items-center text-sm border-t border-gray-100 dark:border-gray-700 pt-3">
<div className="flex items-center gap-2 text-gray-500">
<span>Répondu le {answer.createdAt}</span>
{isQuestionAuthor && !isAccepted && (
<button
onClick={handleAccept}
className="ml-4 flex items-center gap-1 text-gray-400 hover:text-green-600 transition-colors"
>
<CheckCircle2 size={16} />
Accepter cette réponse
</button>
)}
</div>
<div className="flex items-center gap-2 bg-gray-50 dark:bg-gray-700/30 px-3 py-1.5 rounded-lg">
<img
src={answer.author.avatar}
alt={answer.author.name}
className="w-6 h-6 rounded-full object-cover"
/>
<span className="font-medium text-gray-700 dark:text-gray-300">{answer.author.name}</span>
<span className="text-xs text-gray-400">{answer.author.role === 'MENTOR' ? 'Mentor' : 'Étudiant'}</span>
</div>
</div>
</div>
</div>
</div>
);
};
export default AnswerCard;