mirror of
https://github.com/urosran/cally.git
synced 2025-07-10 15:17:17 +00:00
192 lines
8.9 KiB
TypeScript
192 lines
8.9 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(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()];
|
|
}; |