mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 00:24:53 +00:00
bugfixes
This commit is contained in:
@ -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;
|
||||
|
||||
@ -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",
|
||||
},
|
||||
});
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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},
|
||||
});
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user