mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 16:34:54 +00:00
- Rewrote add, edit groceries
- Added validation
This commit is contained in:
@ -1,33 +1,43 @@
|
||||
import { Text, TextField, TextFieldRef, View } from "react-native-ui-lib";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { GroceryCategory, useGroceryContext } from "@/contexts/GroceryContext";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { GroceryCategory, GroceryFrequency, useGroceryContext } from "@/contexts/GroceryContext";
|
||||
import { Dropdown } from "react-native-element-dropdown";
|
||||
import CloseXIcon from "@/assets/svgs/CloseXIcon";
|
||||
import { findNodeHandle, StyleSheet, UIManager } from "react-native";
|
||||
import {Alert, findNodeHandle, StyleSheet, UIManager} from "react-native";
|
||||
import DropdownIcon from "@/assets/svgs/DropdownIcon";
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||
import { IGrocery } from "@/hooks/firebase/types/groceryData";
|
||||
|
||||
interface IEditGrocery {
|
||||
id?: string;
|
||||
title: string;
|
||||
category: GroceryCategory;
|
||||
setTitle: (value: string) => void;
|
||||
setCategory?: (category: GroceryCategory) => void;
|
||||
setSubmit?: (value: boolean) => void;
|
||||
closeEdit?: () => void;
|
||||
handleEditSubmit?: Function;
|
||||
}
|
||||
const defaultGroceryItem = {
|
||||
id: "",
|
||||
title: "",
|
||||
category: GroceryCategory.None,
|
||||
approved: false,
|
||||
recurring: false,
|
||||
frequency: GroceryFrequency.Never,
|
||||
bought: false,
|
||||
};
|
||||
|
||||
const EditGroceryItem = ({
|
||||
editGrocery,
|
||||
onInputFocus,
|
||||
closeEdit
|
||||
}: {
|
||||
editGrocery: IEditGrocery;
|
||||
editGrocery?: IGrocery;
|
||||
onInputFocus: (y: number) => void;
|
||||
closeEdit?: Function
|
||||
}) => {
|
||||
const { fuzzyMatchGroceryCategory } = useGroceryContext();
|
||||
const inputRef = useRef<TextFieldRef>(null);
|
||||
const containerRef = useRef(null);
|
||||
const { profileData } = useAuthContext();
|
||||
const {
|
||||
updateGroceryItem,
|
||||
addGrocery,
|
||||
} = useGroceryContext();
|
||||
|
||||
const [grocery, setGrocery] = useState(editGrocery ?? defaultGroceryItem);
|
||||
|
||||
const handleFocus = () => {
|
||||
if (containerRef.current) {
|
||||
@ -57,29 +67,47 @@ const EditGroceryItem = ({
|
||||
})
|
||||
);
|
||||
|
||||
const handleClose = () => {
|
||||
setGrocery(defaultGroceryItem);
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
inputRef?.current?.blur();
|
||||
if (editGrocery.setSubmit) {
|
||||
editGrocery.setSubmit(true);
|
||||
if (validateGrocery()) {
|
||||
if (grocery?.id === "") {
|
||||
addGrocery({...grocery, approved: profileData?.userType === ProfileType.PARENT || profileData?.userType === ProfileType.CAREGIVER});
|
||||
} else {
|
||||
updateGroceryItem(grocery);
|
||||
}
|
||||
setGrocery(defaultGroceryItem);
|
||||
if (closeEdit) {
|
||||
closeEdit();
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const validateGrocery = () => {
|
||||
if (!grocery?.title || grocery?.title === "") {
|
||||
Alert.alert('Alert', 'Title field cannot be empty');
|
||||
return false;
|
||||
} else if (grocery.title?.length < 3 || grocery.title?.length > 25) {
|
||||
Alert.alert('Alert', 'Title should be between 3 and 25 characters');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!grocery?.category || grocery?.category === "") {
|
||||
Alert.alert('Alert', 'Category cannot be empty');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
if (editGrocery.handleEditSubmit) {
|
||||
editGrocery.handleEditSubmit({
|
||||
id: editGrocery.id,
|
||||
title: editGrocery.title,
|
||||
category: editGrocery.category,
|
||||
});
|
||||
}
|
||||
if (editGrocery.closeEdit) {
|
||||
editGrocery.closeEdit();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
|
||||
console.log(editGrocery.category);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -100,37 +128,36 @@ const EditGroceryItem = ({
|
||||
ref={inputRef}
|
||||
onFocus={handleFocus}
|
||||
placeholder="Grocery"
|
||||
value={editGrocery.title}
|
||||
value={grocery?.title}
|
||||
onSubmitEditing={handleSubmit}
|
||||
numberOfLines={1}
|
||||
returnKeyType="done"
|
||||
onChangeText={(value) => {
|
||||
editGrocery.setTitle(value);
|
||||
let groceryCategory = fuzzyMatchGroceryCategory(value);
|
||||
if (editGrocery.setCategory) {
|
||||
editGrocery.setCategory(groceryCategory);
|
||||
}
|
||||
setGrocery((oldData) => ({...oldData, title: value, category: groceryCategory}));
|
||||
}}
|
||||
maxLength={25}
|
||||
/>
|
||||
{(editGrocery.title || editGrocery.title !== "") && <View row centerV>
|
||||
<AntDesign
|
||||
name="check"
|
||||
size={24}
|
||||
style={{
|
||||
color: "green",
|
||||
marginRight: 15,
|
||||
}}
|
||||
onPress={handleSubmit}
|
||||
/>
|
||||
<CloseXIcon
|
||||
onPress={() => {
|
||||
if (editGrocery.closeEdit) {
|
||||
editGrocery.closeEdit();
|
||||
{(grocery?.title !== "") &&
|
||||
<View row centerV>
|
||||
{grocery.title?.length > 2 && grocery.title?.length <= 25 &&
|
||||
<AntDesign
|
||||
name="check"
|
||||
size={24}
|
||||
style={{
|
||||
color: "green",
|
||||
marginRight: 15,
|
||||
}}
|
||||
onPress={handleSubmit}
|
||||
/>
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>}
|
||||
<CloseXIcon
|
||||
onPress={() => {
|
||||
handleClose();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
</View>
|
||||
<Dropdown
|
||||
style={{ marginTop: 15 }}
|
||||
@ -143,7 +170,7 @@ const EditGroceryItem = ({
|
||||
}}
|
||||
labelField="label"
|
||||
valueField="value"
|
||||
value={editGrocery.category}
|
||||
value={grocery?.category ?? GroceryCategory.None}
|
||||
iconColor="white"
|
||||
activeColor={"#fd1775"}
|
||||
containerStyle={styles.dropdownStyle}
|
||||
@ -154,7 +181,7 @@ const EditGroceryItem = ({
|
||||
<DropdownIcon
|
||||
style={{ marginRight: 8 }}
|
||||
color={
|
||||
editGrocery.category == GroceryCategory.None
|
||||
grocery?.category == GroceryCategory.None
|
||||
? "#7b7b7b"
|
||||
: "#fd1775"
|
||||
}
|
||||
@ -168,17 +195,7 @@ const EditGroceryItem = ({
|
||||
);
|
||||
}}
|
||||
onChange={(item) => {
|
||||
if (editGrocery.handleEditSubmit) {
|
||||
editGrocery.handleEditSubmit({
|
||||
id: editGrocery.id,
|
||||
category: item.value,
|
||||
});
|
||||
if (editGrocery.closeEdit) editGrocery.closeEdit();
|
||||
} else {
|
||||
if (editGrocery.setCategory) {
|
||||
editGrocery.setCategory(item.value);
|
||||
}
|
||||
}
|
||||
setGrocery((oldData) => ({...oldData, category: item.value}));
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Checkbox, Text, TouchableOpacity, View } from "react-native-ui-lib";
|
||||
import React, { useState } from "react";
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
import { GroceryCategory, useGroceryContext } from "@/contexts/GroceryContext";
|
||||
import { useGroceryContext } from "@/contexts/GroceryContext";
|
||||
import EditGroceryFrequency from "./EditGroceryFrequency";
|
||||
import EditGroceryItem from "./EditGroceryItem";
|
||||
import { ImageBackground, StyleSheet } from "react-native";
|
||||
@ -32,10 +32,6 @@ const GroceryItem = ({
|
||||
|
||||
const [openFreqEdit, setOpenFreqEdit] = useState<boolean>(false);
|
||||
const [isEditingTitle, setIsEditingTitle] = useState<boolean>(false);
|
||||
const [newTitle, setNewTitle] = useState<string>(item.title ?? "");
|
||||
const [category, setCategory] = useState<GroceryCategory>(
|
||||
item.category ?? GroceryCategory.None
|
||||
);
|
||||
|
||||
const closeEdit = () => setIsEditingTitle(false);
|
||||
|
||||
@ -72,15 +68,9 @@ const GroceryItem = ({
|
||||
|
||||
{isEditingTitle ? (
|
||||
<EditGroceryItem
|
||||
editGrocery={{
|
||||
id: item.id,
|
||||
title: newTitle,
|
||||
category: category,
|
||||
setTitle: setNewTitle,
|
||||
setCategory: setCategory,
|
||||
closeEdit: closeEdit,
|
||||
}}
|
||||
editGrocery={item}
|
||||
onInputFocus={onInputFocus}
|
||||
closeEdit={closeEdit}
|
||||
/>
|
||||
) : (
|
||||
<View flex>
|
||||
|
||||
@ -2,11 +2,10 @@ import { ActivityIndicator, Dimensions, FlatList, StyleSheet } from "react-nativ
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Text, TouchableOpacity, View } from "react-native-ui-lib";
|
||||
import GroceryItem from "./GroceryItem";
|
||||
import { GroceryCategory, GroceryFrequency, useGroceryContext } from "@/contexts/GroceryContext";
|
||||
import { useGroceryContext } from "@/contexts/GroceryContext";
|
||||
import HeaderTemplate from "@/components/shared/HeaderTemplate";
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
import EditGroceryItem from "./EditGroceryItem";
|
||||
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||
import { IGrocery } from "@/hooks/firebase/types/groceryData";
|
||||
import Ionicons from '@expo/vector-icons/Ionicons';
|
||||
import AddChoreDialog from "@/components/pages/todos/AddChoreDialog";
|
||||
@ -28,24 +27,14 @@ const GroceryList = ({onInputFocus}: {onInputFocus: (y: number) => void}) => {
|
||||
const {
|
||||
groceries,
|
||||
updateGroceryItem,
|
||||
isAddingGrocery,
|
||||
setIsAddingGrocery,
|
||||
addGrocery,
|
||||
} = useGroceryContext();
|
||||
|
||||
const { profileData } = useAuthContext();
|
||||
const [approvedGroceries, setApprovedGroceries] = useState<IGrocery[]>(
|
||||
groceries?.filter((item) => item.approved)
|
||||
);
|
||||
const [pendingGroceries, setPendingGroceries] = useState<IGrocery[]>(
|
||||
groceries?.filter((item) => !item.approved)
|
||||
);
|
||||
const [category, setCategory] = useState<GroceryCategory>(
|
||||
GroceryCategory.None
|
||||
);
|
||||
|
||||
const [title, setTitle] = useState<string>("");
|
||||
const [submit, setSubmitted] = useState<boolean>(false);
|
||||
|
||||
const [pendingVisible, setPendingVisible] = useState<boolean>(true);
|
||||
const [approvedVisible, setApprovedVisible] = useState<boolean>(true);
|
||||
@ -74,37 +63,11 @@ const GroceryList = ({onInputFocus}: {onInputFocus: (y: number) => void}) => {
|
||||
{}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (submit) {
|
||||
if (title?.length > 2 && title?.length <= 25) {
|
||||
addGrocery({
|
||||
id: "",
|
||||
title: title,
|
||||
category: category,
|
||||
approved: profileData?.userType === ProfileType.PARENT || profileData?.userType === ProfileType.CAREGIVER,
|
||||
recurring: false,
|
||||
frequency: GroceryFrequency.Never,
|
||||
bought: false,
|
||||
});
|
||||
|
||||
setIsAddingGrocery(false);
|
||||
setSubmitted(false);
|
||||
setTitle("");
|
||||
}
|
||||
}
|
||||
}, [submit]);
|
||||
|
||||
useEffect(() => {
|
||||
setApprovedGroceries(groceries?.filter((item) => item.approved));
|
||||
setPendingGroceries(groceries?.filter((item) => !item.approved));
|
||||
}, [groceries]);
|
||||
|
||||
const handleCancelAddGrocery = () => {
|
||||
setIsAddingGrocery(false);
|
||||
setTitle("");
|
||||
setCategory(GroceryCategory.None)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{!groceries &&
|
||||
@ -260,14 +223,6 @@ const GroceryList = ({onInputFocus}: {onInputFocus: (y: number) => void}) => {
|
||||
</View>
|
||||
<View style={{marginTop: 8}}>
|
||||
<EditGroceryItem
|
||||
editGrocery={{
|
||||
title: title,
|
||||
setCategory: setCategory,
|
||||
category: category,
|
||||
setTitle: setTitle,
|
||||
setSubmit: setSubmitted,
|
||||
closeEdit: handleCancelAddGrocery
|
||||
}}
|
||||
onInputFocus={onInputFocus}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { Dimensions, ScrollView, Keyboard, Platform } from "react-native";
|
||||
import { View } from "react-native-ui-lib";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import AddGroceryItem from "./AddGroceryItem";
|
||||
import GroceryList from "./GroceryList";
|
||||
import { useGroceryContext } from "@/contexts/GroceryContext";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user