Files
cally/hooks/firebase/useUpdateTodo.ts

192 lines
8.8 KiB
TypeScript

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<IToDo>) => {
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();
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 = () => {
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const now = new Date();
return days[now.getDay()];
};