don't ask me how, but it works
This commit is contained in:
@@ -8,8 +8,6 @@ import { Redirect, router, Stack, useFocusEffect } from 'expo-router';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { Alert, Modal, Pressable, ScrollView, Text, View, ActivityIndicator } from 'react-native';
|
||||
|
||||
import type { SubjectColor } from '@/lib/subjectColors';
|
||||
|
||||
const FLOW_STEPS = [
|
||||
{
|
||||
label: '1',
|
||||
@@ -77,8 +75,6 @@ export default function Subjects() {
|
||||
}, [session?.user.id]);
|
||||
|
||||
const GetSubjects = useCallback(async () => {
|
||||
if (!session?.user.id) return;
|
||||
const GetSubjects = async () => {
|
||||
if (!session?.user.id) {
|
||||
SetIsLoading(false);
|
||||
return;
|
||||
@@ -86,8 +82,6 @@ export default function Subjects() {
|
||||
|
||||
SetIsLoading(true);
|
||||
|
||||
SetIsLoading(true);
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('subjects')
|
||||
.select('*')
|
||||
@@ -98,14 +92,11 @@ export default function Subjects() {
|
||||
|
||||
if (error) {
|
||||
Alert.alert('Subjects could not be fetched, please try again');
|
||||
SetIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
SetSubjects((data as Subject[]) ?? []);
|
||||
}, [session?.user.id]);
|
||||
SetIsLoading(false);
|
||||
};
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
@@ -121,6 +112,8 @@ export default function Subjects() {
|
||||
|
||||
if (needsSetup) {
|
||||
return <Redirect href="/setup" />;
|
||||
}
|
||||
|
||||
const RenderSubjectCard = (subject: Subject) => {
|
||||
const colorKey: SubjectColor = subject.color ?? 'slate';
|
||||
const colorSet = SUBJECT_COLORS[colorKey];
|
||||
|
||||
@@ -345,12 +345,6 @@ export default function ViewDetailsSubject() {
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="mt-5">
|
||||
<View className="mb-2 flex-row items-center justify-between">
|
||||
<Text className="text-sm font-semibold text-text-secondary">
|
||||
Assignments completed
|
||||
</Text>
|
||||
{totalAssignments > 0 ? (
|
||||
<View className="mt-5">
|
||||
<View className="mb-2 flex-row items-center justify-between">
|
||||
<Text className="text-sm font-semibold text-text-secondary">
|
||||
@@ -379,8 +373,11 @@ export default function ViewDetailsSubject() {
|
||||
remainingAssignments === 1 ? '' : 's'
|
||||
} remaining`}
|
||||
</Text>
|
||||
|
||||
<Text className="mt-1 text-xs text-text-muted">
|
||||
Based only on completed assignments in this subject.
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
<Text className="mt-4 text-sm text-text-muted">
|
||||
Last changed: {formatDateTime(subject.lastChanged)}
|
||||
|
||||
@@ -35,6 +35,7 @@ const { tId } = useLocalSearchParams<{ tId: string }>();
|
||||
|
||||
const [task, SetTask] = useState<Task | null>(null);
|
||||
const [session, SetSession] = useState<Session | null>(null);
|
||||
const [isLoading, SetIsLoading] = useState(false);
|
||||
const [completedFocusSessions, setCompletedFocusSessions] = useState(0);
|
||||
const [contextMeta, setContextMeta] = useState({
|
||||
subjectTitle: 'No Subject',
|
||||
@@ -70,6 +71,8 @@ const loadTaskStudyActivity = useCallback(async (taskId: string, userId: string)
|
||||
}, []);
|
||||
|
||||
const GetTask = useCallback(async (taskId: string) => {
|
||||
SetIsLoading(true);
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('tasks')
|
||||
.select('*')
|
||||
@@ -77,6 +80,14 @@ const GetTask = useCallback(async (taskId: string) => {
|
||||
.single();
|
||||
|
||||
if (error || !data) {
|
||||
SetTask(null);
|
||||
setContextMeta({
|
||||
subjectTitle: 'Unknown Subject',
|
||||
assignmentTitle: 'Unknown Assignment',
|
||||
subjectColor: 'slate',
|
||||
});
|
||||
setCompletedFocusSessions(0);
|
||||
SetIsLoading(false);
|
||||
Alert.alert('Task could not be fetched, please try again');
|
||||
return;
|
||||
}
|
||||
@@ -84,30 +95,21 @@ const GetTask = useCallback(async (taskId: string) => {
|
||||
SetTask(data);
|
||||
await loadTaskStudyActivity(taskId, data.uId);
|
||||
|
||||
let nextContextMeta = {
|
||||
subjectTitle: 'Unknown Subject',
|
||||
assignmentTitle: 'Unknown Assignment',
|
||||
subjectColor: 'slate' as SubjectColor,
|
||||
};
|
||||
|
||||
if (data.aId) {
|
||||
const { data: assignmentData, error: assignmentError } = await supabase
|
||||
.from('assignments')
|
||||
.select('title, sId')
|
||||
.eq('aId', data.aId)
|
||||
const GetTask = async (taskId: string) => {
|
||||
SetIsLoading(true);
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('tasks')
|
||||
.select('*')
|
||||
.eq('tId', taskId)
|
||||
.single();
|
||||
|
||||
SetIsLoading(false);
|
||||
|
||||
if (assignmentError || !assignmentData) {
|
||||
setContextMeta({
|
||||
subjectTitle: 'Unknown Subject',
|
||||
assignmentTitle: 'Unknown Assignment',
|
||||
subjectColor: 'slate',
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!assignmentError && assignmentData) {
|
||||
nextContextMeta.assignmentTitle = assignmentData.title ?? 'Unknown Assignment';
|
||||
|
||||
if (assignmentData.sId) {
|
||||
const { data: subjectData, error: subjectError } = await supabase
|
||||
@@ -116,61 +118,25 @@ const GetTask = useCallback(async (taskId: string) => {
|
||||
.eq('sId', assignmentData.sId)
|
||||
.single();
|
||||
|
||||
if (subjectError || !subjectData) {
|
||||
SetTask(data);
|
||||
|
||||
if (data.aId) {
|
||||
SetIsLoading(true);
|
||||
|
||||
const { data: assignmentData, error: assignmentError } = await supabase
|
||||
.from('assignments')
|
||||
.select('title, sId')
|
||||
.eq('aId', data.aId)
|
||||
.single();
|
||||
|
||||
SetIsLoading(false);
|
||||
|
||||
if (assignmentError || !assignmentData) {
|
||||
setContextMeta({
|
||||
subjectTitle: 'Unknown Subject',
|
||||
assignmentTitle: assignmentData.title ?? 'Unknown Assignment',
|
||||
subjectColor: 'slate',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setContextMeta({
|
||||
if (!subjectError && subjectData) {
|
||||
nextContextMeta = {
|
||||
subjectTitle: subjectData.title ?? 'Unknown Subject',
|
||||
assignmentTitle: assignmentData.title ?? 'Unknown Assignment',
|
||||
subjectColor: (subjectData.color as SubjectColor | undefined) ?? 'slate',
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [loadTaskStudyActivity]);
|
||||
if (assignmentData.sId) {
|
||||
SetIsLoading(true);
|
||||
|
||||
const { data: subjectData, error: subjectError } = await supabase
|
||||
.from('subjects')
|
||||
.select('title, color')
|
||||
.eq('sId', assignmentData.sId)
|
||||
.single();
|
||||
|
||||
setContextMeta(nextContextMeta);
|
||||
SetIsLoading(false);
|
||||
|
||||
if (subjectError || !subjectData) {
|
||||
setContextMeta({
|
||||
subjectTitle: 'Unknown Subject',
|
||||
assignmentTitle: assignmentData.title ?? 'Unknown Assignment',
|
||||
subjectColor: 'slate',
|
||||
});
|
||||
return;
|
||||
}
|
||||
}, [loadTaskStudyActivity]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (session && tId) {
|
||||
GetTask(tId);
|
||||
void GetTask(tId);
|
||||
}
|
||||
}, [GetTask, session, tId])
|
||||
);
|
||||
@@ -189,9 +155,7 @@ const handleSprintStart = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const secondsLeft = Math.ceil((activeSession.endTime - Date.now()) / 1000)
|
||||
const secondsLeft = Math.ceil((activeSession.endTime - Date.now()) / 1000);
|
||||
|
||||
if (secondsLeft <= 0) {
|
||||
await finalizeStoredSession('expired', activeSession);
|
||||
@@ -200,19 +164,19 @@ const handleSprintStart = async () => {
|
||||
params: {
|
||||
tId: task?.tId,
|
||||
durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES),
|
||||
}
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (activeSession.taskId === task?.tId) {
|
||||
router.push({
|
||||
pathname: '/task/timer',
|
||||
params: {
|
||||
tId: activeSession.taskId ?? undefined,
|
||||
durationMinutes: String(DEFAULT_FOCUS_DURATION_MINUTES),
|
||||
}});
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -220,7 +184,7 @@ const handleSprintStart = async () => {
|
||||
'Active session in progress',
|
||||
`End the current session and start a new ${DEFAULT_FOCUS_DURATION_MINUTES} minute sprint on this task?`,
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel', },
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Start new sprint',
|
||||
style: 'destructive',
|
||||
@@ -239,36 +203,6 @@ const handleSprintStart = async () => {
|
||||
);
|
||||
};
|
||||
|
||||
const colorSet = getSubjectColorSet(contextMeta.subjectColor);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<View className="flex-1 items-center justify-center bg-app-bg">
|
||||
<ActivityIndicator size="large" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (!task) {
|
||||
return (
|
||||
<View className="flex-1 bg-app-bg px-5 pt-6">
|
||||
<Stack.Screen
|
||||
options={{
|
||||
title: 'Task Details',
|
||||
headerRight: () => (
|
||||
<Pressable
|
||||
className="rounded-full bg-app-subtle px-4 py-2"
|
||||
onPress={async () => await supabase.auth.signOut()}
|
||||
>
|
||||
<Text className="text-sm font-semibold text-text-secondary">
|
||||
Logout
|
||||
</Text>
|
||||
</Pressable>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
const DeleteTask = async (taskId: string) => {
|
||||
Alert.alert(
|
||||
'Delete Task',
|
||||
@@ -312,6 +246,14 @@ const DeleteTask = async (taskId: string) => {
|
||||
|
||||
const colorSet = getSubjectColorSet(contextMeta.subjectColor);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<View className="flex-1 items-center justify-center bg-app-bg">
|
||||
<ActivityIndicator size="large" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (!task) {
|
||||
return (
|
||||
<View className="flex-1 bg-app-bg px-5 pt-6">
|
||||
@@ -394,9 +336,9 @@ return (
|
||||
backgroundColor: task.isCompleted ? colorSet.strong : '#EFEBE3',
|
||||
}}
|
||||
>
|
||||
{task.isCompleted && (
|
||||
{task.isCompleted ? (
|
||||
<Text className="text-sm font-bold text-text-inverse">✓</Text>
|
||||
)}
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
<View className="flex-1">
|
||||
@@ -479,11 +421,11 @@ return (
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{isOwner && (
|
||||
{isOwner ? (
|
||||
<View className="mt-5 border-t border-app-border pt-5">
|
||||
<Pressable
|
||||
className="h-14 items-center justify-center rounded-2xl bg-accent"
|
||||
onPress={() => handleSprintStart()}
|
||||
onPress={handleSprintStart}
|
||||
>
|
||||
<Text className="text-base font-bold text-text-inverse">
|
||||
Start Sprint
|
||||
@@ -508,6 +450,7 @@ return (
|
||||
Edit
|
||||
</Text>
|
||||
</Pressable>
|
||||
|
||||
<Pressable
|
||||
className="flex-1 items-center justify-center rounded-2xl border border-app-border bg-app-surface py-3"
|
||||
onPress={() => DeleteTask(task.tId)}
|
||||
@@ -518,7 +461,7 @@ return (
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user