SMKBK1 commited on
Commit
eaa6dec
·
verified ·
1 Parent(s): 3df7bf7

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +84 -24
index.html CHANGED
@@ -151,6 +151,11 @@
151
  const [teacherFilter, setTeacherFilter] = useState('all');
152
  const [searchQuery, setSearchQuery] = useState('');
153
  const [isSaving, setIsSaving] = useState(false);
 
 
 
 
 
154
 
155
  const CLASSES = useMemo(() => {
156
  const sheetClasses = Object.keys(studentsData || {});
@@ -164,8 +169,10 @@
164
 
165
  const currentTimeSlots = getDynamicTimeSlots(selectedClass);
166
 
167
- const today = new Date();
168
- const dateId = `${today.getDate().toString().padStart(2, '0')}-${(today.getMonth() + 1).toString().padStart(2, '0')}-${today.getFullYear()}`;
 
 
169
 
170
  const selectedClassData = allClassLogs[selectedClass] || {};
171
  const teacherLogs = selectedClassData.teacherLogs || {};
@@ -219,11 +226,11 @@
219
  return () => clearInterval(interval);
220
  }, [fetchLogs]);
221
 
222
- const formattedDateStr = `${today.getDate().toString().padStart(2, '0')}/${(today.getMonth() + 1).toString().padStart(2, '0')}/${today.getFullYear()}`;
223
- const fallbackDateStr = `${today.getDate()}/${today.getMonth() + 1}/${today.getFullYear()}`;
224
 
225
  let todaysAttendance = attendanceData[formattedDateStr] || attendanceData[fallbackDateStr];
226
- if (!todaysAttendance && Object.keys(attendanceData).length > 0) {
227
  todaysAttendance = attendanceData[Object.keys(attendanceData)[Object.keys(attendanceData).length - 1]];
228
  }
229
 
@@ -264,23 +271,29 @@
264
  .sort((a, b) => b[1] - a[1])
265
  .slice(0, 3);
266
 
267
- const currentHour = today.getHours();
268
- const currentMin = today.getMinutes();
269
 
270
- const activeTimeSlotObj = getCurrentActiveSlot(selectedClass, currentHour, currentMin);
271
  const activeTimeSlotId = activeTimeSlotObj ? activeTimeSlotObj.id : null;
272
 
273
  const lastSlot = currentTimeSlots[currentTimeSlots.length - 1];
274
- const isAfterSchool = currentHour > lastSlot.endHour || (currentHour === lastSlot.endHour && currentMin >= lastSlot.endMin);
 
 
275
 
276
  const missedPeriods = currentTimeSlots.filter(slot => {
277
  if (slot.id === 'R') return false;
 
 
 
 
278
  const hasEnded = currentHour > slot.endHour || (currentHour === slot.endHour && currentMin >= slot.endMin);
279
  return hasEnded && !teacherLogs[slot.id];
280
  });
281
 
282
  const classesTeacherStatus = CLASSES.map(cls => {
283
- const activeSlot = getCurrentActiveSlot(cls, currentHour, currentMin);
284
  const clsLogs = allClassLogs[cls] || {};
285
  const clsTeacherLogs = clsLogs.teacherLogs || {};
286
 
@@ -348,7 +361,8 @@
348
  name: teacher.name,
349
  period: slotId,
350
  subject: teacher.subject,
351
- action: 'set'
 
352
  });
353
  setIsSaving(false);
354
  };
@@ -367,7 +381,7 @@
367
  const students = [...selectedStudents];
368
  const cls = selectedClass;
369
  const logId = Date.now();
370
- const timeOutStr = `${today.getHours().toString().padStart(2, '0')}:${today.getMinutes().toString().padStart(2, '0')}`;
371
 
372
  const newLog = {
373
  id: logId,
@@ -393,7 +407,8 @@
393
  action: 'exit',
394
  students: students,
395
  timeOut: timeOutStr,
396
- logId: logId
 
397
  });
398
  setIsSaving(false);
399
  };
@@ -417,7 +432,8 @@
417
  type: 'student',
418
  period: slotId,
419
  action: 'delete',
420
- logId: logId
 
421
  });
422
  } else if (toDelete.type === 'teacher') {
423
  const { slotId } = toDelete;
@@ -432,7 +448,8 @@
432
  className: selectedClass,
433
  type: 'teacher',
434
  period: slotId,
435
- action: 'delete'
 
436
  });
437
  }
438
  setIsSaving(false);
@@ -462,7 +479,8 @@
462
  name: prevLog.name,
463
  period: currentSlotId,
464
  subject: prevLog.subject,
465
- action: 'set'
 
466
  });
467
  setIsSaving(false);
468
  }
@@ -499,9 +517,39 @@
499
  </div>
500
 
501
  <div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-3 text-sm">
502
- <div className="bg-indigo-800/60 backdrop-blur-md px-3 py-2 rounded-lg border border-indigo-500/30 flex items-center gap-2 justify-center">
503
- <Calendar className="w-4 h-4 text-indigo-300" />
504
- <span>{today.toLocaleDateString('ms-MY', { weekday: 'long', day: 'numeric', month: 'short', year: 'numeric' })}</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  </div>
506
 
507
  {activeTab === 'class_view' && (
@@ -621,13 +669,25 @@
621
  <div className="flex flex-col md:flex-row md:items-center justify-between gap-3 border-b border-slate-100 pb-4">
622
  <div>
623
  <h2 className="text-lg font-bold text-slate-800 flex items-center gap-2">
624
- <Activity className="w-5 h-5 text-indigo-600" /> Status Guru Semasa (Real-Time)
625
  </h2>
626
  <p className="text-xs text-slate-500 mt-0.5">
627
- Memaparkan status guru mengajar di setiap kelas mengikut waktu jam sekarang (
628
- <span className="font-bold text-indigo-700">
629
- {today.toLocaleTimeString('ms-MY', { hour: '2-digit', minute: '2-digit' })}
630
- </span>)
 
 
 
 
 
 
 
 
 
 
 
 
631
  </p>
632
  </div>
633
 
 
151
  const [teacherFilter, setTeacherFilter] = useState('all');
152
  const [searchQuery, setSearchQuery] = useState('');
153
  const [isSaving, setIsSaving] = useState(false);
154
+ const [selectedDate, setSelectedDate] = useState(() => {
155
+ const d = new Date();
156
+ d.setHours(0, 0, 0, 0);
157
+ return d;
158
+ });
159
 
160
  const CLASSES = useMemo(() => {
161
  const sheetClasses = Object.keys(studentsData || {});
 
169
 
170
  const currentTimeSlots = getDynamicTimeSlots(selectedClass);
171
 
172
+ const now = new Date();
173
+ const isToday = selectedDate.toDateString() === now.toDateString();
174
+ const dateId = `${selectedDate.getDate().toString().padStart(2, '0')}-${(selectedDate.getMonth() + 1).toString().padStart(2, '0')}-${selectedDate.getFullYear()}`;
175
+ const selectedDateInputValue = `${selectedDate.getFullYear()}-${(selectedDate.getMonth() + 1).toString().padStart(2, '0')}-${selectedDate.getDate().toString().padStart(2, '0')}`;
176
 
177
  const selectedClassData = allClassLogs[selectedClass] || {};
178
  const teacherLogs = selectedClassData.teacherLogs || {};
 
226
  return () => clearInterval(interval);
227
  }, [fetchLogs]);
228
 
229
+ const formattedDateStr = `${selectedDate.getDate().toString().padStart(2, '0')}/${(selectedDate.getMonth() + 1).toString().padStart(2, '0')}/${selectedDate.getFullYear()}`;
230
+ const fallbackDateStr = `${selectedDate.getDate()}/${selectedDate.getMonth() + 1}/${selectedDate.getFullYear()}`;
231
 
232
  let todaysAttendance = attendanceData[formattedDateStr] || attendanceData[fallbackDateStr];
233
+ if (!todaysAttendance && isToday && Object.keys(attendanceData).length > 0) {
234
  todaysAttendance = attendanceData[Object.keys(attendanceData)[Object.keys(attendanceData).length - 1]];
235
  }
236
 
 
271
  .sort((a, b) => b[1] - a[1])
272
  .slice(0, 3);
273
 
274
+ const currentHour = now.getHours();
275
+ const currentMin = now.getMinutes();
276
 
277
+ const activeTimeSlotObj = isToday ? getCurrentActiveSlot(selectedClass, currentHour, currentMin) : null;
278
  const activeTimeSlotId = activeTimeSlotObj ? activeTimeSlotObj.id : null;
279
 
280
  const lastSlot = currentTimeSlots[currentTimeSlots.length - 1];
281
+ const isAfterSchool = isToday
282
+ ? (currentHour > lastSlot.endHour || (currentHour === lastSlot.endHour && currentMin >= lastSlot.endMin))
283
+ : (selectedDate < now);
284
 
285
  const missedPeriods = currentTimeSlots.filter(slot => {
286
  if (slot.id === 'R') return false;
287
+ if (!isToday) {
288
+ // For past/future dates: treat as missed if no teacher log
289
+ return !teacherLogs[slot.id];
290
+ }
291
  const hasEnded = currentHour > slot.endHour || (currentHour === slot.endHour && currentMin >= slot.endMin);
292
  return hasEnded && !teacherLogs[slot.id];
293
  });
294
 
295
  const classesTeacherStatus = CLASSES.map(cls => {
296
+ const activeSlot = isToday ? getCurrentActiveSlot(cls, currentHour, currentMin) : null;
297
  const clsLogs = allClassLogs[cls] || {};
298
  const clsTeacherLogs = clsLogs.teacherLogs || {};
299
 
 
361
  name: teacher.name,
362
  period: slotId,
363
  subject: teacher.subject,
364
+ action: 'set',
365
+ date: dateId
366
  });
367
  setIsSaving(false);
368
  };
 
381
  const students = [...selectedStudents];
382
  const cls = selectedClass;
383
  const logId = Date.now();
384
+ const timeOutStr = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
385
 
386
  const newLog = {
387
  id: logId,
 
407
  action: 'exit',
408
  students: students,
409
  timeOut: timeOutStr,
410
+ logId: logId,
411
+ date: dateId
412
  });
413
  setIsSaving(false);
414
  };
 
432
  type: 'student',
433
  period: slotId,
434
  action: 'delete',
435
+ logId: logId,
436
+ date: dateId
437
  });
438
  } else if (toDelete.type === 'teacher') {
439
  const { slotId } = toDelete;
 
448
  className: selectedClass,
449
  type: 'teacher',
450
  period: slotId,
451
+ action: 'delete',
452
+ date: dateId
453
  });
454
  }
455
  setIsSaving(false);
 
479
  name: prevLog.name,
480
  period: currentSlotId,
481
  subject: prevLog.subject,
482
+ action: 'set',
483
+ date: dateId
484
  });
485
  setIsSaving(false);
486
  }
 
517
  </div>
518
 
519
  <div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-3 text-sm">
520
+ <div className="bg-indigo-800/60 backdrop-blur-md px-3 py-2 rounded-lg border border-indigo-500/30 flex items-center gap-2 justify-center relative">
521
+ <Calendar className="w-4 h-4 text-indigo-300 flex-shrink-0" />
522
+ <label className="cursor-pointer flex items-center gap-2">
523
+ <span className="whitespace-nowrap">
524
+ {selectedDate.toLocaleDateString('ms-MY', { weekday: 'long', day: 'numeric', month: 'short', year: 'numeric' })}
525
+ </span>
526
+ <input
527
+ type="date"
528
+ value={selectedDateInputValue}
529
+ onChange={(e) => {
530
+ if (!e.target.value) return;
531
+ const [y, m, d] = e.target.value.split('-').map(Number);
532
+ const newDate = new Date(y, m - 1, d);
533
+ newDate.setHours(0, 0, 0, 0);
534
+ setSelectedDate(newDate);
535
+ }}
536
+ className="absolute inset-0 opacity-0 cursor-pointer w-full h-full"
537
+ title="Pilih tarikh"
538
+ />
539
+ </label>
540
+ {!isToday && (
541
+ <button
542
+ onClick={() => {
543
+ const d = new Date();
544
+ d.setHours(0, 0, 0, 0);
545
+ setSelectedDate(d);
546
+ }}
547
+ className="ml-1 text-[10px] font-bold bg-white/20 hover:bg-white/30 px-1.5 py-0.5 rounded text-white whitespace-nowrap"
548
+ title="Kembali ke hari ini"
549
+ >
550
+ Hari Ini
551
+ </button>
552
+ )}
553
  </div>
554
 
555
  {activeTab === 'class_view' && (
 
669
  <div className="flex flex-col md:flex-row md:items-center justify-between gap-3 border-b border-slate-100 pb-4">
670
  <div>
671
  <h2 className="text-lg font-bold text-slate-800 flex items-center gap-2">
672
+ <Activity className="w-5 h-5 text-indigo-600" /> Status Guru {isToday ? 'Semasa (Real-Time)' : 'Mengikut Tarikh Dipilih'}
673
  </h2>
674
  <p className="text-xs text-slate-500 mt-0.5">
675
+ {isToday ? (
676
+ <>
677
+ Memaparkan status guru mengajar di setiap kelas mengikut waktu jam sekarang (
678
+ <span className="font-bold text-indigo-700">
679
+ {now.toLocaleTimeString('ms-MY', { hour: '2-digit', minute: '2-digit' })}
680
+ </span>)
681
+ </>
682
+ ) : (
683
+ <>
684
+ Memaparkan rekod guru untuk tarikh{' '}
685
+ <span className="font-bold text-indigo-700">
686
+ {selectedDate.toLocaleDateString('ms-MY', { weekday: 'long', day: 'numeric', month: 'short', year: 'numeric' })}
687
+ </span>
688
+ {' '}(bukan hari ini)
689
+ </>
690
+ )}
691
  </p>
692
  </div>
693