tahamajs/IE / Projects /front /src /components /messages /PollCreateModal.tsx
tahamajs's picture
download
raw
7.98 kB
// src/components/messages/PollCreateModal.tsx
import { useState } from "react";
import { X, Plus, Trash2, HelpCircle, BarChart3, Clock, GripVertical } from "lucide-react";
import { toast } from "react-toastify";
interface PollCreateModalProps {
isOpen: boolean;
onClose: () => void;
onCreatePoll: (pollData: {
question: string;
options: string[];
multipleChoice: boolean;
isQuiz: boolean;
expiresIn?: number; // minutes
explanation?: string;
}) => void;
}
export function PollCreateModal({ isOpen, onClose, onCreatePoll }: PollCreateModalProps) {
const [question, setQuestion] = useState("");
const [options, setOptions] = useState<string[]>(["", ""]);
const [multipleChoice, setMultipleChoice] = useState(false);
const [isQuiz, setIsQuiz] = useState(false);
const [correctOptionIdx, setCorrectOptionIdx] = useState<number>(-1);
const [explanation, setExplanation] = useState("");
const [expiresIn, setExpiresIn] = useState<number>(0); // 0 = no expiry
if (!isOpen) return null;
const addOption = () => setOptions([...options, ""]);
const removeOption = (idx: number) => {
if (options.length <= 2) return;
setOptions(options.filter((_, i) => i !== idx));
if (correctOptionIdx === idx) setCorrectOptionIdx(-1);
};
const updateOption = (idx: number, value: string) => {
setOptions(options.map((o, i) => (i === idx ? value : o)));
};
const handleCreate = () => {
const trimmedQuestion = question.trim();
const trimmedOptions = options.map((o) => o.trim()).filter(Boolean);
if (!trimmedQuestion) return toast.warning("Please enter a question");
if (trimmedOptions.length < 2) return toast.warning("Add at least 2 options");
if (isQuiz && correctOptionIdx < 0) return toast.warning("Select a correct answer for the quiz");
onCreatePoll({
question: trimmedQuestion,
options: trimmedOptions,
multipleChoice,
isQuiz,
expiresIn: expiresIn || undefined,
explanation: isQuiz ? explanation.trim() : undefined,
});
// Reset form
setQuestion("");
setOptions(["", ""]);
setMultipleChoice(false);
setIsQuiz(false);
setCorrectOptionIdx(-1);
setExplanation("");
setExpiresIn(0);
onClose();
};
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4" onClick={onClose}>
<div
className="bg-white dark:bg-gray-800 rounded-2xl max-w-md w-full p-6 shadow-2xl overflow-y-auto max-h-[90vh]"
onClick={(e) => e.stopPropagation()}
>
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-bold flex items-center gap-2">
{isQuiz ? (
<HelpCircle className="w-5 h-5 text-purple-500" />
) : (
<BarChart3 className="w-5 h-5 text-primary" />
)}
Create {isQuiz ? "Quiz" : "Poll"}
</h2>
<button onClick={onClose} className="text-gray-500 hover:text-gray-700">
<X className="w-5 h-5" />
</button>
</div>
{/* Type toggle */}
<div className="flex bg-gray-100 dark:bg-gray-700 rounded-xl p-1 mb-4">
<button
onClick={() => { setIsQuiz(false); setCorrectOptionIdx(-1); }}
className={`flex-1 py-2 text-sm font-medium rounded-lg transition ${
!isQuiz ? "bg-white dark:bg-gray-600 shadow text-primary" : "text-gray-500"
}`}
>
📊 Poll
</button>
<button
onClick={() => setIsQuiz(true)}
className={`flex-1 py-2 text-sm font-medium rounded-lg transition ${
isQuiz ? "bg-white dark:bg-gray-600 shadow text-purple-500" : "text-gray-500"
}`}
>
🧠 Quiz
</button>
</div>
{/* Question */}
<input
type="text"
placeholder="Ask a question..."
value={question}
onChange={(e) => setQuestion(e.target.value)}
className="w-full p-3 border border-gray-200 dark:border-gray-700 rounded-xl mb-4 bg-transparent focus:ring-2 focus:ring-primary focus:outline-none"
autoFocus
/>
{/* Options */}
<div className="space-y-2 mb-4">
{options.map((opt, idx) => (
<div key={idx} className="flex items-center gap-2">
<GripVertical className="w-4 h-4 text-gray-400 shrink-0" />
<input
type="text"
placeholder={`Option ${idx + 1}`}
value={opt}
onChange={(e) => updateOption(idx, e.target.value)}
className="flex-1 p-2.5 border border-gray-200 dark:border-gray-700 rounded-xl bg-transparent focus:ring-2 focus:ring-primary focus:outline-none text-sm"
/>
{isQuiz && (
<button
onClick={() => setCorrectOptionIdx(idx)}
className={`p-1.5 rounded-lg text-xs shrink-0 transition ${
correctOptionIdx === idx
? "bg-green-100 dark:bg-green-900/30 text-green-600"
: "bg-gray-100 dark:bg-gray-700 text-gray-400"
}`}
title="Mark as correct answer"
>
✓
</button>
)}
<button
onClick={() => removeOption(idx)}
className="p-1.5 text-gray-400 hover:text-red-500 shrink-0"
disabled={options.length <= 2}
>
<Trash2 className="w-4 h-4" />
</button>
</div>
))}
<button
onClick={addOption}
className="flex items-center gap-2 text-sm text-primary hover:underline p-2"
>
<Plus className="w-4 h-4" /> Add option
</button>
</div>
{/* Settings */}
<div className="space-y-3 mb-4 border-t border-gray-100 dark:border-gray-700 pt-3">
{/* Multiple choice */}
<label className="flex items-center justify-between cursor-pointer">
<span className="text-sm text-gray-600 dark:text-gray-400">Allow multiple answers</span>
<input
type="checkbox"
checked={multipleChoice}
onChange={(e) => setMultipleChoice(e.target.checked)}
className="rounded border-gray-300 dark:border-gray-600 text-primary focus:ring-primary"
/>
</label>
{/* Expiry */}
<div className="flex items-center gap-3">
<Clock className="w-4 h-4 text-gray-400" />
<select
value={expiresIn}
onChange={(e) => setExpiresIn(Number(e.target.value))}
className="text-sm border border-gray-200 dark:border-gray-700 rounded-lg p-2 bg-transparent"
>
<option value={0}>No expiry</option>
<option value={5}>5 minutes</option>
<option value={30}>30 minutes</option>
<option value={60}>1 hour</option>
<option value={1440}>24 hours</option>
<option value={10080}>7 days</option>
</select>
</div>
{/* Quiz explanation */}
{isQuiz && (
<textarea
placeholder="Explanation after answer (optional)"
value={explanation}
onChange={(e) => setExplanation(e.target.value)}
className="w-full p-2.5 border border-gray-200 dark:border-gray-700 rounded-xl bg-transparent text-sm focus:ring-2 focus:ring-primary focus:outline-none"
rows={2}
/>
)}
</div>
{/* Create button */}
<button onClick={handleCreate} className="btn btn-primary w-full">
Create {isQuiz ? "Quiz" : "Poll"}
</button>
</div>
</div>
);
}

Xet Storage Details

Size:
7.98 kB
·
Xet hash:
6374dbe89e2f99461f0704b97451b845ad58a349481c4211a9de7b5a1b4a82f3

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.