mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 16:34:54 +00:00
- Implemented optimistic update when completing todos and groceries to avoid delays
This commit is contained in:
@ -1,12 +1,11 @@
|
|||||||
import { Checkbox, Text, TouchableOpacity, View } from "react-native-ui-lib";
|
import { Checkbox, Text, TouchableOpacity, View } from "react-native-ui-lib";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { AntDesign } from "@expo/vector-icons";
|
import { AntDesign } from "@expo/vector-icons";
|
||||||
import { GroceryCategory, useGroceryContext } from "@/contexts/GroceryContext";
|
import { GroceryCategory, useGroceryContext } from "@/contexts/GroceryContext";
|
||||||
import EditGroceryFrequency from "./EditGroceryFrequency";
|
import EditGroceryFrequency from "./EditGroceryFrequency";
|
||||||
import EditGroceryItem from "./EditGroceryItem";
|
import EditGroceryItem from "./EditGroceryItem";
|
||||||
import { ImageBackground, StyleSheet } from "react-native";
|
import { ImageBackground, StyleSheet } from "react-native";
|
||||||
import { IGrocery } from "@/hooks/firebase/types/groceryData";
|
import { IGrocery } from "@/hooks/firebase/types/groceryData";
|
||||||
import { UserProfile } from "@/hooks/firebase/types/profileTypes";
|
|
||||||
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||||
import { useGetUserById } from "@/hooks/firebase/useGetUserById";
|
import { useGetUserById } from "@/hooks/firebase/useGetUserById";
|
||||||
import { useDeleteGrocery } from "@/hooks/firebase/useDeleteGrocery";
|
import { useDeleteGrocery } from "@/hooks/firebase/useDeleteGrocery";
|
||||||
@ -15,10 +14,14 @@ const GroceryItem = ({
|
|||||||
item,
|
item,
|
||||||
handleItemApproved,
|
handleItemApproved,
|
||||||
onInputFocus,
|
onInputFocus,
|
||||||
|
approvedGroceries,
|
||||||
|
setApprovedGroceries
|
||||||
}: {
|
}: {
|
||||||
item: IGrocery;
|
item: IGrocery;
|
||||||
handleItemApproved: (id: string, changes: Partial<IGrocery>) => void;
|
handleItemApproved: (id: string, changes: Partial<IGrocery>) => void;
|
||||||
onInputFocus: (y: number) => void;
|
onInputFocus: (y: number) => void;
|
||||||
|
approvedGroceries?: Array<IGrocery>,
|
||||||
|
setApprovedGroceries?: Function
|
||||||
}) => {
|
}) => {
|
||||||
const { updateGroceryItem } = useGroceryContext();
|
const { updateGroceryItem } = useGroceryContext();
|
||||||
const { mutateAsync: deleteGrocery } = useDeleteGrocery();
|
const { mutateAsync: deleteGrocery } = useDeleteGrocery();
|
||||||
@ -150,9 +153,11 @@ const GroceryItem = ({
|
|||||||
borderRadius={50}
|
borderRadius={50}
|
||||||
color="#fd1575"
|
color="#fd1575"
|
||||||
hitSlop={20}
|
hitSlop={20}
|
||||||
onValueChange={() =>
|
onValueChange={() => {
|
||||||
|
const updatedApprovedGroceries = approvedGroceries.map((grocery) => grocery.id === item.id ? {...grocery, bought: !item.bought} : grocery);
|
||||||
|
setApprovedGroceries(updatedApprovedGroceries);
|
||||||
updateGroceryItem({ id: item.id, bought: !item.bought })
|
updateGroceryItem({ id: item.id, bought: !item.bought })
|
||||||
}
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -33,7 +33,7 @@ const GroceryList = ({onInputFocus}: {onInputFocus: (y: number) => void}) => {
|
|||||||
addGrocery,
|
addGrocery,
|
||||||
} = useGroceryContext();
|
} = useGroceryContext();
|
||||||
const {profileData} = useAuthContext();
|
const {profileData} = useAuthContext();
|
||||||
const [approvedGroceries, setapprovedGroceries] = useState<IGrocery[]>(
|
const [approvedGroceries, setApprovedGroceries] = useState<IGrocery[]>(
|
||||||
groceries?.filter((item) => item.approved)
|
groceries?.filter((item) => item.approved)
|
||||||
);
|
);
|
||||||
const [pendingGroceries, setPendingGroceries] = useState<IGrocery[]>(
|
const [pendingGroceries, setPendingGroceries] = useState<IGrocery[]>(
|
||||||
@ -94,7 +94,7 @@ const GroceryList = ({onInputFocus}: {onInputFocus: (y: number) => void}) => {
|
|||||||
}, [submit]);
|
}, [submit]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setapprovedGroceries(groceries?.filter((item) => item.approved));
|
setApprovedGroceries(groceries?.filter((item) => item.approved));
|
||||||
setPendingGroceries(groceries?.filter((item) => !item.approved));
|
setPendingGroceries(groceries?.filter((item) => !item.approved));
|
||||||
}, [groceries]);
|
}, [groceries]);
|
||||||
|
|
||||||
@ -290,6 +290,8 @@ const GroceryList = ({onInputFocus}: {onInputFocus: (y: number) => void}) => {
|
|||||||
updateGroceryItem({...changes, id: id})
|
updateGroceryItem({...changes, id: id})
|
||||||
}
|
}
|
||||||
onInputFocus={onInputFocus}
|
onInputFocus={onInputFocus}
|
||||||
|
approvedGroceries={approvedGroceries}
|
||||||
|
setApprovedGroceries={setApprovedGroceries}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -25,6 +25,8 @@ const ToDoItem = (props: {
|
|||||||
item: IToDo;
|
item: IToDo;
|
||||||
isSettings?: boolean;
|
isSettings?: boolean;
|
||||||
is7Days?: boolean;
|
is7Days?: boolean;
|
||||||
|
localTodos: Array<IToDo>;
|
||||||
|
setLocalTodos: Function
|
||||||
}) => {
|
}) => {
|
||||||
const { updateToDo } = useToDosContext();
|
const { updateToDo } = useToDosContext();
|
||||||
const { data: members } = useGetFamilyMembers();
|
const { data: members } = useGetFamilyMembers();
|
||||||
@ -131,6 +133,8 @@ const ToDoItem = (props: {
|
|||||||
borderRadius={50}
|
borderRadius={50}
|
||||||
color="#fd1575"
|
color="#fd1575"
|
||||||
onValueChange={() => {
|
onValueChange={() => {
|
||||||
|
const updatedTodos = props.localTodos?.map((item) => item.id === props.item.id ? { ...item, done: !props.item.done } : item);
|
||||||
|
props.setLocalTodos(updatedTodos);
|
||||||
updateToDo({ id: props.item.id, done: !props.item.done });
|
updateToDo({ id: props.item.id, done: !props.item.done });
|
||||||
if (!props.item.done && isChild) {
|
if (!props.item.done && isChild) {
|
||||||
handleTodoClickAnimation();
|
handleTodoClickAnimation();
|
||||||
|
|||||||
@ -110,6 +110,11 @@ const resolveFilterOptions = (members, user) => {
|
|||||||
|
|
||||||
const ToDosList = ({ isSettings, members }: { isSettings?: boolean, members?: Array<UserProfile> }) => {
|
const ToDosList = ({ isSettings, members }: { isSettings?: boolean, members?: Array<UserProfile> }) => {
|
||||||
const { toDos } = useToDosContext();
|
const { toDos } = useToDosContext();
|
||||||
|
const [localTodos, setLocalTodos] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLocalTodos(toDos);
|
||||||
|
}, [toDos]);
|
||||||
|
|
||||||
const [groupedToDos, setGroupedToDos] = useState([]);
|
const [groupedToDos, setGroupedToDos] = useState([]);
|
||||||
const { user } = useAuthContext()
|
const { user } = useAuthContext()
|
||||||
@ -131,18 +136,18 @@ const ToDosList = ({ isSettings, members }: { isSettings?: boolean, members?: Ar
|
|||||||
}, [JSON.stringify(members)]);
|
}, [JSON.stringify(members)]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (toDos && selectedFilter) {
|
if (localTodos && selectedFilter) {
|
||||||
let resolvedGroupedTodos;
|
let resolvedGroupedTodos;
|
||||||
if (selectedFilter?.value === FILTER_OPTIONS.EVERYONE) {
|
if (selectedFilter?.value === FILTER_OPTIONS.EVERYONE) {
|
||||||
resolvedGroupedTodos = groupToDosByDate(toDos ?? []);
|
resolvedGroupedTodos = groupToDosByDate(toDos ?? []);
|
||||||
} else {
|
} else {
|
||||||
let filtered = toDos?.filter((todo) => todo.assignees?.includes(selectedFilter.value)) || [];
|
let filtered = localTodos?.filter((todo) => todo.assignees?.includes(selectedFilter.value)) || [];
|
||||||
|
|
||||||
resolvedGroupedTodos = groupToDosByDate(filtered || []);
|
resolvedGroupedTodos = groupToDosByDate(filtered || []);
|
||||||
}
|
}
|
||||||
setGroupedToDos(resolvedGroupedTodos || []);
|
setGroupedToDos(resolvedGroupedTodos || []);
|
||||||
}
|
}
|
||||||
}, [selectedFilter, JSON.stringify(toDos)]);
|
}, [selectedFilter, JSON.stringify(localTodos)]);
|
||||||
|
|
||||||
const toggleExpand = (dateKey: string) => {
|
const toggleExpand = (dateKey: string) => {
|
||||||
setExpandedGroups((prev) => ({
|
setExpandedGroups((prev) => ({
|
||||||
@ -231,6 +236,8 @@ const ToDosList = ({ isSettings, members }: { isSettings?: boolean, members?: Ar
|
|||||||
key={item.id}
|
key={item.id}
|
||||||
item={item}
|
item={item}
|
||||||
is7Days={false}
|
is7Days={false}
|
||||||
|
localTodos={localTodos}
|
||||||
|
setLocalTodos={setLocalTodos}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
@ -281,6 +288,8 @@ const ToDosList = ({ isSettings, members }: { isSettings?: boolean, members?: Ar
|
|||||||
key={item.id}
|
key={item.id}
|
||||||
item={item}
|
item={item}
|
||||||
is7Days={dateKey === "Next 7 Days"}
|
is7Days={dateKey === "Next 7 Days"}
|
||||||
|
localTodos={localTodos}
|
||||||
|
setLocalTodos={setLocalTodos}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
@ -347,7 +356,7 @@ const ToDosList = ({ isSettings, members }: { isSettings?: boolean, members?: Ar
|
|||||||
noDateToDos
|
noDateToDos
|
||||||
.sort((a, b) => Number(a.done) - Number(b.done))
|
.sort((a, b) => Number(a.done) - Number(b.done))
|
||||||
.map((item) => (
|
.map((item) => (
|
||||||
<ToDoItem isSettings={isSettings} key={item.id} item={item} />
|
<ToDoItem isSettings={isSettings} key={item.id} item={item} localTodos={localTodos} setLocalTodos={setLocalTodos} />
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user