linguabot commited on
Commit
158a0ac
·
verified ·
1 Parent(s): 9e08dc7

Upload folder using huggingface_hub

Browse files
client/src/components/Layout.tsx CHANGED
@@ -174,8 +174,8 @@ const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
174
  navigation = navigation.filter(item => item.name !== 'Slides');
175
  }
176
 
177
- // Add Manage link for admin users (hide in student view, per toggle)
178
- if (user?.role === 'admin' && effectiveRole !== 'student') {
179
  navigation.push({ name: 'Manage', href: '/manage', icon: Cog6ToothIcon });
180
  }
181
 
@@ -202,17 +202,7 @@ const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
202
  <img src="/favicon-512x512.png" alt="logo" className="h-8 w-8 mr-2" />
203
  TransHub
204
  </Link>
205
- <div>
206
- {user?.role === 'admin' && effectiveRole === 'student' && (
207
- <Link
208
- to="/manage"
209
- className="inline-flex items-center px-3 py-1.5 rounded-md text-sm font-medium text-ui-text bg-white/60 hover:bg-white/80 ring-1 ring-inset ring-ui-border"
210
- title="Open Manage while in Student view"
211
- >
212
- Manage
213
- </Link>
214
- )}
215
- </div>
216
  </div>
217
  </header>
218
 
 
174
  navigation = navigation.filter(item => item.name !== 'Slides');
175
  }
176
 
177
+ // Add Manage link for admin users (always keep in nav)
178
+ if (user?.role === 'admin') {
179
  navigation.push({ name: 'Manage', href: '/manage', icon: Cog6ToothIcon });
180
  }
181
 
 
202
  <img src="/favicon-512x512.png" alt="logo" className="h-8 w-8 mr-2" />
203
  TransHub
204
  </Link>
205
+ <div />
 
 
 
 
 
 
 
 
 
 
206
  </div>
207
  </header>
208
 
client/src/pages/Dashboard.tsx CHANGED
@@ -40,6 +40,8 @@ const Dashboard: React.FC = () => {
40
 
41
  const getRoleDisplay = () => {
42
  if (!user) return '';
 
 
43
  return user.role === 'admin' ? 'Admin' : 'Student';
44
  };
45
 
@@ -211,8 +213,8 @@ const Dashboard: React.FC = () => {
211
  </div>
212
  </div>
213
 
214
- {/* Admin Panel (only for admin users) */}
215
- {user.role === 'admin' && (
216
  <div className="mb-8">
217
  <h2 className="text-lg font-medium text-gray-900 mb-4">Admin Panel</h2>
218
  <div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
 
40
 
41
  const getRoleDisplay = () => {
42
  if (!user) return '';
43
+ const viewMode = (localStorage.getItem('viewMode') || 'auto');
44
+ if (viewMode === 'student' && user.role === 'admin') return 'Student (view)';
45
  return user.role === 'admin' ? 'Admin' : 'Student';
46
  };
47
 
 
213
  </div>
214
  </div>
215
 
216
+ {/* Admin Panel (only for admin users; hidden in Student view) */}
217
+ {user.role === 'admin' && (localStorage.getItem('viewMode')||'auto') !== 'student' && (
218
  <div className="mb-8">
219
  <h2 className="text-lg font-medium text-gray-900 mb-4">Admin Panel</h2>
220
  <div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
client/src/pages/Feedback.tsx CHANGED
@@ -10,7 +10,12 @@ const Feedback: React.FC = () => {
10
 
11
  useEffect(() => {
12
  const u = localStorage.getItem('user');
13
- try { const parsed = u ? JSON.parse(u) : null; setIsAdmin(parsed?.role === 'admin'); } catch {}
 
 
 
 
 
14
  }, []);
15
 
16
  const send = async () => {
 
10
 
11
  useEffect(() => {
12
  const u = localStorage.getItem('user');
13
+ try {
14
+ const parsed = u ? JSON.parse(u) : null;
15
+ const viewMode = (localStorage.getItem('viewMode') || 'auto');
16
+ const admin = parsed?.role === 'admin';
17
+ setIsAdmin(viewMode === 'student' ? false : admin);
18
+ } catch {}
19
  }, []);
20
 
21
  const send = async () => {
client/src/pages/Slides.tsx CHANGED
@@ -31,7 +31,12 @@ const Slides: React.FC = () => {
31
  let aborted = false;
32
  (async () => {
33
  const u = localStorage.getItem('user');
34
- try { const parsed = u ? JSON.parse(u) : null; setIsAdmin(parsed?.role === 'admin'); } catch {}
 
 
 
 
 
35
  try {
36
  setLoading(true); setError('');
37
  const resp = await api.get('/api/slides', { headers: { 'Cache-Control': 'no-cache' } });
 
31
  let aborted = false;
32
  (async () => {
33
  const u = localStorage.getItem('user');
34
+ try {
35
+ const parsed = u ? JSON.parse(u) : null;
36
+ const viewMode = (localStorage.getItem('viewMode') || 'auto');
37
+ const admin = parsed?.role === 'admin';
38
+ setIsAdmin(viewMode === 'student' ? false : admin);
39
+ } catch {}
40
  try {
41
  setLoading(true); setError('');
42
  const resp = await api.get('/api/slides', { headers: { 'Cache-Control': 'no-cache' } });
client/src/pages/Toolkit.tsx CHANGED
@@ -110,8 +110,9 @@ const Toolkit: React.FC = () => {
110
  try {
111
  const u = localStorage.getItem('user');
112
  const role = u ? (JSON.parse(u)?.role || 'visitor') : 'visitor';
 
113
  setIsVisitor(role === 'visitor');
114
- setIsAdmin(role === 'admin');
115
  } catch {
116
  setIsVisitor(true);
117
  setIsAdmin(false);
 
110
  try {
111
  const u = localStorage.getItem('user');
112
  const role = u ? (JSON.parse(u)?.role || 'visitor') : 'visitor';
113
+ const viewMode = (localStorage.getItem('viewMode') || 'auto');
114
  setIsVisitor(role === 'visitor');
115
+ setIsAdmin(viewMode === 'student' ? false : role === 'admin');
116
  } catch {
117
  setIsVisitor(true);
118
  setIsAdmin(false);
client/src/pages/TutorialTasks.tsx CHANGED
@@ -67,7 +67,9 @@ const TutorialTasks: React.FC = () => {
67
  // Move a task up or down by normalizing positions for the current visible list (weeks 4–6 only)
68
  const moveTask = async (taskId: string, direction: 'up' | 'down') => {
69
  try {
70
- const isAdmin = JSON.parse(localStorage.getItem('user') || '{}').role === 'admin';
 
 
71
  if (!isAdmin || selectedWeek < 4) return;
72
  // Build ordered list for the current week from what is rendered
73
  const current = tutorialTasks.filter(t => t.weekNumber === selectedWeek);
@@ -124,7 +126,9 @@ const TutorialTasks: React.FC = () => {
124
  const [urlInput, setUrlInput] = useState<string>('');
125
  const [errorMsg, setErrorMsg] = useState<string>('');
126
  const [copiedLink, setCopiedLink] = useState<string>('');
127
- const isAdmin = (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin');
 
 
128
 
129
  const CopySquaresIcon: React.FC<{ className?: string }> = ({ className }) => (
130
  <svg className={className || 'h-4 w-4'} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg">
 
67
  // Move a task up or down by normalizing positions for the current visible list (weeks 4–6 only)
68
  const moveTask = async (taskId: string, direction: 'up' | 'down') => {
69
  try {
70
+ const viewMode = (localStorage.getItem('viewMode') || 'auto');
71
+ const actualRole = (JSON.parse(localStorage.getItem('user') || '{}').role);
72
+ const isAdmin = viewMode === 'student' ? false : actualRole === 'admin';
73
  if (!isAdmin || selectedWeek < 4) return;
74
  // Build ordered list for the current week from what is rendered
75
  const current = tutorialTasks.filter(t => t.weekNumber === selectedWeek);
 
126
  const [urlInput, setUrlInput] = useState<string>('');
127
  const [errorMsg, setErrorMsg] = useState<string>('');
128
  const [copiedLink, setCopiedLink] = useState<string>('');
129
+ const viewMode = (localStorage.getItem('viewMode') || 'auto');
130
+ const actualRole = (JSON.parse(localStorage.getItem('user') || '{}').role);
131
+ const isAdmin = viewMode === 'student' ? false : actualRole === 'admin';
132
 
133
  const CopySquaresIcon: React.FC<{ className?: string }> = ({ className }) => (
134
  <svg className={className || 'h-4 w-4'} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg">
client/src/pages/WeeklyPractice.tsx CHANGED
@@ -1474,7 +1474,7 @@ const WeeklyPractice: React.FC = () => {
1474
  </div>
1475
  <h3 className="text-ui-text font-semibold text-xl">Translation Brief</h3>
1476
  </div>
1477
- {JSON.parse(localStorage.getItem('user') || '{}').role === 'admin' && (
1478
  <div className="flex items-center space-x-2">
1479
  {editingBrief[selectedWeek] ? (
1480
  <>
@@ -1537,7 +1537,7 @@ const WeeklyPractice: React.FC = () => {
1537
  </div>
1538
  ) : (
1539
  // Show add brief button when no brief exists
1540
- JSON.parse(localStorage.getItem('user') || '{}').role === 'admin' && (
1541
  <div className="bg-ui-panel rounded-xl p-8 mb-8 border border-ui-border border-dashed">
1542
  <div className="flex items-center justify-between mb-4">
1543
  <div className="flex items-center space-x-2">
@@ -1594,7 +1594,7 @@ const WeeklyPractice: React.FC = () => {
1594
  )}
1595
 
1596
  {/* Week Files (Week 6 uploads) */}
1597
- {(weekFiles.source.length > 0 || weekFiles.translation.length > 0 || (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin')) && (
1598
  <div className="bg-white rounded-xl shadow p-6 mb-8">
1599
  <h3 className="text-lg font-semibold text-gray-900 mb-4">Week {selectedWeek} Files</h3>
1600
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6 items-start content-start">
@@ -1624,7 +1624,7 @@ const WeeklyPractice: React.FC = () => {
1624
  <div className="min-w-0 truncate font-medium" title={f.fileName}>{f.fileName}</div>
1625
  <div className="flex items-center space-x-3 flex-shrink-0">
1626
  <button className="text-pink-600 hover:underline" onClick={() => downloadWeekFile(f._id, f.fileName)}>Download</button>
1627
- {JSON.parse(localStorage.getItem('user') || '{}').role === 'admin' && (
1628
  <button
1629
  className="text-red-600 hover:underline"
1630
  onClick={async () => {
@@ -1675,7 +1675,7 @@ const WeeklyPractice: React.FC = () => {
1675
  <div className="min-w-0 truncate font-medium" title={f.fileName}>{f.fileName}</div>
1676
  <div className="flex items-center space-x-3 flex-shrink-0">
1677
  <button className="text-pink-600 hover:underline" onClick={() => downloadWeekFile(f._id, f.fileName)}>Download</button>
1678
- {JSON.parse(localStorage.getItem('user') || '{}').role === 'admin' && (
1679
  <button
1680
  className="text-red-600 hover:underline"
1681
  onClick={async () => {
@@ -1761,7 +1761,7 @@ const WeeklyPractice: React.FC = () => {
1761
  )}
1762
 
1763
  {/* Admin Time Code Editor */}
1764
- {editingSegment && JSON.parse(localStorage.getItem('user') || '{}').role === 'admin' && (
1765
  <div className="bg-indigo-50 border border-indigo-200 rounded-lg p-4 mb-4">
1766
  <h4 className="text-sm font-medium text-indigo-800 mb-2">Edit Time Codes for Segment {editingSegment}</h4>
1767
  <div className="grid grid-cols-2 gap-2">
@@ -1815,7 +1815,7 @@ const WeeklyPractice: React.FC = () => {
1815
  <p className="text-gray-800">
1816
  Segment {currentSegment}: {subtitleSegments[currentSegment - 1]?.startTime} – {subtitleSegments[currentSegment - 1]?.endTime} ({subtitleSegments[currentSegment - 1]?.duration})
1817
  </p>
1818
- {JSON.parse(localStorage.getItem('user') || '{}').role === 'admin' && (
1819
  <button
1820
  onClick={() => handleEditTimeCode(currentSegment)}
1821
  className="bg-indigo-600 hover:bg-indigo-700 text-white px-2 py-1 rounded text-xs flex items-center space-x-1"
@@ -1936,7 +1936,7 @@ const WeeklyPractice: React.FC = () => {
1936
  <span className="text-xs text-gray-500">
1937
  {new Date(submission.submissionDate).toLocaleString()}
1938
  </span>
1939
- {JSON.parse(localStorage.getItem('user') || '{}').role === 'admin' && (
1940
  <button
1941
  onClick={() => handleDeleteSubtitleSubmission(submission._id)}
1942
  className="text-red-500 hover:text-red-700 text-xs"
@@ -2264,7 +2264,7 @@ const WeeklyPractice: React.FC = () => {
2264
  <h3 className="text-lg font-semibold text-gray-900">Source Text #{weeklyPractice.indexOf(practice) + 1}</h3>
2265
  </div>
2266
  </div>
2267
- {JSON.parse(localStorage.getItem('user') || '{}').role === 'admin' && (
2268
  <div className="flex items-center space-x-2">
2269
  {editingPractice === practice._id ? (
2270
  <>
 
1474
  </div>
1475
  <h3 className="text-ui-text font-semibold text-xl">Translation Brief</h3>
1476
  </div>
1477
+ {(localStorage.getItem('viewMode')||'auto') === 'student' ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin') && (
1478
  <div className="flex items-center space-x-2">
1479
  {editingBrief[selectedWeek] ? (
1480
  <>
 
1537
  </div>
1538
  ) : (
1539
  // Show add brief button when no brief exists
1540
+ (localStorage.getItem('viewMode')||'auto') === 'student' ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin') && (
1541
  <div className="bg-ui-panel rounded-xl p-8 mb-8 border border-ui-border border-dashed">
1542
  <div className="flex items-center justify-between mb-4">
1543
  <div className="flex items-center space-x-2">
 
1594
  )}
1595
 
1596
  {/* Week Files (Week 6 uploads) */}
1597
+ {(weekFiles.source.length > 0 || weekFiles.translation.length > 0 || (((localStorage.getItem('viewMode')||'auto') === 'student') ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin'))) && (
1598
  <div className="bg-white rounded-xl shadow p-6 mb-8">
1599
  <h3 className="text-lg font-semibold text-gray-900 mb-4">Week {selectedWeek} Files</h3>
1600
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6 items-start content-start">
 
1624
  <div className="min-w-0 truncate font-medium" title={f.fileName}>{f.fileName}</div>
1625
  <div className="flex items-center space-x-3 flex-shrink-0">
1626
  <button className="text-pink-600 hover:underline" onClick={() => downloadWeekFile(f._id, f.fileName)}>Download</button>
1627
+ {((localStorage.getItem('viewMode')||'auto') === 'student') ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin') && (
1628
  <button
1629
  className="text-red-600 hover:underline"
1630
  onClick={async () => {
 
1675
  <div className="min-w-0 truncate font-medium" title={f.fileName}>{f.fileName}</div>
1676
  <div className="flex items-center space-x-3 flex-shrink-0">
1677
  <button className="text-pink-600 hover:underline" onClick={() => downloadWeekFile(f._id, f.fileName)}>Download</button>
1678
+ {((localStorage.getItem('viewMode')||'auto') === 'student') ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin') && (
1679
  <button
1680
  className="text-red-600 hover:underline"
1681
  onClick={async () => {
 
1761
  )}
1762
 
1763
  {/* Admin Time Code Editor */}
1764
+ {editingSegment && (((localStorage.getItem('viewMode')||'auto') === 'student') ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin')) && (
1765
  <div className="bg-indigo-50 border border-indigo-200 rounded-lg p-4 mb-4">
1766
  <h4 className="text-sm font-medium text-indigo-800 mb-2">Edit Time Codes for Segment {editingSegment}</h4>
1767
  <div className="grid grid-cols-2 gap-2">
 
1815
  <p className="text-gray-800">
1816
  Segment {currentSegment}: {subtitleSegments[currentSegment - 1]?.startTime} – {subtitleSegments[currentSegment - 1]?.endTime} ({subtitleSegments[currentSegment - 1]?.duration})
1817
  </p>
1818
+ {((localStorage.getItem('viewMode')||'auto') === 'student') ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin') && (
1819
  <button
1820
  onClick={() => handleEditTimeCode(currentSegment)}
1821
  className="bg-indigo-600 hover:bg-indigo-700 text-white px-2 py-1 rounded text-xs flex items-center space-x-1"
 
1936
  <span className="text-xs text-gray-500">
1937
  {new Date(submission.submissionDate).toLocaleString()}
1938
  </span>
1939
+ {((localStorage.getItem('viewMode')||'auto') === 'student') ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin') && (
1940
  <button
1941
  onClick={() => handleDeleteSubtitleSubmission(submission._id)}
1942
  className="text-red-500 hover:text-red-700 text-xs"
 
2264
  <h3 className="text-lg font-semibold text-gray-900">Source Text #{weeklyPractice.indexOf(practice) + 1}</h3>
2265
  </div>
2266
  </div>
2267
+ {((localStorage.getItem('viewMode')||'auto') === 'student') ? false : (JSON.parse(localStorage.getItem('user') || '{}').role === 'admin') && (
2268
  <div className="flex items-center space-x-2">
2269
  {editingPractice === practice._id ? (
2270
  <>