File size: 9,612 Bytes
3a75b1c
 
e058d03
3a75b1c
 
8b65a0f
 
 
 
 
 
3a75b1c
 
 
 
 
 
 
 
 
 
e058d03
733e040
3a75b1c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e058d03
733e040
3a75b1c
 
 
 
 
 
e058d03
8b65a0f
 
 
e058d03
3a75b1c
 
 
 
 
 
 
 
 
e058d03
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3a75b1c
 
 
 
8b65a0f
 
3a75b1c
8b65a0f
3a75b1c
8b65a0f
3a75b1c
8b65a0f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3a75b1c
8b65a0f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3a75b1c
 
 
 
8b65a0f
3a75b1c
 
8b65a0f
3a75b1c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e058d03
 
 
 
733e040
3a75b1c
 
 
 
8b65a0f
 
3a75b1c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
'use client';

import { useState } from 'react';
import { GeneratedQuestion, QuestionType } from '@/types/quiz';
import QuestionCard from './QuestionCard';
import { exportQuestionsToDocx } from '@/lib/exportUtils';
import { Button } from '@/components/ui/button';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';

export interface QuestionListProps {
  questions: GeneratedQuestion[];
  questionTypes: QuestionType[];
  selectedQuestions?: Set<string>;
  onQuestionSelect?: (questionId: string, selected: boolean) => void;
  onQuestionEdit?: (question: GeneratedQuestion) => void;
  onQuestionDuplicate?: (question: GeneratedQuestion) => void;
  onQuestionPreview?: (question: GeneratedQuestion) => void;
  onQuestionRemove?: (questionId: string) => void;
  onQuestionReorder?: (questions: GeneratedQuestion[]) => void;
  editingQuestionId?: string | null;
  emptyStateMessage?: string;
  emptyStateIcon?: string;
  className?: string;
  title?: string;
  showCount?: boolean;
}

export default function QuestionList({
  questions,
  questionTypes,
  selectedQuestions = new Set(),
  onQuestionSelect,
  onQuestionEdit,
  onQuestionDuplicate,
  onQuestionPreview,
  onQuestionRemove,
  onQuestionReorder,
  editingQuestionId = null,
  emptyStateMessage = "No questions yet. Start by creating your first question!",
  emptyStateIcon = "πŸ“",
  className = '',
  title = "Question List",
  showCount = true,
}: QuestionListProps) {
  const [draggedId, setDraggedId] = useState<string | null>(null);
  const [isExporting, setIsExporting] = useState(false);
  const [includeAnswers, setIncludeAnswers] = useState(true);
  const [exportFormat, setExportFormat] = useState<'docx' | 'txt'>('docx');

  const handleSelectAll = () => {
    if (onQuestionSelect) {
      const allSelected = questions.length > 0 && questions.every(q => selectedQuestions.has(q.id));
      questions.forEach(question => {
        onQuestionSelect(question.id, !allSelected);
      });
    }
  };

  const handleDragStart = (questionId: string) => {
    setDraggedId(questionId);
  };

  const handleDragEnd = () => {
    setDraggedId(null);
  };

  const handleDrop = (targetId: string) => {
    if (!draggedId || !onQuestionReorder || draggedId === targetId) return;

    const newQuestions = [...questions];
    const draggedIndex = newQuestions.findIndex(q => q.id === draggedId);
    const targetIndex = newQuestions.findIndex(q => q.id === targetId);

    if (draggedIndex !== -1 && targetIndex !== -1) {
      // Remove the dragged item and insert it at the target position
      const [draggedItem] = newQuestions.splice(draggedIndex, 1);
      newQuestions.splice(targetIndex, 0, draggedItem);
      onQuestionReorder(newQuestions);
    }
  };

  const allSelected = questions.length > 0 && questions.every(q => selectedQuestions.has(q.id));
  const someSelected = questions.some(q => selectedQuestions.has(q.id));

  return (
    <Card className={className}>
      <CardHeader className="border-b">
        <div className="flex items-center justify-between">
          <CardTitle className="text-lg font-semibold">
            πŸ—‚οΈ {title} {showCount && `(${questions.length})`}
          </CardTitle>
          
          {/* Export and Bulk Actions */}
          {questions.length > 0 && (
            <div className="flex items-center space-x-3">
              {/* Export Options */}
              <div className="flex items-center space-x-3">
                {/* Format Selector */}
                <Select value={exportFormat} onValueChange={(value) => setExportFormat(value as 'docx' | 'txt')}>
                  <SelectTrigger className="w-[100px]">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="docx">DOCX</SelectItem>
                    <SelectItem value="txt">TXT</SelectItem>
                  </SelectContent>
                </Select>
                
                {/* Include Answers Toggle */}
                <div className="flex items-center space-x-2">
                  <Checkbox
                    id="include-answers"
                    checked={includeAnswers}
                    onCheckedChange={(checked) => setIncludeAnswers(checked as boolean)}
                  />
                  <Label htmlFor="include-answers" className="text-sm cursor-pointer">
                    Include Answers
                  </Label>
                </div>
                
                {/* Export Button */}
                <Button
                  onClick={async () => {
                    if (isExporting) return;
                    
                    setIsExporting(true);
                    try {
                      const questionsToExport = someSelected && selectedQuestions.size > 0 
                        ? questions.filter(q => selectedQuestions.has(q.id))
                        : questions;
                      const filename = someSelected && selectedQuestions.size > 0
                        ? `selected-questions-${selectedQuestions.size}${includeAnswers ? '-with-answers' : '-no-answers'}.${exportFormat}`
                        : `all-questions-${questions.length}${includeAnswers ? '-with-answers' : '-no-answers'}.${exportFormat}`;
                      
                      // Debug: Log the first question structure
                      if (questionsToExport.length > 0) {
                        console.log('First question structure:', questionsToExport[0]);
                        console.log('First question content:', questionsToExport[0].content);
                      }
                      
                      if (exportFormat === 'docx') {
                        await exportQuestionsToDocx(questionsToExport, filename, includeAnswers);
                      } else {
                        // For now, just show a message that TXT export is not implemented
                        alert('TXT export is not yet implemented. Please use DOCX format.');
                      }
                    } catch (error) {
                      console.error('Export failed:', error);
                      // You could add a toast notification here
                    } finally {
                      setIsExporting(false);
                    }
                  }}
                  disabled={isExporting}
                  variant="default"
                  size="sm"
                  title={someSelected && selectedQuestions.size > 0 
                    ? `Export ${selectedQuestions.size} selected questions to ${exportFormat.toUpperCase()} file`
                    : `Export all questions to ${exportFormat.toUpperCase()} file`
                  }
                >
                  <span>{isExporting ? '⏳' : 'πŸ“„'}</span>
                  <span>
                    {isExporting 
                      ? 'Exporting...' 
                      : someSelected && selectedQuestions.size > 0 
                        ? `Export Selected (${selectedQuestions.size})`
                        : `Export to ${exportFormat.toUpperCase()}`
                    }
                  </span>
                </Button>
              </div>
              
              {/* Bulk Actions */}
              {onQuestionSelect && (
                <div className="flex items-center space-x-2">
                  <Button
                    onClick={handleSelectAll}
                    variant="ghost"
                    size="sm"
                  >
                    {allSelected ? 'Deselect All' : 'Select All'}
                  </Button>
                  
                  {someSelected && (
                    <span className="text-xs text-primary">
                      {selectedQuestions.size} selected
                    </span>
                  )}
                </div>
              )}
            </div>
          )}
        </div>
      </CardHeader>
      
      {/* Content */}
      <CardContent className="h-[calc(100%-80px)] overflow-y-auto p-4">
        {questions.length === 0 ? (
          <EmptyState message={emptyStateMessage} icon={emptyStateIcon} />
        ) : (
          <div className="space-y-3">
            {questions.map((question) => (
              <QuestionCard
                key={question.id}
                question={question}
                questionTypes={questionTypes}
                isSelected={selectedQuestions.has(question.id)}
                onSelect={onQuestionSelect}
                onEdit={onQuestionEdit}
                onDuplicate={onQuestionDuplicate}
                onPreview={onQuestionPreview}
                onRemove={onQuestionRemove}
                onDragStart={handleDragStart}
                onDragEnd={handleDragEnd}
                onDrop={handleDrop}
                isDragging={draggedId === question.id}
                isEditing={editingQuestionId === question.id}
              />
            ))}
          </div>
        )}
      </CardContent>
    </Card>
  );
}

// Empty State Component
interface EmptyStateProps {
  message: string;
  icon: string;
}

function EmptyState({ message, icon }: EmptyStateProps) {
  return (
    <div className="text-center text-gray-500 dark:text-gray-400 mt-8">
      <div className="text-4xl mb-4">{icon}</div>
      <p className="text-sm leading-relaxed max-w-md mx-auto">{message}</p>
    </div>
  );
}