import React, { useState, useEffect, useContext } from "react"; import { StyleSheet, Text, SafeAreaView, View, TouchableOpacity, TextInput as Input, Keyboard, } from "react-native"; import { Portal, Button, useTheme, FAB } from "react-native-paper"; import Modal from "react-native-modal"; import Icon from "react-native-vector-icons/FontAwesome5"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { v4 as uuidv4 } from "uuid"; import "react-native-get-random-values"; import { RouteContext } from "../context/routes/RouteContext"; import NewClass from "./newClass"; import NewTask from "./newTask"; import NewTerm from "./newTerm"; import { ClassContext } from "../context/storage/classes/classContext"; import { TaskContext } from "../context/storage/tasks/taskContext"; const globalStyles = require("../../../constants/globalstyles"); export default function ClassPage(props) { const { contextClasses, dispatch } = useContext(ClassContext); const { contextTasks, dispatch: taskDispatch } = useContext(TaskContext); const { route } = useContext(RouteContext); const { colors } = useTheme(); const [className, setClassName] = useState(""); const [classNum, setClassNum] = useState(""); const [roomNum, setRoomNum] = useState(""); const [college, setCollege] = useState(""); const [addDatesArr, setAddDatesArr] = useState([]); const resetClassState = () => { setClassName(""); setClassNum(""); setRoomNum(""); setCollege(""); setAddDatesArr([]); setClassInfoId(""); setClassFocusVis(false); setClassFocusInfoVis(false); setClassFocusDeleteWarning(false); }; const [selectedDay, setSelectedDay] = useState(); const [addDate, setAddDate] = useState(new Date()); const [addTimeStart, setAddTimeStart] = useState(new Date()); const [addTimeEnd, setAddTimeEnd] = useState(new Date()); const [addDateVisible, setAddDateVisible] = useState(false); const setDate = (e, date) => { if (date !== undefined) { setAddDate(date); } }; const setStartTime = (e, time) => { if (time !== undefined) { setAddTimeStart(time); } }; const setEndTime = (e, time) => { if (time !== undefined) { setAddTimeEnd(time); } }; const addToDateArr = () => { var classTime = { date: addDate, timeStart: addTimeStart, timeEnd: addTimeEnd, }; setAddDatesArr((addDatesArr) => [...addDatesArr, classTime]); setAddDate(new Date()); setStartTime(new Date()); setEndTime(new Date()); setAddDateVisible(false); }; const formatDay = (day) => { switch (day) { case 0: return "Sunday"; case 1: return "Monday"; case 2: return "Tuesday"; case 3: return "Wednesday"; case 4: return "Thursday"; case 5: return "Friday"; case 6: return "Saturday"; } }; const formatTime = (time) => { if (time.getHours() == 0 || time.getHours() < 12) { return time.getHours() + ":" + time.getMinutes() + "AM"; } else { return time.getHours() - 12 + ":" + time.getMinutes() + "PM"; } }; const [classFocusVis, setClassFocusVis] = useState(false); const [classInfoId, setClassInfoId] = useState(""); const [classFocusInfoVis, setClassFocusInfoVis] = useState(false); const [classFocusTasksVis, setClassFocusTasksVis] = useState(false); const [classFocusNotesVis, setClassFocusNotesVis] = useState(false); const [classFocusDeleteWarning, setClassFocusDeleteWarning] = useState(false); const getClassData = (id) => { Object.keys(contextClasses).forEach((key) => { if (contextClasses[key]["id"] === id) { console.log("class with id", contextClasses[key]["id"], "opened!"); setClassName(contextClasses[key]["className"]); setClassNum(contextClasses[key]["classNum"]); setRoomNum(contextClasses[key]["roomNum"]); setCollege(contextClasses[key]["college"]); setClassInfoId(id); if (contextClasses[key]["classTimes"]) { setAddDatesArr(contextClasses[key]["classTimes"]); } setClassFocusVis(true); } }); }; const closeClassInfoModal = () => { resetClassState(); setFabVisible(true); }; const deleteClass = () => { dispatch({ type: "REMOVE_CLASS", id: classInfoId }); console.log("Deleted class with ID:", classInfoId); resetClassState(); setClassFocusDeleteWarning(false); closeClassInfoModal(); setFabVisible(true); }; const editClassInfo = async () => { try { const existingClasses = await AsyncStorage.getItem("classes"); let classes = JSON.parse(existingClasses); for (const property in classes) { if (classes[property]["id"] === classInfoId) { console.log(classes[property]["id"]); classes[property]["className"] = className; classes[property]["classNum"] = classNum; classes[property]["roomNum"] = roomNum; classes[property]["college"] = college; } } await AsyncStorage.setItem("classes", JSON.stringify(classes)).then( () => { resetClassState(); setClassFocusVis(false); setFabVisible(true); } ); } catch (e) { console.log(e); } }; const [fabOpened, setFabOpened] = useState(false); const [fabVisible, setFabVisible] = useState(true); const onFabChange = () => { if (!fabOpened) { console.log("opening fab!"); if (taskModalVis == true) { setTaskModalVis(false); } else if (classModalVis == true) { setClassModalVis(false); } else if (termModalVis == true) { setTermModalVis(false); } } else { console.log("closing fab!"); } }; //Show class FAB only on class route useEffect(() => { if (route != "classes") { setFabVisible(false); } else { setFabVisible(true); } }, [route]); const [taskModalVis, setTaskModalVis] = useState(false); const [classModalVis, setClassModalVis] = useState(false); const [termModalVis, setTermModalVis] = useState(false); return ( <> <SafeAreaView style={globalStyles.background}> <View style={globalStyles.container}> {contextClasses.length < 1 ? ( <View style={{ display: "flex", justifyContent: "center", height: "100%", alignItems: "center", marginBottom: 30, }} > <Text style={{ fontWeight: "bold", color: colors.dark, textAlign: "center", fontSize: 24, marginBottom: 20, }} > You currently do not have any classes added. </Text> <Text style={{ fontWeight: "bold", color: colors.dark, textAlign: "center", marginBottom: 50, }} > Click the plus button on the bottom to add a new class! </Text> </View> ) : ( Object.keys(contextClasses).map((key) => ( <TouchableOpacity style={styles.panel} onPress={() => getClassData(contextClasses[key]["id"])} key={contextClasses[key]["id"]} > <Text style={{ fontSize: 18 }}> {contextClasses[key]["className"]} </Text> </TouchableOpacity> )) )} </View> </SafeAreaView> <NewTask shown={taskModalVis} /> <NewClass shown={classModalVis} /> <NewTerm shown={termModalVis} /> <Modal isVisible={classFocusVis} avoidKeyboard={true} hasBackdrop={true} backdropColor="black" style={{ margin: 0, }} > <View style={{ flex: 1, justifyContent: "center", marginHorizontal: 25, }} > <View style={{ justifyContent: "center", flexDirection: "row", paddingHorizontal: 16, paddingVertical: 12, alignItems: "baseline", borderColor: colors.secondaryDarker, borderBottomWidth: 1, backgroundColor: colors.primary, borderTopLeftRadius: 20, borderTopRightRadius: 20, }} > {!classFocusDeleteWarning && !classFocusInfoVis && !classFocusTasksVis && !classFocusNotesVis ? ( <TouchableOpacity onPress={() => { Keyboard.dismiss(); closeClassInfoModal(); }} style={{ marginRight: "auto" }} > <Text style={{ width: 50, fontSize: 16, color: colors.light, fontWeight: "500", }} > Close </Text> </TouchableOpacity> ) : ( <> <TouchableOpacity onPress={() => { Keyboard.dismiss(); classFocusInfoVis ? setClassFocusInfoVis(false) : classFocusNotesVis ? setClassFocusNotesVis(false) : classFocusTasksVis ? setClassFocusTasksVis(false) : setClassFocusDeleteWarning(false); }} style={{ marginRight: "auto" }} > <Text style={{ width: 50, fontSize: 16, color: colors.light, fontWeight: "500", }} > Back </Text> </TouchableOpacity> </> )} <View style={{ marginRight: "auto" }}> <Text style={{ color: colors.light, fontSize: 20, fontWeight: "600", position: "relative", margin: "auto", left: -25, }} > {className} </Text> </View> </View> <View style={{ backgroundColor: "#fff", paddingHorizontal: 16, paddingVertical: 12, paddingBottom: 16, display: "flex", borderBottomRightRadius: 20, borderBottomLeftRadius: 20, }} > {!classFocusDeleteWarning && !classFocusInfoVis && !classFocusTasksVis && !classFocusNotesVis ? ( <View> <TouchableOpacity style={{ display: "flex", flexDirection: "row", justifyContent: "center", backgroundColor: colors.secondary, padding: 12, borderRadius: 10, marginBottom: 10, }} onPress={() => { setClassFocusInfoVis(true); }} > <Text style={{ fontWeight: "500" }}>CLASS INFO</Text> </TouchableOpacity> <TouchableOpacity style={{ display: "flex", flexDirection: "row", justifyContent: "center", backgroundColor: colors.secondary, padding: 12, borderRadius: 10, marginBottom: 10, }} onPress={() => { setClassFocusTasksVis(true); }} > <Text style={{ fontWeight: "500" }}>TASKS</Text> </TouchableOpacity> <TouchableOpacity style={{ display: "flex", flexDirection: "row", justifyContent: "center", backgroundColor: colors.secondary, padding: 12, borderRadius: 10, marginBottom: 10, }} onPress={() => { setClassFocusNotesVis(true); }} > <Text style={{ fontWeight: "500" }}>NOTES</Text> </TouchableOpacity> <Button icon="minus-circle" mode="contained" onPress={() => { setClassFocusDeleteWarning(true); }} color="#e35053" > <Text>Delete Class</Text> </Button> </View> ) : ( <> {classFocusInfoVis && ( <> <View style={{ borderBottomWidth: 1.5, borderColor: colors.primary, paddingBottom: 4, }} > <Text style={{ fontSize: 18, fontWeight: "600", letterSpacing: 1, }} > INFO </Text> </View> <View style={{ display: "flex", flexDirection: "column", marginTop: 8, }} > <View style={{ display: "flex", marginBottom: 12, padding: 6, borderRadius: 8, backgroundColor: colors.light, }} > <Text style={{ fontWeight: "bold", fontSize: 16, marginBottom: 2, color: colors.primary, }} > Class Number </Text> <Input value={classNum} onChangeText={(text) => { setClassNum(text); }} style={{ color: colors.dark }} /> </View> <View style={{ display: "flex", marginBottom: 12, padding: 6, borderRadius: 8, backgroundColor: colors.light, }} > <Text style={{ fontWeight: "bold", fontSize: 16, marginBottom: 2, color: colors.primary, }} > Room Number </Text> <Input value={roomNum} onChangeText={(text) => { setRoomNum(text); }} style={{ color: colors.dark }} /> </View> <View style={{ display: "flex", marginBottom: 12, padding: 6, borderRadius: 8, backgroundColor: colors.light, }} > <Text style={{ fontWeight: "bold", fontSize: 16, marginBottom: 2, color: colors.primary, }} > College </Text> <Input value={college} onChangeText={(text) => { setCollege(text); }} style={{ color: colors.dark }} /> </View> </View> <View> <Text style={{ color: colors.primary, fontWeight: "bold", marginBottom: 2, marginLeft: 1, }} > Class Times </Text> {addDatesArr.map((datetime) => ( <View style={{ backgroundColor: colors.light, display: "flex", flexDirection: "row", justifyContent: "space-between", marginBottom: 4, padding: 8, borderRadius: 8, }} > <View style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", alignItems: "center", }} > <Text>Every</Text> <Text style={{ marginLeft: 4, color: colors.primary, fontWeight: "bold", }} > {formatDay(new Date(datetime["date"]).getDay())} </Text> </View> <View style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", }} > <Text style={{ color: colors.primary, fontWeight: "bold", }} > {new Date( datetime["timeStart"] ).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", })} </Text> <Text style={{ marginHorizontal: 2, fontWeight: "bold", }} > - </Text> <Text style={{ color: colors.primary, fontWeight: "bold", }} > {new Date(datetime["timeEnd"]).toLocaleTimeString( [], { hour: "2-digit", minute: "2-digit", } )} </Text> </View> </View> ))} </View> </> )} {classFocusNotesVis && ( <View style={{ borderBottomWidth: 1.5, borderColor: colors.primary, paddingBottom: 4, }} > <Text style={{ fontSize: 18, fontWeight: "600", letterSpacing: 1, }} > NOTES </Text> <View style={{ display: "flex", flexDirection: "row", alignItems: "center", marginLeft: 1, }} > <Text style={{ fontWeight: "300" }}> What's on your mind? </Text> </View> </View> )} {classFocusTasksVis && ( <View> <View style={{ borderBottomWidth: 1.5, borderColor: colors.primary, paddingBottom: 4, }} > <Text style={{ fontSize: 18, fontWeight: "600", letterSpacing: 1, }} > TASKS </Text> <View style={{ display: "flex", flexDirection: "row", alignItems: "center", marginLeft: 1, }} > <Text style={{ fontWeight: "300" }}> Tasks with the tag{" "} </Text> <Text style={{ color: colors.primary, fontWeight: "500", }} > {className} </Text> <Text style={{ fontWeight: "300" }}> {" "} will appear here. </Text> </View> </View> <View style={{ marginTop: 12 }}> {Object.keys(contextTasks).map((key) => Object.keys( contextTasks[key]["taskTags"]["classTags"] ).map((className) => { if ( contextTasks[key]["taskTags"]["classTags"][ className ] == classInfoId ) { return ( <View style={{ backgroundColor: colors.light, padding: 8, marginBottom: 8, }} > <Text style={{ color: colors.dark, fontWeight: "500", }} > {contextTasks[key]["taskName"]} </Text> </View> ); } }) )} </View> </View> )} {classFocusDeleteWarning && ( <> <View style={{ borderBottomWidth: 1.5, borderColor: colors.primary, paddingBottom: 4, }} > <Text style={{ fontSize: 18, fontWeight: "600", letterSpacing: 1, }} > DELETING {className} </Text> <View style={{ display: "flex", marginLeft: 1, }} > <Text style={{ fontWeight: "300" }}>Are you sure?</Text> </View> </View> <View style={{ marginLeft: 1 }}> <Text style={{ marginTop: 4, color: colors.dark }}> Please note that this action is permenent and cannot be undone. </Text> <Text style={{ marginTop: 4, color: colors.dark }}> Additionally, any tags associated with this class will be removed from tasks. </Text> <Button mode="contained" onPress={() => { setClassFocusDeleteWarning(false); }} color="#fff" labelStyle={{ color: colors.primary }} style={{ marginVertical: 10 }} > Take me back! </Button> <Button mode="contained" onPress={() => { deleteClass(); }} color="#fff" labelStyle={{ color: "#e01e37" }} > Confirm and Delete </Button> </View> </> )} </> )} </View> </View> </Modal> <Portal> <FAB.Group open={fabOpened} icon={"plus"} actions={[ { icon: "pencil", label: "New Task", onPress: () => { setTaskModalVis(true); setFabOpened(false); }, style: { marginRight: 8 }, }, { icon: "google-classroom", label: "Add Class", onPress: () => { setClassModalVis(true); setFabOpened(false); }, style: { marginRight: 8 }, }, { icon: "school", label: "New Term", onPress: () => { setTermModalVis(true); setFabOpened(false); }, style: { marginRight: 8 }, }, ]} onStateChange={onFabChange} onPress={() => { setFabOpened(!fabOpened); }} fabStyle={{ backgroundColor: colors.primary, marginBottom: 70, marginRight: 25, }} visible={fabVisible} /> </Portal> </> ); } const styles = StyleSheet.create({ panel: { display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center", textAlign: "center", fontWeight: "normal", backgroundColor: "#fff", paddingTop: 15, paddingBottom: 15, marginBottom: 12, marginTop: 4, marginRight: 4, marginLeft: 4, borderRadius: 10, }, });