From 219d599617c14b5a880fb22d4807cf058a3120e7 Mon Sep 17 00:00:00 2001 From: Chris Sanden Date: Sat, 2 May 2026 20:01:40 +0200 Subject: [PATCH] added help button and improved dashboard styling to be in line with the rest of the project --- app/(tabs)/index.tsx | 332 ++++++++++++++++++++++++++++------------ app/(tabs)/subjects.tsx | 144 +++++++++++++++-- 2 files changed, 364 insertions(+), 112 deletions(-) diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index aa6a730..47df45c 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,4 +1,3 @@ -import { defaultStyles } from "@/constants/defaultStyles"; import { GetActiveSprint, RemoveActiveSprint, @@ -6,11 +5,20 @@ import { } from '@/lib/asyncStorage'; import { formatDate } from '@/lib/date'; import { RegisterForLocalNotificationsAsync } from '@/lib/notifications'; +import { CheckAssignmentCompletion } from '@/lib/progress'; import { supabase } from "@/lib/supabase"; +import MaterialIcons from '@expo/vector-icons/MaterialIcons'; import { Session } from '@supabase/supabase-js'; import { router, Stack, useFocusEffect } from "expo-router"; import { useCallback, useEffect, useState } from 'react'; -import { Button, Pressable, StyleSheet, Text, View } from "react-native"; +import { + Alert, + Modal, + Pressable, + ScrollView, + Text, + View, +} from "react-native"; type UpcomingDeadlineTask = { tId: string; @@ -22,6 +30,29 @@ type UpcomingDeadlineTask = { deadline: string; }; +const FLOW_STEPS = [ + { + label: '1', + title: 'Subject', + description: 'A subject is the top-level container for one course or area you are studying.', + }, + { + label: '2', + title: 'Assignment', + description: 'Each subject contains assignments like projects, exercises, or exam prep blocks.', + }, + { + label: '3', + title: 'Task', + description: 'Assignments are broken down into tasks so you always have one concrete thing to work on.', + }, + { + label: '4', + title: 'Sprint', + description: 'A sprint is one focused work session tied to a single task and tracked by the timer.', + }, +] as const; + function formatTime(totalSeconds: number) { const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; @@ -36,6 +67,8 @@ export default function HomeScreen() { const [activeSprintTaskDesc, setActiveSprintTaskDesc] = useState(null); const [remainingSeconds, setRemainingSeconds] = useState(0); const [upcomingDeadlineTasks, setUpcomingDeadlineTasks] = useState([]); + const [isFlowInfoVisible, setIsFlowInfoVisible] = useState(false); + const [completingTaskId, setCompletingTaskId] = useState(null); const loadActiveSprint = useCallback(async () => { const storedSprint = await GetActiveSprint(); @@ -221,37 +254,177 @@ export default function HomeScreen() { return () => clearInterval(intervalId); }, [activeSprint]); + const handleTaskCompletion = useCallback(async (task: UpcomingDeadlineTask) => { + if (completingTaskId) { + return; + } + + setCompletingTaskId(task.tId); + + const { error } = await supabase + .from('tasks') + .update({ + isCompleted: true, + lastChanged: new Date().toISOString(), + }) + .eq('tId', task.tId); + + if (error) { + setCompletingTaskId(null); + Alert.alert('Task could not be completed, please try again'); + return; + } + + try { + await CheckAssignmentCompletion(task.aId); + } catch { + setCompletingTaskId(null); + Alert.alert('Task was updated, but assignment progress could not be refreshed'); + return; + } + + setUpcomingDeadlineTasks((currentTasks) => + currentTasks.filter((currentTask) => currentTask.tId !== task.tId) + ); + setCompletingTaskId(null); + }, [completingTaskId]); + return ( - + { + return ( + + setIsFlowInfoVisible(true)} + > + + + + ) + }, headerRight: () => { return ( - -