Question Card (components/Editor/question-card.tsx)¶
Overview¶
A dynamic card component for displaying and managing individual tender questions, featuring theme assignment, editing capabilities, and smooth animations. The component provides an interactive interface for question management with expandable content and theme selection.
Features¶
- Expandable content
- Theme selection
- Question editing
- Hover effects
- Remove mode
- Checkbox selection
- Theme assignment
- State persistence
- Error handling
- Visual feedback
Dependencies¶
import { useState, useEffect } from 'react'
import { motion } from 'framer-motion'
import { Card, CardContent } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Textarea } from '@/components/ui/textarea'
import { Checkbox } from '@/components/ui/checkbox'
Props¶
interface QuestionCardProps {
id: string;
question: string;
themes: Theme[];
onThemeChange: (id: string, themes: Theme[]) => void;
onEdit: (id: string, question: string) => void;
isRemoveMode: boolean;
onSelect: (id: string) => void;
isSelected: boolean;
}
interface Theme {
id: string;
name: string;
description: string;
}
Implementation¶
State Management¶
const [isEditing, setIsEditing] = useState(false);
const [editedQuestion, setEditedQuestion] = useState(question);
const [selectedThemes, setSelectedThemes] = useState<Theme[]>(themes);
Methods¶
const handleSave = () => {
onEdit(id, editedQuestion);
setIsEditing(false);
};
const handleThemeToggle = (theme: Theme) => {
const newThemes = selectedThemes.some(t => t.id === theme.id)
? selectedThemes.filter(t => t.id !== theme.id)
: [...selectedThemes, theme];
setSelectedThemes(newThemes);
onThemeChange(id, newThemes);
};
Unique Functionality¶
HTML Structure¶
<Card className="relative hover:shadow-md transition-shadow duration-300">
<CardContent className="p-4">
{isRemoveMode ? (
<div className="absolute top-4 right-4">
<Checkbox
checked={isSelected}
onCheckedChange={() => onSelect(id)}
/>
</div>
) : (
<div className="flex justify-end space-x-2">
<Button onClick={() => setIsEditing(!isEditing)}>
{isEditing ? 'Cancel' : 'Edit'}
</Button>
{isEditing && (
<Button onClick={handleSave}>Save</Button>
)}
</div>
)}
{isEditing ? (
<Textarea
value={editedQuestion}
onChange={(e) => setEditedQuestion(e.target.value)}
className="mt-4"
/>
) : (
<p className="mt-4">{question}</p>
)}
<div className="mt-4">
<h4 className="text-sm font-semibold mb-2">Assigned Themes</h4>
<div className="flex flex-wrap gap-2">
{themes.map(theme => (
<Button
key={theme.id}
variant={selectedThemes.some(t => t.id === theme.id) ? 'default' : 'outline'}
onClick={() => handleThemeToggle(theme)}
>
{theme.name}
</Button>
))}
</div>
</div>
</CardContent>
</Card>
API Integration¶
- Not applicable for this component
Components Used¶
Notes¶
- Supports theme assignment
- Features question editing
- Provides visual feedback
- Maintains state consistency
- Handles user interactions