This commit is contained in:
Milan Paunovic
2024-10-28 01:27:33 +01:00
parent 7c18fd1d40
commit 059082cf65
8 changed files with 1052 additions and 1067 deletions

View File

@ -1,123 +1,119 @@
import { Dimensions, ScrollView } from "react-native";
import React, { useState } from "react";
import { View, Text, Button } from "react-native-ui-lib";
import {Dimensions, ScrollView, StyleSheet} from "react-native";
import React, {useState} from "react";
import {Button, Text, TextField, View} from "react-native-ui-lib";
import DumpList from "./DumpList";
import HeaderTemplate from "@/components/shared/HeaderTemplate";
import { TextField } from "react-native-ui-lib";
import { StyleSheet } from "react-native";
import { Feather, MaterialIcons } from "@expo/vector-icons";
import { TextInput } from "react-native-gesture-handler";
import {Feather, MaterialIcons} from "@expo/vector-icons";
import AddBrainDump from "./AddBrainDump";
import LinearGradient from "react-native-linear-gradient";
const BrainDumpPage = () => {
const [searchText, setSearchText] = useState<string>("");
const [isAddVisible, setIsAddVisible] = useState<boolean>(false);
const [searchText, setSearchText] = useState<string>("");
const [isAddVisible, setIsAddVisible] = useState<boolean>(false);
return (
<View height={"100%"}>
<View>
<ScrollView
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
>
<View marginH-25>
<HeaderTemplate
message={"Welcome to your notes!"}
isWelcome={false}
children={
<Text
style={{ fontFamily: "Manrope_400Regular", fontSize: 14 }}
>
Drop your notes on-the-go here, and{"\n"}organize them later.
</Text>
}
/>
return (
<View height={"100%"}>
<View>
<View style={styles.searchField} centerV>
<TextField
value={searchText}
onChangeText={(value) => {
setSearchText(value);
}}
leadingAccessory={
<Feather
name="search"
size={24}
color="#9b9b9b"
style={{ paddingRight: 10 }}
/>
}
style={{
fontFamily: "Manrope_500Medium",
fontSize: 15,
}}
placeholder="Search notes..."
/>
</View>
<DumpList searchText={searchText} />
<ScrollView
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
>
<View marginH-25>
<HeaderTemplate
message={"Welcome to your notes!"}
isWelcome={false}
children={
<Text
style={{fontFamily: "Manrope_400Regular", fontSize: 14}}
>
Drop your notes on-the-go here, and{"\n"}organize them later.
</Text>
}
/>
<View>
<View style={styles.searchField} centerV>
<TextField
value={searchText}
onChangeText={(value) => {
setSearchText(value);
}}
leadingAccessory={
<Feather
name="search"
size={24}
color="#9b9b9b"
style={{paddingRight: 10}}
/>
}
style={{
fontFamily: "Manrope_500Medium",
fontSize: 15,
}}
placeholder="Search notes..."
/>
</View>
<DumpList searchText={searchText}/>
</View>
</View>
</ScrollView>
</View>
</View>
</ScrollView>
</View>
<LinearGradient
colors={["#f2f2f2", "transparent"]}
start={{ x: 0.5, y: 1 }}
end={{ x: 0.5, y: 0 }}
style={{
position: "absolute",
bottom: 0,
height: 90,
width: Dimensions.get("screen").width,
}}
>
<Button
style={{
height: 40,
position: "relative",
marginLeft: "auto",
width: 20,
right: 20,
bottom: -10,
borderRadius: 30,
backgroundColor: "#fd1775",
}}
color="white"
enableShadow
onPress={() => {
setIsAddVisible(true);
}}
>
<View row centerV centerH>
<MaterialIcons name="add" size={22} color={"white"} />
<Text
white
style={{ fontSize: 16, fontFamily: "Manrope_600SemiBold" }}
<LinearGradient
colors={["#f9f8f700", "#f9f8f7"]}
locations={[0,1]}
style={{
position: "absolute",
bottom: 0,
height: 120,
width: Dimensions.get("screen").width,
justifyContent:'center',
alignItems:"center"
}}
>
New
</Text>
</View>
</Button>
</LinearGradient>
<AddBrainDump
addBrainDumpProps={{
isVisible: isAddVisible,
setIsVisible: setIsAddVisible,
}}
/>
</View>
);
<Button
style={{
height: 40,
position: "relative",
width: "90%",
bottom: -10,
borderRadius: 30,
backgroundColor: "#fd1775",
}}
color="white"
enableShadow
onPress={() => {
setIsAddVisible(true);
}}
>
<View row centerV centerH>
<MaterialIcons name="add" size={22} color={"white"}/>
<Text
white
style={{fontSize: 16, fontFamily: "Manrope_600SemiBold"}}
>
New
</Text>
</View>
</Button>
</LinearGradient>
<AddBrainDump
addBrainDumpProps={{
isVisible: isAddVisible,
setIsVisible: setIsAddVisible,
}}
/>
</View>
);
};
const styles = StyleSheet.create({
searchField: {
borderWidth: 0.7,
borderColor: "#9b9b9b",
borderRadius: 15,
height: 42,
paddingLeft: 10,
marginVertical: 20,
},
searchField: {
borderWidth: 0.7,
borderColor: "#9b9b9b",
borderRadius: 15,
height: 42,
paddingLeft: 10,
marginVertical: 20,
},
});
export default BrainDumpPage;

View File

@ -1,134 +1,125 @@
import React, { memo } from "react";
import {
Button,
Picker,
PickerModes,
SegmentedControl,
Text,
View,
} from "react-native-ui-lib";
import { MaterialIcons } from "@expo/vector-icons";
import { modeMap, months } from "./constants";
import { StyleSheet } from "react-native";
import { useAtom } from "jotai";
import { modeAtom, selectedDateAtom } from "@/components/pages/calendar/atoms";
import { isSameDay } from "date-fns";
import { useAuthContext } from "@/contexts/AuthContext";
import React, {memo} from "react";
import {Button, Picker, PickerModes, SegmentedControl, Text, View,} from "react-native-ui-lib";
import {MaterialIcons} from "@expo/vector-icons";
import {modeMap, months} from "./constants";
import {StyleSheet} from "react-native";
import {useAtom} from "jotai";
import {modeAtom, selectedDateAtom} from "@/components/pages/calendar/atoms";
import {isSameDay} from "date-fns";
import {useAuthContext} from "@/contexts/AuthContext";
export const CalendarHeader = memo(() => {
const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom);
const [mode, setMode] = useAtom(modeAtom);
const { profileData } = useAuthContext();
const [selectedDate, setSelectedDate] = useAtom(selectedDateAtom);
const [mode, setMode] = useAtom(modeAtom);
const {profileData} = useAuthContext();
const handleSegmentChange = (index: number) => {
const selectedMode = modeMap.get(index);
if (selectedMode) {
setTimeout(() => {
setMode(selectedMode as "day" | "week" | "month");
}, 150);
}
};
const handleSegmentChange = (index: number) => {
const selectedMode = modeMap.get(index);
if (selectedMode) {
setTimeout(() => {
setMode(selectedMode as "day" | "week" | "month");
}, 150);
}
};
const handleMonthChange = (month: string) => {
const currentDay = selectedDate.getDate();
const currentYear = selectedDate.getFullYear();
const newMonthIndex = months.indexOf(month);
const handleMonthChange = (month: string) => {
const currentDay = selectedDate.getDate();
const currentYear = selectedDate.getFullYear();
const newMonthIndex = months.indexOf(month);
const updatedDate = new Date(currentYear, newMonthIndex, currentDay);
setSelectedDate(updatedDate);
};
const updatedDate = new Date(currentYear, newMonthIndex, currentDay);
setSelectedDate(updatedDate);
};
const isSelectedDateToday = isSameDay(selectedDate, new Date());
const isSelectedDateToday = isSameDay(selectedDate, new Date());
return (
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: 10,
paddingVertical: 8,
borderRadius: 20,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
backgroundColor: "white",
marginBottom: 10,
}}
>
<View row centerV gap-3>
<Text style={{ fontFamily: "Manrope_500Medium", fontSize: 17 }}>
{selectedDate.getFullYear()}
</Text>
<Picker
value={months[selectedDate.getMonth()]}
placeholder={"Select Month"}
style={{ fontFamily: "Manrope_500Medium", fontSize: 17, width: 85 }}
mode={PickerModes.SINGLE}
onChange={(itemValue) => handleMonthChange(itemValue as string)}
trailingAccessory={<MaterialIcons name={"keyboard-arrow-down"} />}
topBarProps={{
title: selectedDate.getFullYear().toString(),
titleStyle: { fontFamily: "Manrope_500Medium", fontSize: 17 },
}}
>
{months.map((month) => (
<Picker.Item key={month} label={month} value={month} />
))}
</Picker>
</View>
<View row centerV>
{!isSelectedDateToday && (
<Button
size={"xSmall"}
marginR-0
avoidInnerPadding
padding-7
return (
<View
style={{
borderRadius: 5,
backgroundColor: "white",
borderWidth: 0.7,
borderColor: "#dadce0",
height: 30,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: 10,
paddingVertical: 8,
borderRadius: 20,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
backgroundColor: "white",
marginBottom: 10,
}}
labelStyle={{
fontSize: 12,
color: "black",
fontFamily: "Manrope_500Medium",
}}
label={new Date().toLocaleDateString("en-US", {
timeZone: profileData?.timeZone || "",
})}
onPress={() => {
setSelectedDate(new Date());
setMode("day");
console.log(profileData?.timeZone)
}}
/>
)}
>
<View row centerV gap-3>
<Text style={{fontFamily: "Manrope_500Medium", fontSize: 17}}>
{selectedDate.getFullYear()}
</Text>
<Picker
value={months[selectedDate.getMonth()]}
placeholder={"Select Month"}
style={{fontFamily: "Manrope_500Medium", fontSize: 17, width: 85}}
mode={PickerModes.SINGLE}
onChange={(itemValue) => handleMonthChange(itemValue as string)}
trailingAccessory={<MaterialIcons name={"keyboard-arrow-down"}/>}
topBarProps={{
title: selectedDate.getFullYear().toString(),
titleStyle: {fontFamily: "Manrope_500Medium", fontSize: 17},
}}
>
{months.map((month) => (
<Picker.Item key={month} label={month} value={month}/>
))}
</Picker>
</View>
<View>
<SegmentedControl
segments={[{ label: "D" }, { label: "W" }, { label: "M" }]}
backgroundColor="#ececec"
inactiveColor="#919191"
activeBackgroundColor="#ea156c"
activeColor="white"
outlineColor="white"
outlineWidth={3}
segmentLabelStyle={styles.segmentslblStyle}
onChangeIndex={handleSegmentChange}
initialIndex={mode === "day" ? 0 : mode === "week" ? 1 : 2}
/>
<View row centerV>
{!isSelectedDateToday && (
<Button
size={"xSmall"}
marginR-0
avoidInnerPadding
style={{
borderRadius: 50,
backgroundColor: "white",
borderWidth: 0.7,
borderColor: "#dadce0",
height: 30,
paddingHorizontal: 10
}}
labelStyle={{
fontSize: 12,
color: "black",
fontFamily: "Manrope_500Medium",
}}
label={new Date().toLocaleDateString("en-US", {
timeZone: profileData?.timeZone || "",
})}
onPress={() => {
setSelectedDate(new Date());
}}
/>
)}
<View>
<SegmentedControl
segments={[{label: "D"}, {label: "W"}, {label: "M"}]}
backgroundColor="#ececec"
inactiveColor="#919191"
activeBackgroundColor="#ea156c"
activeColor="white"
outlineColor="white"
outlineWidth={3}
segmentLabelStyle={styles.segmentslblStyle}
onChangeIndex={handleSegmentChange}
initialIndex={mode === "day" ? 0 : mode === "week" ? 1 : 2}
/>
</View>
</View>
</View>
</View>
</View>
);
);
});
const styles = StyleSheet.create({
segmentslblStyle: {
fontSize: 12,
fontFamily: "Manrope_600SemiBold",
},
segmentslblStyle: {
fontSize: 12,
fontFamily: "Manrope_600SemiBold",
},
});

View File

@ -103,10 +103,11 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(
}, []);
const dayHeaderColor = useMemo(() => {
return isSameDate(todaysDate, selectedDate) && mode === "day" ? "white" : "#4d4d4d";
return isSameDate(todaysDate, selectedDate) ? "white" : "#4d4d4d";
}, [selectedDate, mode]);
const dateStyle = useMemo(() => {
if (mode === "week") return undefined
return isSameDate(todaysDate, selectedDate) && mode === "day"
? styles.dayHeader
: styles.otherDayHeader;

View File

@ -1,96 +1,78 @@
import { StyleSheet } from "react-native";
import React, { useState } from "react";
import {
Button,
Colors,
Dialog,
Drawer,
Text,
View,
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 { isAddingGrocery, setIsAddingGrocery } = useGroceryContext();
const [visible, setVisible] = useState<boolean>(false);
import {StyleSheet} from "react-native";
import React from "react";
import {Button, View,} from "react-native-ui-lib";
import {useGroceryContext} from "@/contexts/GroceryContext";
import {FontAwesome6} from "@expo/vector-icons";
const handleShowDialog = () => {
setVisible(true);
};
const handleHideDialog = () => {
setVisible(false);
};
return (
<View
row
spread
paddingH-25
style={{
position: "absolute",
bottom: 20,
width: "100%",
height: 60,
}}
>
<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}
labelStyle={styles.addBtnLbl}
enableShadow
onPress={() => {
setIsAddingGrocery(true);
}}
/>
</View>
</View>
);
const AddGroceryItem = () => {
const {setIsAddingGrocery} = useGroceryContext();
return (
<View
row
spread
paddingH-25
style={{
position: "absolute",
bottom: 20,
width: "100%",
height: 60,
}}
>
<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}
labelStyle={styles.addBtnLbl}
enableShadow
onPress={() => {
setIsAddingGrocery(true);
}}
/>
</View>
</View>
);
};
export default AddGroceryItem;
const styles = StyleSheet.create({
container: {
paddingVertical: 10,
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
},
inner: {
paddingHorizontal: 20,
display: "flex",
flexDirection: "column",
},
title: {
fontSize: 20,
fontWeight: "400",
textAlign: "center",
},
divider: {
width: "100%",
height: 1,
backgroundColor: "#E0E0E0",
marginVertical: 10,
},
btnContainer: {
width: "100%",
justifyContent: "center",
},
finishShopBtn: {
width: "100%",
},
shoppingBtn: {
flex: 1,
marginHorizontal: 3,
},
addBtnLbl: { fontFamily: "Manrope_500Medium", fontSize: 17, marginLeft: 5 },
container: {
paddingVertical: 10,
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
},
inner: {
paddingHorizontal: 20,
display: "flex",
flexDirection: "column",
},
title: {
fontSize: 20,
fontWeight: "400",
textAlign: "center",
},
divider: {
width: "100%",
height: 1,
backgroundColor: "#E0E0E0",
marginVertical: 10,
},
btnContainer: {
width: "100%",
justifyContent: "center",
},
finishShopBtn: {
width: "100%",
},
shoppingBtn: {
flex: 1,
marginHorizontal: 3,
},
addBtnLbl: {fontFamily: "Manrope_500Medium", fontSize: 17, marginLeft: 5},
});

View File

@ -1,159 +1,167 @@
import { Text, View } from "react-native-ui-lib";
import React, { useEffect, useRef, useState } from "react";
import { TextField, TextFieldRef } from "react-native-ui-lib";
import { GroceryCategory, useGroceryContext } from "@/contexts/GroceryContext";
import { Dropdown } from "react-native-element-dropdown";
import {Text, TextField, TextFieldRef, View} from "react-native-ui-lib";
import React, {useEffect, useRef} from "react";
import {GroceryCategory, useGroceryContext} from "@/contexts/GroceryContext";
import {Dropdown} from "react-native-element-dropdown";
import CloseXIcon from "@/assets/svgs/CloseXIcon";
import { StyleSheet } from "react-native";
import {StyleSheet} from "react-native";
import DropdownIcon from "@/assets/svgs/DropdownIcon";
import {AntDesign} from "@expo/vector-icons";
interface IEditGrocery {
id?: string;
title: string;
category: GroceryCategory;
setTitle: (value: string) => void;
setCategory?: (category: GroceryCategory) => void;
setSubmit?: (value: boolean) => void;
closeEdit?: () => void;
handleEditSubmit?: Function;
id?: string;
title: string;
category: GroceryCategory;
setTitle: (value: string) => void;
setCategory?: (category: GroceryCategory) => void;
setSubmit?: (value: boolean) => void;
closeEdit?: () => void;
handleEditSubmit?: Function;
}
const EditGroceryItem = ({ editGrocery }: { editGrocery: IEditGrocery }) => {
const { fuzzyMatchGroceryCategory } = useGroceryContext();
const inputRef = useRef<TextFieldRef>(null);
const groceryCategoryOptions = Object.values(GroceryCategory).map(
(category) => ({
label: category,
value: category,
})
);
const EditGroceryItem = ({editGrocery}: { editGrocery: IEditGrocery }) => {
const {fuzzyMatchGroceryCategory} = useGroceryContext();
const inputRef = useRef<TextFieldRef>(null);
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus(); // Focus on the TextField
const groceryCategoryOptions = Object.values(GroceryCategory).map(
(category) => ({
label: category,
value: category,
})
);
const handleSubmit = () => {
inputRef?.current?.blur()
console.log("CALLLLLL")
if (editGrocery.setSubmit) {
editGrocery.setSubmit(true);
}
if (editGrocery.handleEditSubmit) {
editGrocery.handleEditSubmit({
id: editGrocery.id,
title: editGrocery.title,
category: editGrocery.category,
});
}
if (editGrocery.closeEdit) {
editGrocery.closeEdit();
}
}
console.log(editGrocery.category);
}, []);
return (
<View
style={{
backgroundColor: "white",
width: "100%",
borderRadius: 25,
paddingHorizontal: 13,
paddingVertical: 10,
marginTop: 0,
}}
>
<View row spread centerV>
<TextField
text70T
style={{}}
ref={inputRef}
placeholder="Grocery"
value={editGrocery.title}
onChangeText={(value) => {
editGrocery.setTitle(value);
let groceryCategory = fuzzyMatchGroceryCategory(value);
if (editGrocery.setCategory) {
editGrocery.setCategory(groceryCategory);
}
}}
maxLength={25}
/>
<View row centerV>
<AntDesign
name="check"
size={24}
style={{
color: "green",
marginRight: 15,
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
console.log(editGrocery.category);
}, []);
return (
<View
style={{
backgroundColor: "white",
width: "100%",
borderRadius: 25,
paddingHorizontal: 13,
paddingVertical: 10,
marginTop: 0,
}}
>
<View row spread centerV>
<TextField
text70T
ref={inputRef}
placeholder="Grocery"
value={editGrocery.title}
onSubmitEditing={handleSubmit}
numberOfLines={1}
returnKeyType="done"
onChangeText={(value) => {
editGrocery.setTitle(value);
let groceryCategory = fuzzyMatchGroceryCategory(value);
if (editGrocery.setCategory) {
editGrocery.setCategory(groceryCategory);
}
}}
maxLength={25}
/>
<View row centerV>
<AntDesign
name="check"
size={24}
style={{
color: "green",
marginRight: 15,
}}
onPress={handleSubmit}
/>
<CloseXIcon
onPress={() => {
if (editGrocery.closeEdit) {
editGrocery.closeEdit();
}
}}
/>
</View>
</View>
<Dropdown
style={{marginTop: 15}}
data={groceryCategoryOptions}
placeholder="Select grocery category"
placeholderStyle={{color: "#a2a2a2", fontFamily: "Manrope_500Medium", fontSize: 13.2}}
labelField="label"
valueField="value"
value={
editGrocery.category
}
iconColor="white"
activeColor={"#fd1775"}
containerStyle={styles.dropdownStyle}
itemTextStyle={styles.itemText}
itemContainerStyle={styles.itemStyle}
selectedTextStyle={styles.selectedText}
renderLeftIcon={() => (
<DropdownIcon style={{marginRight: 8}}
color={editGrocery.category == GroceryCategory.None ? "#7b7b7b" : "#fd1775"}/>
)}
renderItem={(item) => {
return (
<View height={36.02} centerV>
<Text style={styles.itemText}>{item.label}</Text>
</View>
);
}}
onPress={() => {
if (editGrocery.setSubmit) {
editGrocery.setSubmit(true);
}
onChange={(item) => {
if (editGrocery.handleEditSubmit) {
editGrocery.handleEditSubmit({
id: editGrocery.id,
title: editGrocery.title,
category: editGrocery.category,
category: item.value,
});
}
if (editGrocery.closeEdit) {
editGrocery.closeEdit();
}
}}
/>
<CloseXIcon
onPress={() => {
if (editGrocery.closeEdit) {
editGrocery.closeEdit();
if (editGrocery.closeEdit) editGrocery.closeEdit();
} else {
if (editGrocery.setCategory) {
editGrocery.setCategory(item.value);
}
}
}}
/>
</View>
</View>
<Dropdown
style={{marginTop: 15}}
data={groceryCategoryOptions}
placeholder="Select grocery category"
placeholderStyle={{ color: "#a2a2a2", fontFamily: "Manrope_500Medium", fontSize: 13.2 }}
labelField="label"
valueField="value"
value={
editGrocery.category
}
iconColor="white"
activeColor={"#fd1775"}
containerStyle={styles.dropdownStyle}
itemTextStyle={styles.itemText}
itemContainerStyle={styles.itemStyle}
selectedTextStyle={styles.selectedText}
renderLeftIcon={() => (
<DropdownIcon style={{ marginRight: 8 }} color={editGrocery.category == GroceryCategory.None ? "#7b7b7b" : "#fd1775"} />
)}
renderItem={(item) => {
return (
<View height={36.02} centerV>
<Text style={styles.itemText}>{item.label}</Text>
</View>
);
}}
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);
}
}
}}
/>
</View>
);
);
};
const styles = StyleSheet.create({
itemText: {
fontFamily: "Manrope_400Regular",
fontSize: 15.42,
paddingLeft: 15,
},
selectedText: {
fontFamily: "Manrope_500Medium",
fontSize: 13.2,
color: "#fd1775",
},
dropdownStyle: { borderRadius: 6.61, height: 115.34, width: 187 },
itemStyle: { padding: 0, margin: 0 },
itemText: {
fontFamily: "Manrope_400Regular",
fontSize: 15.42,
paddingLeft: 15,
},
selectedText: {
fontFamily: "Manrope_500Medium",
fontSize: 13.2,
color: "#fd1775",
},
dropdownStyle: {borderRadius: 6.61, height: 115.34, width: 187},
itemStyle: {padding: 0, margin: 0},
});
export default EditGroceryItem;

View File

@ -1,302 +1,294 @@
import { FlatList, StyleSheet } from "react-native";
import React, { useEffect, useState } from "react";
import { Text, TouchableOpacity, View } from "react-native-ui-lib";
import {FlatList, StyleSheet} from "react-native";
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 {GroceryCategory, GroceryFrequency, useGroceryContext,} from "@/contexts/GroceryContext";
import HeaderTemplate from "@/components/shared/HeaderTemplate";
import { AntDesign, MaterialIcons } from "@expo/vector-icons";
import {AntDesign} from "@expo/vector-icons";
import EditGroceryItem from "./EditGroceryItem";
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
import { IGrocery } from "@/hooks/firebase/types/groceryData";
import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
import {IGrocery} from "@/hooks/firebase/types/groceryData";
import AddPersonIcon from "@/assets/svgs/AddPersonIcon";
const GroceryList = () => {
const {
groceries,
updateGroceryItem,
isAddingGrocery,
setIsAddingGrocery,
addGrocery,
} = useGroceryContext();
const { profileData } = useAuthContext();
const [approvedGroceries, setapprovedGroceries] = useState<IGrocery[]>(
groceries?.filter((item) => item.approved === true)
);
const [pendingGroceries, setPendingGroceries] = useState<IGrocery[]>(
groceries?.filter((item) => item.approved !== true)
);
const [category, setCategory] = useState<GroceryCategory>(
GroceryCategory.None
);
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 [title, setTitle] = useState<string>("");
const [submit, setSubmitted] = useState<boolean>(false);
const [pendingVisible, setPendingVisible] = useState<boolean>(true);
const [approvedVisible, setApprovedVisible] = useState<boolean>(true);
const [pendingVisible, setPendingVisible] = useState<boolean>(true);
const [approvedVisible, setApprovedVisible] = useState<boolean>(true);
// Group approved groceries by category
const approvedGroceriesByCategory = approvedGroceries?.reduce(
(groups: any, item: IGrocery) => {
const category = item.category || "Uncategorized";
if (!groups[category]) {
groups[category] = [];
}
groups[category].push(item);
return groups;
},
{}
);
// Group approved groceries by category
const approvedGroceriesByCategory = approvedGroceries?.reduce(
(groups: any, item: IGrocery) => {
const category = item.category || "Uncategorized";
if (!groups[category]) {
groups[category] = [];
}
groups[category].push(item);
return groups;
},
{}
);
useEffect(() => {
if (submit) {
if (title?.length > 2 && title?.length <= 25) {
addGrocery({
id: "",
title: title,
category: category,
approved: profileData?.userType === ProfileType.PARENT,
recurring: false,
frequency: GroceryFrequency.Never,
bought: false,
});
useEffect(() => {
if (submit) {
if (title?.length > 2 && title?.length <= 25) {
addGrocery({
id: "",
title: title,
category: category,
approved: profileData?.userType === ProfileType.PARENT,
recurring: false,
frequency: GroceryFrequency.Never,
bought: false,
});
setIsAddingGrocery(false);
setSubmitted(false);
setTitle("");
}
}
}, [submit]);
setIsAddingGrocery(false);
setSubmitted(false);
setTitle("");
}
}
}, [submit]);
useEffect(() => {
/**/
}, [category]);
useEffect(() => {
setapprovedGroceries(groceries?.filter((item) => item.approved));
setPendingGroceries(groceries?.filter((item) => !item.approved));
}, [groceries]);
useEffect(() => {
setapprovedGroceries(groceries?.filter((item) => item.approved === true));
setPendingGroceries(groceries?.filter((item) => item.approved !== true));
}, [groceries]);
return (
<View marginH-20 marginB-20>
<HeaderTemplate
message={"Welcome to your grocery list"}
isWelcome={false}
>
<View row centerV>
<View
backgroundColor="#e2eed8"
paddingH-15
paddingV-8
marginR-5
centerV
style={{ borderRadius: 50 }}
>
<Text text70BL color="#46a80a" style={styles.counterText}>
{approvedGroceries?.length} list{" "}
{approvedGroceries?.length === 1 ? (
<Text text70BL color="#46a80a" style={styles.counterText}>
item
</Text>
) : (
<Text text70BL color="#46a80a" style={styles.counterText}>
items
</Text>
)}
</Text>
</View>
<View
backgroundColor="#faead2"
padding-8
paddingH-12
marginR-15
style={{ borderRadius: 50 }}
>
<Text text70 style={styles.counterText} color="#e28800">
{pendingGroceries?.length} pending
</Text>
</View>
<TouchableOpacity>
<AddPersonIcon width={24}/>
</TouchableOpacity>
</View>
</HeaderTemplate>
{/* Pending Approval Section */}
<View row spread marginT-40 marginB-10 centerV>
<View row centerV>
<Text style={styles.subHeader}>Pending Approval</Text>
{pendingVisible && (
<AntDesign
name="down"
size={17}
style={styles.dropIcon}
color="#9f9f9f"
onPress={() => {
setPendingVisible(false);
}}
/>
)}
{!pendingVisible && (
<AntDesign
name="right"
size={15}
style={styles.dropIcon}
color="#9f9f9f"
onPress={() => {
setPendingVisible(true);
}}
/>
)}
</View>
<View
centerV
style={{
aspectRatio: 1,
width: 35,
backgroundColor: "#faead2",
borderRadius: 50,
}}
>
<Text style={styles.counterNr} center color="#e28800">
{pendingGroceries?.length.toString()}
</Text>
</View>
</View>
{pendingGroceries?.length > 0
? pendingVisible && (
<FlatList
data={pendingGroceries}
renderItem={({ item }) => (
<GroceryItem
item={item}
handleItemApproved={(id, changes) =>
updateGroceryItem({ ...changes, id: id })
}
/>
)}
keyExtractor={(item) => item.id.toString()}
/>
)
: pendingVisible && (
<Text style={styles.noItemTxt}>No items pending approval.</Text>
)}
{/* Approved Section */}
<View row spread marginT-40 marginB-0 centerV>
<View row centerV>
<Text style={styles.subHeader}>Shopping List</Text>
{approvedVisible && (
<AntDesign
name="down"
size={17}
style={styles.dropIcon}
color="#9f9f9f"
onPress={() => {
setApprovedVisible(false);
}}
/>
)}
{!approvedVisible && (
<AntDesign
name="right"
size={15}
style={styles.dropIcon}
color="#9f9f9f"
onPress={() => {
setApprovedVisible(true);
}}
/>
)}
</View>
<View
centerV
style={{
aspectRatio: 1,
width: 35,
backgroundColor: "#e2eed8",
borderRadius: 50,
}}
>
<Text style={styles.counterNr} center color="#46a80a">
{approvedGroceries?.length.toString()}
</Text>
</View>
</View>
{isAddingGrocery && (
<View style={{ marginTop: 8 }}>
<EditGroceryItem
editGrocery={{
title: title,
setCategory: setCategory,
category: category,
setTitle: setTitle,
setSubmit: setSubmitted,
closeEdit: () => setIsAddingGrocery(false)
}}
/>
</View>
)}
{/* Render Approved Groceries Grouped by Category */}
{approvedGroceries?.length > 0
? approvedVisible && (
<FlatList
data={Object.keys(approvedGroceriesByCategory)}
renderItem={({ item: category }) => (
<View key={category}>
{/* Render Category Header */}
<Text text80M style={{ marginTop: 10 }} color="#666">
{category}
</Text>
{/* Render Grocery Items for this Category */}
{approvedGroceriesByCategory[category].map(
(grocery: IGrocery) => (
<GroceryItem
key={grocery.id}
item={grocery}
handleItemApproved={(id, changes) =>
updateGroceryItem({ ...changes, id: id })
}
/>
)
)}
return (
<View marginH-20 marginB-20>
<HeaderTemplate
message={"Welcome to your grocery list"}
isWelcome={false}
>
<View row centerV>
<View
backgroundColor="#e2eed8"
paddingH-15
paddingV-8
marginR-5
centerV
style={{borderRadius: 50}}
>
<Text text70BL color="#46a80a" style={styles.counterText}>
{approvedGroceries?.length} list{" "}
{approvedGroceries?.length === 1 ? (
<Text text70BL color="#46a80a" style={styles.counterText}>
item
</Text>
) : (
<Text text70BL color="#46a80a" style={styles.counterText}>
items
</Text>
)}
</Text>
</View>
<View
backgroundColor="#faead2"
padding-8
paddingH-12
marginR-15
style={{borderRadius: 50}}
>
<Text text70 style={styles.counterText} color="#e28800">
{pendingGroceries?.length} pending
</Text>
</View>
<TouchableOpacity>
<AddPersonIcon width={24}/>
</TouchableOpacity>
</View>
)}
keyExtractor={(category) => category}
/>
)
: approvedVisible && (
<Text style={styles.noItemTxt}>No approved items.</Text>
)}
</View>
);
</HeaderTemplate>
{/* Pending Approval Section */}
<View row spread marginT-40 marginB-10 centerV>
<View row centerV>
<Text style={styles.subHeader}>Pending Approval</Text>
{pendingVisible && (
<AntDesign
name="down"
size={17}
style={styles.dropIcon}
color="#9f9f9f"
onPress={() => {
setPendingVisible(false);
}}
/>
)}
{!pendingVisible && (
<AntDesign
name="right"
size={15}
style={styles.dropIcon}
color="#9f9f9f"
onPress={() => {
setPendingVisible(true);
}}
/>
)}
</View>
<View
centerV
style={{
aspectRatio: 1,
width: 35,
backgroundColor: "#faead2",
borderRadius: 50,
}}
>
<Text style={styles.counterNr} center color="#e28800">
{pendingGroceries?.length.toString()}
</Text>
</View>
</View>
{pendingGroceries?.length > 0
? pendingVisible && (
<FlatList
data={pendingGroceries}
renderItem={({item}) => (
<GroceryItem
item={item}
handleItemApproved={(id, changes) =>
updateGroceryItem({...changes, id: id})
}
/>
)}
keyExtractor={(item) => item.id.toString()}
/>
)
: pendingVisible && (
<Text style={styles.noItemTxt}>No items pending approval.</Text>
)}
{/* Approved Section */}
<View row spread marginT-40 marginB-0 centerV>
<View row centerV>
<Text style={styles.subHeader}>Shopping List</Text>
{approvedVisible && (
<AntDesign
name="down"
size={17}
style={styles.dropIcon}
color="#9f9f9f"
onPress={() => {
setApprovedVisible(false);
}}
/>
)}
{!approvedVisible && (
<AntDesign
name="right"
size={15}
style={styles.dropIcon}
color="#9f9f9f"
onPress={() => {
setApprovedVisible(true);
}}
/>
)}
</View>
<View
centerV
style={{
aspectRatio: 1,
width: 35,
backgroundColor: "#e2eed8",
borderRadius: 50,
}}
>
<Text style={styles.counterNr} center color="#46a80a">
{approvedGroceries?.length.toString()}
</Text>
</View>
</View>
{isAddingGrocery && (
<View style={{marginTop: 8}}>
<EditGroceryItem
editGrocery={{
title: title,
setCategory: setCategory,
category: category,
setTitle: setTitle,
setSubmit: setSubmitted,
closeEdit: () => setIsAddingGrocery(false)
}}
/>
</View>
)}
{/* Render Approved Groceries Grouped by Category */}
{approvedGroceries?.length > 0
? approvedVisible && (
<FlatList
data={Object.keys(approvedGroceriesByCategory)}
renderItem={({item: category}) => (
<View key={category}>
{/* Render Category Header */}
<Text text80M style={{marginTop: 10}} color="#666">
{category}
</Text>
{/* Render Grocery Items for this Category */}
{approvedGroceriesByCategory[category].map(
(grocery: IGrocery) => (
<GroceryItem
key={grocery.id}
item={grocery}
handleItemApproved={(id, changes) =>
updateGroceryItem({...changes, id: id})
}
/>
)
)}
</View>
)}
keyExtractor={(category) => category}
/>
)
: approvedVisible && (
<Text style={styles.noItemTxt}>No approved items.</Text>
)}
</View>
);
};
const styles = StyleSheet.create({
dropIcon: {
marginHorizontal: 10,
},
noItemTxt: {
fontFamily: "Manrope_400Regular",
fontSize: 14,
},
counterText: {
fontSize: 14,
fontFamily: "PlusJakartaSans_600SemiBold",
},
subHeader: {
fontSize: 15,
fontFamily: "Manrope_700Bold",
},
counterNr: {
fontFamily: "PlusJakartaSans_600SemiBold",
fontSize: 14
}
dropIcon: {
marginHorizontal: 10,
},
noItemTxt: {
fontFamily: "Manrope_400Regular",
fontSize: 14,
},
counterText: {
fontSize: 14,
fontFamily: "PlusJakartaSans_600SemiBold",
},
subHeader: {
fontSize: 15,
fontFamily: "Manrope_700Bold",
},
counterNr: {
fontFamily: "PlusJakartaSans_600SemiBold",
fontSize: 14
}
});
export default GroceryList;

View File

@ -1,38 +1,38 @@
import { Text, ScrollView } from "react-native";
import { View } from "react-native-ui-lib";
import React, { useEffect, useRef } from "react";
import {ScrollView} from "react-native";
import {View} from "react-native-ui-lib";
import React, {useEffect, useRef} from "react";
import AddGroceryItem from "./AddGroceryItem";
import GroceryList from "./GroceryList";
import { useGroceryContext } from "@/contexts/GroceryContext";
import {useGroceryContext} from "@/contexts/GroceryContext";
const GroceryWrapper = () => {
const { isAddingGrocery } = useGroceryContext();
const scrollViewRef = useRef<ScrollView>(null); // Reference to the ScrollView
const {isAddingGrocery} = useGroceryContext();
const scrollViewRef = useRef<ScrollView>(null); // Reference to the ScrollView
useEffect(() => {
if (isAddingGrocery && scrollViewRef.current) {
scrollViewRef.current.scrollTo({
y: 400, // Adjust this value to scroll a bit down (100 is an example)
animated: true,
});
}
}, [isAddingGrocery]);
useEffect(() => {
if (isAddingGrocery && scrollViewRef.current) {
scrollViewRef.current.scrollTo({
y: 400, // Adjust this value to scroll a bit down (100 is an example)
animated: true,
});
}
}, [isAddingGrocery]);
return (
<View height={"100%"} paddingT-15 paddingH-15>
<View height={"100%"}>
<ScrollView
ref={scrollViewRef} // Assign the ref to the ScrollView
automaticallyAdjustKeyboardInsets={true}
>
<View marginB-70>
<GroceryList />
</View>
</ScrollView>
{!isAddingGrocery && <AddGroceryItem />}
</View>
</View>
);
return (
<View height={"100%"} paddingT-15 paddingH-15>
<View height={"100%"}>
<ScrollView
ref={scrollViewRef}
automaticallyAdjustKeyboardInsets={true}
>
<View marginB-70>
<GroceryList/>
</View>
</ScrollView>
{!isAddingGrocery && <AddGroceryItem/>}
</View>
</View>
);
};
export default GroceryWrapper;

View File

@ -1,338 +1,353 @@
import { View, Text, Button, Switch, PickerModes } from "react-native-ui-lib";
import React, { useRef, useState } from "react";
import PointsSlider from "@/components/shared/PointsSlider";
import { repeatOptions, useToDosContext } from "@/contexts/ToDosContext";
import { Feather, AntDesign, Ionicons } from "@expo/vector-icons";
import {
Dialog,
TextField,
DateTimePicker,
Picker,
ButtonSize,
Button,
ButtonSize,
DateTimePicker,
Dialog,
Picker,
PickerModes,
Switch,
Text,
TextField,
TextFieldRef,
View
} from "react-native-ui-lib";
import { PanningDirectionsEnum } from "react-native-ui-lib/src/incubator/panView";
import { Dimensions, StyleSheet } from "react-native";
import React, {useEffect, useRef, useState} from "react";
import PointsSlider from "@/components/shared/PointsSlider";
import {repeatOptions, useToDosContext} from "@/contexts/ToDosContext";
import {Ionicons} from "@expo/vector-icons";
import {PanningDirectionsEnum} from "react-native-ui-lib/src/incubator/panView";
import {Dimensions, KeyboardAvoidingView, StyleSheet} from "react-native";
import DropModalIcon from "@/assets/svgs/DropModalIcon";
import { IToDo } from "@/hooks/firebase/types/todoData";
import {IToDo} from "@/hooks/firebase/types/todoData";
import AssigneesDisplay from "@/components/shared/AssigneesDisplay";
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
import CalendarIcon from "@/assets/svgs/CalendarIcon";
import ClockIcon from "@/assets/svgs/ClockIcon";
import ClockOIcon from "@/assets/svgs/ClockOIcon";
import ProfileIcon from "@/assets/svgs/ProfileIcon";
import RepeatFreq from "./RepeatFreq";
interface IAddChoreDialog {
isVisible: boolean;
setIsVisible: (value: boolean) => void;
selectedTodo?: IToDo;
isVisible: boolean;
setIsVisible: (value: boolean) => void;
selectedTodo?: IToDo;
}
const defaultTodo = {
id: "",
title: "",
points: 10,
date: new Date(),
rotate: false,
repeatType: "Every week",
assignees: [],
repeatDays: []
id: "",
title: "",
points: 10,
date: new Date(),
rotate: false,
repeatType: "Every week",
assignees: [],
repeatDays: []
};
const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
const { addToDo, updateToDo } = useToDosContext();
const [todo, setTodo] = useState<IToDo>(
addChoreDialogProps.selectedTodo ?? defaultTodo
);
const [selectedAssignees, setSelectedAssignees] = useState<string[]>(
addChoreDialogProps?.selectedTodo?.assignees ?? []
);
const { width, height } = Dimensions.get("screen");
const [points, setPoints] = useState<number>(todo.points);
const {addToDo, updateToDo} = useToDosContext();
const [todo, setTodo] = useState<IToDo>(
addChoreDialogProps.selectedTodo ?? defaultTodo
);
const [selectedAssignees, setSelectedAssignees] = useState<string[]>(
addChoreDialogProps?.selectedTodo?.assignees ?? []
);
const {width} = Dimensions.get("screen");
const [points, setPoints] = useState<number>(todo.points);
const { data: members } = useGetFamilyMembers();
const titleRef = useRef<TextFieldRef>(null)
const handleClose = () => {
setTodo(defaultTodo);
setSelectedAssignees([]);
addChoreDialogProps.setIsVisible(false);
};
const {data: members} = useGetFamilyMembers();
const handleChange = (text: string) => {
const numericValue = parseInt(text, 10);
const handleClose = () => {
setTodo(defaultTodo);
setSelectedAssignees([]);
addChoreDialogProps.setIsVisible(false);
};
if (!isNaN(numericValue) && numericValue >= 0 && numericValue <= 100) {
setPoints(numericValue);
} else if (text === "") {
setPoints(0);
}
};
const handleChange = (text: string) => {
const numericValue = parseInt(text, 10);
const handleRepeatDaysChange = (day: string, set: boolean) => {
if (set) {
const updatedTodo = {
...todo,
repeatDays: [...todo.repeatDays, day]
}
setTodo(updatedTodo);
} else {
const array = todo.repeatDays ?? [];
let index = array.indexOf(day);
array.splice(index, 1);
const updatedTodo = {
...todo,
repeatDays: array
}
setTodo(updatedTodo);
}
}
if (!isNaN(numericValue) && numericValue >= 0 && numericValue <= 100) {
setPoints(numericValue);
} else if (text === "") {
setPoints(0);
}
};
return (
<Dialog
bottom={true}
height={"90%"}
width={width}
panDirection={PanningDirectionsEnum.DOWN}
onDismiss={() => handleClose}
containerStyle={{
borderRadius: 10,
backgroundColor: "white",
alignSelf: "stretch",
padding: 0,
paddingTop: 4,
margin: 0,
}}
visible={addChoreDialogProps.isVisible}
>
<View row spread>
<Button
color="#05a8b6"
style={styles.topBtn}
label="Cancel"
onPress={() => {
handleClose();
}}
/>
<View marginT-12>
<DropModalIcon
onPress={() => {
handleClose();
}}
/>
</View>
<Button
color="#05a8b6"
style={styles.topBtn}
label="Save"
onPress={() => {
try {
if (addChoreDialogProps.selectedTodo) {
updateToDo({
...todo,
points: points,
assignees: selectedAssignees
});
} else {
addToDo({
...todo,
done: false,
points: points,
assignees: selectedAssignees,
repeatDays: todo.repeatDays ?? []
});
}
handleClose();
} catch (error) {
console.error(error);
const handleRepeatDaysChange = (day: string, set: boolean) => {
if (set) {
const updatedTodo = {
...todo,
repeatDays: [...todo.repeatDays, day]
}
}}
/>
</View>
<TextField
placeholder="Add a To Do"
autoFocus
value={todo?.title}
onChangeText={(text) => {
setTodo((oldValue: IToDo) => ({ ...oldValue, title: text }));
}}
placeholderTextColor="#2d2d30"
text60R
marginT-15
marginL-30
/>
<View style={styles.divider} marginT-8 />
<View marginL-30 centerV>
<View row marginB-10>
{todo?.date && (
<View row centerV>
<CalendarIcon color="#919191" width={24} height={24} />
<DateTimePicker
value={todo.date}
text70
style={{
fontFamily: "PlusJakartaSans_500Medium",
fontSize: 16,
}}
marginL-12
onChange={(date) => {
setTodo((oldValue: IToDo) => ({ ...oldValue, date: date }));
}}
/>
</View>
)}
</View>
<View row centerV>
<ClockOIcon />
<Picker
marginL-12
placeholder="Select Repeat Type"
value={todo?.repeatType}
onChange={(value) => {
if (value) {
if (value.toString() == "None") {
setTodo((oldValue) => ({
...oldValue,
date: null,
repeatType: "None",
}));
} else {
setTodo((oldValue) => ({
...oldValue,
date: new Date(),
repeatType: value.toString(),
}));
}
}
}}
topBarProps={{ title: "Repeat" }}
style={{
marginVertical: 5,
fontFamily: "PlusJakartaSans_500Medium",
fontSize: 16,
}}
>
{repeatOptions.map((option) => (
<Picker.Item
key={option.value}
label={option.label}
value={option.value}
/>
))}
</Picker>
</View>
{todo.repeatType == "Every week" && <RepeatFreq handleRepeatDaysChange={handleRepeatDaysChange} repeatDays={todo.repeatDays ?? []}/>}
</View>
<View style={styles.divider} />
setTodo(updatedTodo);
} else {
const array = todo.repeatDays ?? [];
let index = array.indexOf(day);
array.splice(index, 1);
const updatedTodo = {
...todo,
repeatDays: array
}
setTodo(updatedTodo);
}
}
<View marginH-30 marginB-10 row centerV>
<ProfileIcon color="#919191" />
<Text style={styles.sub} marginL-10>
Assignees
</Text>
<View flex-1 />
<Picker
marginL-8
value={selectedAssignees}
onChange={(value) => {
setSelectedAssignees([...selectedAssignees, ...value]);
}}
style={{ marginVertical: 5 }}
mode={PickerModes.MULTI}
renderInput={() => (
<Button
size={ButtonSize.small}
paddingH-8
iconSource={() => (
<Ionicons name="add-outline" size={20} color="#ea156c" />
)}
style={{
marginLeft: "auto",
borderRadius: 8,
backgroundColor: "#ffe8f1",
borderColor: "#ea156c",
borderWidth: 1,
}}
color="#ea156c"
label="Assign"
labelStyle={{ fontFamily: "Manrope_600SemiBold", fontSize: 14 }}
/>
)}
useEffect(() => {
setTimeout(() => {
titleRef?.current?.focus()
}, 500)
}, []);
return (
<Dialog
bottom={true}
height={"90%"}
width={width}
panDirection={PanningDirectionsEnum.DOWN}
onDismiss={() => handleClose}
containerStyle={{
borderRadius: 10,
backgroundColor: "white",
alignSelf: "stretch",
padding: 0,
paddingTop: 4,
margin: 0,
}}
visible={addChoreDialogProps.isVisible}
>
{members?.map((member) => (
<Picker.Item
key={member.uid}
label={member?.firstName + " " + member?.lastName}
value={member?.uid!}
/>
))}
</Picker>
</View>
<View row marginL-27 marginT-0>
<AssigneesDisplay
selectedAttendees={selectedAssignees}
setSelectedAttendees={setSelectedAssignees}
/>
</View>
<View row centerV style={styles.rotateSwitch}>
<Text style={{ fontFamily: "PlusJakartaSans_500Medium", fontSize: 16 }}>
Take Turns
</Text>
<Switch
onColor={"#ea156c"}
value={todo.rotate}
style={{ width: 43.06, height: 27.13 }}
marginL-10
onValueChange={(value) =>
setTodo((oldValue) => ({ ...oldValue, rotate: value }))
}
/>
</View>
<View style={styles.divider} />
<View marginH-30 marginB-15 row centerV>
<Ionicons name="gift-outline" size={25} color="#919191" />
<Text style={styles.sub} marginL-10>
Reward Points
</Text>
</View>
<PointsSlider
points={points}
setPoints={setPoints}
handleChange={handleChange}
/>
</Dialog>
);
<View row spread>
<Button
color="#05a8b6"
style={styles.topBtn}
label="Cancel"
onPress={() => {
handleClose();
}}
/>
<View marginT-12>
<DropModalIcon
onPress={() => {
handleClose();
}}
/>
</View>
<Button
color="#05a8b6"
style={styles.topBtn}
label="Save"
onPress={() => {
try {
if (addChoreDialogProps.selectedTodo) {
updateToDo({
...todo,
points: points,
assignees: selectedAssignees
});
} else {
addToDo({
...todo,
done: false,
points: points,
assignees: selectedAssignees,
repeatDays: todo.repeatDays ?? []
});
}
handleClose();
} catch (error) {
console.error(error);
}
}}
/>
</View>
<KeyboardAvoidingView>
<TextField
placeholder="Add a To Do"
value={todo?.title}
onChangeText={(text) => {
setTodo((oldValue: IToDo) => ({...oldValue, title: text}));
}}
placeholderTextColor="#2d2d30"
text60R
marginT-15
marginL-30
ref={titleRef}
/>
<View style={styles.divider} marginT-8/>
<View marginL-30 centerV>
<View row marginB-10>
{todo?.date && (
<View row centerV>
<CalendarIcon color="#919191" width={24} height={24}/>
<DateTimePicker
value={todo.date}
text70
style={{
fontFamily: "PlusJakartaSans_500Medium",
fontSize: 16,
}}
marginL-12
onChange={(date) => {
setTodo((oldValue: IToDo) => ({...oldValue, date: date}));
}}
/>
</View>
)}
</View>
<View row centerV>
<ClockOIcon/>
<Picker
marginL-12
placeholder="Select Repeat Type"
value={todo?.repeatType}
onChange={(value) => {
if (value) {
if (value.toString() == "None") {
setTodo((oldValue) => ({
...oldValue,
date: null,
repeatType: "None",
}));
} else {
setTodo((oldValue) => ({
...oldValue,
date: new Date(),
repeatType: value.toString(),
}));
}
}
}}
topBarProps={{title: "Repeat"}}
style={{
marginVertical: 5,
fontFamily: "PlusJakartaSans_500Medium",
fontSize: 16,
}}
>
{repeatOptions.map((option) => (
<Picker.Item
key={option.value}
label={option.label}
value={option.value}
/>
))}
</Picker>
</View>
{todo.repeatType == "Every week" && <RepeatFreq handleRepeatDaysChange={handleRepeatDaysChange}
repeatDays={todo.repeatDays ?? []}/>}
</View>
<View style={styles.divider}/>
<View marginH-30 marginB-10 row centerV>
<ProfileIcon color="#919191"/>
<Text style={styles.sub} marginL-10>
Assignees
</Text>
<View flex-1/>
<Picker
marginL-8
value={selectedAssignees}
onChange={(value) => {
setSelectedAssignees([...selectedAssignees, ...value]);
}}
style={{marginVertical: 5}}
mode={PickerModes.MULTI}
renderInput={() => (
<Button
size={ButtonSize.small}
paddingH-8
iconSource={() => (
<Ionicons name="add-outline" size={20} color="#ea156c"/>
)}
style={{
marginLeft: "auto",
borderRadius: 8,
backgroundColor: "#ffe8f1",
borderColor: "#ea156c",
borderWidth: 1,
}}
color="#ea156c"
label="Assign"
labelStyle={{fontFamily: "Manrope_600SemiBold", fontSize: 14}}
/>
)}
>
{members?.map((member) => (
<Picker.Item
key={member.uid}
label={member?.firstName + " " + member?.lastName}
value={member?.uid!}
/>
))}
</Picker>
</View>
<View row marginL-27 marginT-0>
<AssigneesDisplay
selectedAttendees={selectedAssignees}
setSelectedAttendees={setSelectedAssignees}
/>
</View>
<View row centerV style={styles.rotateSwitch}>
<Text style={{fontFamily: "PlusJakartaSans_500Medium", fontSize: 16}}>
Take Turns
</Text>
<Switch
onColor={"#ea156c"}
value={todo.rotate}
style={{width: 43.06, height: 27.13}}
marginL-10
onValueChange={(value) =>
setTodo((oldValue) => ({...oldValue, rotate: value}))
}
/>
</View>
<View style={styles.divider}/>
<View marginH-30 marginB-15 row centerV>
<Ionicons name="gift-outline" size={25} color="#919191"/>
<Text style={styles.sub} marginL-10>
Reward Points
</Text>
</View>
<PointsSlider
points={points}
setPoints={setPoints}
handleChange={handleChange}
/>
</KeyboardAvoidingView>
</Dialog>
);
};
export default AddChoreDialog;
const styles = StyleSheet.create({
divider: { height: 1, backgroundColor: "#e4e4e4", marginVertical: 15 },
gradient: {
height: "25%",
position: "absolute",
bottom: 0,
width: "100%",
},
buttonContainer: {
position: "absolute",
bottom: 25,
width: "100%",
},
button: {
backgroundColor: "rgb(253, 23, 117)",
paddingVertical: 20,
},
topBtn: {
backgroundColor: "white",
color: "#05a8b6",
},
rotateSwitch: {
marginLeft: 35,
marginBottom: 10,
marginTop: 25,
},
sub: {
fontFamily: "Manrope_600SemiBold",
fontSize: 18,
},
divider: {height: 1, backgroundColor: "#e4e4e4", marginVertical: 15},
gradient: {
height: "25%",
position: "absolute",
bottom: 0,
width: "100%",
},
buttonContainer: {
position: "absolute",
bottom: 25,
width: "100%",
},
button: {
backgroundColor: "rgb(253, 23, 117)",
paddingVertical: 20,
},
topBtn: {
backgroundColor: "white",
color: "#05a8b6",
},
rotateSwitch: {
marginLeft: 35,
marginBottom: 10,
marginTop: 25,
},
sub: {
fontFamily: "Manrope_600SemiBold",
fontSize: 18,
},
});