From fd6f080e7c1c09dc2852f593287fe30cc715654c Mon Sep 17 00:00:00 2001 From: ivic00 <102467664+ivic00@users.noreply.github.com> Date: Tue, 22 Oct 2024 19:34:59 +0200 Subject: [PATCH] add todo repeat freq --- assets/svgs/CalendarIcon.tsx | 1 + assets/svgs/ClockOIcon.tsx | 20 ++ assets/svgs/DropdownIcon.tsx | 20 ++ components/pages/grocery/EditGroceryItem.tsx | 195 +++++++++++++------ components/pages/grocery/GroceryItem.tsx | 57 +++--- components/pages/grocery/GroceryList.tsx | 2 +- components/pages/todos/AddChore.tsx | 95 ++++----- components/pages/todos/AddChoreDialog.tsx | 128 +++++++----- components/pages/todos/RepeatFreq.tsx | 83 ++++++++ components/pages/todos/ToDosList.tsx | 32 ++- hooks/firebase/types/todoData.ts | 24 +-- package.json | 1 + yarn.lock | 7 + 13 files changed, 466 insertions(+), 199 deletions(-) create mode 100644 assets/svgs/ClockOIcon.tsx create mode 100644 assets/svgs/DropdownIcon.tsx create mode 100644 components/pages/todos/RepeatFreq.tsx diff --git a/assets/svgs/CalendarIcon.tsx b/assets/svgs/CalendarIcon.tsx index a688729..89ec32d 100644 --- a/assets/svgs/CalendarIcon.tsx +++ b/assets/svgs/CalendarIcon.tsx @@ -4,6 +4,7 @@ const CalendarIcon: React.FC = (props) => ( diff --git a/assets/svgs/ClockOIcon.tsx b/assets/svgs/ClockOIcon.tsx new file mode 100644 index 0000000..1ebe908 --- /dev/null +++ b/assets/svgs/ClockOIcon.tsx @@ -0,0 +1,20 @@ +import * as React from "react" +import Svg, { SvgProps, Path } from "react-native-svg" +const ClockOIcon = (props: SvgProps) => ( + + + +) +export default ClockOIcon diff --git a/assets/svgs/DropdownIcon.tsx b/assets/svgs/DropdownIcon.tsx new file mode 100644 index 0000000..930c5b4 --- /dev/null +++ b/assets/svgs/DropdownIcon.tsx @@ -0,0 +1,20 @@ +import * as React from "react"; +import Svg, { SvgProps, Path } from "react-native-svg"; +const DropdownIcon = (props: SvgProps) => ( + + + +); +export default DropdownIcon; diff --git a/components/pages/grocery/EditGroceryItem.tsx b/components/pages/grocery/EditGroceryItem.tsx index 73d994c..3806a66 100644 --- a/components/pages/grocery/EditGroceryItem.tsx +++ b/components/pages/grocery/EditGroceryItem.tsx @@ -1,74 +1,141 @@ -import {Text, View} from "react-native"; -import React, {useEffect, useRef, useState} from "react"; -import {TextField, TextFieldRef} from "react-native-ui-lib"; -import {GroceryCategory, useGroceryContext,} from "@/contexts/GroceryContext"; -import CategoryDropdown from "./CategoryDropdown"; +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 CloseXIcon from "@/assets/svgs/CloseXIcon"; +import { StyleSheet } from "react-native"; +import DropdownIcon from "@/assets/svgs/DropdownIcon"; interface IEditGrocery { - id?: string; - title: string; - category: GroceryCategory; - setTitle: (value: string) => void; - setCategory?: (category: GroceryCategory) => void; - setSubmit?: (value: boolean) => void; - closeEdit?: (value: boolean) => void; - handleEditSubmit?: Function + id?: string; + title: string; + category: GroceryCategory; + setTitle: (value: string) => void; + setCategory?: (category: GroceryCategory) => void; + setSubmit?: (value: boolean) => void; + closeEdit?: (value: boolean) => void; + handleEditSubmit?: Function; } -const EditGroceryItem = ({editGrocery}: { editGrocery: IEditGrocery }) => { - const {fuzzyMatchGroceryCategory} = useGroceryContext(); - const inputRef = useRef(null); - const [category, setCategory] = useState(GroceryCategory.None); +const EditGroceryItem = ({ editGrocery }: { editGrocery: IEditGrocery }) => { + const { fuzzyMatchGroceryCategory } = useGroceryContext(); + const inputRef = useRef(null); - useEffect(() => { - if (editGrocery.setCategory) - editGrocery.setCategory(fuzzyMatchGroceryCategory(editGrocery.title)); - }, [editGrocery.title]); + const groceryCategoryOptions = Object.values(GroceryCategory).map( + (category) => ({ + label: category, + value: category, + }) + ); - useEffect(() => { - if (inputRef.current) { - inputRef.current.focus(); // Focus on the TextField + useEffect(() => { + if (inputRef.current) { + inputRef.current.focus(); // Focus on the TextField + } + console.log(editGrocery.category); + }, []); + + return ( + + + { + editGrocery.setTitle(value); + }} + onSubmitEditing={() => { + 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(false); + } + }} + maxLength={25} + /> + { + if (editGrocery.closeEdit) editGrocery.closeEdit(false); + }} + /> + + - { - editGrocery.setTitle(value); - }} - onSubmitEditing={() => { - if (editGrocery.setSubmit) { - editGrocery.setSubmit(true); - } - if (editGrocery.setCategory) { - editGrocery.setCategory(fuzzyMatchGroceryCategory(editGrocery.title)); - } - if (editGrocery.handleEditSubmit) { - editGrocery.handleEditSubmit({id: editGrocery.id, title: editGrocery.title, category: editGrocery.category}); - } - if (editGrocery.closeEdit) { - editGrocery.closeEdit(false); - } - }} - maxLength={25} - /> - {editGrocery.category} - - ); + iconColor="white" + activeColor={"#fd1775"} + containerStyle={styles.dropdownStyle} + itemTextStyle={styles.itemText} + itemContainerStyle={styles.itemStyle} + selectedTextStyle={styles.selectedText} + renderLeftIcon={() => ( + + )} + renderItem={(item) => { + return ( + + {item.label} + + ); + }} + onChange={(item) => { + if (editGrocery.handleEditSubmit) { + editGrocery.handleEditSubmit({ + id: editGrocery.id, + category: item.value, + }); + console.log("kategorija vo diropdown: " + item.value); + if (editGrocery.closeEdit) editGrocery.closeEdit(false); + } + }} + /> + + ); }; +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 }, +}); + export default EditGroceryItem; diff --git a/components/pages/grocery/GroceryItem.tsx b/components/pages/grocery/GroceryItem.tsx index 864f75e..b275d3c 100644 --- a/components/pages/grocery/GroceryItem.tsx +++ b/components/pages/grocery/GroceryItem.tsx @@ -36,7 +36,7 @@ const GroceryItem = ({ useEffect(() => { setNewTitle(item.title); - + console.log(item); getItemCreator(item?.creatorId); }, []); @@ -56,11 +56,14 @@ const GroceryItem = ({ return ( ) : ( )} {!item.approved ? ( @@ -115,14 +118,19 @@ const GroceryItem = ({ /> ) : ( - - updateGroceryItem({ id: item.id, bought: !item.bought }) - } - /> + !isEditingTitle && ( + + updateGroceryItem({ id: item.id, bought: !item.bought }) + } + /> + ) )} {!item.approved && ( @@ -138,9 +146,9 @@ const GroceryItem = ({ borderRadius: 50, backgroundColor: "red", marginRight: 10, - overflow: 'hidden' + overflow: "hidden", }} - source={require('../../../assets/images/child-picture.png')} + source={require("../../../assets/images/child-picture.png")} /> Requested by {itemCreator?.firstName} @@ -166,6 +174,9 @@ const styles = StyleSheet.create({ fontFamily: "Manrope_500Medium", fontSize: 15, }, + checked: { + borderRadius: 50, + }, }); export default GroceryItem; diff --git a/components/pages/grocery/GroceryList.tsx b/components/pages/grocery/GroceryList.tsx index e6fc88c..5add444 100644 --- a/components/pages/grocery/GroceryList.tsx +++ b/components/pages/grocery/GroceryList.tsx @@ -30,7 +30,7 @@ const GroceryList = () => { groceries?.filter((item) => item.approved !== true) ); const [category, setCategory] = useState( - GroceryCategory.Bakery + GroceryCategory.None ); const [title, setTitle] = useState(""); const [submit, setSubmitted] = useState(false); diff --git a/components/pages/todos/AddChore.tsx b/components/pages/todos/AddChore.tsx index 340de47..955e11c 100644 --- a/components/pages/todos/AddChore.tsx +++ b/components/pages/todos/AddChore.tsx @@ -1,56 +1,61 @@ -import {StyleSheet} from "react-native"; -import React, {useState} from "react"; -import {Button, ButtonSize, Text, View} from "react-native-ui-lib"; -import {AntDesign} from "@expo/vector-icons"; +import { StyleSheet } from "react-native"; +import React, { useState } from "react"; +import { Button, ButtonSize, Text, View } from "react-native-ui-lib"; +import { AntDesign } from "@expo/vector-icons"; import LinearGradient from "react-native-linear-gradient"; import AddChoreDialog from "./AddChoreDialog"; const AddChore = () => { - const [isVisible, setIsVisible] = useState(false); + const [isVisible, setIsVisible] = useState(false); - return ( - + + - ); + + + Create new to do + + + + + + ); }; export default AddChore; const styles = StyleSheet.create({ - gradient: { - height: 150, - position: "absolute", - bottom: 0, - width: "100%", - justifyContent: "center", - alignItems: "center", - }, - buttonContainer: { - width: "100%", - alignItems: "center", - }, - button: { - backgroundColor: "rgb(253, 23, 117)", - paddingVertical: 15, - paddingHorizontal: 30, - borderRadius: 30, - }, -}); \ No newline at end of file + gradient: { + height: 150, + position: "absolute", + bottom: 0, + width: "100%", + justifyContent: "center", + alignItems: "center", + }, + buttonContainer: { + width: "100%", + alignItems: "center", + }, + button: { + backgroundColor: "rgb(253, 23, 117)", + paddingVertical: 15, + paddingHorizontal: 30, + borderRadius: 30, + width: 335, + }, +}); diff --git a/components/pages/todos/AddChoreDialog.tsx b/components/pages/todos/AddChoreDialog.tsx index 8a0782e..d93b20f 100644 --- a/components/pages/todos/AddChoreDialog.tsx +++ b/components/pages/todos/AddChoreDialog.tsx @@ -1,4 +1,4 @@ -import {View, Text, Button, Switch, PickerModes} from "react-native-ui-lib"; +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"; @@ -15,7 +15,12 @@ import { Dimensions, StyleSheet } from "react-native"; import DropModalIcon from "@/assets/svgs/DropModalIcon"; 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; @@ -30,7 +35,7 @@ const defaultTodo = { date: new Date(), rotate: false, repeatType: "Every week", - assignees: [] + assignees: [], }; const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { @@ -38,11 +43,13 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { const [todo, setTodo] = useState( addChoreDialogProps.selectedTodo ?? defaultTodo ); - const [selectedAssignees, setSelectedAssignees] = useState(addChoreDialogProps?.selectedTodo?.assignees ?? []); + const [selectedAssignees, setSelectedAssignees] = useState( + addChoreDialogProps?.selectedTodo?.assignees ?? [] + ); const { width, height } = Dimensions.get("screen"); const [points, setPoints] = useState(todo.points); - const {data: members} = useGetFamilyMembers(); + const { data: members } = useGetFamilyMembers(); const handleClose = () => { setTodo(defaultTodo); @@ -100,13 +107,17 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { onPress={() => { try { if (addChoreDialogProps.selectedTodo) { - updateToDo({ ...todo, points: points, assignees: selectedAssignees }); + updateToDo({ + ...todo, + points: points, + assignees: selectedAssignees, + }); } else { addToDo({ ...todo, done: false, points: points, - assignees: selectedAssignees + assignees: selectedAssignees, }); } handleClose(); @@ -133,11 +144,15 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { {todo?.date && ( - + { setTodo((oldValue: IToDo) => ({ ...oldValue, date: date })); }} @@ -146,9 +161,9 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { )} - + { @@ -169,7 +184,11 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { } }} topBarProps={{ title: "Repeat" }} - style={{ marginVertical: 5 }} + style={{ + marginVertical: 5, + fontFamily: "PlusJakartaSans_500Medium", + fontSize: 16, + }} > {repeatOptions.map((option) => ( { ))} + {todo.repeatType == "Every week" && } - - + + Assignees - + { - setSelectedAssignees([...selectedAssignees, ...value]); - }} - style={{ marginVertical: 5 }} - mode={PickerModes.MULTI} - renderInput={() => - - + - Take Turns + + Take Turns + setTodo((oldValue) => ({ ...oldValue, rotate: value })) @@ -243,7 +269,7 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => { - + Reward Points @@ -284,4 +310,8 @@ const styles = StyleSheet.create({ marginBottom: 10, marginTop: 25, }, + sub: { + fontFamily: "Manrope_600SemiBold", + fontSize: 18, + }, }); diff --git a/components/pages/todos/RepeatFreq.tsx b/components/pages/todos/RepeatFreq.tsx new file mode 100644 index 0000000..1e02b3b --- /dev/null +++ b/components/pages/todos/RepeatFreq.tsx @@ -0,0 +1,83 @@ +import { View, Text, TouchableOpacity, Picker } from "react-native-ui-lib"; +import React, { useEffect, useState } from "react"; + +const RepeatFreq = () => { + const [weeks, setWeeks] = useState(1); + const weekOptions: number[] = Array.from({ length: 52 }, (_, i) => i + 1); + + useEffect(() => { + }, [weeks]); + + return ( + + + + + + + + + + + + + {weeks == 1 ? "Week" : "Weeks"} + + } + value={weeks} + onChange={(value) => { + if (typeof value === "number") { + setWeeks(value); + } + }} + placeholder={"Select number of weeks"} + useWheelPicker + color={"#fd1575"} + style={{ + maxWidth: 18, + fontFamily: "Manrope_700Bold", + }} + containerStyle={{ + borderWidth: 1, + borderRadius: 6, + paddingRight: 5, + paddingLeft: 3, + borderColor: "#fd1575", + backgroundColor: "#ffe8f1", + }} + > + {weekOptions.map((num) => ( + + ))} + + + + ); +}; + +export default RepeatFreq; + +const RepeatOption = ({ value }: { value: string }) => { + const [isSet, setisSet] = useState(false); + return ( + setisSet(!isSet)}> + + {value.at(0)} + + + ); +}; diff --git a/components/pages/todos/ToDosList.tsx b/components/pages/todos/ToDosList.tsx index 2f2775a..6589427 100644 --- a/components/pages/todos/ToDosList.tsx +++ b/components/pages/todos/ToDosList.tsx @@ -2,7 +2,13 @@ import { View, Text, TouchableOpacity, Icon } from "react-native-ui-lib"; import React, { useState } from "react"; import { useToDosContext } from "@/contexts/ToDosContext"; import ToDoItem from "./ToDoItem"; -import { format, isToday, isTomorrow } from "date-fns"; +import { + addDays, + format, + isToday, + isTomorrow, + isWithinInterval, +} from "date-fns"; import { AntDesign } from "@expo/vector-icons"; import { IToDo } from "@/hooks/firebase/types/todoData"; @@ -11,12 +17,26 @@ const groupToDosByDate = (toDos: IToDo[]) => { return sortedTodos.reduce((groups, toDo) => { let dateKey; + const isNext7Days = (date: Date) => { + const today = new Date(); + return isWithinInterval(date, { start: today, end: addDays(today, 7) }); + }; + + const isNext30Days = (date: Date) => { + const today = new Date(); + return isWithinInterval(date, { start: today, end: addDays(today, 30) }); + }; + if (toDo.date === null) { dateKey = "No Date"; } else if (isToday(toDo.date)) { - dateKey = "Today • " + format(toDo.date, "EEE MMM dd"); + dateKey = "Today"; } else if (isTomorrow(toDo.date)) { - dateKey = "Tomorrow • " + format(toDo.date, "EEE MMM dd"); + dateKey = "Tomorrow"; + } else if (isNext7Days(toDo.date)) { + dateKey = "Next 7 Days"; + } else if (isNext30Days(toDo.date)) { + dateKey = "Next 30 Days"; } else { dateKey = format(toDo.date, "EEE MMM dd"); } @@ -110,12 +130,12 @@ const ToDosList = ({ isSettings }: { isSettings?: boolean }) => { flexDirection: "row", justifyContent: "space-between", alignItems: "center", - paddingHorizontal: 20, - marginVertical: 8, + paddingHorizontal: 0, + marginBottom: 4, + marginTop: 15, }} >