import { useMutation, useQueryClient } from "@tanstack/react-query"; import firestore from "@react-native-firebase/firestore"; import { IToDo, REPEAT_TYPE } from "@/hooks/firebase/types/todoData"; import { compareAsc, format } from "date-fns"; import { getNextDailyDates, getNextMonthlyDates, getNextWeeklyDates, getNextYearlyDates } from "@/hooks/firebase/useCreateTodo"; import { useAuthContext } from "@/contexts/AuthContext"; import {UserProfile} from "@/hooks/firebase/types/profileTypes"; export const useUpdateTodo = () => { const { user: currentUser, profileData } = useAuthContext(); const queryClients = useQueryClient() return useMutation({ mutationKey: ["updateTodo"], mutationFn: async (todoData: Partial) => { try { if (todoData.connectedTodoId) { let nextDates; 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) .get(); const connectedTodos = snapshot.docs.map((doc) => { const data = doc.data(); return { ...data, id: doc.id, date: data.date ? new Date(data.date.seconds * 1000) : null, ref: doc.ref }; }) as unknown as IToDo[]; 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(); }); // Update existing todos or create new ones filteredTodos?.map((todo, index) => { const newDate = nextDates[index]; let assignee; if (todoData.assignees && todoData.rotate && todoData?.assignees?.length !== 0) { assignee = todoData.assignees[index % todoData.assignees.length]; } if (newDate) { const nextTodo = { ...todoData, date: newDate, assignees: assignee ? [assignee] : todoData.assignees } let docRef = todo.ref; batch.update(docRef, nextTodo) } else { return null; } }); const existingDates = filteredTodos?.map((todo) => todo.date); nextDates .filter((date) => !existingDates.includes(date)) .map((date, index) => { const newDocRef = todosRef.doc(); let assignee; if (todoData.assignees && todoData.rotate && todoData?.assignees?.length !== 0) { assignee = todoData.assignees[index % todoData.assignees.length]; } 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 { let documentSnapshot = await firestore().collection("Todos").doc(todoData.id).get(); if (documentSnapshot.exists) { let todoUpdate = documentSnapshot.data() as IToDo; 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) { console.error(e) } }, onSuccess: () => { queryClients.invalidateQueries({queryKey: ["todos"]}) } }) };