mirror of
https://github.com/urosran/cally.git
synced 2025-08-26 06:09:40 +00:00
add groceryContext and manipulation
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -20,3 +20,4 @@ expo-env.d.ts
|
|||||||
# @end expo-cli
|
# @end expo-cli
|
||||||
/ios/GoogleService-Info.plist
|
/ios/GoogleService-Info.plist
|
||||||
/ios/cally.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
|
/ios/cally.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
|
||||||
|
expo-env.d.ts
|
||||||
|
@ -4,34 +4,19 @@ import Octicons from "@expo/vector-icons/Octicons";
|
|||||||
import GroceryList from "@/components/pages/grocery/GroceryList";
|
import GroceryList from "@/components/pages/grocery/GroceryList";
|
||||||
import AddGroceryItem from "@/components/pages/grocery/AddGroceryItem";
|
import AddGroceryItem from "@/components/pages/grocery/AddGroceryItem";
|
||||||
import { useAuthContext } from "@/contexts/AuthContext";
|
import { useAuthContext } from "@/contexts/AuthContext";
|
||||||
|
import { GroceryProvider } from "@/contexts/GroceryContext";
|
||||||
|
import TopDisplay from "@/components/pages/grocery/TopDisplay";
|
||||||
|
|
||||||
export default function Screen() {
|
export default function Screen() {
|
||||||
return (
|
return (
|
||||||
<View>
|
<GroceryProvider>
|
||||||
<AddGroceryItem />
|
<View>
|
||||||
<View backgroundColor="#e1e1e1" paddingL-20 paddingT-20 paddingB-10>
|
<AddGroceryItem />
|
||||||
<Text text50BL marginB-10 color="black">
|
<TopDisplay />
|
||||||
Welcome to your grocery list!
|
<View>
|
||||||
</Text>
|
<GroceryList />
|
||||||
<View row bottom style={{ justifyContent: "space-between" }}>
|
|
||||||
<View>
|
|
||||||
<Text text70BL color="black">
|
|
||||||
X approved items
|
|
||||||
</Text>
|
|
||||||
<Text text70BL color="black">
|
|
||||||
Y pending items
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<Button
|
|
||||||
backgroundColor="#e1e1e1"
|
|
||||||
right
|
|
||||||
children={<Octicons name="share" size={24} color="black" />}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View>
|
</GroceryProvider>
|
||||||
<GroceryList />
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,13 @@ import {
|
|||||||
View,
|
View,
|
||||||
PanningProvider,
|
PanningProvider,
|
||||||
} from "react-native-ui-lib";
|
} from "react-native-ui-lib";
|
||||||
|
import { useGroceryContext } from "@/contexts/GroceryContext";
|
||||||
interface AddGroceryItemProps {
|
interface AddGroceryItemProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
const AddGroceryItem = () => {
|
const AddGroceryItem = () => {
|
||||||
|
const { setIsShopping, isShopping } = useGroceryContext();
|
||||||
const [visible, setVisible] = useState<boolean>(false);
|
const [visible, setVisible] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleShowDialog = () => {
|
const handleShowDialog = () => {
|
||||||
@ -52,18 +54,38 @@ const AddGroceryItem = () => {
|
|||||||
height: 60,
|
height: 60,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
{!isShopping ? (
|
||||||
label="View shopping list"
|
<View style={styles.btnContainer} row>
|
||||||
color="#337a11"
|
<Button
|
||||||
backgroundColor="#c6e0b3"
|
label="View shopping list"
|
||||||
/>
|
color="#337a11"
|
||||||
<Button
|
flex-2
|
||||||
color="white"
|
marginR-5
|
||||||
backgroundColor="#19ad61"
|
backgroundColor="#c6e0b3"
|
||||||
label="Create new"
|
onPress={() => setIsShopping(true)}
|
||||||
enableShadow
|
/>
|
||||||
onPress={() => setVisible(true)}
|
<Button
|
||||||
/>
|
label="Create new"
|
||||||
|
color="white"
|
||||||
|
flex-1
|
||||||
|
backgroundColor="#19ad61"
|
||||||
|
enableShadow
|
||||||
|
onPress={() => {}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View style={styles.btnContainer} row>
|
||||||
|
<Button
|
||||||
|
color="white"
|
||||||
|
backgroundColor="#81a861"
|
||||||
|
label="Finish shopping"
|
||||||
|
text70BL
|
||||||
|
style={styles.finishShopBtn}
|
||||||
|
enableShadow
|
||||||
|
onPress={() => setIsShopping(false)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
{addGroceryDialog}
|
{addGroceryDialog}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
@ -94,4 +116,15 @@ const styles = StyleSheet.create({
|
|||||||
backgroundColor: "#E0E0E0",
|
backgroundColor: "#E0E0E0",
|
||||||
marginVertical: 10,
|
marginVertical: 10,
|
||||||
},
|
},
|
||||||
|
btnContainer: {
|
||||||
|
width: "100%",
|
||||||
|
justifyContent: "center",
|
||||||
|
},
|
||||||
|
finishShopBtn: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
shoppingBtn: {
|
||||||
|
flex: 1,
|
||||||
|
marginHorizontal: 3,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -9,14 +9,18 @@ import {
|
|||||||
Picker,
|
Picker,
|
||||||
PickerValue,
|
PickerValue,
|
||||||
} from "react-native-ui-lib";
|
} from "react-native-ui-lib";
|
||||||
import { GroceryFrequency, IGrocery } from "./GroceryItem";
|
import {
|
||||||
interface EditGroceryItemProps {
|
GroceryFrequency,
|
||||||
|
IGrocery,
|
||||||
|
useGroceryContext,
|
||||||
|
} from "@/contexts/GroceryContext";
|
||||||
|
interface EditGroceryFrequencyProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
item: IGrocery;
|
item: IGrocery;
|
||||||
}
|
}
|
||||||
const EditGroceryItem = (props: EditGroceryItemProps) => {
|
const EditGroceryFrequency = (props: EditGroceryFrequencyProps) => {
|
||||||
const [recurring, setRecurring] = useState<boolean>(false);
|
const { updateGroceryItem } = useGroceryContext();
|
||||||
const pickerItems = Object.values(GroceryFrequency).map((value) => ({
|
const pickerItems = Object.values(GroceryFrequency).map((value) => ({
|
||||||
label: value,
|
label: value,
|
||||||
value: value,
|
value: value,
|
||||||
@ -35,18 +39,26 @@ const EditGroceryItem = (props: EditGroceryItemProps) => {
|
|||||||
<View style={styles.inner}>
|
<View style={styles.inner}>
|
||||||
<View row spread>
|
<View row spread>
|
||||||
<Text text70>Recurring</Text>
|
<Text text70>Recurring</Text>
|
||||||
<Switch value={recurring} onValueChange={value => setRecurring(value)} onColor={'lime'}/>
|
<Switch
|
||||||
|
value={props.item.recurring}
|
||||||
|
onValueChange={(value) =>
|
||||||
|
updateGroceryItem(props.item.id, { recurring: value })
|
||||||
|
}
|
||||||
|
onColor={"lime"}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Picker
|
<Picker
|
||||||
value={props.item.frequency}
|
value={props.item.frequency}
|
||||||
fieldType="form"
|
fieldType="form"
|
||||||
useWheelPicker
|
useDialog
|
||||||
items={pickerItems}
|
items={pickerItems}
|
||||||
onChange={(item: PickerValue) => {
|
onChange={(item: PickerValue) => {
|
||||||
const selectedFrequency =
|
const selectedFrequency =
|
||||||
GroceryFrequency[item as keyof typeof GroceryFrequency];
|
GroceryFrequency[item as keyof typeof GroceryFrequency];
|
||||||
if (selectedFrequency) {
|
if (selectedFrequency) {
|
||||||
//props.handleFrequency(props.item.id, selectedFrequency);
|
updateGroceryItem(props.item.id, {
|
||||||
|
frequency: selectedFrequency,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
console.error("Invalid frequency selected");
|
console.error("Invalid frequency selected");
|
||||||
}
|
}
|
||||||
@ -58,7 +70,7 @@ const EditGroceryItem = (props: EditGroceryItemProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EditGroceryItem;
|
export default EditGroceryFrequency;
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
@ -1,82 +1,54 @@
|
|||||||
import { View, Text, Button } from "react-native-ui-lib";
|
import {
|
||||||
import React, { useState } from "react";
|
View,
|
||||||
|
Text,
|
||||||
|
Button,
|
||||||
|
TouchableOpacity,
|
||||||
|
Checkbox,
|
||||||
|
} from "react-native-ui-lib";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||||
import { MaterialCommunityIcons, AntDesign } from "@expo/vector-icons";
|
import { MaterialCommunityIcons, AntDesign } from "@expo/vector-icons";
|
||||||
import { ListItem } from "react-native-ui-lib";
|
import { ListItem } from "react-native-ui-lib";
|
||||||
import EditGroceryItem from "./EditGroceryItem";
|
import { IGrocery, useGroceryContext } from "@/contexts/GroceryContext";
|
||||||
|
import EditGroceryFrequency from "./EditGroceryFrequency";
|
||||||
export enum GroceryFrequency {
|
import { TextInput } from "react-native";
|
||||||
Never = "Never",
|
|
||||||
Daily = "Daily",
|
|
||||||
Weekly = "Weekly",
|
|
||||||
BiWeekly = "BiWeekly",
|
|
||||||
Monthly = "Monthly",
|
|
||||||
Quarterly = "Quarterly",
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IGrocery {
|
|
||||||
id: number;
|
|
||||||
title: String;
|
|
||||||
category: GroceryCategory;
|
|
||||||
approved: boolean;
|
|
||||||
recurring: boolean;
|
|
||||||
frequency: GroceryFrequency;
|
|
||||||
bought: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum GroceryCategory {
|
|
||||||
Fruit = "Fruit",
|
|
||||||
Dairy = "Dairy",
|
|
||||||
Vegetables = "Vegetables",
|
|
||||||
Meat = "Meat",
|
|
||||||
Poultry = "Poultry",
|
|
||||||
Bakery = "Bakery",
|
|
||||||
Beverages = "Beverages",
|
|
||||||
Snacks = "Snacks",
|
|
||||||
Household = "Household",
|
|
||||||
PersonalCare = "Personal Care",
|
|
||||||
Frozen = "Frozen",
|
|
||||||
}
|
|
||||||
|
|
||||||
type MaterialIconNames = keyof typeof MaterialCommunityIcons.glyphMap;
|
|
||||||
const iconMapping: { [key in GroceryCategory]: MaterialIconNames } = {
|
|
||||||
//за сад се иконице за категорију бирају одавде
|
|
||||||
[GroceryCategory.Fruit]: "food-apple",
|
|
||||||
[GroceryCategory.Dairy]: "cheese",
|
|
||||||
[GroceryCategory.Vegetables]: "carrot",
|
|
||||||
[GroceryCategory.Meat]: "food-steak",
|
|
||||||
[GroceryCategory.Poultry]: "food-drumstick",
|
|
||||||
[GroceryCategory.Bakery]: "bread-slice",
|
|
||||||
[GroceryCategory.Beverages]: "cup-water",
|
|
||||||
[GroceryCategory.Snacks]: "candy",
|
|
||||||
[GroceryCategory.Household]: "home",
|
|
||||||
[GroceryCategory.PersonalCare]: "face-man-profile",
|
|
||||||
[GroceryCategory.Frozen]: "snowflake",
|
|
||||||
};
|
|
||||||
|
|
||||||
const GroceryItem = ({
|
const GroceryItem = ({
|
||||||
item,
|
item,
|
||||||
handleItemApproved,
|
handleItemApproved,
|
||||||
}: {
|
}: {
|
||||||
item: IGrocery;
|
item: IGrocery;
|
||||||
handleItemApproved: (id: number, approved: boolean) => void;
|
handleItemApproved: (id: number, changes: Partial<IGrocery>) => void;
|
||||||
|
|
||||||
}) => {
|
}) => {
|
||||||
|
const { iconMapping, updateGroceryItem, groceries, isShopping } =
|
||||||
|
useGroceryContext();
|
||||||
|
|
||||||
const { profileType } = useAuthContext();
|
const { profileType } = useAuthContext();
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
const [openFreqEdit, setOpenFreqEdit] = useState<boolean>(false);
|
||||||
|
const [isEditingTitle, setIsEditingTitle] = useState<boolean>(false);
|
||||||
|
const [newTitle, setNewTitle] = useState<string>("");
|
||||||
|
|
||||||
|
const handleTitleChange = (newTitle: string) => {
|
||||||
|
updateGroceryItem(item.id, { title: newTitle });
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setNewTitle(item.title);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
backgroundColor="white"
|
backgroundColor="white"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setOpen(true);
|
setOpenFreqEdit(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<EditGroceryItem
|
<EditGroceryFrequency
|
||||||
visible={open}
|
visible={openFreqEdit}
|
||||||
key={item.id}
|
key={item.id}
|
||||||
item={item}
|
item={item}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setOpen(false);
|
setOpenFreqEdit(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ListItem.Part left containerStyle={{ flex: 1, paddingStart: 15 }}>
|
<ListItem.Part left containerStyle={{ flex: 1, paddingStart: 15 }}>
|
||||||
@ -95,14 +67,35 @@ const GroceryItem = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<View>
|
<View>
|
||||||
<Text>{item.title}</Text>
|
{!isEditingTitle ? (
|
||||||
|
<TouchableOpacity onPress={() => setIsEditingTitle(true)}>
|
||||||
|
<Text text70BL>{item.title}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
) : (
|
||||||
|
<TextInput
|
||||||
|
value={item.title}
|
||||||
|
onChangeText={handleTitleChange}
|
||||||
|
onBlur={() => {
|
||||||
|
setIsEditingTitle(false);
|
||||||
|
console.log(groceries);
|
||||||
|
}}
|
||||||
|
autoFocus
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
padding: 0,
|
||||||
|
margin: 0,
|
||||||
|
fontWeight: "bold",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Text>{iconMapping[item.category]}</Text>
|
<Text>{iconMapping[item.category]}</Text>
|
||||||
</View>
|
</View>
|
||||||
</ListItem.Part>
|
</ListItem.Part>
|
||||||
<ListItem.Part right containerStyle={{ paddingEnd: 15 }}>
|
<ListItem.Part right containerStyle={{ paddingEnd: 15 }}>
|
||||||
{profileType == ProfileType.PARENT ? (
|
{profileType == ProfileType.PARENT && !isShopping ? (
|
||||||
<View row>
|
<View row>
|
||||||
<Button
|
<Button
|
||||||
|
padding-0
|
||||||
children={
|
children={
|
||||||
<AntDesign
|
<AntDesign
|
||||||
name="check"
|
name="check"
|
||||||
@ -115,10 +108,11 @@ const GroceryItem = ({
|
|||||||
backgroundColor="transparent"
|
backgroundColor="transparent"
|
||||||
size={Button.sizes.small}
|
size={Button.sizes.small}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
handleItemApproved(item.id, true);
|
handleItemApproved(item.id, { approved: true });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
padding-0
|
||||||
children={
|
children={
|
||||||
<AntDesign
|
<AntDesign
|
||||||
name="close"
|
name="close"
|
||||||
@ -129,18 +123,18 @@ const GroceryItem = ({
|
|||||||
backgroundColor="transparent"
|
backgroundColor="transparent"
|
||||||
size={Button.sizes.small}
|
size={Button.sizes.small}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
handleItemApproved(item.id, false);
|
handleItemApproved(item.id, { approved: false });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<Text style={{ color: item.bought ? "green" : "red" }}>
|
<Checkbox
|
||||||
{item.approved ? (
|
value={item.bought}
|
||||||
<AntDesign name="check" size={24} color={"green"} />
|
color={"#f58749"}
|
||||||
) : (
|
onValueChange={() =>
|
||||||
"X"
|
updateGroceryItem(item.id, { bought: !item.bought })
|
||||||
)}
|
}
|
||||||
</Text>
|
/>
|
||||||
)}
|
)}
|
||||||
</ListItem.Part>
|
</ListItem.Part>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
@ -5,61 +5,18 @@ import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons";
|
|||||||
import { useAuthContext } from "@/contexts/AuthContext";
|
import { useAuthContext } from "@/contexts/AuthContext";
|
||||||
import AntDesign from "@expo/vector-icons/AntDesign";
|
import AntDesign from "@expo/vector-icons/AntDesign";
|
||||||
import AddGroceryItem from "./AddGroceryItem";
|
import AddGroceryItem from "./AddGroceryItem";
|
||||||
import GroceryItem, { IGrocery, GroceryCategory, GroceryFrequency } from "./GroceryItem";
|
import GroceryItem from "./GroceryItem";
|
||||||
|
import { useGroceryContext } from "@/contexts/GroceryContext";
|
||||||
|
|
||||||
const GroceryList = () => {
|
const GroceryList = () => {
|
||||||
const [groceries, setGroceries] = useState<IGrocery[]>([
|
const { groceries, updateGroceryItem } = useGroceryContext();
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
title: "Carrots",
|
|
||||||
category: GroceryCategory.Vegetables,
|
|
||||||
approved: false,
|
|
||||||
bought: false,
|
|
||||||
recurring: false,
|
|
||||||
frequency: GroceryFrequency.Never
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
title: "Steak",
|
|
||||||
category: GroceryCategory.Meat,
|
|
||||||
approved: true,
|
|
||||||
bought: false,
|
|
||||||
recurring: false,
|
|
||||||
frequency: GroceryFrequency.Never
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
title: "Chicken Breast",
|
|
||||||
category: GroceryCategory.Poultry,
|
|
||||||
approved: true,
|
|
||||||
bought: false,
|
|
||||||
recurring: false,
|
|
||||||
frequency: GroceryFrequency.Never
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
title: "Greek Yoghurt",
|
|
||||||
category: GroceryCategory.Dairy,
|
|
||||||
approved: false,
|
|
||||||
bought: false,
|
|
||||||
recurring: false,
|
|
||||||
frequency: GroceryFrequency.Never
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const setItemApproved = (id: number, approved: boolean) => {
|
|
||||||
setGroceries((prevGroceries) =>
|
|
||||||
prevGroceries.map((grocery) =>
|
|
||||||
grocery.id === id ? { ...grocery, approved } : grocery
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={groceries}
|
data={groceries}
|
||||||
renderItem={({ item }) => <GroceryItem item={item} handleItemApproved={setItemApproved} />}
|
renderItem={({ item }) => (
|
||||||
|
<GroceryItem item={item} handleItemApproved={updateGroceryItem} />
|
||||||
|
)}
|
||||||
keyExtractor={(item) => item.id.toString()}
|
keyExtractor={(item) => item.id.toString()}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
60
components/pages/grocery/TopDisplay.tsx
Normal file
60
components/pages/grocery/TopDisplay.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { View, Text, Button } from "react-native-ui-lib";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { Octicons } from "@expo/vector-icons";
|
||||||
|
import { useGroceryContext } from "@/contexts/GroceryContext";
|
||||||
|
|
||||||
|
const TopDisplay = () => {
|
||||||
|
const { groceries, isShopping } = useGroceryContext();
|
||||||
|
const [approved, setApproved] = useState<number>(0);
|
||||||
|
const [pending, setPending] = useState<number>(0);
|
||||||
|
const [notBoughtCound, setNotBoughtCound] = useState<number>(0);
|
||||||
|
useEffect(() => {
|
||||||
|
const approvedCount = groceries.filter(
|
||||||
|
(grocery) => grocery.approved
|
||||||
|
).length;
|
||||||
|
const pendingCount = groceries.filter(
|
||||||
|
(grocery) => !grocery.approved
|
||||||
|
).length;
|
||||||
|
const notBoughtCound = groceries.filter(
|
||||||
|
(grocery) => !grocery.bought
|
||||||
|
).length;
|
||||||
|
|
||||||
|
setApproved(approvedCount);
|
||||||
|
setPending(pendingCount);
|
||||||
|
setNotBoughtCound(notBoughtCound);
|
||||||
|
}, [groceries]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View backgroundColor="#e1e1e1" paddingL-20 paddingT-20 paddingB-10>
|
||||||
|
<Text text50BL marginB-10 color="black">
|
||||||
|
Welcome to your grocery list!
|
||||||
|
</Text>
|
||||||
|
{!isShopping ? (
|
||||||
|
<View row bottom style={{ justifyContent: "space-between" }}>
|
||||||
|
<View>
|
||||||
|
<Text text70BL color="black">
|
||||||
|
{approved} approved items
|
||||||
|
</Text>
|
||||||
|
<Text text70BL color="black">
|
||||||
|
{pending} pending items
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Button
|
||||||
|
backgroundColor="#e1e1e1"
|
||||||
|
right
|
||||||
|
padding-0
|
||||||
|
children={<Octicons name="share" size={30} color="black" />}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View>
|
||||||
|
<Text text70BL color="black">
|
||||||
|
You have {notBoughtCound} items left in your cart
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TopDisplay;
|
123
contexts/GroceryContext.tsx
Normal file
123
contexts/GroceryContext.tsx
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
||||||
|
import { createContext, useContext, useState } from "react";
|
||||||
|
|
||||||
|
export enum GroceryFrequency {
|
||||||
|
Never = "Never",
|
||||||
|
Daily = "Daily",
|
||||||
|
Weekly = "Weekly",
|
||||||
|
BiWeekly = "BiWeekly",
|
||||||
|
Monthly = "Monthly",
|
||||||
|
Quarterly = "Quarterly",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGrocery {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
category: GroceryCategory;
|
||||||
|
approved: boolean;
|
||||||
|
recurring: boolean;
|
||||||
|
frequency: GroceryFrequency;
|
||||||
|
bought: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum GroceryCategory {
|
||||||
|
Fruit = "Fruit",
|
||||||
|
Dairy = "Dairy",
|
||||||
|
Vegetables = "Vegetables",
|
||||||
|
Meat = "Meat",
|
||||||
|
Poultry = "Poultry",
|
||||||
|
Bakery = "Bakery",
|
||||||
|
Beverages = "Beverages",
|
||||||
|
Snacks = "Snacks",
|
||||||
|
Household = "Household",
|
||||||
|
PersonalCare = "Personal Care",
|
||||||
|
Frozen = "Frozen",
|
||||||
|
}
|
||||||
|
|
||||||
|
type MaterialIconNames = keyof typeof MaterialCommunityIcons.glyphMap;
|
||||||
|
const iconMapping: { [key in GroceryCategory]: MaterialIconNames } = {
|
||||||
|
//за сад се иконице за категорију бирају одавде
|
||||||
|
[GroceryCategory.Fruit]: "food-apple",
|
||||||
|
[GroceryCategory.Dairy]: "cheese",
|
||||||
|
[GroceryCategory.Vegetables]: "carrot",
|
||||||
|
[GroceryCategory.Meat]: "food-steak",
|
||||||
|
[GroceryCategory.Poultry]: "food-drumstick",
|
||||||
|
[GroceryCategory.Bakery]: "bread-slice",
|
||||||
|
[GroceryCategory.Beverages]: "cup-water",
|
||||||
|
[GroceryCategory.Snacks]: "candy",
|
||||||
|
[GroceryCategory.Household]: "home",
|
||||||
|
[GroceryCategory.PersonalCare]: "face-man-profile",
|
||||||
|
[GroceryCategory.Frozen]: "snowflake",
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IGroceryContext {
|
||||||
|
groceries: IGrocery[];
|
||||||
|
iconMapping: { [key in GroceryCategory]: MaterialIconNames };
|
||||||
|
updateGroceryItem: (id: number, changes: Partial<IGrocery>) => void;
|
||||||
|
isShopping: boolean;
|
||||||
|
setIsShopping: (value: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GroceryContext = createContext<IGroceryContext | undefined>(undefined);
|
||||||
|
|
||||||
|
export const GroceryProvider: React.FC<{ children: React.ReactNode }> = ({
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const [isShopping, setIsShopping] = useState<boolean>(false);
|
||||||
|
const [groceries, setGroceries] = useState<IGrocery[]>([
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
title: "Carrots",
|
||||||
|
category: GroceryCategory.Vegetables,
|
||||||
|
approved: false,
|
||||||
|
bought: false,
|
||||||
|
recurring: false,
|
||||||
|
frequency: GroceryFrequency.Never,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "Steak",
|
||||||
|
category: GroceryCategory.Meat,
|
||||||
|
approved: true,
|
||||||
|
bought: false,
|
||||||
|
recurring: false,
|
||||||
|
frequency: GroceryFrequency.Never,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: "Chicken Breast",
|
||||||
|
category: GroceryCategory.Poultry,
|
||||||
|
approved: true,
|
||||||
|
bought: false,
|
||||||
|
recurring: false,
|
||||||
|
frequency: GroceryFrequency.Never,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: "Greek Yoghurt",
|
||||||
|
category: GroceryCategory.Dairy,
|
||||||
|
approved: false,
|
||||||
|
bought: false,
|
||||||
|
recurring: false,
|
||||||
|
frequency: GroceryFrequency.Never,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const updateGroceryItem = (id: number, changes: Partial<IGrocery>) => {
|
||||||
|
setGroceries((prevGroceries) =>
|
||||||
|
prevGroceries.map((grocery) =>
|
||||||
|
grocery.id === id ? { ...grocery, ...changes } : grocery
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GroceryContext.Provider
|
||||||
|
value={{ groceries, iconMapping, updateGroceryItem, isShopping, setIsShopping }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</GroceryContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGroceryContext = () => useContext(GroceryContext)!;
|
Reference in New Issue
Block a user