changes to grocery, todos

This commit is contained in:
ivic00
2024-09-12 15:39:20 +02:00
parent 8d85cbdaad
commit 53f7118656
24 changed files with 643 additions and 208 deletions

View File

@ -10,12 +10,13 @@ import {
PanningProvider,
} from "react-native-ui-lib";
import { useGroceryContext } from "@/contexts/GroceryContext";
import { FontAwesome6 } from "@expo/vector-icons";
interface AddGroceryItemProps {
visible: boolean;
onClose: () => void;
}
const AddGroceryItem = () => {
const { setIsShopping, isShopping } = useGroceryContext();
const { isAddingGrocery, setIsAddingGrocery } = useGroceryContext();
const [visible, setVisible] = useState<boolean>(false);
const handleShowDialog = () => {
@ -24,23 +25,6 @@ const AddGroceryItem = () => {
const handleHideDialog = () => {
setVisible(false);
};
const addGroceryDialog = (
<Dialog
visible={visible}
onDismiss={handleHideDialog}
panDirection={PanningProvider.Directions.DOWN}
containerStyle={{ borderRadius: 12, backgroundColor: "white" }}
>
<View style={styles.container}>
<Text style={styles.title}>New Grocery</Text>
<View style={styles.divider} />
<View style={styles.inner}>
<Text>Category</Text>
</View>
</View>
</Dialog>
);
return (
<View
row
@ -53,39 +37,18 @@ const AddGroceryItem = () => {
height: 60,
}}
>
{!isShopping ? (
<View style={styles.btnContainer} row>
<Button
label="View shopping list"
color="#337a11"
flex-2
marginR-5
backgroundColor="#c6e0b3"
onPress={() => setIsShopping(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"
text60L
style={styles.finishShopBtn}
enableShadow
onPress={() => setIsShopping(false)}
/>
</View>
)}
{addGroceryDialog}
<View style={styles.btnContainer} row>
<Button
color="white"
backgroundColor="#fd1775"
label="Add item"
text70L
iconSource={() => <FontAwesome6 name="add" size={18} color="white" />}
style={styles.finishShopBtn}
enableShadow
onPress={() => {setIsAddingGrocery(true)}}
/>
</View>
</View>
);
};

View File

@ -0,0 +1,27 @@
import React from "react";
import { View, Text, TouchableOpacity } from "react-native-ui-lib";
import { GroceryCategory } from "@/contexts/GroceryContext";
import { ScrollView } from "react-native-gesture-handler";
const CategoryDropdown = () => {
const groceryCategories = Object.values(GroceryCategory);
return (
<ScrollView height={100}>
{groceryCategories.map((category) => (
<TouchableOpacity onPress={() => {}}>
<View
key={category}
style={{
padding: 10,
}}
>
<Text>{category}</Text>
</View>
</TouchableOpacity>
))}
</ScrollView>
);
};
export default CategoryDropdown;

View File

@ -20,7 +20,7 @@ const GroceryItem = ({
item: IGrocery;
handleItemApproved: (id: number, changes: Partial<IGrocery>) => void;
}) => {
const { iconMapping, updateGroceryItem, groceries, isShopping } =
const { updateGroceryItem, groceries } =
useGroceryContext();
const { profileType } = useAuthContext();
@ -38,8 +38,10 @@ const GroceryItem = ({
return (
<ListItem
style={{borderRadius: 50, marginVertical: 5, height: 55}}
backgroundColor="white"
padding-3
centerV
padding-0
onPress={() => {
setOpenFreqEdit(true);
}}
@ -52,8 +54,8 @@ const GroceryItem = ({
setOpenFreqEdit(false);
}}
/>
<ListItem.Part left containerStyle={{ flex: 1, paddingStart: 15 }}>
<View
<ListItem.Part left containerStyle={{ flex: 1, paddingStart: 20 }}>
{/* <View
height={50}
width={50}
style={{ borderRadius: 15 }}
@ -66,7 +68,7 @@ const GroceryItem = ({
color="orange"
/>
}
/>
/>*/}
<View>
{!isEditingTitle ? (
<TouchableOpacity onPress={() => setIsEditingTitle(true)}>
@ -89,11 +91,10 @@ const GroceryItem = ({
}}
/>
)}
<Text>{iconMapping[item.category]}</Text>
</View>
</ListItem.Part>
<ListItem.Part right containerStyle={{ paddingEnd: 15 }}>
{profileType == ProfileType.PARENT && !isShopping ? (
<ListItem.Part right containerStyle={{ paddingEnd: 20 }}>
{!item.approved ? (
<View row>
<Button
padding-0

View File

@ -1,33 +1,147 @@
import { FlatList } from "react-native";
import React, { useState } from "react";
import { View, Text, ListItem, Button } from "react-native-ui-lib";
import React, { useEffect, useState } from "react";
import {
View,
Text,
ListItem,
Button,
TextField,
Picker,
} from "react-native-ui-lib";
import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons";
import { useAuthContext } from "@/contexts/AuthContext";
import AntDesign from "@expo/vector-icons/AntDesign";
import AddGroceryItem from "./AddGroceryItem";
import GroceryItem from "./GroceryItem";
import { useGroceryContext } from "@/contexts/GroceryContext";
import {
GroceryCategory,
IGrocery,
useGroceryContext,
} from "@/contexts/GroceryContext";
import HeaderTemplate from "@/components/shared/HeaderTemplate";
import CategoryDropdown from "./CategoryDropdown";
const GroceryList = () => {
const { groceries, updateGroceryItem } = useGroceryContext();
const { groceries, updateGroceryItem, isAddingGrocery } = useGroceryContext();
const [approvedGroceries, setapprovedGroceries] = useState<IGrocery[]>(
groceries.filter((item) => item.approved == true)
);
const [pendingGroceries, setPendingGroceries] = useState<IGrocery[]>(
groceries.filter((item) => item.approved != true)
);
useEffect(() => {
setapprovedGroceries(groceries.filter((item) => item.approved == true));
setPendingGroceries(groceries.filter((item) => item.approved != true));
}, [groceries]);
return (
<View>
<FlatList
ItemSeparatorComponent={() => (
<View marginH-20>
<HeaderTemplate
message={"Welcome to your grocery list"}
isWelcome={false}
>
<View row spread>
<View
style={{
height: 1.5,
backgroundColor: "#e0e0e0",
marginHorizontal: 15,
}}
/>
)}
data={groceries}
renderItem={({ item }) => (
<GroceryItem item={item} handleItemApproved={updateGroceryItem} />
)}
keyExtractor={(item) => item.id.toString()}
/>
backgroundColor="#e2eed8"
padding-8
style={{ borderRadius: 50 }}
>
<Text text70BL color="#46a80a">
{approvedGroceries.length} list{" "}
{approvedGroceries.length == 1 ? (
<Text text70BL color="#46a80a">
item
</Text>
) : (
<Text text70BL color="#46a80a">
items
</Text>
)}
</Text>
</View>
<View
backgroundColor="#faead2"
padding-8
style={{ borderRadius: 50 }}
>
<Text text70BL color="#e28800">
{pendingGroceries.length} pending
</Text>
</View>
</View>
</HeaderTemplate>
{/* Pending Approval Section */}
<View row spread marginT-40 marginB-20 centerV>
<Text text70BL>Pending Approval</Text>
<View
centerV
style={{
aspectRatio: 1,
width: 40,
backgroundColor: "#faead2",
borderRadius: 50,
}}
>
<Text text60L center color="#e28800">
{pendingGroceries.length.toString()}
</Text>
</View>
</View>
{pendingGroceries.length > 0 ? (
<FlatList
data={pendingGroceries}
renderItem={({ item }) => (
<GroceryItem item={item} handleItemApproved={updateGroceryItem} />
)}
keyExtractor={(item) => item.id.toString()}
/>
) : (
<Text>No items pending approval.</Text>
)}
{/* Approved Section */}
<View row spread marginT-40 marginB-20 centerV>
<Text text70BL>Shopping List</Text>
<View
centerV
style={{
aspectRatio: 1,
width: 40,
backgroundColor: "#e2eed8",
borderRadius: 50,
}}
>
<Text text60L center color="#46a80a">
{approvedGroceries.length.toString()}
</Text>
</View>
</View>
{isAddingGrocery && (
<View
style={{
backgroundColor: "white",
width: "100%",
borderRadius: 25,
padding: 15,
}}
>
<TextField placeholder="Grocery" maxLength={25} />
<CategoryDropdown />
</View>
)}
{approvedGroceries.length > 0 ? (
<FlatList
data={approvedGroceries}
renderItem={({ item }) => (
<GroceryItem item={item} handleItemApproved={updateGroceryItem} />
)}
keyExtractor={(item) => item.id.toString()}
/>
) : (
<Text>No approved items.</Text>
)}
</View>
);
};

View File

@ -3,10 +3,11 @@ import React, { useState } from "react";
import SignUpPage from "./SignUpPage";
import SignInPage from "./SignInPage";
import { useSignUp } from "@/hooks/firebase/useSignUp";
import { StyleSheet } from "react-native";
const Entry = () => {
const [isRegister, setIsRegister] = useState<boolean>(false);
const {mutateAsync: signUp} = useSignUp();
const { mutateAsync: signUp } = useSignUp();
const setRegister = () => {
setIsRegister(true);
@ -17,9 +18,7 @@ const Entry = () => {
return (
<View>
{isRegister ? (
<SignUpPage
unsetRegister={unsetRegister}
/>
<SignUpPage unsetRegister={unsetRegister} />
) : (
<SignInPage setRegister={setRegister} />
)}

View File

@ -1,49 +1,67 @@
import { View, Text, Button, TextField } from "react-native-ui-lib";
import { View, Text, Button, TextField, ButtonSize } from "react-native-ui-lib";
import React, { useState } from "react";
import { useSignIn } from "@/hooks/firebase/useSignIn";
import { StyleSheet } from "react-native";
const SignInPage = (props: { setRegister: () => any }) => {
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const { mutateAsync: signIn, error, isError } = useSignIn();
const { mutateAsync: signIn, error, isError } = useSignIn();
const handleSignIn = async () => {
await signIn({ email, password });
};
const handleSignIn = async () => {
await signIn({ email, password });
};
return (
<View padding-10>
<TextField
placeholder="Email"
value={email}
onChangeText={setEmail}
style={{ marginBottom: 10 }}
floatingPlaceholder
/>
<TextField
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
style={{ marginBottom: 10 }}
floatingPlaceholder
/>
<Button label="Login" onPress={handleSignIn} style={{ marginBottom: 20 }} />
{isError && (
<Text center style={{ marginBottom: 20 }}>{`${error}`}</Text>
)}
<Text center style={{ marginBottom: 5 }}>Don't have an account?</Text>
<Button
onPress={props.setRegister}
label="Sign Up"
link
padding-0
margin-0
left
/>
</View>
);
return (
<View padding-10 centerV height={"100%"}>
<TextField
placeholder="Email"
value={email}
onChangeText={setEmail}
style={styles.textfield}
/>
<TextField
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
style={styles.textfield}
/>
<Button
label="Login"
onPress={handleSignIn}
style={{ marginBottom: 20 }}
backgroundColor="#fd1775"
/>
{isError && <Text center style={{ marginBottom: 20 }}>{`${error}`}</Text>}
<View row centerH>
<Text center style={{ marginBottom: 5 }}>
Don't have an account?
</Text>
<Button
onPress={props.setRegister}
label="Sign Up"
link
size={ButtonSize.xSmall}
padding-0
margin-0
left
color="#fd1775"
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
textfield: {
backgroundColor: "white",
marginVertical: 10,
padding: 30,
height: 45,
borderRadius: 50,
},
});
export default SignInPage;

View File

@ -1,46 +1,85 @@
import React, { useState } from "react";
import {Checkbox, Button, View, Text, TextField} from "react-native-ui-lib";
import {
Checkbox,
Button,
View,
Text,
TextField,
ButtonSize,
} from "react-native-ui-lib";
import { useSignUp } from "@/hooks/firebase/useSignUp";
import { ProfileType } from "@/contexts/AuthContext";
import { StyleSheet } from "react-native";
import { AntDesign } from "@expo/vector-icons";
const SignUpPage = (props: { unsetRegister: () => any }) => {
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [isParent, setIsParent] = useState<boolean>(true);
const [isChild, setIsChild] = useState<boolean>(false);
const [isCaregiver, setIsCaregiver] = useState<boolean>(false);
const [profileType, setProfileType] = useState<ProfileType>(
ProfileType.PARENT
);
const { mutateAsync: signUp } = useSignUp();
const [email, setEmail] = useState<string>("");
const [firstName, setFirstName] = useState<string>("");
const [lastName, setLastName] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [isParent, setIsParent] = useState<boolean>(true);
const [isChild, setIsChild] = useState<boolean>(false);
const [isCaregiver, setIsCaregiver] = useState<boolean>(false);
const [profileType, setProfileType] = useState<ProfileType>(
ProfileType.PARENT
);
const { mutateAsync: signUp } = useSignUp();
const handleSignUp = async () => {
await signUp({ email, password });
};
const handleSignUp = async () => {
await signUp({ email, password });
};
return (
<View padding-10>
<TextField
placeholder="Email"
value={email}
onChangeText={setEmail}
style={{ marginBottom: 10 }}
floatingPlaceholder
/>
<TextField
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
style={{ marginBottom: 10 }}
floatingPlaceholder
/>
<Button
label="Register"
onPress={handleSignUp}
style={{ marginBottom: 10 }}
/>
<Text style={{ marginBottom: 10 }}>Choose Profile Type:</Text>
return (
<View padding-10>
<Text text30 center>
Get started with Kali
</Text>
<Text>Please enter your details.</Text>
<TextField
marginT-60
placeholder="First name"
value={firstName}
onChangeText={setFirstName}
style={styles.textfield}
/>
<TextField
placeholder="Last name"
value={lastName}
onChangeText={setLastName}
style={styles.textfield}
/>
<TextField
placeholder="Email"
value={email}
onChangeText={setEmail}
style={styles.textfield}
/>
<TextField
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
style={styles.textfield}
/>
<Button
label="Register"
onPress={handleSignUp}
style={{ marginBottom: 10, backgroundColor: "#fd1775" }}
/>
<Button
label="Sign up with Google"
backgroundColor="white"
color="black"
iconSource={() => (
<AntDesign
name="google"
size={24}
color="black"
style={{ marginRight: 15 }}
/>
)}
/>
{/*<Text style={{ marginBottom: 10 }}>Choose Profile Type:</Text>
<Checkbox
label="Parent"
value={isParent}
@ -78,19 +117,33 @@ const SignUpPage = (props: { unsetRegister: () => any }) => {
setIsChild(false);
}
}}
/>
<Text center style={{ marginBottom: 5, marginTop: 10 }}>
Already have an account?
</Text>
<Button
label="Sign In"
margin-0
link
text200
onPress={props.unsetRegister}
/>
</View>
);
/>*/}
<View row centerH>
<Text text70 center style={{ marginBottom: 5, marginTop: 10 }}>
Already have an account?
</Text>
<Button
label="Sign In"
margin-0
link
color="#fd1775"
size={ButtonSize.small}
text200
onPress={props.unsetRegister}
/>
</View>
</View>
);
};
export default SignUpPage;
const styles = StyleSheet.create({
textfield: {
backgroundColor: "white",
marginVertical: 10,
padding: 30,
height: 45,
borderRadius: 50,
},
});

View File

@ -0,0 +1,22 @@
import { Image } from "react-native";
import React from "react";
import { View, Text, Button } from "react-native-ui-lib";
const WelcomeSplash = () => {
return (
<View>
<Image
source={require("../../../assets/images/splash-clock.png")}
height={10}
width={10}
/>
<Button
label="Continue"
style={{ backgroundColor: "#fd1775" }}
onPress={() => {}}
/>
</View>
);
};
export default WelcomeSplash;

View File

@ -0,0 +1,84 @@
import { Image } from "react-native";
import React, { useRef } from "react";
import { View, Text, Button, TextField } from "react-native-ui-lib";
import Onboarding from "react-native-onboarding-swiper";
import { StyleSheet } from "react-native";
import { useAuthContext } from "@/contexts/AuthContext";
import { useSignUp } from "@/hooks/firebase/useSignUp";
const OnboardingFlow = () => {
const onboardingRef = useRef(null);
const { mutateAsync: signUp } = useSignUp();
return (
<Onboarding
showPagination={false}
ref={onboardingRef}
containerStyles={{ backgroundColor: "#f9f8f7" }}
imageContainerStyles={{
paddingBottom: 0,
paddingTop: 0,
}}
pages={[
{
backgroundColor: "#f9f8f7",
image: (
<Image
source={require("../../../assets/images/splash-clock.png")}
height={10}
width={10}
/>
),
title: <Text text30>Welcome to Kali</Text>,
subtitle: (
<View paddingB-250 marginH-20 spread>
<Text text50R>Lightening Mental Loads, One Family at a Time</Text>
<Button
label="Continue"
style={{ backgroundColor: "#fd1775" }}
onPress={() => onboardingRef.current.goToPage(1, true)}
/>
</View>
),
},
{
backgroundColor: "#f9f8f7",
title: <Text>Get started with Kali</Text>,
subtitle: (
<View
style={{
marginBottom: "auto",
width: "100%",
}}
>
<View marginH-30>
{/*<TextField style={styles.textfield} placeholder="First name" />*/}
{/*<TextField style={styles.textfield} placeholder="Last name" />*/}
<TextField style={styles.textfield} placeholder="Email" />
<TextField style={styles.textfield} placeholder="Password" />
<Button
label="Login"
backgroundColor="#ea156c"
onPress={() => {
console.log("Onboarding Done");
}}
/>
</View>
</View>
),
},
]}
/>
);
};
export default OnboardingFlow;
const styles = StyleSheet.create({
textfield: {
backgroundColor: "white",
marginVertical: 10,
padding: 30,
height: 45,
borderRadius: 50,
},
});

View File

View File

@ -12,15 +12,21 @@ import {
NumberInput,
NumberInputData,
DateTimePicker,
Switch,
} from "react-native-ui-lib";
import { AntDesign, Feather, Ionicons } from "@expo/vector-icons";
import LinearGradient from "react-native-linear-gradient";
import { PanningDirectionsEnum } from "react-native-ui-lib/src/components/panningViews/panningProvider";
import { useToDosContext } from "@/contexts/ToDosContext";
const AddChore = () => {
const { addToDo, toDos } = useToDosContext();
const [newTitle, setNewTitle] = useState<string>("");
const [isVisible, setIsVisible] = useState<boolean>(false);
const [points, setPoints] = useState<number>(10);
const [choreDate, setChoreDate] = useState<Date>(new Date());
const [rotate, setRotate] = useState<boolean>(false);
const handleChange = (text: string) => {
const numericValue = parseInt(text, 10);
@ -66,8 +72,38 @@ const AddChore = () => {
}}
visible={isVisible}
>
<View row spread>
<Button color="#05a8b6" style={styles.topBtn} label="Cancel" onPress={() => {setIsVisible(false)}} />
<Button
style={styles.topBtn}
iconSource={() => (
<Feather name="chevron-down" size={24} color="black" />
)} onPress={() => {setIsVisible(false)}}
/>
<Button
color="#05a8b6"
style={styles.topBtn}
label="Save"
onPress={() => {
addToDo({
id: 0,
title: newTitle,
done: false,
date: choreDate,
points: points,
rotate: rotate,
});
setIsVisible(false);
console.log(toDos);
}}
/>
</View>
<TextField
placeholder="Add chore title"
value={newTitle}
onChangeText={(text) => {
setNewTitle(text);
}}
placeholderTextColor="#2d2d30"
text60R
marginT-15
@ -134,6 +170,7 @@ const AddChore = () => {
}}
/>
</View>
<Switch onColor={'#ea156c'} value={rotate} style={styles.rotateSwitch} onValueChange={(value) => setRotate(value)} />
<View style={styles.divider} />
<View marginH-30 marginB-10 row centerV>
<Ionicons name="gift-outline" size={30} color="#919191" />
@ -195,4 +232,12 @@ const styles = StyleSheet.create({
backgroundColor: "rgb(253, 23, 117)",
paddingVertical: 20,
},
topBtn: {
backgroundColor: "white",
color: "#05a8b6",
},
rotateSwitch: {
marginLeft: 'auto',
marginRight: 35
}
});

View File

@ -1,17 +1,37 @@
import { View, Text, Checkbox } from "react-native-ui-lib";
import React from "react";
import { IToDo } from "@/contexts/ToDosContext";
import { IToDo, useToDosContext } from "@/contexts/ToDosContext";
import { Ionicons } from "@expo/vector-icons";
const ToDoItem = (props: { item: IToDo }) => {
const { updateToDo } = useToDosContext();
return (
<View centerV backgroundColor="white" paddingV-10 paddingH-10 marginH-25 marginV-10 style={{borderRadius: 22}}>
<View
centerV
backgroundColor="white"
paddingV-10
paddingH-10
marginH-25
marginV-10
style={{ borderRadius: 22 }}
>
<View paddingB-5 row spread>
<Text text70R>{props.item.title}</Text>
<Checkbox value={props.item.done} />
<Checkbox
value={props.item.done}
onValueChange={(value) => {
updateToDo(props.item.id, { done: !props.item.done });
}}
/>
</View>
<View centerH paddingV-5>
<View centerV height={2} width={"100%"} backgroundColor="#e7e7e7" centerH />
<View
centerV
height={2}
width={"100%"}
backgroundColor="#e7e7e7"
centerH
/>
</View>
<View centerH row spread>
{props.item.points && props.item.points > 0 ? (

View File

@ -27,7 +27,7 @@ const ToDosList = () => {
const groupedToDos = groupToDosByDate(toDos);
return (
<View>
<View marginB-140>
{Object.keys(groupedToDos).map((dateKey) => (
<View key={dateKey}>
<Text text70 style={{ fontWeight: "bold", marginVertical: 8, paddingHorizontal: 20}}>

View File

@ -2,14 +2,21 @@ import { View, Text } from "react-native-ui-lib";
import React from "react";
import { useAuthContext } from "@/contexts/AuthContext";
const HeaderTemplate = (props: { message: string }) => {
const HeaderTemplate = (props: { message: string; isWelcome: boolean; children?: React.ReactNode }) => {
const { user, profileData } = useAuthContext();
return (
<View row centerV padding-25>
<View backgroundColor="pink" height={65} width={65} style={{borderRadius: 22}} marginR-20 />
<View
backgroundColor="pink"
height={65}
width={65}
style={{ borderRadius: 22 }}
marginR-20
/>
<View>
<Text text70L>Welcome, {user?.email}!</Text>
{props.isWelcome && <Text text70L>Welcome, {user?.email}!</Text>}
<Text text70BL>{props.message}</Text>
{props.children && <View>{props.children}</View>}
</View>
</View>
);