From 40694d9749fe61571bb6fb8293232a67344af17c Mon Sep 17 00:00:00 2001 From: "lky062@naver.com" Date: Sun, 1 Sep 2024 18:01:44 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[SKP-168]=20feat=20:=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80=ED=95=98=EA=B8=B0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icon/ic_noti.svg | 14 ++ src/assets/icon/ic_noti_color.svg | 14 ++ src/assets/icon/ic_plus.svg | 3 + src/assets/icon/index.ts | 3 + .../CategoryCard/CategoryCard.style.tsx | 2 +- .../mutations/category/usePostCategoryAdd.ts | 23 +++ src/navigators/StackNavigator.tsx | 3 +- src/navigators/constants/menu.ts | 1 + src/navigators/types/index.ts | 1 + .../CategoryPlus/CategoryPlus.style.ts | 76 +++++++++ src/screens/CategoryPlus/CategoryPlus.tsx | 146 ++++++++++++++++++ .../CategoryTab/CategoryTab.style.ts | 30 +++- .../TabNavigator/CategoryTab/CategoryTab.tsx | 17 +- 13 files changed, 324 insertions(+), 9 deletions(-) create mode 100644 src/assets/icon/ic_noti.svg create mode 100644 src/assets/icon/ic_noti_color.svg create mode 100644 src/assets/icon/ic_plus.svg create mode 100644 src/hooks/mutations/category/usePostCategoryAdd.ts create mode 100644 src/screens/CategoryPlus/CategoryPlus.style.ts create mode 100644 src/screens/CategoryPlus/CategoryPlus.tsx diff --git a/src/assets/icon/ic_noti.svg b/src/assets/icon/ic_noti.svg new file mode 100644 index 0000000..c816403 --- /dev/null +++ b/src/assets/icon/ic_noti.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/icon/ic_noti_color.svg b/src/assets/icon/ic_noti_color.svg new file mode 100644 index 0000000..a060a73 --- /dev/null +++ b/src/assets/icon/ic_noti_color.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/icon/ic_plus.svg b/src/assets/icon/ic_plus.svg new file mode 100644 index 0000000..0d984e3 --- /dev/null +++ b/src/assets/icon/ic_plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/index.ts b/src/assets/icon/index.ts index 08bd956..244489f 100644 --- a/src/assets/icon/index.ts +++ b/src/assets/icon/index.ts @@ -37,3 +37,6 @@ export {default as IcCategoryRest} from './ic_category_rest2.svg'; export {default as IcSad} from './ic_sad_face.svg'; export {default as IcAppleLogo} from './ic_apple_logo.svg'; export {default as IcAnalyze} from './ic_analyze.svg'; +export {default as IcPlus} from './ic_plus.svg'; +export {default as IcNoti} from './ic_noti.svg'; +export {default as IcNotiColor} from './ic_noti_color.svg'; diff --git a/src/components/common/Category/CategoryCard/CategoryCard.style.tsx b/src/components/common/Category/CategoryCard/CategoryCard.style.tsx index b4fd9e7..aa8bcf8 100644 --- a/src/components/common/Category/CategoryCard/CategoryCard.style.tsx +++ b/src/components/common/Category/CategoryCard/CategoryCard.style.tsx @@ -25,7 +25,7 @@ const styles = StyleSheet.create({ }, description: { ...theme.typography.body_m_16, - color: '#555', + color: theme.palette.gray6, }, }); diff --git a/src/hooks/mutations/category/usePostCategoryAdd.ts b/src/hooks/mutations/category/usePostCategoryAdd.ts new file mode 100644 index 0000000..ba6c7e0 --- /dev/null +++ b/src/hooks/mutations/category/usePostCategoryAdd.ts @@ -0,0 +1,23 @@ +import {useMutation} from '@tanstack/react-query'; +import {POST} from '../../../apis/client'; + +export interface ICategoryData { + name: string; + description: string; +} + +/** + * 카테고리 추가 + */ +export const addCategory = async (data: ICategoryData) => { + const res = await POST(`/api/user-category`, data); + return res.data; +}; + +export const usePostAddCategory = () => { + const addCategoryMutation = useMutation({ + mutationFn: (data: ICategoryData) => addCategory(data), // Use the mutation function with typed data + }); + + return {addCategoryMutation}; +}; diff --git a/src/navigators/StackNavigator.tsx b/src/navigators/StackNavigator.tsx index 7a16e02..29cdbcf 100644 --- a/src/navigators/StackNavigator.tsx +++ b/src/navigators/StackNavigator.tsx @@ -11,6 +11,7 @@ import Login from '../screens/Login/Login'; import Withdraw from '../screens/Withdraw/Withdraw'; import CategoryList from '../screens/CategoryList/CategoryList'; +import CategoryPlus from '../screens/CategoryPlus/CategoryPlus'; const Stack = createNativeStackNavigator(); @@ -39,7 +40,7 @@ export default function StackNavigator() { {/* 카테고리 리스트 */} - + {/* 장소 상세 */} diff --git a/src/navigators/constants/menu.ts b/src/navigators/constants/menu.ts index 2ac5892..a124070 100644 --- a/src/navigators/constants/menu.ts +++ b/src/navigators/constants/menu.ts @@ -13,6 +13,7 @@ export const enum StackMenu { Detail = 'Detail', CategoryList = 'CategoryList', + CategoryPlus = 'CategoryPlus', } export const enum TabMenu { diff --git a/src/navigators/types/index.ts b/src/navigators/types/index.ts index 03ccd33..ef77c65 100644 --- a/src/navigators/types/index.ts +++ b/src/navigators/types/index.ts @@ -26,6 +26,7 @@ export type StackParamList = { Detail: {id: number}; CategoryList: {title: string; description: string}; + CategoryPlus: undefined; }; export type TabParamList = { diff --git a/src/screens/CategoryPlus/CategoryPlus.style.ts b/src/screens/CategoryPlus/CategoryPlus.style.ts new file mode 100644 index 0000000..5ed61a8 --- /dev/null +++ b/src/screens/CategoryPlus/CategoryPlus.style.ts @@ -0,0 +1,76 @@ +import {StyleSheet} from 'react-native'; +import {theme} from '../../styles'; + +const styles = StyleSheet.create({ + container: { + paddingTop: 100, + flex: 1, + backgroundColor: theme.palette.white, + alignItems: 'center', + }, + scrollViewContent: { + flexGrow: 1, + width: 375, + padding: 28, + }, + title: { + paddingLeft: 28, + ...theme.typography.title_sb_21, + textAlign: 'left', + alignSelf: 'flex-start', + }, + inputWrapper: { + marginTop: 15, + gap: 10, + }, + label: { + fontSize: 14, + fontWeight: '600', + color: theme.palette.gray4, + marginBottom: 5, + }, + input: { + borderBottomWidth: 1, + borderBottomColor: theme.palette.gray3, + paddingVertical: 8, + fontSize: 16, + color: theme.palette.black, + }, + charCount: { + fontSize: 12, + color: theme.palette.gray5, + textAlign: 'right', + marginTop: 4, + }, + helperWrapper: { + marginVertical: 20, + backgroundColor: theme.palette.gray1, + padding: 10, + borderRadius: 4, + }, + helperText: { + fontSize: 12, + color: theme.palette.gray6, + textAlign: 'center', + }, + createButtonWrapper: { + position: 'absolute', + width: '100%', + bottom: 0, + alignItems: 'center', + backgroundColor: theme.palette.white, + }, + createButton: { + width: '100%', + backgroundColor: theme.palette.primary, + paddingVertical: 15, + alignItems: 'center', + }, + createButtonText: { + color: theme.palette.white, + fontSize: 16, + fontWeight: 'bold', + }, +}); + +export default styles; diff --git a/src/screens/CategoryPlus/CategoryPlus.tsx b/src/screens/CategoryPlus/CategoryPlus.tsx new file mode 100644 index 0000000..0d867a2 --- /dev/null +++ b/src/screens/CategoryPlus/CategoryPlus.tsx @@ -0,0 +1,146 @@ +import React, {useEffect, useRef, useState} from 'react'; +import { + View, + Text, + TextInput, + ScrollView, + KeyboardAvoidingView, + TouchableOpacity, + Keyboard, +} from 'react-native'; +import styles from './CategoryPlus.style'; +import {theme} from '../../styles'; +import {IcNoti, IcNotiColor} from '../../assets/icon'; +import {usePostAddCategory} from '../../hooks/mutations/category/usePostCategoryAdd'; + +export default function CategoryPlus() { + const nameInputRef = useRef(null); + const memoInputRef = useRef(null); + + const [nameValue, setNameValue] = useState(''); // State for name input value + const [memoValue, setMemoValue] = useState(''); // State for memo input value + + const {addCategoryMutation} = usePostAddCategory(); + + const [currentFocus, setCurrentFocus] = useState<'name' | 'memo'>('name'); + const [buttonBottomPosition, setButtonBottomPosition] = useState(0); + + useEffect(() => { + if (currentFocus === 'name' && nameInputRef.current) { + nameInputRef.current.focus(); + } else if (currentFocus === 'memo' && memoInputRef.current) { + memoInputRef.current.focus(); + } + }, [currentFocus]); + + useEffect(() => { + const keyboardWillShowListener = Keyboard.addListener( + 'keyboardWillShow', + event => { + setButtonBottomPosition(event.endCoordinates.height); + }, + ); + + const keyboardWillHideListener = Keyboard.addListener( + 'keyboardWillHide', + () => { + setButtonBottomPosition(0); + }, + ); + + return () => { + keyboardWillShowListener.remove(); + keyboardWillHideListener.remove(); + }; + }, []); + const handleNameInputFocus = () => { + setCurrentFocus('name'); + }; + + const handleMemoInputFocus = () => { + setCurrentFocus('memo'); + }; + + const handleCreateButtonPress = () => { + console.log('내가 바디에 담은 값들', { + name: nameValue, + description: memoValue || ' ', + }); + + addCategoryMutation.mutate( + { + name: nameValue, + description: memoValue || ' ', + }, + { + onSuccess: () => { + console.log('Category added successfully!'); + // navigation.navigate('SomeScreen'); + }, + onError: error => { + console.error('Error adding category:', error); + }, + }, + ); + }; + + return ( + + 원하는 카테고리를 만들어주세요 + + + + + 이름 + + + 0/12 + + + + + 메모 (선택) + + + {currentFocus === 'memo' ? : } + + + + + + 만들기 + + + + ); +} diff --git a/src/screens/TabNavigator/CategoryTab/CategoryTab.style.ts b/src/screens/TabNavigator/CategoryTab/CategoryTab.style.ts index 62c4a8c..434b6e6 100644 --- a/src/screens/TabNavigator/CategoryTab/CategoryTab.style.ts +++ b/src/screens/TabNavigator/CategoryTab/CategoryTab.style.ts @@ -1,24 +1,46 @@ import {Dimensions, StyleSheet} from 'react-native'; import {theme} from '../../../styles'; +import {flexBox} from '../../../styles/common'; const styles = StyleSheet.create({ container: { - flex: 1, paddingTop: 100, backgroundColor: theme.palette.white, + flex: 1, + alignItems: 'center', }, title: { paddingLeft: 28, - fontSize: 24, - fontWeight: 'bold', + ...theme.typography.title_sb_21, + textAlign: 'left', + alignSelf: 'flex-start', + }, + subTitle: { + top: -130, + textAlign: 'center', + ...theme.typography.body_m_15, + marginBottom: 20, }, cardContainer: { paddingLeft: 28, - marginTop: 60, + marginTop: 80, }, cardWrapper: { width: Dimensions.get('window').width - 150, }, + addButton: { + ...flexBox('row', 'center', 'center'), + top: -130, + backgroundColor: theme.palette.primary, + paddingVertical: 12, + gap: 5, + paddingHorizontal: 32, + borderRadius: 30, + }, + addButtonText: { + color: theme.palette.white, + ...theme.typography.button_sb_15, + }, }); export default styles; diff --git a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx index 1ec27dc..e95e167 100644 --- a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx +++ b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx @@ -1,9 +1,9 @@ import React, {useMemo} from 'react'; import styles from './CategoryTab.style'; -import {View, Text, FlatList} from 'react-native'; +import {View, Text, FlatList, TouchableOpacity} from 'react-native'; import Card from '../../../components/common/Category/CategoryCard/CategoryCard'; import {theme} from '../../../styles'; -import {IcCardRest} from '../../../assets/icon'; +import {IcCardRest, IcPlus} from '../../../assets/icon'; import {useGetCategoryListQuery} from '../../../hooks/queries/category/useGetCategoryList'; import { COLOR_MAP, @@ -30,6 +30,8 @@ export default function CategoryTab({navigation}: CategoryTabProps) { [mappedData], ); + const handleGoDetail = () => {}; + const handleCardPress = (item: CardData) => { navigation.navigate('CategoryList', { title: item.title, @@ -53,7 +55,7 @@ export default function CategoryTab({navigation}: CategoryTabProps) { 나만의 카테고리로 {'\n'} - 명소를 기록해봐요 + 여행지를 기록해봐요 + + 카테고리별로 다양한 여행지를 만나봐요! + + navigation.navigate('CategoryPlus')}> + + 카테고리 추가 + ); } From ccb0a1528be76847469fa621c7c835a950ef7578 Mon Sep 17 00:00:00 2001 From: "lky062@naver.com" Date: Mon, 2 Sep 2024 16:59:56 +0900 Subject: [PATCH 2/9] =?UTF-8?q?[SKP-168]=20feat=20:=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80=20=EC=8B=A4=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../queries/category/useGetCategoryList.ts | 5 ++- src/screens/CategoryPlus/CategoryPlus.tsx | 35 ++++++++++++------- .../TabNavigator/CategoryTab/CategoryTab.tsx | 2 -- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/hooks/queries/category/useGetCategoryList.ts b/src/hooks/queries/category/useGetCategoryList.ts index f4cda22..c6cd4aa 100644 --- a/src/hooks/queries/category/useGetCategoryList.ts +++ b/src/hooks/queries/category/useGetCategoryList.ts @@ -2,6 +2,7 @@ import {useQuery} from '@tanstack/react-query'; import {categoryQueryKeys} from '../../../constants/queryKeys/category'; import {CategoryCardResponseDto} from '../../../types/dtos/category'; import {axiosApi} from '../../../apis/client'; +import {CATEGORY_KEYS} from '../QueryKeys'; export const categoryApi = { getCategoryList: async (): Promise => { @@ -11,8 +12,10 @@ export const categoryApi = { }; export const useGetCategoryListQuery = () => { + const QUERY_KEY = CATEGORY_KEYS.all; + const {data: cardListData = []} = useQuery({ - queryKey: [categoryQueryKeys.cardList], + queryKey: QUERY_KEY, queryFn: categoryApi.getCategoryList, }); diff --git a/src/screens/CategoryPlus/CategoryPlus.tsx b/src/screens/CategoryPlus/CategoryPlus.tsx index 0d867a2..d5241bf 100644 --- a/src/screens/CategoryPlus/CategoryPlus.tsx +++ b/src/screens/CategoryPlus/CategoryPlus.tsx @@ -12,19 +12,24 @@ import styles from './CategoryPlus.style'; import {theme} from '../../styles'; import {IcNoti, IcNotiColor} from '../../assets/icon'; import {usePostAddCategory} from '../../hooks/mutations/category/usePostCategoryAdd'; +import {StackScreenProps} from '../../navigators/types'; +import {useQueryClient} from '@tanstack/react-query'; +import {CATEGORY_KEYS} from '../../hooks/queries/QueryKeys'; -export default function CategoryPlus() { +type CategoryPlusProps = StackScreenProps<'CategoryPlus'>; +export default function CategoryPlus({navigation}: CategoryPlusProps) { const nameInputRef = useRef(null); const memoInputRef = useRef(null); - const [nameValue, setNameValue] = useState(''); // State for name input value - const [memoValue, setMemoValue] = useState(''); // State for memo input value - - const {addCategoryMutation} = usePostAddCategory(); - const [currentFocus, setCurrentFocus] = useState<'name' | 'memo'>('name'); const [buttonBottomPosition, setButtonBottomPosition] = useState(0); + const [nameValue, setNameValue] = useState(''); + const [memoValue, setMemoValue] = useState(''); + + const {addCategoryMutation} = usePostAddCategory(); + const queryClient = useQueryClient(); + useEffect(() => { if (currentFocus === 'name' && nameInputRef.current) { nameInputRef.current.focus(); @@ -33,6 +38,9 @@ export default function CategoryPlus() { } }, [currentFocus]); + /** + * 진입 시 키보드 항상 활성화 & 키보드 위치 위에 버튼 생성 + */ useEffect(() => { const keyboardWillShowListener = Keyboard.addListener( 'keyboardWillShow', @@ -53,20 +61,15 @@ export default function CategoryPlus() { keyboardWillHideListener.remove(); }; }, []); + const handleNameInputFocus = () => { setCurrentFocus('name'); }; - const handleMemoInputFocus = () => { setCurrentFocus('memo'); }; const handleCreateButtonPress = () => { - console.log('내가 바디에 담은 값들', { - name: nameValue, - description: memoValue || ' ', - }); - addCategoryMutation.mutate( { name: nameValue, @@ -75,7 +78,13 @@ export default function CategoryPlus() { { onSuccess: () => { console.log('Category added successfully!'); - // navigation.navigate('SomeScreen'); + navigation.replace('CategoryList', { + title: nameValue, + description: memoValue, + }); + queryClient.invalidateQueries({ + queryKey: CATEGORY_KEYS.all, + }); }, onError: error => { console.error('Error adding category:', error); diff --git a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx index e95e167..034a36c 100644 --- a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx +++ b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx @@ -30,8 +30,6 @@ export default function CategoryTab({navigation}: CategoryTabProps) { [mappedData], ); - const handleGoDetail = () => {}; - const handleCardPress = (item: CardData) => { navigation.navigate('CategoryList', { title: item.title, From d992363ccfde7bfce73d1a0fffbad458e9b8b7e1 Mon Sep 17 00:00:00 2001 From: "lky062@naver.com" Date: Mon, 2 Sep 2024 20:04:43 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[SKP-168]=20feat=20:=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icon/ic_round_activity.svg | 20 +++++ src/assets/icon/ic_round_etc.svg | 10 +++ src/assets/icon/ic_round_festival.svg | 84 +++++++++++++++++++ src/assets/icon/ic_round_food.svg | 25 ++++++ src/assets/icon/ic_round_history.svg | 24 ++++++ src/assets/icon/ic_round_nature.svg | 51 +++++++++++ src/assets/icon/ic_round_rest.svg | 34 ++++++++ src/assets/icon/ic_round_shopping.svg | 32 +++++++ src/assets/icon/index.ts | 9 ++ src/constants/components/CategoryCard.ts | 30 +++++++ src/navigators/StackNavigator.tsx | 4 +- src/navigators/constants/menu.ts | 2 +- src/navigators/types/index.ts | 2 +- .../CategoryAdd.style.ts} | 0 .../CategoryAdd.tsx} | 6 +- src/screens/CategoryList/CategoryList.tsx | 11 ++- .../TabNavigator/CategoryTab/CategoryTab.tsx | 2 +- 17 files changed, 334 insertions(+), 12 deletions(-) create mode 100644 src/assets/icon/ic_round_activity.svg create mode 100644 src/assets/icon/ic_round_etc.svg create mode 100644 src/assets/icon/ic_round_festival.svg create mode 100644 src/assets/icon/ic_round_food.svg create mode 100644 src/assets/icon/ic_round_history.svg create mode 100644 src/assets/icon/ic_round_nature.svg create mode 100644 src/assets/icon/ic_round_rest.svg create mode 100644 src/assets/icon/ic_round_shopping.svg rename src/screens/{CategoryPlus/CategoryPlus.style.ts => CategoryAdd/CategoryAdd.style.ts} (100%) rename src/screens/{CategoryPlus/CategoryPlus.tsx => CategoryAdd/CategoryAdd.tsx} (96%) diff --git a/src/assets/icon/ic_round_activity.svg b/src/assets/icon/ic_round_activity.svg new file mode 100644 index 0000000..e3c9009 --- /dev/null +++ b/src/assets/icon/ic_round_activity.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icon/ic_round_etc.svg b/src/assets/icon/ic_round_etc.svg new file mode 100644 index 0000000..93a53e8 --- /dev/null +++ b/src/assets/icon/ic_round_etc.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/icon/ic_round_festival.svg b/src/assets/icon/ic_round_festival.svg new file mode 100644 index 0000000..675693d --- /dev/null +++ b/src/assets/icon/ic_round_festival.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icon/ic_round_food.svg b/src/assets/icon/ic_round_food.svg new file mode 100644 index 0000000..66aa9a2 --- /dev/null +++ b/src/assets/icon/ic_round_food.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icon/ic_round_history.svg b/src/assets/icon/ic_round_history.svg new file mode 100644 index 0000000..142187d --- /dev/null +++ b/src/assets/icon/ic_round_history.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icon/ic_round_nature.svg b/src/assets/icon/ic_round_nature.svg new file mode 100644 index 0000000..a21765f --- /dev/null +++ b/src/assets/icon/ic_round_nature.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icon/ic_round_rest.svg b/src/assets/icon/ic_round_rest.svg new file mode 100644 index 0000000..2a5d6f9 --- /dev/null +++ b/src/assets/icon/ic_round_rest.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icon/ic_round_shopping.svg b/src/assets/icon/ic_round_shopping.svg new file mode 100644 index 0000000..654c940 --- /dev/null +++ b/src/assets/icon/ic_round_shopping.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icon/index.ts b/src/assets/icon/index.ts index 244489f..b5c64f6 100644 --- a/src/assets/icon/index.ts +++ b/src/assets/icon/index.ts @@ -40,3 +40,12 @@ export {default as IcAnalyze} from './ic_analyze.svg'; export {default as IcPlus} from './ic_plus.svg'; export {default as IcNoti} from './ic_noti.svg'; export {default as IcNotiColor} from './ic_noti_color.svg'; + +export {default as IcRoundActivity} from './ic_round_activity.svg'; +export {default as IcRoundFestival} from './ic_round_festival.svg'; +export {default as IcRoundFood} from './ic_round_food.svg'; +export {default as IcRoundHistory} from './ic_round_history.svg'; +export {default as IcRoundNature} from './ic_round_nature.svg'; +export {default as IcRoundShopping} from './ic_round_shopping.svg'; +export {default as IcRoundRest} from './ic_round_rest.svg'; +export {default as IcRoundEtc} from './ic_round_etc.svg'; diff --git a/src/constants/components/CategoryCard.ts b/src/constants/components/CategoryCard.ts index a53f8de..04d90aa 100644 --- a/src/constants/components/CategoryCard.ts +++ b/src/constants/components/CategoryCard.ts @@ -12,9 +12,18 @@ import { IcFood, IcHistory, IcNature, + IcRoundActivity, + IcRoundEtc, + IcRoundFestival, + IcRoundFood, + IcRoundHistory, + IcRoundNature, + IcRoundRest, + IcRoundShopping, IcShopping, IcVacation, } from '../../assets/icon'; +import {theme} from '../../styles'; export const ICON_MAPS: Record> = { 액티비티: IcCardActivity, @@ -26,6 +35,17 @@ export const ICON_MAPS: Record> = { '쇼핑/도심': IcCardShopping, }; +export const ICON_DETAIL_MAPS: Record> = { + 액티비티: IcRoundActivity, + '문화/축제': IcRoundFestival, + 맛집: IcRoundFood, + '역사/유적지': IcRoundHistory, + '공원/자연': IcRoundNature, + 휴식: IcRoundRest, + '쇼핑/도심': IcRoundShopping, + 기타: IcRoundEtc, +}; + export const IC_MAPS: Record> = { 액티비티: IcActivity, '문화/축제': IcFestival, @@ -47,6 +67,16 @@ export const COLOR_MAP: Record = { 기타: '#BEFBF0', }; +export const COLOR_DETAIL_MAP: Record = { + 휴식: '#E3F7FF', + '공원/자연': '#E5FBE1', + '문화/축제': '#FFFDEB', + '쇼핑/도심': '#F1E5FF', + '역사/유적지': '#F2F2F2', + 맛집: '#FFE7D1', + 액티비티: '#DFFDF7', + 기타: theme.palette.primary, +}; export const CARD_SIZE = Dimensions.get('window').width - 150; export const MARGIN = 20; export const OFFSET = CARD_SIZE - MARGIN; diff --git a/src/navigators/StackNavigator.tsx b/src/navigators/StackNavigator.tsx index 29cdbcf..18fabaa 100644 --- a/src/navigators/StackNavigator.tsx +++ b/src/navigators/StackNavigator.tsx @@ -11,7 +11,7 @@ import Login from '../screens/Login/Login'; import Withdraw from '../screens/Withdraw/Withdraw'; import CategoryList from '../screens/CategoryList/CategoryList'; -import CategoryPlus from '../screens/CategoryPlus/CategoryPlus'; +import CategoryAdd from '../screens/CategoryAdd/CategoryAdd'; const Stack = createNativeStackNavigator(); @@ -40,7 +40,7 @@ export default function StackNavigator() { {/* 카테고리 리스트 */} - + {/* 장소 상세 */} diff --git a/src/navigators/constants/menu.ts b/src/navigators/constants/menu.ts index a124070..e32e0af 100644 --- a/src/navigators/constants/menu.ts +++ b/src/navigators/constants/menu.ts @@ -13,7 +13,7 @@ export const enum StackMenu { Detail = 'Detail', CategoryList = 'CategoryList', - CategoryPlus = 'CategoryPlus', + CategoryAdd = 'CategoryAdd', } export const enum TabMenu { diff --git a/src/navigators/types/index.ts b/src/navigators/types/index.ts index ef77c65..23df0ad 100644 --- a/src/navigators/types/index.ts +++ b/src/navigators/types/index.ts @@ -26,7 +26,7 @@ export type StackParamList = { Detail: {id: number}; CategoryList: {title: string; description: string}; - CategoryPlus: undefined; + CategoryAdd: undefined; }; export type TabParamList = { diff --git a/src/screens/CategoryPlus/CategoryPlus.style.ts b/src/screens/CategoryAdd/CategoryAdd.style.ts similarity index 100% rename from src/screens/CategoryPlus/CategoryPlus.style.ts rename to src/screens/CategoryAdd/CategoryAdd.style.ts diff --git a/src/screens/CategoryPlus/CategoryPlus.tsx b/src/screens/CategoryAdd/CategoryAdd.tsx similarity index 96% rename from src/screens/CategoryPlus/CategoryPlus.tsx rename to src/screens/CategoryAdd/CategoryAdd.tsx index d5241bf..25ec6d8 100644 --- a/src/screens/CategoryPlus/CategoryPlus.tsx +++ b/src/screens/CategoryAdd/CategoryAdd.tsx @@ -8,7 +8,7 @@ import { TouchableOpacity, Keyboard, } from 'react-native'; -import styles from './CategoryPlus.style'; +import styles from './CategoryAdd.style'; import {theme} from '../../styles'; import {IcNoti, IcNotiColor} from '../../assets/icon'; import {usePostAddCategory} from '../../hooks/mutations/category/usePostCategoryAdd'; @@ -16,8 +16,8 @@ import {StackScreenProps} from '../../navigators/types'; import {useQueryClient} from '@tanstack/react-query'; import {CATEGORY_KEYS} from '../../hooks/queries/QueryKeys'; -type CategoryPlusProps = StackScreenProps<'CategoryPlus'>; -export default function CategoryPlus({navigation}: CategoryPlusProps) { +type CategoryAddProps = StackScreenProps<'CategoryAdd'>; +export default function CategoryAdd({navigation}: CategoryAddProps) { const nameInputRef = useRef(null); const memoInputRef = useRef(null); diff --git a/src/screens/CategoryList/CategoryList.tsx b/src/screens/CategoryList/CategoryList.tsx index 424d91f..d3e1a23 100644 --- a/src/screens/CategoryList/CategoryList.tsx +++ b/src/screens/CategoryList/CategoryList.tsx @@ -9,8 +9,11 @@ import { } from 'react-native'; import {StackScreenProps} from '../../navigators/types'; import {styles} from './CategoryList.style'; -import {IcLeft, IcCategoryRest} from '../../assets/icon'; -import {COLOR_MAP, ICON_MAPS} from '../../constants/components/CategoryCard'; +import {IcLeft, IcRoundEtc} from '../../assets/icon'; +import { + COLOR_DETAIL_MAP, + ICON_DETAIL_MAPS, +} from '../../constants/components/CategoryCard'; import {theme} from '../../styles'; import {wrapper} from '../../styles/common'; import PlaceDetail from '../../components/common/PlaceDetail/PlaceDetail'; @@ -22,8 +25,8 @@ type CategoryListProps = StackScreenProps<'CategoryList'>; export default function CategoryList({navigation, route}: CategoryListProps) { const {title, description} = route.params; - const backgroundColor = COLOR_MAP[title] || theme.palette.gray1; - const IconComponent = ICON_MAPS[title] || IcCategoryRest; + const backgroundColor = COLOR_DETAIL_MAP[title] || theme.palette.gray1; + const IconComponent = ICON_DETAIL_MAPS[title] || IcRoundEtc; const {data, loadMore, isFetching, hasNextPage, totalElement} = useGetCategoryList({ diff --git a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx index 034a36c..150d98e 100644 --- a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx +++ b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx @@ -70,7 +70,7 @@ export default function CategoryTab({navigation}: CategoryTabProps) { navigation.navigate('CategoryPlus')}> + onPress={() => navigation.navigate('CategoryAdd')}> 카테고리 추가 From 902a3931cf84aba06a547082578dab62afcf0d09 Mon Sep 17 00:00:00 2001 From: "lky062@naver.com" Date: Tue, 3 Sep 2024 01:39:34 +0900 Subject: [PATCH 4/9] =?UTF-8?q?[SKP-168]=20feat=20:=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20=EC=82=AD=EC=A0=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icon/ic_card_etc.svg | 9 +++++ src/assets/icon/index.ts | 1 + src/components/common/Header/CustomHeader.tsx | 36 +++++++++++++++++++ .../mutations/category/useDeleteCategory.ts | 22 ++++++++++++ .../CategoryList/CategoryList.style.ts | 1 - src/screens/CategoryList/CategoryList.tsx | 30 ++++++++++++++++ .../TabNavigator/CategoryTab/CategoryTab.tsx | 6 ++-- 7 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 src/assets/icon/ic_card_etc.svg create mode 100644 src/components/common/Header/CustomHeader.tsx create mode 100644 src/hooks/mutations/category/useDeleteCategory.ts diff --git a/src/assets/icon/ic_card_etc.svg b/src/assets/icon/ic_card_etc.svg new file mode 100644 index 0000000..08142e5 --- /dev/null +++ b/src/assets/icon/ic_card_etc.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/icon/index.ts b/src/assets/icon/index.ts index b5c64f6..bfbb4dc 100644 --- a/src/assets/icon/index.ts +++ b/src/assets/icon/index.ts @@ -26,6 +26,7 @@ export {default as IcCardFood} from './ic_card_food.svg'; export {default as IcCardHistory} from './ic_card_history.svg'; export {default as IcCardNature} from './ic_card_nature.svg'; export {default as IcCardRest} from './ic_card_rest.svg'; +export {default as IcCardEtc} from './ic_card_etc.svg'; export {default as IcCardShopping} from './ic_card_shopping.svg'; export {default as IcRight} from './ic_right.svg'; diff --git a/src/components/common/Header/CustomHeader.tsx b/src/components/common/Header/CustomHeader.tsx new file mode 100644 index 0000000..e91a385 --- /dev/null +++ b/src/components/common/Header/CustomHeader.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import {View, Text, TouchableOpacity} from 'react-native'; +import {IcLeft} from '../../../assets/icon'; +import useNavigator from '../../../navigators/hooks/useNavigator'; +import {useDeleteCategory} from '../../../hooks/mutations/category/useDeleteCategory'; + +/** + * [커스텀 헤더 보류] + * 타이틀 전달받고 카테고리 목록 조회다시 호출해서 거기서 + * 타이틀이랑 비교해서 아이디값을 저장하고 delete할 때 그 아이디값을 보낸다 + * 결국 아이디 값을 전역으로 가지고 있어야 필터링이 가능 + */ +export default function CustomHeader() { + const {stackNavigation} = useNavigator(); + const {mutate: deleteCategory} = useDeleteCategory(); + + return ( + + stackNavigation.goBack()}> + + + + + 삭제 + + + ); +} diff --git a/src/hooks/mutations/category/useDeleteCategory.ts b/src/hooks/mutations/category/useDeleteCategory.ts new file mode 100644 index 0000000..e840bdc --- /dev/null +++ b/src/hooks/mutations/category/useDeleteCategory.ts @@ -0,0 +1,22 @@ +import {useMutation} from '@tanstack/react-query'; +import {DELETE} from '../../../apis/client'; + +interface DeleteCategoryRequest { + userCategoryId: number; +} + +/** + * 명소 삭제 + */ +export const deleteCategory = async ({ + userCategoryId, +}: DeleteCategoryRequest) => { + const res = await DELETE(`/api/user-category/${userCategoryId}`); + return res.data; +}; + +export const useDeleteCategory = () => { + return useMutation({ + mutationFn: (req: DeleteCategoryRequest) => deleteCategory(req), + }); +}; diff --git a/src/screens/CategoryList/CategoryList.style.ts b/src/screens/CategoryList/CategoryList.style.ts index 5f15a2b..f545fa8 100644 --- a/src/screens/CategoryList/CategoryList.style.ts +++ b/src/screens/CategoryList/CategoryList.style.ts @@ -3,7 +3,6 @@ import {theme} from '../../styles'; export const styles = StyleSheet.create({ headerContainer: { - paddingTop: 80, alignItems: 'center', paddingVertical: 30, backgroundColor: theme.palette.secondary, diff --git a/src/screens/CategoryList/CategoryList.tsx b/src/screens/CategoryList/CategoryList.tsx index d3e1a23..e249923 100644 --- a/src/screens/CategoryList/CategoryList.tsx +++ b/src/screens/CategoryList/CategoryList.tsx @@ -19,6 +19,9 @@ import {wrapper} from '../../styles/common'; import PlaceDetail from '../../components/common/PlaceDetail/PlaceDetail'; import useGetCategoryList from '../../hooks/queries/category/useGetCategoryDetail'; import {UserLocation} from '../../types/dtos/location'; +import {useDeleteCategory} from '../../hooks/mutations/category/useDeleteCategory'; +import {useQueryClient} from '@tanstack/react-query'; +import {CATEGORY_KEYS} from '../../hooks/queries/QueryKeys'; type CategoryListProps = StackScreenProps<'CategoryList'>; @@ -49,10 +52,37 @@ export default function CategoryList({navigation, route}: CategoryListProps) { navigation.navigate('TabNavigator'); } + const {mutate: deleteCategory} = useDeleteCategory(); + const queryClient = useQueryClient(); + + function handleDeleteCategory() { + if (data && data.length > 0) { + const userCategoryId = data[0].userCategory.id; + + deleteCategory( + {userCategoryId}, + { + onSuccess: () => { + navigation.navigate('TabNavigator'); + queryClient.invalidateQueries({ + queryKey: CATEGORY_KEYS.all, + }); + }, + onError: error => { + console.error('Failed to delete category:', error); + }, + }, + ); + } + } + return ( + + 삭제 + diff --git a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx index 150d98e..62a8e49 100644 --- a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx +++ b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx @@ -3,7 +3,7 @@ import styles from './CategoryTab.style'; import {View, Text, FlatList, TouchableOpacity} from 'react-native'; import Card from '../../../components/common/Category/CategoryCard/CategoryCard'; import {theme} from '../../../styles'; -import {IcCardRest, IcPlus} from '../../../assets/icon'; +import {IcCardEtc, IcCardRest, IcPlus} from '../../../assets/icon'; import {useGetCategoryListQuery} from '../../../hooks/queries/category/useGetCategoryList'; import { COLOR_MAP, @@ -20,8 +20,8 @@ export default function CategoryTab({navigation}: CategoryTabProps) { const mappedData = cardListData.map(item => ({ title: item.name, description: item.description, - IconComponent: ICON_MAPS[item.name] || IcCardRest, - backgroundColor: COLOR_MAP[item.name] || theme.palette.white, + IconComponent: ICON_MAPS[item.name] || IcCardEtc, + backgroundColor: COLOR_MAP[item.name] || theme.palette.primary, })); const snapToOffsets = useMemo( From b4808f5901c884d865511213db457752c3492f77 Mon Sep 17 00:00:00 2001 From: "lky062@naver.com" Date: Tue, 3 Sep 2024 01:42:34 +0900 Subject: [PATCH 5/9] =?UTF-8?q?[SKP-168]=20chore=20:=20=ED=97=A4=EB=8D=94?= =?UTF-8?q?=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/screens/CategoryList/CategoryList.style.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/screens/CategoryList/CategoryList.style.ts b/src/screens/CategoryList/CategoryList.style.ts index f545fa8..d8c2546 100644 --- a/src/screens/CategoryList/CategoryList.style.ts +++ b/src/screens/CategoryList/CategoryList.style.ts @@ -1,5 +1,6 @@ import {StyleSheet} from 'react-native'; import {theme} from '../../styles'; +import {flexBox} from '../../styles/common'; export const styles = StyleSheet.create({ headerContainer: { @@ -11,6 +12,8 @@ export const styles = StyleSheet.create({ marginBottom: 16, }, backIcon: { + width: '95%', + ...flexBox('row', 'space-between'), position: 'absolute', zIndex: 9, top: 70, From 55ff1610bfbc67e1a6a39c7bca1aeb539e292790 Mon Sep 17 00:00:00 2001 From: "lky062@naver.com" Date: Tue, 3 Sep 2024 20:34:31 +0900 Subject: [PATCH 6/9] =?UTF-8?q?[SKP-168]=20feat=20:=20=EC=97=AC=ED=96=89?= =?UTF-8?q?=EC=A7=80=200=EA=B0=9C=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icon/ic_empty.svg | 13 +++++++ src/assets/icon/index.ts | 1 + .../Category/EmptyCategoryList.style.ts | 37 +++++++++++++++++++ src/components/Category/EmptyCategoryList.tsx | 25 +++++++++++++ src/screens/CategoryList/CategoryList.tsx | 7 +++- 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/assets/icon/ic_empty.svg create mode 100644 src/components/Category/EmptyCategoryList.style.ts create mode 100644 src/components/Category/EmptyCategoryList.tsx diff --git a/src/assets/icon/ic_empty.svg b/src/assets/icon/ic_empty.svg new file mode 100644 index 0000000..4cc819c --- /dev/null +++ b/src/assets/icon/ic_empty.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/assets/icon/index.ts b/src/assets/icon/index.ts index bfbb4dc..ee25c21 100644 --- a/src/assets/icon/index.ts +++ b/src/assets/icon/index.ts @@ -41,6 +41,7 @@ export {default as IcAnalyze} from './ic_analyze.svg'; export {default as IcPlus} from './ic_plus.svg'; export {default as IcNoti} from './ic_noti.svg'; export {default as IcNotiColor} from './ic_noti_color.svg'; +export {default as IcEmpty} from './ic_empty.svg'; export {default as IcRoundActivity} from './ic_round_activity.svg'; export {default as IcRoundFestival} from './ic_round_festival.svg'; diff --git a/src/components/Category/EmptyCategoryList.style.ts b/src/components/Category/EmptyCategoryList.style.ts new file mode 100644 index 0000000..51b29cd --- /dev/null +++ b/src/components/Category/EmptyCategoryList.style.ts @@ -0,0 +1,37 @@ +import {StyleSheet} from 'react-native'; +import {theme} from '../../styles'; +import {flexBox} from '../../styles/common'; + +export const styles = StyleSheet.create({ + emptyContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + padding: 20, + }, + emptyIconContainer: { + marginBottom: 20, + }, + emptyText: { + ...theme.typography.body_sb_17, + color: theme.palette.black, + marginBottom: 10, + }, + emptySubText: { + ...theme.typography.text_m_13, + color: theme.palette.gray5, + textAlign: 'center', + marginBottom: 30, + }, + addButton: { + ...flexBox('row', 'center', 'center'), + backgroundColor: theme.palette.primary, + paddingVertical: 10, + paddingHorizontal: 20, + borderRadius: 30, + }, + addButtonText: { + ...theme.typography.button_sb_15, + color: theme.palette.white, + }, +}); diff --git a/src/components/Category/EmptyCategoryList.tsx b/src/components/Category/EmptyCategoryList.tsx new file mode 100644 index 0000000..78e62d5 --- /dev/null +++ b/src/components/Category/EmptyCategoryList.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import {View, Text, TouchableOpacity} from 'react-native'; +import {IcEmpty, IcPlus} from '../../assets/icon'; +import useAnalyze from '../../hooks/useAnalyze'; +import {styles} from './EmptyCategoryList.style'; + +export default function EmptyCategoryList() { + const {handleGoToGallery} = useAnalyze(); + + return ( + + + + + 아직 저장된 여행지가 없어요! + + 여행지 정보가 담긴 스크린샷을 선택해주세요 + + + + 여행지 추가 + + + ); +} diff --git a/src/screens/CategoryList/CategoryList.tsx b/src/screens/CategoryList/CategoryList.tsx index e249923..96234b0 100644 --- a/src/screens/CategoryList/CategoryList.tsx +++ b/src/screens/CategoryList/CategoryList.tsx @@ -6,10 +6,11 @@ import { ActivityIndicator, SafeAreaView, TouchableOpacity, + StyleSheet, } from 'react-native'; import {StackScreenProps} from '../../navigators/types'; import {styles} from './CategoryList.style'; -import {IcLeft, IcRoundEtc} from '../../assets/icon'; +import {IcEmpty, IcLeft, IcRoundEtc} from '../../assets/icon'; import { COLOR_DETAIL_MAP, ICON_DETAIL_MAPS, @@ -22,11 +23,14 @@ import {UserLocation} from '../../types/dtos/location'; import {useDeleteCategory} from '../../hooks/mutations/category/useDeleteCategory'; import {useQueryClient} from '@tanstack/react-query'; import {CATEGORY_KEYS} from '../../hooks/queries/QueryKeys'; +import useAnalyze from '../../hooks/useAnalyze'; +import EmptyCategoryList from '../../components/Category/EmptyCategoryList'; type CategoryListProps = StackScreenProps<'CategoryList'>; export default function CategoryList({navigation, route}: CategoryListProps) { const {title, description} = route.params; + const {handleGoToGallery} = useAnalyze(); const backgroundColor = COLOR_DETAIL_MAP[title] || theme.palette.gray1; const IconComponent = ICON_DETAIL_MAPS[title] || IcRoundEtc; @@ -107,6 +111,7 @@ export default function CategoryList({navigation, route}: CategoryListProps) { ) : null } + ListEmptyComponent={EmptyCategoryList} /> ); From f67bc09d5128dd16914bad46be5eba28755e4c11 Mon Sep 17 00:00:00 2001 From: "lky062@naver.com" Date: Wed, 4 Sep 2024 01:01:50 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[SKP-168]=20feat=20:=20=EA=B8=80=EC=9E=90?= =?UTF-8?q?=EC=88=98=20=EC=B2=B4=ED=81=AC=20=EB=B0=8F=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=ED=97=A4=EB=8D=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/navigators/StackNavigator.tsx | 17 ++++++++++++++++- src/screens/CategoryAdd/CategoryAdd.style.ts | 6 +++++- src/screens/CategoryAdd/CategoryAdd.tsx | 20 ++++++++++++++++++-- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/navigators/StackNavigator.tsx b/src/navigators/StackNavigator.tsx index 18fabaa..0971ab7 100644 --- a/src/navigators/StackNavigator.tsx +++ b/src/navigators/StackNavigator.tsx @@ -12,6 +12,8 @@ import Login from '../screens/Login/Login'; import Withdraw from '../screens/Withdraw/Withdraw'; import CategoryList from '../screens/CategoryList/CategoryList'; import CategoryAdd from '../screens/CategoryAdd/CategoryAdd'; +import {TouchableOpacity} from 'react-native'; +import {IcLeft} from '../assets/icon'; const Stack = createNativeStackNavigator(); @@ -40,7 +42,20 @@ export default function StackNavigator() { {/* 카테고리 리스트 */} - + ({ + headerShown: true, + title: '', + headerLeft: () => ( + navigation.goBack()}> + + + ), + })} + /> + {/* 장소 상세 */} diff --git a/src/screens/CategoryAdd/CategoryAdd.style.ts b/src/screens/CategoryAdd/CategoryAdd.style.ts index 5ed61a8..b14448f 100644 --- a/src/screens/CategoryAdd/CategoryAdd.style.ts +++ b/src/screens/CategoryAdd/CategoryAdd.style.ts @@ -1,9 +1,10 @@ import {StyleSheet} from 'react-native'; import {theme} from '../../styles'; +import {flexBox} from '../../styles/common'; const styles = StyleSheet.create({ container: { - paddingTop: 100, + paddingTop: 20, flex: 1, backgroundColor: theme.palette.white, alignItems: 'center', @@ -36,6 +37,9 @@ const styles = StyleSheet.create({ fontSize: 16, color: theme.palette.black, }, + countContainer: { + ...flexBox('row', 'space-between'), + }, charCount: { fontSize: 12, color: theme.palette.gray5, diff --git a/src/screens/CategoryAdd/CategoryAdd.tsx b/src/screens/CategoryAdd/CategoryAdd.tsx index 25ec6d8..4a55d48 100644 --- a/src/screens/CategoryAdd/CategoryAdd.tsx +++ b/src/screens/CategoryAdd/CategoryAdd.tsx @@ -118,7 +118,13 @@ export default function CategoryAdd({navigation}: CategoryAddProps) { value={nameValue} onChangeText={setNameValue} /> - 0/12 + + {`${nameValue.length}/12`} + @@ -136,9 +142,19 @@ export default function CategoryAdd({navigation}: CategoryAddProps) { placeholderTextColor={theme.palette.gray5} onFocus={handleMemoInputFocus} value={memoValue} + maxLength={22} onChangeText={setMemoValue} /> - {currentFocus === 'memo' ? : } + + {currentFocus === 'memo' ? : } + + {`${memoValue.length}/22`} + + From 5b8ee98f74cd2a29adb3cafb0511eab8b53d0cf8 Mon Sep 17 00:00:00 2001 From: "lky062@naver.com" Date: Wed, 4 Sep 2024 01:40:48 +0900 Subject: [PATCH 8/9] =?UTF-8?q?[SKP-168]=20chore=20:=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20ID=EA=B0=92=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icon/ic_delete.svg | 16 +++++ src/assets/icon/index.ts | 1 + src/navigators/types/index.ts | 2 +- .../CategoryList/CategoryList.style.ts | 3 + src/screens/CategoryList/CategoryList.tsx | 64 ++++++++++--------- .../TabNavigator/CategoryTab/CategoryTab.tsx | 4 +- src/types/components/category/category.ts | 1 + 7 files changed, 59 insertions(+), 32 deletions(-) create mode 100644 src/assets/icon/ic_delete.svg diff --git a/src/assets/icon/ic_delete.svg b/src/assets/icon/ic_delete.svg new file mode 100644 index 0000000..d553e33 --- /dev/null +++ b/src/assets/icon/ic_delete.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/icon/index.ts b/src/assets/icon/index.ts index ee25c21..7bd10ab 100644 --- a/src/assets/icon/index.ts +++ b/src/assets/icon/index.ts @@ -42,6 +42,7 @@ export {default as IcPlus} from './ic_plus.svg'; export {default as IcNoti} from './ic_noti.svg'; export {default as IcNotiColor} from './ic_noti_color.svg'; export {default as IcEmpty} from './ic_empty.svg'; +export {default as IcDelete} from './ic_delete.svg'; export {default as IcRoundActivity} from './ic_round_activity.svg'; export {default as IcRoundFestival} from './ic_round_festival.svg'; diff --git a/src/navigators/types/index.ts b/src/navigators/types/index.ts index 23df0ad..4a89691 100644 --- a/src/navigators/types/index.ts +++ b/src/navigators/types/index.ts @@ -25,7 +25,7 @@ export type StackParamList = { ReAnalyze: {history: AnalyzeLocationResponse; request: ReanalyzeRequest}; Detail: {id: number}; - CategoryList: {title: string; description: string}; + CategoryList: {title: string; description: string; id: number}; CategoryAdd: undefined; }; diff --git a/src/screens/CategoryList/CategoryList.style.ts b/src/screens/CategoryList/CategoryList.style.ts index d8c2546..94912b8 100644 --- a/src/screens/CategoryList/CategoryList.style.ts +++ b/src/screens/CategoryList/CategoryList.style.ts @@ -8,6 +8,9 @@ export const styles = StyleSheet.create({ paddingVertical: 30, backgroundColor: theme.palette.secondary, }, + modalIcon: { + marginBottom: 10, + }, icon: { marginBottom: 16, }, diff --git a/src/screens/CategoryList/CategoryList.tsx b/src/screens/CategoryList/CategoryList.tsx index 96234b0..3d86529 100644 --- a/src/screens/CategoryList/CategoryList.tsx +++ b/src/screens/CategoryList/CategoryList.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useState} from 'react'; import { View, Text, @@ -6,11 +6,10 @@ import { ActivityIndicator, SafeAreaView, TouchableOpacity, - StyleSheet, } from 'react-native'; import {StackScreenProps} from '../../navigators/types'; import {styles} from './CategoryList.style'; -import {IcEmpty, IcLeft, IcRoundEtc} from '../../assets/icon'; +import {IcDelete, IcLeft, IcRoundEtc} from '../../assets/icon'; import { COLOR_DETAIL_MAP, ICON_DETAIL_MAPS, @@ -23,18 +22,19 @@ import {UserLocation} from '../../types/dtos/location'; import {useDeleteCategory} from '../../hooks/mutations/category/useDeleteCategory'; import {useQueryClient} from '@tanstack/react-query'; import {CATEGORY_KEYS} from '../../hooks/queries/QueryKeys'; -import useAnalyze from '../../hooks/useAnalyze'; import EmptyCategoryList from '../../components/Category/EmptyCategoryList'; +import Modal from '../../components/common/Modal/Modal'; type CategoryListProps = StackScreenProps<'CategoryList'>; export default function CategoryList({navigation, route}: CategoryListProps) { - const {title, description} = route.params; - const {handleGoToGallery} = useAnalyze(); - + const {title, description, id} = route.params; + const [modalVisible, setModalVisible] = useState(false); + const queryClient = useQueryClient(); const backgroundColor = COLOR_DETAIL_MAP[title] || theme.palette.gray1; const IconComponent = ICON_DETAIL_MAPS[title] || IcRoundEtc; + const {mutate: deleteCategory} = useDeleteCategory(); const {data, loadMore, isFetching, hasNextPage, totalElement} = useGetCategoryList({ userCategory: title, @@ -53,38 +53,31 @@ export default function CategoryList({navigation, route}: CategoryListProps) { ); function handleGoBack() { - navigation.navigate('TabNavigator'); + navigation.goBack(); } - - const {mutate: deleteCategory} = useDeleteCategory(); - const queryClient = useQueryClient(); - function handleDeleteCategory() { - if (data && data.length > 0) { - const userCategoryId = data[0].userCategory.id; - - deleteCategory( - {userCategoryId}, - { - onSuccess: () => { - navigation.navigate('TabNavigator'); - queryClient.invalidateQueries({ - queryKey: CATEGORY_KEYS.all, - }); - }, - onError: error => { - console.error('Failed to delete category:', error); - }, + const userCategoryId = id; + deleteCategory( + {userCategoryId}, + { + onSuccess: () => { + navigation.navigate('TabNavigator'); + queryClient.invalidateQueries({ + queryKey: CATEGORY_KEYS.all, + }); + }, + onError: error => { + console.error('카테고리 삭제 실패 :', error); }, - ); - } + }, + ); } return ( - + setModalVisible(true)}> 삭제 @@ -113,6 +106,17 @@ export default function CategoryList({navigation, route}: CategoryListProps) { } ListEmptyComponent={EmptyCategoryList} /> + + setModalVisible(false)} + onConfirm={handleDeleteCategory} + IconComponent={} + modalTitle="카테고리를 삭제하시겠어요?" + modalSubtitle={`삭제하면 다시 복구할 수 없어요!`} + modalButtonCancelText="놔둘래요" + modalButtonConfirmText="삭제할래요" + /> ); } diff --git a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx index 62a8e49..4139b2e 100644 --- a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx +++ b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx @@ -3,7 +3,7 @@ import styles from './CategoryTab.style'; import {View, Text, FlatList, TouchableOpacity} from 'react-native'; import Card from '../../../components/common/Category/CategoryCard/CategoryCard'; import {theme} from '../../../styles'; -import {IcCardEtc, IcCardRest, IcPlus} from '../../../assets/icon'; +import {IcCardEtc, IcPlus} from '../../../assets/icon'; import {useGetCategoryListQuery} from '../../../hooks/queries/category/useGetCategoryList'; import { COLOR_MAP, @@ -20,6 +20,7 @@ export default function CategoryTab({navigation}: CategoryTabProps) { const mappedData = cardListData.map(item => ({ title: item.name, description: item.description, + id: item.id, IconComponent: ICON_MAPS[item.name] || IcCardEtc, backgroundColor: COLOR_MAP[item.name] || theme.palette.primary, })); @@ -34,6 +35,7 @@ export default function CategoryTab({navigation}: CategoryTabProps) { navigation.navigate('CategoryList', { title: item.title, description: item.description, + id: item.id, }); }; diff --git a/src/types/components/category/category.ts b/src/types/components/category/category.ts index f6e6284..56ad3a3 100644 --- a/src/types/components/category/category.ts +++ b/src/types/components/category/category.ts @@ -10,5 +10,6 @@ export interface CardData { backgroundColor: string; title: string; description: string; + id: number; IconComponent: React.ComponentType<{}>; } From 3098fa2e5aba2064fb96dea1e5c9fea96bd275d7 Mon Sep 17 00:00:00 2001 From: "lky062@naver.com" Date: Wed, 4 Sep 2024 13:50:56 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[SKP-168]=20fix=20:=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20ID=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mutations/category/usePostCategoryAdd.ts | 7 ++++- .../queries/category/useGetCategoryDetail.ts | 16 ++++++---- src/screens/CategoryAdd/CategoryAdd.tsx | 30 ++++++++++++++----- src/screens/CategoryList/CategoryList.tsx | 2 +- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/hooks/mutations/category/usePostCategoryAdd.ts b/src/hooks/mutations/category/usePostCategoryAdd.ts index ba6c7e0..640b0cf 100644 --- a/src/hooks/mutations/category/usePostCategoryAdd.ts +++ b/src/hooks/mutations/category/usePostCategoryAdd.ts @@ -11,7 +11,12 @@ export interface ICategoryData { */ export const addCategory = async (data: ICategoryData) => { const res = await POST(`/api/user-category`, data); - return res.data; + const locationHeader = res.headers['location']; + console.log('headers', locationHeader); + return { + data: res.data, + locationHeader, + }; }; export const usePostAddCategory = () => { diff --git a/src/hooks/queries/category/useGetCategoryDetail.ts b/src/hooks/queries/category/useGetCategoryDetail.ts index 6968645..292a30a 100644 --- a/src/hooks/queries/category/useGetCategoryDetail.ts +++ b/src/hooks/queries/category/useGetCategoryDetail.ts @@ -6,25 +6,29 @@ import {UserLocation} from '../../../types/dtos/location'; import {IPage} from '../../../types/dtos/category'; export interface GetPostHistoryRequest { - userCategory: string; + userCategoryId: number; page: number; } -const getCategoryList = async ({userCategory, page}: GetPostHistoryRequest) => { +const getCategoryList = async ({ + userCategoryId, + page, +}: GetPostHistoryRequest) => { const { data: {result}, } = await GET>('/api/user-location', { params: { page, - userCategory, + userCategoryId, }, }); + console.log(userCategoryId); return { items: result.userLocationList, nextPage: result.totalPage > page ? page + 1 : undefined, totalPage: result.totalPage, - totalElement: result.totalElement, + totalElement: result.totalElement, }; }; @@ -36,7 +40,7 @@ const useGetCategoryList = (requestParams: GetPostHistoryRequest) => { getNextPageParam: lastPage => lastPage.nextPage, select: data => ({ pages: data.pages.flatMap(page => page.items), - totalElement: data.pages?.[0]?.totalElement ?? 0, + totalElement: data.pages?.[0]?.totalElement ?? 0, }), initialPageParam: requestParams.page, }); @@ -52,7 +56,7 @@ const useGetCategoryList = (requestParams: GetPostHistoryRequest) => { loadMore, isFetching, hasNextPage, - totalElement: data?.totalElement, + totalElement: data?.totalElement, }; }; diff --git a/src/screens/CategoryAdd/CategoryAdd.tsx b/src/screens/CategoryAdd/CategoryAdd.tsx index 4a55d48..a55c06b 100644 --- a/src/screens/CategoryAdd/CategoryAdd.tsx +++ b/src/screens/CategoryAdd/CategoryAdd.tsx @@ -76,23 +76,37 @@ export default function CategoryAdd({navigation}: CategoryAddProps) { description: memoValue || ' ', }, { - onSuccess: () => { - console.log('Category added successfully!'); - navigation.replace('CategoryList', { - title: nameValue, - description: memoValue, - }); + onSuccess: response => { + console.log('=====카테고리 추가 성공====='); + const locationHeader = response.locationHeader; + + const userCategoryIdMatch = + locationHeader.match(/userCategoryId=(\d+)/); + const userCategoryId = userCategoryIdMatch + ? userCategoryIdMatch[1] + : null; + + if (userCategoryId) { + navigation.replace('CategoryList', { + title: nameValue, + description: memoValue, + id: userCategoryId, + }); + } else { + console.error('카테고리ID 추출 실패'); + } + queryClient.invalidateQueries({ queryKey: CATEGORY_KEYS.all, }); }, onError: error => { - console.error('Error adding category:', error); + console.error('카테고리 추가 실패 :', error); }, }, ); }; - + return ( 원하는 카테고리를 만들어주세요 diff --git a/src/screens/CategoryList/CategoryList.tsx b/src/screens/CategoryList/CategoryList.tsx index 3d86529..8b8333a 100644 --- a/src/screens/CategoryList/CategoryList.tsx +++ b/src/screens/CategoryList/CategoryList.tsx @@ -37,7 +37,7 @@ export default function CategoryList({navigation, route}: CategoryListProps) { const {mutate: deleteCategory} = useDeleteCategory(); const {data, loadMore, isFetching, hasNextPage, totalElement} = useGetCategoryList({ - userCategory: title, + userCategoryId: id, page: 1, });