Tristan Yu commited on
Commit
2c94120
·
1 Parent(s): 04f8035

Fix layout logic: Add Task uses side-by-side for ALL weeks, Add Image uses dynamic layout, fix WeeklyPractice image display

Browse files
client/src/pages/TutorialTasks.tsx CHANGED
@@ -1398,9 +1398,9 @@ const TutorialTasks: React.FC = () => {
1398
  ) : (
1399
  <div className="space-y-4">
1400
  {task.imageUrl ? (
1401
- // Different layout based on task's week number
1402
- task.weekNumber >= 3 ? (
1403
- // Week 3+ layout with dynamic sizing and alignment
1404
  <div className={`flex flex-col md:flex-row gap-6 items-start ${
1405
  task.imageAlignment === 'left' ? 'md:flex-row' :
1406
  task.imageAlignment === 'right' ? 'md:flex-row-reverse' :
@@ -1436,19 +1436,9 @@ const TutorialTasks: React.FC = () => {
1436
  )}
1437
  </div>
1438
  </div>
1439
- {/* Text section - only show if content exists and is not image-only */}
1440
- {task.content && task.content !== 'Image-based task' && (
1441
- <div className={`${
1442
- task.imageAlignment === 'left' ? 'w-full md:w-1/2' :
1443
- task.imageAlignment === 'right' ? 'w-full md:w-1/2' :
1444
- 'w-full'
1445
- }`}>
1446
- <div className="text-indigo-900 leading-relaxed text-lg font-source-text whitespace-pre-wrap">{task.content}</div>
1447
- </div>
1448
- )}
1449
  </div>
1450
  ) : (
1451
- // Week 1-2 layout (original side-by-side)
1452
  <div className="flex flex-col md:flex-row gap-6 items-start">
1453
  {/* Image on the left - 50% width */}
1454
  <div className="w-full md:w-1/2 flex justify-center">
@@ -1576,8 +1566,8 @@ const TutorialTasks: React.FC = () => {
1576
  </div>
1577
  )}
1578
 
1579
- {/* Translation Input (always show if user is logged in, but hide for image-only content in week 3+) */}
1580
- {localStorage.getItem('token') && !(task.weekNumber >= 3 && task.content === 'Image-based task') && (
1581
  <div className="bg-white rounded-lg p-6 border border-gray-200 shadow-sm">
1582
  <div className="flex items-center space-x-3 mb-4">
1583
  <div className="bg-gray-100 rounded-lg p-2">
 
1398
  ) : (
1399
  <div className="space-y-4">
1400
  {task.imageUrl ? (
1401
+ // Check if this is an image-only task (created via "Add Image" function)
1402
+ task.content === 'Image-based task' ? (
1403
+ // Image-only layout with dynamic sizing and alignment
1404
  <div className={`flex flex-col md:flex-row gap-6 items-start ${
1405
  task.imageAlignment === 'left' ? 'md:flex-row' :
1406
  task.imageAlignment === 'right' ? 'md:flex-row-reverse' :
 
1436
  )}
1437
  </div>
1438
  </div>
 
 
 
 
 
 
 
 
 
 
1439
  </div>
1440
  ) : (
1441
+ // Regular task layout (original side-by-side for ALL weeks)
1442
  <div className="flex flex-col md:flex-row gap-6 items-start">
1443
  {/* Image on the left - 50% width */}
1444
  <div className="w-full md:w-1/2 flex justify-center">
 
1566
  </div>
1567
  )}
1568
 
1569
+ {/* Translation Input (always show if user is logged in, but hide for image-only content) */}
1570
+ {localStorage.getItem('token') && task.content !== 'Image-based task' && (
1571
  <div className="bg-white rounded-lg p-6 border border-gray-200 shadow-sm">
1572
  <div className="flex items-center space-x-3 mb-4">
1573
  <div className="bg-gray-100 rounded-lg p-2">
client/src/pages/WeeklyPractice.tsx CHANGED
@@ -2030,43 +2030,25 @@ const WeeklyPractice: React.FC = () => {
2030
  </div>
2031
  ) : (
2032
  <div>
2033
- {practice.imageUrl && practice.weekNumber >= 3 ? (
2034
- <div className={`flex flex-col md:flex-row gap-6 items-start ${
2035
- practice.imageAlignment === 'left' ? 'md:flex-row' :
2036
- practice.imageAlignment === 'right' ? 'md:flex-row-reverse' :
2037
- 'md:flex-col'
2038
- }`}>
2039
- {/* Image with dynamic alignment */}
2040
- <div className={`${
2041
- practice.imageAlignment === 'left' ? 'w-full md:w-1/2' :
2042
- practice.imageAlignment === 'right' ? 'w-full md:w-1/2' :
2043
- 'w-full'
2044
- } flex ${
2045
- practice.imageAlignment === 'left' ? 'justify-start' :
2046
- practice.imageAlignment === 'right' ? 'justify-end' :
2047
- 'justify-center'
2048
  }`}>
2049
- {practice.imageUrl.startsWith('data:') ? (
2050
- <div className="inline-block rounded-lg shadow-md overflow-hidden">
2051
- <img
2052
- src={practice.imageUrl}
2053
- alt={practice.imageAlt || 'Uploaded image'}
2054
- className="w-full h-auto"
2055
- style={{
2056
- height: `${practice.imageSize || 200}px`,
2057
- width: 'auto',
2058
- objectFit: 'contain'
2059
- }}
2060
- onError={(e) => {
2061
- console.error('Error loading image:', e);
2062
- e.currentTarget.style.display = 'none';
2063
- }}
2064
- />
2065
- {practice.imageAlt && (
2066
- <div className="text-xs text-gray-500 mt-2 text-center">Alt: {practice.imageAlt}</div>
2067
- )}
2068
- </div>
2069
- ) : (
2070
  <div className="inline-block rounded-lg shadow-md overflow-hidden">
2071
  <img
2072
  src={practice.imageUrl}
@@ -2080,38 +2062,50 @@ const WeeklyPractice: React.FC = () => {
2080
  onError={(e) => {
2081
  console.error('Error loading image:', e);
2082
  e.currentTarget.style.display = 'none';
2083
- // Show fallback if image fails to load
2084
- const fallback = e.currentTarget.parentElement;
2085
- if (fallback) {
2086
- fallback.innerHTML = `
2087
- <div class="inline-block rounded-lg shadow-md bg-green-500 text-white p-6 text-center">
2088
- <div class="text-3xl mb-2">📷</div>
2089
- <div class="font-semibold">Image Uploaded</div>
2090
- <div class="text-sm opacity-75">${practice.imageUrl}</div>
2091
- ${practice.imageAlt ? `<div class="text-xs opacity-50 mt-2">Alt: ${practice.imageAlt}</div>` : ''}
2092
- </div>
2093
- `;
2094
- }
2095
  }}
2096
  />
2097
  {practice.imageAlt && (
2098
  <div className="text-xs text-gray-500 mt-2 text-center">Alt: {practice.imageAlt}</div>
2099
  )}
2100
  </div>
2101
- )}
2102
  </div>
2103
- {/* Text with conditional display */}
2104
- {practice.content && practice.content !== 'Image-based practice' && (
2105
- <div className={`${
2106
- practice.imageAlignment === 'left' ? 'w-full md:w-1/2' :
2107
- practice.imageAlignment === 'right' ? 'w-full md:w-1/2' :
2108
- 'w-full'
2109
- }`}>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2110
  <p className="text-orange-800 leading-relaxed text-lg font-source-text whitespace-pre-wrap">{practice.content}</p>
2111
  </div>
2112
- )}
2113
- </div>
2114
  ) : (
 
2115
  <p className="text-orange-800 leading-relaxed text-lg font-source-text whitespace-pre-wrap">{practice.content}</p>
2116
  )}
2117
  </div>
@@ -2198,8 +2192,8 @@ const WeeklyPractice: React.FC = () => {
2198
  </div>
2199
  )}
2200
 
2201
- {/* Translation Input (only show if user is logged in and has no submission, and not for image-only content in week 3+) */}
2202
- {localStorage.getItem('token') && (!userSubmissions[practice._id] || userSubmissions[practice._id].length === 0) && !(practice.weekNumber >= 3 && practice.content === 'Image-based practice') && (
2203
  <div className="bg-gradient-to-r from-purple-50 to-violet-50 rounded-xl p-6 border border-purple-200">
2204
  <div className="flex items-center space-x-2 mb-4">
2205
  <div className="bg-purple-100 rounded-full p-1">
 
2030
  </div>
2031
  ) : (
2032
  <div>
2033
+ {practice.imageUrl ? (
2034
+ // Check if this is an image-only practice (created via "Add Image" function)
2035
+ practice.content === 'Image-based practice' ? (
2036
+ // Image-only layout with dynamic sizing and alignment
2037
+ <div className={`flex flex-col md:flex-row gap-6 items-start ${
2038
+ practice.imageAlignment === 'left' ? 'md:flex-row' :
2039
+ practice.imageAlignment === 'right' ? 'md:flex-row-reverse' :
2040
+ 'md:flex-col'
 
 
 
 
 
 
 
2041
  }`}>
2042
+ {/* Image section */}
2043
+ <div className={`${
2044
+ practice.imageAlignment === 'left' ? 'w-full md:w-1/2' :
2045
+ practice.imageAlignment === 'right' ? 'w-full md:w-1/2' :
2046
+ 'w-full'
2047
+ } flex ${
2048
+ practice.imageAlignment === 'left' ? 'justify-start' :
2049
+ practice.imageAlignment === 'right' ? 'justify-end' :
2050
+ 'justify-center'
2051
+ }`}>
 
 
 
 
 
 
 
 
 
 
 
2052
  <div className="inline-block rounded-lg shadow-md overflow-hidden">
2053
  <img
2054
  src={practice.imageUrl}
 
2062
  onError={(e) => {
2063
  console.error('Error loading image:', e);
2064
  e.currentTarget.style.display = 'none';
 
 
 
 
 
 
 
 
 
 
 
 
2065
  }}
2066
  />
2067
  {practice.imageAlt && (
2068
  <div className="text-xs text-gray-500 mt-2 text-center">Alt: {practice.imageAlt}</div>
2069
  )}
2070
  </div>
2071
+ </div>
2072
  </div>
2073
+ ) : (
2074
+ // Regular practice layout (original side-by-side for ALL weeks)
2075
+ <div className="flex flex-col md:flex-row gap-6 items-start">
2076
+ {/* Image on the left - 50% width */}
2077
+ <div className="w-full md:w-1/2 flex justify-center">
2078
+ {practice.imageUrl.startsWith('data:') ? (
2079
+ // Show actual image if it's a data URL
2080
+ <div className="inline-block rounded-lg shadow-md overflow-hidden">
2081
+ <img
2082
+ src={practice.imageUrl}
2083
+ alt={practice.imageAlt || 'Uploaded image'}
2084
+ className="w-full h-auto"
2085
+ style={{ height: '200px', width: 'auto', objectFit: 'contain' }} // Fixed height for consistency
2086
+ onError={(e) => {
2087
+ console.error('Error loading image:', e);
2088
+ e.currentTarget.style.display = 'none';
2089
+ }}
2090
+ />
2091
+ </div>
2092
+ ) : (
2093
+ // Show placeholder if it's not a data URL
2094
+ <div className="inline-block rounded-lg shadow-md bg-green-500 text-white p-6 text-center">
2095
+ <div className="text-3xl mb-2">📷</div>
2096
+ <div className="font-semibold">Image Uploaded</div>
2097
+ <div className="text-sm opacity-75">{practice.imageUrl}</div>
2098
+ </div>
2099
+ )}
2100
+ </div>
2101
+ {/* Text on the right - 50% width */}
2102
+ <div className="w-full md:w-1/2">
2103
  <p className="text-orange-800 leading-relaxed text-lg font-source-text whitespace-pre-wrap">{practice.content}</p>
2104
  </div>
2105
+ </div>
2106
+ )
2107
  ) : (
2108
+ // Text only when no image
2109
  <p className="text-orange-800 leading-relaxed text-lg font-source-text whitespace-pre-wrap">{practice.content}</p>
2110
  )}
2111
  </div>
 
2192
  </div>
2193
  )}
2194
 
2195
+ {/* Translation Input (only show if user is logged in and has no submission, but hide for image-only content) */}
2196
+ {localStorage.getItem('token') && (!userSubmissions[practice._id] || userSubmissions[practice._id].length === 0) && practice.content !== 'Image-based practice' && (
2197
  <div className="bg-gradient-to-r from-purple-50 to-violet-50 rounded-xl p-6 border border-purple-200">
2198
  <div className="flex items-center space-x-2 mb-4">
2199
  <div className="bg-purple-100 rounded-full p-1">