import { defaultStyles } from '@/constants/defaultStyles'; import * as AsyncStorage from '@/lib/asyncStorage'; import { supabase } from '@/lib/supabase'; import * as Notifications from 'expo-notifications'; import { router, Stack, useLocalSearchParams } from 'expo-router'; import { useEffect, useState } from 'react'; import { ActivityIndicator, Alert, Keyboard, KeyboardAvoidingView, Platform, Pressable, ScrollView, Text, TextInput, TouchableWithoutFeedback, View, } from 'react-native'; export default function UpsertAssignment() { const { aId, sId: routeSId, flow } = useLocalSearchParams<{ aId?: string; sId?: string; flow?: string; }>(); const isEditMode = Boolean(aId); const isSetupFlow = flow === 'setup'; const [title, SetTitle] = useState(''); const [description, SetDescription] = useState(''); const [deadline, SetDeadline] = useState(''); const [isCompleted, SetIsCompleted] = useState(false); const [subjectId, SetSubjectId] = useState(routeSId ?? null); const [isLoading, SetIsLoading] = useState(isEditMode); const [isSaving, SetIsSaving] = useState(false); useEffect(() => { if (!isEditMode || !aId) { SetIsLoading(false); return; } const loadAssignment = async () => { SetIsLoading(true); const { data, error } = await supabase .from('assignments') .select('*') .eq('aId', aId) .single(); SetIsLoading(false); if (error || !data) { Alert.alert('Assignment could not be loaded, please try again'); router.back(); return; } SetTitle(data.title ?? ''); SetDescription(data.description ?? ''); SetDeadline(data.deadline ?? ''); SetIsCompleted(data.isCompleted ?? false); SetSubjectId(data.sId ?? routeSId ?? null); }; loadAssignment(); }, [aId, isEditMode, routeSId]); const ScheduleDeadlineReminder = async ( assignmentId: string, assignmentTitle: string, assignmentDeadline: string ) => { const dl = new Date(assignmentDeadline); if (Number.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: `${assignmentTitle} is due in 24 hours.`, data: { aId: assignmentId }, }, trigger: { type: Notifications.SchedulableTriggerInputTypes.DATE, date: deadlineReminder, }, }); return nId; }; const updateDeadlineReminder = async ( assignmentId: string, assignmentTitle: string, assignmentDeadline: string, completed: boolean ) => { const existingNotificationId = await AsyncStorage.GetAssignmentNotificationId(assignmentId); if (existingNotificationId) { try { await Notifications.cancelScheduledNotificationAsync( existingNotificationId ); } catch {} await AsyncStorage.RemoveAssignmentNotificationId(assignmentId); } if (completed) return; const nId = await ScheduleDeadlineReminder( assignmentId, assignmentTitle, assignmentDeadline ); if (nId) { await AsyncStorage.SaveAssignmentNotificationId(assignmentId, nId); } }; const handleSubmit = async () => { if (title.trim() === '') { Alert.alert('Title is required!'); return; } const { data: userData, error: userError } = await supabase.auth.getUser(); if (userError || !userData.user) { router.replace('/login'); return; } if (!subjectId) { Alert.alert('Missing subject', 'This assignment is not linked to a subject.'); return; } SetIsSaving(true); const payload = { title: title.trim(), description: description.trim(), deadline: deadline.trim(), isCompleted, lastChanged: new Date().toISOString(), uId: userData.user.id, sId: subjectId, }; const result = isEditMode && aId ? await supabase .from('assignments') .update(payload) .eq('aId', aId) .select() .single() : await supabase.from('assignments').insert(payload).select().single(); if (result.error || !result.data) { SetIsSaving(false); Alert.alert( isEditMode ? 'Assignment could not be updated, please try again' : 'Assignment could not be created, please try again' ); return; } const savedAssignment = result.data; await updateDeadlineReminder( savedAssignment.aId, savedAssignment.title, savedAssignment.deadline, savedAssignment.isCompleted ); SetIsSaving(false); if (!isEditMode && isSetupFlow) { router.replace({ pathname: '/task/upsertTask', params: { aId: savedAssignment.aId, flow: 'setup', }, }); return; } Alert.alert( isEditMode ? 'Assignment successfully updated!' : 'Assignment successfully created!' ); 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'; if (isLoading) { return ( ); } return ( <> {isEditMode ? 'Edit Assignment' : 'Create Assignment'} {isEditMode ? 'Update this assignment and keep your subject organized.' : '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 ? ( {isEditMode ? 'Saving...' : 'Creating...'} ) : ( {isEditMode ? 'Save Changes' : 'Create Assignment'} )} router.back()} disabled={isSaving} > Cancel ); }