From 71305142888a92e94796e53a45a85181ea6f7ea5 Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 18:02:15 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=ED=83=80=EC=9E=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20sort/filter=20=ED=83=80=EC=9E=85=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/timeline/api.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/types/timeline/api.ts b/src/types/timeline/api.ts index 5e1a96e9..3846b2d1 100644 --- a/src/types/timeline/api.ts +++ b/src/types/timeline/api.ts @@ -23,6 +23,9 @@ export const TIMELINE_PERFORMANCE_STATUS = [ export type TTimelinePerformanceStatus = (typeof TIMELINE_PERFORMANCE_STATUS)[number]; +export const TIMELINE_SORTS = ["DISPLAY_ORDER", "LATEST", "OLDEST"] as const; +export type TTimelineSort = (typeof TIMELINE_SORTS)[number]; + /** API 3종 + UI 전용 미정(PENDING). null/미지 값은 UI에서 PENDING으로 정규화 */ export type TTimelinePerformanceStatusUi = | TTimelinePerformanceStatus @@ -102,3 +105,13 @@ export interface IUpdateTimelineVariables { timelineId: number; body: ITimelineUpsertRequest; } + +/*목록 조회 쿼리. status가 생략되면 전체보이도록*/ +export interface ITimelineListParams { + status?: TTimelinePerformanceStatus; + sort?: TTimelineSort; +} + +export interface IUpdateTimelineDisplayOrderRequest { + timelineIds: number[]; +} From 1c3336babda69de47dbf651c8b7e20c82d4d63d5 Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 18:14:32 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20list=ED=82=A4=EC=97=90=20sort/sta?= =?UTF-8?q?tus=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/queryKeys.ts | 13 +++++++++++++ src/types/timeline/api.ts | 1 + 2 files changed, 14 insertions(+) diff --git a/src/lib/queryKeys.ts b/src/lib/queryKeys.ts index aba20f01..aa8d3457 100644 --- a/src/lib/queryKeys.ts +++ b/src/lib/queryKeys.ts @@ -82,7 +82,20 @@ export const QUERY_KEYS = { }, timeline: { + /*invalidate용 prefix - status/sort 없이 */ list: (orgId: number | null) => ["timeline", "list", orgId] as const, + /*실제 useQuery용*/ + listWithParams: ( + orgId: number | null, + params: { status?: string | null; sort?: string } = {}, + ) => + [ + "timeline", + "list", + orgId, + params.status ?? null, + params.sort ?? "DISPLAY_ORDER", + ] as const, detail: (orgId: number | null, timelineId: number | null) => ["timeline", "detail", orgId, timelineId] as const, }, diff --git a/src/types/timeline/api.ts b/src/types/timeline/api.ts index 3846b2d1..66ca27ce 100644 --- a/src/types/timeline/api.ts +++ b/src/types/timeline/api.ts @@ -47,6 +47,7 @@ export interface ITimelineListItem { endDate: string; /** 성과 미산출 시 null일 수 있음 */ performanceStatus: TTimelinePerformanceStatus | null; + displayOrder: number; } export interface ITimelineDailyTrend { From 8c6626903c1a2f76e9a86a88080b3f05fb2e98a0 Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 18:17:21 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20=ED=83=80=EC=9E=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=EC=A1=B0=ED=9A=8C=20API=ED=9B=85=EC=97=90=20params?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/timeline/timeline.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/api/timeline/timeline.ts b/src/api/timeline/timeline.ts index 78a1bac2..9a713d16 100644 --- a/src/api/timeline/timeline.ts +++ b/src/api/timeline/timeline.ts @@ -2,6 +2,7 @@ import type { ICommonResponse } from "@/types/common/common"; import { type ITimelineDetail, type ITimelineListItem, + type ITimelineListParams, type ITimelineMutationResponse, type ITimelineUpsertRequest, type TTimelineEmptyResponse, @@ -23,10 +24,16 @@ export const getTimelineDetail = async ( //타임라인 목록 조회 API export const getTimelineList = async ( orgId: number, + params: ITimelineListParams = {}, ): Promise => { const { data } = await axiosInstance.get< ICommonResponse - >(`/api/org/${orgId}/timeline`); + >(`/api/org/${orgId}/timeline`, { + params: { + ...(params.status ? { status: params.status } : {}), + ...(params.sort ? { sort: params.sort } : {}), + }, + }); return data.data; }; From f3732642d8fcc696876f5e97a25ecf6b5ed3dffc Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 18:20:52 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20useTimelineList=ED=9B=85=20params?= =?UTF-8?q?=EB=B0=9B=EC=95=84=EC=84=9C=20=EC=BF=BC=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/timeline/useTimelineList.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hooks/timeline/useTimelineList.ts b/src/hooks/timeline/useTimelineList.ts index dcdd50f5..1c61bcab 100644 --- a/src/hooks/timeline/useTimelineList.ts +++ b/src/hooks/timeline/useTimelineList.ts @@ -1,14 +1,25 @@ +import type { ITimelineListParams } from "@/types/timeline/api"; + import { useCoreQuery } from "@/hooks/customQuery"; import { getTimelineList } from "@/api/timeline/timeline"; import { QUERY_KEYS } from "@/lib/queryKeys"; import useWorkspaceStore from "@/store/useWorkspaceStore"; -export function useTimelineList() { +export function useTimelineList(params: ITimelineListParams = {}) { const orgId = useWorkspaceStore((s) => s.selectedOrgId); + const sort = params.sort ?? "DISPLAY_ORDER"; + return useCoreQuery( - QUERY_KEYS.timeline.list(orgId), - () => getTimelineList(orgId!), + QUERY_KEYS.timeline.listWithParams(orgId, { + status: params.status ?? null, + sort, + }), + () => + getTimelineList(orgId!, { + status: params.status, + sort, + }), { enabled: orgId != null, }, From 4dca9638286df369f11f102452bc193244ff6483 Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 22:41:33 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=ED=95=84=ED=84=B0/=EC=A0=95?= =?UTF-8?q?=EB=A0=AC=20=EB=9D=BC=EB=B2=A8=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/timeline/filterSort.ts | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/constants/timeline/filterSort.ts diff --git a/src/constants/timeline/filterSort.ts b/src/constants/timeline/filterSort.ts new file mode 100644 index 00000000..60eb5531 --- /dev/null +++ b/src/constants/timeline/filterSort.ts @@ -0,0 +1,36 @@ +import type { + TTimelinePerformanceStatus, + TTimelineSort, +} from "@/types/timeline/api"; + +import { TIMELINE_PERFORMANCE_STATUS_STYLE } from "./statusStyle"; + +export type TTimelineStatusFilter = TTimelinePerformanceStatus | "ALL"; + +export const TIMELINE_STATUS_FILTER_OPTIONS: { + value: TTimelineStatusFilter; + label: string; +}[] = [ + { value: "ALL", label: "전체" }, + { + value: "ON_TRACK", + label: TIMELINE_PERFORMANCE_STATUS_STYLE.ON_TRACK.label, + }, + { + value: "ABOVE_AVG", + label: TIMELINE_PERFORMANCE_STATUS_STYLE.ABOVE_AVG.label, + }, + { + value: "UNDERPERFORM", + label: TIMELINE_PERFORMANCE_STATUS_STYLE.UNDERPERFORM.label, + }, +]; + +export const TIMELINE_SORT_OPTIONS: { + value: TTimelineSort; + label: string; +}[] = [ + { value: "DISPLAY_ORDER", label: "생성 순서" }, + { value: "LATEST", label: "종료일 가까운 순" }, + { value: "OLDEST", label: "종료일 먼 순" }, +]; From ccbf7470e6b6d7950f9c3f4c6e248756f87c3e2d Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 22:55:57 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20=ED=83=80=EC=9E=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20=EC=A0=95=EB=A0=AC/=ED=95=84=ED=84=B0=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timeline/TimelineFilterSortMenus.tsx | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/components/timeline/TimelineFilterSortMenus.tsx diff --git a/src/components/timeline/TimelineFilterSortMenus.tsx b/src/components/timeline/TimelineFilterSortMenus.tsx new file mode 100644 index 00000000..57859e7a --- /dev/null +++ b/src/components/timeline/TimelineFilterSortMenus.tsx @@ -0,0 +1,73 @@ +import { twMerge } from "tailwind-merge"; + +import type { TTimelineSort } from "@/types/timeline/api"; +import { + TIMELINE_SORT_OPTIONS, + TIMELINE_STATUS_FILTER_OPTIONS, + type TTimelineStatusFilter, +} from "@/constants/timeline/filterSort"; + +import { + DropdownMenu, + type TMenuItem, +} from "../common/dropdownmenu/DropdownMenu"; + +import FilterIcon from "@/assets/icon/timeline/filter.svg?react"; +import SortIcon from "@/assets/icon/timeline/sort.svg?react"; + +const TOOLBAR_ACTIONS_CLASS = + "flex cursor-pointer items-center gap-1.5 rounded-lg px-2 py-1.5 font-caption text-text-muted transition-all hover:bg-surface-200 hover:text-text-body"; + +interface ITimelineFilterSortMenusProps { + statusFilter: TTimelineStatusFilter; + sort: TTimelineSort; + onStatusFilterChange: (value: TTimelineStatusFilter) => void; + onSortChange: (value: TTimelineSort) => void; + className?: string; +} + +export default function TimelineFilterSortMenus({ + statusFilter, + sort, + onStatusFilterChange, + onSortChange, + className, +}: ITimelineFilterSortMenusProps) { + const sortItems: TMenuItem[] = TIMELINE_SORT_OPTIONS.map((opt) => ({ + label: opt.label, + active: sort === opt.value, + onClick: () => onSortChange(opt.value), + })); + + const filterItems: TMenuItem[] = TIMELINE_STATUS_FILTER_OPTIONS.map( + (opt) => ({ + label: opt.label, + active: statusFilter === opt.value, + onClick: () => onStatusFilterChange(opt.value), + }), + ); + return ( +
+ + + Sort + + } + /> + + + Filter + + } + /> +
+ ); +} From 43ae445fbfe619735840eb7f6c49628dc518d6cd Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 22:57:01 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20mock=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/timeline/timeline.mock.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/timeline/timeline.mock.ts b/src/types/timeline/timeline.mock.ts index 637b7a1c..1582aed7 100644 --- a/src/types/timeline/timeline.mock.ts +++ b/src/types/timeline/timeline.mock.ts @@ -43,6 +43,7 @@ export const TIMELINE_LIST_MOCK: ITimelineListItem[] = [ startDate: "2026-06-01", endDate: "2026-06-30", performanceStatus: "ON_TRACK", + displayOrder: 1, }, { timelineId: 2, @@ -50,6 +51,7 @@ export const TIMELINE_LIST_MOCK: ITimelineListItem[] = [ startDate: "2026-06-10", endDate: "2026-06-30", performanceStatus: "UNDERPERFORM", + displayOrder: 2, }, ]; From f4d44a4880f71800dfb4f134238e0dfd297ae9fd Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 23:33:29 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20=ED=83=80=EC=9E=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EB=90=9C=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=82=BD=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/dashboard/timeline/Timeline.tsx | 57 +++++++++++------------ 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/pages/dashboard/timeline/Timeline.tsx b/src/pages/dashboard/timeline/Timeline.tsx index 98acf1ef..8451fc05 100644 --- a/src/pages/dashboard/timeline/Timeline.tsx +++ b/src/pages/dashboard/timeline/Timeline.tsx @@ -2,11 +2,13 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { toast } from "sonner"; import { twMerge } from "tailwind-merge"; +import type { TTimelineSort } from "@/types/timeline/api"; import type { ITimelineSummaryPanelData } from "@/types/timeline/summary"; import type { ITimelineCampaignBar, TTimelineViewUnit, } from "@/types/timeline/ui"; +import type { TTimelineStatusFilter } from "@/constants/timeline/filterSort"; import { TIMELINE_COL_WIDTH, TIMELINE_PAGE_HEIGHT, @@ -31,6 +33,7 @@ import TimelineAxis from "@/components/timeline/TimelineAxis"; import TimelineBar from "@/components/timeline/TimelineBar"; import TimelineCreateModal from "@/components/timeline/TimelineCreateModal"; import TimelineEmptyState from "@/components/timeline/TimelineEmptyState"; +import TimelineFilterSortMenus from "@/components/timeline/TimelineFilterSortMenus"; import TimelineGrid from "@/components/timeline/TimelineGrid"; import TimelinePerformancePanel from "@/components/timeline/TimelinePerformancePanel"; import { @@ -41,15 +44,10 @@ import TimelineStatusLegend from "@/components/timeline/TimelineStatusLegend"; import PlusIcon from "@/assets/icon/common/plus.svg?react"; import TrashIcon from "@/assets/icon/common/trash.svg?react"; -import FilterIcon from "@/assets/icon/timeline/filter.svg?react"; -import SortIcon from "@/assets/icon/timeline/sort.svg?react"; const SUMMARY_POLL_INTERVAL_MS = 1500; const SUMMARY_POLL_TIMEOUT_MS = 90000; -const TOOLBAR_ACTION_CLASS = - "flex items-center gap-1.5 rounded-lg px-2 py-1.5 font-caption text-text-muted opacity-50 cursor-not-allowed"; - export default function Timeline() { const scrollRef = useRef(null); @@ -71,12 +69,9 @@ export default function Timeline() { number | null >(null); - const { - data: timelineList = [], - isLoading, - isError, - error, - } = useTimelineList(); + const [statusFilter, setStatusFilter] = + useState("ALL"); + const [sort, setSort] = useState("DISPLAY_ORDER"); const { mutate: deleteTimeline, isPending: isDeleting } = useDeleteTimeline(); const { mutate: requestSummary, isPending: isSummaryPending } = @@ -103,6 +98,21 @@ export default function Timeline() { }; }, [editDetail]); + const listParams = useMemo( + () => ({ + status: statusFilter === "ALL" ? undefined : statusFilter, + sort, + }), + [statusFilter, sort], + ); + + const { + data: timelineList = [], + isLoading, + isError, + error, + } = useTimelineList(listParams); + const gridData = useMemo( () => buildTimelineGrid({ items: timelineList, viewUnit, periodIndex }), [timelineList, viewUnit, periodIndex], @@ -325,24 +335,13 @@ export default function Timeline() { onGoToToday={handleGoToToday} className="justify-self-center" /> -
- - - Sort - - - - Filter - -
+ {hasNoTimelines ? ( From 08eba537e345412b32c84e5880d8b0090aaf7c6d Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 23:37:48 +0900 Subject: [PATCH 09/11] =?UTF-8?q?fix:=20=ED=83=80=EC=9E=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20=EC=A0=95=EB=A0=AC=20=EB=9D=BC=EB=B2=A8=EC=9D=84=20?= =?UTF-8?q?=EC=8B=A4=EC=A0=9C=20=EC=A0=95=EB=A0=AC=EC=88=9C=EC=84=9C?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/timeline/filterSort.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/constants/timeline/filterSort.ts b/src/constants/timeline/filterSort.ts index 60eb5531..76b5dff6 100644 --- a/src/constants/timeline/filterSort.ts +++ b/src/constants/timeline/filterSort.ts @@ -30,7 +30,7 @@ export const TIMELINE_SORT_OPTIONS: { value: TTimelineSort; label: string; }[] = [ - { value: "DISPLAY_ORDER", label: "생성 순서" }, - { value: "LATEST", label: "종료일 가까운 순" }, - { value: "OLDEST", label: "종료일 먼 순" }, + { value: "DISPLAY_ORDER", label: "기본 순서" }, + { value: "LATEST", label: "종료일 먼 순" }, + { value: "OLDEST", label: "종료일 가까운 순" }, ]; From b173bb074547e92e843357f401b306f72357f7eb Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 23:51:05 +0900 Subject: [PATCH 10/11] =?UTF-8?q?fix:=20=EC=83=81=EB=8C=80=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=84=EC=B9=AD=20import=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/timeline/TimelineFilterSortMenus.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/timeline/TimelineFilterSortMenus.tsx b/src/components/timeline/TimelineFilterSortMenus.tsx index 57859e7a..54e68d8d 100644 --- a/src/components/timeline/TimelineFilterSortMenus.tsx +++ b/src/components/timeline/TimelineFilterSortMenus.tsx @@ -10,7 +10,7 @@ import { import { DropdownMenu, type TMenuItem, -} from "../common/dropdownmenu/DropdownMenu"; +} from "@/components/common/dropdownmenu/DropdownMenu"; import FilterIcon from "@/assets/icon/timeline/filter.svg?react"; import SortIcon from "@/assets/icon/timeline/sort.svg?react"; From 3d16801c4d0491c7c26b0d29a7f7911fd065fc6d Mon Sep 17 00:00:00 2001 From: JAESEON PARK Date: Thu, 6 Aug 2026 23:56:41 +0900 Subject: [PATCH 11/11] =?UTF-8?q?fix:=20=ED=83=80=EC=9E=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20=EB=B0=94=20=EC=A0=95=EB=A0=AC/=ED=95=84=ED=84=B0?= =?UTF-8?q?=20=EA=B0=92=20=ED=8E=98=EC=9D=B4=EC=A7=80=20unmount=ED=9B=84?= =?UTF-8?q?=EC=97=90=EB=8F=84=20=EB=82=A8=EC=95=84=EC=9D=B4=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20Zustand=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/dashboard/timeline/Timeline.tsx | 10 +++++----- src/store/useTimelineStore.ts | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 src/store/useTimelineStore.ts diff --git a/src/pages/dashboard/timeline/Timeline.tsx b/src/pages/dashboard/timeline/Timeline.tsx index 8451fc05..637ca7ce 100644 --- a/src/pages/dashboard/timeline/Timeline.tsx +++ b/src/pages/dashboard/timeline/Timeline.tsx @@ -2,13 +2,11 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { toast } from "sonner"; import { twMerge } from "tailwind-merge"; -import type { TTimelineSort } from "@/types/timeline/api"; import type { ITimelineSummaryPanelData } from "@/types/timeline/summary"; import type { ITimelineCampaignBar, TTimelineViewUnit, } from "@/types/timeline/ui"; -import type { TTimelineStatusFilter } from "@/constants/timeline/filterSort"; import { TIMELINE_COL_WIDTH, TIMELINE_PAGE_HEIGHT, @@ -44,6 +42,7 @@ import TimelineStatusLegend from "@/components/timeline/TimelineStatusLegend"; import PlusIcon from "@/assets/icon/common/plus.svg?react"; import TrashIcon from "@/assets/icon/common/trash.svg?react"; +import useTimelineStore from "@/store/useTimelineStore"; const SUMMARY_POLL_INTERVAL_MS = 1500; const SUMMARY_POLL_TIMEOUT_MS = 90000; @@ -69,9 +68,10 @@ export default function Timeline() { number | null >(null); - const [statusFilter, setStatusFilter] = - useState("ALL"); - const [sort, setSort] = useState("DISPLAY_ORDER"); + const statusFilter = useTimelineStore((s) => s.statusFilter); + const sort = useTimelineStore((s) => s.sort); + const setStatusFilter = useTimelineStore((s) => s.setStatusFilter); + const setSort = useTimelineStore((s) => s.setSort); const { mutate: deleteTimeline, isPending: isDeleting } = useDeleteTimeline(); const { mutate: requestSummary, isPending: isSummaryPending } = diff --git a/src/store/useTimelineStore.ts b/src/store/useTimelineStore.ts new file mode 100644 index 00000000..ec21240e --- /dev/null +++ b/src/store/useTimelineStore.ts @@ -0,0 +1,20 @@ +import { create } from "zustand"; + +import type { TTimelineSort } from "@/types/timeline/api"; +import type { TTimelineStatusFilter } from "@/constants/timeline/filterSort"; + +interface ITimelineUiState { + statusFilter: TTimelineStatusFilter; + sort: TTimelineSort; + setStatusFilter: (statusFilter: TTimelineStatusFilter) => void; + setSort: (sort: TTimelineSort) => void; +} + +const useTimelineStore = create((set) => ({ + statusFilter: "ALL", + sort: "DISPLAY_ORDER", + setStatusFilter: (statusFilter) => set({ statusFilter }), + setSort: (sort) => set({ sort }), +})); + +export default useTimelineStore;