From 764ddd9a44cddd232823598796c2b14b5c18549c Mon Sep 17 00:00:00 2001 From: dioo1461 Date: Fri, 6 Feb 2026 21:24:33 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=EB=82=B4=EA=B0=80=20=EB=A7=8C?= =?UTF-8?q?=EB=93=A0=20=EB=AA=A9=ED=91=9C=EC=99=80=20=EA=B7=B8=EB=A3=B9?= =?UTF-8?q?=EC=97=90=20=EC=86=8D=ED=95=9C=20=EB=AA=A9=ED=91=9C=EB=A5=BC=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../category/hooks/useCategoryColor.ts | 5 +- .../ui/InlineCategoryItem/index.style.ts | 2 +- src/features/groups/hooks/useGroupColorKey.ts | 72 +++++++----- src/hooks/useCategoryData.ts | 33 ++++++ src/locales/ko/manageCategory.json | 3 +- .../components/JoinedGroupPanel/index.tsx | 7 +- .../components/CategoryItem/index.style.ts | 2 +- .../GroupCategoryItem/index.style.ts | 51 +++++++++ .../components/GroupCategoryItem/index.tsx | 108 ++++++++++++++++++ .../ManageCategoryScreen/index.style.ts | 2 +- .../category/ManageCategoryScreen/index.tsx | 44 +++++-- .../groupDetail/GroupDetailScreen/index.tsx | 8 +- .../DashBoardButtonGroup/index.tsx | 6 +- src/store/studySlice.ts | 1 + 14 files changed, 296 insertions(+), 48 deletions(-) create mode 100644 src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.style.ts create mode 100644 src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx diff --git a/src/features/category/hooks/useCategoryColor.ts b/src/features/category/hooks/useCategoryColor.ts index 303e0432..55ff9a5d 100644 --- a/src/features/category/hooks/useCategoryColor.ts +++ b/src/features/category/hooks/useCategoryColor.ts @@ -1,7 +1,7 @@ import { type GroupColorKey } from '@/constants/groupColors'; import { useGroupsQuery } from '@/features/groups/api/queries'; -import { useGroupColorKey } from '@/features/groups/hooks/useGroupColorKey'; +import { useGroupColorKeyMap } from '@/features/groups/hooks/useGroupColorKey'; import { theme } from '@/theme'; const DEFAULT_COLOR_KEY: GroupColorKey = theme.color.primary[500]; @@ -12,7 +12,8 @@ export const useCategoryColor = (categoryId: number) => { const matchingGroupId = groupsData?.find((g) => g.categoryIds.includes(categoryId))?.groupId ?? null; - const { colorKey: groupColor } = useGroupColorKey(matchingGroupId); + const { colorKeyMap } = useGroupColorKeyMap(); + const groupColor = matchingGroupId ? colorKeyMap.get(matchingGroupId) : null; const colorKey = groupColor ?? DEFAULT_COLOR_KEY; return { colorKey }; diff --git a/src/features/category/ui/InlineCategoryItem/index.style.ts b/src/features/category/ui/InlineCategoryItem/index.style.ts index f3355dc4..be3fa861 100644 --- a/src/features/category/ui/InlineCategoryItem/index.style.ts +++ b/src/features/category/ui/InlineCategoryItem/index.style.ts @@ -9,7 +9,7 @@ export const styles = StyleSheet.create({ container: { flexDirection: 'row', alignItems: 'center', - gap: theme.spacing[100], + gap: theme.spacing[200], }, }); diff --git a/src/features/groups/hooks/useGroupColorKey.ts b/src/features/groups/hooks/useGroupColorKey.ts index 4e546ea8..ccb81933 100644 --- a/src/features/groups/hooks/useGroupColorKey.ts +++ b/src/features/groups/hooks/useGroupColorKey.ts @@ -1,11 +1,15 @@ -import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useQueries, useQueryClient } from '@tanstack/react-query'; +import { useCallback, useMemo } from 'react'; import type { GroupColorKey } from '@/constants/groupColors'; import { GROUP_COLORS } from '@/constants/groupColors'; import { useProfileQuery } from '@/features/user/api/queries'; import { ASYNC_KEYS, asyncStorage } from '@/utils/asyncStorage'; +import { useGroupsQuery } from '../api/queries'; + const GROUP_COLOR_KEYS = Object.keys(GROUP_COLORS) as GroupColorKey[]; +const queryKey = (userId: number | null, groupId: number) => ['groupColor', userId, groupId]; const pickRandomGroupColorKey = (): GroupColorKey => GROUP_COLOR_KEYS[Math.floor(Math.random() * GROUP_COLOR_KEYS.length)]; @@ -13,38 +17,54 @@ const pickRandomGroupColorKey = (): GroupColorKey => const isGroupColorKey = (v: string): v is GroupColorKey => (GROUP_COLOR_KEYS as readonly string[]).includes(v); -export const useGroupColorKey = (groupId: number | null) => { - const { data: profileData } = useProfileQuery(); - const userId = profileData?.id; +export const useGroupColorKeyMap = () => { + const groups = useGroupsQuery().data; + const groupIds = useMemo( + () => Array.from(new Set(groups?.map(g => g.groupId))).sort((a, b) => a - b), + [groups], + ); + const userId = useProfileQuery().data?.id ?? null; const qc = useQueryClient(); - const queryKey = ['groupColor', userId, groupId]; - - const { data: colorKey } = useQuery({ - queryKey, - enabled: userId != null && groupId != null, - queryFn: async () => { - if (userId == null || groupId == null) return null; + const results = useQueries({ + queries: groupIds.map((groupId) => ({ + queryKey: queryKey(userId, groupId), + enabled: userId != null && groupId != null, + queryFn: async (): Promise => { + if (userId == null) return null; + const storageKey = ASYNC_KEYS.groupColor(userId, groupId); + const stored = await asyncStorage.get(storageKey); - const storageKey = ASYNC_KEYS.groupColor(userId, groupId); - const stored = await asyncStorage.get(storageKey); + if (stored && isGroupColorKey(stored)) return stored; - if (stored && isGroupColorKey(stored)) return stored; + const newKey = pickRandomGroupColorKey(); + await asyncStorage.set(storageKey, newKey); + return newKey; + }, + staleTime: Infinity, + gcTime: Infinity, + })), + }); - const newKey = pickRandomGroupColorKey(); - await asyncStorage.set(storageKey, newKey); - return newKey; - }, - staleTime: Infinity, - gcTime: Infinity, + const colorKeyMap = new Map(); + groupIds.forEach((groupId, idx) => { + const colorKey = results[idx]?.data ?? null; + if (colorKey) colorKeyMap.set(groupId, colorKey); }); - const updateColorKey = async (next: GroupColorKey) => { - if (userId == null || groupId == null) return; + const updateColorKey = useCallback( + async (groupId: number, next: GroupColorKey) => { + if (userId == null) return; + qc.setQueryData(queryKey(userId, groupId), next); + await asyncStorage.set(ASYNC_KEYS.groupColor(userId, groupId), next); + }, + [qc, userId], + ); - qc.setQueryData(queryKey, next); - await asyncStorage.set(ASYNC_KEYS.groupColor(userId, groupId), next); + return { + colorKeyMap: colorKeyMap, + updateColorKey, + isReady: userId != null, }; - - return { colorKey: colorKey ?? null, updateColorKey }; }; + diff --git a/src/hooks/useCategoryData.ts b/src/hooks/useCategoryData.ts index 4b8989a7..f0819f27 100644 --- a/src/hooks/useCategoryData.ts +++ b/src/hooks/useCategoryData.ts @@ -1,4 +1,8 @@ +import type { GroupColorKey } from '@/constants/groupColors'; import { useCategoriesQuery } from '@/features/category/api/queries'; +import type { GetCategoriesResponse } from '@/features/category/model'; +import { useGroupsQuery } from '@/features/groups/api/queries'; +import { useGroupColorKeyMap } from '@/features/groups/hooks/useGroupColorKey'; import { useStudyStatByDateQuery } from '@/features/study/api/queries'; import { studyDataUtils } from '@/store/studySlice'; @@ -39,4 +43,33 @@ export const useTodayGoals = () => { export const useTodayStudyRecords = () => { const { data: todayStudyRecords = [] } = useStudyStatByDateQuery(new Date()); return todayStudyRecords; +}; + +export const useSplitCategoriesByGroup = ( + categories: GetCategoriesResponse['data'], +) => { + const { data: groups = [] } = useGroupsQuery(); + const { colorKeyMap } = useGroupColorKeyMap(); + + return categories.reduce( + (acc, category) => { + const belongingGroup = groups.find(group => + group.categoryIds.includes(category.id), + ); + if (belongingGroup) { + const groupColorKey = belongingGroup ? colorKeyMap.get(belongingGroup.groupId) : null; + if (!groupColorKey) return acc; + acc.groupCategories.push({ ...category, groupColorKey: groupColorKey }); + } else { + acc.myCategories.push(category); + } + return acc; + }, + { + groupCategories: [] as ( + GetCategoriesResponse['data'][number] & { groupColorKey: GroupColorKey } + )[], + myCategories: [] as GetCategoriesResponse['data'], + }, + ); }; \ No newline at end of file diff --git a/src/locales/ko/manageCategory.json b/src/locales/ko/manageCategory.json index 41fbede3..10636226 100644 --- a/src/locales/ko/manageCategory.json +++ b/src/locales/ko/manageCategory.json @@ -1,6 +1,7 @@ { "manage-my-goals": "내 목표 관리", - "my-goals": "나의 목표", + "my-goals": "내가 만든 목표", + "group-goals": "그룹에 속한 목표", "goal-count": "총 {{count}}개", "goal-time": "목표 시간 {{time}}", "goal-time-null": "목표 시간 없음", diff --git a/src/screens/bottomTab/GroupsScreen/components/JoinedGroupPanel/index.tsx b/src/screens/bottomTab/GroupsScreen/components/JoinedGroupPanel/index.tsx index 75b43c35..13198db1 100644 --- a/src/screens/bottomTab/GroupsScreen/components/JoinedGroupPanel/index.tsx +++ b/src/screens/bottomTab/GroupsScreen/components/JoinedGroupPanel/index.tsx @@ -2,7 +2,7 @@ import { GroupButton } from '@features/groups/ui'; import { Button, Icon, Panel } from '@/components'; import { useGroupsQuery } from '@/features/groups/api/queries'; -import { useGroupColorKey } from '@/features/groups/hooks/useGroupColorKey'; +import { useGroupColorKeyMap } from '@/features/groups/hooks/useGroupColorKey'; import type { GetGroupsResponse } from '@/features/groups/model/groups'; import { useStackNavigation } from '@/hooks'; import { useTranslatedText } from '@/hooks/useTranslatedText'; @@ -38,8 +38,9 @@ const JoinedGroupPanel = () => { }; const GroupListItem = ({ group }: { group: GetGroupsResponse['data'][number] }) => { - const { colorKey: groupColorKey } = useGroupColorKey(group.groupId); - if (!groupColorKey) return null; + const { colorKeyMap } = useGroupColorKeyMap(); + const groupColorKey = colorKeyMap.get(group.groupId); + if (groupColorKey == null) return null; const leaderImageUrl = group.profiles.find(p => p.role === 'LEADER')?.imageUrl ?? null; diff --git a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts index 75a4f963..b4f14034 100644 --- a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts +++ b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts @@ -14,7 +14,7 @@ export const styles = StyleSheet.create({ content: { flexDirection: 'row', alignItems: 'center', - gap: theme.spacing[100], + gap: theme.spacing[200], }, }); diff --git a/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.style.ts b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.style.ts new file mode 100644 index 00000000..248e7f93 --- /dev/null +++ b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.style.ts @@ -0,0 +1,51 @@ +import type { ViewStyle } from 'react-native'; +import { StyleSheet } from 'react-native'; + +import type { TextProps } from '@/components/Text'; +import { GROUP_COLORS, type GroupColorKey } from '@/constants/groupColors'; +import { theme } from '@/theme'; +import type { Color } from '@/types'; + +export const createStyles = ({ + groupColorKey, +}: { + groupColorKey: GroupColorKey; +}) => StyleSheet.create({ + container: { + flexDirection: 'row', + justifyContent: 'space-between', + paddingVertical: theme.spacing[200], + }, + content: { + flexDirection: 'row', + alignItems: 'center', + gap: theme.spacing[200], + }, + groupColorIndicator: { + backgroundColor: GROUP_COLORS[groupColorKey].medium, + width: 10, height: 10, + borderRadius: theme.radius['max'], + }, +}); + +export const GOAL_NAME_TEXT_STYLE: TextProps = { + font: 'b3', +}; + +export const GOAL_TIME_TEXT_STYLE: TextProps = { + font: 'b4', + color: theme.color.neutral[500], +}; + +export const TAG_CONTAINER_STYLE = (color: Color): ViewStyle => ({ + borderRadius: theme.radius['max'], + borderWidth: 1, + borderColor: color, + paddingVertical: theme.spacing[50], + paddingHorizontal: theme.spacing[100], +}); + +export const TAG_TEXT_STYLE = (color: Color): TextProps => ({ + font: 'b5', + color, +}); diff --git a/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx new file mode 100644 index 00000000..1a5b2dfa --- /dev/null +++ b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx @@ -0,0 +1,108 @@ +import { View } from 'react-native'; + +import { Button, Icon, Shapes, Text, TText } from '@/components'; +import { type GroupColorKey } from '@/constants/groupColors'; +import { useDeleteCategoryMutation } from '@/features/category/api/mutations'; +import type { CategoryTag } from '@/features/category/model'; +import { useStackNavigation } from '@/hooks'; +import { dialogService } from '@/utils/dialog'; +import type { Time } from '@/utils/Time'; + +import CategoryDeletionAlert from '../CategoryDeletionAlert'; +import { + createStyles, + GOAL_NAME_TEXT_STYLE, + GOAL_TIME_TEXT_STYLE, + TAG_CONTAINER_STYLE, + TAG_TEXT_STYLE, +} from './index.style'; + +interface CategoryItemProps { + id: number | null; + groupColorKey: GroupColorKey; + temporaryName: string | null; + title: string; + goal: Time | null; + tags?: CategoryTag[]; +} + +const GroupCategoryItem = ({ id, groupColorKey, title, goal, tags = [] }: CategoryItemProps) => { + const navigation = useStackNavigation(); + const { mutateAsync: deleteCategoryMutate } = useDeleteCategoryMutation(); + const styles = createStyles({ groupColorKey }); + + const onEditPress = () => { + navigation.navigate('EditCategory', { + // TODO: id가 null일 때 처리 로직 추가 + categoryId: id, + temporaryName: null, + }); + }; + + // TODO: 수정, 삭제 연속으로 누르면 둘 다 반응하는 문제 해결하기 + const onDeletePress = () => { + dialogService.add({ + content: ( + { + // TODO: id가 null일 때 처리 로직 추가 + await deleteCategoryMutate(id!); + }} + /> + ), + options: { + cancelable: false, + }, + }); + }; + + return ( + + + + + {title} + + + {goal ? ( + + ) : ( + + )} + {tags.map((tag) => ( + + + {tag.name} + + + ))} + + + + + + + ); +}; + +export default GroupCategoryItem; diff --git a/src/screens/category/ManageCategoryScreen/index.style.ts b/src/screens/category/ManageCategoryScreen/index.style.ts index 1a73dcaf..98fad50a 100644 --- a/src/screens/category/ManageCategoryScreen/index.style.ts +++ b/src/screens/category/ManageCategoryScreen/index.style.ts @@ -12,7 +12,7 @@ export const styles = StyleSheet.create({ gap: theme.spacing[300], }, toggleButtonContainer: { - justifyContent: 'space-between', + justifyContent: 'space-around', marginHorizontal: theme.spacing[300], }, }); diff --git a/src/screens/category/ManageCategoryScreen/index.tsx b/src/screens/category/ManageCategoryScreen/index.tsx index 624eb118..80f999c9 100644 --- a/src/screens/category/ManageCategoryScreen/index.tsx +++ b/src/screens/category/ManageCategoryScreen/index.tsx @@ -1,8 +1,9 @@ import { useState } from 'react'; import { Panel, ToggleButtonGroup, TText } from '@/components'; +import type { GetCategoriesResponse } from '@/features/category/model'; import type { DAY_MASK_BY_UTC_CODE } from '@/features/category/model/types'; -import { useAvailableCategories } from '@/hooks/useCategoryData'; +import { useAvailableCategories, useSplitCategoriesByGroup } from '@/hooks/useCategoryData'; import { useTranslatedText } from '@/hooks/useTranslatedText'; import { StackableScreenLayout } from '@/layout'; import { getDayByUTCCode } from '@/utils/date'; @@ -10,6 +11,7 @@ import { typedEntries } from '@/utils/object'; import CategoryItem from './components/CategoryItem'; import EmptyFallback from './components/EmptyFallback'; +import GroupCategoryItem from './components/GroupCategoryItem'; import { GOAL_COUNT_TEXT_STYLE, styles, @@ -21,18 +23,23 @@ import { const ManageCategoryScreen = () => { const tManageMyGoals = useTranslatedText({ tKey: 'manageCategory.manage-my-goals' }); const tMyGoals = useTranslatedText({ tKey: 'manageCategory.my-goals' }); + const tGroupGoals = useTranslatedText({ tKey: 'manageCategory.group-goals' }); const [selectedDays, setSelectedDays] = useState[]>( [getDayByUTCCode(new Date().getDay() as keyof typeof DAY_MASK_BY_UTC_CODE)], ); const categories = useAvailableCategories(); - const filteredCategories = categories.filter(cat => { - for (const [k, v] of typedEntries(cat.dayBelong)) { + + const filterCategoryBySelectedDays = (category: GetCategoriesResponse['data'][number]) => { + for (const [k, v] of typedEntries(category.dayBelong)) { if (!v) continue; if (selectedDays.includes(k)) return true; } return false; - }); + }; + const filteredByDaysCategories = categories.filter(cat => filterCategoryBySelectedDays(cat)); + const { myCategories, groupCategories } = useSplitCategoriesByGroup(filteredByDaysCategories); + return ( { /> { - filteredCategories.length ? - filteredCategories.map(category => ( + myCategories.length ? + myCategories.map(category => ( { ) } + {!!groupCategories.length && ( + + + + {groupCategories.map(category => ( + + ))} + + )} ); diff --git a/src/screens/group/groupDetail/GroupDetailScreen/index.tsx b/src/screens/group/groupDetail/GroupDetailScreen/index.tsx index b14e1ce4..45295396 100644 --- a/src/screens/group/groupDetail/GroupDetailScreen/index.tsx +++ b/src/screens/group/groupDetail/GroupDetailScreen/index.tsx @@ -6,7 +6,7 @@ import { useCategoriesQuery } from '@/features/category/api/queries'; import { isDayInDayBelong } from '@/features/category/model/dayBelongHelper'; import { useChatCount } from '@/features/chat/sse/useChatCount'; import { useGroupDetailQuery } from '@/features/groups/api/queries'; -import { useGroupColorKey } from '@/features/groups/hooks/useGroupColorKey'; +import { useGroupColorKeyMap } from '@/features/groups/hooks/useGroupColorKey'; import { useStackRoute } from '@/hooks'; import { StackableScreenLayout } from '@/layout'; import { studyDataUtils } from '@/store/studySlice'; @@ -17,8 +17,10 @@ import TodaysGoalPanel from '../components/TodaysGoalPanel'; const GroupDetailScreen = () => { const { data: categories } = useCategoriesQuery(); const { params } = useStackRoute<'GroupDetail'>(); - const { colorKey } = useGroupColorKey(params.groupId); - const groupColor = colorKey ? GROUP_COLORS[colorKey] : null; + const { colorKeyMap } = useGroupColorKeyMap(); + const groupColor = colorKeyMap.get(params.groupId) + ? GROUP_COLORS[colorKeyMap.get(params.groupId)!] + : null; const { data, isPending } = useGroupDetailQuery(params.groupId); const chatCount = useChatCount(params.chatRoomId); diff --git a/src/screens/group/groupDetail/components/GroupInfoPanel/DashBoardButtonGroup/index.tsx b/src/screens/group/groupDetail/components/GroupInfoPanel/DashBoardButtonGroup/index.tsx index 40dffe29..ca700e17 100644 --- a/src/screens/group/groupDetail/components/GroupInfoPanel/DashBoardButtonGroup/index.tsx +++ b/src/screens/group/groupDetail/components/GroupInfoPanel/DashBoardButtonGroup/index.tsx @@ -3,7 +3,7 @@ import { View } from 'react-native'; import { Icon, Toast } from '@/components'; import type { GroupColorKey } from '@/constants/groupColors'; import { GROUP_COLORS } from '@/constants/groupColors'; -import { useGroupColorKey } from '@/features/groups/hooks/useGroupColorKey'; +import { useGroupColorKeyMap } from '@/features/groups/hooks/useGroupColorKey'; import type { GroupMember } from '@/features/groups/model'; import { useProfileQuery } from '@/features/user/api/queries'; import { useStackNavigation } from '@/hooks/useStackNavigation'; @@ -39,7 +39,7 @@ const DashBoardButtonGroup = ({ const styles = createStyles(groupColorKey, disabled); const buttonPrimaryColor = GROUP_COLORS[groupColorKey].medium; - const { updateColorKey } = useGroupColorKey(groupId); + const { updateColorKey } = useGroupColorKeyMap(); const { data: profileData } = useProfileQuery(); if (!profileData) return null; @@ -61,7 +61,7 @@ const DashBoardButtonGroup = ({ { - updateColorKey(selectedColorKey); + updateColorKey(groupId, selectedColorKey); }} />), }); diff --git a/src/store/studySlice.ts b/src/store/studySlice.ts index 5dcb8526..46ad6dd8 100644 --- a/src/store/studySlice.ts +++ b/src/store/studySlice.ts @@ -2,6 +2,7 @@ import type { StateCreator } from 'zustand'; import type { Category } from '@/features/category/model'; import type { DAY_MASK_BY_UTC_CODE } from '@/features/category/model/types'; +import { GetGroupsResponse } from '@/features/groups/model/groups'; import { getDayByUTCCode } from '@/utils/date'; import { Time } from '@/utils/Time'; From caae26b6c6e6ddc4ba6e96d4ff648837d0543d0e Mon Sep 17 00:00:00 2001 From: dioo1461 Date: Fri, 6 Feb 2026 21:25:32 +0900 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20=EA=B7=B8=EB=A3=B9=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=EB=8A=94=20=EC=88=98=EC=A0=95/?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EB=B2=84=ED=8A=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../components/GroupCategoryItem/index.tsx | 14 -------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index e889fc2f..b463c5d5 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ yarn-error.log # build cache & logs msbuild.binlog android/.kotlin/* +tsconfig.tsbuildinfo # env .env diff --git a/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx index 1a5b2dfa..800f876f 100644 --- a/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx +++ b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx @@ -87,20 +87,6 @@ const GroupCategoryItem = ({ id, groupColorKey, title, goal, tags = [] }: Catego ))} - - - - ); }; From a55df4a37d59c1d6b90f941bad2a279f340715bc Mon Sep 17 00:00:00 2001 From: dioo1461 Date: Fri, 6 Feb 2026 21:28:10 +0900 Subject: [PATCH 3/6] =?UTF-8?q?style:=20=EB=82=B4=EA=B0=80=20=EB=A7=8C?= =?UTF-8?q?=EB=93=A0=20=EB=AA=A9=ED=91=9C=EC=97=90=EB=8F=84=20=EB=85=B8?= =?UTF-8?q?=EB=9E=80=EC=83=89=20color=20indicator=20=EB=82=98=ED=83=80?= =?UTF-8?q?=EB=82=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/CategoryItem/index.style.ts | 7 +++++++ .../ManageCategoryScreen/components/CategoryItem/index.tsx | 1 + 2 files changed, 8 insertions(+) diff --git a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts index b4f14034..c36ea946 100644 --- a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts +++ b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts @@ -2,6 +2,8 @@ import type { ViewStyle } from 'react-native'; import { StyleSheet } from 'react-native'; import type { TextProps } from '@/components/Text'; +import type { GroupColorKey } from '@/constants/groupColors'; +import { GROUP_COLORS } from '@/constants/groupColors'; import { theme } from '@/theme'; import type { Color } from '@/types'; @@ -15,6 +17,11 @@ export const styles = StyleSheet.create({ flexDirection: 'row', alignItems: 'center', gap: theme.spacing[200], + }, + groupColorIndicator: { + backgroundColor: theme.color.primary[500], + width: 10, height: 10, + borderRadius: theme.radius['max'], }, }); diff --git a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.tsx b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.tsx index 53ddfc83..ee03fb56 100644 --- a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.tsx +++ b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.tsx @@ -56,6 +56,7 @@ const CategoryItem = ({ id, title, goal, tags = [] }: CategoryItemProps) => { return ( + {title} From 92e0a4fc706c54e5ed55a6a7d401f0f9170b2efc Mon Sep 17 00:00:00 2001 From: dioo1461 Date: Fri, 6 Feb 2026 21:41:41 +0900 Subject: [PATCH 4/6] =?UTF-8?q?style:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=EC=88=98=EC=A0=95/=EC=82=AD=EC=A0=9C=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Button/Icon/index.tsx | 4 ++-- src/navigation/BottomTabNavigator/BottomNavHeader.tsx | 4 ++-- .../components/CategoryItem/index.style.ts | 8 +++++++- .../components/CategoryItem/index.tsx | 5 +++++ .../GroupChatScreen/components/MessageInput/index.tsx | 4 ++-- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/components/Button/Icon/index.tsx b/src/components/Button/Icon/index.tsx index f8937b66..2b0065fa 100644 --- a/src/components/Button/Icon/index.tsx +++ b/src/components/Button/Icon/index.tsx @@ -7,7 +7,7 @@ import type { Icon, IconProps } from '@/types/icon'; interface IconButtonProps extends Omit { Icon: Icon; buttonPadding?: number; - style?: StyleProp; + containerStyle?: StyleProp; iconStyle?: StyleProp; buttonType?: 'touchableOpacity' | 'pressable'; onPress?: () => void; @@ -17,7 +17,7 @@ const IconButton = ({ Icon, onPress, buttonPadding = 2, - style: containerStyle, + containerStyle, iconStyle, buttonType = 'touchableOpacity', ...props diff --git a/src/navigation/BottomTabNavigator/BottomNavHeader.tsx b/src/navigation/BottomTabNavigator/BottomNavHeader.tsx index 04b031f1..ed6e4380 100644 --- a/src/navigation/BottomTabNavigator/BottomNavHeader.tsx +++ b/src/navigation/BottomTabNavigator/BottomNavHeader.tsx @@ -15,13 +15,13 @@ const BottomNavHeader = () => { navigation.navigate('Settings')} diff --git a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts index c36ea946..33902a04 100644 --- a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts +++ b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts @@ -5,7 +5,7 @@ import type { TextProps } from '@/components/Text'; import type { GroupColorKey } from '@/constants/groupColors'; import { GROUP_COLORS } from '@/constants/groupColors'; import { theme } from '@/theme'; -import type { Color } from '@/types'; +import type { Color, IconProps } from '@/types'; export const styles = StyleSheet.create({ container: { @@ -23,6 +23,12 @@ export const styles = StyleSheet.create({ width: 10, height: 10, borderRadius: theme.radius['max'], }, + iconContainer: { + borderWidth: 1, + borderRadius: 8, + paddingVertical: 4, + paddingHorizontal: 6, + }, }); export const GOAL_NAME_TEXT_STYLE: TextProps = { diff --git a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.tsx b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.tsx index ee03fb56..fc7a976a 100644 --- a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.tsx +++ b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.tsx @@ -4,6 +4,7 @@ import { Button, Icon, Shapes, Text, TText } from '@/components'; import { useDeleteCategoryMutation } from '@/features/category/api/mutations'; import type { CategoryTag } from '@/features/category/model'; import { useStackNavigation } from '@/hooks'; +import { theme } from '@/theme'; import { dialogService } from '@/utils/dialog'; import type { Time } from '@/utils/Time'; @@ -87,12 +88,16 @@ const CategoryItem = ({ id, title, goal, tags = [] }: CategoryItemProps) => { ); From 22899bd5e8823ccf3594175b0ba645390e61482a Mon Sep 17 00:00:00 2001 From: dioo1461 Date: Fri, 6 Feb 2026 21:53:17 +0900 Subject: [PATCH 5/6] fix: update BUTTON_ICON_STYLE to use containerStyle and remove unused id prop from GroupCategoryItem --- .../Panel/PanelView/PanelHeader.style.ts | 2 +- .../components/GroupCategoryItem/index.tsx | 30 +------------------ .../category/ManageCategoryScreen/index.tsx | 1 - src/types/icon.d.ts | 3 +- 4 files changed, 4 insertions(+), 32 deletions(-) diff --git a/src/components/Panel/PanelView/PanelHeader.style.ts b/src/components/Panel/PanelView/PanelHeader.style.ts index d9b45c60..d6ec6ec6 100644 --- a/src/components/Panel/PanelView/PanelHeader.style.ts +++ b/src/components/Panel/PanelView/PanelHeader.style.ts @@ -17,7 +17,7 @@ export const TITLE_TEXT_STYLE: TextProps = { export const BUTTON_ICON_STYLE: IconProps = { width: 20, height: 20, - style: { + containerStyle: { position: 'absolute', right: 0, top: 0, }, diff --git a/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx index 800f876f..63eda5c7 100644 --- a/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx +++ b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx @@ -18,7 +18,6 @@ import { } from './index.style'; interface CategoryItemProps { - id: number | null; groupColorKey: GroupColorKey; temporaryName: string | null; title: string; @@ -26,36 +25,9 @@ interface CategoryItemProps { tags?: CategoryTag[]; } -const GroupCategoryItem = ({ id, groupColorKey, title, goal, tags = [] }: CategoryItemProps) => { - const navigation = useStackNavigation(); - const { mutateAsync: deleteCategoryMutate } = useDeleteCategoryMutation(); +const GroupCategoryItem = ({ groupColorKey, title, goal, tags = [] }: CategoryItemProps) => { const styles = createStyles({ groupColorKey }); - const onEditPress = () => { - navigation.navigate('EditCategory', { - // TODO: id가 null일 때 처리 로직 추가 - categoryId: id, - temporaryName: null, - }); - }; - - // TODO: 수정, 삭제 연속으로 누르면 둘 다 반응하는 문제 해결하기 - const onDeletePress = () => { - dialogService.add({ - content: ( - { - // TODO: id가 null일 때 처리 로직 추가 - await deleteCategoryMutate(id!); - }} - /> - ), - options: { - cancelable: false, - }, - }); - }; - return ( diff --git a/src/screens/category/ManageCategoryScreen/index.tsx b/src/screens/category/ManageCategoryScreen/index.tsx index 80f999c9..14311972 100644 --- a/src/screens/category/ManageCategoryScreen/index.tsx +++ b/src/screens/category/ManageCategoryScreen/index.tsx @@ -99,7 +99,6 @@ const ManageCategoryScreen = () => { & MultipleColorProps; -type SingleIconProps = SvgProps; +type SingleIconProps = SvgProps & { containerStyle?: StyleProp }; export type IconProps = SingleIconProps & MultiIconProps; export type SingleIcon = FC; From 068c2b48a2e2ee308339d932bf7411a16335e27c Mon Sep 17 00:00:00 2001 From: dioo1461 Date: Fri, 6 Feb 2026 22:03:32 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useCategoryData.ts | 2 +- .../components/CategoryItem/index.style.ts | 4 +--- .../components/GroupCategoryItem/index.tsx | 6 +----- src/screens/group/groupDetail/GroupDetailScreen/index.tsx | 5 ++--- src/store/studySlice.ts | 1 - 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/hooks/useCategoryData.ts b/src/hooks/useCategoryData.ts index f0819f27..7cf157ea 100644 --- a/src/hooks/useCategoryData.ts +++ b/src/hooks/useCategoryData.ts @@ -57,7 +57,7 @@ export const useSplitCategoriesByGroup = ( group.categoryIds.includes(category.id), ); if (belongingGroup) { - const groupColorKey = belongingGroup ? colorKeyMap.get(belongingGroup.groupId) : null; + const groupColorKey = colorKeyMap.get(belongingGroup.groupId); if (!groupColorKey) return acc; acc.groupCategories.push({ ...category, groupColorKey: groupColorKey }); } else { diff --git a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts index 33902a04..c1672626 100644 --- a/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts +++ b/src/screens/category/ManageCategoryScreen/components/CategoryItem/index.style.ts @@ -2,10 +2,8 @@ import type { ViewStyle } from 'react-native'; import { StyleSheet } from 'react-native'; import type { TextProps } from '@/components/Text'; -import type { GroupColorKey } from '@/constants/groupColors'; -import { GROUP_COLORS } from '@/constants/groupColors'; import { theme } from '@/theme'; -import type { Color, IconProps } from '@/types'; +import type { Color } from '@/types'; export const styles = StyleSheet.create({ container: { diff --git a/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx index 63eda5c7..814be017 100644 --- a/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx +++ b/src/screens/category/ManageCategoryScreen/components/GroupCategoryItem/index.tsx @@ -1,14 +1,10 @@ import { View } from 'react-native'; -import { Button, Icon, Shapes, Text, TText } from '@/components'; +import { Shapes, Text, TText } from '@/components'; import { type GroupColorKey } from '@/constants/groupColors'; -import { useDeleteCategoryMutation } from '@/features/category/api/mutations'; import type { CategoryTag } from '@/features/category/model'; -import { useStackNavigation } from '@/hooks'; -import { dialogService } from '@/utils/dialog'; import type { Time } from '@/utils/Time'; -import CategoryDeletionAlert from '../CategoryDeletionAlert'; import { createStyles, GOAL_NAME_TEXT_STYLE, diff --git a/src/screens/group/groupDetail/GroupDetailScreen/index.tsx b/src/screens/group/groupDetail/GroupDetailScreen/index.tsx index 45295396..996d3993 100644 --- a/src/screens/group/groupDetail/GroupDetailScreen/index.tsx +++ b/src/screens/group/groupDetail/GroupDetailScreen/index.tsx @@ -18,9 +18,8 @@ const GroupDetailScreen = () => { const { data: categories } = useCategoriesQuery(); const { params } = useStackRoute<'GroupDetail'>(); const { colorKeyMap } = useGroupColorKeyMap(); - const groupColor = colorKeyMap.get(params.groupId) - ? GROUP_COLORS[colorKeyMap.get(params.groupId)!] - : null; + const colorKey = colorKeyMap.get(params.groupId); + const groupColor = colorKey ? GROUP_COLORS[colorKey] : null; const { data, isPending } = useGroupDetailQuery(params.groupId); const chatCount = useChatCount(params.chatRoomId); diff --git a/src/store/studySlice.ts b/src/store/studySlice.ts index 46ad6dd8..5dcb8526 100644 --- a/src/store/studySlice.ts +++ b/src/store/studySlice.ts @@ -2,7 +2,6 @@ import type { StateCreator } from 'zustand'; import type { Category } from '@/features/category/model'; import type { DAY_MASK_BY_UTC_CODE } from '@/features/category/model/types'; -import { GetGroupsResponse } from '@/features/groups/model/groups'; import { getDayByUTCCode } from '@/utils/date'; import { Time } from '@/utils/Time';