diff --git a/app/assignment/_layout.tsx b/app/assignment/_layout.tsx index 87149d5..7fb96ef 100644 --- a/app/assignment/_layout.tsx +++ b/app/assignment/_layout.tsx @@ -3,9 +3,7 @@ import { Stack } from "expo-router"; export default function AssignmentLayout() { return ( - - - + ); diff --git a/app/assignment/assignments.tsx b/app/assignment/assignments.tsx deleted file mode 100644 index 8fb9f77..0000000 --- a/app/assignment/assignments.tsx +++ /dev/null @@ -1,336 +0,0 @@ -import { defaultStyles } from '@/constants/defaultStyles'; -import { CheckSubjectCompletion } from '@/lib/progress'; -import { supabase } from '@/lib/supabase'; -import type { Assignment, Task } from '@/lib/types'; -import { Ionicons } from '@expo/vector-icons'; -import { Session } from '@supabase/supabase-js'; -import { router, Stack, useFocusEffect } from 'expo-router'; -import { useCallback, useEffect, useState } from 'react'; -import { - Alert, - Pressable, - SectionList, - Text, - View, -} from 'react-native'; - -export default function Assignments() { - const [assignments, SetAssignments] = useState([]); - const [tasksByAssignment, SetTasksByAssignment] = useState>({}); - const [session, SetSession] = useState(null); - - const assignmentSections = [ - { - title: 'Upcoming Assignments', - data: assignments.filter((assignment) => !assignment.isCompleted), - emptyMessage: 'No upcoming assignments', - }, - { - title: 'Completed Assignments', - data: assignments.filter((assignment) => assignment.isCompleted), - emptyMessage: 'No completed assignments', - }, - ]; - - 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 GetAssignments = async () => { - const { data: assignmentsData, error: assignmentsError } = await supabase - .from('assignments') - .select('*') - .order('deadline', { ascending: false }); - - if (assignmentsError) { - Alert.alert('Assignments could not be fetched, please try again'); - return; - } - - const assignmentRows = assignmentsData ?? []; - SetAssignments(assignmentRows); - - if (assignmentRows.length === 0) { - SetTasksByAssignment({}); - return; - } - - const aIds = assignmentRows.map((assignment) => assignment.aId); - - const { data: tasksData, error: tasksError } = await supabase - .from('tasks') - .select('*') - .in('aId', aIds); - - if (tasksError) { - Alert.alert('Assignment tasks could not be fetched, please try again'); - SetTasksByAssignment({}); - return; - } - - const groupedTasks: Record = {}; - - for (const task of tasksData ?? []) { - if (!groupedTasks[task.aId]) { - groupedTasks[task.aId] = []; - } - groupedTasks[task.aId].push(task); - } - - SetTasksByAssignment(groupedTasks); - }; - - useFocusEffect( - useCallback(() => { - if (session) { - GetAssignments(); - } - }, [session]) - ); - - const DeleteAssignment = async (aId: string, sId: string) => { - Alert.alert( - 'Delete Assignment', - 'Are you sure you want to delete this assignment?', - [ - { - text: 'Cancel', - style: 'cancel', - }, - { - text: 'Delete', - style: 'destructive', - onPress: async () => { - const { error } = await supabase - .from('assignments') - .delete() - .eq('aId', aId); - - if (error) { - Alert.alert('Assignment could not be deleted, please try again'); - return; - } - - Alert.alert('Assignment deleted successfully!'); - - try { - await CheckSubjectCompletion(sId); - } catch { - Alert.alert("Failed to update subject status"); - } - - GetAssignments(); - }, - }, - ] - ); - }; - - return ( - - ( - - - - - - await supabase.auth.signOut()} - > - - Logout - - - - ), - }} - /> - - - - - Assignments - - - Track what is coming up and what you have already finished. - - - - router.push('/assignment/createAssignment')} - > - - Create Assignment - - - - item.aId} - showsVerticalScrollIndicator={false} - stickySectionHeadersEnabled={false} - contentContainerStyle={{ - paddingBottom: 32, - }} - renderSectionHeader={({ section: { title, data } }) => ( - - - {title} - - - - - {data.length} - - - - )} - renderItem={({ item }) => { - const isOwner = session?.user.id === item.uId; - - const assignmentTasks = tasksByAssignment[item.aId] ?? []; - const progress = assignmentTasks.length === 0 ? 0 : Math.round((assignmentTasks.filter(task => task.isCompleted).length / assignmentTasks.length) * 100); - - return ( - - - router.push({ - pathname: '/assignment/viewDetailsAssignment', - params: { aId: item.aId }, - }) - } - > - - - {item.isCompleted && ( - - ✓ - - )} - - - - - {item.title} - - - {item.description ? ( - - {item.description} - - ) : null} - - - - Deadline: {item.deadline || 'No deadline'} - - - - - {progress}% - - - - - - - - - - {isOwner && ( - - - router.push({ - pathname: '/assignment/editAssignment', - params: { aId: item.aId }, - }) - } - > - - Edit - - - - DeleteAssignment(item.aId, item.sId)} - > - - Delete - - - - )} - - ); - }} - renderSectionFooter={({ section }) => - section.data.length === 0 ? ( - - - {section.emptyMessage} - - - New assignments will show up here. - - - ) : ( - - ) - } - /> - - - ); -} \ No newline at end of file diff --git a/app/assignment/editAssignment.tsx b/app/assignment/editAssignment.tsx deleted file mode 100644 index 7115942..0000000 --- a/app/assignment/editAssignment.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import { defaultStyles } from '@/constants/defaultStyles'; -import { GetAssignmentNotificationId, RemoveAssignmentNotificationId, SaveAssignmentNotificationId } from '@/lib/asyncStorage'; -import { CheckSubjectCompletion } from '@/lib/progress'; -import { supabase } from '@/lib/supabase'; -import type { Assignment } from '@/lib/types'; -import * as Notifications from 'expo-notifications'; -import { router, Stack, useFocusEffect, useLocalSearchParams } from 'expo-router'; -import { useCallback, useState } from 'react'; -import { ActivityIndicator, Alert, Button, Keyboard, KeyboardAvoidingView, Platform, Pressable, Text, TextInput, TouchableWithoutFeedback, View } from 'react-native'; - -export default function EditAssignment() { - const { aId } = useLocalSearchParams<{ aId: string }>(); - const [assignment, SetAssignment] = useState(null) - const [isSaving, SetIsSaving] = useState(false); - - const ScheduleDeadlineReminder = async (aId: string, title: string, deadline: string) => { - const dl = new Date(deadline); - - if (isNaN(dl.getTime())) return null; - - const deadlineReminder = new Date(dl.getTime() - 24 * 60 * 60 * 1000); - - if (deadlineReminder <= new Date()) return null; - - const nId = await Notifications.scheduleNotificationAsync({ - content: { - title: 'Assignment deadline coming up', - body: `${title} is due in 24 hours.`, - data: { aId }, - }, - trigger: { - type: Notifications.SchedulableTriggerInputTypes.DATE, - date: deadlineReminder, - }, - }); - - return nId; - } - - const CancelDeadlineReminder = async (aId: string) => { - const nId = await GetAssignmentNotificationId(aId); - - if (!nId) return; - - await Notifications.cancelScheduledNotificationAsync(nId); - await RemoveAssignmentNotificationId(aId); - } - - const GetAssignment = async (aId: string) => { - const { data, error } = await supabase.from("assignments").select("*").eq("aId", aId).single(); - - if (error) { - Alert.alert("Assignment could not be fetched, please try again"); - return; - } - - SetAssignment(data ?? null); - } - - useFocusEffect( - useCallback(() => { - if (aId) { - GetAssignment(aId); - } - }, [aId]) - ); - - const EditAssignment = async () => { - if (!assignment) return; - - if(assignment.title.trim() === '' || assignment.deadline.trim() === '') { - Alert.alert("Title and deadline are required!"); - return; - } - - const { data: userData, error: userError } = await supabase.auth.getUser(); - - if(userError || !userData.user) { - router.replace("../createUser"); - return; - } - - SetIsSaving(true); - - const { data: assignmentData, error: dbError } = await supabase.from("assignments").update({ - title: assignment.title, - description: assignment.description, - deadline: assignment.deadline, - isCompleted: assignment.isCompleted, - lastChanged: new Date().toISOString(), - uId: userData.user.id, - sId: assignment.sId, - }) - .eq("aId", aId) - .select() - .single(); - - SetIsSaving(false); - - if (dbError) { - Alert.alert("Assignment could not be edited, please try again"); - return; - } - - Alert.alert("Assignment successfully edited!"); - - if (assignmentData) { - await CancelDeadlineReminder(assignmentData.aId); - - if (!assignmentData.isCompleted) { - const nId = await ScheduleDeadlineReminder(assignmentData.aId, assignmentData.title, assignmentData.deadline); - - if (nId) { - await SaveAssignmentNotificationId(assignmentData.aId, nId); - } - } - } - - if (assignmentData.sId) { - try { - await CheckSubjectCompletion(assignmentData.sId); - } catch { - Alert.alert("Failed to update subject status"); - } - } - - router.back(); - } - - return ( - - - - {!assignment && ( - - Assignment not found - - )} - - {assignment && ( - - Edit Assignment - - - - SetAssignment(prev => prev ? { ...prev, title: text } : prev)} - /> - SetAssignment(prev => prev ? { ...prev, description: text } : prev)} - /> - SetAssignment(prev => prev ? { ...prev, deadline: text } : prev)} - /> - SetAssignment(prev => prev ? { ...prev, isCompleted: !prev.isCompleted } : prev)} - style={defaultStyles.checkboxContainer} - > - - {assignment.isCompleted && } - - {assignment.isCompleted ? 'Completed' : 'Not Completed'} - - -