From a35353f45b5a527f98400eaf9fb4848047aa325d Mon Sep 17 00:00:00 2001 From: Teodor Date: Thu, 23 Apr 2026 03:27:26 +0200 Subject: [PATCH] Added progress bar for assignments (UI fix needed) --- app.json | 9 +- app/(tabs)/assignments.tsx | 74 +++++++++++--- app/(tabs)/subjects.tsx | 10 +- app/(tabs)/tasks.tsx | 11 +-- app/assignment/editAssignment.tsx | 12 +-- app/assignment/viewDetailsAssignment.tsx | 45 +++++---- app/subject/editSubject.tsx | 10 +- app/subject/viewDetailsSubject.tsx | 25 +---- app/task/createTask.tsx | 9 ++ app/task/editTask.tsx | 20 ++-- app/task/viewDetailsTask.tsx | 23 +++-- eas.json | 21 ++++ lib/progress.ts | 15 +++ lib/types.ts | 29 ++++++ notes/new-build-guide.md | 71 ++++++++++++++ package-lock.json | 118 +++++++++++++++++++++++ package.json | 1 + 17 files changed, 388 insertions(+), 115 deletions(-) create mode 100644 eas.json create mode 100644 lib/progress.ts create mode 100644 lib/types.ts create mode 100644 notes/new-build-guide.md diff --git a/app.json b/app.json index e1b0afe..f4860ed 100644 --- a/app.json +++ b/app.json @@ -19,7 +19,8 @@ "monochromeImage": "./assets/images/android-icon-monochrome.png" }, "edgeToEdgeEnabled": true, - "predictiveBackGestureEnabled": false + "predictiveBackGestureEnabled": false, + "package": "com.teodorsa.StudySprint" }, "web": { "output": "static", @@ -44,6 +45,12 @@ "experiments": { "typedRoutes": true, "reactCompiler": true + }, + "extra": { + "router": {}, + "eas": { + "projectId": "25652385-934a-4a29-8fa7-deff3281e03e" + } } } } diff --git a/app/(tabs)/assignments.tsx b/app/(tabs)/assignments.tsx index abeb58e..69190ab 100644 --- a/app/(tabs)/assignments.tsx +++ b/app/(tabs)/assignments.tsx @@ -1,5 +1,6 @@ import { defaultStyles } from '@/constants/defaultStyles'; 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'; @@ -12,19 +13,9 @@ import { View, } from 'react-native'; -type Assignment = { - aId: string; - title: string; - description: string; - deadline: string; - isCompleted: boolean; - lastChanged: string; - uId: string; - sId: string; -}; - export default function Assignments() { const [assignments, SetAssignments] = useState([]); + const [tasksByAssignment, SetTasksByAssignment] = useState>({}); const [session, SetSession] = useState(null); const assignmentSections = [ @@ -55,17 +46,47 @@ export default function Assignments() { }, []); const GetAssignments = async () => { - const { data, error } = await supabase + const { data: assignmentsData, error: assignmentsError } = await supabase .from('assignments') .select('*') .order('deadline', { ascending: false }); - if (error) { + if (assignmentsError) { Alert.alert('Assignments could not be fetched, please try again'); return; } - SetAssignments(data ?? []); + 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( @@ -178,6 +199,9 @@ export default function Assignments() { 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 ( + + + {progress}% + + + + + diff --git a/app/(tabs)/subjects.tsx b/app/(tabs)/subjects.tsx index 5abaa9f..323d021 100644 --- a/app/(tabs)/subjects.tsx +++ b/app/(tabs)/subjects.tsx @@ -1,5 +1,6 @@ import { defaultStyles } from '@/constants/defaultStyles'; import { supabase } from '@/lib/supabase'; +import type { Subject } from '@/lib/types'; import { Ionicons } from '@expo/vector-icons'; import { Session } from '@supabase/supabase-js'; import { router, Stack, useFocusEffect } from 'expo-router'; @@ -12,15 +13,6 @@ import { View, } from 'react-native'; -type Subject = { - sId: string; - title: string; - description: string; - isActive: boolean; - lastChanged: string; - uId: string; -}; - export default function Subjects() { const [subjects, SetSubjects] = useState([]); const [session, SetSession] = useState(null); diff --git a/app/(tabs)/tasks.tsx b/app/(tabs)/tasks.tsx index 447c948..6b204e4 100644 --- a/app/(tabs)/tasks.tsx +++ b/app/(tabs)/tasks.tsx @@ -1,5 +1,6 @@ import { defaultStyles } from '@/constants/defaultStyles'; import { supabase } from '@/lib/supabase'; +import type { Task } from '@/lib/types'; import { Ionicons } from '@expo/vector-icons'; import { Session } from '@supabase/supabase-js'; import { router, Stack, useFocusEffect } from 'expo-router'; @@ -12,16 +13,6 @@ import { View, } from 'react-native'; -type Task = { - tId: string; - title: string; - description: string; - isCompleted: boolean; - lastChanged: string; - uId: string; - aId: string; -}; - export default function Tasks() { const [tasks, SetTasks] = useState([]); const [session, SetSession] = useState(null); diff --git a/app/assignment/editAssignment.tsx b/app/assignment/editAssignment.tsx index 41fa9c3..76e0348 100644 --- a/app/assignment/editAssignment.tsx +++ b/app/assignment/editAssignment.tsx @@ -1,22 +1,12 @@ import { defaultStyles } from '@/constants/defaultStyles'; import { GetAssignmentNotificationId, RemoveAssignmentNotificationId, SaveAssignmentNotificationId } from '@/lib/asyncStorage'; 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'; -type Assignment = { - aId: string; - title: string; - description: string; - deadline: string; - isCompleted: boolean; - lastChanged: string; - uId: string; - sId: string; -} - export default function EditAssignment() { const { aId } = useLocalSearchParams<{ aId: string }>(); const [assignment, SetAssignment] = useState(null) diff --git a/app/assignment/viewDetailsAssignment.tsx b/app/assignment/viewDetailsAssignment.tsx index e1548a7..99a97d4 100644 --- a/app/assignment/viewDetailsAssignment.tsx +++ b/app/assignment/viewDetailsAssignment.tsx @@ -1,31 +1,11 @@ import { defaultStyles } from '@/constants/defaultStyles'; import { supabase } from '@/lib/supabase'; +import type { Assignment, 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, Button, Pressable, SectionList, Text, View } from "react-native"; -type Assignment = { - aId: string; - title: string; - description: string; - deadline: string; - isCompleted: boolean; - lastChanged: string; - uId: string; - sId: string; -} - -type Task = { - tId: string; - title: string; - description: string; - isCompleted: boolean; - lastChanged: string; - uId: string; - aId: string; -} - export default function ViewDetailsAssignment() { const { aId } = useLocalSearchParams<{ aId: string }>(); const [assignment, SetAssignment] = useState(null) @@ -133,6 +113,8 @@ export default function ViewDetailsAssignment() { ) } + const progress = tasks.length === 0 ? 0 : Math.round((tasks.filter(task => task.isCompleted).length / tasks.length) * 100); + return ( {assignment.isCompleted && } + + {progress}% + + + + + {assignment.lastChanged}