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 pointsPerDay = userData.weeklyDayPoints || { Monday: 0, Tuesday: 0, Wednesday: 0, Thursday: 0, Friday: 0, Saturday: 0, Sunday: 0, }; const currentDay = getCurrentDay(todoUpdate.date); const updatedPointsPerDay = todoData.done ? pointsPerDay[currentDay] + todoUpdate.points : pointsPerDay[currentDay] - todoUpdate.points; pointsPerDay[currentDay] = Math.max(0, updatedPointsPerDay); let userAllTimePoints = userData.allTimePoints ?? 0; const allTimePoints = todoData.done ? userAllTimePoints + todoUpdate.points : userAllTimePoints - todoUpdate.points; const weeklyCompletedTodos = todoData.done ? (userData.weeklyCompletedTodos || 0) + 1 : (userData.weeklyCompletedTodos || 0) - 1; // Update the user's points in Firestore userData = { ...userData, weeklyPoints: weeklyPoints >= 0 ? weeklyPoints : 0, weeklyDayPoints: pointsPerDay, allTimePoints: allTimePoints >= 0 ? allTimePoints : 0, weeklyCompletedTodos: weeklyCompletedTodos >= 0 ? weeklyCompletedTodos : 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"]}) } }) }; const getCurrentDay = (date) => { let selectedDate = new Date(date.seconds * 1000); const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; return days[selectedDate.getDay()]; };