mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 00:24:53 +00:00
Implementation of fetching, adding and updating todos to db
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import { View, Text, Button, Switch } from "react-native-ui-lib";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useState } from "react";
|
||||
import PointsSlider from "@/components/shared/PointsSlider";
|
||||
import { repeatOptions, useToDosContext } from "@/contexts/ToDosContext";
|
||||
import { Feather, AntDesign, Ionicons } from "@expo/vector-icons";
|
||||
@ -27,7 +27,7 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
||||
const [rotate, setRotate] = useState<boolean>(false);
|
||||
const [repeatType, setRepeatType] = useState<string>("Every week");
|
||||
|
||||
const handleCLose = () => {
|
||||
const handleClose = () => {
|
||||
setNewTitle("");
|
||||
setPoints(10);
|
||||
setChoreDate(new Date());
|
||||
@ -50,7 +50,7 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
||||
bottom={true}
|
||||
height={"90%"}
|
||||
panDirection={PanningDirectionsEnum.DOWN}
|
||||
onDismiss={() => handleCLose}
|
||||
onDismiss={() => handleClose}
|
||||
containerStyle={{
|
||||
borderRadius: 10,
|
||||
backgroundColor: "white",
|
||||
@ -68,13 +68,13 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
||||
style={styles.topBtn}
|
||||
label="Cancel"
|
||||
onPress={() => {
|
||||
handleCLose();
|
||||
handleClose();
|
||||
}}
|
||||
/>
|
||||
<View marginT-12>
|
||||
<DropModalIcon
|
||||
onPress={() => {
|
||||
handleCLose()
|
||||
handleClose()
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@ -85,7 +85,7 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
||||
onPress={() => {
|
||||
try {
|
||||
addToDo({
|
||||
id: 0,
|
||||
id: "",
|
||||
title: newTitle,
|
||||
done: false,
|
||||
date: choreDate,
|
||||
@ -93,8 +93,7 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
||||
rotate: rotate,
|
||||
repeatType: repeatType,
|
||||
});
|
||||
handleCLose();
|
||||
console.log(toDos);
|
||||
handleClose();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
@ -10,9 +10,10 @@ import {
|
||||
ButtonSize,
|
||||
} from "react-native-ui-lib";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { IToDo, useToDosContext } from "@/contexts/ToDosContext";
|
||||
import { useToDosContext } from "@/contexts/ToDosContext";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import PointsSlider from "@/components/shared/PointsSlider";
|
||||
import {IToDo} from "@/hooks/firebase/types/todoData";
|
||||
|
||||
const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
|
||||
const { updateToDo } = useToDosContext();
|
||||
@ -61,7 +62,7 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
|
||||
value={props.item.title}
|
||||
text70R
|
||||
onChangeText={(text) => {
|
||||
updateToDo(props.item.id, { title: text });
|
||||
updateToDo({id: props.item.id, title: text });
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
setEditing(false);
|
||||
@ -74,7 +75,7 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
|
||||
<Checkbox
|
||||
value={props.item.done}
|
||||
onValueChange={(value) => {
|
||||
updateToDo(props.item.id, { done: !props.item.done });
|
||||
updateToDo({id: props.item.id, done: !props.item.done });
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@ -151,7 +152,7 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
|
||||
backgroundColor="#fd1775"
|
||||
style={{height: 60, width: 150}}
|
||||
onPress={() => {
|
||||
updateToDo(props.item.id, { points: points });
|
||||
updateToDo({id: props.item.id, points: points });
|
||||
setPointsModalVisible(false);
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { View, Text, TouchableOpacity, Icon } from "react-native-ui-lib";
|
||||
import React, { useState } from "react";
|
||||
import { IToDo, useToDosContext } from "@/contexts/ToDosContext";
|
||||
import { useToDosContext } from "@/contexts/ToDosContext";
|
||||
import ToDoItem from "./ToDoItem";
|
||||
import { format, isToday, isTomorrow } from "date-fns";
|
||||
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
import {IToDo} from "@/hooks/firebase/types/todoData";
|
||||
|
||||
const groupToDosByDate = (toDos: IToDo[]) => {
|
||||
return toDos.reduce((groups, toDo) => {
|
||||
|
||||
@ -1,35 +1,12 @@
|
||||
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
||||
import {IToDo} from "@/hooks/firebase/types/todoData";
|
||||
import {useGetGroceries} from "@/hooks/firebase/useGetGroceries";
|
||||
import {useGetTodos} from "@/hooks/firebase/useGetTodos";
|
||||
import {useCreateGrocery} from "@/hooks/firebase/useCreateGrocery";
|
||||
import {useCreateTodo} from "@/hooks/firebase/useCreateTodo";
|
||||
import {useUpdateTodo} from "@/hooks/firebase/useUpdateTodo";
|
||||
|
||||
export interface IToDo {
|
||||
id: number;
|
||||
title: string;
|
||||
done: boolean;
|
||||
date: Date | null;
|
||||
points?: number;
|
||||
rotate: boolean;
|
||||
repeatType: string;
|
||||
}
|
||||
|
||||
export const repeatOptions = [
|
||||
{ label: "None", value: "None" },
|
||||
{ label: "Every week", value: "Every week" },
|
||||
{ label: "Once a month", value: "Once a month" },
|
||||
{ label: "Once a year", value: "Once a year" },
|
||||
];
|
||||
|
||||
interface IToDosContext {
|
||||
toDos: IToDo[];
|
||||
updateToDo: (id: number, changes: Partial<IToDo>) => void;
|
||||
addToDo: (newToDo: IToDo) => void;
|
||||
maxPoints: number;
|
||||
}
|
||||
|
||||
const ToDosContext = createContext<IToDosContext>(undefined!);
|
||||
|
||||
export const ToDosContextProvider: FC<{ children: ReactNode }> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [toDos, setToDos] = useState<IToDo[]>([
|
||||
const initialTodosList = [
|
||||
{
|
||||
id: 0,
|
||||
title: "Pay: Credit card",
|
||||
@ -105,42 +82,57 @@ export const ToDosContextProvider: FC<{ children: ReactNode }> = ({
|
||||
repeatType: "None",
|
||||
points: 10,
|
||||
},
|
||||
]);
|
||||
];
|
||||
|
||||
export const repeatOptions = [
|
||||
{ label: "None", value: "None" },
|
||||
{ label: "Every week", value: "Every week" },
|
||||
{ label: "Once a month", value: "Once a month" },
|
||||
{ label: "Once a year", value: "Once a year" },
|
||||
];
|
||||
|
||||
interface IToDosContext {
|
||||
toDos: IToDo[];
|
||||
updateToDo: (changes: Partial<IToDo>) => void;
|
||||
addToDo: (newToDo: IToDo) => void;
|
||||
maxPoints: number;
|
||||
}
|
||||
|
||||
const ToDosContext = createContext<IToDosContext>(undefined!);
|
||||
|
||||
export const ToDosContextProvider: FC<{ children: ReactNode }> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { data: toDos } = useGetTodos();
|
||||
const { mutateAsync: createTodo } = useCreateTodo();
|
||||
const { mutateAsync: updateTodo } = useUpdateTodo();
|
||||
|
||||
const initCalc = (): number => {
|
||||
return toDos.reduce(
|
||||
return (toDos ?? []).reduce(
|
||||
(sum, todo) => sum + (todo.points ? todo.points : 0),
|
||||
50
|
||||
);
|
||||
};
|
||||
|
||||
const calculateMaxPoints = () => {
|
||||
const totalPoints = toDos.reduce(
|
||||
let totalPoints = 0;
|
||||
if (toDos) {
|
||||
totalPoints = toDos.reduce(
|
||||
(sum, todo) => sum + (todo.points ? todo.points : 0),
|
||||
0
|
||||
);
|
||||
}
|
||||
setMaxPoints(totalPoints);
|
||||
};
|
||||
|
||||
const [maxPoints, setMaxPoints] = useState<number>(initCalc);
|
||||
|
||||
const updateToDo = (id: number, changes: Partial<IToDo>) => {
|
||||
setToDos((prevToDos) =>
|
||||
prevToDos.map((toDo) => (toDo.id === id ? { ...toDo, ...changes } : toDo))
|
||||
);
|
||||
|
||||
calculateMaxPoints();
|
||||
const updateToDo = (changes: Partial<IToDo>) => {
|
||||
updateTodo(changes).then(calculateMaxPoints);
|
||||
};
|
||||
|
||||
const addToDo = (newToDo: IToDo) => {
|
||||
setToDos((prevToDos) => [
|
||||
...prevToDos,
|
||||
{
|
||||
...newToDo,
|
||||
id: prevToDos.length ? prevToDos[prevToDos.length - 1].id + 1 : 0,
|
||||
},
|
||||
]);
|
||||
calculateMaxPoints();
|
||||
createTodo(newToDo).then(calculateMaxPoints);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
11
hooks/firebase/types/todoData.ts
Normal file
11
hooks/firebase/types/todoData.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export interface IToDo {
|
||||
id: string;
|
||||
title: string;
|
||||
done: boolean;
|
||||
date: Date | null;
|
||||
points?: number;
|
||||
rotate: boolean;
|
||||
repeatType: string;
|
||||
creatorId?: string,
|
||||
familyId?: string
|
||||
}
|
||||
26
hooks/firebase/useCreateTodo.ts
Normal file
26
hooks/firebase/useCreateTodo.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { useMutation, useQueryClient } from "react-query";
|
||||
import firestore from "@react-native-firebase/firestore";
|
||||
import { useAuthContext } from "@/contexts/AuthContext";
|
||||
import { IToDo } from "@/hooks/firebase/types/todoData";
|
||||
|
||||
export const useCreateTodo = () => {
|
||||
const { user: currentUser, profileData } = useAuthContext();
|
||||
const queryClients = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ["createTodo"],
|
||||
mutationFn: async (todoData: Partial<IToDo>) => {
|
||||
try {
|
||||
const newDoc = firestore().collection('Todos').doc();
|
||||
await firestore()
|
||||
.collection("Todos")
|
||||
.add({...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClients.invalidateQueries("todos")
|
||||
}
|
||||
})
|
||||
}
|
||||
32
hooks/firebase/useGetTodos.ts
Normal file
32
hooks/firebase/useGetTodos.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { useQuery } from "react-query";
|
||||
import firestore from "@react-native-firebase/firestore";
|
||||
import { useAuthContext } from "@/contexts/AuthContext";
|
||||
|
||||
export const useGetTodos = () => {
|
||||
const { user, profileData } = useAuthContext();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ["todos", user?.uid],
|
||||
queryFn: async () => {
|
||||
const snapshot = await firestore()
|
||||
.collection("Todos")
|
||||
.where("familyId", "==", profileData?.familyId)
|
||||
.get();
|
||||
|
||||
return snapshot.docs.map((doc) => {
|
||||
const data = doc.data();
|
||||
|
||||
return {
|
||||
id: doc.id,
|
||||
title: data.title,
|
||||
done: data.done,
|
||||
date: data.date ? new Date(data.date.seconds * 1000) : null,
|
||||
points: data.points,
|
||||
rotate: data.points,
|
||||
repeatType: data.repeatType,
|
||||
creatorId: data.creatorId
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
};
|
||||
24
hooks/firebase/useUpdateTodo.ts
Normal file
24
hooks/firebase/useUpdateTodo.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { useMutation, useQueryClient } from "react-query";
|
||||
import firestore from "@react-native-firebase/firestore";
|
||||
import { IToDo } from "@/hooks/firebase/types/todoData";
|
||||
|
||||
export const useUpdateTodo = () => {
|
||||
const queryClients = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ["updateTodo"],
|
||||
mutationFn: async (todoData: Partial<IToDo>) => {
|
||||
try {
|
||||
await firestore()
|
||||
.collection("Todos")
|
||||
.doc(todoData.id)
|
||||
.update(todoData);
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClients.invalidateQueries("todos")
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user