mirror of
https://github.com/urosran/cally.git
synced 2025-07-17 02:25:10 +00:00
ui fixes
This commit is contained in:
19
assets/svgs/PlusIcon.tsx
Normal file
19
assets/svgs/PlusIcon.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import Svg, { SvgProps, Path } from "react-native-svg";
|
||||||
|
const PlusIcon = (props: SvgProps) => (
|
||||||
|
<Svg
|
||||||
|
width={props.width || 14}
|
||||||
|
height={props.height || 15}
|
||||||
|
fill="none"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Path
|
||||||
|
stroke="#fff"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M1 7.632h12m-6-6v12"
|
||||||
|
/>
|
||||||
|
</Svg>
|
||||||
|
);
|
||||||
|
export default PlusIcon;
|
@ -6,6 +6,7 @@ import HeaderTemplate from "@/components/shared/HeaderTemplate";
|
|||||||
import {Feather, MaterialIcons} from "@expo/vector-icons";
|
import {Feather, MaterialIcons} from "@expo/vector-icons";
|
||||||
import AddBrainDump from "./AddBrainDump";
|
import AddBrainDump from "./AddBrainDump";
|
||||||
import LinearGradient from "react-native-linear-gradient";
|
import LinearGradient from "react-native-linear-gradient";
|
||||||
|
import PlusIcon from "@/assets/svgs/PlusIcon";
|
||||||
|
|
||||||
const BrainDumpPage = () => {
|
const BrainDumpPage = () => {
|
||||||
const [searchText, setSearchText] = useState<string>("");
|
const [searchText, setSearchText] = useState<string>("");
|
||||||
@ -85,10 +86,10 @@ const BrainDumpPage = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View row centerV centerH>
|
<View row centerV centerH>
|
||||||
<MaterialIcons name="add" size={22} color={"white"}/>
|
<PlusIcon />
|
||||||
<Text
|
<Text
|
||||||
white
|
white
|
||||||
style={{fontSize: 16, fontFamily: "Manrope_600SemiBold"}}
|
style={{fontSize: 16, fontFamily: "Manrope_600SemiBold", marginLeft: 5}}
|
||||||
>
|
>
|
||||||
New
|
New
|
||||||
</Text>
|
</Text>
|
||||||
|
@ -10,6 +10,7 @@ import CalendarIcon from "@/assets/svgs/CalendarIcon";
|
|||||||
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
||||||
import {useSetAtom} from "jotai";
|
import {useSetAtom} from "jotai";
|
||||||
import {selectedNewEventDateAtom} from "@/components/pages/calendar/atoms";
|
import {selectedNewEventDateAtom} from "@/components/pages/calendar/atoms";
|
||||||
|
import PlusIcon from "@/assets/svgs/PlusIcon";
|
||||||
|
|
||||||
export const AddEventDialog = () => {
|
export const AddEventDialog = () => {
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
@ -50,8 +51,8 @@ export const AddEventDialog = () => {
|
|||||||
onPress={() => setShow(true)}
|
onPress={() => setShow(true)}
|
||||||
>
|
>
|
||||||
<View row centerV centerH>
|
<View row centerV centerH>
|
||||||
<MaterialIcons name="add" size={22} color={"white"}/>
|
<PlusIcon />
|
||||||
<Text white style={{fontSize: 16, fontFamily: 'Manrope_600SemiBold'}}>
|
<Text white style={{fontSize: 16, fontFamily: 'Manrope_600SemiBold', marginLeft: 5}}>
|
||||||
New
|
New
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
@ -3,6 +3,7 @@ import React from "react";
|
|||||||
import {Button, View,} from "react-native-ui-lib";
|
import {Button, View,} from "react-native-ui-lib";
|
||||||
import {useGroceryContext} from "@/contexts/GroceryContext";
|
import {useGroceryContext} from "@/contexts/GroceryContext";
|
||||||
import {FontAwesome6} from "@expo/vector-icons";
|
import {FontAwesome6} from "@expo/vector-icons";
|
||||||
|
import PlusIcon from "@/assets/svgs/PlusIcon";
|
||||||
|
|
||||||
const AddGroceryItem = () => {
|
const AddGroceryItem = () => {
|
||||||
const {setIsAddingGrocery} = useGroceryContext();
|
const {setIsAddingGrocery} = useGroceryContext();
|
||||||
@ -11,12 +12,12 @@ const AddGroceryItem = () => {
|
|||||||
<View
|
<View
|
||||||
row
|
row
|
||||||
spread
|
spread
|
||||||
paddingH-25
|
paddingH-20
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
bottom: 65,
|
bottom: 15,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: 60,
|
height: 53.26,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View style={styles.btnContainer} row>
|
<View style={styles.btnContainer} row>
|
||||||
@ -25,7 +26,7 @@ const AddGroceryItem = () => {
|
|||||||
backgroundColor="#fd1775"
|
backgroundColor="#fd1775"
|
||||||
label="Add item"
|
label="Add item"
|
||||||
text70L
|
text70L
|
||||||
iconSource={() => <FontAwesome6 name="add" size={18} color="white"/>}
|
iconSource={() => <PlusIcon />}
|
||||||
style={styles.finishShopBtn}
|
style={styles.finishShopBtn}
|
||||||
labelStyle={styles.addBtnLbl}
|
labelStyle={styles.addBtnLbl}
|
||||||
enableShadow
|
enableShadow
|
||||||
@ -69,6 +70,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
finishShopBtn: {
|
finishShopBtn: {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
|
height: 53.26,
|
||||||
},
|
},
|
||||||
shoppingBtn: {
|
shoppingBtn: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -1,167 +1,204 @@
|
|||||||
import {Text, TextField, TextFieldRef, View} from "react-native-ui-lib";
|
import { Text, TextField, TextFieldRef, View } from "react-native-ui-lib";
|
||||||
import React, {useEffect, useRef} from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import {GroceryCategory, useGroceryContext} from "@/contexts/GroceryContext";
|
import { GroceryCategory, useGroceryContext } from "@/contexts/GroceryContext";
|
||||||
import {Dropdown} from "react-native-element-dropdown";
|
import { Dropdown } from "react-native-element-dropdown";
|
||||||
import CloseXIcon from "@/assets/svgs/CloseXIcon";
|
import CloseXIcon from "@/assets/svgs/CloseXIcon";
|
||||||
import {StyleSheet} from "react-native";
|
import { findNodeHandle, StyleSheet, UIManager } from "react-native";
|
||||||
import DropdownIcon from "@/assets/svgs/DropdownIcon";
|
import DropdownIcon from "@/assets/svgs/DropdownIcon";
|
||||||
import {AntDesign} from "@expo/vector-icons";
|
import { AntDesign } from "@expo/vector-icons";
|
||||||
|
|
||||||
interface IEditGrocery {
|
interface IEditGrocery {
|
||||||
id?: string;
|
id?: string;
|
||||||
title: string;
|
title: string;
|
||||||
category: GroceryCategory;
|
category: GroceryCategory;
|
||||||
setTitle: (value: string) => void;
|
setTitle: (value: string) => void;
|
||||||
setCategory?: (category: GroceryCategory) => void;
|
setCategory?: (category: GroceryCategory) => void;
|
||||||
setSubmit?: (value: boolean) => void;
|
setSubmit?: (value: boolean) => void;
|
||||||
closeEdit?: () => void;
|
closeEdit?: () => void;
|
||||||
handleEditSubmit?: Function;
|
handleEditSubmit?: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EditGroceryItem = ({
|
||||||
|
editGrocery,
|
||||||
|
onInputFocus,
|
||||||
|
}: {
|
||||||
|
editGrocery: IEditGrocery;
|
||||||
|
onInputFocus: (y: number) => void;
|
||||||
|
}) => {
|
||||||
|
const { fuzzyMatchGroceryCategory } = useGroceryContext();
|
||||||
|
const inputRef = useRef<TextFieldRef>(null);
|
||||||
|
const containerRef = useRef(null);
|
||||||
|
|
||||||
const EditGroceryItem = ({editGrocery}: { editGrocery: IEditGrocery }) => {
|
const handleFocus = () => {
|
||||||
const {fuzzyMatchGroceryCategory} = useGroceryContext();
|
if (containerRef.current) {
|
||||||
const inputRef = useRef<TextFieldRef>(null);
|
const handle = findNodeHandle(containerRef.current);
|
||||||
|
if (handle) {
|
||||||
|
UIManager.measure(
|
||||||
|
handle,
|
||||||
|
(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
pageX: number,
|
||||||
|
pageY: number
|
||||||
|
) => {
|
||||||
|
onInputFocus(pageY);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const groceryCategoryOptions = Object.values(GroceryCategory).map(
|
const groceryCategoryOptions = Object.values(GroceryCategory).map(
|
||||||
(category) => ({
|
(category) => ({
|
||||||
label: category,
|
label: category,
|
||||||
value: category,
|
value: category,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
inputRef?.current?.blur()
|
inputRef?.current?.blur();
|
||||||
console.log("CALLLLLL")
|
console.log("CALLLLLL");
|
||||||
if (editGrocery.setSubmit) {
|
if (editGrocery.setSubmit) {
|
||||||
editGrocery.setSubmit(true);
|
editGrocery.setSubmit(true);
|
||||||
}
|
}
|
||||||
if (editGrocery.handleEditSubmit) {
|
if (editGrocery.handleEditSubmit) {
|
||||||
editGrocery.handleEditSubmit({
|
editGrocery.handleEditSubmit({
|
||||||
id: editGrocery.id,
|
id: editGrocery.id,
|
||||||
title: editGrocery.title,
|
title: editGrocery.title,
|
||||||
category: editGrocery.category,
|
category: editGrocery.category,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (editGrocery.closeEdit) {
|
if (editGrocery.closeEdit) {
|
||||||
editGrocery.closeEdit();
|
editGrocery.closeEdit();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (inputRef.current) {
|
||||||
|
inputRef.current.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
console.log(editGrocery.category);
|
||||||
if (inputRef.current) {
|
}, []);
|
||||||
inputRef.current.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(editGrocery.category);
|
return (
|
||||||
}, []);
|
<View
|
||||||
|
ref={containerRef}
|
||||||
return (
|
style={{
|
||||||
<View
|
backgroundColor: "white",
|
||||||
|
width: "100%",
|
||||||
|
borderRadius: 25,
|
||||||
|
paddingHorizontal: 13,
|
||||||
|
paddingVertical: 10,
|
||||||
|
marginTop: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View row spread centerV>
|
||||||
|
<TextField
|
||||||
|
text70T
|
||||||
|
ref={inputRef}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
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={{
|
style={{
|
||||||
backgroundColor: "white",
|
color: "green",
|
||||||
width: "100%",
|
marginRight: 15,
|
||||||
borderRadius: 25,
|
|
||||||
paddingHorizontal: 13,
|
|
||||||
paddingVertical: 10,
|
|
||||||
marginTop: 0,
|
|
||||||
}}
|
}}
|
||||||
>
|
onPress={handleSubmit}
|
||||||
<View row spread centerV>
|
/>
|
||||||
<TextField
|
<CloseXIcon
|
||||||
text70T
|
onPress={() => {
|
||||||
ref={inputRef}
|
if (editGrocery.closeEdit) {
|
||||||
placeholder="Grocery"
|
editGrocery.closeEdit();
|
||||||
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>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
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>
|
</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({
|
const styles = StyleSheet.create({
|
||||||
itemText: {
|
itemText: {
|
||||||
fontFamily: "Manrope_400Regular",
|
fontFamily: "Manrope_400Regular",
|
||||||
fontSize: 15.42,
|
fontSize: 15.42,
|
||||||
paddingLeft: 15,
|
paddingLeft: 15,
|
||||||
},
|
},
|
||||||
selectedText: {
|
selectedText: {
|
||||||
fontFamily: "Manrope_500Medium",
|
fontFamily: "Manrope_500Medium",
|
||||||
fontSize: 13.2,
|
fontSize: 13.2,
|
||||||
color: "#fd1775",
|
color: "#fd1775",
|
||||||
},
|
},
|
||||||
dropdownStyle: {borderRadius: 6.61, height: 115.34, width: 187},
|
dropdownStyle: { borderRadius: 6.61, height: 115.34, width: 187 },
|
||||||
itemStyle: {padding: 0, margin: 0},
|
itemStyle: { padding: 0, margin: 0 },
|
||||||
});
|
});
|
||||||
|
|
||||||
export default EditGroceryItem;
|
export default EditGroceryItem;
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
import {Checkbox, Text, TouchableOpacity, View} from "react-native-ui-lib";
|
import { Checkbox, Text, TouchableOpacity, View } from "react-native-ui-lib";
|
||||||
import React, {useEffect, useState} from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import {AntDesign} from "@expo/vector-icons";
|
import { AntDesign } from "@expo/vector-icons";
|
||||||
import {GroceryCategory, useGroceryContext} from "@/contexts/GroceryContext";
|
import { GroceryCategory, useGroceryContext } from "@/contexts/GroceryContext";
|
||||||
import EditGroceryFrequency from "./EditGroceryFrequency";
|
import EditGroceryFrequency from "./EditGroceryFrequency";
|
||||||
import EditGroceryItem from "./EditGroceryItem";
|
import EditGroceryItem from "./EditGroceryItem";
|
||||||
import {ImageBackground, StyleSheet} from "react-native";
|
import { ImageBackground, StyleSheet } from "react-native";
|
||||||
import {IGrocery} from "@/hooks/firebase/types/groceryData";
|
import { IGrocery } from "@/hooks/firebase/types/groceryData";
|
||||||
import firestore from "@react-native-firebase/firestore";
|
import firestore from "@react-native-firebase/firestore";
|
||||||
import {UserProfile} from "@/hooks/firebase/types/profileTypes";
|
import { UserProfile } from "@/hooks/firebase/types/profileTypes";
|
||||||
import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
|
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||||
|
|
||||||
const GroceryItem = ({
|
const GroceryItem = ({
|
||||||
item,
|
item,
|
||||||
handleItemApproved,
|
handleItemApproved,
|
||||||
|
onInputFocus,
|
||||||
}: {
|
}: {
|
||||||
item: IGrocery;
|
item: IGrocery;
|
||||||
handleItemApproved: (id: string, changes: Partial<IGrocery>) => void;
|
handleItemApproved: (id: string, changes: Partial<IGrocery>) => void;
|
||||||
|
onInputFocus: (y: number) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { updateGroceryItem } = useGroceryContext();
|
const { updateGroceryItem } = useGroceryContext();
|
||||||
const { profileData } = useAuthContext();
|
const { profileData } = useAuthContext();
|
||||||
@ -24,12 +26,14 @@ const GroceryItem = ({
|
|||||||
const [openFreqEdit, setOpenFreqEdit] = useState<boolean>(false);
|
const [openFreqEdit, setOpenFreqEdit] = useState<boolean>(false);
|
||||||
const [isEditingTitle, setIsEditingTitle] = useState<boolean>(false);
|
const [isEditingTitle, setIsEditingTitle] = useState<boolean>(false);
|
||||||
const [newTitle, setNewTitle] = useState<string>(item.title ?? "");
|
const [newTitle, setNewTitle] = useState<string>(item.title ?? "");
|
||||||
const [category, setCategory] = useState<GroceryCategory>(item.category ?? GroceryCategory.None);
|
const [category, setCategory] = useState<GroceryCategory>(
|
||||||
|
item.category ?? GroceryCategory.None
|
||||||
|
);
|
||||||
const [itemCreator, setItemCreator] = useState<UserProfile>(null);
|
const [itemCreator, setItemCreator] = useState<UserProfile>(null);
|
||||||
|
|
||||||
const closeEdit = () => {
|
const closeEdit = () => {
|
||||||
setIsEditingTitle(false);
|
setIsEditingTitle(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleTitleChange = (newTitle: string) => {
|
const handleTitleChange = (newTitle: string) => {
|
||||||
updateGroceryItem({ id: item?.id, title: newTitle });
|
updateGroceryItem({ id: item?.id, title: newTitle });
|
||||||
@ -82,57 +86,70 @@ const GroceryItem = ({
|
|||||||
setOpenFreqEdit(false);
|
setOpenFreqEdit(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{isEditingTitle ?
|
{isEditingTitle ? (
|
||||||
<EditGroceryItem
|
<EditGroceryItem
|
||||||
editGrocery={{
|
editGrocery={{
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: newTitle,
|
title: newTitle,
|
||||||
category: category,
|
category: category,
|
||||||
setTitle: setNewTitle,
|
setTitle: setNewTitle,
|
||||||
setCategory: setCategory,
|
setCategory: setCategory,
|
||||||
closeEdit: closeEdit,
|
closeEdit: closeEdit,
|
||||||
handleEditSubmit: updateGroceryItem,
|
handleEditSubmit: updateGroceryItem,
|
||||||
}}
|
}}
|
||||||
/> :
|
onInputFocus={onInputFocus}
|
||||||
<View>
|
/>
|
||||||
{isParent ?
|
) : (
|
||||||
<TouchableOpacity onPress={() => setIsEditingTitle(true)}>
|
<View>
|
||||||
<Text text70T black style={styles.title}>
|
{isParent ? (
|
||||||
{item.title}
|
<TouchableOpacity onPress={() => setIsEditingTitle(true)}>
|
||||||
</Text>
|
|
||||||
</TouchableOpacity> :
|
|
||||||
<Text text70T black style={styles.title}>
|
<Text text70T black style={styles.title}>
|
||||||
{item.title}
|
{item.title}
|
||||||
</Text>
|
</Text>
|
||||||
}
|
</TouchableOpacity>
|
||||||
</View>
|
) : (
|
||||||
}
|
<Text text70T black style={styles.title}>
|
||||||
|
{item.title}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
{!item.approved ? (
|
{!item.approved ? (
|
||||||
<View row centerV marginB-10>
|
<View row centerV marginB-10>
|
||||||
{isParent &&
|
{isParent && (
|
||||||
<>
|
<>
|
||||||
<AntDesign
|
<AntDesign
|
||||||
name="check"
|
name="check"
|
||||||
size={24}
|
size={24}
|
||||||
style={{
|
style={{
|
||||||
color: "green",
|
color: "green",
|
||||||
marginRight: 15,
|
marginRight: 15,
|
||||||
}}
|
}}
|
||||||
onPress={isParent ? () => handleItemApproved(item.id, { approved: true }) : null}
|
onPress={
|
||||||
/>
|
isParent
|
||||||
<AntDesign
|
? () => handleItemApproved(item.id, { approved: true })
|
||||||
name="close"
|
: null
|
||||||
size={24}
|
}
|
||||||
style={{ color: "red" }}
|
/>
|
||||||
onPress={isParent ? () => handleItemApproved(item.id, { approved: false }) : null}
|
<AntDesign
|
||||||
/>
|
name="close"
|
||||||
</>}
|
size={24}
|
||||||
|
style={{ color: "red" }}
|
||||||
|
onPress={
|
||||||
|
isParent
|
||||||
|
? () => handleItemApproved(item.id, { approved: false })
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
!isEditingTitle && isParent && (
|
!isEditingTitle &&
|
||||||
|
isParent && (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
value={item.bought}
|
value={item.bought}
|
||||||
containerStyle={[styles.checkbox, {borderRadius: 50}]}
|
containerStyle={[styles.checkbox, { borderRadius: 50 }]}
|
||||||
style={styles.checked}
|
style={styles.checked}
|
||||||
borderRadius={50}
|
borderRadius={50}
|
||||||
color="#fd1575"
|
color="#fd1575"
|
||||||
@ -150,7 +167,8 @@ const GroceryItem = ({
|
|||||||
<View height={0.7} backgroundColor="#e7e7e7" width={"98%"} />
|
<View height={0.7} backgroundColor="#e7e7e7" width={"98%"} />
|
||||||
</View>
|
</View>
|
||||||
<View paddingL-0 paddingT-12 flexS row centerV>
|
<View paddingL-0 paddingT-12 flexS row centerV>
|
||||||
{profileData?.pfp ? <ImageBackground
|
{profileData?.pfp ? (
|
||||||
|
<ImageBackground
|
||||||
source={require("../../../assets/images/child-picture.png")}
|
source={require("../../../assets/images/child-picture.png")}
|
||||||
style={{
|
style={{
|
||||||
height: 24.64,
|
height: 24.64,
|
||||||
@ -158,16 +176,17 @@ const GroceryItem = ({
|
|||||||
borderRadius: 22,
|
borderRadius: 22,
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
/> :
|
/>
|
||||||
|
) : (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
position: "relative",
|
position: "relative",
|
||||||
width: 24.64,
|
width: 24.64,
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
marginRight: 4
|
marginRight: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#ccc",
|
backgroundColor: "#ccc",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
@ -176,18 +195,21 @@ const GroceryItem = ({
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
color: "#fff",
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: "bold",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{itemCreator ? getInitials(itemCreator.firstName, itemCreator.lastName) : ""}
|
<Text
|
||||||
</Text>
|
style={{
|
||||||
|
color: "#fff",
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: "bold",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{itemCreator
|
||||||
|
? getInitials(itemCreator.firstName, itemCreator.lastName)
|
||||||
|
: ""}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>}
|
)}
|
||||||
<Text color="#858585" style={styles.authorTxt}>
|
<Text color="#858585" style={styles.authorTxt}>
|
||||||
Requested by {itemCreator?.firstName}
|
Requested by {itemCreator?.firstName}
|
||||||
</Text>
|
</Text>
|
||||||
|
@ -10,7 +10,7 @@ import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
|
|||||||
import {IGrocery} from "@/hooks/firebase/types/groceryData";
|
import {IGrocery} from "@/hooks/firebase/types/groceryData";
|
||||||
import AddPersonIcon from "@/assets/svgs/AddPersonIcon";
|
import AddPersonIcon from "@/assets/svgs/AddPersonIcon";
|
||||||
|
|
||||||
const GroceryList = () => {
|
const GroceryList = ({onInputFocus}: {onInputFocus: (y: number) => void}) => {
|
||||||
const {
|
const {
|
||||||
groceries,
|
groceries,
|
||||||
updateGroceryItem,
|
updateGroceryItem,
|
||||||
@ -169,6 +169,7 @@ const GroceryList = () => {
|
|||||||
handleItemApproved={(id, changes) =>
|
handleItemApproved={(id, changes) =>
|
||||||
updateGroceryItem({...changes, id: id})
|
updateGroceryItem({...changes, id: id})
|
||||||
}
|
}
|
||||||
|
onInputFocus={onInputFocus}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
keyExtractor={(item) => item.id.toString()}
|
keyExtractor={(item) => item.id.toString()}
|
||||||
@ -230,6 +231,7 @@ const GroceryList = () => {
|
|||||||
setSubmit: setSubmitted,
|
setSubmit: setSubmitted,
|
||||||
closeEdit: () => setIsAddingGrocery(false)
|
closeEdit: () => setIsAddingGrocery(false)
|
||||||
}}
|
}}
|
||||||
|
onInputFocus={onInputFocus}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
@ -254,6 +256,7 @@ const GroceryList = () => {
|
|||||||
handleItemApproved={(id, changes) =>
|
handleItemApproved={(id, changes) =>
|
||||||
updateGroceryItem({...changes, id: id})
|
updateGroceryItem({...changes, id: id})
|
||||||
}
|
}
|
||||||
|
onInputFocus={onInputFocus}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
@ -1,42 +1,79 @@
|
|||||||
import { Dimensions, ScrollView } from "react-native";
|
import { Dimensions, ScrollView, Keyboard, Platform } from "react-native";
|
||||||
import { View } from "react-native-ui-lib";
|
import { View } from "react-native-ui-lib";
|
||||||
import React, { useEffect, useRef } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import AddGroceryItem from "./AddGroceryItem";
|
import AddGroceryItem from "./AddGroceryItem";
|
||||||
import GroceryList from "./GroceryList";
|
import GroceryList from "./GroceryList";
|
||||||
import { useGroceryContext } from "@/contexts/GroceryContext";
|
import { useGroceryContext } from "@/contexts/GroceryContext";
|
||||||
|
|
||||||
const GroceryWrapper = () => {
|
const GroceryWrapper = () => {
|
||||||
const { isAddingGrocery } = useGroceryContext();
|
const { isAddingGrocery } = useGroceryContext();
|
||||||
const scrollViewRef = useRef<ScrollView>(null); // Reference to the ScrollView
|
const scrollViewRef = useRef<ScrollView>(null);
|
||||||
|
const [keyboardHeight, setKeyboardHeight] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const keyboardWillShowListener = Keyboard.addListener(
|
||||||
|
Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow',
|
||||||
|
(e) => {
|
||||||
|
setKeyboardHeight(e.endCoordinates.height);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const keyboardWillHideListener = Keyboard.addListener(
|
||||||
|
Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide',
|
||||||
|
() => {
|
||||||
|
setKeyboardHeight(0);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
keyboardWillShowListener.remove();
|
||||||
|
keyboardWillHideListener.remove();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isAddingGrocery && scrollViewRef.current) {
|
if (isAddingGrocery && scrollViewRef.current) {
|
||||||
scrollViewRef.current.scrollTo({
|
scrollViewRef.current.scrollTo({
|
||||||
y: 400, // Adjust this value to scroll a bit down (100 is an example)
|
y: 400,
|
||||||
animated: true,
|
animated: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [isAddingGrocery]);
|
}, [isAddingGrocery]);
|
||||||
|
|
||||||
|
const handleInputFocus = (y: number) => {
|
||||||
|
if (scrollViewRef.current) {
|
||||||
|
// Get the window height
|
||||||
|
const windowHeight = Dimensions.get('window').height;
|
||||||
|
// Calculate the space we want to leave at the top
|
||||||
|
const topSpacing = 20;
|
||||||
|
|
||||||
|
// Calculate the target scroll position:
|
||||||
|
// y (position of input) - topSpacing (space we want at top)
|
||||||
|
// if keyboard is shown, we need to account for its height
|
||||||
|
const scrollPosition = Math.max(0, y - topSpacing);
|
||||||
|
|
||||||
|
scrollViewRef.current.scrollTo({
|
||||||
|
y: scrollPosition,
|
||||||
|
animated: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View height={Dimensions.get("window").height}>
|
<>
|
||||||
<View>
|
<ScrollView
|
||||||
<ScrollView
|
ref={scrollViewRef}
|
||||||
ref={scrollViewRef}
|
automaticallyAdjustKeyboardInsets={true}
|
||||||
automaticallyAdjustKeyboardInsets={true}
|
showsHorizontalScrollIndicator={false}
|
||||||
showsHorizontalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
showsVerticalScrollIndicator={false}
|
>
|
||||||
>
|
<View marginB-60>
|
||||||
<View height={"100%"}>
|
<GroceryList onInputFocus={handleInputFocus} />
|
||||||
<View marginB-115>
|
</View>
|
||||||
<GroceryList />
|
</ScrollView>
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
</View>
|
|
||||||
{!isAddingGrocery && <AddGroceryItem />}
|
{!isAddingGrocery && <AddGroceryItem />}
|
||||||
</View>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GroceryWrapper;
|
export default GroceryWrapper;
|
@ -1,38 +1,46 @@
|
|||||||
import { StyleSheet } from "react-native";
|
import { Dimensions, StyleSheet } from "react-native";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Button, ButtonSize, Text, View } from "react-native-ui-lib";
|
import { Button, ButtonSize, Text, View } from "react-native-ui-lib";
|
||||||
import { AntDesign } from "@expo/vector-icons";
|
import { AntDesign } from "@expo/vector-icons";
|
||||||
import LinearGradient from "react-native-linear-gradient";
|
import LinearGradient from "react-native-linear-gradient";
|
||||||
import AddChoreDialog from "./AddChoreDialog";
|
import AddChoreDialog from "./AddChoreDialog";
|
||||||
|
import PlusIcon from "@/assets/svgs/PlusIcon";
|
||||||
|
|
||||||
const AddChore = () => {
|
const AddChore = () => {
|
||||||
const [isVisible, setIsVisible] = useState<boolean>(false);
|
const [isVisible, setIsVisible] = useState<boolean>(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LinearGradient
|
<View
|
||||||
colors={["#f9f8f700", "#f9f8f7", "#f9f8f700"]}
|
row
|
||||||
locations={[0, 0.5, 1]}
|
spread
|
||||||
style={styles.gradient}
|
paddingH-20
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 15,
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<View style={styles.buttonContainer}>
|
<View style={styles.buttonContainer}>
|
||||||
<Button
|
<Button
|
||||||
marginH-25
|
marginH-20
|
||||||
size={ButtonSize.large}
|
size={ButtonSize.large}
|
||||||
style={styles.button}
|
style={styles.button}
|
||||||
onPress={() => setIsVisible(!isVisible)}
|
onPress={() => setIsVisible(!isVisible)}
|
||||||
>
|
>
|
||||||
<AntDesign name="plus" size={24} color="white" />
|
<PlusIcon />
|
||||||
<Text
|
<Text
|
||||||
white
|
white
|
||||||
style={{ fontFamily: "Manrope_600SemiBold", fontSize: 15 }}
|
style={{ fontFamily: "Manrope_600SemiBold", fontSize: 15 }}
|
||||||
marginL-10
|
marginL-5
|
||||||
>
|
>
|
||||||
Create new to do
|
Create new to do
|
||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
{isVisible && <AddChoreDialog isVisible={isVisible} setIsVisible={setIsVisible} />}
|
{isVisible && (
|
||||||
</LinearGradient>
|
<AddChoreDialog isVisible={isVisible} setIsVisible={setIsVisible} />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,8 +61,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
backgroundColor: "rgb(253, 23, 117)",
|
backgroundColor: "rgb(253, 23, 117)",
|
||||||
paddingVertical: 15,
|
height: 53.26,
|
||||||
paddingHorizontal: 30,
|
|
||||||
borderRadius: 30,
|
borderRadius: 30,
|
||||||
width: 335,
|
width: 335,
|
||||||
},
|
},
|
||||||
|
@ -17,8 +17,13 @@ import AddChoreDialog from "@/components/pages/todos/AddChoreDialog";
|
|||||||
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
|
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
|
||||||
import RepeatIcon from "@/assets/svgs/RepeatIcon";
|
import RepeatIcon from "@/assets/svgs/RepeatIcon";
|
||||||
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
|
||||||
const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
|
const ToDoItem = (props: {
|
||||||
|
item: IToDo;
|
||||||
|
isSettings?: boolean;
|
||||||
|
is7Days?: boolean;
|
||||||
|
}) => {
|
||||||
const { updateToDo } = useToDosContext();
|
const { updateToDo } = useToDosContext();
|
||||||
const { data: members } = useGetFamilyMembers();
|
const { data: members } = useGetFamilyMembers();
|
||||||
const { profileData } = useAuthContext();
|
const { profileData } = useAuthContext();
|
||||||
@ -55,6 +60,7 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
|
key={props.item.id}
|
||||||
centerV
|
centerV
|
||||||
paddingV-10
|
paddingV-10
|
||||||
paddingH-13
|
paddingH-13
|
||||||
@ -154,6 +160,9 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
|
|||||||
return props.item.repeatType;
|
return props.item.repeatType;
|
||||||
}
|
}
|
||||||
})()}
|
})()}
|
||||||
|
{props.item.date &&
|
||||||
|
props.is7Days &&
|
||||||
|
" / " + format(props.item.date, "EEEE")}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
@ -14,40 +14,64 @@ import { IToDo } from "@/hooks/firebase/types/todoData";
|
|||||||
|
|
||||||
const groupToDosByDate = (toDos: IToDo[]) => {
|
const groupToDosByDate = (toDos: IToDo[]) => {
|
||||||
let sortedTodos = toDos.sort((a, b) => a.date - b.date);
|
let sortedTodos = toDos.sort((a, b) => a.date - b.date);
|
||||||
return sortedTodos.reduce((groups, toDo) => {
|
return sortedTodos.reduce(
|
||||||
let dateKey;
|
(groups, toDo) => {
|
||||||
|
let dateKey;
|
||||||
|
let subDateKey;
|
||||||
|
|
||||||
const isNext7Days = (date: Date) => {
|
const isNext7Days = (date: Date) => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
return isWithinInterval(date, { start: today, end: addDays(today, 7) });
|
return isWithinInterval(date, { start: today, end: addDays(today, 7) });
|
||||||
};
|
};
|
||||||
|
|
||||||
const isNext30Days = (date: Date) => {
|
const isNext30Days = (date: Date) => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
return isWithinInterval(date, { start: today, end: addDays(today, 30) });
|
return isWithinInterval(date, {
|
||||||
};
|
start: today,
|
||||||
|
end: addDays(today, 30),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (toDo.date === null) {
|
if (toDo.date === null) {
|
||||||
dateKey = "No Date";
|
dateKey = "No Date";
|
||||||
} else if (isToday(toDo.date)) {
|
} else if (isToday(toDo.date)) {
|
||||||
dateKey = "Today";
|
dateKey = "Today";
|
||||||
} else if (isTomorrow(toDo.date)) {
|
} else if (isTomorrow(toDo.date)) {
|
||||||
dateKey = "Tomorrow";
|
dateKey = "Tomorrow";
|
||||||
} else if (isNext7Days(toDo.date)) {
|
} else if (isNext7Days(toDo.date)) {
|
||||||
dateKey = "Next 7 Days";
|
dateKey = "Next 7 Days";
|
||||||
} else if (isNext30Days(toDo.date)) {
|
} else if (isNext30Days(toDo.date)) {
|
||||||
dateKey = "Next 30 Days";
|
dateKey = "Next 30 Days";
|
||||||
} else {
|
subDateKey = format(toDo.date, "MMM d");
|
||||||
dateKey = format(toDo.date, "EEE MMM dd");
|
} else {
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!groups[dateKey]) {
|
||||||
|
groups[dateKey] = {
|
||||||
|
items: [],
|
||||||
|
subgroups: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dateKey === "Next 30 Days" && subDateKey) {
|
||||||
|
if (!groups[dateKey].subgroups[subDateKey]) {
|
||||||
|
groups[dateKey].subgroups[subDateKey] = [];
|
||||||
|
}
|
||||||
|
groups[dateKey].subgroups[subDateKey].push(toDo);
|
||||||
|
} else {
|
||||||
|
groups[dateKey].items.push(toDo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
},
|
||||||
|
{} as {
|
||||||
|
[key: string]: {
|
||||||
|
items: IToDo[];
|
||||||
|
subgroups: { [key: string]: IToDo[] };
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
);
|
||||||
if (!groups[dateKey]) {
|
|
||||||
groups[dateKey] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
groups[dateKey].push(toDo);
|
|
||||||
return groups;
|
|
||||||
}, {} as { [key: string]: IToDo[] });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
|
const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
|
||||||
@ -67,11 +91,139 @@ const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const noDateToDos = groupedToDos["No Date"] || [];
|
const noDateToDos = groupedToDos["No Date"]?.items || [];
|
||||||
const datedToDos = Object.keys(groupedToDos).filter(
|
const datedToDos = Object.keys(groupedToDos).filter(
|
||||||
(key) => key !== "No Date"
|
(key) => key !== "No Date"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const renderTodoGroup = (dateKey: string) => {
|
||||||
|
const isExpanded = expandedGroups[dateKey] || false;
|
||||||
|
|
||||||
|
if (dateKey === "Next 30 Days") {
|
||||||
|
const subgroups = Object.entries(groupedToDos[dateKey].subgroups).sort(
|
||||||
|
([dateA], [dateB]) => {
|
||||||
|
const dateAObj = new Date(dateA);
|
||||||
|
const dateBObj = new Date(dateB);
|
||||||
|
return dateAObj.getTime() - dateBObj.getTime();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View key={dateKey}>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => toggleExpand(dateKey)}
|
||||||
|
style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
paddingHorizontal: 0,
|
||||||
|
marginBottom: 4,
|
||||||
|
marginTop: 15,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontFamily: "Manrope_700Bold",
|
||||||
|
fontSize: 15,
|
||||||
|
color: "#484848",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dateKey}
|
||||||
|
</Text>
|
||||||
|
<AntDesign
|
||||||
|
name={isExpanded ? "caretdown" : "caretright"}
|
||||||
|
size={24}
|
||||||
|
color="#fd1575"
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
{isExpanded &&
|
||||||
|
subgroups.map(([subDate, items]) => {
|
||||||
|
const sortedItems = [
|
||||||
|
...items.filter((toDo) => !toDo.done),
|
||||||
|
...items.filter((toDo) => toDo.done),
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View key={subDate} marginT-15>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
marginBottom: 8,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontFamily: "Manrope_600SemiBold",
|
||||||
|
fontSize: 14,
|
||||||
|
color: "#919191",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{subDate}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{sortedItems.map((item) => (
|
||||||
|
<ToDoItem
|
||||||
|
isSettings={isSettings}
|
||||||
|
key={item.id}
|
||||||
|
item={item}
|
||||||
|
is7Days={false}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedToDos = [
|
||||||
|
...groupedToDos[dateKey].items.filter((toDo) => !toDo.done),
|
||||||
|
...groupedToDos[dateKey].items.filter((toDo) => toDo.done),
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View key={dateKey}>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => toggleExpand(dateKey)}
|
||||||
|
style={{
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
paddingHorizontal: 0,
|
||||||
|
marginBottom: 4,
|
||||||
|
marginTop: 15,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontFamily: "Manrope_700Bold",
|
||||||
|
fontSize: 15,
|
||||||
|
color: "#484848",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dateKey}
|
||||||
|
</Text>
|
||||||
|
<AntDesign
|
||||||
|
name={isExpanded ? "caretdown" : "caretright"}
|
||||||
|
size={24}
|
||||||
|
color="#fd1575"
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
{isExpanded &&
|
||||||
|
sortedToDos.map((item) => (
|
||||||
|
<ToDoItem
|
||||||
|
isSettings={isSettings}
|
||||||
|
key={item.id}
|
||||||
|
item={item}
|
||||||
|
is7Days={dateKey === "Next 7 Days"}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View marginB-402>
|
<View marginB-402>
|
||||||
{noDateToDos.length > 0 && (
|
{noDateToDos.length > 0 && (
|
||||||
@ -85,26 +237,14 @@ const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
|
|||||||
>
|
>
|
||||||
Unscheduled
|
Unscheduled
|
||||||
</Text>
|
</Text>
|
||||||
{!expandNoDate && (
|
<AntDesign
|
||||||
<AntDesign
|
name={expandNoDate ? "caretdown" : "caretright"}
|
||||||
name="caretright"
|
size={24}
|
||||||
size={24}
|
color="#fd1575"
|
||||||
color="#fd1575"
|
onPress={() => {
|
||||||
onPress={() => {
|
setExpandNoDate(!expandNoDate);
|
||||||
setExpandNoDate(!expandNoDate);
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{expandNoDate && (
|
|
||||||
<AntDesign
|
|
||||||
name="caretdown"
|
|
||||||
size={24}
|
|
||||||
color="#fd1575"
|
|
||||||
onPress={() => {
|
|
||||||
setExpandNoDate(!expandNoDate);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
{expandNoDate &&
|
{expandNoDate &&
|
||||||
noDateToDos
|
noDateToDos
|
||||||
@ -115,50 +255,7 @@ const ToDosList = ({ isSettings }: { isSettings?: boolean }) => {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{datedToDos.map((dateKey) => {
|
{datedToDos.map(renderTodoGroup)}
|
||||||
const isExpanded = expandedGroups[dateKey] || false;
|
|
||||||
const sortedToDos = [
|
|
||||||
...groupedToDos[dateKey].filter((toDo) => !toDo.done),
|
|
||||||
...groupedToDos[dateKey].filter((toDo) => toDo.done),
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View key={dateKey}>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => toggleExpand(dateKey)}
|
|
||||||
style={{
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center",
|
|
||||||
paddingHorizontal: 0,
|
|
||||||
marginBottom: 4,
|
|
||||||
marginTop: 15,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
fontFamily: "Manrope_700Bold",
|
|
||||||
fontSize: 15,
|
|
||||||
color: "#484848",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{dateKey}
|
|
||||||
</Text>
|
|
||||||
{!isExpanded && (
|
|
||||||
<AntDesign name="caretright" size={24} color="#fd1575" />
|
|
||||||
)}
|
|
||||||
{isExpanded && (
|
|
||||||
<AntDesign name="caretdown" size={24} color="#fd1575" />
|
|
||||||
)}
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
{isExpanded &&
|
|
||||||
sortedToDos.map((item) => (
|
|
||||||
<ToDoItem isSettings={isSettings} key={item.id} item={item} />
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -32,7 +32,6 @@ const ToDosPage = () => {
|
|||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
paddingH-25
|
paddingH-25
|
||||||
backgroundColor="#f9f8f7"
|
|
||||||
height={"100%"}
|
height={"100%"}
|
||||||
width={width}
|
width={width}
|
||||||
>
|
>
|
||||||
|
Reference in New Issue
Block a user