From 5c67ffccbde5f90dc515f8413a5f58d6680355ce Mon Sep 17 00:00:00 2001 From: Dejan Date: Sat, 26 Oct 2024 13:20:09 +0200 Subject: [PATCH] - Implemented the complete update of recurring todo and handle changing the recurring rule and date --- hooks/firebase/useCreateTodo.ts | 39 +++---- hooks/firebase/useUpdateTodo.ts | 182 +++++++++++++++++++++++--------- 2 files changed, 153 insertions(+), 68 deletions(-) diff --git a/hooks/firebase/useCreateTodo.ts b/hooks/firebase/useCreateTodo.ts index e897e16..afffdde 100644 --- a/hooks/firebase/useCreateTodo.ts +++ b/hooks/firebase/useCreateTodo.ts @@ -2,7 +2,7 @@ import {useMutation, useQueryClient} from "react-query"; import firestore from "@react-native-firebase/firestore"; import {useAuthContext} from "@/contexts/AuthContext"; import {DAYS_OF_WEEK_ENUM, IToDo, REPEAT_TYPE} from "@/hooks/firebase/types/todoData"; -import {addDays, addMonths, addWeeks, compareAsc, format, getDay, subDays} from "date-fns"; +import {addDays, addMonths, addWeeks, addYears, compareAsc, format, subDays} from "date-fns"; export const daysOfWeek = [ DAYS_OF_WEEK_ENUM.MONDAY, @@ -21,14 +21,20 @@ export const useCreateTodo = () => { mutationKey: ["createTodo"], mutationFn: async (todoData: Partial) => { try { - // Create the one original to do - const newDoc = firestore().collection('Todos').doc(); - let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid} - await firestore() - .collection("Todos") - .add(originalTodo); + if (todoData.repeatType === REPEAT_TYPE.NONE) { + const newDoc = firestore().collection('Todos').doc(); + let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid} + await firestore() + .collection("Todos") + .add(originalTodo); + } else { + // Create the one original to do + const newDoc = firestore().collection('Todos').doc(); + let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid, connectedTodoId: newDoc.id}; + await firestore() + .collection("Todos") + .add(originalTodo); - if (todoData.repeatType !== REPEAT_TYPE.NONE) { const batch = firestore().batch(); if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) { @@ -57,36 +63,33 @@ export const useCreateTodo = () => { dates?.forEach((dateToAdd) => { let newTodoDate = addWeeks(dateToAdd, i); if (compareAsc(newTodoDate, originalTodo.date) !== 0) { - const newTodo = { ...originalTodo, date: newTodoDate, connectedTodoId: newDoc.id }; let docRef = firestore().collection("Todos").doc(); + const newTodo = { ...originalTodo, id: docRef.id, date: newTodoDate, connectedTodoId: newDoc.id }; batch.set(docRef, newTodo); - console.log(newTodo); } }) } } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) { // for the next 12 months - for (let i = 0; i < 12; i++) { + for (let i = 1; i < 12; i++) { let date = originalTodo.date; - const nextMonth = addMonths(date, i + 1); - const newTodo = { ...originalTodo, date: nextMonth, connectedTodoId: newDoc.id }; - console.log(newTodo); + const nextMonth = addMonths(date, i); let docRef = firestore().collection("Todos").doc(); + const newTodo = { ...originalTodo, id: docRef.id, date: nextMonth, connectedTodoId: newDoc.id }; batch.set(docRef, newTodo); } } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) { // for the next 5 years - for (let i = 0; i < 5; i++) { + for (let i = 1; i < 5; i++) { let date = originalTodo.date; - const nextMonth = addMonths(date, i + 1); - const newTodo = { ...originalTodo, date: nextMonth, connectedTodoId: newDoc.id }; - console.log(newTodo); + const nextMonth = addYears(date, i); let docRef = firestore().collection("Todos").doc(); + const newTodo = { ...originalTodo, id: docRef.id, date: nextMonth, connectedTodoId: newDoc.id }; batch.set(docRef, newTodo); } } diff --git a/hooks/firebase/useUpdateTodo.ts b/hooks/firebase/useUpdateTodo.ts index de7a263..a0a04ec 100644 --- a/hooks/firebase/useUpdateTodo.ts +++ b/hooks/firebase/useUpdateTodo.ts @@ -1,24 +1,24 @@ import { useMutation, useQueryClient } from "react-query"; import firestore from "@react-native-firebase/firestore"; -import {IToDo} from "@/hooks/firebase/types/todoData"; -import {addDays, addWeeks, compareAsc, format, subDays} from "date-fns"; +import {IToDo, REPEAT_TYPE} from "@/hooks/firebase/types/todoData"; +import {addDays, addMonths, addWeeks, addYears, compareAsc, format, subDays} from "date-fns"; import {daysOfWeek} from "@/hooks/firebase/useCreateTodo"; +import {useAuthContext} from "@/contexts/AuthContext"; export const useUpdateTodo = () => { + const { user: currentUser, profileData } = useAuthContext(); const queryClients = useQueryClient() return useMutation({ mutationKey: ["updateTodo"], mutationFn: async (todoData: Partial) => { try { + const snapshot = await firestore() + .collection("Todos") + .where("connectedTodoId", "==", todoData.connectedTodoId) + .get(); + if (todoData.connectedTodoId) { - console.log("CONNECTED TODO"); - const snapshot = await firestore() - .collection("Todos") - .where("connectedTodoId", "==", todoData.connectedTodoId) - .get(); - - const connectedTodos = snapshot.docs.map((doc) => { const data = doc.data(); @@ -30,25 +30,37 @@ export const useUpdateTodo = () => { }; }) as IToDo[]; - let filteredTodos = connectedTodos?.filter((item) => item.date >= todoData.date).sort((a,b) =>{ + console.log("CONNECTED TODO"); + 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) =>{ return b.date?.getSeconds() - a.date?.getSeconds(); }); - console.log(filteredTodos); let firstTodo = filteredTodos?.[0]; - // resolve the repeating const batch = firestore().batch(); - const todosToAddCycles = filteredTodos?.length / firstTodo?.repeatDays?.length; - console.log(todosToAddCycles); - if (firstTodo?.repeatDays !== todoData.repeatDays) { - let newRepeatDays = todoData.repeatDays?.filter((element) => firstTodo?.repeatDays?.indexOf(element) === -1); - let removeRepeatDays = firstTodo?.repeatDays?.filter((element) => todoData?.repeatDays?.indexOf(element) === -1); + if (compareAsc(format(firstTodo?.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) !== 0 || firstTodo?.repeatType !== todoData.repeatType) { + + console.log("DELETE"); + filteredTodos?.forEach((item) => { + 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.EVERY_WEEK) { + + console.log("EVERY WEEK"); + let date = todoData?.date; + let repeatDays = todoData?.repeatDays; const dates = []; - let date = firstTodo?.date; const originalDateDay = format(date, 'EEEE'); const originalNumber = daysOfWeek.indexOf(originalDateDay); - newRepeatDays?.forEach((day) => { + repeatDays?.forEach((day) => { let number = daysOfWeek.indexOf(day); let newDate; if (originalNumber > number) { @@ -61,53 +73,67 @@ export const useUpdateTodo = () => { dates.push(newDate); }); - console.log("REPEAT") - console.log(newRepeatDays); - console.log(removeRepeatDays); + let todosToAddCycles = 4; + if (firstTodo?.repeatType === REPEAT_TYPE.EVERY_WEEK) { + todosToAddCycles = filteredTodos?.length / firstTodo?.repeatDays?.length; + } + console.log(todosToAddCycles); + let newDoc = firestore().collection("Todos").doc(); + const newTodo = { ...todoData, id: newDoc.id, date: todoData.date, connectedTodoId: newDoc?.id }; + batch.set(newDoc, newTodo); + console.log(dates); - - filteredTodos?.forEach((item) => { - - batch.update(item.ref, {...todoData, date: item.date}); - }) - // TODO: for the next connected -> filtered todos - number of weeks for (let i = 0; i < todosToAddCycles; i++) { dates?.forEach((dateToAdd) => { let newTodoDate = addWeeks(dateToAdd, i); - if (compareAsc(newTodoDate, firstTodo?.date) !== 0) { - const newTodo = { ...todoData, date: newTodoDate }; + console.log("ENTER") let docRef = firestore().collection("Todos").doc(); + const newTodo = { ...todoData, id: docRef.id, date: newTodoDate, connectedTodoId: newDoc?.id }; batch.set(docRef, newTodo); - console.log("ADD") - console.log(newTodo); - } }) } + } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) { - removeRepeatDays?.forEach((removeDay) => { - filteredTodos?.forEach((item) => { + 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); + const newTodo = { ...todoData, date: nextMonth, connectedTodoId: firstTodo?.connectedTodoId }; - let todoDate = item.date; - const todoDateDay = format(todoDate, 'EEEE'); - console.log(todoDateDay); - if (todoDateDay === removeDay) { - batch.delete(item.ref); - } - }) - }) + let docRef = firestore().collection("Todos").doc(); + batch.set(docRef, newTodo); + } + } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) { - } else { - filteredTodos?.forEach((item) => { + 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); + const newTodo = { ...todoData, date: nextMonth, connectedTodoId: firstTodo?.connectedTodoId }; - console.log("UPDATE"); - batch.update(item.ref, {...todoData, date: item.date}); - }) + let docRef = firestore().collection("Todos").doc(); + batch.set(docRef, newTodo); + } } - await batch.commit(); + await batch.commit(); + } else if (firstTodo?.repeatDays !== todoData.repeatDays) { + + console.log("UPDATE REPEAT DAYS"); + await updateRepeatDaysTodos(batch, todoData, firstTodo, filteredTodos) + } else { + filteredTodos?.forEach((item) => { + + console.log("UPDATE"); + batch.update(item.ref, {...todoData, date: item.date}); + }) + await batch.commit(); + } } else { - console.log("Update"); + console.log("REGULAR UPDATE"); console.log(todoData); await firestore() .collection("Todos") @@ -122,4 +148,60 @@ export const useUpdateTodo = () => { queryClients.invalidateQueries("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); + }); + + // TODO: for the next connected -> filtered todos - number of weeks + for (let i = 0; i < todosToAddCycles; i++) { + dates?.forEach((dateToAdd) => { + let newTodoDate = addWeeks(dateToAdd, i); + if (compareAsc(newTodoDate, firstTodo?.date) !== 0) { + const newTodo = {...todoData, date: newTodoDate}; + + 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(); } \ No newline at end of file