linguabot commited on
Commit
9c091e0
·
verified ·
1 Parent(s): 29d4d6d

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. client/src/pages/TutorialTasks.tsx +146 -145
client/src/pages/TutorialTasks.tsx CHANGED
@@ -1,6 +1,7 @@
1
  import React, { useState, useEffect, useCallback, useRef, useTransition, useDeferredValue } from 'react';
2
  import { useNavigate } from 'react-router-dom';
3
  import { api } from '../services/api';
 
4
  import {
5
  AcademicCapIcon,
6
  DocumentTextIcon,
@@ -39,7 +40,7 @@ interface UserSubmission {
39
  }
40
 
41
  interface WeekBrief {
42
- _id: string;
43
  weekNumber: number;
44
  title: string;
45
  description: string;
@@ -163,7 +164,7 @@ const TutorialTasks: React.FC = () => {
163
  if (response.status >= 200 && response.status < 300) {
164
  const result = response.data;
165
  console.log('Submission created successfully:', result);
166
-
167
  setTranslationText({ ...translationText, [taskId]: '' });
168
  setSelectedGroups({ ...selectedGroups, [taskId]: 0 });
169
  setSubmitting({ ...submitting, [taskId]: false });
@@ -229,7 +230,7 @@ const TutorialTasks: React.FC = () => {
229
  const saveTask = async () => {
230
  if (!editingTask || !editTaskText.trim()) return;
231
 
232
- setSaving(true);
233
  try {
234
  const response = await api.put(`/api/tasks/${editingTask}`, {
235
  content: editTaskText
@@ -254,8 +255,8 @@ const TutorialTasks: React.FC = () => {
254
  const response = await api.put(`/api/tasks/${taskId}/move`, { direction });
255
  if (response.status === 200) {
256
  fetchTutorialTasks();
257
- }
258
- } catch (error) {
259
  console.error('Error moving task:', error);
260
  }
261
  };
@@ -307,18 +308,18 @@ const TutorialTasks: React.FC = () => {
307
  {/* Week Selector */}
308
  <div className="flex items-center justify-center space-x-4 mb-8">
309
  {[1, 2, 3, 4, 5].map((week) => (
310
- <button
311
- key={week}
312
  onClick={() => setSelectedWeek(week)}
313
  className={`px-6 py-3 rounded-lg font-medium transition-colors ${
314
- selectedWeek === week
315
- ? 'bg-indigo-600 text-white'
316
  : 'bg-white text-gray-700 hover:bg-gray-50 border border-gray-200'
317
- }`}
318
- >
319
- Week {week}
320
- </button>
321
- ))}
322
  </div>
323
 
324
  {/* Admin Controls */}
@@ -346,11 +347,11 @@ const TutorialTasks: React.FC = () => {
346
  isWeekHidden ? 'translate-x-5' : 'translate-x-0.5'
347
  } mt-0.5`}
348
  />
349
- </div>
350
- </div>
351
  </label>
352
- </div>
353
  </div>
 
354
  </div>
355
  )}
356
 
@@ -362,7 +363,7 @@ const TutorialTasks: React.FC = () => {
362
  <DocumentTextIcon className="h-5 w-5 text-indigo-600" />
363
  </div>
364
  <h2 className="text-xl font-semibold text-gray-900">Translation Brief</h2>
365
- </div>
366
  <div className="prose prose-indigo max-w-none">
367
  <p className="text-gray-700 leading-relaxed">
368
  This week focuses on translating {selectedWeek === 1 ? 'basic conversational phrases' :
@@ -378,19 +379,19 @@ const TutorialTasks: React.FC = () => {
378
  {/* Group Google Doc Section */}
379
  {!isWeekHidden && (
380
  <div ref={groupDocRef} className="bg-white rounded-lg p-6 mb-8 border border-gray-200 shadow-sm">
381
- <div className="flex items-center justify-between mb-4">
382
- <div className="flex items-center space-x-3">
383
  <div className="bg-green-100 rounded-full p-2">
384
  <DocumentTextIcon className="h-5 w-5 text-green-600" />
385
  </div>
386
  <h3 className="text-lg font-semibold text-gray-900">Group Google Doc</h3>
387
  </div>
388
- </div>
389
 
390
- <div className="space-y-4">
391
  <div className="flex items-center space-x-4">
392
- <input
393
- type="text"
394
  placeholder="Enter Google Doc URL"
395
  className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500"
396
  />
@@ -402,38 +403,38 @@ const TutorialTasks: React.FC = () => {
402
  </select>
403
  <button className="px-6 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors">
404
  Add Doc Link
405
- </button>
406
- </div>
407
-
408
  <div className="bg-gray-50 rounded-lg p-4">
409
  <h4 className="font-medium text-gray-900 mb-2">All Groups</h4>
410
- <div className="space-y-2">
411
  <div className="flex items-center justify-between py-2 px-3 bg-white rounded border">
412
  <span className="text-sm text-gray-600">No Google Doc links added yet</span>
413
- </div>
414
- </div>
415
- </div>
416
- </div>
417
- </div>
418
  )}
419
 
420
  {/* Tasks List */}
421
  {!isWeekHidden && (
422
  <div ref={listRef} className="space-y-8">
423
  {tutorialTasks.length === 0 ? (
424
- <div className="text-center py-12">
425
  <div className="bg-gray-100 rounded-full p-4 w-16 h-16 mx-auto mb-4">
426
  <DocumentTextIcon className="h-8 w-8 text-gray-400" />
427
  </div>
428
  <h3 className="text-lg font-medium text-gray-900 mb-2">No tasks available</h3>
429
  <p className="text-gray-600">Tasks for this week will be added soon.</p>
430
- </div>
431
- ) : (
432
  tutorialTasks.map((task, index) => (
433
  <div key={task._id} className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden" style={{ minHeight: '700px' }}>
434
  <div className="p-6">
435
- <div className="flex items-center justify-between mb-4">
436
- <div className="flex items-center space-x-3">
437
  <div className="relative p-2 rounded-2xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)]">
438
  <div className="pointer-events-none absolute inset-0 rounded-2xl opacity-60 [background:linear-gradient(to_bottom,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%)]" />
439
  <div className="pointer-events-none absolute inset-0 rounded-2xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-50" />
@@ -441,63 +442,63 @@ const TutorialTasks: React.FC = () => {
441
  <div className="pointer-events-none absolute inset-0 rounded-2xl" style={{ background: 'radial-gradient(120%_120%_at_50%_55%,rgba(0,0,0,0.04),rgba(0,0,0,0)_60%)', opacity: 0.9 }} />
442
  <div className="pointer-events-none absolute inset-0 rounded-2xl bg-sky-500/30 mix-blend-overlay opacity-35" />
443
  <DocumentTextIcon className="relative h-5 w-5 text-ui-text" />
444
- </div>
445
- <div>
446
  <h3 className="text-lg font-semibold text-gray-900 flex items-center">Source Text #{index + 1}
447
  {isAdmin && selectedWeek >= 4 && (
448
- <span className="ml-2 inline-flex items-center space-x-1">
449
- <button
450
- className="px-2 py-1 text-xs bg-gray-100 rounded hover:bg-gray-200"
451
- onClick={() => moveTask(task._id, 'up')}
452
- title="Move up"
453
- >↑</button>
454
- <button
455
- className="px-2 py-1 text-xs bg-gray-100 rounded hover:bg-gray-200"
456
- onClick={() => moveTask(task._id, 'down')}
457
- title="Move down"
458
- >↓</button>
459
- </span>
460
- )}
461
- </h3>
 
462
  </div>
463
- </div>
464
  {isAdmin && (
465
- <div className="flex items-center space-x-2">
466
- {editingTask === task._id ? (
467
- <>
468
- <button
469
- onClick={saveTask}
470
- disabled={saving}
471
- className="bg-green-100 hover:bg-green-200 text-green-700 px-3 py-1 rounded-lg transition-colors duration-200"
472
- >
473
- {saving ? (
474
- <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-green-600"></div>
475
- ) : (
476
- <CheckIcon className="h-4 w-4" />
477
- )}
478
- </button>
479
- <button
480
  onClick={cancelEditTask}
481
  className="bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-lg transition-colors duration-200"
482
- >
483
- <XMarkIcon className="h-4 w-4" />
484
- </button>
485
- </>
486
- ) : (
487
  <button
488
  onClick={() => setEditingTask(task._id)}
489
  className="bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-lg transition-colors duration-200"
490
  >
491
  <PencilIcon className="h-4 w-4" />
492
  </button>
493
- )}
494
- </div>
495
- )}
496
- </div>
497
 
498
  {/* Source Text Content */}
499
  <div className="bg-gray-50 rounded-lg p-4 mb-6">
500
- {editingTask === task._id ? (
501
  <textarea
502
  value={editTaskText}
503
  onChange={(e) => setEditTaskText(e.target.value)}
@@ -506,62 +507,62 @@ const TutorialTasks: React.FC = () => {
506
  ) : (
507
  <p className="text-gray-800 leading-relaxed whitespace-pre-wrap">{task.content}</p>
508
  )}
509
- </div>
510
 
511
- {/* All Submissions for this Task */}
512
- {userSubmissions[task._id] && userSubmissions[task._id].length > 0 && (
513
- <div className="bg-gradient-to-r from-white to-indigo-50 rounded-xl p-6 mb-6 border border-stone-200">
514
- <div className="flex items-center justify-between mb-4">
515
- <div className="flex items-center space-x-2">
516
- <div className="bg-indigo-100 rounded-full p-1">
517
- <CheckCircleIcon className="h-4 w-4 text-indigo-900" />
518
- </div>
519
- <h4 className="text-stone-900 font-semibold text-lg">All Submissions ({userSubmissions[task._id].length})</h4>
520
- </div>
521
- <button
522
- onClick={() => toggleExpanded(task._id)}
523
- className="flex items-center space-x-1 text-indigo-900 hover:text-indigo-900 text-sm font-medium"
524
- >
525
  <span>{expandedSections[task._id] ? 'Hide' : 'Show'}</span>
526
  <ChevronDownIcon className={`h-4 w-4 transition-transform ${expandedSections[task._id] ? 'rotate-180' : ''}`} />
527
- </button>
528
- </div>
529
- <div className={`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 transition-all duration-300 ${
530
- expandedSections[task._id]
531
- ? 'max-h-none overflow-visible'
532
- : 'max-h-0 overflow-hidden'
533
- }`}>
534
  {userSubmissions[task._id].map((submission, submissionIndex) => (
535
- <div key={submission._id} className="bg-white rounded-lg p-3 border border-stone-200 flex flex-col justify-between h-full">
536
- <div className="flex items-center justify-between mb-2">
537
- <div className="flex items-center space-x-2">
538
- {submission.isOwner && (
539
- <span className="inline-block bg-purple-100 text-purple-800 text-xs px-1.5 py-0.5 rounded-full">
540
  You
541
- </span>
542
- )}
543
  <span className="text-xs text-gray-500">Group {submission.groupNumber}</span>
544
- </div>
545
- <div className="flex items-center space-x-1">
546
  {getStatusIcon(submission.status)}
547
  {submission.isOwner && (
548
  <div className="flex space-x-1">
549
- <button
550
- onClick={() => handleEditSubmission(submission._id, submission.transcreation)}
551
  className="text-blue-600 hover:text-blue-800 text-xs"
552
- >
553
- Edit
554
- </button>
555
- <button
556
- onClick={() => handleDeleteSubmission(submission._id)}
557
  className="text-red-600 hover:text-red-800 text-xs"
558
- >
559
- Delete
560
- </button>
561
  </div>
562
- )}
563
- </div>
564
- </div>
565
  <div className="text-sm text-gray-700 mb-2 flex-grow">
566
  {editingSubmission?.id === submission._id ? (
567
  <div className="space-y-2">
@@ -583,15 +584,15 @@ const TutorialTasks: React.FC = () => {
583
  >
584
  Cancel
585
  </button>
586
- </div>
587
- </div>
588
  ) : (
589
  <p className="whitespace-pre-wrap">{submission.transcreation}</p>
590
  )}
591
- </div>
592
- </div>
593
  ))}
594
- </div>
595
  </div>
596
  )}
597
 
@@ -606,15 +607,15 @@ const TutorialTasks: React.FC = () => {
606
  onTranslationChange={(v) => setTranslationText(prev => ({ ...prev, [task._id]: v }))}
607
  onSubmit={(localText, localGroup) => handleSubmitTranslation(task._id, localText, localGroup)}
608
  />
609
- )}
610
 
611
- {/* Show login message for visitors */}
612
- {!localStorage.getItem('token') && (
613
  <div className="relative rounded-xl p-6 border border-gray-200">
614
  <div className="absolute inset-0 rounded-xl bg-gradient-to-r from-gray-100/70 to-indigo-100/60" />
615
  <div className="relative rounded-xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)] p-6">
616
  <div className="pointer-events-none absolute inset-0 rounded-xl opacity-50 [background:linear-gradient(to_bottom,rgba(255,255,255,0.3),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.28),rgba(255,255,255,0)_28%)]" />
617
- <div className="flex items-center space-x-2 mb-4">
618
  <div className="relative p-2 rounded-2xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)]">
619
  <div className="pointer-events-none absolute inset-0 rounded-2xl opacity-60 [background:linear-gradient(to_bottom,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%)]" />
620
  <div className="pointer-events-none absolute inset-0 rounded-2xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-50" />
@@ -622,26 +623,26 @@ const TutorialTasks: React.FC = () => {
622
  <div className="pointer-events-none absolute inset-0 rounded-2xl" style={{ background: 'radial-gradient(120%_120%_at_50%_55%,rgba(0,0,0,0.04),rgba(0,0,0,0)_60%)', opacity: 0.9 }} />
623
  <div className="pointer-events-none absolute inset-0 rounded-2xl bg-sky-500/30 mix-blend-overlay opacity-35" />
624
  <DocumentTextIcon className="relative h-5 w-5 text-ui-text" />
625
- </div>
626
  <h4 className="text-gray-900 font-semibold text-lg">Group Translation</h4>
627
- </div>
628
  <div className="text-center py-8">
629
  <p className="text-gray-600 mb-4">Please log in to submit your translation</p>
630
- <button
631
  onClick={() => navigate('/login')}
632
  className="px-6 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
633
- >
634
  Log In
635
- </button>
636
  </div>
637
  </div>
 
 
638
  </div>
639
- )}
640
- </div>
641
- </div>
642
- ))
643
- )}
644
- </div>
645
  )}
646
  </div>
647
 
@@ -833,4 +834,4 @@ const TranslationSection: React.FC<{
833
  a.taskId === b.taskId
834
  ));
835
 
836
- export default TutorialTasks;
 
1
  import React, { useState, useEffect, useCallback, useRef, useTransition, useDeferredValue } from 'react';
2
  import { useNavigate } from 'react-router-dom';
3
  import { api } from '../services/api';
4
+ import { flushSync } from 'react-dom';
5
  import {
6
  AcademicCapIcon,
7
  DocumentTextIcon,
 
40
  }
41
 
42
  interface WeekBrief {
43
+ _id: string;
44
  weekNumber: number;
45
  title: string;
46
  description: string;
 
164
  if (response.status >= 200 && response.status < 300) {
165
  const result = response.data;
166
  console.log('Submission created successfully:', result);
167
+
168
  setTranslationText({ ...translationText, [taskId]: '' });
169
  setSelectedGroups({ ...selectedGroups, [taskId]: 0 });
170
  setSubmitting({ ...submitting, [taskId]: false });
 
230
  const saveTask = async () => {
231
  if (!editingTask || !editTaskText.trim()) return;
232
 
233
+ setSaving(true);
234
  try {
235
  const response = await api.put(`/api/tasks/${editingTask}`, {
236
  content: editTaskText
 
255
  const response = await api.put(`/api/tasks/${taskId}/move`, { direction });
256
  if (response.status === 200) {
257
  fetchTutorialTasks();
258
+ }
259
+ } catch (error) {
260
  console.error('Error moving task:', error);
261
  }
262
  };
 
308
  {/* Week Selector */}
309
  <div className="flex items-center justify-center space-x-4 mb-8">
310
  {[1, 2, 3, 4, 5].map((week) => (
311
+ <button
312
+ key={week}
313
  onClick={() => setSelectedWeek(week)}
314
  className={`px-6 py-3 rounded-lg font-medium transition-colors ${
315
+ selectedWeek === week
316
+ ? 'bg-indigo-600 text-white'
317
  : 'bg-white text-gray-700 hover:bg-gray-50 border border-gray-200'
318
+ }`}
319
+ >
320
+ Week {week}
321
+ </button>
322
+ ))}
323
  </div>
324
 
325
  {/* Admin Controls */}
 
347
  isWeekHidden ? 'translate-x-5' : 'translate-x-0.5'
348
  } mt-0.5`}
349
  />
350
+ </div>
351
+ </div>
352
  </label>
 
353
  </div>
354
+ </div>
355
  </div>
356
  )}
357
 
 
363
  <DocumentTextIcon className="h-5 w-5 text-indigo-600" />
364
  </div>
365
  <h2 className="text-xl font-semibold text-gray-900">Translation Brief</h2>
366
+ </div>
367
  <div className="prose prose-indigo max-w-none">
368
  <p className="text-gray-700 leading-relaxed">
369
  This week focuses on translating {selectedWeek === 1 ? 'basic conversational phrases' :
 
379
  {/* Group Google Doc Section */}
380
  {!isWeekHidden && (
381
  <div ref={groupDocRef} className="bg-white rounded-lg p-6 mb-8 border border-gray-200 shadow-sm">
382
+ <div className="flex items-center justify-between mb-4">
383
+ <div className="flex items-center space-x-3">
384
  <div className="bg-green-100 rounded-full p-2">
385
  <DocumentTextIcon className="h-5 w-5 text-green-600" />
386
  </div>
387
  <h3 className="text-lg font-semibold text-gray-900">Group Google Doc</h3>
388
  </div>
389
+ </div>
390
 
391
+ <div className="space-y-4">
392
  <div className="flex items-center space-x-4">
393
+ <input
394
+ type="text"
395
  placeholder="Enter Google Doc URL"
396
  className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500"
397
  />
 
403
  </select>
404
  <button className="px-6 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors">
405
  Add Doc Link
406
+ </button>
407
+ </div>
408
+
409
  <div className="bg-gray-50 rounded-lg p-4">
410
  <h4 className="font-medium text-gray-900 mb-2">All Groups</h4>
411
+ <div className="space-y-2">
412
  <div className="flex items-center justify-between py-2 px-3 bg-white rounded border">
413
  <span className="text-sm text-gray-600">No Google Doc links added yet</span>
414
+ </div>
415
+ </div>
416
+ </div>
417
+ </div>
418
+ </div>
419
  )}
420
 
421
  {/* Tasks List */}
422
  {!isWeekHidden && (
423
  <div ref={listRef} className="space-y-8">
424
  {tutorialTasks.length === 0 ? (
425
+ <div className="text-center py-12">
426
  <div className="bg-gray-100 rounded-full p-4 w-16 h-16 mx-auto mb-4">
427
  <DocumentTextIcon className="h-8 w-8 text-gray-400" />
428
  </div>
429
  <h3 className="text-lg font-medium text-gray-900 mb-2">No tasks available</h3>
430
  <p className="text-gray-600">Tasks for this week will be added soon.</p>
431
+ </div>
432
+ ) : (
433
  tutorialTasks.map((task, index) => (
434
  <div key={task._id} className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden" style={{ minHeight: '700px' }}>
435
  <div className="p-6">
436
+ <div className="flex items-center justify-between mb-4">
437
+ <div className="flex items-center space-x-3">
438
  <div className="relative p-2 rounded-2xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)]">
439
  <div className="pointer-events-none absolute inset-0 rounded-2xl opacity-60 [background:linear-gradient(to_bottom,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%)]" />
440
  <div className="pointer-events-none absolute inset-0 rounded-2xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-50" />
 
442
  <div className="pointer-events-none absolute inset-0 rounded-2xl" style={{ background: 'radial-gradient(120%_120%_at_50%_55%,rgba(0,0,0,0.04),rgba(0,0,0,0)_60%)', opacity: 0.9 }} />
443
  <div className="pointer-events-none absolute inset-0 rounded-2xl bg-sky-500/30 mix-blend-overlay opacity-35" />
444
  <DocumentTextIcon className="relative h-5 w-5 text-ui-text" />
445
+ </div>
446
+ <div>
447
  <h3 className="text-lg font-semibold text-gray-900 flex items-center">Source Text #{index + 1}
448
  {isAdmin && selectedWeek >= 4 && (
449
+ <span className="ml-2 inline-flex items-center space-x-1">
450
+ <button
451
+ className="px-2 py-1 text-xs bg-gray-100 rounded hover:bg-gray-200"
452
+ onClick={() => moveTask(task._id, 'up')}
453
+ title="Move up"
454
+ >↑</button>
455
+ <button
456
+ className="px-2 py-1 text-xs bg-gray-100 rounded hover:bg-gray-200"
457
+ onClick={() => moveTask(task._id, 'down')}
458
+ title="Move down"
459
+ >↓</button>
460
+ </span>
461
+ )}
462
+ </h3>
463
+ </div>
464
  </div>
 
465
  {isAdmin && (
466
+ <div className="flex items-center space-x-2">
467
+ {editingTask === task._id ? (
468
+ <>
469
+ <button
470
+ onClick={saveTask}
471
+ disabled={saving}
472
+ className="bg-green-100 hover:bg-green-200 text-green-700 px-3 py-1 rounded-lg transition-colors duration-200"
473
+ >
474
+ {saving ? (
475
+ <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-green-600"></div>
476
+ ) : (
477
+ <CheckIcon className="h-4 w-4" />
478
+ )}
479
+ </button>
480
+ <button
481
  onClick={cancelEditTask}
482
  className="bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-lg transition-colors duration-200"
483
+ >
484
+ <XMarkIcon className="h-4 w-4" />
485
+ </button>
486
+ </>
487
+ ) : (
488
  <button
489
  onClick={() => setEditingTask(task._id)}
490
  className="bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-lg transition-colors duration-200"
491
  >
492
  <PencilIcon className="h-4 w-4" />
493
  </button>
494
+ )}
495
+ </div>
496
+ )}
497
+ </div>
498
 
499
  {/* Source Text Content */}
500
  <div className="bg-gray-50 rounded-lg p-4 mb-6">
501
+ {editingTask === task._id ? (
502
  <textarea
503
  value={editTaskText}
504
  onChange={(e) => setEditTaskText(e.target.value)}
 
507
  ) : (
508
  <p className="text-gray-800 leading-relaxed whitespace-pre-wrap">{task.content}</p>
509
  )}
510
+ </div>
511
 
512
+ {/* All Submissions for this Task */}
513
+ {userSubmissions[task._id] && userSubmissions[task._id].length > 0 && (
514
+ <div className="bg-gradient-to-r from-white to-indigo-50 rounded-xl p-6 mb-6 border border-stone-200">
515
+ <div className="flex items-center justify-between mb-4">
516
+ <div className="flex items-center space-x-2">
517
+ <div className="bg-indigo-100 rounded-full p-1">
518
+ <CheckCircleIcon className="h-4 w-4 text-indigo-900" />
519
+ </div>
520
+ <h4 className="text-stone-900 font-semibold text-lg">All Submissions ({userSubmissions[task._id].length})</h4>
521
+ </div>
522
+ <button
523
+ onClick={() => toggleExpanded(task._id)}
524
+ className="flex items-center space-x-1 text-indigo-900 hover:text-indigo-900 text-sm font-medium"
525
+ >
526
  <span>{expandedSections[task._id] ? 'Hide' : 'Show'}</span>
527
  <ChevronDownIcon className={`h-4 w-4 transition-transform ${expandedSections[task._id] ? 'rotate-180' : ''}`} />
528
+ </button>
529
+ </div>
530
+ <div className={`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 transition-all duration-300 ${
531
+ expandedSections[task._id]
532
+ ? 'max-h-none overflow-visible'
533
+ : 'max-h-0 overflow-hidden'
534
+ }`}>
535
  {userSubmissions[task._id].map((submission, submissionIndex) => (
536
+ <div key={submission._id} className="bg-white rounded-lg p-3 border border-stone-200 flex flex-col justify-between h-full">
537
+ <div className="flex items-center justify-between mb-2">
538
+ <div className="flex items-center space-x-2">
539
+ {submission.isOwner && (
540
+ <span className="inline-block bg-purple-100 text-purple-800 text-xs px-1.5 py-0.5 rounded-full">
541
  You
542
+ </span>
543
+ )}
544
  <span className="text-xs text-gray-500">Group {submission.groupNumber}</span>
545
+ </div>
546
+ <div className="flex items-center space-x-1">
547
  {getStatusIcon(submission.status)}
548
  {submission.isOwner && (
549
  <div className="flex space-x-1">
550
+ <button
551
+ onClick={() => handleEditSubmission(submission._id, submission.transcreation)}
552
  className="text-blue-600 hover:text-blue-800 text-xs"
553
+ >
554
+ Edit
555
+ </button>
556
+ <button
557
+ onClick={() => handleDeleteSubmission(submission._id)}
558
  className="text-red-600 hover:text-red-800 text-xs"
559
+ >
560
+ Delete
561
+ </button>
562
  </div>
563
+ )}
564
+ </div>
565
+ </div>
566
  <div className="text-sm text-gray-700 mb-2 flex-grow">
567
  {editingSubmission?.id === submission._id ? (
568
  <div className="space-y-2">
 
584
  >
585
  Cancel
586
  </button>
587
+ </div>
588
+ </div>
589
  ) : (
590
  <p className="whitespace-pre-wrap">{submission.transcreation}</p>
591
  )}
592
+ </div>
593
+ </div>
594
  ))}
595
+ </div>
596
  </div>
597
  )}
598
 
 
607
  onTranslationChange={(v) => setTranslationText(prev => ({ ...prev, [task._id]: v }))}
608
  onSubmit={(localText, localGroup) => handleSubmitTranslation(task._id, localText, localGroup)}
609
  />
610
+ )}
611
 
612
+ {/* Show login message for visitors */}
613
+ {!localStorage.getItem('token') && (
614
  <div className="relative rounded-xl p-6 border border-gray-200">
615
  <div className="absolute inset-0 rounded-xl bg-gradient-to-r from-gray-100/70 to-indigo-100/60" />
616
  <div className="relative rounded-xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)] p-6">
617
  <div className="pointer-events-none absolute inset-0 rounded-xl opacity-50 [background:linear-gradient(to_bottom,rgba(255,255,255,0.3),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.28),rgba(255,255,255,0)_28%)]" />
618
+ <div className="flex items-center space-x-2 mb-4">
619
  <div className="relative p-2 rounded-2xl bg-white/10 backdrop-blur-md ring-1 ring-inset ring-white/30 shadow-[inset_0_0.5px_0_rgba(255,255,255,0.5),inset_0_-1px_1.5px_rgba(0,0,0,0.12)]">
620
  <div className="pointer-events-none absolute inset-0 rounded-2xl opacity-60 [background:linear-gradient(to_bottom,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%),linear-gradient(to_right,rgba(255,255,255,0.35),rgba(255,255,255,0)_28%)]" />
621
  <div className="pointer-events-none absolute inset-0 rounded-2xl bg-gradient-to-tr from-white/30 via-white/10 to-transparent opacity-50" />
 
623
  <div className="pointer-events-none absolute inset-0 rounded-2xl" style={{ background: 'radial-gradient(120%_120%_at_50%_55%,rgba(0,0,0,0.04),rgba(0,0,0,0)_60%)', opacity: 0.9 }} />
624
  <div className="pointer-events-none absolute inset-0 rounded-2xl bg-sky-500/30 mix-blend-overlay opacity-35" />
625
  <DocumentTextIcon className="relative h-5 w-5 text-ui-text" />
626
+ </div>
627
  <h4 className="text-gray-900 font-semibold text-lg">Group Translation</h4>
628
+ </div>
629
  <div className="text-center py-8">
630
  <p className="text-gray-600 mb-4">Please log in to submit your translation</p>
631
+ <button
632
  onClick={() => navigate('/login')}
633
  className="px-6 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
634
+ >
635
  Log In
636
+ </button>
637
  </div>
638
  </div>
639
+ </div>
640
+ )}
641
  </div>
642
+ </div>
643
+ ))
644
+ )}
645
+ </div>
 
 
646
  )}
647
  </div>
648
 
 
834
  a.taskId === b.taskId
835
  ));
836
 
837
+ export default TutorialTasks;