File size: 11,619 Bytes
6849482
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Minimalistic MCQ Generator - Multiple Tests</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        .section-tab.active { background-color: #3B82F6; color: white; }
        .section-content { display: none; }
        .section-content.active { display: block; }
    </style>
</head>
<body class="bg-gray-100 min-h-screen py-8">
    <div class="container mx-auto max-w-2xl bg-white p-6 rounded-lg shadow-md">
        <h1 class="text-3xl font-bold text-center mb-6 text-gray-800">MCQ Generator</h1>
        
        <!-- Topics input area -->
        <div id="topics-container" class="space-y-4 mb-6">
            <div class="topic-row flex items-center space-x-2">
                <input type="text" name="topic" placeholder="Topic Name" class="flex-grow p-2 border rounded" required>
                <input type="number" name="num" placeholder="# of Questions" class="w-32 p-2 border rounded" required min="1">
                <!-- Status indicator for this topic row -->
                <span class="row-status w-6"></span>
                <button class="remove-topic bg-red-500 text-white p-2 rounded hover:bg-red-600 transition">
                    <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                        <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
                    </svg>
                </button>
            </div>
        </div>

        <!-- Controls: Add Topic, Number of Tests & Generate MCQs -->
        <div class="flex justify-center items-center space-x-4 mb-8">
            <button id="add-topic" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition">Add Topic</button>
            <input type="number" id="num-tests" placeholder="# of Tests" class="w-32 p-2 border rounded" required min="1">
            <button id="submit-topics" class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600 transition">Generate MCQs</button>
        </div>
        
        <!-- Results area for tests -->
        <div id="tests-results" class="mt-8">
            <h2 class="text-2xl font-semibold text-center mb-4 text-gray-700">Results:</h2>
            <!-- Test containers will be appended here -->
        </div>
    </div>
    
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const topicsContainer = document.getElementById('topics-container');
            const addTopicBtn = document.getElementById('add-topic');
            const submitTopicsBtn = document.getElementById('submit-topics');
            const testsResults = document.getElementById('tests-results');

            addTopicBtn.addEventListener('click', addTopicRow);
            submitTopicsBtn.addEventListener('click', submitTopics);
            topicsContainer.addEventListener('click', handleRemoveTopic);

            // Add a new topic row
            function addTopicRow() {
                const newRow = document.createElement('div');
                newRow.className = 'topic-row flex items-center space-x-2';
                newRow.innerHTML = `
                    <input type="text" name="topic" placeholder="Topic Name" class="flex-grow p-2 border rounded" required>
                    <input type="number" name="num" placeholder="# of Questions" class="w-32 p-2 border rounded" required min="1">
                    <span class="row-status w-6"></span>
                    <button class="remove-topic bg-red-500 text-white p-2 rounded hover:bg-red-600 transition">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
                        </svg>
                    </button>
                `;
                topicsContainer.appendChild(newRow);
            }

            // Remove a topic row
            function handleRemoveTopic(event) {
                if (event.target.closest('.remove-topic')) {
                    event.target.closest('.topic-row').remove();
                }
            }

            // Generate tests and call backend for each test & topic
            function submitTopics() {
                // Clear previous test results
                testsResults.innerHTML = `<h2 class="text-2xl font-semibold text-center mb-4 text-gray-700">Results:</h2>`;
                
                const numTests = parseInt(document.getElementById('num-tests').value);
                const rows = document.querySelectorAll('.topic-row');
                
                // Reset dataset counter for each topic row (to track completions across tests)
                rows.forEach(row => {
                    row.dataset.completed = "0";
                });
                
                // For each test (e.g. Test 1 to Test numTests)
                for (let testIndex = 1; testIndex <= numTests; testIndex++) {
                    // Create a container for each test
                    const testContainer = document.createElement('div');
                    testContainer.className = 'test-container mb-8 border p-4 rounded';
                    testContainer.innerHTML = `<h2 class="text-2xl font-semibold text-center mb-4 text-gray-700">Test ${testIndex}</h2>`;
                    
                    // Create containers for tab headers and tab contents for this test
                    const tabHeaders = document.createElement('div');
                    tabHeaders.className = 'tab-headers flex flex-wrap gap-2 mb-4';
                    const tabContents = document.createElement('div');
                    tabContents.className = 'tab-contents';
                    
                    testContainer.appendChild(tabHeaders);
                    testContainer.appendChild(tabContents);
                    testsResults.appendChild(testContainer);
                    
                    // For each topic row, create a tab for that topic in this test
                    rows.forEach((row, topicIndex) => {
                        const topic = row.querySelector('input[name="topic"]').value;
                        const num = parseInt(row.querySelector('input[name="num"]').value);
                        
                        // Create tab header for current test & topic with spinner status
                        const tabHeader = document.createElement('button');
                        tabHeader.className = 'tab-header px-4 py-2 rounded-t-lg bg-gray-200 hover:bg-gray-300 transition';
                        tabHeader.id = `tab-header-${testIndex}-${topicIndex}`;
                        tabHeader.setAttribute('data-tab', `${testIndex}-${topicIndex}`);
                        tabHeader.innerHTML = `${topic} <span class="status ml-2" id="status-${testIndex}-${topicIndex}">
                            <div class="animate-spin rounded-full h-3 w-3 border-b-2 border-blue-500 inline-block"></div>
                        </span>`;
                        tabHeader.addEventListener('click', () => activateTab(testIndex, topicIndex));
                        tabHeaders.appendChild(tabHeader);
                        
                        // Create tab content container for current test & topic
                        const tabContent = document.createElement('div');
                        tabContent.className = 'tab-content hidden p-4 bg-gray-100 rounded-b-lg';
                        tabContent.id = `tab-content-${testIndex}-${topicIndex}`;
                        tabContent.innerHTML = 'Loading...';
                        tabContents.appendChild(tabContent);
                        
                        // Call the backend API for this test and topic
                        callBackend(topic, num, testIndex, (responseText) => {
                            updateTabContent(testIndex, topicIndex, responseText);
                            // Update the tab header status to tick (✓)
                            document.getElementById(`status-${testIndex}-${topicIndex}`).innerHTML = '✓';
                            
                            // Update the topic row's status counter
                            let completed = parseInt(row.dataset.completed) || 0;
                            completed++;
                            row.dataset.completed = completed;
                            // When all tests for a topic are complete, update its row status with tick
                            if (completed === numTests) {
                                row.querySelector('.row-status').innerHTML = '✓';
                            }
                        });
                    });
                    
                    // Activate the first tab for this test by default (if available)
                    if (rows.length > 0) {
                        activateTab(testIndex, 0);
                    }
                }
            }

            // Update the tab content for given test & topic
            function updateTabContent(testIndex, topicIndex, content) {
                document.getElementById(`tab-content-${testIndex}-${topicIndex}`).innerHTML = `<pre class="whitespace-pre-wrap">${content}</pre>`;
            }

            // Activate a tab for a specific test
            function activateTab(testIndex, topicIndex) {
                // Find the test container by getting any element inside it
                const testContainer = document.getElementById(`tab-header-${testIndex}-${topicIndex}`).closest('.test-container');
                const tabHeaders = testContainer.querySelectorAll('.tab-header');
                const tabContents = testContainer.querySelectorAll('.tab-content');
                tabHeaders.forEach(header => header.classList.remove('bg-blue-500', 'text-white'));
                tabContents.forEach(content => content.classList.add('hidden'));
                document.getElementById(`tab-header-${testIndex}-${topicIndex}`).classList.add('bg-blue-500', 'text-white');
                document.getElementById(`tab-content-${testIndex}-${topicIndex}`).classList.remove('hidden');
            }

            // Real backend API call for MCQ generation
            function callBackend(topic, num, testNumber, callback) {
                fetch('/generate_mcq', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ topic: topic, num: num, test: testNumber })
                })
                .then(response => {
                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }
                    return response.json();
                })
                .then(data => {
                    callback(data.mcqs);
                })
                .catch(error => {
                    callback("Error: " + error.message);
                });
            }
        });
    </script>
</body>
</html>