diff --git a/assets/svgs/PlusIcon.tsx b/assets/svgs/PlusIcon.tsx
new file mode 100644
index 0000000..5e9af64
--- /dev/null
+++ b/assets/svgs/PlusIcon.tsx
@@ -0,0 +1,19 @@
+import * as React from "react";
+import Svg, { SvgProps, Path } from "react-native-svg";
+const PlusIcon = (props: SvgProps) => (
+
+);
+export default PlusIcon;
diff --git a/components/pages/brain_dump/BrainDumpPage.tsx b/components/pages/brain_dump/BrainDumpPage.tsx
index 979e9c9..98782c5 100644
--- a/components/pages/brain_dump/BrainDumpPage.tsx
+++ b/components/pages/brain_dump/BrainDumpPage.tsx
@@ -6,6 +6,7 @@ import HeaderTemplate from "@/components/shared/HeaderTemplate";
import {Feather, MaterialIcons} from "@expo/vector-icons";
import AddBrainDump from "./AddBrainDump";
import LinearGradient from "react-native-linear-gradient";
+import PlusIcon from "@/assets/svgs/PlusIcon";
const BrainDumpPage = () => {
const [searchText, setSearchText] = useState("");
@@ -85,10 +86,10 @@ const BrainDumpPage = () => {
}}
>
-
+
New
diff --git a/components/pages/calendar/AddEventDialog.tsx b/components/pages/calendar/AddEventDialog.tsx
index def5322..1eab83d 100644
--- a/components/pages/calendar/AddEventDialog.tsx
+++ b/components/pages/calendar/AddEventDialog.tsx
@@ -10,6 +10,7 @@ import CalendarIcon from "@/assets/svgs/CalendarIcon";
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
import {useSetAtom} from "jotai";
import {selectedNewEventDateAtom} from "@/components/pages/calendar/atoms";
+import PlusIcon from "@/assets/svgs/PlusIcon";
export const AddEventDialog = () => {
const [show, setShow] = useState(false);
@@ -50,8 +51,8 @@ export const AddEventDialog = () => {
onPress={() => setShow(true)}
>
-
-
+
+
New
diff --git a/components/pages/calendar/ManuallyAddEventModal.tsx b/components/pages/calendar/ManuallyAddEventModal.tsx
index 888ec2f..326f4e2 100644
--- a/components/pages/calendar/ManuallyAddEventModal.tsx
+++ b/components/pages/calendar/ManuallyAddEventModal.tsx
@@ -383,10 +383,6 @@ export const ManuallyAddEventModal = () => {
onChange={(time) => {
if (time <= endTime) {
setStartTime(time);
- } else {
- const currentTime = new Date();
- currentTime.setSeconds(0, 0);
- setStartTime(currentTime);
}
}}
minuteInterval={5}
@@ -428,10 +424,6 @@ export const ManuallyAddEventModal = () => {
onChange={(time) => {
if (time >= endTime) {
setEndTime(time);
- } else {
- const currentTime = new Date();
- currentTime.setSeconds(0, 0);
- setEndTime(currentTime);
}
}}
minimumDate={startTime}
diff --git a/components/pages/grocery/AddGroceryItem.tsx b/components/pages/grocery/AddGroceryItem.tsx
index 5304a7a..ec5c7f2 100644
--- a/components/pages/grocery/AddGroceryItem.tsx
+++ b/components/pages/grocery/AddGroceryItem.tsx
@@ -3,6 +3,7 @@ import React from "react";
import {Button, View,} from "react-native-ui-lib";
import {useGroceryContext} from "@/contexts/GroceryContext";
import {FontAwesome6} from "@expo/vector-icons";
+import PlusIcon from "@/assets/svgs/PlusIcon";
const AddGroceryItem = () => {
const {setIsAddingGrocery} = useGroceryContext();
@@ -11,12 +12,12 @@ const AddGroceryItem = () => {
@@ -25,7 +26,7 @@ const AddGroceryItem = () => {
backgroundColor="#fd1775"
label="Add item"
text70L
- iconSource={() => }
+ iconSource={() => }
style={styles.finishShopBtn}
labelStyle={styles.addBtnLbl}
enableShadow
@@ -69,6 +70,7 @@ const styles = StyleSheet.create({
},
finishShopBtn: {
width: "100%",
+ height: 53.26,
},
shoppingBtn: {
flex: 1,
diff --git a/components/pages/grocery/EditGroceryItem.tsx b/components/pages/grocery/EditGroceryItem.tsx
index 0aecb91..812e98d 100644
--- a/components/pages/grocery/EditGroceryItem.tsx
+++ b/components/pages/grocery/EditGroceryItem.tsx
@@ -1,167 +1,204 @@
-import {Text, TextField, TextFieldRef, View} from "react-native-ui-lib";
-import React, {useEffect, useRef} from "react";
-import {GroceryCategory, useGroceryContext} from "@/contexts/GroceryContext";
-import {Dropdown} from "react-native-element-dropdown";
+import { Text, TextField, TextFieldRef, View } from "react-native-ui-lib";
+import React, { useEffect, useRef } from "react";
+import { GroceryCategory, useGroceryContext } from "@/contexts/GroceryContext";
+import { Dropdown } from "react-native-element-dropdown";
import CloseXIcon from "@/assets/svgs/CloseXIcon";
-import {StyleSheet} from "react-native";
+import { findNodeHandle, StyleSheet, UIManager } from "react-native";
import DropdownIcon from "@/assets/svgs/DropdownIcon";
-import {AntDesign} from "@expo/vector-icons";
+import { AntDesign } from "@expo/vector-icons";
interface IEditGrocery {
- id?: string;
- title: string;
- category: GroceryCategory;
- setTitle: (value: string) => void;
- setCategory?: (category: GroceryCategory) => void;
- setSubmit?: (value: boolean) => void;
- closeEdit?: () => void;
- handleEditSubmit?: Function;
+ id?: string;
+ title: string;
+ category: GroceryCategory;
+ setTitle: (value: string) => void;
+ setCategory?: (category: GroceryCategory) => void;
+ setSubmit?: (value: boolean) => void;
+ closeEdit?: () => void;
+ handleEditSubmit?: Function;
}
+const EditGroceryItem = ({
+ editGrocery,
+ onInputFocus,
+}: {
+ editGrocery: IEditGrocery;
+ onInputFocus: (y: number) => void;
+}) => {
+ const { fuzzyMatchGroceryCategory } = useGroceryContext();
+ const inputRef = useRef(null);
+ const containerRef = useRef(null);
-const EditGroceryItem = ({editGrocery}: { editGrocery: IEditGrocery }) => {
- const {fuzzyMatchGroceryCategory} = useGroceryContext();
- const inputRef = useRef(null);
+ const handleFocus = () => {
+ if (containerRef.current) {
+ const handle = findNodeHandle(containerRef.current);
+ if (handle) {
+ UIManager.measure(
+ handle,
+ (
+ x: number,
+ y: number,
+ width: number,
+ height: number,
+ pageX: number,
+ pageY: number
+ ) => {
+ onInputFocus(pageY);
+ }
+ );
+ }
+ }
+ };
- const groceryCategoryOptions = Object.values(GroceryCategory).map(
- (category) => ({
- label: category,
- value: category,
- })
- );
+ const groceryCategoryOptions = Object.values(GroceryCategory).map(
+ (category) => ({
+ label: category,
+ value: category,
+ })
+ );
- const handleSubmit = () => {
- inputRef?.current?.blur()
- console.log("CALLLLLL")
- if (editGrocery.setSubmit) {
- editGrocery.setSubmit(true);
- }
- if (editGrocery.handleEditSubmit) {
- editGrocery.handleEditSubmit({
- id: editGrocery.id,
- title: editGrocery.title,
- category: editGrocery.category,
- });
- }
- if (editGrocery.closeEdit) {
- editGrocery.closeEdit();
- }
+ const handleSubmit = () => {
+ inputRef?.current?.blur();
+ console.log("CALLLLLL");
+ if (editGrocery.setSubmit) {
+ editGrocery.setSubmit(true);
+ }
+ if (editGrocery.handleEditSubmit) {
+ editGrocery.handleEditSubmit({
+ id: editGrocery.id,
+ title: editGrocery.title,
+ category: editGrocery.category,
+ });
+ }
+ if (editGrocery.closeEdit) {
+ editGrocery.closeEdit();
+ }
+ };
+
+ useEffect(() => {
+ if (inputRef.current) {
+ inputRef.current.focus();
}
- useEffect(() => {
- if (inputRef.current) {
- inputRef.current.focus();
- }
+ console.log(editGrocery.category);
+ }, []);
- console.log(editGrocery.category);
- }, []);
-
- return (
-
+
+ {
+ editGrocery.setTitle(value);
+ let groceryCategory = fuzzyMatchGroceryCategory(value);
+ if (editGrocery.setCategory) {
+ editGrocery.setCategory(groceryCategory);
+ }
+ }}
+ maxLength={25}
+ />
+
+
-
- {
- editGrocery.setTitle(value);
- let groceryCategory = fuzzyMatchGroceryCategory(value);
- if (editGrocery.setCategory) {
- editGrocery.setCategory(groceryCategory);
- }
- }}
- maxLength={25}
- />
-
-
- {
- if (editGrocery.closeEdit) {
- editGrocery.closeEdit();
- }
- }}
- />
-
-
- (
-
- )}
- renderItem={(item) => {
- return (
-
- {item.label}
-
- );
- }}
- onChange={(item) => {
- if (editGrocery.handleEditSubmit) {
- editGrocery.handleEditSubmit({
- id: editGrocery.id,
- category: item.value,
- });
- if (editGrocery.closeEdit) editGrocery.closeEdit();
- } else {
- if (editGrocery.setCategory) {
- editGrocery.setCategory(item.value);
- }
- }
- }}
- />
+ onPress={handleSubmit}
+ />
+ {
+ if (editGrocery.closeEdit) {
+ editGrocery.closeEdit();
+ }
+ }}
+ />
- );
+
+ (
+
+ )}
+ renderItem={(item) => {
+ return (
+
+ {item.label}
+
+ );
+ }}
+ onChange={(item) => {
+ if (editGrocery.handleEditSubmit) {
+ editGrocery.handleEditSubmit({
+ id: editGrocery.id,
+ category: item.value,
+ });
+ if (editGrocery.closeEdit) editGrocery.closeEdit();
+ } else {
+ if (editGrocery.setCategory) {
+ editGrocery.setCategory(item.value);
+ }
+ }
+ }}
+ />
+
+ );
};
const styles = StyleSheet.create({
- itemText: {
- fontFamily: "Manrope_400Regular",
- fontSize: 15.42,
- paddingLeft: 15,
- },
- selectedText: {
- fontFamily: "Manrope_500Medium",
- fontSize: 13.2,
- color: "#fd1775",
- },
- dropdownStyle: {borderRadius: 6.61, height: 115.34, width: 187},
- itemStyle: {padding: 0, margin: 0},
+ itemText: {
+ fontFamily: "Manrope_400Regular",
+ fontSize: 15.42,
+ paddingLeft: 15,
+ },
+ selectedText: {
+ fontFamily: "Manrope_500Medium",
+ fontSize: 13.2,
+ color: "#fd1775",
+ },
+ dropdownStyle: { borderRadius: 6.61, height: 115.34, width: 187 },
+ itemStyle: { padding: 0, margin: 0 },
});
export default EditGroceryItem;
diff --git a/components/pages/grocery/GroceryItem.tsx b/components/pages/grocery/GroceryItem.tsx
index e521e44..45427f6 100644
--- a/components/pages/grocery/GroceryItem.tsx
+++ b/components/pages/grocery/GroceryItem.tsx
@@ -1,21 +1,23 @@
-import {Checkbox, Text, TouchableOpacity, View} from "react-native-ui-lib";
-import React, {useEffect, useState} from "react";
-import {AntDesign} from "@expo/vector-icons";
-import {GroceryCategory, useGroceryContext} from "@/contexts/GroceryContext";
+import { Checkbox, Text, TouchableOpacity, View } from "react-native-ui-lib";
+import React, { useEffect, useState } from "react";
+import { AntDesign } from "@expo/vector-icons";
+import { GroceryCategory, useGroceryContext } from "@/contexts/GroceryContext";
import EditGroceryFrequency from "./EditGroceryFrequency";
import EditGroceryItem from "./EditGroceryItem";
-import {ImageBackground, StyleSheet} from "react-native";
-import {IGrocery} from "@/hooks/firebase/types/groceryData";
+import { ImageBackground, StyleSheet } from "react-native";
+import { IGrocery } from "@/hooks/firebase/types/groceryData";
import firestore from "@react-native-firebase/firestore";
-import {UserProfile} from "@/hooks/firebase/types/profileTypes";
-import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
+import { UserProfile } from "@/hooks/firebase/types/profileTypes";
+import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
const GroceryItem = ({
item,
handleItemApproved,
+ onInputFocus,
}: {
item: IGrocery;
handleItemApproved: (id: string, changes: Partial) => void;
+ onInputFocus: (y: number) => void;
}) => {
const { updateGroceryItem } = useGroceryContext();
const { profileData } = useAuthContext();
@@ -24,12 +26,14 @@ const GroceryItem = ({
const [openFreqEdit, setOpenFreqEdit] = useState(false);
const [isEditingTitle, setIsEditingTitle] = useState(false);
const [newTitle, setNewTitle] = useState(item.title ?? "");
- const [category, setCategory] = useState(item.category ?? GroceryCategory.None);
+ const [category, setCategory] = useState(
+ item.category ?? GroceryCategory.None
+ );
const [itemCreator, setItemCreator] = useState(null);
const closeEdit = () => {
setIsEditingTitle(false);
- }
+ };
const handleTitleChange = (newTitle: string) => {
updateGroceryItem({ id: item?.id, title: newTitle });
@@ -82,57 +86,70 @@ const GroceryItem = ({
setOpenFreqEdit(false);
}}
/>
- {isEditingTitle ?
- :
-
- {isParent ?
- setIsEditingTitle(true)}>
-
- {item.title}
-
- :
+ {isEditingTitle ? (
+
+ ) : (
+
+ {isParent ? (
+ setIsEditingTitle(true)}>
{item.title}
- }
-
- }
+
+ ) : (
+
+ {item.title}
+
+ )}
+
+ )}
{!item.approved ? (
- {isParent &&
- <>
- handleItemApproved(item.id, { approved: true }) : null}
- />
- handleItemApproved(item.id, { approved: false }) : null}
- />
- >}
+ {isParent && (
+ <>
+ handleItemApproved(item.id, { approved: true })
+ : null
+ }
+ />
+ handleItemApproved(item.id, { approved: false })
+ : null
+ }
+ />
+ >
+ )}
) : (
- !isEditingTitle && isParent && (
+ !isEditingTitle &&
+ isParent && (
- {profileData?.pfp ? :
+ />
+ ) : (
-
-
- {itemCreator ? getInitials(itemCreator.firstName, itemCreator.lastName) : ""}
-
+
+ {itemCreator
+ ? getInitials(itemCreator.firstName, itemCreator.lastName)
+ : ""}
+
+
- }
+ )}
Requested by {itemCreator?.firstName}
diff --git a/components/pages/grocery/GroceryList.tsx b/components/pages/grocery/GroceryList.tsx
index 7c495b7..b6ec6da 100644
--- a/components/pages/grocery/GroceryList.tsx
+++ b/components/pages/grocery/GroceryList.tsx
@@ -10,7 +10,7 @@ import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
import {IGrocery} from "@/hooks/firebase/types/groceryData";
import AddPersonIcon from "@/assets/svgs/AddPersonIcon";
-const GroceryList = () => {
+const GroceryList = ({onInputFocus}: {onInputFocus: (y: number) => void}) => {
const {
groceries,
updateGroceryItem,
@@ -169,6 +169,7 @@ const GroceryList = () => {
handleItemApproved={(id, changes) =>
updateGroceryItem({...changes, id: id})
}
+ onInputFocus={onInputFocus}
/>
)}
keyExtractor={(item) => item.id.toString()}
@@ -230,6 +231,7 @@ const GroceryList = () => {
setSubmit: setSubmitted,
closeEdit: () => setIsAddingGrocery(false)
}}
+ onInputFocus={onInputFocus}
/>
)}
@@ -254,6 +256,7 @@ const GroceryList = () => {
handleItemApproved={(id, changes) =>
updateGroceryItem({...changes, id: id})
}
+ onInputFocus={onInputFocus}
/>
)
)}
diff --git a/components/pages/grocery/GroceryWrapper.tsx b/components/pages/grocery/GroceryWrapper.tsx
index fd91bd3..b93db37 100644
--- a/components/pages/grocery/GroceryWrapper.tsx
+++ b/components/pages/grocery/GroceryWrapper.tsx
@@ -1,42 +1,79 @@
-import { Dimensions, ScrollView } from "react-native";
+import { Dimensions, ScrollView, Keyboard, Platform } from "react-native";
import { View } from "react-native-ui-lib";
-import React, { useEffect, useRef } from "react";
+import React, { useEffect, useRef, useState } from "react";
import AddGroceryItem from "./AddGroceryItem";
import GroceryList from "./GroceryList";
import { useGroceryContext } from "@/contexts/GroceryContext";
const GroceryWrapper = () => {
const { isAddingGrocery } = useGroceryContext();
- const scrollViewRef = useRef(null); // Reference to the ScrollView
+ const scrollViewRef = useRef(null);
+ const [keyboardHeight, setKeyboardHeight] = useState(0);
+
+ useEffect(() => {
+ const keyboardWillShowListener = Keyboard.addListener(
+ Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow',
+ (e) => {
+ setKeyboardHeight(e.endCoordinates.height);
+ }
+ );
+
+ const keyboardWillHideListener = Keyboard.addListener(
+ Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide',
+ () => {
+ setKeyboardHeight(0);
+ }
+ );
+
+ return () => {
+ keyboardWillShowListener.remove();
+ keyboardWillHideListener.remove();
+ };
+ }, []);
useEffect(() => {
if (isAddingGrocery && scrollViewRef.current) {
scrollViewRef.current.scrollTo({
- y: 400, // Adjust this value to scroll a bit down (100 is an example)
+ y: 400,
animated: true,
});
}
}, [isAddingGrocery]);
+ const handleInputFocus = (y: number) => {
+ if (scrollViewRef.current) {
+ // Get the window height
+ const windowHeight = Dimensions.get('window').height;
+ // Calculate the space we want to leave at the top
+ const topSpacing = 20;
+
+ // Calculate the target scroll position:
+ // y (position of input) - topSpacing (space we want at top)
+ // if keyboard is shown, we need to account for its height
+ const scrollPosition = Math.max(0, y - topSpacing);
+
+ scrollViewRef.current.scrollTo({
+ y: scrollPosition,
+ animated: true,
+ });
+ }
+ };
+
return (
-
-
-
-
-
-
-
-
-
-
+ <>
+
+
+
+
+
{!isAddingGrocery && }
-
+ >
);
};
-export default GroceryWrapper;
+export default GroceryWrapper;
\ No newline at end of file
diff --git a/components/pages/todos/AddChore.tsx b/components/pages/todos/AddChore.tsx
index 4ba3fc8..0c66e8e 100644
--- a/components/pages/todos/AddChore.tsx
+++ b/components/pages/todos/AddChore.tsx
@@ -1,38 +1,46 @@
-import { StyleSheet } from "react-native";
+import { Dimensions, StyleSheet } from "react-native";
import React, { useState } from "react";
import { Button, ButtonSize, Text, View } from "react-native-ui-lib";
import { AntDesign } from "@expo/vector-icons";
import LinearGradient from "react-native-linear-gradient";
import AddChoreDialog from "./AddChoreDialog";
+import PlusIcon from "@/assets/svgs/PlusIcon";
const AddChore = () => {
const [isVisible, setIsVisible] = useState(false);
return (
-
- {isVisible && }
-
+ {isVisible && (
+
+ )}
+
);
};
@@ -53,8 +61,7 @@ const styles = StyleSheet.create({
},
button: {
backgroundColor: "rgb(253, 23, 117)",
- paddingVertical: 15,
- paddingHorizontal: 30,
+ height: 53.26,
borderRadius: 30,
width: 335,
},
diff --git a/components/pages/todos/ToDoItem.tsx b/components/pages/todos/ToDoItem.tsx
index 7bc1446..55bb8c3 100644
--- a/components/pages/todos/ToDoItem.tsx
+++ b/components/pages/todos/ToDoItem.tsx
@@ -17,8 +17,13 @@ import AddChoreDialog from "@/components/pages/todos/AddChoreDialog";
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
import RepeatIcon from "@/assets/svgs/RepeatIcon";
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
+import { format } from "date-fns";
-const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
+const ToDoItem = (props: {
+ item: IToDo;
+ isSettings?: boolean;
+ is7Days?: boolean;
+}) => {
const { updateToDo } = useToDosContext();
const { data: members } = useGetFamilyMembers();
const { profileData } = useAuthContext();
@@ -55,6 +60,7 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
return (
{
return props.item.repeatType;
}
})()}
+ {props.item.date &&
+ props.is7Days &&
+ " / " + format(props.item.date, "EEEE")}
)}
diff --git a/components/pages/todos/ToDosList.tsx b/components/pages/todos/ToDosList.tsx
index 6589427..431c293 100644
--- a/components/pages/todos/ToDosList.tsx
+++ b/components/pages/todos/ToDosList.tsx
@@ -14,40 +14,64 @@ import { IToDo } from "@/hooks/firebase/types/todoData";
const groupToDosByDate = (toDos: IToDo[]) => {
let sortedTodos = toDos.sort((a, b) => a.date - b.date);
- return sortedTodos.reduce((groups, toDo) => {
- let dateKey;
+ return sortedTodos.reduce(
+ (groups, toDo) => {
+ let dateKey;
+ let subDateKey;
- const isNext7Days = (date: Date) => {
- const today = new Date();
- return isWithinInterval(date, { start: today, end: addDays(today, 7) });
- };
+ const isNext7Days = (date: Date) => {
+ const today = new Date();
+ return isWithinInterval(date, { start: today, end: addDays(today, 7) });
+ };
- const isNext30Days = (date: Date) => {
- const today = new Date();
- return isWithinInterval(date, { start: today, end: addDays(today, 30) });
- };
+ const isNext30Days = (date: Date) => {
+ const today = new Date();
+ return isWithinInterval(date, {
+ start: today,
+ end: addDays(today, 30),
+ });
+ };
- if (toDo.date === null) {
- dateKey = "No Date";
- } else if (isToday(toDo.date)) {
- dateKey = "Today";
- } else if (isTomorrow(toDo.date)) {
- dateKey = "Tomorrow";
- } else if (isNext7Days(toDo.date)) {
- dateKey = "Next 7 Days";
- } else if (isNext30Days(toDo.date)) {
- dateKey = "Next 30 Days";
- } else {
- dateKey = format(toDo.date, "EEE MMM dd");
+ if (toDo.date === null) {
+ dateKey = "No Date";
+ } else if (isToday(toDo.date)) {
+ dateKey = "Today";
+ } else if (isTomorrow(toDo.date)) {
+ dateKey = "Tomorrow";
+ } else if (isNext7Days(toDo.date)) {
+ dateKey = "Next 7 Days";
+ } else if (isNext30Days(toDo.date)) {
+ dateKey = "Next 30 Days";
+ subDateKey = format(toDo.date, "MMM d");
+ } else {
+ return groups;
+ }
+
+ if (!groups[dateKey]) {
+ groups[dateKey] = {
+ items: [],
+ subgroups: {},
+ };
+ }
+
+ if (dateKey === "Next 30 Days" && subDateKey) {
+ if (!groups[dateKey].subgroups[subDateKey]) {
+ groups[dateKey].subgroups[subDateKey] = [];
+ }
+ groups[dateKey].subgroups[subDateKey].push(toDo);
+ } else {
+ groups[dateKey].items.push(toDo);
+ }
+
+ return groups;
+ },
+ {} as {
+ [key: string]: {
+ items: IToDo[];
+ subgroups: { [key: string]: IToDo[] };
+ };
}
-
- if (!groups[dateKey]) {
- groups[dateKey] = [];
- }
-
- groups[dateKey].push(toDo);
- return groups;
- }, {} as { [key: string]: IToDo[] });
+ );
};
const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
@@ -67,11 +91,139 @@ const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
}));
};
- const noDateToDos = groupedToDos["No Date"] || [];
+ const noDateToDos = groupedToDos["No Date"]?.items || [];
const datedToDos = Object.keys(groupedToDos).filter(
(key) => key !== "No Date"
);
+ const renderTodoGroup = (dateKey: string) => {
+ const isExpanded = expandedGroups[dateKey] || false;
+
+ if (dateKey === "Next 30 Days") {
+ const subgroups = Object.entries(groupedToDos[dateKey].subgroups).sort(
+ ([dateA], [dateB]) => {
+ const dateAObj = new Date(dateA);
+ const dateBObj = new Date(dateB);
+ return dateAObj.getTime() - dateBObj.getTime();
+ }
+ );
+
+ return (
+
+ toggleExpand(dateKey)}
+ style={{
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+ paddingHorizontal: 0,
+ marginBottom: 4,
+ marginTop: 15,
+ }}
+ >
+
+ {dateKey}
+
+
+
+
+ {isExpanded &&
+ subgroups.map(([subDate, items]) => {
+ const sortedItems = [
+ ...items.filter((toDo) => !toDo.done),
+ ...items.filter((toDo) => toDo.done),
+ ];
+
+ return (
+
+
+
+ {subDate}
+
+
+
+ {sortedItems.map((item) => (
+
+ ))}
+
+ );
+ })}
+
+ );
+ }
+
+ const sortedToDos = [
+ ...groupedToDos[dateKey].items.filter((toDo) => !toDo.done),
+ ...groupedToDos[dateKey].items.filter((toDo) => toDo.done),
+ ];
+
+ return (
+
+ toggleExpand(dateKey)}
+ style={{
+ flexDirection: "row",
+ justifyContent: "space-between",
+ alignItems: "center",
+ paddingHorizontal: 0,
+ marginBottom: 4,
+ marginTop: 15,
+ }}
+ >
+
+ {dateKey}
+
+
+
+
+ {isExpanded &&
+ sortedToDos.map((item) => (
+
+ ))}
+
+ );
+ };
+
return (
{noDateToDos.length > 0 && (
@@ -85,26 +237,14 @@ const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
>
Unscheduled
- {!expandNoDate && (
- {
- setExpandNoDate(!expandNoDate);
- }}
- />
- )}
- {expandNoDate && (
- {
- setExpandNoDate(!expandNoDate);
- }}
- />
- )}
+ {
+ setExpandNoDate(!expandNoDate);
+ }}
+ />
{expandNoDate &&
noDateToDos
@@ -115,50 +255,7 @@ const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
)}
- {datedToDos.map((dateKey) => {
- const isExpanded = expandedGroups[dateKey] || false;
- const sortedToDos = [
- ...groupedToDos[dateKey].filter((toDo) => !toDo.done),
- ...groupedToDos[dateKey].filter((toDo) => toDo.done),
- ];
-
- return (
-
- toggleExpand(dateKey)}
- style={{
- flexDirection: "row",
- justifyContent: "space-between",
- alignItems: "center",
- paddingHorizontal: 0,
- marginBottom: 4,
- marginTop: 15,
- }}
- >
-
- {dateKey}
-
- {!isExpanded && (
-
- )}
- {isExpanded && (
-
- )}
-
-
- {isExpanded &&
- sortedToDos.map((item) => (
-
- ))}
-
- );
- })}
+ {datedToDos.map(renderTodoGroup)}
);
};
diff --git a/components/pages/todos/ToDosPage.tsx b/components/pages/todos/ToDosPage.tsx
index b8ab4c6..590a901 100644
--- a/components/pages/todos/ToDosPage.tsx
+++ b/components/pages/todos/ToDosPage.tsx
@@ -32,7 +32,6 @@ const ToDosPage = () => {
>