File size: 14,952 Bytes
7050e07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
// Initialize Supabase client
const supabaseUrl = 'https://your-project.supabase.co';
const supabaseKey = 'your-anon-key';
const supabase = window.supabase.createClient(supabaseUrl, supabaseKey);

// App State
let currentView = 'dashboard';
let recordingSession = {
    sentences: [],
    currentIndex: 0,
    recordings: [],
    startTime: null
};

let mediaRecorder = null;
let audioChunks = [];
let recordingStartTime = null;

// DOM Elements
const views = {
    dashboard: document.getElementById('dashboard-view'),
    recording: document.getElementById('recording-view'),
    admin: document.getElementById('admin-view')
};

// Initialize app
document.addEventListener('DOMContentLoaded', () => {
    initializeEventListeners();
    loadDashboardData();
    checkAdminAccess();
});

// Event Listeners
function initializeEventListeners() {
    // Dashboard
    document.getElementById('start-recording-btn').addEventListener('click', startRecordingSession);
    document.getElementById('recent-recordings-btn').addEventListener('click', toggleRecentWork);
    
    // Recording interface
    document.getElementById('record-btn').addEventListener('click', toggleRecording);
    document.getElementById('skip-btn').addEventListener('click', skipSentence);
    document.getElementById('next-btn').addEventListener('click', nextSentence);
    
    // Navigation will be handled by navbar component
}

// Navigation
function showView(viewName) {
    Object.keys(views).forEach(key => {
        views[key].classList.add('hidden');
    });
    if (views[viewName]) {
        views[viewName].classList.remove('hidden');
        currentView = viewName;
        
        if (viewName === 'admin') {
            loadAdminData();
        } else if (viewName === 'dashboard') {
            loadDashboardData();
        }
    }
}

// Dashboard Functions
async function loadDashboardData() {
    try {
        // Mock data for MVP
        const mockData = {
            totalEarnings: '12.50',
            completedCount: 125,
            pendingCount: 8
        };
        
        document.getElementById('total-earnings').textContent = mockData.totalEarnings;
        document.getElementById('completed-count').textContent = mockData.completedCount;
        document.getElementById('pending-count').textContent = mockData.pendingCount;
        
        loadRecentRecordings();
    } catch (error) {
        console.error('Error loading dashboard:', error);
    }
}

function loadRecentRecordings() {
    // Mock recent recordings
    const recentRecordings = [
        { id: 1, frenchText: "Bonjour, comment allez-vous?", status: 'approved', date: '2024-01-15' },
        { id: 2, frenchText: "Je voudrais un café", status: 'pending', date: '2024-01-15' },
        { id: 3, frenchText: "Où est la gare?", status: 'approved', date: '2024-01-14' }
    ];
    
    const recentList = document.getElementById('recent-list');
    recentList.innerHTML = recentRecordings.map(rec => `
        <div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg border border-gray-200">
            <div class="flex-1">
                <p class="text-sm text-gray-800">${rec.frenchText}</p>
                <p class="text-xs text-gray-500">${rec.date}</p>
            </div>
            <span class="px-2 py-1 text-xs font-medium rounded-full ${
                rec.status === 'approved' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'
            }">
                ${rec.status}
            </span>
        </div>
    `).join('');
}

function toggleRecentWork() {
    const recentWork = document.getElementById('recent-work');
    recentWork.classList.toggle('hidden');
}

// Recording Session Functions
async function startRecordingSession() {
    try {
        // Load 10 random sentences (mock data for MVP)
        recordingSession.sentences = [
            { id: 1, french_text: "Bonjour, comment allez-vous?", domain: "greetings" },
            { id: 2, french_text: "Je voudrais un café, s'il vous plaît", domain: "food" },
            { id: 3, french_text: "Où se trouve la bibliothèque?", domain: "directions" },
            { id: 4, french_text: "Quel temps fait-il aujourd'hui?", domain: "weather" },
            { id: 5, french_text: "Merci beaucoup pour votre aide", domain: "gratitude" },
            { id: 6, french_text: "Je ne comprends pas", domain: "communication" },
            { id: 7, french_text: "À quelle heure fermez-vous?", domain: "time" },
            { id: 8, french_text: "Combien ça coûte?", domain: "shopping" },
            { id: 9, french_text: "Pouvez-vous répéter, s'il vous plaît?", domain: "communication" },
            { id: 10, french_text: "J'ai besoin d'un taxi", domain: "transport" }
        ];
        
        recordingSession.currentIndex = 0;
        recordingSession.recordings = [];
        recordingSession.startTime = new Date();
        
        showView('recording');
        loadCurrentSentence();
    } catch (error) {
        console.error('Error starting session:', error);
        alert('Error starting recording session');
    }
}

function loadCurrentSentence() {
    const sentence = recordingSession.sentences[recordingSession.currentIndex];
    if (!sentence) return;
    
    document.getElementById('current-sentence').textContent = recordingSession.currentIndex + 1;
    document.getElementById('progress-bar').style.width = `${((recordingSession.currentIndex + 1) / 10) * 100}%`;
    document.getElementById('french-sentence').textContent = sentence.french_text;
    
    // Reset UI
    resetRecordingUI();
    
    // Load French audio (mock - in real app would fetch from storage)
    const frenchAudio = document.getElementById('french-audio');
    frenchAudio.src = `https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3?t=${sentence.id}`;
}

function resetRecordingUI() {
    const recordBtn = document.getElementById('record-btn');
    const recordingIndicator = document.getElementById('recording-indicator');
    const pulaarAudioSection = document.getElementById('pulaar-audio-section');
    const nextBtn = document.getElementById('next-btn');
    
    recordBtn.innerHTML = '<i data-feather="mic" class="w-12 h-12"></i>';
    recordBtn.classList.remove('recording-active', 'bg-green-500', 'hover:bg-green-600');
    recordBtn.classList.add('bg-red-500', 'hover:bg-red-600');
    recordingIndicator.classList.add('hidden');
    pulaarAudioSection.classList.add('hidden');
    nextBtn.disabled = true;
    
    feather.replace();
}

// Recording Functions
async function toggleRecording() {
    if (mediaRecorder && mediaRecorder.state === 'recording') {
        stopRecording();
    } else {
        await startRecording();
    }
}

async function startRecording() {
    try {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        mediaRecorder = new MediaRecorder(stream);
        audioChunks = [];
        
        mediaRecorder.ondataavailable = (event) => {
            audioChunks.push(event.data);
        };
        
        mediaRecorder.onstop = () => {
            const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
            const audioUrl = URL.createObjectURL(audioBlob);
            
            // Show the recording
            const pulaarAudio = document.getElementById('pulaar-audio');
            pulaarAudio.src = audioUrl;
            document.getElementById('pulaar-audio-section').classList.remove('hidden');
            
            // Enable next button
            document.getElementById('next-btn').disabled = false;
            
            // Store recording
            recordingSession.recordings[recordingSession.currentIndex] = {
                audioBlob: audioBlob,
                audioUrl: audioUrl,
                timestamp: new Date()
            };
            
            // Stop all tracks
            stream.getTracks().forEach(track => track.stop());
        };
        
        mediaRecorder.start();
        recordingStartTime = Date.now();
        
        // Update UI
        const recordBtn = document.getElementById('record-btn');
        recordBtn.innerHTML = '<i data-feather="square" class="w-12 h-12"></i>';
        recordBtn.classList.remove('bg-red-500', 'hover:bg-red-600');
        recordBtn.classList.add('bg-green-500', 'hover:bg-green-600', 'recording-active');
        
        document.getElementById('recording-indicator').classList.remove('hidden');
        
        // Update timer
        updateRecordingTimer();
        
        feather.replace();
    } catch (error) {
        console.error('Error starting recording:', error);
        alert('Could not access microphone. Please check permissions.');
    }
}

function stopRecording() {
    if (mediaRecorder && mediaRecorder.state === 'recording') {
        mediaRecorder.stop();
    }
}

function updateRecordingTimer() {
    if (mediaRecorder && mediaRecorder.state === 'recording') {
        const elapsed = Math.floor((Date.now() - recordingStartTime) / 1000);
        const minutes = Math.floor(elapsed / 60).toString().padStart(2, '0');
        const seconds = (elapsed % 60).toString().padStart(2, '0');
        document.getElementById('recording-timer').textContent = `${minutes}:${seconds}`;
        
        requestAnimationFrame(updateRecordingTimer);
    }
}

function skipSentence() {
    recordingSession.recordings[recordingSession.currentIndex] = null;
    nextSentence();
}

function nextSentence() {
    recordingSession.currentIndex++;
    
    if (recordingSession.currentIndex >= recordingSession.sentences.length) {
        // Session complete
        finishRecordingSession();
    } else {
        loadCurrentSentence();
    }
}

async function finishRecordingSession() {
    // Calculate earnings
    const completedRecordings = recordingSession.recordings.filter(r => r !== null).length;
    const earnings = completedRecordings * 0.10;
    
    // Show completion message
    alert(`Session Complete!\n\nCompleted recordings: ${completedRecordings}\nEstimated earnings: €${earnings.toFixed(2)}\n\nYour recordings are now pending review.`);
    
    // Return to dashboard
    showView('dashboard');
    
    // Refresh dashboard data
    loadDashboardData();
}

// Admin Functions
function checkAdminAccess() {
    // Check if user is admin (mock for MVP)
    const isAdmin = window.location.hash === '#admin';
    if (isAdmin) {
        // In real app, check auth role
    }
}

async function loadAdminData() {
    try {
        // Mock data for MVP
        const mockSubmissions = [
            {
                id: 1,
                userName: 'User 1',
                frenchText: "Bonjour, comment allez-vous?",
                frenchAudioUrl: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3',
                pulaarAudioUrl: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3',
                status: 'pending',
                createdAt: '2024-01-15T10:30:00Z'
            },
            {
                id: 2,
                userName: 'User 2',
                frenchText: "Je voudrais un café",
                frenchAudioUrl: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-3.mp3',
                pulaarAudioUrl: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-4.mp3',
                status: 'pending',
                createdAt: '2024-01-15T09:45:00Z'
            }
        ];
        
        // Update stats
        document.getElementById('admin-total-submissions').textContent = mockSubmissions.length;
        document.getElementById('admin-pending').textContent = mockSubmissions.filter(s => s.status === 'pending').length;
        document.getElementById('admin-approved').textContent = 0;
        document.getElementById('admin-rejected').textContent = 0;
        
        // Render submissions
        renderSubmissions(mockSubmissions);
    } catch (error) {
        console.error('Error loading admin data:', error);
    }
}

function renderSubmissions(submissions) {
    const submissionsList = document.getElementById('submissions-list');
    
    submissionsList.innerHTML = submissions.map(sub => `
        <div class="bg-gray-50 rounded-lg p-4 border border-gray-200">
            <div class="mb-3">
                <div class="flex justify-between items-start mb-2">
                    <div>
                        <p class="font-medium text-gray-800">${sub.userName}</p>
                        <p class="text-sm text-gray-600">${new Date(sub.createdAt).toLocaleString()}</p>
                    </div>
                    <span class="px-2 py-1 text-xs font-medium rounded-full bg-yellow-100 text-yellow-800">
                        ${sub.status}
                    </span>
                </div>
                <p class="text-gray-700">${sub.frenchText}</p>
            </div>
            
            <div class="grid md:grid-cols-2 gap-4 mb-4">
                <div>
                    <p class="text-sm font-medium text-gray-600 mb-1">French Audio:</p>
                    <audio controls class="w-full">
                        <source src="${sub.frenchAudioUrl}" type="audio/mpeg">
                    </audio>
                </div>
                <div>
                    <p class="text-sm font-medium text-gray-600 mb-1">Pulaar Audio:</p>
                    <audio controls class="w-full">
                        <source src="${sub.pulaarAudioUrl}" type="audio/mpeg">
                    </audio>
                </div>
            </div>
            
            <div class="flex gap-3">
                <button onclick="updateSubmissionStatus(${sub.id}, 'approved')" class="flex-1 bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200">
                    <i data-feather="check" class="w-4 h-4 inline mr-1"></i>
                    Approve
                </button>
                <button onclick="updateSubmissionStatus(${sub.id}, 'rejected')" class="flex-1 bg-red-600 hover:bg-red-700 text-white font-medium py-2 px-4 rounded-lg transition duration-200">
                    <i data-feather="x" class="w-4 h-4 inline mr-1"></i>
                    Reject
                </button>
            </div>
        </div>
    `).join('');
    
    feather.replace();
}

async function updateSubmissionStatus(submissionId, status) {
    try {
        // In real app, update in Supabase
        console.log(`Updating submission ${submissionId} to ${status}`);
        
        // Reload data
        loadAdminData();
        
        // Show feedback
        alert(`Submission ${status} successfully!`);
    } catch (error) {
        console.error('Error updating submission:', error);
        alert('Error updating submission status');
    }
}

// Make functions globally available for onclick handlers
window.updateSubmissionStatus = updateSubmissionStatus;
window.showView = showView;