diff --git a/app/(tabs)/inboxView.jsx b/app/(tabs)/inboxView.jsx index f69f652..1877007 100644 --- a/app/(tabs)/inboxView.jsx +++ b/app/(tabs)/inboxView.jsx @@ -1,33 +1,71 @@ -import CategoryScroll from '@/components/CategoryScroll'; +import CategoryMainItem from '@/components/categoryView/CategoryMainItem'; +import LoadingSpinner from '@/components/common/molecules/LoadingSpinner'; // import InboxTodos from '@/components/InboxTodos'; import InboxTodos from '@/components/inboxView/inboxTodos/InboxTodos'; +import CalendarBottomSheet from '@/components/todayView/dailyTodos/calendarBottomSheet/CalendarBottomSheet'; +import CalendarBottomSheetProvider from '@/contexts/CalendarBottomSheetProvider'; import CategoryProvider from '@/contexts/CategoryContext'; import DateProvider from '@/contexts/DateContext'; import { LoginContext } from '@/contexts/LoginContext'; +import useTodoStore from '@/contexts/TodoStore'; +import useCategoriesQuery from '@/hooks/api/useCategoriesQuery'; +import useInboxTodoQuery from '@/hooks/api/useInboxTodoQuery'; import { handleLogEvent, INBOXVIEW_VIEW_EVENT } from '@/utils/logEvent'; -import React, { useContext } from 'react'; -import { SafeAreaView, StatusBar, StyleSheet, View } from 'react-native'; +import { widthPercentage } from '@/utils/responsiveSize'; +import { StatusBar } from 'expo-status-bar'; +import React, { Suspense, useContext } from 'react'; +import { useTranslation } from 'react-i18next'; +import { FlatList, SafeAreaView, StyleSheet, View } from 'react-native'; const InboxView = () => { + const { i18n } = useTranslation(); const { userId } = useContext(LoginContext); + const getLoadingText = () => { + if (i18n.language === 'ko') { + return `투두`; + } else if (i18n.language === 'en') { + return `Todo`; + } + }; handleLogEvent(INBOXVIEW_VIEW_EVENT, { time: new Date().toISOString(), userId: userId, }); + const renderCategoriesTodo = ({ item }) => { + return ( + + + + + ); + }; + + const { data: categoriesData } = useCategoriesQuery(userId); + const { data: todosData } = useInboxTodoQuery(userId); + const { selectedTodo } = useTodoStore(); + return ( - - - - - - - + + + + + + + } + > + + + + + ); @@ -38,6 +76,10 @@ export default InboxView; const styles = StyleSheet.create({ container: { flex: 1, + backgroundColor: 'white', + }, + bottomContainer: { + paddingHorizontal: widthPercentage(20), }, content: { flex: 1, diff --git a/components/inboxView/inboxTodos/InboxTodos.jsx b/components/inboxView/inboxTodos/InboxTodos.jsx deleted file mode 100644 index 0c50832..0000000 --- a/components/inboxView/inboxTodos/InboxTodos.jsx +++ /dev/null @@ -1,112 +0,0 @@ -import { CategoryContext } from '@/contexts/CategoryContext'; -import { LoginContext } from '@/contexts/LoginContext'; -import useTodoStore from '@/contexts/TodoStore'; -import useInboxTodoQuery from '@/hooks/api/useInboxTodoQuery'; -import { useTodoAddMutation } from '@/hooks/api/useTodoMutations'; -import '@/locales/index'; -import { - DEFAULT_SCROLL_EVENT_THROTTLE, - handleScroll, -} from '@/utils/handleScroll'; -import { TODAYVIEW_SCROLL_EVENT } from '@/utils/logEvent'; -import { LexoRank } from 'lexorank'; -import { Fragment, useContext, useEffect } from 'react'; -import { KeyboardAvoidingView, Text } from 'react-native'; -import DraggableFlatList, { - ScaleDecorator, -} from 'react-native-draggable-flatlist'; -import { GestureHandlerRootView } from 'react-native-gesture-handler'; -import InboxTodo from './inboxTodo/InboxTodo'; - -const InboxTodos = () => { - const { userId } = useContext(LoginContext); - const { selectedCategory } = useContext(CategoryContext); - const { - isLoading, - error, - data: inboxTodoData, - isSuccess: isInboxTodoQuerySuccess, - } = useInboxTodoQuery(userId); - const setInboxTodos = useTodoStore(state => state.setInboxTodos); - const inboxCurrentTodos = useTodoStore(state => state.inboxCurrentTodos); - const setInboxCurrentTodos = useTodoStore( - state => state.setInboxCurrentTodos, - ); - const { mutate: updateTodo } = useTodoAddMutation(); - - const renderTodo = ({ item, drag, isActive }) => { - return ( - - - - ); - }; - - const handleDragEnd = async ({ data }) => { - const updatedData = data.map(item => { - return { - todoId: item.id, - order: LexoRank.parse(item.order).toString(), - }; - }); - updateTodo(updatedData); - }; - //TODO: order 순서 생각해보니까 이제 서버에서 하잖아? 일단 전체 투두에서 계속 마지막으로 붙이는 식으로 구현 - // const handleSubmit = async () => { - // const newTodoData = { - // content: input, - // categoryId: selectedCategory, - // }; - - // addInboxTodo({ todoData: newTodoData }); - // setInput(''); - // }; - - useEffect(() => { - if (isInboxTodoQuerySuccess) { - setInboxTodos(inboxTodoData); - let filteredTodos = inboxTodoData.filter( - todo => todo.categoryId === selectedCategory, - ); - setInboxCurrentTodos(filteredTodos); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isInboxTodoQuerySuccess, inboxTodoData, selectedCategory]); - - if (isLoading) return Loading...; - if (error) return Error: {error.message}; - - return ( - - - - item.id.toString()} - onScroll={() => handleScroll(TODAYVIEW_SCROLL_EVENT, userId)} - scrollEventThrottle={DEFAULT_SCROLL_EVENT_THROTTLE} - /> - - {/* - {isTextInputOpen && ( - - - - )} - */} - - - ); -}; - -export default InboxTodos; diff --git a/components/inboxView/inboxTodos/InboxTodos.tsx b/components/inboxView/inboxTodos/InboxTodos.tsx new file mode 100644 index 0000000..86c543f --- /dev/null +++ b/components/inboxView/inboxTodos/InboxTodos.tsx @@ -0,0 +1,150 @@ +import CalendarBottomSheetProvider from '@/contexts/CalendarBottomSheetProvider'; +import { CategoryContext } from '@/contexts/CategoryContext'; +import { LoginContext } from '@/contexts/LoginContext'; +import { TextInputContext } from '@/contexts/textInputContext'; +import { + useTodoAddMutation, + useTodoUpdateMutation, +} from '@/hooks/api/useTodoMutations'; +import useFilteredInboxTodos from '@/hooks/todo/useFilteredInboxTodo'; +import '@/locales/index'; +import colors from '@/theme/theme.json'; +import { + DEFAULT_SCROLL_EVENT_THROTTLE, + handleScroll, +} from '@/utils/handleScroll'; +import { INBOXVIEW_SCROLL_EVENT } from '@/utils/logEvent'; +import { heightPercentage, widthPercentage } from '@/utils/responsiveSize'; +import { Icon } from '@ui-kitten/components'; +import { LexoRank } from 'lexorank'; +import React, { Fragment, useContext, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { + KeyboardAvoidingView, + StyleSheet, + TextInput, + View, +} from 'react-native'; +import DraggableFlatList, { + ScaleDecorator, +} from 'react-native-draggable-flatlist'; +import { GestureHandlerRootView } from 'react-native-gesture-handler'; +import { KeyboardAccessoryView } from 'react-native-keyboard-accessory'; +import InboxTodo from './inboxTodo/InboxTodo'; + +interface InboxTodosProps { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + todosData: any; + categoryId: number; +} + +const InboxTodos: React.FC = ({ todosData, categoryId }) => { + const { t } = useTranslation(); + const { userId } = useContext(LoginContext); + const { selectedCategory, setSelectedCategory } = useContext(CategoryContext); + setSelectedCategory(categoryId); + const inboxCurrentTodos = useFilteredInboxTodos(todosData, categoryId); + const { mutate: addInboxTodo } = useTodoAddMutation(); + const { mutate: updateInboxTodo } = useTodoUpdateMutation(); + const { isTextInputOpen, activatedCategoryId } = useContext(TextInputContext); + const [input, setInput] = useState(''); + + const renderTodo = ({ item, drag, isActive }) => { + return ( + + + + ); + }; + + const handleDragEnd = async ({ data }) => { + const updatedData = data.map(item => { + return { + todoId: item.id, + order: LexoRank.parse(item.order).toString(), + }; + }); + updateInboxTodo(updatedData); + }; + //TODO: order 순서 생각해보니까 이제 서버에서 하잖아? 일단 전체 투두에서 계속 마지막으로 붙이는 식으로 구현 + const handleInputSubmit = async () => { + const newTodoData = { + content: input, + categoryId: selectedCategory, + }; + + addInboxTodo({ todoData: newTodoData }); + setInput(''); + }; + + return ( + + + + + item.id.toString()} + onScroll={() => handleScroll(INBOXVIEW_SCROLL_EVENT, userId)} + scrollEventThrottle={DEFAULT_SCROLL_EVENT_THROTTLE} + /> + + {isTextInputOpen && categoryId === activatedCategoryId ? ( + + + + + + + ) : null} + + + + ); +}; + +const styles = StyleSheet.create({ + touchableCheck: { + paddingTop: 0, + justifyContent: 'center', + }, + checkIcon: { + width: widthPercentage(20), + height: heightPercentage(20), + }, + inputContainer: { + flexDirection: 'row', + }, + textInput: { + backgroundColor: colors.Gray02, + flex: 1, + borderRadius: widthPercentage(4), + marginLeft: widthPercentage(2), + paddingHorizontal: widthPercentage(4), + }, + keyboardInputContainer: { + backgroundColor: 'white', + borderTopWidth: 0, + }, +}); + +export default InboxTodos; diff --git a/components/inboxView/inboxTodos/inboxTodo/InboxTodo.jsx b/components/inboxView/inboxTodos/inboxTodo/InboxTodo.jsx index 26c1035..07bce6f 100644 --- a/components/inboxView/inboxTodos/inboxTodo/InboxTodo.jsx +++ b/components/inboxView/inboxTodos/inboxTodo/InboxTodo.jsx @@ -1,10 +1,10 @@ +import SubTodoGenerateModal from '@/components/SubTodoGenerateModal'; +import GeneratedSubTodoList from '@/components/todayView/dailyTodos/dailyTodo/generatedSubTodoList/GeneratedSubTodoList'; import { TextInputContext } from '@/contexts/textInputContext'; import '@/locales/index'; -import { widthPercentage } from '@/utils/responsiveSize'; import React, { useContext } from 'react'; -import { StyleSheet, View } from 'react-native'; +import { View } from 'react-native'; import useModal from '../../../../hooks/common/useModal'; -import TodoModal from '../../../TodoModal'; import SubTodoInfo from './subTodoInfo/SubTodoInfo'; import SubTodoList from './subTodoList/SubTodoList'; import TodoListItem from './todoListItem/TodoListItem'; @@ -18,17 +18,19 @@ const InboxTodo = ({ item, drag, isActive }) => { setIsSubTodoToggleActivated, subTodoInputActivated, setSubTodoInputActivated, + generatedSubTodos, + setGeneratedSubTodos, } = useInboxTodo(); const { setTextInputOpen } = useContext(TextInputContext); - const { isVisible: isTodoModalVisible, setIsVisible: setIsTodoModalVisible } = - useModal(); + const { + isVisible: isSubTodoGenerateModalVisible, + setIsVisible: setIsSubTodoGenerateModalVisible, + } = useModal(); + + const { setIsVisible: setIsTodoModalVisible } = useModal(); - const handleSubTodoCreate = () => { - setIsTodoModalVisible(false); - setSubTodoInputActivated(true); - }; const handleEdit = () => { setIsEditing(true); setTextInputOpen(false); @@ -36,15 +38,18 @@ const InboxTodo = ({ item, drag, isActive }) => { }; return ( - + 0} + onEdit={handleEdit} + setSubTodoInputActivated={setSubTodoInputActivated} /> { setSubTodoInputActivated={setSubTodoInputActivated} /> ) : null} - + ); }; -const styles = StyleSheet.create({ - container: { - paddingHorizontal: widthPercentage(20), - }, -}); - export default InboxTodo; diff --git a/components/inboxView/inboxTodos/inboxTodo/subTodoList/InboxSubTodo.jsx b/components/inboxView/inboxTodos/inboxTodo/subTodoList/InboxSubTodo.jsx index 4af50b0..d0ee342 100644 --- a/components/inboxView/inboxTodos/inboxTodo/subTodoList/InboxSubTodo.jsx +++ b/components/inboxView/inboxTodos/inboxTodo/subTodoList/InboxSubTodo.jsx @@ -1,46 +1,27 @@ -import TodoModal from '@/components/TodoModal'; import { LoginContext } from '@/contexts/LoginContext'; import { TextInputContext } from '@/contexts/textInputContext'; import { useSubTodoUpdateMutation } from '@/hooks/api/useSubTodoMutations'; -import getIconFillColor from '@/utils/getIconFillColor'; import { handleLogEvent, INBOXTODO_SUBTODO_COMPLETECLICK_EVENT, } from '@/utils/logEvent'; import { heightPercentage, widthPercentage } from '@/utils/responsiveSize'; -import { Icon, Text, useTheme } from '@ui-kitten/components'; +import { Icon, useTheme } from '@ui-kitten/components'; import { useContext, useState } from 'react'; -import { - Pressable, - StyleSheet, - TextInput, - TouchableOpacity, - View, -} from 'react-native'; +import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native'; +import SubTodoMoreMenu from './subTodoMoreMenu/SubTodoMoreMenu'; const InboxSubTodo = ({ item }) => { - const [completed, setCompleted] = useState(item.isCompleted); const [isEditing, setIsEditing] = useState(false); const [content, setContent] = useState(item.content); const theme = useTheme(); - const [modalVisible, setModalVisible] = useState(false); const { mutate: updateSubTodo } = useSubTodoUpdateMutation(); const { userId } = useContext(LoginContext); const { setTextInputOpen } = useContext(TextInputContext); - const handleCheck = () => { - setCompleted(!completed); - const updatedData = { - subtodoId: item.id, - isCompleted: !item.isCompleted, - }; - updateSubTodo(updatedData); - }; - const handleEdit = () => { setIsEditing(true); setTextInputOpen(false); - setModalVisible(false); }; const handleSubTodoUpdate = () => { @@ -51,7 +32,7 @@ const InboxSubTodo = ({ item }) => { updateSubTodo(updatedData); }; - const checkIcon = props => { + const accessoryLeft = props => { return ( { @@ -60,38 +41,27 @@ const InboxSubTodo = ({ item }) => { userId: userId, subtodoId: item.id, }); - handleCheck(); }} > ); }; - const settingIcon = props => { - return ( - setModalVisible(true)}> - - - ); + const accessoryRight = () => { + return ; }; return ( <> - {checkIcon()} + {accessoryLeft()} {isEditing ? ( { autoFocus={true} /> ) : ( - setModalVisible(true)} - > + {item.content} )} - {settingIcon()} + {accessoryRight()} - ); }; diff --git a/components/inboxView/inboxTodos/inboxTodo/subTodoList/SubTodoList.tsx b/components/inboxView/inboxTodos/inboxTodo/subTodoList/SubTodoList.tsx index a7e13e6..fd4fcb2 100644 --- a/components/inboxView/inboxTodos/inboxTodo/subTodoList/SubTodoList.tsx +++ b/components/inboxView/inboxTodos/inboxTodo/subTodoList/SubTodoList.tsx @@ -1,7 +1,9 @@ -import { Input, List } from '@ui-kitten/components'; +import colors from '@/theme/theme.json'; +import { heightPercentage, widthPercentage } from '@/utils/responsiveSize'; +import { Icon, List } from '@ui-kitten/components'; import React from 'react'; import { useTranslation } from 'react-i18next'; -import { StyleSheet } from 'react-native'; +import { StyleSheet, TextInput, View } from 'react-native'; import { Todo } from '../../../../../types/todo'; import InboxSubTodo from './InboxSubTodo'; import useSubTodoList from './useSubTodoList'; @@ -34,16 +36,33 @@ const SubTodoList: React.FC = ({ contentContainerStyle={{ marginLeft: 40, paddingLeft: 40 }} ListFooterComponent={ subTodoInputActivated ? ( - { - setSubtodoInput(nextInput); - }} - autoFocus={true} - onSubmitEditing={handleSubtodoSubmit} - /> + // { + // setSubtodoInput(nextInput); + // }} + // autoFocus={true} + // onSubmitEditing={handleSubtodoSubmit} + // /> + + + { + setSubtodoInput(nextInput); + }} + autoFocus={true} + onSubmitEditing={handleSubtodoSubmit} + style={styles.textInput} + /> + ) : null } /> @@ -54,8 +73,21 @@ const styles = StyleSheet.create({ listContainer: { backgroundColor: 'white', }, - input: { - paddingLeft: 40, + inputContainer: { + marginLeft: widthPercentage(20), + flexDirection: 'row', + }, + icon: { + width: widthPercentage(20), + height: heightPercentage(20), + marginRight: widthPercentage(4), + }, + textInput: { + backgroundColor: colors.Gray02, + borderRadius: widthPercentage(4), + paddingLeft: widthPercentage(4), + textAlign: 'left', + flex: 1, }, }); diff --git a/components/inboxView/inboxTodos/inboxTodo/subTodoList/subTodoMoreMenu/SubTodoMoreMenu.tsx b/components/inboxView/inboxTodos/inboxTodo/subTodoList/subTodoMoreMenu/SubTodoMoreMenu.tsx new file mode 100644 index 0000000..ef4c228 --- /dev/null +++ b/components/inboxView/inboxTodos/inboxTodo/subTodoList/subTodoMoreMenu/SubTodoMoreMenu.tsx @@ -0,0 +1,113 @@ +import '@/locales/index'; +import { + Icon, + Layout, + MenuItem, + OverflowMenu, + Text, +} from '@ui-kitten/components'; +import React, { useCallback, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { StyleSheet, TouchableOpacity } from 'react-native'; +import fontStyles from '../../../../../../theme/fontStyles'; +import { scale, moderateScale } from 'react-native-size-matters/extend'; +import EditIcon from '@/components/icons/EditIcon'; +import DeleteIcon from '@/components/icons/DeleteIcon'; +import theme from '@/theme/theme.json'; +import useSubTodoMoreMenu from './useSubTodoMoreMenu'; + +const TodoText = ({ titleText, disabled = false }) => { + return ( + + {titleText} + + ); +}; + +const MenuIconButton = onPress => ( + + + +); + +const SubTodoMoreMenu = ({ onEdit, item }) => { + const { handleEditPress, handleDeletePress } = useSubTodoMoreMenu({ + onEdit, + item, + }); + const [visible, setVisible] = useState(false); + const { t } = useTranslation(); + + const toggleMenu = useCallback(() => { + setVisible(true); + }, []); + + return ( + + MenuIconButton(toggleMenu)} + visible={visible} + onBackdropPress={() => setVisible(false)} + style={styles.container} + > + + onPress={() => { + handleEditPress(); + }} + style={styles.topMenuItem} + /> + + onPress={() => { + handleDeletePress(); + }} + style={styles.middleMenuItem} + /> + + + ); +}; + +const styles = StyleSheet.create({ + container: { + borderRadius: 8, + padding: 16, + width: scale(172), + }, + topMenuItem: { + paddingBottom: moderateScale(6), + paddingHorizontal: 0, + paddingTop: 0, + justifyContent: 'flex-start', + }, + middleMenuItem: { + paddingVertical: moderateScale(6), + paddingHorizontal: 0, + justifyContent: 'flex-start', + }, + bottomMenuItem: { + paddingTop: moderateScale(6), + paddingHorizontal: 0, + paddingBottom: 0, + justifyContent: 'flex-start', + }, +}); + +export default SubTodoMoreMenu; diff --git a/components/inboxView/inboxTodos/inboxTodo/subTodoList/subTodoMoreMenu/useSubTodoMoreMenu.tsx b/components/inboxView/inboxTodos/inboxTodo/subTodoList/subTodoMoreMenu/useSubTodoMoreMenu.tsx new file mode 100644 index 0000000..dc5ecb0 --- /dev/null +++ b/components/inboxView/inboxTodos/inboxTodo/subTodoList/subTodoMoreMenu/useSubTodoMoreMenu.tsx @@ -0,0 +1,42 @@ +import { LoginContext } from '@/contexts/LoginContext'; +import { useSubTodoDeleteMutation } from '@/hooks/api/useSubTodoMutations'; +import { + handleLogEvent, + TODOMODAL_DELETE_CLICK_EVENT, + TODOMODAL_EDIT_CLICK_EVENT, +} from '@/utils/logEvent'; +import { useContext } from 'react'; + +const useSubTodoMoreMenu = ({ item, onEdit = () => {} }) => { + const { userId } = useContext(LoginContext); + const { mutate: deleteSubTodo } = useSubTodoDeleteMutation(); + + const handleDelete = async itemId => { + deleteSubTodo({ subTodoId: itemId }); + }; + + const handleEditPress = () => { + handleLogEvent(TODOMODAL_EDIT_CLICK_EVENT, { + time: new Date().toISOString(), + userId: userId, + todoId: item.id, + }); + onEdit(); + }; + + const handleDeletePress = () => { + handleLogEvent(TODOMODAL_DELETE_CLICK_EVENT, { + time: new Date().toISOString(), + userId: userId, + todoId: item.id, + }); + handleDelete(item.id); + }; + + return { + handleEditPress, + handleDeletePress, + }; +}; + +export default useSubTodoMoreMenu; diff --git a/components/inboxView/inboxTodos/inboxTodo/todoListItem/TodoListItem.tsx b/components/inboxView/inboxTodos/inboxTodo/todoListItem/TodoListItem.tsx index e763662..7099e44 100644 --- a/components/inboxView/inboxTodos/inboxTodo/todoListItem/TodoListItem.tsx +++ b/components/inboxView/inboxTodos/inboxTodo/todoListItem/TodoListItem.tsx @@ -1,10 +1,11 @@ +import EditableTextField from '@/components/common/molecules/EditableTextField'; import { heightPercentage, widthPercentage } from '@/utils/responsiveSize'; -import { Icon } from '@ui-kitten/components'; +import { Icon, ListItem } from '@ui-kitten/components'; import React from 'react'; -import { Pressable, StyleSheet, TouchableOpacity, View } from 'react-native'; +import { Pressable, StyleSheet, Text } from 'react-native'; import { RenderItemParams } from 'react-native-draggable-flatlist'; import { Todo } from '../../../../../types/todo'; -import EditableTextField from '../../../../common/molecules/EditableTextField'; +import TodoMoreMenu from './todoMoreMenu/TodoMoreMenu'; import useTodoListItem from './useTodoListItem'; interface TodoListItemProps extends RenderItemParams { @@ -14,38 +15,40 @@ interface TodoListItemProps extends RenderItemParams { React.SetStateAction >; setIsTodoModalVisible: React.Dispatch>; + onEdit: () => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + bottomSheetRef: React.MutableRefObject; + subTodoInputActivated: boolean; + setSubTodoInputActivated: React.SetStateAction; } const TodoListItem: React.FC = ({ item, drag, - // eslint-disable-next-line @typescript-eslint/no-unused-vars + isActive, isEditing, setIsEditing, setIsSubTodoGenerateModalVisible, - setIsTodoModalVisible, + onEdit, + setSubTodoInputActivated, }) => { const { theme, + // eslint-disable-next-line @typescript-eslint/no-unused-vars handleCheckIconPress, handleTodoListItemPress, handleTodoListItemSubmitEditing, - handleSettingIconPress, } = useTodoListItem({ item, isEditing, setIsEditing, setIsSubTodoGenerateModalVisible, - setIsTodoModalVisible, }); const accessoryLeft = (props?) => { return ( - handleCheckIconPress()} - style={styles.touchableCheck} - > + = ({ ); }; - const accessoryRight = (props?) => { + const accessoryRight = () => { return ( - - - - - + ); }; const title = () => ( - + <> + + {item.dueTime && ( + + {item.dueTime.split(':').slice(0, 2).join(':')} + + )} + ); return ( - - - {accessoryLeft()} - - {title} - - - {accessoryRight()} - + <> + + ); }; diff --git a/components/inboxView/inboxTodos/inboxTodo/todoListItem/todoMoreMenu/TodoMoreMenu.tsx b/components/inboxView/inboxTodos/inboxTodo/todoListItem/todoMoreMenu/TodoMoreMenu.tsx new file mode 100644 index 0000000..da25e6c --- /dev/null +++ b/components/inboxView/inboxTodos/inboxTodo/todoListItem/todoMoreMenu/TodoMoreMenu.tsx @@ -0,0 +1,169 @@ +import AddIcon from '@/components/icons/AddIcon'; +import ChangeDateIcon from '@/components/icons/ChangeDateIcon'; +import DeleteIcon from '@/components/icons/DeleteIcon'; +import EditIcon from '@/components/icons/EditIcon'; +import GenerateSubtodoIcon from '@/components/icons/GenerateSubtodoIcon'; +import { CalendarBottomSheetContext } from '@/contexts/CalendarBottomSheetProvider'; +import useTodoStore from '@/contexts/TodoStore'; +import '@/locales/index'; +import theme from '@/theme/theme.json'; +import { + Icon, + Layout, + MenuItem, + OverflowMenu, + Text, +} from '@ui-kitten/components'; +import React, { useCallback, useContext, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { StyleSheet, TouchableOpacity } from 'react-native'; +import { moderateScale, scale } from 'react-native-size-matters/extend'; +import fontStyles from '../../../../../../theme/fontStyles'; +import useTodoMoreMenu from './useTodoMoreMenu'; + +const TodoText = ({ titleText, disabled = false }) => { + return ( + + {titleText} + + ); +}; + +const MenuIconButton = onPress => ( + + + +); + +const TodoMoreMenu = ({ + setIsSubTodoGenerateModalVisible, + onEdit, + item, + setSubTodoInputActivated, +}) => { + const { + handleEditPress, + handleDeletePress, + handleGenerateSubTodoPress, + handleCreateSubTodoPress: handleAddSubTodoPress, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + handlePutTodoToInboxPress, + } = useTodoMoreMenu({ + setIsSubTodoGenerateModalVisible, + onEdit, + item, + setSubTodoInputActivated, + }); + const [visible, setVisible] = useState(false); + const { t } = useTranslation(); + const { openBottomSheet } = useContext(CalendarBottomSheetContext); + const { setSelectedTodo } = useTodoStore(); + + const toggleMenu = useCallback(() => { + setVisible(true); + }, []); + + return ( + + MenuIconButton(toggleMenu)} + visible={visible} + onBackdropPress={() => setVisible(false)} + style={styles.container} + > + + onPress={() => { + handleEditPress(); + }} + style={styles.topMenuItem} + /> + + onPress={() => { + handleDeletePress(); + }} + style={styles.middleMenuItem} + /> + + onPress={() => { + setSelectedTodo(item); + openBottomSheet(); + setVisible(false); + }} + style={styles.middleMenuItem} + /> + 0} + accessoryLeft={GenerateSubtodoIcon} + title= 0} + titleText={t('components.todoMoreMenu.createSubTodoWithAi')} + /> + onPress={() => { + handleGenerateSubTodoPress(); + }} + style={styles.middleMenuItem} + /> + + onPress={() => { + handleAddSubTodoPress(); + }} + style={styles.middleMenuItem} + /> + + + ); +}; + +const styles = StyleSheet.create({ + container: { + borderRadius: 8, + padding: 16, + width: scale(172), + }, + topMenuItem: { + paddingBottom: moderateScale(6), + paddingHorizontal: 0, + paddingTop: 0, + justifyContent: 'flex-start', + }, + middleMenuItem: { + paddingVertical: moderateScale(6), + paddingHorizontal: 0, + justifyContent: 'flex-start', + }, + bottomMenuItem: { + paddingTop: moderateScale(6), + paddingHorizontal: 0, + paddingBottom: 0, + justifyContent: 'flex-start', + }, +}); + +export default TodoMoreMenu; diff --git a/components/inboxView/inboxTodos/inboxTodo/todoListItem/todoMoreMenu/useTodoMoreMenu.tsx b/components/inboxView/inboxTodos/inboxTodo/todoListItem/todoMoreMenu/useTodoMoreMenu.tsx new file mode 100644 index 0000000..dea7a21 --- /dev/null +++ b/components/inboxView/inboxTodos/inboxTodo/todoListItem/todoMoreMenu/useTodoMoreMenu.tsx @@ -0,0 +1,105 @@ +import { CategoryContext } from '@/contexts/CategoryContext'; +import { LoginContext } from '@/contexts/LoginContext'; +import { + useTodoDeleteMutation, + useTodoUpdateMutation, +} from '@/hooks/api/useTodoMutations'; +import { convertGmtToKst } from '@/utils/convertTimezone'; +import { + handleLogEvent, + TODOMODAL_CHANGEDATE_CLICK_EVENT, + TODOMODAL_CREATESUBTODO_CLICK_EVENT, + TODOMODAL_DELETE_CLICK_EVENT, + TODOMODAL_EDIT_CLICK_EVENT, + TODOMODAL_MOVETOINBOX_CLICK_EVENT, +} from '@/utils/logEvent'; +import { useContext } from 'react'; + +const useTodoMoreMenu = ({ + item, + onEdit = () => {}, + setIsSubTodoGenerateModalVisible, + setSubTodoInputActivated, +}) => { + const { selectedCategory } = useContext(CategoryContext); + const { userId } = useContext(LoginContext); + + const { mutate: updateTodoDate } = useTodoUpdateMutation(); + const { mutate: deleteTodo } = useTodoDeleteMutation(); + + const handleDelete = async itemId => { + deleteTodo({ todoId: itemId }); + }; + + const handleDateUpdate = date => { + const kstDate = date + ? convertGmtToKst(date).toISOString().split('T')[0] + : null; + + const updatedTodo = { + date: kstDate, + todo_id: item.id, + category_id: selectedCategory, + }; + updateTodoDate(updatedTodo); + }; + + const handleEditPress = () => { + handleLogEvent(TODOMODAL_EDIT_CLICK_EVENT, { + time: new Date().toISOString(), + userId: userId, + todoId: item.id, + }); + onEdit(); + }; + + const handleDeletePress = () => { + handleLogEvent(TODOMODAL_DELETE_CLICK_EVENT, { + time: new Date().toISOString(), + userId: userId, + todoId: item.id, + }); + handleDelete(item.id); + }; + + const handleChaneDatePress = () => { + handleLogEvent(TODOMODAL_CHANGEDATE_CLICK_EVENT, { + time: new Date().toISOString(), + userId: userId, + todoId: item.id, + }); + }; + + const handleGenerateSubTodoPress = () => { + setIsSubTodoGenerateModalVisible(true); + }; + + const handleCreateSubTodoPress = () => { + handleLogEvent(TODOMODAL_CREATESUBTODO_CLICK_EVENT, { + time: new Date().toISOString(), + userId: userId, + todoId: item.id, + }); + setSubTodoInputActivated(true); + }; + + const handlePutTodoToInboxPress = () => { + handleLogEvent(TODOMODAL_MOVETOINBOX_CLICK_EVENT, { + time: new Date().toISOString(), + userId: userId, + todoId: item.id, + }); + handleDateUpdate(null); + }; + + return { + handleEditPress, + handleDeletePress, + handleChaneDatePress, + handleGenerateSubTodoPress, + handleCreateSubTodoPress, + handlePutTodoToInboxPress, + }; +}; + +export default useTodoMoreMenu; diff --git a/components/inboxView/inboxTodos/inboxTodo/todoListItem/useTodoListItem.ts b/components/inboxView/inboxTodos/inboxTodo/todoListItem/useTodoListItem.ts index ee0d26c..90c835e 100644 --- a/components/inboxView/inboxTodos/inboxTodo/todoListItem/useTodoListItem.ts +++ b/components/inboxView/inboxTodos/inboxTodo/todoListItem/useTodoListItem.ts @@ -15,7 +15,6 @@ const useTodoListItem = ({ isEditing, setIsEditing, setIsSubTodoGenerateModalVisible, - setIsTodoModalVisible, }) => { const { mutate: updateTodo } = useTodoUpdateMutation(); const { userId } = useContext(LoginContext); @@ -47,7 +46,6 @@ const useTodoListItem = ({ userId: userId, todoId: item.id, }); - setIsTodoModalVisible(true); }; const handleTodoContentUpdate = content => { @@ -74,7 +72,6 @@ const useTodoListItem = ({ userId: userId, todoId: item.id, }); - setIsTodoModalVisible(true); }; return { diff --git a/components/inboxView/inboxTodos/inboxTodo/useInboxTodo.ts b/components/inboxView/inboxTodos/inboxTodo/useInboxTodo.ts index 3335a29..2c8f7c6 100644 --- a/components/inboxView/inboxTodos/inboxTodo/useInboxTodo.ts +++ b/components/inboxView/inboxTodos/inboxTodo/useInboxTodo.ts @@ -5,6 +5,7 @@ const useInboxTodo = () => { const [isSubtodoToggleActivated, setIsSubTodoToggleActivated] = useState(true); const [subTodoInputActivated, setSubTodoInputActivated] = useState(false); + const [generatedSubTodos, setGeneratedSubTodos] = useState([]); return { isEditing, @@ -13,6 +14,8 @@ const useInboxTodo = () => { setIsSubTodoToggleActivated, subTodoInputActivated, setSubTodoInputActivated, + generatedSubTodos, + setGeneratedSubTodos, }; }; diff --git a/components/todayView/dailyTodos/DailyTodos.tsx b/components/todayView/dailyTodos/DailyTodos.tsx index aab8e0c..bf10571 100644 --- a/components/todayView/dailyTodos/DailyTodos.tsx +++ b/components/todayView/dailyTodos/DailyTodos.tsx @@ -33,7 +33,8 @@ import { KeyboardAccessoryView } from 'react-native-keyboard-accessory'; import DailyTodo from './dailyTodo/DailyTodo'; interface DailyTodosProps { - todosData: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + todosData: any; categoryId: number; } @@ -41,7 +42,6 @@ const DailyTodos: React.FC = ({ todosData, categoryId }) => { const { userId } = useContext(LoginContext); const { setSelectedCategory } = useContext(CategoryContext); setSelectedCategory(categoryId); - setSelectedCategory(categoryId); const { selectedDate } = useContext(DateContext); // const { data: todosData } = useTodosQuery(userId); const { t } = useTranslation(); diff --git a/components/todayView/dailyTodos/dailyTodo/subTodoList/DailySubTodo.jsx b/components/todayView/dailyTodos/dailyTodo/subTodoList/DailySubTodo.jsx index 10bbab8..5daf07c 100644 --- a/components/todayView/dailyTodos/dailyTodo/subTodoList/DailySubTodo.jsx +++ b/components/todayView/dailyTodos/dailyTodo/subTodoList/DailySubTodo.jsx @@ -10,6 +10,7 @@ import { heightPercentage, widthPercentage } from '@/utils/responsiveSize'; import { Icon, Text, useTheme } from '@ui-kitten/components'; import { useContext, useState } from 'react'; import { Pressable, StyleSheet, TextInput, View } from 'react-native'; +import SubTodoMoreMenu from './subTodoMoreMenu/SubTodoMoreMenu'; const DailySubTodo = ({ item }) => { const [completed, setCompleted] = useState(item.isCompleted); @@ -29,6 +30,11 @@ const DailySubTodo = ({ item }) => { updateSubTodo(updatedData); }; + const handleEdit = () => { + setIsEditing(true); + setTextInputOpen(false); + }; + const handleSubTodoUpdate = () => { const updatedData = { subtodoId: item.id, @@ -37,7 +43,7 @@ const DailySubTodo = ({ item }) => { updateSubTodo(updatedData); }; - const checkIcon = props => { + const accessoryLeft = props => { return ( { @@ -59,34 +65,15 @@ const DailySubTodo = ({ item }) => { ); }; - // const settingIcon = () => { - // return ( - // // <<<<<<< HEAD - // // setModalVisible(true)}> - // // - // // - // // ======= - // { - // setIsEditing(true); - // }} - // /> - // // >>>>>>> 70a1703a79f232558c00f81dad0f789f863ae1c5 - // ); - // }; + const accessoryRight = () => { + return ; + }; return ( <> - {checkIcon()} + {accessoryLeft()} {isEditing ? ( { autoFocus={true} /> ) : ( - // <<<<<<< HEAD - // setModalVisible(true)} - // > - // {item.content} - // - // )} - // - // {settingIcon()} - // - // {item.content} {item.dueTime && ( @@ -127,6 +96,7 @@ const DailySubTodo = ({ item }) => { )} + {accessoryRight()} ); diff --git a/components/todayView/dailyTodos/dailyTodo/todoListItem/TodoListItem.tsx b/components/todayView/dailyTodos/dailyTodo/todoListItem/TodoListItem.tsx index be3c597..ed138ec 100644 --- a/components/todayView/dailyTodos/dailyTodo/todoListItem/TodoListItem.tsx +++ b/components/todayView/dailyTodos/dailyTodo/todoListItem/TodoListItem.tsx @@ -64,29 +64,6 @@ const TodoListItem: React.FC = ({ const accessoryRight = () => { return ( - // <<<<<<< HEAD - // - // {item.children.length === 0 && !item.isCompleted && ( - // - // - // - // )} - // - // - // - // - // ======= = ({ }; const title = () => ( - // <<<<<<< HEAD - // - // ); - - // return ( - // - // - // {accessoryLeft()} - // - // {title} - // - // - // {accessoryRight()} - // - // ======= <> = ({ title={title} /> - // >>>>>>> 70a1703a79f232558c00f81dad0f789f863ae1c5 ); }; diff --git a/hooks/todo/useFilteredInboxTodo.js b/hooks/todo/useFilteredInboxTodo.js new file mode 100644 index 0000000..d09ac78 --- /dev/null +++ b/hooks/todo/useFilteredInboxTodo.js @@ -0,0 +1,18 @@ +import { useEffect, useState } from 'react'; + +const useFilteredInboxTodos = (todos, selectedCategory) => { + const [filteredTodos, setFilteredTodos] = useState([]); + + useEffect(() => { + if (todos) { + const filtered = todos.filter( + todo => todo.categoryId === selectedCategory, + ); + setFilteredTodos(filtered); + } + }, [todos, selectedCategory]); + + return filteredTodos; +}; + +export default useFilteredInboxTodos;