diff --git a/app/(team)/alarm.tsx b/app/(team)/alarm.tsx index 3462397..cc488e3 100644 --- a/app/(team)/alarm.tsx +++ b/app/(team)/alarm.tsx @@ -13,8 +13,10 @@ import { } from "@/shared/ui"; import NemoText from "@/shared/ui/atoms/NemoText"; import Tab from "@/shared/ui/atoms/Tab"; +import { getAlertNavigationTarget } from "@/shared/utils/alertNavigation"; import { AntDesign } from "@expo/vector-icons"; import { useRouter } from "expo-router"; +import type { Href } from "expo-router"; import { useMemo, useState } from "react"; import { FlatList, Pressable, StyleSheet, View } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; @@ -60,9 +62,18 @@ const AlarmScreen = ({}: AlarmScreenProps) => { }; const handlePressAlert = - (alertId: number, teamId: number, read: boolean) => () => { + (alertId: number, type: string, teamId: number, read: boolean) => () => { if (!read) markAsRead.mutate(alertId); - route.push(`/${teamId}/calendar`); + + const target = getAlertNavigationTarget({ type, teamId }); + if (!target) return; + + if (target.method === "replace") { + route.replace(target.href as Href); + return; + } + + route.push(target.href as Href); }; return ( @@ -98,7 +109,12 @@ const AlarmScreen = ({}: AlarmScreenProps) => { renderItem={({ item }) => ( { - if (!data?.type) return; + const target = getAlertNavigationTarget({ + type: data?.type, + teamId: data?.teamId, + }); + if (!target) return; - switch (data.type) { - case "SCHEDULE_ASSIGNEE_ADDED": - router.push(`/${data.teamId}`); - break; - - default: - break; + if (target.method === "replace") { + router.replace(target.href as Href); + return; } + + router.push(target.href as Href); }; // 🔹 앱이 종료 상태였다가 켜진 경우 처리 diff --git a/features/notifications/types/alert.model.ts b/features/notifications/types/alert.model.ts index b118461..36b7f02 100644 --- a/features/notifications/types/alert.model.ts +++ b/features/notifications/types/alert.model.ts @@ -1,6 +1,8 @@ +import type { AlertType } from "@/shared/utils/alertNavigation"; + export interface AlertResponse { id: number; - type: string; + type: AlertType; teamId: number; teamName: string; content: string; diff --git a/shared/ui/molecules/CalendarWeek.tsx b/shared/ui/molecules/CalendarWeek.tsx index 0d5985d..2042194 100644 --- a/shared/ui/molecules/CalendarWeek.tsx +++ b/shared/ui/molecules/CalendarWeek.tsx @@ -79,7 +79,7 @@ const CalendarWeek = ({ } const { selectedDate } = calendarContext; - const MAX_LANES = height > 1200 ? 6 : 4; + const MAX_LANES = height > 1200 ? maxLanes + 2 : maxLanes; const totalHeight = DATES_HEIGHT + MAX_LANES * (LANE_HEIGHT + LANE_GAP); const handleWeekPress = (event: GestureResponderEvent) => { @@ -125,7 +125,7 @@ const CalendarWeekDates = ({ const { width, height } = useWindowDimensions(); const WEEK_WIDTH = width - 40; const DAY_WIDTH = WEEK_WIDTH / 7; - const MAX_LANES = height > 1200 ? 6 : 4; // Replace 600 with the appropriate threshold value + const MAX_LANES = height > 1200 ? maxLanes + 2 : maxLanes; // Replace 600 with the appropriate threshold value const totalHeight = DATES_HEIGHT + MAX_LANES * (LANE_HEIGHT + LANE_GAP); return ( @@ -172,7 +172,7 @@ const CalendarWeekSchedules = ({ ); } const { width, height } = useWindowDimensions(); - const MAX_LANES = height > 1200 ? 6 : 4; // Replace 600 with the appropriate threshold value + const MAX_LANES = height > 1200 ? maxLanes + 2 : maxLanes; // Replace 600 with the appropriate threshold value const weekSchedules = getWeekSchedules(dates, schedules); // maxVisible 쓰면 여기서 자르세요 diff --git a/shared/ui/templates/CalendarDetailModal.tsx b/shared/ui/templates/CalendarDetailModal.tsx index a8f19c9..79135da 100644 --- a/shared/ui/templates/CalendarDetailModal.tsx +++ b/shared/ui/templates/CalendarDetailModal.tsx @@ -138,8 +138,9 @@ const CalendarDetailModal = ({ diff --git a/shared/ui/templates/ScheduleListModal.tsx b/shared/ui/templates/ScheduleListModal.tsx index 4b8ea78..c3db66b 100644 --- a/shared/ui/templates/ScheduleListModal.tsx +++ b/shared/ui/templates/ScheduleListModal.tsx @@ -434,9 +434,12 @@ const styles = StyleSheet.create({ flexDirection: "row", gap: 4, marginVertical: 8, + justifyContent: "center", + alignItems: "center", }, border: { width: 3, + height: 16, borderRadius: 2, }, }); diff --git a/shared/utils/alertNavigation.ts b/shared/utils/alertNavigation.ts new file mode 100644 index 0000000..9b9fefa --- /dev/null +++ b/shared/utils/alertNavigation.ts @@ -0,0 +1,51 @@ +export type AlertType = + | "SCHEDULE_ASSIGNEE_ADDED" + | "SCHEDULE_POSITION_ADDED" + | "NOTICE_UPDATED" + | "TODO_DUE_TODAY" + | "TEAM_MEMBER_JOINED" + | "TEAM_DISSOLVED"; + +type AlertNavigationTarget = { + href: string; + method: "push" | "replace"; +}; + +const toTeamId = (teamId: number | string | null | undefined) => { + if (teamId == null) return null; + const parsed = Number(teamId); + if (Number.isNaN(parsed)) return null; + return parsed; +}; + +export const getAlertNavigationTarget = (params: { + type?: string | null; + teamId?: number | string | null; +}): AlertNavigationTarget | null => { + const { type, teamId } = params; + if (!type) return null; + + const parsedTeamId = toTeamId(teamId); + + switch (type as AlertType) { + case "SCHEDULE_ASSIGNEE_ADDED": + case "SCHEDULE_POSITION_ADDED": + case "NOTICE_UPDATED": + if (parsedTeamId == null) return null; + return { href: `/${parsedTeamId}/calendar`, method: "push" }; + + case "TODO_DUE_TODAY": + if (parsedTeamId == null) return null; + return { href: `/${parsedTeamId}/calendar/todos`, method: "push" }; + + case "TEAM_MEMBER_JOINED": + if (parsedTeamId == null) return null; + return { href: `/(team)/members?teamId=${parsedTeamId}`, method: "push" }; + + case "TEAM_DISSOLVED": + return { href: "/teams/check", method: "replace" }; + + default: + return null; + } +};