import { GetActiveSprint, RemoveActiveSprint } from '@/lib/asyncStorage'; import { formatDateTime } from '@/lib/date'; import { CheckAssignmentCompletion } from '@/lib/progress'; import { getSubjectColorSet, type SubjectColor } from '@/lib/subjectColors'; import { supabase } from '@/lib/supabase'; import type { Task } from '@/lib/types'; import { Session } from '@supabase/supabase-js'; import { router, Stack, useFocusEffect, useLocalSearchParams } from 'expo-router'; import { useCallback, useEffect, useState } from 'react'; import { Alert, Pressable, Text, View } from 'react-native'; function formatTrackedTime(totalSeconds: number) { if (totalSeconds <= 0) { return '0m'; } const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); if (hours === 0) { return `${minutes}m`; } if (minutes === 0) { return `${hours}h`; } return `${hours}h ${minutes}m`; } export default function ViewDetailsTask() { const { tId } = useLocalSearchParams<{ tId: string }>(); const [task, SetTask] = useState(null); const [session, SetSession] = useState(null); const [contextMeta, setContextMeta] = useState({ subjectTitle: 'No Subject', assignmentTitle: 'No Assignment', subjectColor: 'slate' as SubjectColor, }); useEffect(() => { supabase.auth.getSession().then(({ data }) => SetSession(data.session ?? null)); const { data: sub } = supabase.auth.onAuthStateChange((_event, newSession) => { SetSession(newSession); }); return () => sub.subscription.unsubscribe(); }, []); const GetTask = async (taskId: string) => { const { data, error } = await supabase .from('tasks') .select('*') .eq('tId', taskId) .single(); if (error || !data) { Alert.alert('Task could not be fetched, please try again'); return; } SetTask(data); if (data.aId) { const { data: assignmentData, error: assignmentError } = await supabase .from('assignments') .select('title, sId') .eq('aId', data.aId) .single(); if (assignmentError || !assignmentData) { setContextMeta({ subjectTitle: 'Unknown Subject', assignmentTitle: 'Unknown Assignment', subjectColor: 'slate', }); return; } if (assignmentData.sId) { const { data: subjectData, error: subjectError } = await supabase .from('subjects') .select('title, color') .eq('sId', assignmentData.sId) .single(); if (subjectError || !subjectData) { setContextMeta({ subjectTitle: 'Unknown Subject', assignmentTitle: assignmentData.title ?? 'Unknown Assignment', subjectColor: 'slate', }); return; } setContextMeta({ subjectTitle: subjectData.title ?? 'Unknown Subject', assignmentTitle: assignmentData.title ?? 'Unknown Assignment', subjectColor: (subjectData.color as SubjectColor | undefined) ?? 'slate', }); } } }; useFocusEffect( useCallback(() => { if (session && tId) { GetTask(tId); } }, [session, tId]) ); const handleSprintStart = async () => { const activeSprint = await GetActiveSprint(); if (!activeSprint) { router.push({ pathname: '/task/timer', params: { tId: task?.tId}, }); return; } const secondsLeft = Math.ceil((activeSprint.endTime - Date.now()) / 1000) if (secondsLeft <= 0) { await RemoveActiveSprint(); router.push({ pathname: '/task/timer', params: { tId: task?.tId} }); return; } if (activeSprint!.taskId === task?.tId) { router.push({ pathname: '/task/timer', params: { tId: activeSprint!.taskId}}); return; } Alert.alert( 'Active sprint in progress', 'Starting a new sprint will end the current active sprint', [ { text: 'Cancel', style: 'cancel', }, { text: 'Start new sprint', style: 'destructive', onPress: async () => { await RemoveActiveSprint(); router.push({ pathname: '/task/timer', params: { tId: task?.tId }, }); }, }, ] ); } const DeleteTask = async (taskId: string) => { Alert.alert( 'Delete Task', 'Are you sure you want to delete this task?', [ { text: 'Cancel', style: 'cancel', }, { text: 'Delete', style: 'destructive', onPress: async () => { const { error } = await supabase .from('tasks') .delete() .eq('tId', taskId); if (error) { Alert.alert('Task could not be deleted, please try again'); return; } const aId = task?.aId; if (aId) { try { await CheckAssignmentCompletion(aId); } catch { Alert.alert('Failed to update assignment completion state'); } } Alert.alert('Task deleted successfully!'); router.back(); }, }, ] ); }; const colorSet = getSubjectColorSet(contextMeta.subjectColor); if (!task) { return ( ( await supabase.auth.signOut()} > Logout ), }} /> Task not found The task could not be loaded. router.back()} > Go back ); } const isOwner = session?.user.id === task.uId; return ( ( await supabase.auth.signOut()} > Logout ), }} /> {task.isCompleted && ( )} {task.title} {task.description ? ( {task.description} ) : ( No description added. )} {contextMeta.subjectTitle} {contextMeta.assignmentTitle} Last changed: {formatDateTime(task.lastChanged)} Time spent: {formatTrackedTime(task.totalTimeInSeconds ?? 0)} {isOwner && ( router.push({ pathname: '/task/upsertTask', params: { tId: task.tId }, }) } > Edit handleSprintStart() }> Start Sprint DeleteTask(task.tId)} > Delete )} ); }