diff --git a/src/types/timeline/api.ts b/src/types/timeline/api.ts new file mode 100644 index 00000000..76aa827e --- /dev/null +++ b/src/types/timeline/api.ts @@ -0,0 +1,85 @@ +import type { TProviderType } from "../dashboard/provider"; + +/*타임라인 추적 지표*/ +export const TIMELINE_METRICS = [ + "CLICK", + "CONVERSION", + "IMPRESSION", + "ROAS", +] as const; +export type TTimelineMetric = (typeof TIMELINE_METRICS)[number]; + +/*성과 상태*/ +export const TIMELINE_PERFORMANCE_STATUS = [ + "ON_TRACK", + "AT_RISK", + "OFF_TRACK", +] as const; +export type TTimelinePerformanceStatus = + (typeof TIMELINE_PERFORMANCE_STATUS)[number]; + +/*비교 기간 타입*/ +export const TIMELINE_COMPARISON_PERIOD_TYPES = [ + "LAST_WEEK", + "LAST_MONTH", + "PREVIOUS_PERIOD", +] as const; +export type TTimelineComparisonPeriodType = + (typeof TIMELINE_COMPARISON_PERIOD_TYPES)[number]; + +export interface ITimelineListItem { + timelineId: number; + name: string; + startDate: string; + endDate: string; + performanceStatus: TTimelinePerformanceStatus; +} + +export interface ITimelineDailyTrend { + date: string; + clicks: number; + conversions: number; + impressions: number; + roas: number; +} + +export interface ITimelinePlatformContribution { + platform: TProviderType; + contributionRate: number; +} + +export interface ITimelineDetail { + timelineId: number; + name: string; + startDate: string; + endDate: string; + performanceStatus: TTimelinePerformanceStatus; + metrics: TTimelineMetric[]; + summary: string; + dailyTrend: ITimelineDailyTrend[]; + platformContributions: ITimelinePlatformContribution[]; +} + +/* Request body*/ +export interface ITimelineUpsertRequest { + name: string; + startDate: string; + endDate: string; + metrics: TTimelineMetric[]; + comparisonPeriodType: TTimelineComparisonPeriodType; +} + +export interface ITimelineMutationResponse { + timelineId: number; + name: string; + startDate: string; + endDate: string; + metrics: TTimelineMetric[]; + comparisonStartDate: string; + comparisonEndDate: string; + performanceStatus: TTimelinePerformanceStatus; + createdAt: string; +} + +/*DELETE / summary 요청 등 빈 data*/ +export type TTimelineEmptyResponse = Record; diff --git a/src/types/timeline/form.ts b/src/types/timeline/form.ts new file mode 100644 index 00000000..90e22388 --- /dev/null +++ b/src/types/timeline/form.ts @@ -0,0 +1,21 @@ +import type { + TTimelineComparisonPeriodType, + TTimelineMetric, +} from "@/types/timeline/api"; + +export interface ITimelineFormValues { + name: string; + startDate: string; + endDate: string; + metrics: TTimelineMetric[]; + comparisonPeriodType: TTimelineComparisonPeriodType; +} + +/*후속 zod 연동 전 기본값*/ +export const TIMELINE_FORM_DEFAULT_VALUES: ITimelineFormValues = { + name: "", + startDate: "", + endDate: "", + metrics: ["CLICK"], + comparisonPeriodType: "LAST_WEEK", +}; diff --git a/src/types/timeline/summary.ts b/src/types/timeline/summary.ts new file mode 100644 index 00000000..3684a106 --- /dev/null +++ b/src/types/timeline/summary.ts @@ -0,0 +1,26 @@ +import type { TProviderType } from "@/types/dashboard/provider"; +import type { TTimelineMetric } from "@/types/timeline/api"; + +/*패널 상단 KPI 카드 한개*/ +export interface ITimelineSummaryMetric { + metric: TTimelineMetric; + label: string; //클릭, 전환 등 UI 라벨 + value: number; //실제 값 + unit?: string; // %, 회 + changeRate?: number; //전기 대비 (-0.05 = -5%) +} + +/*플랫폼 기여도*/ +export interface ITimelineSummaryPlatformShare { + provider: TProviderType; + contributionRate: number; /*기여도*/ +} + +/*성과 요약 패널 전체*/ +export interface ITimelineSummaryPanelData { + timelineName: string; + periodLabel: string; + aiSummary: string; + metrics: ITimelineSummaryMetric[]; + platformShare: ITimelineSummaryPlatformShare[]; +} diff --git a/src/types/timeline/timeline.mock.ts b/src/types/timeline/timeline.mock.ts new file mode 100644 index 00000000..8aaf94df --- /dev/null +++ b/src/types/timeline/timeline.mock.ts @@ -0,0 +1,141 @@ +import type { + ITimelineDetail, + ITimelineListItem, + ITimelineMutationResponse, +} from "@/types/timeline/api"; +import type { ITimelineSummaryPanelData } from "@/types/timeline/summary"; +import type { ITimelineGridData } from "@/types/timeline/ui"; + +/*GET /timeline 목록 mock*/ +export const TIMELINE_LIST_MOCK: ITimelineListItem[] = [ + { + timelineId: 1, + name: "6월 봄 프로모션", + startDate: "2026-06-01", + endDate: "2026-06-30", + performanceStatus: "ON_TRACK", + }, + { + timelineId: 2, + name: "리타겟팅 집중 기간", + startDate: "2026-06-10", + endDate: "2026-06-30", + performanceStatus: "AT_RISK", + }, +]; + +/*GET /timeline/{id} 상세 mock*/ +export const TIMELINE_DETAIL_MOCK: ITimelineDetail = { + timelineId: 1, + name: "6월 봄 프로모션", + startDate: "2026-06-01", + endDate: "2026-06-30", + performanceStatus: "ON_TRACK", + metrics: ["CLICK", "CONVERSION", "ROAS"], + summary: + "Google Ads 전환이 전주 대비 12% 상승했습니다. Meta는 노출은 늘었으나 ROAS가 소폭 하락했습니다.", + dailyTrend: [ + { + date: "2026-06-18", + clicks: 1240, + conversions: 86, + impressions: 45200, + roas: 3.2, + }, + { + date: "2026-06-19", + clicks: 1310, + conversions: 91, + impressions: 46800, + roas: 3.4, + }, + { + date: "2026-06-20", + clicks: 1180, + conversions: 78, + impressions: 44100, + roas: 2.9, + }, + ], + platformContributions: [ + { platform: "GOOGLE", contributionRate: 0.52 }, + { platform: "META", contributionRate: 0.31 }, + { platform: "NAVER", contributionRate: 0.17 }, + ], +}; + +/*POST 생성 응답 mock*/ +export const TIMELINE_CREATE_RESPONSE_MOCK: ITimelineMutationResponse = { + timelineId: 3, + name: "신규 타임라인", + startDate: "2026-06-01", + endDate: "2026-06-30", + metrics: ["CLICK"], + comparisonStartDate: "2026-05-25", + comparisonEndDate: "2026-05-31", + performanceStatus: "ON_TRACK", + createdAt: "2026-06-20T07:58:24.795Z", +}; + +/*UI 그리드 mock*/ +export const TIMELINE_GRID_MOCK: ITimelineGridData = { + viewUnit: "WEEK", + periodLabel: "30 Dec - 5 Jan", + columns: [ + { day: "M", date: 30, isWeekend: false }, + { day: "T", date: 31, isWeekend: false }, + { day: "W", date: 1, isWeekend: false }, + { day: "T", date: 2, isWeekend: false, isToday: true }, + { day: "F", date: 3, isWeekend: false }, + { day: "S", date: 4, isWeekend: true }, + { day: "S", date: 5, isWeekend: true }, + ], + bars: [ + { + id: 1, + title: "봄 프로모션 캠페인", + subtitle: "Google Ads 전환", + provider: "GOOGLE", + colStart: 3.2, + colEnd: 9, + row: 1, + colorClass: "bg-primary-300", + performanceStatus: "ON_TRACK", + }, + { + id: 2, + title: "리타겟팅 캠페인", + subtitle: "META 트래픽", + provider: "META", + colStart: 8.9, + colEnd: 15.3, + row: 2, + colorClass: "bg-primary-400", + performanceStatus: "AT_RISK", + }, + ], +}; + +/*성과 요약 패널 mock*/ +export const TIMELINE_SUMMARY_PANEL_MOCK: ITimelineSummaryPanelData = { + timelineName: TIMELINE_DETAIL_MOCK.name, + periodLabel: "2026.06.01 ~ 2026.06.30", + aiSummary: TIMELINE_DETAIL_MOCK.summary, + metrics: [ + { metric: "CLICK", label: "클릭", value: 3730, changeRate: 0.08 }, + { metric: "CONVERSION", label: "전환", value: 255, changeRate: 0.12 }, + { metric: "IMPRESSION", label: "노출", value: 136100, changeRate: 0.05 }, + { + metric: "ROAS", + label: "ROAS", + value: 3.17, + unit: "x", + changeRate: -0.03, + }, + ], + platformShare: [ + { provider: "GOOGLE", contributionRate: 0.52 }, + { provider: "META", contributionRate: 0.31 }, + { provider: "NAVER", contributionRate: 0.17 }, + ], +}; diff --git a/src/types/timeline/ui.ts b/src/types/timeline/ui.ts new file mode 100644 index 00000000..29b2b5ed --- /dev/null +++ b/src/types/timeline/ui.ts @@ -0,0 +1,35 @@ +import type { TProviderType } from "@/types/dashboard/provider"; +import type { TTimelinePerformanceStatus } from "@/types/timeline/api"; + +export type TTimelineViewUnit = "DAY" | "WEEK" | "MONTH"; + +/*날짜 축 한칸*/ +export interface ITimelineGridColumn { + day: string; + date: number; + isWeekend: boolean; + isToday?: boolean; + /*원본 날짜*/ + isoDate?: string; +} + +/*타임라인 위 캠페인 바*/ +export interface ITimelineCampaignBar { + id: number; + title: string; + subtitle: string; + provider?: TProviderType; + colStart: number; //그리드 시작 위치 + colEnd: number; + row: number; + colorClass: string; + performanceStatus?: TTimelinePerformanceStatus; +} + +/*그리드 + 바 묶음*/ +export interface ITimelineGridData { + viewUnit: TTimelineViewUnit; + periodLabel: string; + columns: ITimelineGridColumn[]; + bars: ITimelineCampaignBar[]; +}