diff --git a/app.json b/app.json index b7c46f2..e1b0afe 100644 --- a/app.json +++ b/app.json @@ -38,7 +38,8 @@ "backgroundColor": "#000000" } } - ] + ], + "expo-secure-store" ], "experiments": { "typedRoutes": true, diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 9f40e79..e51a2bc 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,9 +1,8 @@ import { supabase } from "@/lib/supabase"; import { Session } from "@supabase/supabase-js"; -import { Tabs } from "expo-router"; +import { Redirect, Tabs } from "expo-router"; import { useEffect, useState } from "react"; - export default function TabLayout() { const [session, SetSession] = useState(null) const [loading, SetLoading] = useState(true); @@ -28,14 +27,29 @@ export default function TabLayout() { return null; } - // if (!session) { - // return ; - // } + if (!session) { + return ; + } return ( - + + + + + + + + + + + + + + + + ); } \ No newline at end of file diff --git a/app/(tabs)/assignment/createAssignment.tsx b/app/(tabs)/assignment/createAssignment.tsx new file mode 100644 index 0000000..d6b9841 --- /dev/null +++ b/app/(tabs)/assignment/createAssignment.tsx @@ -0,0 +1,213 @@ +import { defaultStyles } from '@/constants/defaultStyles'; +import { supabase } from '@/lib/supabase'; +import { router, Stack, useLocalSearchParams } from 'expo-router'; +import { useState } from 'react'; +import { + ActivityIndicator, + Alert, + Keyboard, + KeyboardAvoidingView, + Platform, + Pressable, + ScrollView, + Text, + TextInput, + TouchableWithoutFeedback, + View, +} from 'react-native'; + +export default function CreateAssignment() { + const sId = (useLocalSearchParams().sId as string) ?? null; + + const [title, SetTitle] = useState(''); + const [description, SetDescription] = useState(''); + const [deadline, SetDeadline] = useState(''); + const [isCompleted, SetIsCompleted] = useState(false); + const [isSaving, SetIsSaving] = useState(false); + + const CreateAssignment = async () => { + if (title.trim() === '') { + Alert.alert('Title is required!'); + return; + } + + const { data, error: userError } = await supabase.auth.getUser(); + + if (userError || !data.user) { + router.replace('../createUser'); + return; + } + + SetIsSaving(true); + + const { error: dbError } = await supabase.from('assignments').insert({ + title: title.trim(), + description: description.trim(), + deadline: deadline.trim(), + isCompleted, + lastChanged: new Date().toISOString(), + uId: data.user.id, + sId, + }); + + if (dbError) { + SetIsSaving(false); + Alert.alert('Assignment could not be created, please try again'); + return; + } + + Alert.alert('Assignment successfully created!'); + + SetTitle(''); + SetDescription(''); + SetDeadline(''); + SetIsCompleted(false); + SetIsSaving(false); + + router.back(); + }; + + const inputClassName = + 'rounded-2xl border border-app-border bg-app-subtle px-4 py-3 text-base text-text-main'; + + const labelClassName = 'mb-2 text-sm font-semibold text-text-secondary'; + + return ( + <> + + + + + + + + Create Assignment + + + Add a new assignment to keep your subject organized. + + + + + + Title + + + + + Description + + + + + Deadline + + + + SetIsCompleted((current) => !current)} + disabled={isSaving} + > + + {isCompleted && ( + + ✓ + + )} + + + + + Mark as completed + + + You can change this later. + + + + + + {isSaving ? ( + + + + Creating... + + + ) : ( + + Create Assignment + + )} + + + router.back()} + disabled={isSaving} + > + + Cancel + + + + + + + + ); +} \ No newline at end of file diff --git a/app/(tabs)/assignment/editAssignment.tsx b/app/(tabs)/assignment/editAssignment.tsx new file mode 100644 index 0000000..f558deb --- /dev/null +++ b/app/(tabs)/assignment/editAssignment.tsx @@ -0,0 +1,143 @@ +import { defaultStyles } from '@/constants/defaultStyles'; +import { supabase } from '@/lib/supabase'; +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) + const [isSaving, SetIsSaving] = useState(false); + + 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, error: userError } = await supabase.auth.getUser(); + + if(userError || !data.user) { + router.replace("../createUser"); + return; + } + + SetIsSaving(true); + + const { error: dbError } = await supabase.from("assignments").update({ + title: assignment.title, + description: assignment.description, + deadline: assignment.deadline, + isCompleted: assignment.isCompleted, + lastChanged: new Date().toISOString(), + uId: data.user.id, + sId: assignment.sId, + }).eq("aId", aId); + + SetIsSaving(false); + + if (dbError) { + Alert.alert("Assignment could not be edited, please try again"); + return; + } + + Alert.alert("Assignment successfully edited!"); + + 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'} + + +