Files
cally/components/pages/todos/ToDosList.tsx
2024-11-17 20:24:01 +01:00

349 lines
9.8 KiB
TypeScript

import {Text, TouchableOpacity, View} from "react-native-ui-lib";
import React, {useEffect, useState} from "react";
import {useToDosContext} from "@/contexts/ToDosContext";
import ToDoItem from "./ToDoItem";
import {addDays, format, isToday, isTomorrow, isWithinInterval,} from "date-fns";
import {AntDesign} from "@expo/vector-icons";
import {IToDo} from "@/hooks/firebase/types/todoData";
import DropdownIcon from "@/assets/svgs/DropdownIcon";
import {Dropdown} from "react-native-element-dropdown";
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
import {StyleSheet} from "react-native";
const groupToDosByDate = (toDos: IToDo[]) => {
let sortedTodos = toDos.sort((a, b) => a.date - b.date);
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 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";
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[] };
};
}
);
};
const resolveFilterOptions = (members, user) => {
return members?.map((member) => {
let label = member?.firstName;
if (member.uid === user?.uid) {
label = "Me";
}
return (member.uid !== user?.uid || member.profileType !== ProfileType.PARENT) && {value: member?.uid, label: label};
});
}
const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
const { toDos } = useToDosContext();
const [groupedToDos, setGroupedToDos] = useState([]);
const { user } = useAuthContext()
const { data: members } = useGetFamilyMembers();
const [expandedGroups, setExpandedGroups] = useState<{
[key: string]: boolean;
}>({});
const [expandNoDate, setExpandNoDate] = useState<boolean>(true);
const [selectedFilter, setSelectedFilter] = useState(null);
const [filterOptions, setFilterOptions] = useState([]);
useEffect(() => {
let options = resolveFilterOptions(members, user);
setFilterOptions(options);
let selectedOption = options?.find((option) => option.value === user?.uid);
setSelectedFilter(selectedOption);
}, []);
useEffect(() => {
if (toDos && selectedFilter) {
let filtered = toDos?.filter((todo) => todo.creatorId === selectedFilter.value);
let filteredGroupedTodos = groupToDosByDate(filtered || []);
setGroupedToDos(filteredGroupedTodos || []);
}
}, [selectedFilter]);
console.log("MEMBERS");
console.log(members);
const toggleExpand = (dateKey: string) => {
setExpandedGroups((prev) => ({
...prev,
[dateKey]: !prev[dateKey],
}));
};
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 (
<View key={dateKey}>
<TouchableOpacity
onPress={() => toggleExpand(dateKey)}
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: 0,
marginBottom: 4,
marginTop: 15,
}}
>
<Text
style={{
fontFamily: "Manrope_700Bold",
fontSize: 15,
color: "#484848",
}}
>
{dateKey}
</Text>
<AntDesign
name={isExpanded ? "caretdown" : "caretright"}
size={24}
color="#fd1575"
/>
</TouchableOpacity>
{isExpanded &&
subgroups.map(([subDate, items]) => {
const sortedItems = [
...items.filter((toDo) => !toDo.done),
...items.filter((toDo) => toDo.done),
];
return (
<View key={subDate} marginT-15>
<View
style={{
marginBottom: 8,
}}
>
<Text
style={{
fontFamily: "Manrope_600SemiBold",
fontSize: 14,
color: "#919191",
}}
>
{subDate}
</Text>
</View>
{sortedItems.map((item) => (
<ToDoItem
isSettings={isSettings}
key={item.id}
item={item}
is7Days={false}
/>
))}
</View>
);
})}
</View>
);
}
const sortedToDos = [
...groupedToDos[dateKey].items.filter((toDo) => !toDo.done),
...groupedToDos[dateKey].items.filter((toDo) => toDo.done),
];
return (
<View key={dateKey}>
<TouchableOpacity
onPress={() => toggleExpand(dateKey)}
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: 0,
marginBottom: 4,
marginTop: 15,
}}
>
<Text
style={{
fontFamily: "Manrope_700Bold",
fontSize: 15,
color: "#484848",
}}
>
{dateKey}
</Text>
<AntDesign
name={isExpanded ? "caretdown" : "caretright"}
size={24}
color="#fd1575"
/>
</TouchableOpacity>
{isExpanded &&
sortedToDos.map((item) => (
<ToDoItem
isSettings={isSettings}
key={item.id}
item={item}
is7Days={dateKey === "Next 7 Days"}
/>
))}
</View>
);
};
return (
<View marginB-402>
<Dropdown
style={{ marginBottom: 15 }}
data={filterOptions}
value={selectedFilter}
placeholder="Filter todos"
placeholderStyle={{
color: "#a2a2a2",
fontFamily: "Manrope_500Medium",
fontSize: 13.2,
}}
labelField="label"
valueField="value"
iconColor="white"
activeColor={"#fd1775"}
containerStyle={styles.dropdownStyle}
itemTextStyle={styles.itemText}
itemContainerStyle={styles.itemStyle}
selectedTextStyle={styles.selectedText}
renderLeftIcon={() => (
<DropdownIcon
style={{ marginRight: 8 }}
/>
)}
renderItem={(item) => {
return (
<View height={36.02} centerV>
<Text style={styles.itemText}>{item.label}</Text>
</View>
);
}}
onChange={(item) => {
setSelectedFilter(item);
}}
/>
{noDateToDos.length > 0 && (
<View key="No Date">
<View row spread paddingH-19 marginB-12>
<Text
text70
style={{
fontWeight: "bold",
}}
>
Unscheduled
</Text>
<AntDesign
name={expandNoDate ? "caretdown" : "caretright"}
size={24}
color="#fd1575"
onPress={() => {
setExpandNoDate(!expandNoDate);
}}
/>
</View>
{expandNoDate &&
noDateToDos
.sort((a, b) => Number(a.done) - Number(b.done))
.map((item) => (
<ToDoItem isSettings={isSettings} key={item.id} item={item} />
))}
</View>
)}
{datedToDos.map(renderTodoGroup)}
</View>
);
};
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: "100%", width: 187 },
itemStyle: { padding: 0, margin: 0 },
});
export default ToDosList;