import { Ionicons } from '@expo/vector-icons'; import { useFocusEffect, useRouter } from 'expo-router'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { ActivityIndicator, StyleSheet, View } from 'react-native'; import { AddClassModal } from '@/components/add-class-modal'; import { AppHeader, AppText, Button, Card, EmptyState, IconButton, InlineBanner, RecessCard, ScheduleEventCard, Screen, WeekStrip, colors, spacing, type WeekDay, } from '@/components/ui'; import { addDays, dateKey, formatDayHeading, mondayOfWeek } from '@/lib/date'; import { subjectToneFor } from '@/lib/design'; import { collegeApi } from '@/lib/api'; type TimetableClass = Awaited>['classes'][number]; export default function TimetableScreen() { const router = useRouter(); const [activeDate, setActiveDate] = useState(() => { const today = new Date(); return today.getDay() === 0 || today.getDay() === 6 ? mondayOfWeek(today) : today; }); const [schedule, setSchedule] = useState([]); const [weekendSchedule, setWeekendSchedule] = useState(false); const [recess, setRecess] = useState<{ enabled: boolean; start: string; end: string }>({ enabled: false, start: '13:00', end: '14:00' }); const [loading, setLoading] = useState(true); const [loadError, setLoadError] = useState(''); const [addClassOpen, setAddClassOpen] = useState(false); const [refresh, setRefresh] = useState(0); const selectedDateKey = dateKey(activeDate); const todayKey = dateKey(new Date()); const weekStart = useMemo(() => mondayOfWeek(activeDate), [activeDate]); const weekDays: WeekDay[] = useMemo(() => Array.from({ length: 7 }, (_, index) => addDays(weekStart, index)) .filter((date) => weekendSchedule || (date.getDay() !== 0 && date.getDay() !== 6)) .map((date) => ({ date })), [weekStart, weekendSchedule]); useFocusEffect(useCallback(() => { let active = true; collegeApi.profile().then((profile) => { if (!active) return; setWeekendSchedule(Boolean(profile.weekendSchedule)); setRecess({ enabled: Boolean(profile.recessEnabled), start: profile.recessStart, end: profile.recessEnd }); }).catch(() => undefined); return () => { active = false; }; }, [])); const load = useCallback(() => { setLoading(true); setLoadError(''); collegeApi.timetable(selectedDateKey) .then(({ classes }) => setSchedule(classes)) .catch((error: Error) => { setSchedule([]); setLoadError(error.message); }) .finally(() => setLoading(false)); }, [selectedDateKey]); useEffect(() => { load(); }, [load, refresh]); const moveWeek = (amount: number) => setActiveDate(addDays(activeDate, amount * 7)); const weekday = new Intl.DateTimeFormat(undefined, { weekday: 'long' }).format(activeDate); const showRecess = recess.enabled && recess.start < recess.end; const timelineItems = [ ...schedule.map((item) => ({ type: 'class' as const, start: item.startTime, end: item.endTime, item })), ...(showRecess ? [{ type: 'recess' as const, start: recess.start, end: recess.end }] : []), ].sort((left, right) => left.start.localeCompare(right.start) || (left.type === 'recess' ? -1 : 1)); return moveWeek(-1)} /> Week of {new Intl.DateTimeFormat(undefined, { month: 'short', day: 'numeric' }).format(weekStart)} {new Intl.DateTimeFormat(undefined, { year: 'numeric' }).format(activeDate)} {todayKey !== selectedDateKey ?