Merge branch 'dev'

This commit is contained in:
Milan Paunovic
2024-12-24 16:12:36 +01:00
13 changed files with 230 additions and 246 deletions

View File

@ -73,7 +73,7 @@ const AddBrainDump = ({
onPress={() => { onPress={() => {
addBrainDump({ addBrainDump({
id: 99, id: '99',
title: dumpTitle.trimEnd().trimStart(), title: dumpTitle.trimEnd().trimStart(),

View File

@ -100,7 +100,7 @@ export const DetailedCalendar: React.FC<EventCalendarProps> = React.memo(({calen
{...bodyProps} {...bodyProps}
renderEvent={renderEvent} renderEvent={renderEvent}
/> />
<View marginB-45/> <View marginB-0/>
</CalendarContainer> </CalendarContainer>
); );
}); });

View File

@ -74,7 +74,8 @@ const styles = StyleSheet.create({
eventCell: { eventCell: {
flex: 1, flex: 1,
borderRadius: 4, borderRadius: 4,
padding: 8, paddingHorizontal: 8,
paddingBottom: 8,
height: '100%', height: '100%',
}, },
eventTitle: { eventTitle: {

View File

@ -28,7 +28,7 @@ export const InnerCalendar = () => {
style={{flex: 1, backgroundColor: "#fff", borderRadius: 0, marginBottom: 0, overflow: "hidden"}} style={{flex: 1, backgroundColor: "#fff", borderRadius: 0, marginBottom: 0, overflow: "hidden"}}
ref={calendarContainerRef} ref={calendarContainerRef}
onLayout={onLayout} onLayout={onLayout}
paddingB-15 paddingB-0
> >
{calendarHeight > 0 && ( {calendarHeight > 0 && (
<EventCalendar <EventCalendar

View File

@ -567,18 +567,10 @@ export const ManuallyAddEventModal = () => {
Save Save
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
{editEvent && (
<Button
style={styles.topBtn}
marginL-5
iconSource={() => <BinIcon/>}
onPress={showDeleteEventModal}
/>
)}
</View> </View>
</View> </View>
{/*)}*/} {/*)}*/}
<ScrollView style={{minHeight: "85%"}}> <ScrollView style={{minHeight: "81%"}}>
<TextField <TextField
placeholder="Add event title" placeholder="Add event title"
ref={titleRef} ref={titleRef}
@ -788,7 +780,6 @@ export const ManuallyAddEventModal = () => {
<Button <Button
disabled disabled
marginH-30 marginH-30
marginB-30
label="Create event from image" label="Create event from image"
text70 text70
style={{height: 47}} style={{height: 47}}
@ -799,7 +790,24 @@ export const ManuallyAddEventModal = () => {
<CameraIcon color="white"/> <CameraIcon color="white"/>
</View> </View>
)} )}
/> />
{editEvent && (
<TouchableOpacity
onPress={showDeleteEventModal}
style={{ marginTop: 15, marginBottom: 40, alignSelf: "center" }}
hitSlop={{left: 30, right: 30, top: 10, bottom: 10}}
>
<Text
style={{
color: "#ff1637",
fontFamily: "PlusJakartaSans_500Medium",
fontSize: 15,
}}
>
Delete Event
</Text>
</TouchableOpacity>
)}
</View> </View>
{editEvent && ( {editEvent && (
<DeleteEventDialog <DeleteEventDialog

View File

@ -652,7 +652,7 @@ export const MonthCalendar: React.FC<EventCalendarProps> = React.memo(
ampm ampm
// renderCustomDateForMonth={renderCustomDateForMonth} // renderCustomDateForMonth={renderCustomDateForMonth}
/> />
<View style={{backgroundColor: 'white', height: 50, width: '100%'}}/> {/*<View style={{backgroundColor: 'white', height: 50, width: '100%'}}/>*/}
</> </>
); );
@ -666,7 +666,7 @@ const styles = StyleSheet.create({
}, },
calHeader: { calHeader: {
borderWidth: 0, borderWidth: 0,
paddingBottom: 60, paddingBottom: 0,
}, },
dayModeHeader: { dayModeHeader: {
alignSelf: "flex-start", alignSelf: "flex-start",

View File

@ -8,7 +8,7 @@ import {
Checkbox, Checkbox,
} from "react-native-ui-lib"; } from "react-native-ui-lib";
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import { useToDosContext } from "@/contexts/ToDosContext"; import { useToDosContext } from "@/contexts/ToDosContext";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import PointsSlider from "@/components/shared/PointsSlider"; import PointsSlider from "@/components/shared/PointsSlider";
@ -26,7 +26,7 @@ const ToDoItem = (props: {
isSettings?: boolean; isSettings?: boolean;
is7Days?: boolean; is7Days?: boolean;
localTodos: Array<IToDo>; localTodos: Array<IToDo>;
setLocalTodos: Function setLocalTodos: Function;
}) => { }) => {
const { updateToDo } = useToDosContext(); const { updateToDo } = useToDosContext();
const { data: members } = useGetFamilyMembers(); const { data: members } = useGetFamilyMembers();
@ -38,13 +38,15 @@ const ToDoItem = (props: {
const [visible, setVisible] = useState<boolean>(false); const [visible, setVisible] = useState<boolean>(false);
const [points, setPoints] = useState(props.item.points); const [points, setPoints] = useState(props.item.points);
const [pointsModalVisible, setPointsModalVisible] = useState<boolean>(false); const [pointsModalVisible, setPointsModalVisible] = useState<boolean>(false);
const [creator, setCreator] = useState(''); const [creator, setCreator] = useState("");
useEffect(() => { useEffect(() => {
let creatorMember = members?.find((member) => member?.uid === props.item.creatorId); let creatorMember = members?.find(
(member) => member?.uid === props.item.creatorId
);
const fullName = `${creatorMember?.firstName ?? ""}`; const fullName = `${creatorMember?.firstName ?? ""}`;
setCreator(fullName); setCreator(fullName);
}, []) }, []);
const handlePointsChange = (text: string) => { const handlePointsChange = (text: string) => {
const numericValue = parseInt(text, 10); const numericValue = parseInt(text, 10);
@ -93,15 +95,15 @@ const ToDoItem = (props: {
}} }}
> >
{showAnimation && ( {showAnimation && (
<View style={styles.animationContainer}> <View style={styles.animationContainer}>
<View style={styles.animationOverlay}> <View style={styles.animationOverlay}>
<Image <Image
source={require("@/assets/animations/todoCompletedAnimation.gif")} source={require("@/assets/animations/todoCompletedAnimation.gif")}
style={styles.animation} style={styles.animation}
resizeMode="contain" resizeMode="contain"
/> />
</View>
</View> </View>
</View>
)} )}
{visible && ( {visible && (
<AddChoreDialog <AddChoreDialog
@ -111,20 +113,24 @@ const ToDoItem = (props: {
/> />
)} )}
<View paddingB-8 row spread> <View paddingB-8 row spread>
<Text <TouchableOpacity
text70
style={{
textDecorationLine: props.item.done ? "line-through" : "none",
fontFamily: "Manrope_500Medium",
color: props.item.done ? "#a09f9f" : "black",
fontSize: 15,
}}
onPress={() => { onPress={() => {
isTodoEditable ? setVisible(true) : null; isTodoEditable ? setVisible(true) : null;
}} }}
hitSlop={{right: 150, top:10}}
> >
{props.item.title} <Text
</Text> text70
style={{
textDecorationLine: props.item.done ? "line-through" : "none",
fontFamily: "Manrope_500Medium",
color: props.item.done ? "#a09f9f" : "black",
fontSize: 15,
}}
>
{props.item.title}
</Text>
</TouchableOpacity>
<Checkbox <Checkbox
value={props.item.done} value={props.item.done}
containerStyle={[styles.checkbox, { borderRadius: 50 }]} containerStyle={[styles.checkbox, { borderRadius: 50 }]}
@ -133,7 +139,11 @@ const ToDoItem = (props: {
borderRadius={50} borderRadius={50}
color="#fd1575" color="#fd1575"
onValueChange={() => { onValueChange={() => {
const updatedTodos = props.localTodos?.map((item) => item.id === props.item.id ? { ...item, done: !props.item.done } : item); const updatedTodos = props.localTodos?.map((item) =>
item.id === props.item.id
? { ...item, done: !props.item.done }
: item
);
props.setLocalTodos(updatedTodos); props.setLocalTodos(updatedTodos);
updateToDo({ id: props.item.id, done: !props.item.done }); updateToDo({ id: props.item.id, done: !props.item.done });
if (!props.item.done && isChild) { if (!props.item.done && isChild) {
@ -209,11 +219,11 @@ const ToDoItem = (props: {
</View> </View>
<View row centerV marginL-5 marginT-2> <View row centerV marginL-5 marginT-2>
<Text <Text
style={{ style={{
fontSize: 12, fontSize: 12,
fontFamily: "Manrope_500Medium", fontFamily: "Manrope_500Medium",
color: "#858585", color: "#858585",
}} }}
> >
Created by: {creator} Created by: {creator}
</Text> </Text>
@ -231,7 +241,7 @@ const ToDoItem = (props: {
borderRadius: 22, borderRadius: 22,
overflow: "hidden", overflow: "hidden",
borderWidth: 2, borderWidth: 2,
borderColor: member.eventColor || 'transparent' borderColor: member.eventColor || "transparent",
}} }}
/> />
) : ( ) : (
@ -242,7 +252,7 @@ const ToDoItem = (props: {
aspectRatio: 1, aspectRatio: 1,
borderWidth: 2, borderWidth: 2,
borderRadius: 100, borderRadius: 100,
borderColor: member.eventColor || '#ccc', borderColor: member.eventColor || "#ccc",
}} }}
> >
<View <View

View File

@ -3,11 +3,15 @@ import { useDeleteNote } from "@/hooks/firebase/useDeleteNote";
import { useGetNotes } from "@/hooks/firebase/useGetNotes"; import { useGetNotes } from "@/hooks/firebase/useGetNotes";
import { useUpdateNote } from "@/hooks/firebase/useUpdateNote"; import { useUpdateNote } from "@/hooks/firebase/useUpdateNote";
import { createContext, useContext, useState } from "react"; import { createContext, useContext, useState } from "react";
import firestore, { FirebaseFirestoreTypes } from '@react-native-firebase/firestore';
export interface IBrainDump { export interface IBrainDump {
id: number; id: string;
title: string; title: string;
description: string; description: string;
createdAt?: FirebaseFirestoreTypes.Timestamp;
updatedAt?: FirebaseFirestoreTypes.Timestamp;
creatorId?: string;
} }
interface IBrainDumpContext { interface IBrainDumpContext {

View File

@ -43,4 +43,6 @@ export interface UserProfile {
googleAccounts?: { [email: string]: GoogleAccount }; googleAccounts?: { [email: string]: GoogleAccount };
microsoftAccounts?: { [email: string]: MicrosoftAccount }; microsoftAccounts?: { [email: string]: MicrosoftAccount };
appleAccounts?: { [email: string]: AppleAccount }; appleAccounts?: { [email: string]: AppleAccount };
weeklyPoints?: number;
allTimePoints?: number;
} }

View File

@ -12,6 +12,8 @@ export const useCreateNote = () => {
mutationKey: ["createNote"], mutationKey: ["createNote"],
mutationFn: async (note: Partial<IBrainDump>) => { mutationFn: async (note: Partial<IBrainDump>) => {
try { try {
const timestamp = firestore.FieldValue.serverTimestamp();
if (note.id) { if (note.id) {
const snapshot = await firestore() const snapshot = await firestore()
.collection("BrainDumps") .collection("BrainDumps")
@ -27,16 +29,22 @@ export const useCreateNote = () => {
{ {
...note, ...note,
creatorId: currentUser?.uid, creatorId: currentUser?.uid,
updatedAt: timestamp
}, },
{ merge: true } { merge: true }
); );
return; return;
} }
} }
const newDoc = firestore().collection("BrainDumps").doc(); const newDoc = firestore().collection("BrainDumps").doc();
await firestore() await newDoc.set({
.collection("BrainDumps") ...note,
.add({ ...note, id: newDoc.id, creatorId: currentUser?.uid }); id: newDoc.id,
creatorId: currentUser?.uid,
updatedAt: timestamp,
createdAt: timestamp
});
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -14,14 +14,19 @@ export const daysOfWeek = [
DAYS_OF_WEEK_ENUM.SATURDAY, DAYS_OF_WEEK_ENUM.SATURDAY,
DAYS_OF_WEEK_ENUM.SUNDAY]; DAYS_OF_WEEK_ENUM.SUNDAY];
export const getNextDailyDates = (date) => { export const getNextDailyDates = (date, includeToday) => {
const today = new Date(); const today = new Date();
const dates = []; const dates = [];
for (let weekOffset = 0; weekOffset < 52; weekOffset++) { for (let weekOffset = 0; weekOffset < 52; weekOffset++) {
const targetDate = addWeeks(date, weekOffset); const targetDate = addWeeks(date, weekOffset);
if (targetDate > today) {
if (includeToday) {
dates.push(targetDate); dates.push(targetDate);
} else {
if (targetDate > today) {
dates.push(targetDate);
}
} }
} }
@ -46,28 +51,36 @@ export const getNextWeeklyDates = (selectedDays, date) => {
return dates; return dates;
}; };
export const getNextMonthlyDates = (date) => { export const getNextMonthlyDates = (date, includeToday) => {
const today = new Date(); const today = new Date();
const dates = []; const dates = [];
for (let monthOffset = 0; monthOffset < 12; monthOffset++) { for (let monthOffset = 0; monthOffset < 12; monthOffset++) {
const targetDate = addMonths(date, monthOffset); const targetDate = addMonths(date, monthOffset);
if (targetDate > today) { if (includeToday) {
dates.push(targetDate); dates.push(targetDate);
} else {
if (targetDate > today) {
dates.push(targetDate);
}
} }
} }
return dates; return dates;
}; };
export const getNextYearlyDates = (date) => { export const getNextYearlyDates = (date, includeToday) => {
const today = new Date(); const today = new Date();
const dates = []; const dates = [];
for (let yearOffset = 0; yearOffset < 5; yearOffset++) { for (let yearOffset = 0; yearOffset < 5; yearOffset++) {
const nextYear = addYears(date, yearOffset); const nextYear = addYears(date, yearOffset);
if (nextYear > today) { if (includeToday) {
dates.push(nextYear); dates.push(nextYear);
} else {
if (nextYear > today) {
dates.push(nextYear);
}
} }
} }
@ -92,13 +105,13 @@ export const useCreateTodo = () => {
let nextDates; let nextDates;
if (todoData.repeatType === REPEAT_TYPE.DAILY) { if (todoData.repeatType === REPEAT_TYPE.DAILY) {
nextDates = getNextDailyDates(todoData.date); nextDates = getNextDailyDates(todoData.date, false);
} else if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) { } else if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) {
nextDates = getNextWeeklyDates(todoData.repeatDays, todoData.date); nextDates = getNextWeeklyDates(todoData.repeatDays, todoData.date);
} else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) { } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) {
nextDates = getNextMonthlyDates(todoData.date); nextDates = getNextMonthlyDates(todoData.date, false);
} else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) { } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) {
nextDates = getNextYearlyDates(todoData.date); nextDates = getNextYearlyDates(todoData.date, false);
} }
const todosRef = firestore().collection("Todos"); const todosRef = firestore().collection("Todos");

View File

@ -18,6 +18,9 @@ export const useGetNotes = () => {
return snapshot.docs.map((doc) => ({ return snapshot.docs.map((doc) => ({
...doc.data(), ...doc.data(),
id: doc.id,
createdAt: doc.data().createdAt,
updatedAt: doc.data().updatedAt,
})) as IBrainDump[]; })) as IBrainDump[];
} catch (error) { } catch (error) {
console.error("Error fetching braindumps:", error); console.error("Error fetching braindumps:", error);

View File

@ -1,9 +1,15 @@
import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQueryClient } from "@tanstack/react-query";
import firestore from "@react-native-firebase/firestore"; import firestore from "@react-native-firebase/firestore";
import {IToDo, REPEAT_TYPE} from "@/hooks/firebase/types/todoData"; import { IToDo, REPEAT_TYPE } from "@/hooks/firebase/types/todoData";
import {addDays, addMonths, addWeeks, addYears, compareAsc, format, subDays} from "date-fns"; import { compareAsc, format } from "date-fns";
import {daysOfWeek, resolveTodoAlternatingAssignees} from "@/hooks/firebase/useCreateTodo"; import {
import {useAuthContext} from "@/contexts/AuthContext"; getNextDailyDates,
getNextMonthlyDates,
getNextWeeklyDates,
getNextYearlyDates
} from "@/hooks/firebase/useCreateTodo";
import { useAuthContext } from "@/contexts/AuthContext";
import {UserProfile} from "@/hooks/firebase/types/profileTypes";
export const useUpdateTodo = () => { export const useUpdateTodo = () => {
const { user: currentUser, profileData } = useAuthContext(); const { user: currentUser, profileData } = useAuthContext();
@ -14,9 +20,22 @@ export const useUpdateTodo = () => {
mutationFn: async (todoData: Partial<IToDo>) => { mutationFn: async (todoData: Partial<IToDo>) => {
try { try {
if (todoData.connectedTodoId) { if (todoData.connectedTodoId) {
console.log("CONNECTED")
const snapshot = await firestore() let nextDates;
.collection("Todos") if (todoData.repeatType === REPEAT_TYPE.DAILY) {
nextDates = getNextDailyDates(todoData.date, true);
} else if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) {
nextDates = getNextWeeklyDates(todoData.repeatDays, todoData.date);
} else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) {
nextDates = getNextMonthlyDates(todoData.date, true);
} else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) {
nextDates = getNextYearlyDates(todoData.date, true);
}
const todosRef = firestore().collection("Todos");
const batch = firestore().batch();
const snapshot = await todosRef
.where("connectedTodoId", "==", todoData.connectedTodoId) .where("connectedTodoId", "==", todoData.connectedTodoId)
.get(); .get();
const connectedTodos = snapshot.docs.map((doc) => { const connectedTodos = snapshot.docs.map((doc) => {
@ -30,135 +49,109 @@ export const useUpdateTodo = () => {
}; };
}) as IToDo[]; }) as IToDo[];
console.log("CONNECTED TODO");
let filteredTodos = connectedTodos?.filter((item) => compareAsc(format(item.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) === 1 || let filteredTodos = connectedTodos?.filter((item) => compareAsc(format(item.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) === 1 ||
compareAsc(format(item.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) === 0).sort((a,b) =>{ compareAsc(format(item.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) === 0).sort((a,b) =>{
return b.date?.getSeconds() - a.date?.getSeconds(); return b.date?.getSeconds() - a.date?.getSeconds();
}); });
let firstTodo = filteredTodos?.[0]; // Update existing todos or create new ones
const batch = firestore().batch(); filteredTodos?.map((todo, index) => {
if (compareAsc(format(firstTodo?.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) !== 0 || firstTodo?.repeatType !== todoData.repeatType) { const newDate = nextDates[index];
let assignee;
console.log("DELETE"); if (todoData.assignees && todoData.rotate && todoData?.assignees?.length !== 0) {
filteredTodos?.forEach((item) => { assignee = todoData.assignees[index % todoData.assignees.length];
batch.delete(item.ref);
});
if (todoData.repeatType === REPEAT_TYPE.NONE) {
console.log("NONE");
const newDoc = firestore().collection('Todos').doc();
let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid}
batch.set(newDoc, originalTodo);
} else if (todoData.repeatType === REPEAT_TYPE.DAILY) {
console.log("DAILY");
// for the next 52 weeks
for (let i = 0; i < 52; i++) {
let date = todoData?.date;
const nextWeek = addWeeks(date, i);
let docRef = firestore().collection("Todos").doc();
let newTodo = { ...todoData, id: docRef.id, date: nextWeek, connectedTodoId: firstTodo?.connectedTodoId };
newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i);
batch.set(docRef, newTodo);
}
} else if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) {
console.log("EVERY WEEK");
let date = todoData?.date;
let repeatDays = todoData?.repeatDays;
const dates = [];
const originalDateDay = format(date, 'EEEE');
const originalNumber = daysOfWeek.indexOf(originalDateDay);
repeatDays?.forEach((day) => {
let number = daysOfWeek.indexOf(day);
let newDate;
if (originalNumber > number) {
let diff = originalNumber - number;
newDate = subDays(date, diff);
} else {
let diff = number - originalNumber;
newDate = addDays(date, diff);
}
dates.push(newDate);
});
let todosToAddCycles = 52;
if (firstTodo?.repeatType === REPEAT_TYPE.EVERY_WEEK) {
todosToAddCycles = filteredTodos?.length / firstTodo?.repeatDays?.length;
}
console.log(todosToAddCycles);
let newDoc = firestore().collection("Todos").doc();
let originalTodo = { ...todoData, id: newDoc.id, date: todoData.date, connectedTodoId: newDoc?.id };
originalTodo = resolveTodoAlternatingAssignees(todoData, originalTodo, 0);
batch.set(newDoc, originalTodo);
console.log(dates);
let index = 1;
for (let i = 0; i <= todosToAddCycles; i++) {
dates?.forEach((dateToAdd) => {
index++;
let newTodoDate = addWeeks(dateToAdd, i);
if (compareAsc(newTodoDate, originalTodo.date) !== 0) {
let docRef = firestore().collection("Todos").doc();
let newTodo = { ...todoData, id: docRef.id, date: newTodoDate, connectedTodoId: newDoc?.id };
newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, index);
batch.set(docRef, newTodo);
}
})
}
} else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) {
console.log("ONCE A MONTH");
// for the next 12 months
for (let i = 0; i < 12; i++) {
let date = todoData?.date;
const nextMonth = addMonths(date, i);
let docRef = firestore().collection("Todos").doc();
let newTodo = { ...todoData, id: docRef.id, date: nextMonth, connectedTodoId: firstTodo?.connectedTodoId };
newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i);
batch.set(docRef, newTodo);
}
} else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) {
console.log("ONCE A YEAR");
// for the next 5 years
for (let i = 0; i < 5; i++) {
let date = todoData?.date;
const nextMonth = addYears(date, i);
let docRef = firestore().collection("Todos").doc();
let newTodo = { ...todoData, id: docRef.id, date: nextMonth, connectedTodoId: firstTodo?.connectedTodoId };
newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i);
batch.set(docRef, newTodo);
}
} }
await batch.commit(); if (newDate) {
} else if (firstTodo?.repeatDays !== todoData.repeatDays) { const nextTodo = {
...todoData,
date: newDate,
assignees: assignee ? [assignee] : todoData.assignees
}
let docRef = todo.ref;
batch.update(docRef, nextTodo)
} else {
return null;
}
});
console.log("UPDATE REPEAT DAYS"); const existingDates = filteredTodos?.map((todo) => todo.date);
await updateRepeatDaysTodos(batch, todoData, firstTodo, filteredTodos) nextDates
} else { .filter((date) => !existingDates.includes(date))
filteredTodos?.forEach((item) => { .map((date, index) => {
const newDocRef = todosRef.doc();
console.log("UPDATE"); let assignee;
batch.update(item.ref, {...todoData, date: item.date}); if (todoData.assignees && todoData.rotate && todoData?.assignees?.length !== 0) {
}) assignee = todoData.assignees[index % todoData.assignees.length];
await batch.commit(); }
}
const nextTodo = {
...todoData,
date: date,
id: newDocRef.id,
familyId: profileData?.familyId,
creatorId: currentUser?.uid,
connectedTodoId: todoData.connectedTodoId,
assignees: assignee ? [assignee] : todoData.assignees
}
batch.set(newDocRef, nextTodo)
});
// Remove unmatched todos
const unmatchedTodos = filteredTodos?.filter(
(item) => !nextDates.includes(item.date)
);
unmatchedTodos.map((item) =>
batch.delete(item.ref)
);
await batch.commit();
} else { } else {
console.log("REGULAR UPDATE");
console.log(todoData); let documentSnapshot = await firestore().collection("Todos").doc(todoData.id).get();
await firestore() if (documentSnapshot.exists) {
.collection("Todos") let todoUpdate = documentSnapshot.data() as IToDo;
.doc(todoData.id)
.update(todoData); const userBatch = firestore().batch();
if (todoUpdate.done !== todoData.done) {
todoUpdate.assignees?.map(async (userId) => {
const userRef = firestore().collection("Profiles").doc(userId);
let userSnapshot = await userRef.get();
let userData = userSnapshot.data() as UserProfile;
if (!userData) return;
// Calculate new points
let userWeeklyPoints = userData.weeklyPoints ?? 0;
const weeklyPoints = todoData.done
? userWeeklyPoints + todoUpdate.points
: userWeeklyPoints - todoUpdate.points;
let userAllTimePoints = userData.allTimePoints ?? 0;
const allTimePoints = todoData.done
? userAllTimePoints + todoUpdate.points
: userAllTimePoints - todoUpdate.points;
// Update the user's points in Firestore
userData = {
...userData,
weeklyPoints: weeklyPoints >= 0 ? weeklyPoints : 0,
allTimePoints: allTimePoints >= 0 ? allTimePoints : 0
}
userBatch.update(userRef, userData);
});
}
await firestore()
.collection("Todos")
.doc(todoData.id)
.update(todoData);
await userBatch.commit();
}
} }
} catch (e) { } catch (e) {
console.error(e) console.error(e)
@ -168,62 +161,4 @@ export const useUpdateTodo = () => {
queryClients.invalidateQueries({queryKey: ["todos"]}) queryClients.invalidateQueries({queryKey: ["todos"]})
} }
}) })
} };
const updateRepeatDaysTodos = async (batch: any, todoData: IToDo, firstTodo: IToDo, filteredTodos: IToDo[]) => {
const todosToAddCycles = filteredTodos?.length / firstTodo?.repeatDays?.length;
console.log(todosToAddCycles);
filteredTodos?.forEach((item) => {
batch.update(item.ref, {...todoData, date: item.date});
})
let newRepeatDays = todoData.repeatDays?.filter((element) => firstTodo?.repeatDays?.indexOf(element) === -1);
let removeRepeatDays = firstTodo?.repeatDays?.filter((element) => todoData?.repeatDays?.indexOf(element) === -1);
const dates = [];
let date = firstTodo?.date;
const originalDateDay = format(date, 'EEEE');
const originalNumber = daysOfWeek.indexOf(originalDateDay);
newRepeatDays?.forEach((day) => {
let number = daysOfWeek.indexOf(day);
let newDate;
if (originalNumber > number) {
let diff = originalNumber - number;
newDate = subDays(date, diff);
} else {
let diff = number - originalNumber;
newDate = addDays(date, diff);
}
dates.push(newDate);
});
let index = 0;
for (let i = 0; i < todosToAddCycles; i++) {
dates?.forEach((dateToAdd) => {
index ++;
let newTodoDate = addWeeks(dateToAdd, i);
if (compareAsc(newTodoDate, firstTodo?.date) !== 0) {
let newTodo = {...todoData, date: newTodoDate};
newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, index);
let docRef = firestore().collection("Todos").doc();
batch.set(docRef, newTodo);
}
})
}
removeRepeatDays?.forEach((removeDay) => {
filteredTodos?.forEach((item) => {
let todoDate = item.date;
const todoDateDay = format(todoDate, 'EEEE');
if (todoDateDay === removeDay) {
batch.delete(item.ref);
}
})
})
await batch.commit();
}