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

@ -1,23 +1,18 @@
import { ScrollView } from "react-native";
import { Button, FloatingButton, Text, View } from "react-native-ui-lib";
import Octicons from "@expo/vector-icons/Octicons";
import { Text, View } from "react-native-ui-lib";
import GroceryList from "@/components/pages/grocery/GroceryList";
import AddGroceryItem from "@/components/pages/grocery/AddGroceryItem";
import { useAuthContext } from "@/contexts/AuthContext";
import { GroceryProvider, useGroceryContext } from "@/contexts/GroceryContext";
import TopDisplay from "@/components/pages/grocery/TopDisplay";
import { GroceryProvider } from "@/contexts/GroceryContext";
import React from "react";
import HeaderTemplate from "@/components/shared/HeaderTemplate";
import { ScrollView } from "react-native-gesture-handler";
export default function Screen() {
return (
<GroceryProvider>
<View>
<TopDisplay />
<View>
<ScrollView>
<GroceryList />
</View>
</View>
<AddGroceryItem />
</ScrollView>
</GroceryProvider>
);
}

View File

@ -1,5 +1,5 @@
import {Stack} from "expo-router";
export default function Layout() {
return <Stack screenOptions={{title: "Login"}}/>
return <Stack screenOptions={{title: ""}}/>
}

View File

View File

@ -0,0 +1,5 @@
import Entry from "@/components/pages/main/Entry";
export default function Screen() {
return <Entry />;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

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
backgroundColor="#fd1775"
label="Add item"
text70L
iconSource={() => <FontAwesome6 name="add" size={18} color="white" />}
style={styles.finishShopBtn}
enableShadow
onPress={() => setIsShopping(false)}
onPress={() => {setIsAddingGrocery(true)}}
/>
</View>
)}
{addGroceryDialog}
</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,
}}
/>
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>
)}
data={groceries}
</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,6 +1,7 @@
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>("");
@ -13,37 +14,54 @@ const SignInPage = (props: { setRegister: () => any }) => {
};
return (
<View padding-10>
<View padding-10 centerV height={"100%"}>
<TextField
placeholder="Email"
value={email}
onChangeText={setEmail}
style={{ marginBottom: 10 }}
floatingPlaceholder
style={styles.textfield}
/>
<TextField
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
style={{ marginBottom: 10 }}
floatingPlaceholder
style={styles.textfield}
/>
<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
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,10 +1,21 @@
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 [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);
@ -20,27 +31,55 @@ const SignUpPage = (props: { unsetRegister: () => any }) => {
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={{ marginBottom: 10 }}
floatingPlaceholder
style={styles.textfield}
/>
<TextField
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
style={{ marginBottom: 10 }}
floatingPlaceholder
style={styles.textfield}
/>
<Button
label="Register"
onPress={handleSignUp}
style={{ marginBottom: 10 }}
style={{ marginBottom: 10, backgroundColor: "#fd1775" }}
/>
<Text style={{ marginBottom: 10 }}>Choose Profile Type:</Text>
<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 }}>
/>*/}
<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>
);

View File

@ -54,8 +54,8 @@ interface IGroceryContext {
groceries: IGrocery[];
iconMapping: { [key in GroceryCategory]: MaterialIconNames };
updateGroceryItem: (id: number, changes: Partial<IGrocery>) => void;
isShopping: boolean;
setIsShopping: (value: boolean) => void;
isAddingGrocery: boolean;
setIsAddingGrocery: (value: boolean) => void;
}
const GroceryContext = createContext<IGroceryContext | undefined>(undefined);
@ -63,7 +63,7 @@ const GroceryContext = createContext<IGroceryContext | undefined>(undefined);
export const GroceryProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [isShopping, setIsShopping] = useState<boolean>(false);
const [isAddingGrocery, setIsAddingGrocery] = useState<boolean>(false);
const [groceries, setGroceries] = useState<IGrocery[]>([
{
id: 0,
@ -113,7 +113,7 @@ export const GroceryProvider: React.FC<{ children: React.ReactNode }> = ({
return (
<GroceryContext.Provider
value={{ groceries, iconMapping, updateGroceryItem, isShopping, setIsShopping }}
value={{ groceries, iconMapping, updateGroceryItem, isAddingGrocery, setIsAddingGrocery }}
>
{children}
</GroceryContext.Provider>

View File

@ -5,10 +5,12 @@ export interface IToDo {
done: boolean;
date: Date;
points?: number;
rotate: boolean;
}
interface IToDosContext {
toDos: IToDo[];
updateToDo: (id: number, changes: Partial<IToDo>) => void;
addToDo: (newToDo: IToDo) => void;
}
const ToDosContext = createContext<IToDosContext>(undefined!);
@ -17,40 +19,76 @@ export const ToDosContextProvider: FC<{ children: ReactNode }> = ({
children,
}) => {
const [toDos, setToDos] = useState<IToDo[]>([
{ id: 0, title: "Pay: Credit card", done: false, date: new Date() },
{ id: 1, title: "Monthly Log story", done: false, date: new Date() },
{ id: 2, title: "Write: Arcade Highlights", done: false, date: new Date() },
{
id: 0,
title: "Pay: Credit card",
done: false,
date: new Date(),
rotate: true,
},
{
id: 1,
title: "Monthly Log story",
done: false,
date: new Date(),
rotate: false,
},
{
id: 2,
title: "Write: Arcade Highlights",
done: false,
date: new Date(),
rotate: true,
},
{
id: 3,
title: "Dressup: Cat",
done: false,
date: new Date(Date.now() + 86400000),
points: 40,
rotate: false,
},
{
id: 4,
title: "Trim: Nails",
done: false,
date: new Date(Date.now() + 86400000),
rotate: false,
},
{
id: 5,
title: "Monthly Log",
done: false,
date: new Date(Date.now() + 2 * 86400000),
rotate: true,
},
{
id: 6,
title: "Do it",
done: false,
date: new Date(Date.now() + 3 * 86400000),
rotate: false,
},
]);
const updateToDo = (id: number, changes: Partial<IToDo>) => {};
const updateToDo = (id: number, changes: Partial<IToDo>) => {
setToDos((prevToDos) =>
prevToDos.map((toDo) => (toDo.id === id ? { ...toDo, ...changes } : toDo))
);
};
const addToDo = (newToDo: IToDo) => {
setToDos((prevToDos) => [
...prevToDos,
{
...newToDo,
id: prevToDos.length ? prevToDos[prevToDos.length - 1].id + 1 : 0,
},
]);
};
return (
<ToDosContext.Provider value={{ toDos, updateToDo }}>
<ToDosContext.Provider value={{ toDos, updateToDo, addToDo }}>
{children}
</ToDosContext.Provider>
);

33
package-lock.json generated
View File

@ -40,6 +40,7 @@
"react-native-calendars": "^1.1306.0",
"react-native-gesture-handler": "~2.16.1",
"react-native-linear-gradient": "^2.8.3",
"react-native-onboarding-swiper": "^1.3.0",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
@ -52,6 +53,7 @@
"@babel/core": "^7.20.0",
"@types/jest": "^29.5.12",
"@types/react": "~18.2.45",
"@types/react-native-onboarding-swiper": "^1.1.9",
"@types/react-test-renderer": "^18.0.7",
"jest": "^29.2.1",
"jest-expo": "~51.0.3",
@ -8294,6 +8296,17 @@
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-native-onboarding-swiper": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/@types/react-native-onboarding-swiper/-/react-native-onboarding-swiper-1.1.9.tgz",
"integrity": "sha512-xCvsk7e6gQ9tEsK/xUPGA88mjF4sz8xFWAt+8de5xyjvrp3/nY0RJKPUd8ZtZzhGqcDm2tdsfI6KdNS5XuDxuA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/react": "*",
"react-native": "*"
}
},
"node_modules/@types/react-test-renderer": {
"version": "18.3.0",
"resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.3.0.tgz",
@ -12589,9 +12602,9 @@
}
},
"node_modules/firebase-functions": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-5.1.0.tgz",
"integrity": "sha512-VO46n9lqljrNiqOv4BbnFHYxY+yYCdZcOeUIF1t9DbFxBbVPztHdMM9MvpfCDp0nzXP2PugdmghSgM0hORrNvw==",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-5.1.1.tgz",
"integrity": "sha512-KkyKZE98Leg/C73oRyuUYox04PQeeBThdygMfeX+7t1cmKWYKa/ZieYa89U8GHgED+0mF7m7wfNZOfbURYxIKg==",
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.5",
@ -19625,6 +19638,20 @@
"react-native": "*"
}
},
"node_modules/react-native-onboarding-swiper": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/react-native-onboarding-swiper/-/react-native-onboarding-swiper-1.3.0.tgz",
"integrity": "sha512-2ZPMrZrJFgR5dmVWIj60x/vTBWrm0BZPuc2w7Cz2Sq/8ChypCi3oL8F7GYMrzky1fmknCS6Z0WPphfZVpnLUnQ==",
"license": "MIT",
"dependencies": {
"tinycolor2": "^1.4.1"
},
"peerDependencies": {
"prop-types": "*",
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-reanimated": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.10.1.tgz",

View File

@ -47,6 +47,7 @@
"react-native-calendars": "^1.1306.0",
"react-native-gesture-handler": "~2.16.1",
"react-native-linear-gradient": "^2.8.3",
"react-native-onboarding-swiper": "^1.3.0",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
@ -59,6 +60,7 @@
"@babel/core": "^7.20.0",
"@types/jest": "^29.5.12",
"@types/react": "~18.2.45",
"@types/react-native-onboarding-swiper": "^1.1.9",
"@types/react-test-renderer": "^18.0.7",
"jest": "^29.2.1",
"jest-expo": "~51.0.3",

View File

@ -3297,6 +3297,14 @@
resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz"
integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
"@types/react-native-onboarding-swiper@^1.1.9":
version "1.1.9"
resolved "https://registry.npmjs.org/@types/react-native-onboarding-swiper/-/react-native-onboarding-swiper-1.1.9.tgz"
integrity sha512-xCvsk7e6gQ9tEsK/xUPGA88mjF4sz8xFWAt+8de5xyjvrp3/nY0RJKPUd8ZtZzhGqcDm2tdsfI6KdNS5XuDxuA==
dependencies:
"@types/react" "*"
react-native "*"
"@types/react-test-renderer@^18.0.7":
version "18.3.0"
resolved "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.3.0.tgz"
@ -5675,9 +5683,9 @@ find-yarn-workspace-root@~2.0.0:
"@google-cloud/storage" "^7.7.0"
firebase-functions@^5.1.0:
version "5.1.0"
resolved "https://registry.npmjs.org/firebase-functions/-/firebase-functions-5.1.0.tgz"
integrity sha512-VO46n9lqljrNiqOv4BbnFHYxY+yYCdZcOeUIF1t9DbFxBbVPztHdMM9MvpfCDp0nzXP2PugdmghSgM0hORrNvw==
version "5.1.1"
resolved "https://registry.npmjs.org/firebase-functions/-/firebase-functions-5.1.1.tgz"
integrity sha512-KkyKZE98Leg/C73oRyuUYox04PQeeBThdygMfeX+7t1cmKWYKa/ZieYa89U8GHgED+0mF7m7wfNZOfbURYxIKg==
dependencies:
"@types/cors" "^2.8.5"
"@types/express" "4.17.3"
@ -8970,6 +8978,13 @@ react-native-linear-gradient@^2.8.3:
resolved "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz"
integrity sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==
react-native-onboarding-swiper@^1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/react-native-onboarding-swiper/-/react-native-onboarding-swiper-1.3.0.tgz"
integrity sha512-2ZPMrZrJFgR5dmVWIj60x/vTBWrm0BZPuc2w7Cz2Sq/8ChypCi3oL8F7GYMrzky1fmknCS6Z0WPphfZVpnLUnQ==
dependencies:
tinycolor2 "^1.4.1"
react-native-reanimated@*, "react-native-reanimated@>= 1.0.0", react-native-reanimated@>=2.0.0, react-native-reanimated@~3.10.1:
version "3.10.1"
resolved "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.10.1.tgz"
@ -10237,7 +10252,7 @@ through2@^2.0.1:
readable-stream "~2.3.6"
xtend "~4.0.1"
tinycolor2@^1.4.2:
tinycolor2@^1.4.1, tinycolor2@^1.4.2:
version "1.6.0"
resolved "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz"
integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==