From e38bc4c17366b3c3ce23f9742706794a04ecdc9c Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Thu, 12 Feb 2026 23:38:16 +0900 Subject: [PATCH 01/96] =?UTF-8?q?feat:=20dashboard=20card=20code=20type=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard-edit/MiniViewActiveCard.tsx | 7 +++- .../dashboard/dashboardMetricCards.ts | 39 ++++++++++++++++++- frontend/src/constants/dashboard/index.ts | 1 + 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/dashboard/dashboard-edit/MiniViewActiveCard.tsx b/frontend/src/components/dashboard/dashboard-edit/MiniViewActiveCard.tsx index a7de08fa..d1757770 100644 --- a/frontend/src/components/dashboard/dashboard-edit/MiniViewActiveCard.tsx +++ b/frontend/src/components/dashboard/dashboard-edit/MiniViewActiveCard.tsx @@ -2,11 +2,14 @@ import { XIcon } from 'lucide-react'; import { PeriodTag } from '@/components/shared'; import { Button } from '@/components/shared/shadcn-ui'; -import { DASHBOARD_METRIC_CARDS } from '@/constants/dashboard'; +import { + DASHBOARD_METRIC_CARDS, + type MetricCardCode, +} from '@/constants/dashboard'; import { CDN_BASE_URL } from '@/constants/shared/cdnBaseUrl'; interface MiniViewActiveCardProps { - cardCode: string; + cardCode: MetricCardCode; posX: number; posY: number; } diff --git a/frontend/src/constants/dashboard/dashboardMetricCards.ts b/frontend/src/constants/dashboard/dashboardMetricCards.ts index a2b58327..d577b9ab 100644 --- a/frontend/src/constants/dashboard/dashboardMetricCards.ts +++ b/frontend/src/constants/dashboard/dashboardMetricCards.ts @@ -21,7 +21,44 @@ interface MetricCard { sizeY: number; // 세로 크기 (기본값 1) } -export const DASHBOARD_METRIC_CARDS: Record = { +export type MetricCardCode = + | 'WTH_01_01' + | 'WTH_02_01' + | 'WTH_03_04' + | 'WTH_04_07' + | 'WTH_05_07' + | 'WTH_06_07' + | 'SLS_01_01' + | 'SLS_01_02' + | 'SLS_01_03' + | 'SLS_02_01' + | 'SLS_02_02' + | 'SLS_02_03' + | 'SLS_03_01' + | 'SLS_03_02' + | 'SLS_03_03' + | 'SLS_06_01' + | 'SLS_06_02' + | 'SLS_06_03' + | 'SLS_07_01' + | 'SLS_07_02' + | 'SLS_07_03' + | 'SLS_08_01' + | 'SLS_08_02' + | 'SLS_08_03' + | 'SLS_09_04' + | 'SLS_10_07' + | 'SLS_11_07' + | 'SLS_13_01' + | 'SLS_14_06' + | 'MNU_01_01' + | 'MNU_01_04' + | 'MNU_01_05' + | 'MNU_03_01' + | 'MNU_04_01' + | 'MNU_05_04'; + +export const DASHBOARD_METRIC_CARDS: Record = { SLS_01_01: { code: 'SLS_01_01', label: '오늘 실매출', diff --git a/frontend/src/constants/dashboard/index.ts b/frontend/src/constants/dashboard/index.ts index 259eb0cd..02740239 100644 --- a/frontend/src/constants/dashboard/index.ts +++ b/frontend/src/constants/dashboard/index.ts @@ -10,3 +10,4 @@ export { type MetricItem, } from './dashboardMetric'; export { DASHBOARD_METRIC_CARDS } from './dashboardMetricCards'; +export { type MetricCardCode } from './dashboardMetricCards'; From ce16b2fe838ca10341a5ad1825227010fe5d61a6 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Thu, 12 Feb 2026 23:49:28 +0900 Subject: [PATCH 02/96] =?UTF-8?q?chore:=20=EB=8C=80=EC=8B=9C=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=ED=8E=B8=EC=A7=91=20=EC=B9=B4=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20=EC=82=AD=EC=A0=9C=20=EB=B2=84=ED=8A=BC=20shadcn?= =?UTF-8?q?=20button=EC=9C=BC=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/shared/edit-card-wrapper/PlusIconButton.tsx | 6 ++++-- .../shared/edit-card-wrapper/TrashCanIconButton.tsx | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/shared/edit-card-wrapper/PlusIconButton.tsx b/frontend/src/components/shared/edit-card-wrapper/PlusIconButton.tsx index fda2a74f..753f865c 100644 --- a/frontend/src/components/shared/edit-card-wrapper/PlusIconButton.tsx +++ b/frontend/src/components/shared/edit-card-wrapper/PlusIconButton.tsx @@ -1,5 +1,7 @@ import { Plus } from 'lucide-react'; +import { Button } from '../shadcn-ui'; + // 대시보드 편집 용 패널의 우측 위 + 버튼 interface PlusIconButtonProps { onClickAddButton?: () => void; @@ -7,11 +9,11 @@ interface PlusIconButtonProps { export const PlusIconButton = ({ onClickAddButton }: PlusIconButtonProps) => { return ( - + ); }; diff --git a/frontend/src/components/shared/edit-card-wrapper/TrashCanIconButton.tsx b/frontend/src/components/shared/edit-card-wrapper/TrashCanIconButton.tsx index d327d9f5..5095e6ff 100644 --- a/frontend/src/components/shared/edit-card-wrapper/TrashCanIconButton.tsx +++ b/frontend/src/components/shared/edit-card-wrapper/TrashCanIconButton.tsx @@ -1,5 +1,7 @@ import { Trash2 } from 'lucide-react'; +import { Button } from '../shadcn-ui'; + // 대시보드 편집 용 패널의 우측 위 쓰래기통 버튼 interface TrashCanIconButtonProps { onClickDeleteButton?: () => void; @@ -9,11 +11,11 @@ export const TrashCanIconButton = ({ onClickDeleteButton, }: TrashCanIconButtonProps) => { return ( - + ); }; From b01ffa84d83e92cb9798c6a43b5fb13a03e54f06 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 10:10:35 +0900 Subject: [PATCH 03/96] =?UTF-8?q?feat:=20dashboard=20metric=20card=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=83=80=EC=9E=85=20=EC=A0=9C=EB=84=88=EB=A6=AD=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard-edit/CardEditViewCard.tsx | 21 +- .../dashboard-edit/CardEditViewTabContent.tsx | 8 +- .../dashboard-edit/CardEditViewTabs.tsx | 9 +- .../constants/dashboard/dashboardMetric.ts | 310 ++++++++++-------- .../dashboard/dashboardMetricCards.ts | 47 +-- frontend/src/constants/dashboard/index.ts | 9 +- 6 files changed, 218 insertions(+), 186 deletions(-) diff --git a/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx b/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx index 55b73570..cce0edc4 100644 --- a/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx +++ b/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx @@ -1,8 +1,12 @@ import { EditCardWrapper } from '@/components/shared'; -import { DASHBOARD_METRIC_CARDS } from '@/constants/dashboard'; +import { + DASHBOARD_METRIC_CARDS, + type MetricCardCode, +} from '@/constants/dashboard'; +import { formatNumber } from '@/utils/shared'; interface CardEditViewCardProps { - cardCode: string; + cardCode: MetricCardCode; } export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { const card = DASHBOARD_METRIC_CARDS[cardCode]; @@ -21,6 +25,7 @@ export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { className="min-w-full" sizeX={sizeX} sizeY={sizeY} + innerClassName="items-start" > {label}
@@ -29,6 +34,18 @@ export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { {type}
{sizeX} x {sizeY} +
+ + + {formatNumber(295600)} + + + + + {`지난주 월요일\n이 시간보다`} + 5% 늘었어요 + +
); diff --git a/frontend/src/components/dashboard/dashboard-edit/CardEditViewTabContent.tsx b/frontend/src/components/dashboard/dashboard-edit/CardEditViewTabContent.tsx index 5c5c510c..8be7d13f 100644 --- a/frontend/src/components/dashboard/dashboard-edit/CardEditViewTabContent.tsx +++ b/frontend/src/components/dashboard/dashboard-edit/CardEditViewTabContent.tsx @@ -1,22 +1,22 @@ -import type { MetricSection } from '@/constants/dashboard'; +import type { MetricTabs } from '@/constants/dashboard'; import { CardEditViewTabContentItem } from './CardEditViewTabContentItem'; interface CardEditViewTabContentProps { - sections: MetricSection[]; + sections: MetricTabs['sections']; } export const CardEditViewTabContent = ({ sections, }: CardEditViewTabContentProps) => { return (
- {sections.map((section) => ( + {Object.values(sections).map((section) => (

{section.title}

    - {section.items.map((item) => ( + {Object.values(section.items).map((item) => ( ))}
diff --git a/frontend/src/components/dashboard/dashboard-edit/CardEditViewTabs.tsx b/frontend/src/components/dashboard/dashboard-edit/CardEditViewTabs.tsx index 1ad77421..98c78029 100644 --- a/frontend/src/components/dashboard/dashboard-edit/CardEditViewTabs.tsx +++ b/frontend/src/components/dashboard/dashboard-edit/CardEditViewTabs.tsx @@ -1,3 +1,5 @@ +import { useMemo } from 'react'; + import { Tabs, TabsContent, @@ -9,10 +11,11 @@ import { DASHBOARD_METRICS } from '@/constants/dashboard'; import { CardEditViewTabContent } from './CardEditViewTabContent'; export const CardEditViewTabs = () => { + const dashboardMetrics = useMemo(() => Object.values(DASHBOARD_METRICS), []); return ( - + - {DASHBOARD_METRICS.map(({ tab }) => ( + {dashboardMetrics.map(({ tab }) => ( { ))}
- {DASHBOARD_METRICS.map(({ tab, sections }) => ( + {dashboardMetrics.map(({ tab, sections }) => ( diff --git a/frontend/src/constants/dashboard/dashboardMetric.ts b/frontend/src/constants/dashboard/dashboardMetric.ts index aec6ea6b..3ed6d0da 100644 --- a/frontend/src/constants/dashboard/dashboardMetric.ts +++ b/frontend/src/constants/dashboard/dashboardMetric.ts @@ -1,155 +1,193 @@ +import type { MetricCardCode } from './dashboardMetricCards'; + /** * 카드 및 섹션 구조 인터페이스 */ export interface MetricItem { label: string; // 실매출 - cardCodes: string[]; // SLS_01_01, SLS_01_02, ... + cardCodes: readonly MetricCardCode[]; // SLS_01_01, SLS_01_02, ... } export interface MetricSection { title: string; // 매출 현황 - items: MetricItem[]; // 실매출, 주문건수, 건당평균가, + items: Record; // 실매출, 주문건수, 건당평균가, } -interface MetricTabs { +export interface MetricTabs { tab: string; // 매출분석 - sections: MetricSection[]; // 섹션 배열 + sections: Record; // 섹션 정보 } /** * 메인 대시보드 구성 (최종 상수) */ -const SALES_METRICS: MetricSection[] = [ - { - title: '매출현황', - items: [ - { - label: '실매출', - cardCodes: ['SLS_01_01', 'SLS_01_02', 'SLS_01_03'], - }, - { - label: '주문건수', - cardCodes: ['SLS_02_01', 'SLS_02_02', 'SLS_02_03'], - }, - { - label: '건당 평균가', - cardCodes: ['SLS_03_01', 'SLS_03_02', 'SLS_03_03'], - }, - ], - }, - { - title: '매출 유입 구조', - items: [ - { - label: '판매유형별 매출', - cardCodes: ['SLS_06_01', 'SLS_06_02', 'SLS_06_03'], - }, - { - label: '주문수단별 매출', - cardCodes: ['SLS_07_01', 'SLS_07_02', 'SLS_07_03'], - }, - { - label: '결제수단별 매출', - cardCodes: ['SLS_08_01', 'SLS_08_02', 'SLS_08_03'], - }, - ], - }, - { - title: '매출 추이', - items: [ - { - label: '일별 매출 추이', - cardCodes: ['SLS_09_04'], - }, - { - label: '주별 매출 추이', - cardCodes: ['SLS_10_07'], - }, - { - label: '월별 매출 추이', - cardCodes: ['SLS_11_07'], - }, - ], - }, - { - title: '매출 패턴', - items: [ - { - label: '피크타임', - cardCodes: ['SLS_13_01'], - }, - { - label: '요일별 매출 패턴', - cardCodes: ['SLS_14_06'], - }, - ], - }, -]; -const MENU_METRICS: MetricSection[] = [ - { - title: '인기메뉴', - items: [ - { - label: '메뉴별 매출 랭킹', - cardCodes: ['MNU_01_01', 'MNU_01_04', 'MNU_01_05'], - }, - ], +const SALES_METRICS = { + tab: '매출분석', + sections: { + CURRENT_SALES: { + title: '매출현황', + items: { + REAL_SALES: { + label: '실매출', + cardCodes: ['SLS_01_01', 'SLS_01_02', 'SLS_01_03'] as const, + }, + ORDER_COUNT: { + label: '주문건수', + cardCodes: ['SLS_02_01', 'SLS_02_02', 'SLS_02_03'] as const, + }, + AVERAGE_PRICE: { + label: '건당 평균가', + cardCodes: ['SLS_03_01', 'SLS_03_02', 'SLS_03_03'] as const, + }, + }, + }, + INCOME_STRUCTURE: { + title: '매출 유입 구조', + items: { + SALES_TYPE: { + label: '판매유형별 매출', + cardCodes: ['SLS_06_01', 'SLS_06_02', 'SLS_06_03'] as const, + }, + ORDER_METHOD: { + label: '주문수단별 매출', + cardCodes: ['SLS_07_01', 'SLS_07_02', 'SLS_07_03'] as const, + }, + PAYMENT_METHOD: { + label: '결제수단별 매출', + cardCodes: ['SLS_08_01', 'SLS_08_02', 'SLS_08_03'] as const, + }, + }, + }, + SAELS_TREND: { + title: '매출 추이', + items: { + DAILY_SALES_TREND: { + label: '일별 매출 추이', + cardCodes: ['SLS_09_04'] as const, + }, + WEEKLY_SALES_TREND: { + label: '주별 매출 추이', + cardCodes: ['SLS_10_07'] as const, + }, + MONTHLY_SALES_TREND: { + label: '월별 매출 추이', + cardCodes: ['SLS_11_07'] as const, + }, + }, + }, + SALES_PATTERN: { + title: '매출 패턴', + items: { + PEAK_TIME: { + label: '피크타임', + cardCodes: ['SLS_13_01'] as const, + }, + WEEKDAY_SALES_PATTERN: { + label: '요일별 매출 패턴', + cardCodes: ['SLS_14_06'] as const, + }, + }, + }, }, - { - title: '메뉴 판매 패턴', - items: [ - { - label: '시간대별 메뉴 주문건수', - cardCodes: ['MNU_03_01'], - }, - { - label: '식재료 소진량', - cardCodes: ['MNU_04_01'], - }, - { - label: '인기 메뉴 조합', - cardCodes: ['MNU_05_04'], - }, - ], - }, -]; -const WEATHER_METRICS: MetricSection[] = [ - { - title: '날씨예보', - items: [ - { - label: '오늘 날씨 예보', - cardCodes: ['WTH_01_01'], - }, - { - label: '오늘 시간별 예보', - cardCodes: ['WTH_02_01'], - }, - { - label: '주간 날씨 예보', - cardCodes: ['WTH_03_04'], - }, - ], +} as const satisfies MetricTabs; + +const MENU_METRICS = { + tab: '메뉴분석', + sections: { + POPULAR_MENU: { + title: '인기메뉴', + items: { + MENU_SALES_RANKING: { + label: '메뉴별 매출 랭킹', + cardCodes: ['MNU_01_01', 'MNU_01_04', 'MNU_01_05'] as const, + }, + }, + }, + MENU_SALES_PATTERN: { + title: '메뉴 판매 패턴', + items: { + TIME_BASED_MENU_ORDER_COUNT: { + label: '시간대별 메뉴 주문건수', + cardCodes: ['MNU_03_01'] as const, + }, + }, + }, + INGREDIENT_CONSUMPTION_RANK: { + title: '식재료 소진량', + items: { + INGREDIENT_CONSUMPTION_RANK: { + label: '식재료 소진량', + cardCodes: ['MNU_04_01'] as const, + }, + }, + }, + POPULAR_MENU_COMBINATION: { + title: '인기 메뉴 조합', + items: { + POPULAR_MENU_COMBINATION: { + label: '인기 메뉴 조합', + cardCodes: ['MNU_05_04'] as const, + }, + }, + }, }, - { - title: '강수 영향도', - items: [ - { - label: '강수 인사이트', - cardCodes: ['WTH_04_07'], - }, - { - label: '강수 유무 판매채널별 주문건수 비율', - cardCodes: ['WTH_05_07'], - }, - { - label: '강수 주문수 및 매출 변화', - cardCodes: ['WTH_06_07'], - }, - ], +} as const satisfies MetricTabs; + +const WEATHER_METRICS = { + tab: '날씨분석', + sections: { + WEATHER_FORECAST: { + title: '날씨예보', + items: { + TODAY_WEATHER_FORECAST: { + label: '오늘 날씨 예보', + cardCodes: ['WTH_01_01'] as const, + }, + TODAY_WEATHER_FORECAST_HOURLY: { + label: '오늘 시간별 예보', + cardCodes: ['WTH_02_01'] as const, + }, + WEEKLY_WEATHER_FORECAST: { + label: '주간 날씨 예보', + cardCodes: ['WTH_03_04'] as const, + }, + }, + }, + RAIN_INFLUENCE: { + title: '강수 영향도', + items: { + RAIN_INSIGHT: { + label: '강수 인사이트', + cardCodes: ['WTH_04_07'] as const, + }, + ORDER_COUNT_RATIO: { + label: '강수 유무 판매채널별 주문건수 비율', + cardCodes: ['WTH_05_07'] as const, + }, + ORDER_COUNT_AND_SALES_CHANGE: { + label: '강수 주문수 및 매출 변화', + cardCodes: ['WTH_06_07'] as const, + }, + }, + }, }, -]; +} as const satisfies MetricTabs; -export const DASHBOARD_METRICS: MetricTabs[] = [ - { tab: '매출분석', sections: SALES_METRICS }, - { tab: '메뉴분석', sections: MENU_METRICS }, - { tab: '날씨분석', sections: WEATHER_METRICS }, -]; +export const DASHBOARD_METRICS = { + SALES: SALES_METRICS, + MENU: MENU_METRICS, + WEATHER: WEATHER_METRICS, +} as const satisfies Record; + +/** + * 주어진 T가 readonly cardCodes 프로퍼티를 가지고 있고 + * cardCodes 프로퍼티의 타입이 MetricCardCode 하위타입의 배열인 경우 + * cardCodes 프로퍼티의 타입을 추출하는 유틸리티 타입 + * + * @example + * type RealSalesCardCode = ExtractCardCodes; + * 결과: 'SLS_01_01' | 'SLS_01_02' | 'SLS_01_03'; + */ +export type ExtractCardCodes = T extends { + readonly cardCodes: readonly (infer U extends MetricCardCode)[]; +} + ? U + : never; diff --git a/frontend/src/constants/dashboard/dashboardMetricCards.ts b/frontend/src/constants/dashboard/dashboardMetricCards.ts index d577b9ab..6b3aa6ca 100644 --- a/frontend/src/constants/dashboard/dashboardMetricCards.ts +++ b/frontend/src/constants/dashboard/dashboardMetricCards.ts @@ -21,44 +21,7 @@ interface MetricCard { sizeY: number; // 세로 크기 (기본값 1) } -export type MetricCardCode = - | 'WTH_01_01' - | 'WTH_02_01' - | 'WTH_03_04' - | 'WTH_04_07' - | 'WTH_05_07' - | 'WTH_06_07' - | 'SLS_01_01' - | 'SLS_01_02' - | 'SLS_01_03' - | 'SLS_02_01' - | 'SLS_02_02' - | 'SLS_02_03' - | 'SLS_03_01' - | 'SLS_03_02' - | 'SLS_03_03' - | 'SLS_06_01' - | 'SLS_06_02' - | 'SLS_06_03' - | 'SLS_07_01' - | 'SLS_07_02' - | 'SLS_07_03' - | 'SLS_08_01' - | 'SLS_08_02' - | 'SLS_08_03' - | 'SLS_09_04' - | 'SLS_10_07' - | 'SLS_11_07' - | 'SLS_13_01' - | 'SLS_14_06' - | 'MNU_01_01' - | 'MNU_01_04' - | 'MNU_01_05' - | 'MNU_03_01' - | 'MNU_04_01' - | 'MNU_05_04'; - -export const DASHBOARD_METRIC_CARDS: Record = { +export const DASHBOARD_METRIC_CARDS = { SLS_01_01: { code: 'SLS_01_01', label: '오늘 실매출', @@ -339,4 +302,10 @@ export const DASHBOARD_METRIC_CARDS: Record = { sizeX: 1, sizeY: 1, }, -} as const; +} as const satisfies Record; + +export type MetricCardCode = keyof typeof DASHBOARD_METRIC_CARDS; + +export const isMetricCardCode = (code: string): code is MetricCardCode => { + return code in DASHBOARD_METRIC_CARDS; +}; diff --git a/frontend/src/constants/dashboard/index.ts b/frontend/src/constants/dashboard/index.ts index 02740239..02c44e9d 100644 --- a/frontend/src/constants/dashboard/index.ts +++ b/frontend/src/constants/dashboard/index.ts @@ -8,6 +8,11 @@ export { DASHBOARD_METRICS, type MetricSection, type MetricItem, + type MetricTabs, + type ExtractCardCodes, } from './dashboardMetric'; -export { DASHBOARD_METRIC_CARDS } from './dashboardMetricCards'; -export { type MetricCardCode } from './dashboardMetricCards'; +export { + DASHBOARD_METRIC_CARDS, + isMetricCardCode, + type MetricCardCode, +} from './dashboardMetricCards'; From 95cb8dcaa0ef3cf993d014a76dfc23746154fab8 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 16:34:14 +0900 Subject: [PATCH 04/96] =?UTF-8?q?feat:=20=ED=8A=B9=EC=A0=95=20section?= =?UTF-8?q?=EC=9D=98=20=EC=B9=B4=EB=93=9C=20type=20=EC=B6=94=EC=B6=9C=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/constants/dashboard/dashboardMetric.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/frontend/src/constants/dashboard/dashboardMetric.ts b/frontend/src/constants/dashboard/dashboardMetric.ts index 3ed6d0da..3cfb1284 100644 --- a/frontend/src/constants/dashboard/dashboardMetric.ts +++ b/frontend/src/constants/dashboard/dashboardMetric.ts @@ -56,7 +56,7 @@ const SALES_METRICS = { }, }, }, - SAELS_TREND: { + SALES_TREND: { title: '매출 추이', items: { DAILY_SALES_TREND: { @@ -191,3 +191,17 @@ export type ExtractCardCodes = T extends { } ? U : never; + +/** + * 주어진 T가 MetricSection 타입인 경우 + * + * MetricSection의 item들의 cardCodes 타입을 추출하는 유틸리티 타입 + * + * @example + * type RealSalesCardCode = ExtractCardCodesFromSection; + * 결과: 'SLS_01_01' | 'SLS_01_02' | 'SLS_01_03' | 'SLS_02_01' | 'SLS_02_02' | 'SLS_02_03' | 'SLS_03_01' | 'SLS_03_02' | 'SLS_03_03'; + * + */ +export type ExtractCardCodesFromSection = T extends MetricSection + ? ExtractCardCodes + : never; From 67098409bb53b876c95f97be4d02d19ab7b7fc76 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 18:24:24 +0900 Subject: [PATCH 05/96] =?UTF-8?q?feat:=20=EC=A7=80=ED=91=9C=20=EB=B0=A9?= =?UTF-8?q?=ED=96=A5=EC=84=B1=20=EA=B4=80=EB=A0=A8=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/dashboard/index.ts | 2 ++ frontend/src/constants/dashboard/metricTrend.ts | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 frontend/src/constants/dashboard/metricTrend.ts diff --git a/frontend/src/constants/dashboard/index.ts b/frontend/src/constants/dashboard/index.ts index 02c44e9d..406e594d 100644 --- a/frontend/src/constants/dashboard/index.ts +++ b/frontend/src/constants/dashboard/index.ts @@ -10,9 +10,11 @@ export { type MetricItem, type MetricTabs, type ExtractCardCodes, + type ExtractCardCodesFromSection, } from './dashboardMetric'; export { DASHBOARD_METRIC_CARDS, isMetricCardCode, type MetricCardCode, } from './dashboardMetricCards'; +export { METRIC_TREND, type MetricTrend } from './metricTrend'; diff --git a/frontend/src/constants/dashboard/metricTrend.ts b/frontend/src/constants/dashboard/metricTrend.ts new file mode 100644 index 00000000..bb876fd8 --- /dev/null +++ b/frontend/src/constants/dashboard/metricTrend.ts @@ -0,0 +1,9 @@ +import type { ValueOf } from '@/utils/shared'; + +export const METRIC_TREND = { + UP: 'up', + DOWN: 'down', + SAME: 'same', +} as const; + +export type MetricTrend = ValueOf; From 9223f5ba8a971495644eadc825aad8232bb66eeb Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 18:24:45 +0900 Subject: [PATCH 06/96] =?UTF-8?q?feat:=20edit=20card=20wrapper=20inner=20c?= =?UTF-8?q?lass=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared/edit-card-wrapper/EditCardWrapper.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx b/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx index 4c96b597..eaf5d118 100644 --- a/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx +++ b/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx @@ -16,6 +16,7 @@ interface EditCardWrapperProps { isAdded: boolean; children: ReactNode; className?: string; // 전체 wrapper 크기나 보더 등 스타일 + innerClassName?: string; // 자식 컴포넌트 클래스명 period: string; // 오늘, 이번주, 이번달 등 문구 sizeX?: number; // 가로 크기 sizeY?: number; // 세로 크기 @@ -29,6 +30,7 @@ export const EditCardWrapper = ({ isAdded, children, className, + innerClassName, sizeX = 1, sizeY = 1, period = '기간없음', @@ -68,7 +70,10 @@ export const EditCardWrapper = ({
Date: Fri, 13 Feb 2026 18:25:11 +0900 Subject: [PATCH 07/96] =?UTF-8?q?feat:=20=EB=AF=B8=EB=8B=88=EB=B7=B0=20met?= =?UTF-8?q?ricCardCode=20=ED=83=80=EC=9E=85=20=EA=B0=80=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/dashboard-edit/MiniView.tsx | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/dashboard/dashboard-edit/MiniView.tsx b/frontend/src/components/dashboard/dashboard-edit/MiniView.tsx index c1876289..8838148c 100644 --- a/frontend/src/components/dashboard/dashboard-edit/MiniView.tsx +++ b/frontend/src/components/dashboard/dashboard-edit/MiniView.tsx @@ -1,7 +1,10 @@ import { useMemo, useState } from 'react'; import { useLocation } from 'react-router-dom'; -import { DASHBOARD_METRIC_CARDS } from '@/constants/dashboard'; +import { + DASHBOARD_METRIC_CARDS, + isMetricCardCode, +} from '@/constants/dashboard'; import { MiniViewActiveCard } from './MiniViewActiveCard'; import { MiniViewEmptyCard } from './MiniViewEmptyCard'; @@ -28,6 +31,9 @@ export const MiniView = () => { () => 9 - activeCard.reduce((sum, card) => { + if (!isMetricCardCode(card.code)) { + return sum; + } const cardInfo = DASHBOARD_METRIC_CARDS[card.code]; if (!cardInfo) { return sum; // 카드 정보가 없는 경우 해당 카드는 없는 것으로 간주 @@ -48,14 +54,19 @@ export const MiniView = () => { ))} {/* 활성 카드 */} - {activeCard.map((card) => ( - - ))} + {activeCard.map((card) => { + if (!isMetricCardCode(card.code)) { + return null; + } + return ( + + ); + })}
); From 14059caa88306ec3cc1a28fbf2217b2a80825080 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 18:26:00 +0900 Subject: [PATCH 08/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=20=ED=98=84?= =?UTF-8?q?=ED=99=A9=20=EA=B4=80=EB=A0=A8=20=EC=B9=B4=EB=93=9C=20content?= =?UTF-8?q?=20=EA=B3=B5=ED=86=B5=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/sales/CurrentSalesContent.tsx | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 frontend/src/components/dashboard/sales/CurrentSalesContent.tsx diff --git a/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx b/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx new file mode 100644 index 00000000..ed8a112c --- /dev/null +++ b/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx @@ -0,0 +1,104 @@ +import { type ReactNode, useMemo } from 'react'; + +import { METRIC_TREND, type MetricTrend } from '@/constants/dashboard'; +import { CDN_BASE_URL } from '@/constants/shared'; +import { cn, formatNumber } from '@/utils/shared'; + +interface CurrentSalesContentProps { + className?: string; + children?: ReactNode; +} + +export const CurrentSalesContent = ({ + children, + className, +}: CurrentSalesContentProps) => { + return ( +
+ {children} +
+ ); +}; + +interface CurrentSalesTrendBadgeProps { + trend: MetricTrend; +} + +const CurrentSalesTrendBadge = ({ trend }: CurrentSalesTrendBadgeProps) => { + const iconSrc = useMemo(() => { + switch (trend) { + case METRIC_TREND.UP: + return '/assets/images/graph_up.svg'; + case METRIC_TREND.DOWN: + return '/assets/images/graph_down.svg'; + default: + return null; + } + }, [trend]); + + if (!iconSrc) { + return
; + } + + return ; +}; + +interface CurrentSalesContentAmountProps { + amount: number; + unit: string; + className?: string; +} + +const CurrentSalesContentAmount = ({ + amount, + unit, + className, +}: CurrentSalesContentAmountProps) => { + return ( + + + {formatNumber(amount)} + + {unit} + + ); +}; + +interface CurrentSalesContentComparisonMessageProps { + comparisonMessage: string; + changeRateMessage: string; + metricTrend: MetricTrend; + className?: string; +} + +const CurrentSalesContentComparisonMessage = ({ + comparisonMessage, + changeRateMessage, + metricTrend, + className, +}: CurrentSalesContentComparisonMessageProps) => { + return ( + + {comparisonMessage} + + {changeRateMessage} + + + ); +}; + +CurrentSalesContent.TrendBadge = CurrentSalesTrendBadge; +CurrentSalesContent.Amount = CurrentSalesContentAmount; +CurrentSalesContent.ComparisonMessage = CurrentSalesContentComparisonMessage; From 57d2bfc1830fd975d04c538ae4b31d446db9a61b Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 18:26:18 +0900 Subject: [PATCH 09/96] =?UTF-8?q?feat:=20=EA=B0=81=20=EC=A7=80=ED=91=9C=20?= =?UTF-8?q?=EB=B0=A9=ED=96=A5=EC=84=B1=EC=9D=84=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/dashboard/getMetricTrend.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 frontend/src/utils/dashboard/getMetricTrend.ts diff --git a/frontend/src/utils/dashboard/getMetricTrend.ts b/frontend/src/utils/dashboard/getMetricTrend.ts new file mode 100644 index 00000000..f3752db7 --- /dev/null +++ b/frontend/src/utils/dashboard/getMetricTrend.ts @@ -0,0 +1,11 @@ +import { METRIC_TREND } from '@/constants/dashboard'; + +export const getMetricTrend = (differentAmount: number) => { + if (differentAmount > 0) { + return METRIC_TREND.UP; + } else if (differentAmount < 0) { + return METRIC_TREND.DOWN; + } else { + return METRIC_TREND.SAME; + } +}; From ba4ab76b6b7187b87a45acddae06f25e2f86656d Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 18:26:49 +0900 Subject: [PATCH 10/96] =?UTF-8?q?feat:=20interface=EC=9D=98=20=EB=AA=A8?= =?UTF-8?q?=EB=93=A0=20=EC=86=8D=EC=84=B1=EC=9D=84=20nullable=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=EB=A7=8C=EB=93=9C=EB=8A=94=20=EC=9C=A0=ED=8B=B8=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/shared/index.ts | 1 + frontend/src/utils/shared/nullable.ts | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 frontend/src/utils/shared/nullable.ts diff --git a/frontend/src/utils/shared/index.ts b/frontend/src/utils/shared/index.ts index ae9df570..001d5487 100644 --- a/frontend/src/utils/shared/index.ts +++ b/frontend/src/utils/shared/index.ts @@ -37,3 +37,4 @@ export { } from './doughnut-chart'; export { createPeriodTypeProvider } from './period-select'; +export type { Nullable } from './nullable'; diff --git a/frontend/src/utils/shared/nullable.ts b/frontend/src/utils/shared/nullable.ts new file mode 100644 index 00000000..4b1276e3 --- /dev/null +++ b/frontend/src/utils/shared/nullable.ts @@ -0,0 +1,3 @@ +export type Nullable = { + [P in keyof T]?: T[P]; +}; From 1c708d6e50a5f42fc2dab71f883d91996ea4ced9 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 18:27:02 +0900 Subject: [PATCH 11/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=ED=98=84?= =?UTF-8?q?=ED=99=A9=20=EA=B4=80=EB=A0=A8=20dto=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/types/sales/dto/getAveragePriceDto.ts | 5 +++++ frontend/src/types/sales/dto/getOptionCountDto.ts | 6 ++++++ frontend/src/types/sales/dto/getRealTimeSalesDto.ts | 6 ++++++ frontend/src/types/sales/dto/index.ts | 3 +++ frontend/src/types/sales/index.ts | 5 +++++ 5 files changed, 25 insertions(+) create mode 100644 frontend/src/types/sales/dto/getAveragePriceDto.ts create mode 100644 frontend/src/types/sales/dto/getOptionCountDto.ts create mode 100644 frontend/src/types/sales/dto/getRealTimeSalesDto.ts create mode 100644 frontend/src/types/sales/dto/index.ts diff --git a/frontend/src/types/sales/dto/getAveragePriceDto.ts b/frontend/src/types/sales/dto/getAveragePriceDto.ts new file mode 100644 index 00000000..9bb4c5e6 --- /dev/null +++ b/frontend/src/types/sales/dto/getAveragePriceDto.ts @@ -0,0 +1,5 @@ +export interface GetAveragePriceResponseDto { + averageOrderAmount: number; + differenceAmount: number; + hasPreviousData: boolean; +} diff --git a/frontend/src/types/sales/dto/getOptionCountDto.ts b/frontend/src/types/sales/dto/getOptionCountDto.ts new file mode 100644 index 00000000..a73b6b13 --- /dev/null +++ b/frontend/src/types/sales/dto/getOptionCountDto.ts @@ -0,0 +1,6 @@ +export interface GetOptionCountResponseDto { + orderCount: number; + differenceOrderCount: number; + changeRate: number; + hasPreviousData: boolean; +} diff --git a/frontend/src/types/sales/dto/getRealTimeSalesDto.ts b/frontend/src/types/sales/dto/getRealTimeSalesDto.ts new file mode 100644 index 00000000..411d5a15 --- /dev/null +++ b/frontend/src/types/sales/dto/getRealTimeSalesDto.ts @@ -0,0 +1,6 @@ +export interface GetRealTimeSalesResponseDto { + netAmount: number; + differenceAmount: number; + changeRate: number; + hasPreviousData: boolean; +} diff --git a/frontend/src/types/sales/dto/index.ts b/frontend/src/types/sales/dto/index.ts new file mode 100644 index 00000000..3d18da6d --- /dev/null +++ b/frontend/src/types/sales/dto/index.ts @@ -0,0 +1,3 @@ +export type { GetRealTimeSalesResponseDto } from './getRealTimeSalesDto'; +export type { GetOptionCountResponseDto } from './getOptionCountDto'; +export type { GetAveragePriceResponseDto } from './getAveragePriceDto'; diff --git a/frontend/src/types/sales/index.ts b/frontend/src/types/sales/index.ts index c27a2918..d3a4d1d9 100644 --- a/frontend/src/types/sales/index.ts +++ b/frontend/src/types/sales/index.ts @@ -1 +1,6 @@ export type { SalesSource } from './salesSource'; +export type { + GetRealTimeSalesResponseDto, + GetOptionCountResponseDto, + GetAveragePriceResponseDto, +} from './dto'; From 4565f8fb0b08e4a0a15ae29ca1b5f172bcd2122d Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 18:27:33 +0900 Subject: [PATCH 12/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=ED=98=84?= =?UTF-8?q?=ED=99=A9=20-=20=EC=8B=A4=EB=A7=A4=EC=B6=9C=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=BB=A8=ED=85=90=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/sales/RealSalesCardContent.tsx | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 frontend/src/components/dashboard/sales/RealSalesCardContent.tsx diff --git a/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx b/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx new file mode 100644 index 00000000..0bc1bafc --- /dev/null +++ b/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx @@ -0,0 +1,62 @@ +import { useMemo } from 'react'; + +import { + DASHBOARD_METRIC_CARDS, + type DASHBOARD_METRICS, + type ExtractCardCodes, +} from '@/constants/dashboard'; +import type { GetRealTimeSalesResponseDto } from '@/types/sales'; +import { getMetricTrend } from '@/utils/dashboard/getMetricTrend'; +import { getPeriodComparisonMessage } from '@/utils/sales'; +import type { Nullable } from '@/utils/shared'; + +import { CurrentSalesContent } from './CurrentSalesContent'; + +type RealSalesCardCodes = ExtractCardCodes< + typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.REAL_SALES +>; + +const unit = '원'; +const EXAMPLE_AMOUNT = 256000; +const EXAMPLE_CHANGE_RATE = 5; +const EXAMPLE_HAS_PREVIOUS_DATA = true; + +interface RealSalesCardContentProps extends Nullable { + cardCode: RealSalesCardCodes; + className?: string; +} + +export const RealSalesCardContent = ({ + cardCode, + netAmount = EXAMPLE_AMOUNT, + changeRate = EXAMPLE_CHANGE_RATE, + hasPreviousData = EXAMPLE_HAS_PREVIOUS_DATA, + className, +}: RealSalesCardContentProps) => { + const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; + + const comparisonMessage = useMemo(() => { + return getPeriodComparisonMessage(periodType); + }, [periodType]); + + const changeRateMessage = useMemo(() => { + if (!hasPreviousData) { + return `${changeRate}%`; + } + return `동요일 대비 ${changeRate}%`; + }, [changeRate, hasPreviousData]); + + const metricTrend = getMetricTrend(changeRate); + + return ( + + + + + + ); +}; From de5b24ff9cce16a2c402120cf2baf16ae19a493e Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Fri, 13 Feb 2026 18:27:53 +0900 Subject: [PATCH 13/96] =?UTF-8?q?feat:=20=EC=B9=B4=EB=93=9C=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=91=ED=8C=A8=EB=84=90=EC=97=90=20=EC=8B=A4=EB=A7=A4?= =?UTF-8?q?=EC=B6=9C=20=EC=B9=B4=EB=93=9C=20=EC=9E=84=EC=8B=9C=EB=A1=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard-edit/CardEditViewCard.tsx | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx b/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx index cce0edc4..979d678a 100644 --- a/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx +++ b/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx @@ -3,7 +3,8 @@ import { DASHBOARD_METRIC_CARDS, type MetricCardCode, } from '@/constants/dashboard'; -import { formatNumber } from '@/utils/shared'; + +import { RealSalesCardContent } from '../sales/RealSalesCardContent'; interface CardEditViewCardProps { cardCode: MetricCardCode; @@ -25,7 +26,7 @@ export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { className="min-w-full" sizeX={sizeX} sizeY={sizeY} - innerClassName="items-start" + innerClassName="items-start m-0!" > {label}
@@ -34,18 +35,9 @@ export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { {type}
{sizeX} x {sizeY} -
- - - {formatNumber(295600)} - - - - - {`지난주 월요일\n이 시간보다`} - 5% 늘었어요 - -
+ {(code === 'SLS_01_01' || + code === 'SLS_01_02' || + code === 'SLS_01_03') && } ); From cd1eba4c00da07423f2339b306f6b2e0058dcb74 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 16:36:43 +0900 Subject: [PATCH 14/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=8B=A8=EC=9C=84=20=EC=83=81=EC=88=98=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 --- frontend/src/constants/sales/index.ts | 2 ++ frontend/src/constants/sales/salesUnit.ts | 5 +++++ 2 files changed, 7 insertions(+) create mode 100644 frontend/src/constants/sales/salesUnit.ts diff --git a/frontend/src/constants/sales/index.ts b/frontend/src/constants/sales/index.ts index b5c33cb3..e2266562 100644 --- a/frontend/src/constants/sales/index.ts +++ b/frontend/src/constants/sales/index.ts @@ -1,2 +1,4 @@ export { SALES_SOURCE_COLORS } from './salesSource'; export type { SalesSourceType } from './salesSource'; +export { SALES_UNIT } from './salesUnit'; +export { CURRENT_SALES } from './currentSales'; diff --git a/frontend/src/constants/sales/salesUnit.ts b/frontend/src/constants/sales/salesUnit.ts new file mode 100644 index 00000000..73018362 --- /dev/null +++ b/frontend/src/constants/sales/salesUnit.ts @@ -0,0 +1,5 @@ +export const SALES_UNIT = { + WON: '원', + PERCENT: '%', + PERCENT_POINT: '%p', +} as const; From 3d6f7ff44cf04523a318d9610445fcc943397ed6 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 16:39:19 +0900 Subject: [PATCH 15/96] =?UTF-8?q?feat:=20=EC=8B=A4=EB=A7=A4=EC=B6=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=83=81=EC=88=98=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/sales/index.ts | 2 +- frontend/src/constants/sales/realSales.ts | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 frontend/src/constants/sales/realSales.ts diff --git a/frontend/src/constants/sales/index.ts b/frontend/src/constants/sales/index.ts index e2266562..3e700d11 100644 --- a/frontend/src/constants/sales/index.ts +++ b/frontend/src/constants/sales/index.ts @@ -1,4 +1,4 @@ export { SALES_SOURCE_COLORS } from './salesSource'; export type { SalesSourceType } from './salesSource'; export { SALES_UNIT } from './salesUnit'; -export { CURRENT_SALES } from './currentSales'; +export { REAL_SALES } from './realSales'; diff --git a/frontend/src/constants/sales/realSales.ts b/frontend/src/constants/sales/realSales.ts new file mode 100644 index 00000000..a5254d16 --- /dev/null +++ b/frontend/src/constants/sales/realSales.ts @@ -0,0 +1,8 @@ +export const REAL_SALES = { + EXAMPLE_AMOUNT: 256000, + EXAMPLE_CHANGE_RATE: 5, + EXAMPLE_HAS_PREVIOUS_DATA: true, + METRIC_LABEL: '매출', + MIN_CHANGE_RATE: -3, + MAX_CHANGE_RATE: 3, +} as const; From baf029ce03964e016944c41f0db57d4b1fc6bb79 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 16:39:49 +0900 Subject: [PATCH 16/96] =?UTF-8?q?chore:=20=EC=A7=80=ED=91=9C=20=EA=B2=BD?= =?UTF-8?q?=ED=96=A5=EC=84=B1=20=EA=B3=84=EC=82=B0=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=9C=A0=ED=8B=B8=20=EB=A9=94=EC=84=9C=EB=93=9C=20args=20inter?= =?UTF-8?q?face=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/dashboard/getMetricTrend.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/frontend/src/utils/dashboard/getMetricTrend.ts b/frontend/src/utils/dashboard/getMetricTrend.ts index f3752db7..084c66c5 100644 --- a/frontend/src/utils/dashboard/getMetricTrend.ts +++ b/frontend/src/utils/dashboard/getMetricTrend.ts @@ -1,9 +1,19 @@ import { METRIC_TREND } from '@/constants/dashboard'; -export const getMetricTrend = (differentAmount: number) => { - if (differentAmount > 0) { +interface GetMetricTrendArgs { + comparisonAmount: number; + minValue: number; + maxValue: number; +} + +export const getMetricTrend = ({ + comparisonAmount, + minValue, + maxValue, +}: GetMetricTrendArgs) => { + if (comparisonAmount >= maxValue) { return METRIC_TREND.UP; - } else if (differentAmount < 0) { + } else if (comparisonAmount <= minValue) { return METRIC_TREND.DOWN; } else { return METRIC_TREND.SAME; From ff516c093c23940e93177eb30d15fbccbb34dff5 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 16:40:21 +0900 Subject: [PATCH 17/96] =?UTF-8?q?feat:=20=EC=A7=80=ED=91=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=B9=84=EA=B5=90=20message=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/dashboard/getComparisonMessage.ts | 82 +++++++++++++++++++ frontend/src/utils/dashboard/index.ts | 2 + 2 files changed, 84 insertions(+) create mode 100644 frontend/src/utils/dashboard/getComparisonMessage.ts create mode 100644 frontend/src/utils/dashboard/index.ts diff --git a/frontend/src/utils/dashboard/getComparisonMessage.ts b/frontend/src/utils/dashboard/getComparisonMessage.ts new file mode 100644 index 00000000..41573c92 --- /dev/null +++ b/frontend/src/utils/dashboard/getComparisonMessage.ts @@ -0,0 +1,82 @@ +import { METRIC_TREND, type MetricTrend } from '@/constants/dashboard'; +import { DAY_OF_WEEK_LIST, PERIOD_PRESETS } from '@/constants/shared'; + +import type { ValueOf } from '../shared'; + +interface GetComparisonMessageArgs { + periodType: ValueOf; + hasPreviousData: boolean; + metricTrend: MetricTrend; + metricLabel: string; + comparisonAmount: number; + unit: string; +} + +export const getComparisonMessage = ({ + periodType, + hasPreviousData, + metricTrend, + metricLabel, + comparisonAmount, + unit, +}: GetComparisonMessageArgs): { + commonText: string; + highlightText?: string; +} => { + const weekday = DAY_OF_WEEK_LIST[new Date().getDay()]; + + const PERIOD_TEXT = { + [PERIOD_PRESETS.dayWeekMonth.today]: `지난주 ${weekday}요일`, + [PERIOD_PRESETS.dayWeekMonth.thisWeek]: `지난주 이맘때`, + [PERIOD_PRESETS.dayWeekMonth.thisMonth]: `지난달 이맘때`, + }; + + if (!hasPreviousData) { + return { + commonText: `${PERIOD_TEXT[periodType]}에는 ${metricLabel}이 거의 없었어요.`, + }; + } + + const METRIC_TRED_TEXT = { + [METRIC_TREND.UP]: '늘었어요.', + [METRIC_TREND.DOWN]: '줄었어요.', + [METRIC_TREND.SAME]: '비슷해요.', + }; + + switch (periodType) { + case PERIOD_PRESETS.dayWeekMonth.today: + if (metricTrend === METRIC_TREND.SAME) { + return { + commonText: `${PERIOD_TEXT[periodType]} 이 시간과 ${METRIC_TRED_TEXT[metricTrend]}`, + }; + } + return { + commonText: `${PERIOD_TEXT[periodType]} 이 시간보다 `, + highlightText: `${comparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, + }; + case PERIOD_PRESETS.dayWeekMonth.thisWeek: + if (metricTrend === METRIC_TREND.SAME) { + return { + commonText: `${PERIOD_TEXT[periodType]} 이맘때와 ${METRIC_TRED_TEXT[metricTrend]}`, + }; + } + return { + commonText: `${PERIOD_TEXT[periodType]} 이맘때보다 `, + highlightText: `${comparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, + }; + case PERIOD_PRESETS.dayWeekMonth.thisMonth: + if (metricTrend === METRIC_TREND.SAME) { + return { + commonText: `${PERIOD_TEXT[periodType]} 이맘때와 ${METRIC_TRED_TEXT[metricTrend]}`, + }; + } + return { + commonText: `${PERIOD_TEXT[periodType]} 이맘때보다 `, + highlightText: `${comparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, + }; + default: + return { + commonText: `${PERIOD_TEXT[periodType]}에는 ${metricLabel}이 거의 없었어요.`, + }; + } +}; diff --git a/frontend/src/utils/dashboard/index.ts b/frontend/src/utils/dashboard/index.ts new file mode 100644 index 00000000..66eb1edf --- /dev/null +++ b/frontend/src/utils/dashboard/index.ts @@ -0,0 +1,2 @@ +export { getComparisonMessage } from './getComparisonMessage'; +export { getMetricTrend } from './getMetricTrend'; From cb456d8321162c178d60e205d0327047aa2ea6be Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 16:41:05 +0900 Subject: [PATCH 18/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=ED=98=84?= =?UTF-8?q?=ED=99=A9=EC=97=90=20=EB=B3=80=ED=99=94=EC=9C=A8=EC=9D=B4=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20=EC=A1=B0=EA=B1=B4=EB=B6=80=20=EB=A0=8C=EB=8D=94?= =?UTF-8?q?=EB=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/sales/CurrentSalesContent.tsx | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx b/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx index ed8a112c..b7d4e1f3 100644 --- a/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx +++ b/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx @@ -71,7 +71,7 @@ const CurrentSalesContentAmount = ({ interface CurrentSalesContentComparisonMessageProps { comparisonMessage: string; - changeRateMessage: string; + changeRateMessage?: string; metricTrend: MetricTrend; className?: string; } @@ -83,19 +83,21 @@ const CurrentSalesContentComparisonMessage = ({ className, }: CurrentSalesContentComparisonMessageProps) => { return ( - +

{comparisonMessage} - - {changeRateMessage} - - + {changeRateMessage && ( + + {changeRateMessage} + + )} +

); }; From 4c6d274aa0c861b4ce44169c06f257c15b875d56 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 16:41:29 +0900 Subject: [PATCH 19/96] =?UTF-8?q?feat:=20=EC=8B=A4=EB=A7=A4=EC=B6=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=B9=B4=EB=93=9C=20content=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/sales/RealSalesCardContent.tsx | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx b/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx index 0bc1bafc..52ae4609 100644 --- a/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx +++ b/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx @@ -1,13 +1,11 @@ -import { useMemo } from 'react'; - import { DASHBOARD_METRIC_CARDS, type DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; +import { REAL_SALES, SALES_UNIT } from '@/constants/sales'; import type { GetRealTimeSalesResponseDto } from '@/types/sales'; -import { getMetricTrend } from '@/utils/dashboard/getMetricTrend'; -import { getPeriodComparisonMessage } from '@/utils/sales'; +import { getComparisonMessage, getMetricTrend } from '@/utils/dashboard'; import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; @@ -16,16 +14,20 @@ type RealSalesCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.REAL_SALES >; -const unit = '원'; -const EXAMPLE_AMOUNT = 256000; -const EXAMPLE_CHANGE_RATE = 5; -const EXAMPLE_HAS_PREVIOUS_DATA = true; - interface RealSalesCardContentProps extends Nullable { cardCode: RealSalesCardCodes; className?: string; } +const { + METRIC_LABEL, + MIN_CHANGE_RATE, + MAX_CHANGE_RATE, + EXAMPLE_AMOUNT, + EXAMPLE_CHANGE_RATE, + EXAMPLE_HAS_PREVIOUS_DATA, +} = REAL_SALES; + export const RealSalesCardContent = ({ cardCode, netAmount = EXAMPLE_AMOUNT, @@ -35,26 +37,28 @@ export const RealSalesCardContent = ({ }: RealSalesCardContentProps) => { const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; - const comparisonMessage = useMemo(() => { - return getPeriodComparisonMessage(periodType); - }, [periodType]); - - const changeRateMessage = useMemo(() => { - if (!hasPreviousData) { - return `${changeRate}%`; - } - return `동요일 대비 ${changeRate}%`; - }, [changeRate, hasPreviousData]); + const metricTrend = getMetricTrend({ + comparisonAmount: changeRate, + minValue: MIN_CHANGE_RATE, + maxValue: MAX_CHANGE_RATE, + }); - const metricTrend = getMetricTrend(changeRate); + const { commonText, highlightText } = getComparisonMessage({ + periodType, + hasPreviousData, + metricTrend, + metricLabel: METRIC_LABEL, + comparisonAmount: changeRate, + unit: SALES_UNIT.PERCENT, + }); return ( - + From 77b42844dfe1ed0f634e86405699c9e9a63281a3 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 16:41:46 +0900 Subject: [PATCH 20/96] =?UTF-8?q?feat:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EA=B0=92=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared/default-card-wrapper/DefaultCardWrapper.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/components/shared/default-card-wrapper/DefaultCardWrapper.tsx b/frontend/src/components/shared/default-card-wrapper/DefaultCardWrapper.tsx index 2efffa22..bba02918 100644 --- a/frontend/src/components/shared/default-card-wrapper/DefaultCardWrapper.tsx +++ b/frontend/src/components/shared/default-card-wrapper/DefaultCardWrapper.tsx @@ -12,8 +12,6 @@ interface DefaultCardWrapperProps extends ComponentProps<'article'> { hasChevronRightIcon?: boolean; onClickChevronRightIcon?: () => void; className?: string; - width?: number; - height?: number; } export const DefaultCardWrapper = ({ From b779b49b8993740eb5e26319c96d807f99b84ec6 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:05:06 +0900 Subject: [PATCH 21/96] =?UTF-8?q?feat:=20=EB=B3=80=EB=8F=99=EC=84=B1?= =?UTF-8?q?=EC=9D=B4=20=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20image=20asset=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/shared/images/images.stories.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/components/shared/images/images.stories.tsx b/frontend/src/components/shared/images/images.stories.tsx index d2830521..6fef70d2 100644 --- a/frontend/src/components/shared/images/images.stories.tsx +++ b/frontend/src/components/shared/images/images.stories.tsx @@ -24,6 +24,7 @@ const images = [ 'up.svg', 'down.svg', 'graph_down.svg', + 'graph_same.svg', 'graph_up.svg', 'line_graph.svg', 'bar_graph.svg', From 94a6abf96b3ab523c34c19787ff3e5f1b5a4ef2e Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:05:35 +0900 Subject: [PATCH 22/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=20=EC=A7=80?= =?UTF-8?q?=ED=91=9C=20=EC=A3=BC=EB=AC=B8=20=EA=B4=80=EB=A0=A8=20=EC=83=81?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/sales/index.ts | 1 + frontend/src/constants/sales/orderCount.ts | 8 ++++++++ frontend/src/constants/sales/salesUnit.ts | 1 + 3 files changed, 10 insertions(+) create mode 100644 frontend/src/constants/sales/orderCount.ts diff --git a/frontend/src/constants/sales/index.ts b/frontend/src/constants/sales/index.ts index 3e700d11..7dd2cbe8 100644 --- a/frontend/src/constants/sales/index.ts +++ b/frontend/src/constants/sales/index.ts @@ -2,3 +2,4 @@ export { SALES_SOURCE_COLORS } from './salesSource'; export type { SalesSourceType } from './salesSource'; export { SALES_UNIT } from './salesUnit'; export { REAL_SALES } from './realSales'; +export { ORDER_COUNT } from './orderCount'; diff --git a/frontend/src/constants/sales/orderCount.ts b/frontend/src/constants/sales/orderCount.ts new file mode 100644 index 00000000..7fe6f133 --- /dev/null +++ b/frontend/src/constants/sales/orderCount.ts @@ -0,0 +1,8 @@ +export const ORDER_COUNT = { + EXAMPLE_AMOUNT: 42, + EXAMPLE_CHANGE_RATE: 5, + EXAMPLE_HAS_PREVIOUS_DATA: true, + METRIC_LABEL: '주문', + MIN_CHANGE_RATE: -3, + MAX_CHANGE_RATE: 3, +} as const; diff --git a/frontend/src/constants/sales/salesUnit.ts b/frontend/src/constants/sales/salesUnit.ts index 73018362..66f54d7c 100644 --- a/frontend/src/constants/sales/salesUnit.ts +++ b/frontend/src/constants/sales/salesUnit.ts @@ -2,4 +2,5 @@ export const SALES_UNIT = { WON: '원', PERCENT: '%', PERCENT_POINT: '%p', + ORDER: '건', } as const; From e8ed673851d3ebf7df3c5fe245b6c9e5a8a79e86 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:06:09 +0900 Subject: [PATCH 23/96] =?UTF-8?q?chore:=20=EB=A7=A4=EC=B6=9C=20=EC=A7=80?= =?UTF-8?q?=ED=91=9C=20=EC=A3=BC=EB=AC=B8=EA=B1=B4=EC=88=98=20dto=EB=AA=85?= =?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 --- .../sales/dto/{getOptionCountDto.ts => getOrderCountDto.ts} | 2 +- frontend/src/types/sales/dto/index.ts | 2 +- frontend/src/types/sales/index.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename frontend/src/types/sales/dto/{getOptionCountDto.ts => getOrderCountDto.ts} (70%) diff --git a/frontend/src/types/sales/dto/getOptionCountDto.ts b/frontend/src/types/sales/dto/getOrderCountDto.ts similarity index 70% rename from frontend/src/types/sales/dto/getOptionCountDto.ts rename to frontend/src/types/sales/dto/getOrderCountDto.ts index a73b6b13..0cbb5841 100644 --- a/frontend/src/types/sales/dto/getOptionCountDto.ts +++ b/frontend/src/types/sales/dto/getOrderCountDto.ts @@ -1,4 +1,4 @@ -export interface GetOptionCountResponseDto { +export interface GetOrderCountResponseDto { orderCount: number; differenceOrderCount: number; changeRate: number; diff --git a/frontend/src/types/sales/dto/index.ts b/frontend/src/types/sales/dto/index.ts index 3d18da6d..1298736a 100644 --- a/frontend/src/types/sales/dto/index.ts +++ b/frontend/src/types/sales/dto/index.ts @@ -1,3 +1,3 @@ export type { GetRealTimeSalesResponseDto } from './getRealTimeSalesDto'; -export type { GetOptionCountResponseDto } from './getOptionCountDto'; +export type { GetOrderCountResponseDto } from './getOrderCountDto'; export type { GetAveragePriceResponseDto } from './getAveragePriceDto'; diff --git a/frontend/src/types/sales/index.ts b/frontend/src/types/sales/index.ts index d3a4d1d9..a305270a 100644 --- a/frontend/src/types/sales/index.ts +++ b/frontend/src/types/sales/index.ts @@ -1,6 +1,6 @@ export type { SalesSource } from './salesSource'; export type { GetRealTimeSalesResponseDto, - GetOptionCountResponseDto, + GetOrderCountResponseDto, GetAveragePriceResponseDto, } from './dto'; From aa06e107738ecbeed296c5b6408a621b6e979905 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:06:49 +0900 Subject: [PATCH 24/96] =?UTF-8?q?feat:=20=EC=A7=80=ED=91=9C=EC=97=90=20?= =?UTF-8?q?=EB=B3=80=EB=8F=99=EC=84=B1=EC=9D=B4=20=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0,=20=EB=B3=80=EB=8F=99=EC=84=B1=20=EC=97=86?= =?UTF-8?q?=EC=9D=8C=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/dashboard/sales/CurrentSalesContent.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx b/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx index b7d4e1f3..2c57f8f5 100644 --- a/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx +++ b/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx @@ -14,14 +14,14 @@ export const CurrentSalesContent = ({ className, }: CurrentSalesContentProps) => { return ( -
{children} -
+ ); }; @@ -36,6 +36,8 @@ const CurrentSalesTrendBadge = ({ trend }: CurrentSalesTrendBadgeProps) => { return '/assets/images/graph_up.svg'; case METRIC_TREND.DOWN: return '/assets/images/graph_down.svg'; + case METRIC_TREND.SAME: + return '/assets/images/graph_same.svg'; default: return null; } From 94c165fe934d7a72a55ef312a9031b6e81c08024 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:07:24 +0900 Subject: [PATCH 25/96] =?UTF-8?q?feat:=20=EC=A3=BC=EB=AC=B8=20=EA=B1=B4?= =?UTF-8?q?=EC=88=98=20=EA=B4=80=EB=A0=A8=20=EC=B9=B4=EB=93=9C=20content?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/sales/OrderCountCardContent.tsx | 65 +++++++++++++++++++ .../src/components/dashboard/sales/index.ts | 2 + 2 files changed, 67 insertions(+) create mode 100644 frontend/src/components/dashboard/sales/OrderCountCardContent.tsx create mode 100644 frontend/src/components/dashboard/sales/index.ts diff --git a/frontend/src/components/dashboard/sales/OrderCountCardContent.tsx b/frontend/src/components/dashboard/sales/OrderCountCardContent.tsx new file mode 100644 index 00000000..6339b2e3 --- /dev/null +++ b/frontend/src/components/dashboard/sales/OrderCountCardContent.tsx @@ -0,0 +1,65 @@ +import { + DASHBOARD_METRIC_CARDS, + type DASHBOARD_METRICS, + type ExtractCardCodes, +} from '@/constants/dashboard'; +import { ORDER_COUNT, SALES_UNIT } from '@/constants/sales'; +import type { GetOrderCountResponseDto } from '@/types/sales'; +import { getComparisonMessage, getMetricTrend } from '@/utils/dashboard'; +import type { Nullable } from '@/utils/shared'; + +import { CurrentSalesContent } from './CurrentSalesContent'; + +const { + METRIC_LABEL, + MIN_CHANGE_RATE, + MAX_CHANGE_RATE, + EXAMPLE_AMOUNT, + EXAMPLE_CHANGE_RATE, + EXAMPLE_HAS_PREVIOUS_DATA, +} = ORDER_COUNT; + +type OrderCountCardCodes = ExtractCardCodes< + typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.ORDER_COUNT +>; + +interface OrderCountCardContentProps extends Nullable { + cardCode: OrderCountCardCodes; + className?: string; +} + +export const OrderCountCardContent = ({ + cardCode, + orderCount = EXAMPLE_AMOUNT, + changeRate = EXAMPLE_CHANGE_RATE, + hasPreviousData = EXAMPLE_HAS_PREVIOUS_DATA, + className, +}: OrderCountCardContentProps) => { + const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; + + const metricTrend = getMetricTrend({ + comparisonAmount: changeRate, + minValue: MIN_CHANGE_RATE, + maxValue: MAX_CHANGE_RATE, + }); + + const { commonText, highlightText } = getComparisonMessage({ + periodType, + hasPreviousData, + metricTrend, + metricLabel: METRIC_LABEL, + comparisonAmount: changeRate, + unit: SALES_UNIT.PERCENT, + }); + return ( + + + + + + ); +}; diff --git a/frontend/src/components/dashboard/sales/index.ts b/frontend/src/components/dashboard/sales/index.ts new file mode 100644 index 00000000..8a3f3810 --- /dev/null +++ b/frontend/src/components/dashboard/sales/index.ts @@ -0,0 +1,2 @@ +export { RealSalesCardContent } from './RealSalesCardContent'; +export { OrderCountCardContent } from './OrderCountCardContent'; From 0e196deed5ab23cdb543fd365672deb39d5dc566 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:07:57 +0900 Subject: [PATCH 26/96] =?UTF-8?q?chore:=20=EC=83=81=EC=88=98=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/sales/RealSalesCardContent.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx b/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx index 52ae4609..4c28679e 100644 --- a/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx +++ b/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx @@ -10,15 +10,6 @@ import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; -type RealSalesCardCodes = ExtractCardCodes< - typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.REAL_SALES ->; - -interface RealSalesCardContentProps extends Nullable { - cardCode: RealSalesCardCodes; - className?: string; -} - const { METRIC_LABEL, MIN_CHANGE_RATE, @@ -28,6 +19,15 @@ const { EXAMPLE_HAS_PREVIOUS_DATA, } = REAL_SALES; +type RealSalesCardCodes = ExtractCardCodes< + typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.REAL_SALES +>; + +interface RealSalesCardContentProps extends Nullable { + cardCode: RealSalesCardCodes; + className?: string; +} + export const RealSalesCardContent = ({ cardCode, netAmount = EXAMPLE_AMOUNT, From 15f792ce717ff1923a9f7e182b23668b54feebdc Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:08:22 +0900 Subject: [PATCH 27/96] =?UTF-8?q?fix:=20=EC=9D=B4=EB=A7=98=EB=95=8C?= =?UTF-8?q?=EC=AF=A4=EC=9D=B4=202=EB=B2=88=20=EB=82=98=EC=98=A4=EB=8A=94?= =?UTF-8?q?=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/dashboard/getComparisonMessage.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/utils/dashboard/getComparisonMessage.ts b/frontend/src/utils/dashboard/getComparisonMessage.ts index 41573c92..d484a811 100644 --- a/frontend/src/utils/dashboard/getComparisonMessage.ts +++ b/frontend/src/utils/dashboard/getComparisonMessage.ts @@ -57,21 +57,21 @@ export const getComparisonMessage = ({ case PERIOD_PRESETS.dayWeekMonth.thisWeek: if (metricTrend === METRIC_TREND.SAME) { return { - commonText: `${PERIOD_TEXT[periodType]} 이맘때와 ${METRIC_TRED_TEXT[metricTrend]}`, + commonText: `${PERIOD_TEXT[periodType]}와 ${METRIC_TRED_TEXT[metricTrend]}`, }; } return { - commonText: `${PERIOD_TEXT[periodType]} 이맘때보다 `, + commonText: `${PERIOD_TEXT[periodType]}보다 `, highlightText: `${comparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, }; case PERIOD_PRESETS.dayWeekMonth.thisMonth: if (metricTrend === METRIC_TREND.SAME) { return { - commonText: `${PERIOD_TEXT[periodType]} 이맘때와 ${METRIC_TRED_TEXT[metricTrend]}`, + commonText: `${PERIOD_TEXT[periodType]}와 ${METRIC_TRED_TEXT[metricTrend]}`, }; } return { - commonText: `${PERIOD_TEXT[periodType]} 이맘때보다 `, + commonText: `${PERIOD_TEXT[periodType]}보다 `, highlightText: `${comparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, }; default: From ff4bf99f0ad51e8d7713ddd1cc163085f7df6d1f Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:18:04 +0900 Subject: [PATCH 28/96] =?UTF-8?q?chore:=20ooCardContent=EC=97=90=EC=84=9C?= =?UTF-8?q?=20ooContent=EB=A1=9C=20=EB=84=A4=EC=9D=B4=EB=B0=8D=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 --- .../{OrderCountCardContent.tsx => OrderCountContent.tsx} | 6 +++--- .../{RealSalesCardContent.tsx => RealSalesContent.tsx} | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) rename frontend/src/components/dashboard/sales/{OrderCountCardContent.tsx => OrderCountContent.tsx} (91%) rename frontend/src/components/dashboard/sales/{RealSalesCardContent.tsx => RealSalesContent.tsx} (91%) diff --git a/frontend/src/components/dashboard/sales/OrderCountCardContent.tsx b/frontend/src/components/dashboard/sales/OrderCountContent.tsx similarity index 91% rename from frontend/src/components/dashboard/sales/OrderCountCardContent.tsx rename to frontend/src/components/dashboard/sales/OrderCountContent.tsx index 6339b2e3..40df6716 100644 --- a/frontend/src/components/dashboard/sales/OrderCountCardContent.tsx +++ b/frontend/src/components/dashboard/sales/OrderCountContent.tsx @@ -23,18 +23,18 @@ type OrderCountCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.ORDER_COUNT >; -interface OrderCountCardContentProps extends Nullable { +interface OrderCountContentProps extends Nullable { cardCode: OrderCountCardCodes; className?: string; } -export const OrderCountCardContent = ({ +export const OrderCountContent = ({ cardCode, orderCount = EXAMPLE_AMOUNT, changeRate = EXAMPLE_CHANGE_RATE, hasPreviousData = EXAMPLE_HAS_PREVIOUS_DATA, className, -}: OrderCountCardContentProps) => { +}: OrderCountContentProps) => { const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; const metricTrend = getMetricTrend({ diff --git a/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx b/frontend/src/components/dashboard/sales/RealSalesContent.tsx similarity index 91% rename from frontend/src/components/dashboard/sales/RealSalesCardContent.tsx rename to frontend/src/components/dashboard/sales/RealSalesContent.tsx index 4c28679e..bd2391f9 100644 --- a/frontend/src/components/dashboard/sales/RealSalesCardContent.tsx +++ b/frontend/src/components/dashboard/sales/RealSalesContent.tsx @@ -23,18 +23,18 @@ type RealSalesCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.REAL_SALES >; -interface RealSalesCardContentProps extends Nullable { +interface RealSalesContentProps extends Nullable { cardCode: RealSalesCardCodes; className?: string; } -export const RealSalesCardContent = ({ +export const RealSalesContent = ({ cardCode, netAmount = EXAMPLE_AMOUNT, changeRate = EXAMPLE_CHANGE_RATE, hasPreviousData = EXAMPLE_HAS_PREVIOUS_DATA, className, -}: RealSalesCardContentProps) => { +}: RealSalesContentProps) => { const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; const metricTrend = getMetricTrend({ From 9eaddc03889bd0923d5669132b95477692f1b8f8 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:25:02 +0900 Subject: [PATCH 29/96] =?UTF-8?q?feat:=20=EC=A3=BC=EB=AC=B8=EA=B1=B4?= =?UTF-8?q?=EC=88=98=20=EC=A7=80=ED=91=9C=20=EC=B9=B4=EB=93=9C=20content?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/sales/AveragePriceContent.tsx | 66 +++++++++++++++++++ .../src/components/dashboard/sales/index.ts | 5 +- 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 frontend/src/components/dashboard/sales/AveragePriceContent.tsx diff --git a/frontend/src/components/dashboard/sales/AveragePriceContent.tsx b/frontend/src/components/dashboard/sales/AveragePriceContent.tsx new file mode 100644 index 00000000..da69801a --- /dev/null +++ b/frontend/src/components/dashboard/sales/AveragePriceContent.tsx @@ -0,0 +1,66 @@ +import { + DASHBOARD_METRIC_CARDS, + type DASHBOARD_METRICS, + type ExtractCardCodes, +} from '@/constants/dashboard'; +import { AVERAGE_PRICE, SALES_UNIT } from '@/constants/sales'; +import type { GetAveragePriceResponseDto } from '@/types/sales'; +import { getComparisonMessage, getMetricTrend } from '@/utils/dashboard'; +import type { Nullable } from '@/utils/shared'; + +import { CurrentSalesContent } from './CurrentSalesContent'; + +const { + EXAMPLE_AMOUNT, + EXAMPLE_COMPARISON_AMOUNT, + EXAMPLE_HAS_PREVIOUS_DATA, + MIN_CHANGE_RATE, + MAX_CHANGE_RATE, + METRIC_LABEL, +} = AVERAGE_PRICE; + +type AveragePriceCardCodes = ExtractCardCodes< + typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.AVERAGE_PRICE +>; + +interface AveragePriceContentProps extends Nullable { + cardCode: AveragePriceCardCodes; + className?: string; +} + +export const AveragePriceContent = ({ + cardCode, + averageOrderAmount = EXAMPLE_AMOUNT, + differenceAmount = EXAMPLE_COMPARISON_AMOUNT, + hasPreviousData = EXAMPLE_HAS_PREVIOUS_DATA, + className, +}: AveragePriceContentProps) => { + const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; + const metricTrend = getMetricTrend({ + comparisonAmount: differenceAmount, + minValue: MIN_CHANGE_RATE, + maxValue: MAX_CHANGE_RATE, + }); + const { commonText, highlightText } = getComparisonMessage({ + periodType, + hasPreviousData, + metricTrend, + metricLabel: METRIC_LABEL, + comparisonAmount: differenceAmount, + unit: SALES_UNIT.WON, + }); + return ( + + + + + + ); +}; diff --git a/frontend/src/components/dashboard/sales/index.ts b/frontend/src/components/dashboard/sales/index.ts index 8a3f3810..b684b562 100644 --- a/frontend/src/components/dashboard/sales/index.ts +++ b/frontend/src/components/dashboard/sales/index.ts @@ -1,2 +1,3 @@ -export { RealSalesCardContent } from './RealSalesCardContent'; -export { OrderCountCardContent } from './OrderCountCardContent'; +export { RealSalesContent } from './RealSalesContent'; +export { OrderCountContent } from './OrderCountContent'; +export { AveragePriceContent } from './AveragePriceContent'; From 532c129ac3d51ad9a22feb9e3586befa46829d09 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:25:27 +0900 Subject: [PATCH 30/96] =?UTF-8?q?style:=20=EC=97=AC=EB=B0=B1=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/dashboard/sales/CurrentSalesContent.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx b/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx index 2c57f8f5..ccc50fdc 100644 --- a/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx +++ b/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx @@ -90,7 +90,6 @@ const CurrentSalesContentComparisonMessage = ({ {changeRateMessage && ( Date: Sat, 14 Feb 2026 17:25:46 +0900 Subject: [PATCH 31/96] =?UTF-8?q?chore:=20=EC=88=AB=EC=9E=90=EC=97=90=20?= =?UTF-8?q?=ED=8F=AC=EB=A9=94=ED=8C=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/dashboard/getComparisonMessage.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/utils/dashboard/getComparisonMessage.ts b/frontend/src/utils/dashboard/getComparisonMessage.ts index d484a811..61e9eea2 100644 --- a/frontend/src/utils/dashboard/getComparisonMessage.ts +++ b/frontend/src/utils/dashboard/getComparisonMessage.ts @@ -1,7 +1,7 @@ import { METRIC_TREND, type MetricTrend } from '@/constants/dashboard'; import { DAY_OF_WEEK_LIST, PERIOD_PRESETS } from '@/constants/shared'; -import type { ValueOf } from '../shared'; +import { formatNumber, type ValueOf } from '../shared'; interface GetComparisonMessageArgs { periodType: ValueOf; @@ -43,6 +43,8 @@ export const getComparisonMessage = ({ [METRIC_TREND.SAME]: '비슷해요.', }; + const formattedComparisonAmount = formatNumber(comparisonAmount); + switch (periodType) { case PERIOD_PRESETS.dayWeekMonth.today: if (metricTrend === METRIC_TREND.SAME) { @@ -52,7 +54,7 @@ export const getComparisonMessage = ({ } return { commonText: `${PERIOD_TEXT[periodType]} 이 시간보다 `, - highlightText: `${comparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, + highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, }; case PERIOD_PRESETS.dayWeekMonth.thisWeek: if (metricTrend === METRIC_TREND.SAME) { @@ -62,7 +64,7 @@ export const getComparisonMessage = ({ } return { commonText: `${PERIOD_TEXT[periodType]}보다 `, - highlightText: `${comparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, + highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, }; case PERIOD_PRESETS.dayWeekMonth.thisMonth: if (metricTrend === METRIC_TREND.SAME) { @@ -72,7 +74,7 @@ export const getComparisonMessage = ({ } return { commonText: `${PERIOD_TEXT[periodType]}보다 `, - highlightText: `${comparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, + highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, }; default: return { From 5ee98bb13235ceb240633b51d82abe85efcdad01 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:26:02 +0900 Subject: [PATCH 32/96] =?UTF-8?q?feat:=20=EC=B5=9C=EB=8C=80=20=EC=B5=9C?= =?UTF-8?q?=EC=86=8C=EA=B0=80=200=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/dashboard/getMetricTrend.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frontend/src/utils/dashboard/getMetricTrend.ts b/frontend/src/utils/dashboard/getMetricTrend.ts index 084c66c5..1cd9f429 100644 --- a/frontend/src/utils/dashboard/getMetricTrend.ts +++ b/frontend/src/utils/dashboard/getMetricTrend.ts @@ -11,6 +11,16 @@ export const getMetricTrend = ({ minValue, maxValue, }: GetMetricTrendArgs) => { + if (!maxValue && !minValue) { + if (comparisonAmount > 0) { + return METRIC_TREND.UP; + } else if (comparisonAmount < 0) { + return METRIC_TREND.DOWN; + } else { + return METRIC_TREND.SAME; + } + } + if (comparisonAmount >= maxValue) { return METRIC_TREND.UP; } else if (comparisonAmount <= minValue) { From f280f52cb28e76ec07570726c27a09423afd8f89 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:26:21 +0900 Subject: [PATCH 33/96] =?UTF-8?q?feat:=20=EC=A3=BC=EB=AC=B8=20=ED=8F=89?= =?UTF-8?q?=EA=B7=A0=EA=B0=80=20=EA=B4=80=EB=A0=A8=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/sales/averagePrice.ts | 8 ++++++++ frontend/src/constants/sales/index.ts | 1 + 2 files changed, 9 insertions(+) create mode 100644 frontend/src/constants/sales/averagePrice.ts diff --git a/frontend/src/constants/sales/averagePrice.ts b/frontend/src/constants/sales/averagePrice.ts new file mode 100644 index 00000000..a3a5eabe --- /dev/null +++ b/frontend/src/constants/sales/averagePrice.ts @@ -0,0 +1,8 @@ +export const AVERAGE_PRICE = { + EXAMPLE_AMOUNT: 123000, + EXAMPLE_COMPARISON_AMOUNT: 16000, + EXAMPLE_HAS_PREVIOUS_DATA: true, + METRIC_LABEL: '주문', + MIN_CHANGE_RATE: 0, + MAX_CHANGE_RATE: 0, +} as const; diff --git a/frontend/src/constants/sales/index.ts b/frontend/src/constants/sales/index.ts index 7dd2cbe8..eb3cc0c3 100644 --- a/frontend/src/constants/sales/index.ts +++ b/frontend/src/constants/sales/index.ts @@ -3,3 +3,4 @@ export type { SalesSourceType } from './salesSource'; export { SALES_UNIT } from './salesUnit'; export { REAL_SALES } from './realSales'; export { ORDER_COUNT } from './orderCount'; +export { AVERAGE_PRICE } from './averagePrice'; From 0ff9087abe7b43d884e55ab8d5deda9a14941d4c Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sat, 14 Feb 2026 17:50:41 +0900 Subject: [PATCH 34/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=20=EC=9C=A0?= =?UTF-8?q?=EC=9E=85=20=EA=B5=AC=EC=A1=B0=20=EA=B4=80=EB=A0=A8=20DTO=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/dto/getIncomStructureByOrderMethodDto.ts | 14 ++++++++++++++ .../dto/getIncomStructureByPaymentMethodDto.ts | 14 ++++++++++++++ .../sales/dto/getIncomStructureBySalesTypeDto.ts | 14 ++++++++++++++ frontend/src/types/sales/dto/index.ts | 3 +++ .../src/types/sales/salesIncomeStructureInsight.ts | 7 +++++++ 5 files changed, 52 insertions(+) create mode 100644 frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts create mode 100644 frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts create mode 100644 frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts create mode 100644 frontend/src/types/sales/salesIncomeStructureInsight.ts diff --git a/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts b/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts new file mode 100644 index 00000000..37a42db0 --- /dev/null +++ b/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts @@ -0,0 +1,14 @@ +import type { SalesIncomeStructureInsight } from '../salesIncomeStructureInsight'; + +interface OrderMethodItem { + orderChannel: string; + salesAmount: number; + orderCount: number; + share: number; + deltaShare: number; +} + +export interface GetIncomStructureByOrderMethodResponseDto { + insight: SalesIncomeStructureInsight; + items: OrderMethodItem[]; +} diff --git a/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts b/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts new file mode 100644 index 00000000..50863103 --- /dev/null +++ b/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts @@ -0,0 +1,14 @@ +import type { SalesIncomeStructureInsight } from '../salesIncomeStructureInsight'; + +interface PaymentMethodItem { + payMethod: string; + salesAmount: number; + orderCount: number; + share: number; + deltaShare: number; +} + +export interface GetIncomStructureByPaymentMethodResponseDto { + insight: SalesIncomeStructureInsight; + items: PaymentMethodItem[]; +} diff --git a/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts b/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts new file mode 100644 index 00000000..f4fd218e --- /dev/null +++ b/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts @@ -0,0 +1,14 @@ +import type { SalesIncomeStructureInsight } from '../salesIncomeStructureInsight'; + +interface SalesTypeItem { + salesType: string; + salesAmount: number; + orderCount: number; + share: number; + deltaShare: number; +} + +export interface GetIncomStructureBySalesTypeResponseDto { + insight: SalesIncomeStructureInsight; + items: SalesTypeItem[]; +} diff --git a/frontend/src/types/sales/dto/index.ts b/frontend/src/types/sales/dto/index.ts index 1298736a..a46380ae 100644 --- a/frontend/src/types/sales/dto/index.ts +++ b/frontend/src/types/sales/dto/index.ts @@ -1,3 +1,6 @@ export type { GetRealTimeSalesResponseDto } from './getRealTimeSalesDto'; export type { GetOrderCountResponseDto } from './getOrderCountDto'; export type { GetAveragePriceResponseDto } from './getAveragePriceDto'; +export type { GetIncomStructureBySalesTypeResponseDto } from './getIncomStructureBySalesTypeDto'; +export type { GetIncomStructureByOrderMethodResponseDto } from './getIncomStructureByOrderMethodDto'; +export type { GetIncomStructureByPaymentMethodResponseDto } from './getIncomStructureByPaymentMethodDto'; diff --git a/frontend/src/types/sales/salesIncomeStructureInsight.ts b/frontend/src/types/sales/salesIncomeStructureInsight.ts new file mode 100644 index 00000000..f8abc6c2 --- /dev/null +++ b/frontend/src/types/sales/salesIncomeStructureInsight.ts @@ -0,0 +1,7 @@ +export interface SalesIncomeStructureInsight { + topType: string; + topShare: number; + deltaShare: number; + showDeltaText: boolean; + showFocusText: boolean; +} From 9e014a41e3c840097802daf8053c4dfdfb779c74 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 00:24:33 +0900 Subject: [PATCH 35/96] =?UTF-8?q?refactor:=20=EB=A7=A4=EC=B6=9C=20?= =?UTF-8?q?=ED=98=84=ED=99=A9=20=EB=B9=84=EA=B5=90=20=ED=85=8D=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B4=80=EB=A0=A8=20=EC=9C=A0=ED=8B=B8=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=AA=85=ED=99=95?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/dashboard/sales/AveragePriceContent.tsx | 7 +++++-- .../src/components/dashboard/sales/OrderCountContent.tsx | 7 +++++-- .../src/components/dashboard/sales/RealSalesContent.tsx | 7 +++++-- ...risonMessage.ts => getSalesCurrentComparisonMessage.ts} | 6 +++--- 4 files changed, 18 insertions(+), 9 deletions(-) rename frontend/src/utils/dashboard/{getComparisonMessage.ts => getSalesCurrentComparisonMessage.ts} (94%) diff --git a/frontend/src/components/dashboard/sales/AveragePriceContent.tsx b/frontend/src/components/dashboard/sales/AveragePriceContent.tsx index da69801a..3b33cbe1 100644 --- a/frontend/src/components/dashboard/sales/AveragePriceContent.tsx +++ b/frontend/src/components/dashboard/sales/AveragePriceContent.tsx @@ -5,7 +5,10 @@ import { } from '@/constants/dashboard'; import { AVERAGE_PRICE, SALES_UNIT } from '@/constants/sales'; import type { GetAveragePriceResponseDto } from '@/types/sales'; -import { getComparisonMessage, getMetricTrend } from '@/utils/dashboard'; +import { + getMetricTrend, + getSalesCurrentComparisonMessage, +} from '@/utils/dashboard'; import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; @@ -41,7 +44,7 @@ export const AveragePriceContent = ({ minValue: MIN_CHANGE_RATE, maxValue: MAX_CHANGE_RATE, }); - const { commonText, highlightText } = getComparisonMessage({ + const { commonText, highlightText } = getSalesCurrentComparisonMessage({ periodType, hasPreviousData, metricTrend, diff --git a/frontend/src/components/dashboard/sales/OrderCountContent.tsx b/frontend/src/components/dashboard/sales/OrderCountContent.tsx index 40df6716..afd71dc1 100644 --- a/frontend/src/components/dashboard/sales/OrderCountContent.tsx +++ b/frontend/src/components/dashboard/sales/OrderCountContent.tsx @@ -5,7 +5,10 @@ import { } from '@/constants/dashboard'; import { ORDER_COUNT, SALES_UNIT } from '@/constants/sales'; import type { GetOrderCountResponseDto } from '@/types/sales'; -import { getComparisonMessage, getMetricTrend } from '@/utils/dashboard'; +import { + getMetricTrend, + getSalesCurrentComparisonMessage, +} from '@/utils/dashboard'; import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; @@ -43,7 +46,7 @@ export const OrderCountContent = ({ maxValue: MAX_CHANGE_RATE, }); - const { commonText, highlightText } = getComparisonMessage({ + const { commonText, highlightText } = getSalesCurrentComparisonMessage({ periodType, hasPreviousData, metricTrend, diff --git a/frontend/src/components/dashboard/sales/RealSalesContent.tsx b/frontend/src/components/dashboard/sales/RealSalesContent.tsx index bd2391f9..66814edb 100644 --- a/frontend/src/components/dashboard/sales/RealSalesContent.tsx +++ b/frontend/src/components/dashboard/sales/RealSalesContent.tsx @@ -5,7 +5,10 @@ import { } from '@/constants/dashboard'; import { REAL_SALES, SALES_UNIT } from '@/constants/sales'; import type { GetRealTimeSalesResponseDto } from '@/types/sales'; -import { getComparisonMessage, getMetricTrend } from '@/utils/dashboard'; +import { + getMetricTrend, + getSalesCurrentComparisonMessage, +} from '@/utils/dashboard'; import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; @@ -43,7 +46,7 @@ export const RealSalesContent = ({ maxValue: MAX_CHANGE_RATE, }); - const { commonText, highlightText } = getComparisonMessage({ + const { commonText, highlightText } = getSalesCurrentComparisonMessage({ periodType, hasPreviousData, metricTrend, diff --git a/frontend/src/utils/dashboard/getComparisonMessage.ts b/frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts similarity index 94% rename from frontend/src/utils/dashboard/getComparisonMessage.ts rename to frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts index 61e9eea2..938c0396 100644 --- a/frontend/src/utils/dashboard/getComparisonMessage.ts +++ b/frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts @@ -3,7 +3,7 @@ import { DAY_OF_WEEK_LIST, PERIOD_PRESETS } from '@/constants/shared'; import { formatNumber, type ValueOf } from '../shared'; -interface GetComparisonMessageArgs { +interface GetSalesCurrentComparisonMessageArgs { periodType: ValueOf; hasPreviousData: boolean; metricTrend: MetricTrend; @@ -12,14 +12,14 @@ interface GetComparisonMessageArgs { unit: string; } -export const getComparisonMessage = ({ +export const getSalesCurrentComparisonMessage = ({ periodType, hasPreviousData, metricTrend, metricLabel, comparisonAmount, unit, -}: GetComparisonMessageArgs): { +}: GetSalesCurrentComparisonMessageArgs): { commonText: string; highlightText?: string; } => { From 5fe6ea2ed9f22be65832c74704fe2863fe0b3954 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:08:40 +0900 Subject: [PATCH 36/96] =?UTF-8?q?refactor:=20dashboard=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=EC=97=90=EC=84=9C=20sales=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=EC=9C=BC=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 --- .../dashboard-current-sales}/AveragePriceContent.tsx | 0 .../dashboard-current-sales}/CurrentSalesContent.tsx | 0 .../sales => sales/dashboard-current-sales}/OrderCountContent.tsx | 0 .../sales => sales/dashboard-current-sales}/RealSalesContent.tsx | 0 .../{dashboard/sales => sales/dashboard-current-sales}/index.ts | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename frontend/src/components/{dashboard/sales => sales/dashboard-current-sales}/AveragePriceContent.tsx (100%) rename frontend/src/components/{dashboard/sales => sales/dashboard-current-sales}/CurrentSalesContent.tsx (100%) rename frontend/src/components/{dashboard/sales => sales/dashboard-current-sales}/OrderCountContent.tsx (100%) rename frontend/src/components/{dashboard/sales => sales/dashboard-current-sales}/RealSalesContent.tsx (100%) rename frontend/src/components/{dashboard/sales => sales/dashboard-current-sales}/index.ts (100%) diff --git a/frontend/src/components/dashboard/sales/AveragePriceContent.tsx b/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx similarity index 100% rename from frontend/src/components/dashboard/sales/AveragePriceContent.tsx rename to frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx diff --git a/frontend/src/components/dashboard/sales/CurrentSalesContent.tsx b/frontend/src/components/sales/dashboard-current-sales/CurrentSalesContent.tsx similarity index 100% rename from frontend/src/components/dashboard/sales/CurrentSalesContent.tsx rename to frontend/src/components/sales/dashboard-current-sales/CurrentSalesContent.tsx diff --git a/frontend/src/components/dashboard/sales/OrderCountContent.tsx b/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx similarity index 100% rename from frontend/src/components/dashboard/sales/OrderCountContent.tsx rename to frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx diff --git a/frontend/src/components/dashboard/sales/RealSalesContent.tsx b/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx similarity index 100% rename from frontend/src/components/dashboard/sales/RealSalesContent.tsx rename to frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx diff --git a/frontend/src/components/dashboard/sales/index.ts b/frontend/src/components/sales/dashboard-current-sales/index.ts similarity index 100% rename from frontend/src/components/dashboard/sales/index.ts rename to frontend/src/components/sales/dashboard-current-sales/index.ts From 44e91f176e89e6c175e7b3e6438a2f8d1edaf1e1 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:10:01 +0900 Subject: [PATCH 37/96] =?UTF-8?q?refactor:=20switch=20case=20fall=20throug?= =?UTF-8?q?h=20=EB=B0=8F=20assertNever=EB=A5=BC=20=ED=86=B5=ED=95=9C=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../getSalesCurrentComparisonMessage.ts | 25 ++++++------------- frontend/src/utils/shared/assertNever.ts | 3 +++ frontend/src/utils/shared/index.ts | 1 + 3 files changed, 11 insertions(+), 18 deletions(-) create mode 100644 frontend/src/utils/shared/assertNever.ts diff --git a/frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts b/frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts index 938c0396..a3dad0b9 100644 --- a/frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts +++ b/frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts @@ -1,7 +1,7 @@ import { METRIC_TREND, type MetricTrend } from '@/constants/dashboard'; import { DAY_OF_WEEK_LIST, PERIOD_PRESETS } from '@/constants/shared'; -import { formatNumber, type ValueOf } from '../shared'; +import { assertNever, formatNumber, type ValueOf } from '../shared'; interface GetSalesCurrentComparisonMessageArgs { periodType: ValueOf; @@ -37,7 +37,7 @@ export const getSalesCurrentComparisonMessage = ({ }; } - const METRIC_TRED_TEXT = { + const METRIC_TREND_TEXT = { [METRIC_TREND.UP]: '늘었어요.', [METRIC_TREND.DOWN]: '줄었어요.', [METRIC_TREND.SAME]: '비슷해요.', @@ -49,36 +49,25 @@ export const getSalesCurrentComparisonMessage = ({ case PERIOD_PRESETS.dayWeekMonth.today: if (metricTrend === METRIC_TREND.SAME) { return { - commonText: `${PERIOD_TEXT[periodType]} 이 시간과 ${METRIC_TRED_TEXT[metricTrend]}`, + commonText: `${PERIOD_TEXT[periodType]} 이 시간과 ${METRIC_TREND_TEXT[metricTrend]}`, }; } return { commonText: `${PERIOD_TEXT[periodType]} 이 시간보다 `, - highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, + highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TREND_TEXT[metricTrend]}`, }; case PERIOD_PRESETS.dayWeekMonth.thisWeek: - if (metricTrend === METRIC_TREND.SAME) { - return { - commonText: `${PERIOD_TEXT[periodType]}와 ${METRIC_TRED_TEXT[metricTrend]}`, - }; - } - return { - commonText: `${PERIOD_TEXT[periodType]}보다 `, - highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, - }; case PERIOD_PRESETS.dayWeekMonth.thisMonth: if (metricTrend === METRIC_TREND.SAME) { return { - commonText: `${PERIOD_TEXT[periodType]}와 ${METRIC_TRED_TEXT[metricTrend]}`, + commonText: `${PERIOD_TEXT[periodType]}와 ${METRIC_TREND_TEXT[metricTrend]}`, }; } return { commonText: `${PERIOD_TEXT[periodType]}보다 `, - highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TRED_TEXT[metricTrend]}`, + highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TREND_TEXT[metricTrend]}`, }; default: - return { - commonText: `${PERIOD_TEXT[periodType]}에는 ${metricLabel}이 거의 없었어요.`, - }; + return assertNever(periodType); } }; diff --git a/frontend/src/utils/shared/assertNever.ts b/frontend/src/utils/shared/assertNever.ts new file mode 100644 index 00000000..d2f8ed00 --- /dev/null +++ b/frontend/src/utils/shared/assertNever.ts @@ -0,0 +1,3 @@ +export const assertNever = (value: never, message?: string): never => { + throw new Error(message ?? `Unhandled case: ${String(value)}`); +}; diff --git a/frontend/src/utils/shared/index.ts b/frontend/src/utils/shared/index.ts index 001d5487..eeedac6c 100644 --- a/frontend/src/utils/shared/index.ts +++ b/frontend/src/utils/shared/index.ts @@ -38,3 +38,4 @@ export { export { createPeriodTypeProvider } from './period-select'; export type { Nullable } from './nullable'; +export { assertNever } from './assertNever'; From 598a5079763abb8e4565c980d2126dadb59727c7 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:10:32 +0900 Subject: [PATCH 38/96] =?UTF-8?q?fix:=20period=20context=20provider=20?= =?UTF-8?q?=EC=99=B8=EB=B6=80=EC=97=90=EC=84=9C=EB=8F=84=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=ED=95=9C=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../period-select/createPeriodTypeProvider.tsx | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/frontend/src/utils/shared/period-select/createPeriodTypeProvider.tsx b/frontend/src/utils/shared/period-select/createPeriodTypeProvider.tsx index ce6549a4..1faa663b 100644 --- a/frontend/src/utils/shared/period-select/createPeriodTypeProvider.tsx +++ b/frontend/src/utils/shared/period-select/createPeriodTypeProvider.tsx @@ -32,15 +32,8 @@ export const createPeriodTypeProvider = ({ periodPreset, }: createPeriodTypeProviderOptions) => { const periodTypeContext = createContext< - PeriodTypeContextState & PeriodTypeContextAction - >({ - periodType: undefined, - startDate: undefined, - endDate: undefined, - setPeriodType: () => {}, - setStartDate: () => {}, - setEndDate: () => {}, - }); + (PeriodTypeContextState & PeriodTypeContextAction) | undefined + >(undefined); const usePeriodTypeContext = () => { const context = useContext(periodTypeContext); @@ -49,7 +42,7 @@ export const createPeriodTypeProvider = ({ throw new Error('periodTypeContext not found'); } - return context as PeriodTypeContextState & PeriodTypeContextAction; + return context; }; const PeriodTypeProvider = ({ children }: PropsWithChildren) => { From e7a0eed68a659d4c65bc58a521b64af8af282bb8 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:11:13 +0900 Subject: [PATCH 39/96] =?UTF-8?q?feat:=20sales=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EA=B0=80=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/sales/salesSource.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frontend/src/constants/sales/salesSource.ts b/frontend/src/constants/sales/salesSource.ts index 55959e71..a1a0d3c9 100644 --- a/frontend/src/constants/sales/salesSource.ts +++ b/frontend/src/constants/sales/salesSource.ts @@ -34,3 +34,13 @@ export const SALES_SOURCE_COLORS = { [SALES_SOURCE.PAYMENT_METHOD.MOBILE]: 'var(--color-brand-200)', [SALES_SOURCE.PAYMENT_METHOD.ETC]: 'var(--color-brand-50)', }; + +const SALES_SOURCE_TYPES: readonly string[] = [ + ...Object.values(SALES_SOURCE.SALE_TYPE), + ...Object.values(SALES_SOURCE.ORDER_METHOD), + ...Object.values(SALES_SOURCE.PAYMENT_METHOD), +]; + +export const isSalesSourceType = (value: string): value is SalesSourceType => { + return SALES_SOURCE_TYPES.includes(value); +}; From 6aea4638b25df291e26123ff6ced8dea6e812fbe Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:13:01 +0900 Subject: [PATCH 40/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=20=EC=9C=A0?= =?UTF-8?q?=EC=9E=85=20=EA=B5=AC=EC=A1=B0=20=EA=B4=80=EB=A0=A8=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20content=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DashboardSalesIncomeContent.tsx | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx diff --git a/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx new file mode 100644 index 00000000..02c08e4b --- /dev/null +++ b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx @@ -0,0 +1,69 @@ +import type { ReactNode } from 'react'; + +import type { PERIOD_PRESETS } from '@/constants/shared'; +import type { SalesIncomeStructureInsight } from '@/types/sales/salesIncomeStructureInsight'; +import { getSalesIncomeStructureComparisionMessage } from '@/utils/dashboard'; +import { cn, type ValueOf } from '@/utils/shared'; + +interface DashboardSalesIncomeContentProps { + className?: string; + children?: ReactNode; +} + +export const DashboardSalesIncomeContent = ({ + className, + children, +}: DashboardSalesIncomeContentProps) => { + return ( +
+ {children} +
+ ); +}; + +interface DashboardSalesIncomeContentComparisonMessageProps { + periodType: ValueOf; + topType: SalesIncomeStructureInsight['topType']; + topShare: SalesIncomeStructureInsight['topShare']; + deltaShare: SalesIncomeStructureInsight['deltaShare']; +} + +export const DashboardSalesIncomeContentComparisonMessage = ({ + periodType, + topType, + topShare, + deltaShare, +}: DashboardSalesIncomeContentComparisonMessageProps) => { + const comparisonMessageTokens = getSalesIncomeStructureComparisionMessage({ + periodType, + topType, + topShare, + deltaShare, + }); + + return ( +

+ {comparisonMessageTokens.map(({ text, isHighlight }, index) => { + return ( + + {text} + + ); + })} +

+ ); +}; + +DashboardSalesIncomeContent.ComparisonMessage = + DashboardSalesIncomeContentComparisonMessage; From 2fb6c0d2c561da261fbd2796a51902c36f445e85 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:13:32 +0900 Subject: [PATCH 41/96] =?UTF-8?q?feat:=20=ED=8C=90=EB=A7=A4=EC=9C=A0?= =?UTF-8?q?=ED=98=95=EB=B3=84=20=EB=A7=A4=EC=B6=9C=20content=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SalesTypeContent.tsx | 91 +++++++++++++++++++ .../sales/dashboard-sales-income/index.ts | 2 + 2 files changed, 93 insertions(+) create mode 100644 frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx create mode 100644 frontend/src/components/sales/dashboard-sales-income/index.ts diff --git a/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx new file mode 100644 index 00000000..793065de --- /dev/null +++ b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx @@ -0,0 +1,91 @@ +import { DoughnutChart } from '@/components/shared'; +import { + DASHBOARD_METRIC_CARDS, + type DASHBOARD_METRICS, + type ExtractCardCodes, +} from '@/constants/dashboard'; +import { + isSalesSourceType, + SALES_SOURCE_COLORS, + SALES_TYPE, +} from '@/constants/sales'; +import { PERIOD_PRESETS } from '@/constants/shared'; +import type { GetIncomStructureBySalesTypeResponseDto } from '@/types/sales'; +import { assertNever, cn, type Nullable } from '@/utils/shared'; + +import { SalesSourceChartLegend } from '../sales-source'; + +import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; + +const { + EXAMPLE_TOP_TYPE, + EXAMPLE_TOP_SHARE, + EXAMPLE_DELTA_SHARE, + EXAMPLE_SALES_SOURCE_DATA, + DOUGHNUT_CHART_TITLE, +} = SALES_TYPE; + +type DashboardSalesIncomeCardCodes = ExtractCardCodes< + typeof DASHBOARD_METRICS.SALES.sections.INCOME_STRUCTURE.items.SALES_TYPE +>; + +interface SalesTypeContentProps extends Nullable { + cardCode: DashboardSalesIncomeCardCodes; +} + +export const SalesTypeContent = ({ + cardCode, + insight, + items, +}: SalesTypeContentProps) => { + const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; + + const salesSourceData = (items ?? EXAMPLE_SALES_SOURCE_DATA).map((item) => { + if (!isSalesSourceType(item.salesType)) { + return assertNever( + item.salesType as never, + `${item.salesType}는 유효하지 않은 판매 유형입니다.`, + ); + } + return { + salesSourceType: item.salesType, + revenue: item.salesAmount, + count: item.orderCount, + changeRate: item.deltaShare, + }; + }); + + const chartData = salesSourceData.map((data) => ({ + label: data.salesSourceType, + value: data.revenue, + color: SALES_SOURCE_COLORS[data.salesSourceType], + })); + + return ( + + +
+
+ +
+ +
+
+ ); +}; diff --git a/frontend/src/components/sales/dashboard-sales-income/index.ts b/frontend/src/components/sales/dashboard-sales-income/index.ts new file mode 100644 index 00000000..7f975ce4 --- /dev/null +++ b/frontend/src/components/sales/dashboard-sales-income/index.ts @@ -0,0 +1,2 @@ +export { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; +export { SalesTypeContent } from './SalesTypeContent'; From 7f2eeeac127cc99f5193c6ff60614f9262d401f5 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:25:33 +0900 Subject: [PATCH 42/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=20=EC=9C=A0?= =?UTF-8?q?=EC=9E=85=20=EA=B5=AC=EC=A1=B0=20=EA=B4=80=EB=A0=A8=20=EB=B8=8C?= =?UTF-8?q?=EB=A6=AC=ED=95=91=20message=20=EB=B0=98=ED=99=98=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...tSalesIncomeStructureComparisionMessage.ts | 59 +++++++++++++++++++ frontend/src/utils/dashboard/index.ts | 3 +- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 frontend/src/utils/dashboard/getSalesIncomeStructureComparisionMessage.ts diff --git a/frontend/src/utils/dashboard/getSalesIncomeStructureComparisionMessage.ts b/frontend/src/utils/dashboard/getSalesIncomeStructureComparisionMessage.ts new file mode 100644 index 00000000..507e2461 --- /dev/null +++ b/frontend/src/utils/dashboard/getSalesIncomeStructureComparisionMessage.ts @@ -0,0 +1,59 @@ +import { PERIOD_PRESETS } from '@/constants/shared'; +import type { SalesIncomeStructureInsight } from '@/types/sales/salesIncomeStructureInsight'; + +import { formatNumber, type ValueOf } from '../shared'; + +const createMessageToken = (text: string, isHighlight?: boolean) => { + return { + text, + isHighlight, + }; +}; + +interface GetSalesIncomeStructureComparisionMessageArgs extends Omit< + SalesIncomeStructureInsight, + 'showDeltaText' | 'showFocusText' +> { + periodType: ValueOf; +} + +interface GetSalesIncomeStructureComparisionMessageResult { + text: string; + isHighlight?: boolean; +} + +const DELTA_SHARE_THRESHOLD = 3; + +export const getSalesIncomeStructureComparisionMessage = ({ + periodType, + topType, + topShare, + deltaShare, +}: GetSalesIncomeStructureComparisionMessageArgs): GetSalesIncomeStructureComparisionMessageResult[] => { + if ( + periodType === PERIOD_PRESETS.dayWeekMonth.today && + Math.abs(deltaShare) >= DELTA_SHARE_THRESHOLD + ) { + return [ + createMessageToken('최근 7일 대비 '), + createMessageToken( + `${topType} 비중이 ${deltaShare >= 0 ? '+' : '-'}${formatNumber(deltaShare)}%p `, + true, + ), + createMessageToken('변했어요.'), + ]; + } + + if (topShare >= 60) { + return [ + createMessageToken('매출이 '), + createMessageToken(`${topType}(${formatNumber(topShare)}%)`, true), + createMessageToken('에 집중돼 있어요.'), + ]; + } + + return [ + createMessageToken(`${topType}(${formatNumber(topShare)}%) `, true), + createMessageToken('매출이 가장 많아요.'), + ]; +}; diff --git a/frontend/src/utils/dashboard/index.ts b/frontend/src/utils/dashboard/index.ts index 66eb1edf..560324e5 100644 --- a/frontend/src/utils/dashboard/index.ts +++ b/frontend/src/utils/dashboard/index.ts @@ -1,2 +1,3 @@ -export { getComparisonMessage } from './getComparisonMessage'; +export { getSalesCurrentComparisonMessage } from './getSalesCurrentComparisonMessage'; export { getMetricTrend } from './getMetricTrend'; +export { getSalesIncomeStructureComparisionMessage } from './getSalesIncomeStructureComparisionMessage'; From f806c7d11eee7b31aef886896399248627c9055f Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:25:50 +0900 Subject: [PATCH 43/96] =?UTF-8?q?feat:=20dto=20=EB=B0=B0=EB=9F=B4=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/types/sales/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/types/sales/index.ts b/frontend/src/types/sales/index.ts index a305270a..e1206fdf 100644 --- a/frontend/src/types/sales/index.ts +++ b/frontend/src/types/sales/index.ts @@ -3,4 +3,7 @@ export type { GetRealTimeSalesResponseDto, GetOrderCountResponseDto, GetAveragePriceResponseDto, + GetIncomStructureBySalesTypeResponseDto, + GetIncomStructureByOrderMethodResponseDto, + GetIncomStructureByPaymentMethodResponseDto, } from './dto'; From 23d474c2910a616763a272a583820434a24406db Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:26:08 +0900 Subject: [PATCH 44/96] =?UTF-8?q?feat:=20=ED=8C=90=EB=A7=A4=EC=9C=A0?= =?UTF-8?q?=ED=98=95=EB=B3=84=20=EB=A7=A4=EC=B6=9C=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/sales/salesType.ts | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 frontend/src/constants/sales/salesType.ts diff --git a/frontend/src/constants/sales/salesType.ts b/frontend/src/constants/sales/salesType.ts new file mode 100644 index 00000000..6e914a11 --- /dev/null +++ b/frontend/src/constants/sales/salesType.ts @@ -0,0 +1,33 @@ +import type { GetIncomStructureBySalesTypeResponseDto } from '@/types/sales'; + +import { SALES_SOURCE } from './salesSource'; + +export const SALES_TYPE = { + EXAMPLE_TOP_TYPE: '배달', + EXAMPLE_TOP_SHARE: 30, + EXAMPLE_DELTA_SHARE: 10, + EXAMPLE_SALES_SOURCE_DATA: [ + { + salesType: SALES_SOURCE.SALE_TYPE.DINE_IN, + salesAmount: 2371000, + orderCount: 26, + share: 25, + deltaShare: 4.4, + }, + { + salesType: SALES_SOURCE.SALE_TYPE.TAKEOUT, + salesAmount: 4255000, + orderCount: 45, + share: 45, + deltaShare: -5.2, + }, + { + salesType: SALES_SOURCE.SALE_TYPE.DELIVERY, + salesAmount: 2873000, + orderCount: 28, + share: 30, + deltaShare: 1.8, + }, + ] as GetIncomStructureBySalesTypeResponseDto['items'], + DOUGHNUT_CHART_TITLE: '판매 유형 관련 도넛 차트', +} as const; From 1addde0a3c124328c5964c8ebaeefc88b01db650 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:26:21 +0900 Subject: [PATCH 45/96] =?UTF-8?q?feat:=20=EC=A3=BC=EB=AC=B8=EC=88=98?= =?UTF-8?q?=EB=8B=A8=EB=B3=84=20=EB=A7=A4=EC=B6=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/sales/index.ts | 8 ++++- frontend/src/constants/sales/orderMethod.ts | 36 +++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 frontend/src/constants/sales/orderMethod.ts diff --git a/frontend/src/constants/sales/index.ts b/frontend/src/constants/sales/index.ts index eb3cc0c3..2ba171c4 100644 --- a/frontend/src/constants/sales/index.ts +++ b/frontend/src/constants/sales/index.ts @@ -1,6 +1,12 @@ -export { SALES_SOURCE_COLORS } from './salesSource'; +export { + SALES_SOURCE_COLORS, + isSalesSourceType, + SALES_SOURCE, +} from './salesSource'; export type { SalesSourceType } from './salesSource'; export { SALES_UNIT } from './salesUnit'; export { REAL_SALES } from './realSales'; export { ORDER_COUNT } from './orderCount'; export { AVERAGE_PRICE } from './averagePrice'; +export { SALES_TYPE } from './salesType'; +export { ORDER_METHOD } from './orderMethod'; diff --git a/frontend/src/constants/sales/orderMethod.ts b/frontend/src/constants/sales/orderMethod.ts new file mode 100644 index 00000000..e1c020f9 --- /dev/null +++ b/frontend/src/constants/sales/orderMethod.ts @@ -0,0 +1,36 @@ +export const ORDER_METHOD = { + EXAMPLE_TOP_TYPE: 'POS', + EXAMPLE_TOP_SHARE: 30, + EXAMPLE_DELTA_SHARE: 10, + EXAMPLE_ORDER_METHOD_DATA: [ + { + orderChannel: 'POS', + salesAmount: 2371000, + orderCount: 26, + share: 25, + deltaShare: 4.4, + }, + { + orderChannel: '키오스크', + salesAmount: 5329000, + orderCount: 53, + share: 25, + deltaShare: -5.2, + }, + { + orderChannel: '배달앱', + salesAmount: 1986000, + orderCount: 19, + share: 25, + deltaShare: 2.3, + }, + { + orderChannel: '기타', + salesAmount: 954000, + orderCount: 24, + share: 25, + deltaShare: -1.8, + }, + ], + DOUGHNUT_CHART_TITLE: '주문수단별 매출 관련 도넛 차트', +} as const; From a9fc9ad4854ec57e1d81d7a8557c631347e57294 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:26:57 +0900 Subject: [PATCH 46/96] =?UTF-8?q?feat:=20=ED=8C=90=EB=A7=A4=EC=9C=A0?= =?UTF-8?q?=EC=9E=85=EA=B5=AC=EC=A1=B0=20=EB=8F=84=EB=84=9B=20=EC=B0=A8?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EC=83=81=ED=99=94=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DashboardSalesIncomeContent.tsx | 44 ++++++++++++++++++- .../SalesTypeContent.tsx | 33 ++++---------- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx index 02c08e4b..dc592517 100644 --- a/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx @@ -1,10 +1,15 @@ import type { ReactNode } from 'react'; -import type { PERIOD_PRESETS } from '@/constants/shared'; +import { DoughnutChart } from '@/components/shared'; +import { PERIOD_PRESETS } from '@/constants/shared'; +import type { SalesSource } from '@/types/sales'; import type { SalesIncomeStructureInsight } from '@/types/sales/salesIncomeStructureInsight'; +import type { DoughnutChartItem } from '@/types/shared'; import { getSalesIncomeStructureComparisionMessage } from '@/utils/dashboard'; import { cn, type ValueOf } from '@/utils/shared'; +import { SalesSourceChartLegend } from '../sales-source'; + interface DashboardSalesIncomeContentProps { className?: string; children?: ReactNode; @@ -65,5 +70,42 @@ export const DashboardSalesIncomeContentComparisonMessage = ({ ); }; +interface DashboardSalesIncomeContentDoughnutChartProps { + periodType: ValueOf; + chartData: DoughnutChartItem[]; + salesSourceData: SalesSource[]; + title: string; +} + +export const DashboardSalesIncomeContentDoughnutChart = ({ + periodType, + chartData, + salesSourceData, + title, +}: DashboardSalesIncomeContentDoughnutChartProps) => { + return ( +
+
+ +
+ +
+ ); +}; + DashboardSalesIncomeContent.ComparisonMessage = DashboardSalesIncomeContentComparisonMessage; + +DashboardSalesIncomeContent.DoughnutChart = + DashboardSalesIncomeContentDoughnutChart; diff --git a/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx index 793065de..8a005c1f 100644 --- a/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx @@ -1,4 +1,3 @@ -import { DoughnutChart } from '@/components/shared'; import { DASHBOARD_METRIC_CARDS, type DASHBOARD_METRICS, @@ -9,11 +8,8 @@ import { SALES_SOURCE_COLORS, SALES_TYPE, } from '@/constants/sales'; -import { PERIOD_PRESETS } from '@/constants/shared'; import type { GetIncomStructureBySalesTypeResponseDto } from '@/types/sales'; -import { assertNever, cn, type Nullable } from '@/utils/shared'; - -import { SalesSourceChartLegend } from '../sales-source'; +import { assertNever, type Nullable } from '@/utils/shared'; import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; @@ -40,7 +36,7 @@ export const SalesTypeContent = ({ }: SalesTypeContentProps) => { const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; - const salesSourceData = (items ?? EXAMPLE_SALES_SOURCE_DATA).map((item) => { + const salesTypeData = (items ?? EXAMPLE_SALES_SOURCE_DATA).map((item) => { if (!isSalesSourceType(item.salesType)) { return assertNever( item.salesType as never, @@ -55,7 +51,7 @@ export const SalesTypeContent = ({ }; }); - const chartData = salesSourceData.map((data) => ({ + const chartData = salesTypeData.map((data) => ({ label: data.salesSourceType, value: data.revenue, color: SALES_SOURCE_COLORS[data.salesSourceType], @@ -69,23 +65,12 @@ export const SalesTypeContent = ({ topShare={insight?.topShare ?? EXAMPLE_TOP_SHARE} deltaShare={insight?.deltaShare ?? EXAMPLE_DELTA_SHARE} /> -
-
- -
- -
+ ); }; From a978d73b0adb64af386103600970c98cb2840e4f Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:27:34 +0900 Subject: [PATCH 47/96] =?UTF-8?q?feat:=20=EB=8F=84=EB=84=9B=20=EC=B0=A8?= =?UTF-8?q?=ED=8A=B8=20legend=20=EA=B4=80=EB=A0=A8=20=EB=B0=B0=EB=9F=B4=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/sales/sales-source/index.ts | 1 + .../components/sales/sales-source/sales-source-chart/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/frontend/src/components/sales/sales-source/index.ts b/frontend/src/components/sales/sales-source/index.ts index 52d6affa..efd7dce8 100644 --- a/frontend/src/components/sales/sales-source/index.ts +++ b/frontend/src/components/sales/sales-source/index.ts @@ -1 +1,2 @@ export { SalesSource } from './SalesSource'; +export { SalesSourceChart, SalesSourceChartLegend } from './sales-source-chart'; diff --git a/frontend/src/components/sales/sales-source/sales-source-chart/index.ts b/frontend/src/components/sales/sales-source/sales-source-chart/index.ts index 7c2a81b9..79eb0695 100644 --- a/frontend/src/components/sales/sales-source/sales-source-chart/index.ts +++ b/frontend/src/components/sales/sales-source/sales-source-chart/index.ts @@ -1 +1,2 @@ export { SalesSourceChart } from './SalesSourceChart'; +export { SalesSourceChartLegend } from './SalesSourceChartLegend'; From a27deb21fd5bb4808e531beefb7a60eb9f49bdaa Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:27:55 +0900 Subject: [PATCH 48/96] =?UTF-8?q?feat:=20=EC=A3=BC=EB=AC=B8=EC=88=98?= =?UTF-8?q?=EB=8B=A8=EB=B3=84=20=EB=A7=A4=EC=B6=9C=20content=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OrderMethodContent.tsx | 76 +++++++++++++++++++ .../sales/dashboard-sales-income/index.ts | 1 + 2 files changed, 77 insertions(+) create mode 100644 frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx diff --git a/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx new file mode 100644 index 00000000..0be64679 --- /dev/null +++ b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx @@ -0,0 +1,76 @@ +import { + DASHBOARD_METRIC_CARDS, + type DASHBOARD_METRICS, + type ExtractCardCodes, +} from '@/constants/dashboard'; +import { + isSalesSourceType, + ORDER_METHOD, + SALES_SOURCE_COLORS, +} from '@/constants/sales'; +import type { GetIncomStructureByOrderMethodResponseDto } from '@/types/sales'; +import { assertNever, type Nullable } from '@/utils/shared'; + +import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; + +const { + EXAMPLE_TOP_TYPE, + EXAMPLE_TOP_SHARE, + EXAMPLE_DELTA_SHARE, + EXAMPLE_ORDER_METHOD_DATA, + DOUGHNUT_CHART_TITLE, +} = ORDER_METHOD; + +type OrderMethodCardCodes = ExtractCardCodes< + typeof DASHBOARD_METRICS.SALES.sections.INCOME_STRUCTURE.items.ORDER_METHOD +>; + +interface OrderMethodContentProps extends Nullable { + cardCode: OrderMethodCardCodes; +} + +export const OrderMethodContent = ({ + cardCode, + insight, + items, +}: OrderMethodContentProps) => { + const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; + + const orderMethodData = (items ?? EXAMPLE_ORDER_METHOD_DATA).map((item) => { + if (!isSalesSourceType(item.orderChannel)) { + return assertNever( + item.orderChannel as never, + `${item.orderChannel}는 유효하지 않은 주문수단입니다.`, + ); + } + return { + salesSourceType: item.orderChannel, + revenue: item.salesAmount, + count: item.orderCount, + changeRate: item.deltaShare, + }; + }); + + const chartData = orderMethodData.map((data) => ({ + label: data.salesSourceType, + value: data.revenue, + color: SALES_SOURCE_COLORS[data.salesSourceType], + })); + + return ( + + + + + ); +}; diff --git a/frontend/src/components/sales/dashboard-sales-income/index.ts b/frontend/src/components/sales/dashboard-sales-income/index.ts index 7f975ce4..8886b175 100644 --- a/frontend/src/components/sales/dashboard-sales-income/index.ts +++ b/frontend/src/components/sales/dashboard-sales-income/index.ts @@ -1,2 +1,3 @@ export { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; export { SalesTypeContent } from './SalesTypeContent'; +export { OrderMethodContent } from './OrderMethodContent'; From 169dc5e66bd45bfba3112fad0db590324200172a Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:39:21 +0900 Subject: [PATCH 49/96] =?UTF-8?q?feat:=20=EC=98=88=EC=8B=9C=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EC=99=80=20=EB=B8=8C=EB=A6=AC=ED=95=91=20tex?= =?UTF-8?q?t=EA=B0=80=20=EC=9D=BC=EC=B9=98=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/sales/orderMethod.ts | 12 ++++++------ frontend/src/constants/sales/salesType.ts | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/frontend/src/constants/sales/orderMethod.ts b/frontend/src/constants/sales/orderMethod.ts index e1c020f9..3b4fa4c5 100644 --- a/frontend/src/constants/sales/orderMethod.ts +++ b/frontend/src/constants/sales/orderMethod.ts @@ -1,28 +1,28 @@ export const ORDER_METHOD = { - EXAMPLE_TOP_TYPE: 'POS', - EXAMPLE_TOP_SHARE: 30, - EXAMPLE_DELTA_SHARE: 10, + EXAMPLE_TOP_TYPE: '키오스크', + EXAMPLE_TOP_SHARE: 50, + EXAMPLE_DELTA_SHARE: 4, EXAMPLE_ORDER_METHOD_DATA: [ { orderChannel: 'POS', salesAmount: 2371000, orderCount: 26, share: 25, - deltaShare: 4.4, + deltaShare: 2.4, }, { orderChannel: '키오스크', salesAmount: 5329000, orderCount: 53, share: 25, - deltaShare: -5.2, + deltaShare: 4, }, { orderChannel: '배달앱', salesAmount: 1986000, orderCount: 19, share: 25, - deltaShare: 2.3, + deltaShare: -5.2, }, { orderChannel: '기타', diff --git a/frontend/src/constants/sales/salesType.ts b/frontend/src/constants/sales/salesType.ts index 6e914a11..a4f5ced8 100644 --- a/frontend/src/constants/sales/salesType.ts +++ b/frontend/src/constants/sales/salesType.ts @@ -4,8 +4,8 @@ import { SALES_SOURCE } from './salesSource'; export const SALES_TYPE = { EXAMPLE_TOP_TYPE: '배달', - EXAMPLE_TOP_SHARE: 30, - EXAMPLE_DELTA_SHARE: 10, + EXAMPLE_TOP_SHARE: 43, + EXAMPLE_DELTA_SHARE: 6.8, EXAMPLE_SALES_SOURCE_DATA: [ { salesType: SALES_SOURCE.SALE_TYPE.DINE_IN, @@ -16,17 +16,17 @@ export const SALES_TYPE = { }, { salesType: SALES_SOURCE.SALE_TYPE.TAKEOUT, - salesAmount: 4255000, + salesAmount: 3255000, orderCount: 45, share: 45, deltaShare: -5.2, }, { salesType: SALES_SOURCE.SALE_TYPE.DELIVERY, - salesAmount: 2873000, + salesAmount: 4255000, orderCount: 28, share: 30, - deltaShare: 1.8, + deltaShare: 6.8, }, ] as GetIncomStructureBySalesTypeResponseDto['items'], DOUGHNUT_CHART_TITLE: '판매 유형 관련 도넛 차트', From a6ffbd3587fd8eaf63c401bbcb5a8ae75bf6b9c3 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:39:51 +0900 Subject: [PATCH 50/96] =?UTF-8?q?feat:=20=EA=B2=B0=EC=A0=9C=EC=88=98?= =?UTF-8?q?=EB=8B=A8=EB=B3=84=20=EB=A7=A4=EC=B6=9C=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/constants/sales/paymentMethod.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 frontend/src/constants/sales/paymentMethod.ts diff --git a/frontend/src/constants/sales/paymentMethod.ts b/frontend/src/constants/sales/paymentMethod.ts new file mode 100644 index 00000000..13fa50c8 --- /dev/null +++ b/frontend/src/constants/sales/paymentMethod.ts @@ -0,0 +1,36 @@ +export const PAYMENT_METHOD = { + EXAMPLE_TOP_TYPE: '현금', + EXAMPLE_TOP_SHARE: 46, + EXAMPLE_DELTA_SHARE: 6.7, + EXAMPLE_PAYMENT_METHOD_DATA: [ + { + payMethod: '카드', + salesAmount: 2371000, + orderCount: 26, + share: 25, + deltaShare: 4.4, + }, + { + payMethod: '현금', + salesAmount: 7531000, + orderCount: 25, + share: 25, + deltaShare: 6.7, + }, + { + payMethod: '간편결제', + salesAmount: 2567000, + orderCount: 75, + share: 25, + deltaShare: -5.2, + }, + { + payMethod: '기타', + salesAmount: 3894000, + orderCount: 39, + share: 25, + deltaShare: 2.4, + }, + ], + DOUGHNUT_CHART_TITLE: '결제수단별 매출 관련 도넛 차트', +} as const; From 2212eb3a3af4a4c794dde7afa64c1b4517104f5e Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:40:10 +0900 Subject: [PATCH 51/96] =?UTF-8?q?feat:=20=EA=B2=B0=EC=A0=9C=EC=88=98?= =?UTF-8?q?=EB=8B=A8=EB=B3=84=20=EB=A7=A4=EC=B6=9C=20content=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PaymentMethodContent.tsx | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx diff --git a/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx b/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx new file mode 100644 index 00000000..2e1957bc --- /dev/null +++ b/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx @@ -0,0 +1,78 @@ +import { + DASHBOARD_METRIC_CARDS, + type DASHBOARD_METRICS, + type ExtractCardCodes, +} from '@/constants/dashboard'; +import { + isSalesSourceType, + PAYMENT_METHOD, + SALES_SOURCE_COLORS, +} from '@/constants/sales'; +import type { GetIncomStructureByPaymentMethodResponseDto } from '@/types/sales'; +import { assertNever, type Nullable } from '@/utils/shared'; + +import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; + +const { + EXAMPLE_TOP_TYPE, + EXAMPLE_TOP_SHARE, + EXAMPLE_DELTA_SHARE, + EXAMPLE_PAYMENT_METHOD_DATA, + DOUGHNUT_CHART_TITLE, +} = PAYMENT_METHOD; + +type PaymentMethodCardCodes = ExtractCardCodes< + typeof DASHBOARD_METRICS.SALES.sections.INCOME_STRUCTURE.items.PAYMENT_METHOD +>; + +interface PaymentMethodContentProps extends Nullable { + cardCode: PaymentMethodCardCodes; +} + +export const PaymentMethodContent = ({ + cardCode, + insight, + items, +}: PaymentMethodContentProps) => { + const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; + + const paymentMethodData = (items ?? EXAMPLE_PAYMENT_METHOD_DATA).map( + (item) => { + if (!isSalesSourceType(item.payMethod)) { + return assertNever( + item.payMethod as never, + `${item.payMethod}는 유효하지 않은 결제수단입니다.`, + ); + } + return { + salesSourceType: item.payMethod, + revenue: item.salesAmount, + count: item.orderCount, + changeRate: item.deltaShare, + }; + }, + ); + + const chartData = paymentMethodData.map((data) => ({ + label: data.salesSourceType, + value: data.revenue, + color: SALES_SOURCE_COLORS[data.salesSourceType], + })); + + return ( + + + + + ); +}; From 7919dc37fb6d236562f19b8fe995409058b6f059 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:40:24 +0900 Subject: [PATCH 52/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=20=EB=8F=84?= =?UTF-8?q?=EB=84=9B=20=EC=B0=A8=ED=8A=B8=20=EC=83=89=EC=83=81=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 --- frontend/src/constants/sales/index.ts | 1 + frontend/src/constants/sales/salesSource.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/constants/sales/index.ts b/frontend/src/constants/sales/index.ts index 2ba171c4..a14ca5e9 100644 --- a/frontend/src/constants/sales/index.ts +++ b/frontend/src/constants/sales/index.ts @@ -10,3 +10,4 @@ export { ORDER_COUNT } from './orderCount'; export { AVERAGE_PRICE } from './averagePrice'; export { SALES_TYPE } from './salesType'; export { ORDER_METHOD } from './orderMethod'; +export { PAYMENT_METHOD } from './paymentMethod'; diff --git a/frontend/src/constants/sales/salesSource.ts b/frontend/src/constants/sales/salesSource.ts index a1a0d3c9..6980fbe3 100644 --- a/frontend/src/constants/sales/salesSource.ts +++ b/frontend/src/constants/sales/salesSource.ts @@ -28,7 +28,7 @@ export const SALES_SOURCE_COLORS = { [SALES_SOURCE.SALE_TYPE.TAKEOUT]: 'var(--color-brand-50)', [SALES_SOURCE.ORDER_METHOD.POS]: 'var(--color-brand-500)', [SALES_SOURCE.ORDER_METHOD.KIOSK]: 'var(--color-grey-500)', - [SALES_SOURCE.ORDER_METHOD.DELIVERY_APP]: 'var(--color-brand-50)', + [SALES_SOURCE.ORDER_METHOD.DELIVERY_APP]: 'var(--color-brand-200)', [SALES_SOURCE.PAYMENT_METHOD.CARD]: 'var(--color-brand-500)', [SALES_SOURCE.PAYMENT_METHOD.CASH]: 'var(--color-grey-500)', [SALES_SOURCE.PAYMENT_METHOD.MOBILE]: 'var(--color-brand-200)', From 5992ceab263d930e7255307ce0d371bdc7d3ab53 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 03:40:36 +0900 Subject: [PATCH 53/96] =?UTF-8?q?feat:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=B3=80=EC=88=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/stories/DefaultCardWrapper.stories.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/stories/DefaultCardWrapper.stories.tsx b/frontend/src/stories/DefaultCardWrapper.stories.tsx index 2f5495ec..c22599b2 100644 --- a/frontend/src/stories/DefaultCardWrapper.stories.tsx +++ b/frontend/src/stories/DefaultCardWrapper.stories.tsx @@ -43,10 +43,9 @@ export const Default: Story = { export const WithTitleIcon: Story = { args: { - width: 340, - height: 228, title: '오늘 날씨 예보', hasChevronRightIcon: true, children: , + className: 'w-85 h-57', }, }; From 19490a1996c374d696bbae5633494067bfe04ab9 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 12:38:43 +0900 Subject: [PATCH 54/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=EC=9C=A0?= =?UTF-8?q?=EC=9E=85=EA=B5=AC=EC=A1=B0=20top=20type=20=EC=A0=95=EC=9D=98?= =?UTF-8?q?=20=EB=B0=8F=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EA=B0=80=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OrderMethodContent.tsx | 28 ++++++------------- .../PaymentMethodContent.tsx | 28 ++++++------------- .../SalesTypeContent.tsx | 28 ++++++------------- frontend/src/components/sales/index.ts | 9 +++++- .../dto/getIncomStructureByOrderMethodDto.ts | 10 +++++-- .../getIncomStructureByPaymentMethodDto.ts | 10 +++++-- .../dto/getIncomStructureBySalesTypeDto.ts | 7 +++-- .../sales/salesIncomeStructureInsight.ts | 14 +++++++++- 8 files changed, 66 insertions(+), 68 deletions(-) diff --git a/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx index 0be64679..e5a20124 100644 --- a/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx @@ -3,13 +3,9 @@ import { type DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; -import { - isSalesSourceType, - ORDER_METHOD, - SALES_SOURCE_COLORS, -} from '@/constants/sales'; +import { ORDER_METHOD, SALES_SOURCE_COLORS } from '@/constants/sales'; import type { GetIncomStructureByOrderMethodResponseDto } from '@/types/sales'; -import { assertNever, type Nullable } from '@/utils/shared'; +import { type Nullable } from '@/utils/shared'; import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; @@ -36,20 +32,12 @@ export const OrderMethodContent = ({ }: OrderMethodContentProps) => { const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; - const orderMethodData = (items ?? EXAMPLE_ORDER_METHOD_DATA).map((item) => { - if (!isSalesSourceType(item.orderChannel)) { - return assertNever( - item.orderChannel as never, - `${item.orderChannel}는 유효하지 않은 주문수단입니다.`, - ); - } - return { - salesSourceType: item.orderChannel, - revenue: item.salesAmount, - count: item.orderCount, - changeRate: item.deltaShare, - }; - }); + const orderMethodData = (items ?? EXAMPLE_ORDER_METHOD_DATA).map((item) => ({ + salesSourceType: item.orderChannel, + revenue: item.salesAmount, + count: item.orderCount, + changeRate: item.deltaShare, + })); const chartData = orderMethodData.map((data) => ({ label: data.salesSourceType, diff --git a/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx b/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx index 2e1957bc..c7bfe636 100644 --- a/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx @@ -3,13 +3,9 @@ import { type DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; -import { - isSalesSourceType, - PAYMENT_METHOD, - SALES_SOURCE_COLORS, -} from '@/constants/sales'; +import { PAYMENT_METHOD, SALES_SOURCE_COLORS } from '@/constants/sales'; import type { GetIncomStructureByPaymentMethodResponseDto } from '@/types/sales'; -import { assertNever, type Nullable } from '@/utils/shared'; +import { type Nullable } from '@/utils/shared'; import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; @@ -37,20 +33,12 @@ export const PaymentMethodContent = ({ const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; const paymentMethodData = (items ?? EXAMPLE_PAYMENT_METHOD_DATA).map( - (item) => { - if (!isSalesSourceType(item.payMethod)) { - return assertNever( - item.payMethod as never, - `${item.payMethod}는 유효하지 않은 결제수단입니다.`, - ); - } - return { - salesSourceType: item.payMethod, - revenue: item.salesAmount, - count: item.orderCount, - changeRate: item.deltaShare, - }; - }, + (item) => ({ + salesSourceType: item.payMethod, + revenue: item.salesAmount, + count: item.orderCount, + changeRate: item.deltaShare, + }), ); const chartData = paymentMethodData.map((data) => ({ diff --git a/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx index 8a005c1f..61c5972f 100644 --- a/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx @@ -3,13 +3,9 @@ import { type DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; -import { - isSalesSourceType, - SALES_SOURCE_COLORS, - SALES_TYPE, -} from '@/constants/sales'; +import { SALES_SOURCE_COLORS, SALES_TYPE } from '@/constants/sales'; import type { GetIncomStructureBySalesTypeResponseDto } from '@/types/sales'; -import { assertNever, type Nullable } from '@/utils/shared'; +import { type Nullable } from '@/utils/shared'; import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; @@ -36,20 +32,12 @@ export const SalesTypeContent = ({ }: SalesTypeContentProps) => { const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; - const salesTypeData = (items ?? EXAMPLE_SALES_SOURCE_DATA).map((item) => { - if (!isSalesSourceType(item.salesType)) { - return assertNever( - item.salesType as never, - `${item.salesType}는 유효하지 않은 판매 유형입니다.`, - ); - } - return { - salesSourceType: item.salesType, - revenue: item.salesAmount, - count: item.orderCount, - changeRate: item.deltaShare, - }; - }); + const salesTypeData = (items ?? EXAMPLE_SALES_SOURCE_DATA).map((item) => ({ + salesSourceType: item.salesType, + revenue: item.salesAmount, + count: item.orderCount, + changeRate: item.deltaShare, + })); const chartData = salesTypeData.map((data) => ({ label: data.salesSourceType, diff --git a/frontend/src/components/sales/index.ts b/frontend/src/components/sales/index.ts index 4370df7e..8a27ab0b 100644 --- a/frontend/src/components/sales/index.ts +++ b/frontend/src/components/sales/index.ts @@ -1,4 +1,11 @@ export { SalesOverview } from './sales-overview'; export { SalesPatterns } from './sales-patterns'; -export { SalesSource } from './sales-source'; +export { SalesSource, SalesSourceChartLegend } from './sales-source'; export { SalesTrends } from './sales-trends'; +export { + AveragePriceContent, + OrderCountContent, + RealSalesContent, +} from './dashboard-current-sales'; +export { DashboardSalesIncomeContent } from './dashboard-sales-income'; +export { SalesTypeContent, OrderMethodContent } from './dashboard-sales-income'; diff --git a/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts b/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts index 37a42db0..0411dacd 100644 --- a/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts +++ b/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts @@ -1,7 +1,13 @@ -import type { SalesIncomeStructureInsight } from '../salesIncomeStructureInsight'; +import type { + SalesIncomeStructureInsight, + SalesIncomeStructureTopType, +} from '../salesIncomeStructureInsight'; interface OrderMethodItem { - orderChannel: string; + orderChannel: Extract< + SalesIncomeStructureTopType, + 'POS' | '키오스크' | '배달앱' | '기타' + >; salesAmount: number; orderCount: number; share: number; diff --git a/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts b/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts index 50863103..461a76ea 100644 --- a/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts +++ b/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts @@ -1,7 +1,13 @@ -import type { SalesIncomeStructureInsight } from '../salesIncomeStructureInsight'; +import type { + SalesIncomeStructureInsight, + SalesIncomeStructureTopType, +} from '../salesIncomeStructureInsight'; interface PaymentMethodItem { - payMethod: string; + payMethod: Extract< + SalesIncomeStructureTopType, + '카드' | '현금' | '간편결제' | '기타' + >; salesAmount: number; orderCount: number; share: number; diff --git a/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts b/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts index f4fd218e..3a319de4 100644 --- a/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts +++ b/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts @@ -1,7 +1,10 @@ -import type { SalesIncomeStructureInsight } from '../salesIncomeStructureInsight'; +import type { + SalesIncomeStructureInsight, + SalesIncomeStructureTopType, +} from '../salesIncomeStructureInsight'; interface SalesTypeItem { - salesType: string; + salesType: Extract; salesAmount: number; orderCount: number; share: number; diff --git a/frontend/src/types/sales/salesIncomeStructureInsight.ts b/frontend/src/types/sales/salesIncomeStructureInsight.ts index f8abc6c2..f39f7da6 100644 --- a/frontend/src/types/sales/salesIncomeStructureInsight.ts +++ b/frontend/src/types/sales/salesIncomeStructureInsight.ts @@ -1,5 +1,17 @@ +export type SalesIncomeStructureTopType = + | '홀' + | '포장' + | '배달' + | 'POS' + | '키오스크' + | '배달앱' + | '카드' + | '현금' + | '간편결제' + | '기타'; + export interface SalesIncomeStructureInsight { - topType: string; + topType: SalesIncomeStructureTopType; topShare: number; deltaShare: number; showDeltaText: boolean; From 1bc71ac92f24912448b363f3aa52fdee2d31ae09 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 15:51:25 +0900 Subject: [PATCH 55/96] =?UTF-8?q?refactor:=20=EB=8C=80=EC=8B=9C=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=EB=A7=A4=EC=B6=9C=20=EA=B4=80=EB=A0=A8=20=EC=9C=A0?= =?UTF-8?q?=ED=8B=B8=20=ED=95=A8=EC=88=98=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/dashboard/index.ts | 2 -- .../sales/dashboard/createMessageToken.ts | 8 ++++++++ .../getSalesCurrentComparisonMessage.ts | 3 +-- ...tSalesIncomeStructureComparisionMessage.ts | 19 ++++--------------- frontend/src/utils/sales/dashboard/index.ts | 3 +++ frontend/src/utils/sales/index.ts | 5 +++++ 6 files changed, 21 insertions(+), 19 deletions(-) create mode 100644 frontend/src/utils/sales/dashboard/createMessageToken.ts rename frontend/src/utils/{ => sales}/dashboard/getSalesCurrentComparisonMessage.ts (96%) rename frontend/src/utils/{ => sales}/dashboard/getSalesIncomeStructureComparisionMessage.ts (76%) create mode 100644 frontend/src/utils/sales/dashboard/index.ts diff --git a/frontend/src/utils/dashboard/index.ts b/frontend/src/utils/dashboard/index.ts index 560324e5..001fb27d 100644 --- a/frontend/src/utils/dashboard/index.ts +++ b/frontend/src/utils/dashboard/index.ts @@ -1,3 +1 @@ -export { getSalesCurrentComparisonMessage } from './getSalesCurrentComparisonMessage'; export { getMetricTrend } from './getMetricTrend'; -export { getSalesIncomeStructureComparisionMessage } from './getSalesIncomeStructureComparisionMessage'; diff --git a/frontend/src/utils/sales/dashboard/createMessageToken.ts b/frontend/src/utils/sales/dashboard/createMessageToken.ts new file mode 100644 index 00000000..7e417052 --- /dev/null +++ b/frontend/src/utils/sales/dashboard/createMessageToken.ts @@ -0,0 +1,8 @@ +export const createMessageToken = (text: string, isHighlight?: boolean) => { + return { + text, + isHighlight, + }; +}; + +export type MessageToken = ReturnType; diff --git a/frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts b/frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts similarity index 96% rename from frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts rename to frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts index a3dad0b9..443ffe04 100644 --- a/frontend/src/utils/dashboard/getSalesCurrentComparisonMessage.ts +++ b/frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts @@ -1,7 +1,6 @@ import { METRIC_TREND, type MetricTrend } from '@/constants/dashboard'; import { DAY_OF_WEEK_LIST, PERIOD_PRESETS } from '@/constants/shared'; - -import { assertNever, formatNumber, type ValueOf } from '../shared'; +import { assertNever, formatNumber, type ValueOf } from '@/utils/shared'; interface GetSalesCurrentComparisonMessageArgs { periodType: ValueOf; diff --git a/frontend/src/utils/dashboard/getSalesIncomeStructureComparisionMessage.ts b/frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts similarity index 76% rename from frontend/src/utils/dashboard/getSalesIncomeStructureComparisionMessage.ts rename to frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts index 507e2461..00c19780 100644 --- a/frontend/src/utils/dashboard/getSalesIncomeStructureComparisionMessage.ts +++ b/frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts @@ -1,14 +1,10 @@ import { PERIOD_PRESETS } from '@/constants/shared'; import type { SalesIncomeStructureInsight } from '@/types/sales/salesIncomeStructureInsight'; +import { formatNumber, type ValueOf } from '@/utils/shared'; -import { formatNumber, type ValueOf } from '../shared'; +import { createMessageToken, type MessageToken } from './createMessageToken'; -const createMessageToken = (text: string, isHighlight?: boolean) => { - return { - text, - isHighlight, - }; -}; +const DELTA_SHARE_THRESHOLD = 3; interface GetSalesIncomeStructureComparisionMessageArgs extends Omit< SalesIncomeStructureInsight, @@ -17,19 +13,12 @@ interface GetSalesIncomeStructureComparisionMessageArgs extends Omit< periodType: ValueOf; } -interface GetSalesIncomeStructureComparisionMessageResult { - text: string; - isHighlight?: boolean; -} - -const DELTA_SHARE_THRESHOLD = 3; - export const getSalesIncomeStructureComparisionMessage = ({ periodType, topType, topShare, deltaShare, -}: GetSalesIncomeStructureComparisionMessageArgs): GetSalesIncomeStructureComparisionMessageResult[] => { +}: GetSalesIncomeStructureComparisionMessageArgs): MessageToken[] => { if ( periodType === PERIOD_PRESETS.dayWeekMonth.today && Math.abs(deltaShare) >= DELTA_SHARE_THRESHOLD diff --git a/frontend/src/utils/sales/dashboard/index.ts b/frontend/src/utils/sales/dashboard/index.ts new file mode 100644 index 00000000..4437b109 --- /dev/null +++ b/frontend/src/utils/sales/dashboard/index.ts @@ -0,0 +1,3 @@ +export { getSalesPatternPeaktimeMessage } from './getSalesPatternPeaktimeMessage'; +export { getSalesCurrentComparisonMessage } from './getSalesCurrentComparisonMessage'; +export { getSalesIncomeStructureComparisionMessage } from './getSalesIncomeStructureComparisionMessage'; diff --git a/frontend/src/utils/sales/index.ts b/frontend/src/utils/sales/index.ts index 2b69505a..bf6e70f4 100644 --- a/frontend/src/utils/sales/index.ts +++ b/frontend/src/utils/sales/index.ts @@ -1 +1,6 @@ export { getPeriodComparisonMessage } from './sales-overview'; +export { + getSalesPatternPeaktimeMessage, + getSalesCurrentComparisonMessage, + getSalesIncomeStructureComparisionMessage, +} from './dashboard'; From b08a26685948599f8c9b70f7eba5c94d1db94c1e Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 15:52:03 +0900 Subject: [PATCH 56/96] =?UTF-8?q?chore:=20import=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/dashboard-current-sales/AveragePriceContent.tsx | 6 ++---- .../sales/dashboard-current-sales/OrderCountContent.tsx | 6 ++---- .../sales/dashboard-current-sales/RealSalesContent.tsx | 6 ++---- .../dashboard-sales-income/DashboardSalesIncomeContent.tsx | 5 ++--- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx b/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx index 3b33cbe1..5a47e563 100644 --- a/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx @@ -5,10 +5,8 @@ import { } from '@/constants/dashboard'; import { AVERAGE_PRICE, SALES_UNIT } from '@/constants/sales'; import type { GetAveragePriceResponseDto } from '@/types/sales'; -import { - getMetricTrend, - getSalesCurrentComparisonMessage, -} from '@/utils/dashboard'; +import { getMetricTrend } from '@/utils/dashboard'; +import { getSalesCurrentComparisonMessage } from '@/utils/sales'; import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; diff --git a/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx b/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx index afd71dc1..dfb7251b 100644 --- a/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx @@ -5,10 +5,8 @@ import { } from '@/constants/dashboard'; import { ORDER_COUNT, SALES_UNIT } from '@/constants/sales'; import type { GetOrderCountResponseDto } from '@/types/sales'; -import { - getMetricTrend, - getSalesCurrentComparisonMessage, -} from '@/utils/dashboard'; +import { getMetricTrend } from '@/utils/dashboard'; +import { getSalesCurrentComparisonMessage } from '@/utils/sales'; import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; diff --git a/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx b/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx index 66814edb..dfb17bfc 100644 --- a/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx @@ -5,10 +5,8 @@ import { } from '@/constants/dashboard'; import { REAL_SALES, SALES_UNIT } from '@/constants/sales'; import type { GetRealTimeSalesResponseDto } from '@/types/sales'; -import { - getMetricTrend, - getSalesCurrentComparisonMessage, -} from '@/utils/dashboard'; +import { getMetricTrend } from '@/utils/dashboard'; +import { getSalesCurrentComparisonMessage } from '@/utils/sales'; import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; diff --git a/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx index dc592517..51646c02 100644 --- a/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx @@ -2,10 +2,9 @@ import type { ReactNode } from 'react'; import { DoughnutChart } from '@/components/shared'; import { PERIOD_PRESETS } from '@/constants/shared'; -import type { SalesSource } from '@/types/sales'; -import type { SalesIncomeStructureInsight } from '@/types/sales/salesIncomeStructureInsight'; +import type { SalesIncomeStructureInsight, SalesSource } from '@/types/sales'; import type { DoughnutChartItem } from '@/types/shared'; -import { getSalesIncomeStructureComparisionMessage } from '@/utils/dashboard'; +import { getSalesIncomeStructureComparisionMessage } from '@/utils/sales'; import { cn, type ValueOf } from '@/utils/shared'; import { SalesSourceChartLegend } from '../sales-source'; From b932b7d296886b360b79e895291a4654f4a75e6a Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 16:15:00 +0900 Subject: [PATCH 57/96] =?UTF-8?q?refactor:=20sales=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94dashboard=20sub=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/{ => dashboard}/averagePrice.ts | 0 .../dashboard/briefingMessageHighlightColor.ts | 8 ++++++++ frontend/src/constants/sales/dashboard/index.ts | 10 ++++++++++ .../sales/{ => dashboard}/orderCount.ts | 0 .../sales/{ => dashboard}/orderMethod.ts | 0 .../sales/{ => dashboard}/paymentMethod.ts | 0 .../constants/sales/{ => dashboard}/realSales.ts | 0 .../constants/sales/{ => dashboard}/salesType.ts | 2 +- frontend/src/constants/sales/index.ts | 16 ++++++++++------ 9 files changed, 29 insertions(+), 7 deletions(-) rename frontend/src/constants/sales/{ => dashboard}/averagePrice.ts (100%) create mode 100644 frontend/src/constants/sales/dashboard/briefingMessageHighlightColor.ts create mode 100644 frontend/src/constants/sales/dashboard/index.ts rename frontend/src/constants/sales/{ => dashboard}/orderCount.ts (100%) rename frontend/src/constants/sales/{ => dashboard}/orderMethod.ts (100%) rename frontend/src/constants/sales/{ => dashboard}/paymentMethod.ts (100%) rename frontend/src/constants/sales/{ => dashboard}/realSales.ts (100%) rename frontend/src/constants/sales/{ => dashboard}/salesType.ts (94%) diff --git a/frontend/src/constants/sales/averagePrice.ts b/frontend/src/constants/sales/dashboard/averagePrice.ts similarity index 100% rename from frontend/src/constants/sales/averagePrice.ts rename to frontend/src/constants/sales/dashboard/averagePrice.ts diff --git a/frontend/src/constants/sales/dashboard/briefingMessageHighlightColor.ts b/frontend/src/constants/sales/dashboard/briefingMessageHighlightColor.ts new file mode 100644 index 00000000..06425d41 --- /dev/null +++ b/frontend/src/constants/sales/dashboard/briefingMessageHighlightColor.ts @@ -0,0 +1,8 @@ +export const BRIEFING_MESSAGE_HIGHLIGHT_COLOR = { + primary: 'text-brand-main font-bold', + negative: 'text-others-negative font-bold', + default: 'text-grey-500', +} as const; + +export type BriefingMessageHighlightColor = + keyof typeof BRIEFING_MESSAGE_HIGHLIGHT_COLOR; diff --git a/frontend/src/constants/sales/dashboard/index.ts b/frontend/src/constants/sales/dashboard/index.ts new file mode 100644 index 00000000..7c7e42c6 --- /dev/null +++ b/frontend/src/constants/sales/dashboard/index.ts @@ -0,0 +1,10 @@ +export { + BRIEFING_MESSAGE_HIGHLIGHT_COLOR, + type BriefingMessageHighlightColor, +} from './briefingMessageHighlightColor'; +export { AVERAGE_PRICE } from './averagePrice'; +export { ORDER_COUNT } from './orderCount'; +export { REAL_SALES } from './realSales'; +export { ORDER_METHOD } from './orderMethod'; +export { PAYMENT_METHOD } from './paymentMethod'; +export { SALES_TYPE } from './salesType'; diff --git a/frontend/src/constants/sales/orderCount.ts b/frontend/src/constants/sales/dashboard/orderCount.ts similarity index 100% rename from frontend/src/constants/sales/orderCount.ts rename to frontend/src/constants/sales/dashboard/orderCount.ts diff --git a/frontend/src/constants/sales/orderMethod.ts b/frontend/src/constants/sales/dashboard/orderMethod.ts similarity index 100% rename from frontend/src/constants/sales/orderMethod.ts rename to frontend/src/constants/sales/dashboard/orderMethod.ts diff --git a/frontend/src/constants/sales/paymentMethod.ts b/frontend/src/constants/sales/dashboard/paymentMethod.ts similarity index 100% rename from frontend/src/constants/sales/paymentMethod.ts rename to frontend/src/constants/sales/dashboard/paymentMethod.ts diff --git a/frontend/src/constants/sales/realSales.ts b/frontend/src/constants/sales/dashboard/realSales.ts similarity index 100% rename from frontend/src/constants/sales/realSales.ts rename to frontend/src/constants/sales/dashboard/realSales.ts diff --git a/frontend/src/constants/sales/salesType.ts b/frontend/src/constants/sales/dashboard/salesType.ts similarity index 94% rename from frontend/src/constants/sales/salesType.ts rename to frontend/src/constants/sales/dashboard/salesType.ts index a4f5ced8..9b58f523 100644 --- a/frontend/src/constants/sales/salesType.ts +++ b/frontend/src/constants/sales/dashboard/salesType.ts @@ -1,6 +1,6 @@ import type { GetIncomStructureBySalesTypeResponseDto } from '@/types/sales'; -import { SALES_SOURCE } from './salesSource'; +import { SALES_SOURCE } from '../salesSource'; export const SALES_TYPE = { EXAMPLE_TOP_TYPE: '배달', diff --git a/frontend/src/constants/sales/index.ts b/frontend/src/constants/sales/index.ts index a14ca5e9..5061f27c 100644 --- a/frontend/src/constants/sales/index.ts +++ b/frontend/src/constants/sales/index.ts @@ -5,9 +5,13 @@ export { } from './salesSource'; export type { SalesSourceType } from './salesSource'; export { SALES_UNIT } from './salesUnit'; -export { REAL_SALES } from './realSales'; -export { ORDER_COUNT } from './orderCount'; -export { AVERAGE_PRICE } from './averagePrice'; -export { SALES_TYPE } from './salesType'; -export { ORDER_METHOD } from './orderMethod'; -export { PAYMENT_METHOD } from './paymentMethod'; +export { + BRIEFING_MESSAGE_HIGHLIGHT_COLOR, + type BriefingMessageHighlightColor, + AVERAGE_PRICE, + ORDER_COUNT, + REAL_SALES, + ORDER_METHOD, + PAYMENT_METHOD, + SALES_TYPE, +} from './dashboard'; From 1564ea87ab6d7b7693c5f51f0f1bd2a087136d2b Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 16:15:43 +0900 Subject: [PATCH 58/96] =?UTF-8?q?feat:=20=EC=83=89=EC=83=81=20=ED=95=98?= =?UTF-8?q?=EC=9D=B4=EB=9D=BC=EC=9D=B4=ED=8A=B8=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20token=20=EA=B8=B0=EB=B0=98=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=ED=86=B5=EC=9D=BC=20=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AveragePriceContent.tsx | 6 +- .../CurrentSalesContent.tsx | 38 ++++++------ .../OrderCountContent.tsx | 6 +- .../RealSalesContent.tsx | 6 +- .../DashboardSalesIncomeContent.tsx | 28 +++++---- .../sales/dashboard/createMessageToken.ts | 14 ++++- .../getSalesCurrentComparisonMessage.ts | 61 ++++++++++++------- ...tSalesIncomeStructureComparisionMessage.ts | 3 +- 8 files changed, 95 insertions(+), 67 deletions(-) diff --git a/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx b/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx index 5a47e563..d74e5ea6 100644 --- a/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx @@ -42,7 +42,7 @@ export const AveragePriceContent = ({ minValue: MIN_CHANGE_RATE, maxValue: MAX_CHANGE_RATE, }); - const { commonText, highlightText } = getSalesCurrentComparisonMessage({ + const comparisonMessageTokens = getSalesCurrentComparisonMessage({ periodType, hasPreviousData, metricTrend, @@ -58,9 +58,7 @@ export const AveragePriceContent = ({ unit={SALES_UNIT.WON} /> ); diff --git a/frontend/src/components/sales/dashboard-current-sales/CurrentSalesContent.tsx b/frontend/src/components/sales/dashboard-current-sales/CurrentSalesContent.tsx index ccc50fdc..bc7f9f7d 100644 --- a/frontend/src/components/sales/dashboard-current-sales/CurrentSalesContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/CurrentSalesContent.tsx @@ -2,6 +2,7 @@ import { type ReactNode, useMemo } from 'react'; import { METRIC_TREND, type MetricTrend } from '@/constants/dashboard'; import { CDN_BASE_URL } from '@/constants/shared'; +import type { MessageToken } from '@/utils/sales/dashboard/createMessageToken'; import { cn, formatNumber } from '@/utils/shared'; interface CurrentSalesContentProps { @@ -63,7 +64,7 @@ const CurrentSalesContentAmount = ({ }: CurrentSalesContentAmountProps) => { return ( - + {formatNumber(amount)} {unit} @@ -72,31 +73,30 @@ const CurrentSalesContentAmount = ({ }; interface CurrentSalesContentComparisonMessageProps { - comparisonMessage: string; - changeRateMessage?: string; - metricTrend: MetricTrend; + comparisonMessageTokens: MessageToken[]; className?: string; } const CurrentSalesContentComparisonMessage = ({ - comparisonMessage, - changeRateMessage, - metricTrend, + comparisonMessageTokens, className, }: CurrentSalesContentComparisonMessageProps) => { return ( -

- {comparisonMessage} - {changeRateMessage && ( - - {changeRateMessage} - +

+ {comparisonMessageTokens.map( + ({ text, isHighlight, highlightColor }, index) => { + return ( + + {text} + + ); + }, )}

); diff --git a/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx b/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx index dfb7251b..ba852121 100644 --- a/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx @@ -44,7 +44,7 @@ export const OrderCountContent = ({ maxValue: MAX_CHANGE_RATE, }); - const { commonText, highlightText } = getSalesCurrentComparisonMessage({ + const comparisonMessageTokens = getSalesCurrentComparisonMessage({ periodType, hasPreviousData, metricTrend, @@ -57,9 +57,7 @@ export const OrderCountContent = ({ ); diff --git a/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx b/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx index dfb17bfc..c6ac4ba3 100644 --- a/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx @@ -44,7 +44,7 @@ export const RealSalesContent = ({ maxValue: MAX_CHANGE_RATE, }); - const { commonText, highlightText } = getSalesCurrentComparisonMessage({ + const comparisonMessageTokens = getSalesCurrentComparisonMessage({ periodType, hasPreviousData, metricTrend, @@ -58,9 +58,7 @@ export const RealSalesContent = ({ ); diff --git a/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx index 51646c02..5ad50d0e 100644 --- a/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx @@ -52,19 +52,21 @@ export const DashboardSalesIncomeContentComparisonMessage = ({ return (

- {comparisonMessageTokens.map(({ text, isHighlight }, index) => { - return ( - - {text} - - ); - })} + {comparisonMessageTokens.map( + ({ text, isHighlight, highlightColor }, index) => { + return ( + + {text} + + ); + }, + )}

); }; diff --git a/frontend/src/utils/sales/dashboard/createMessageToken.ts b/frontend/src/utils/sales/dashboard/createMessageToken.ts index 7e417052..e3b262dc 100644 --- a/frontend/src/utils/sales/dashboard/createMessageToken.ts +++ b/frontend/src/utils/sales/dashboard/createMessageToken.ts @@ -1,7 +1,19 @@ -export const createMessageToken = (text: string, isHighlight?: boolean) => { +import { + BRIEFING_MESSAGE_HIGHLIGHT_COLOR, + type BriefingMessageHighlightColor, +} from '@/constants/sales'; + +export const createMessageToken = ( + text: string, + isHighlight?: boolean, + highlight?: BriefingMessageHighlightColor, +) => { return { text, isHighlight, + highlightColor: highlight + ? BRIEFING_MESSAGE_HIGHLIGHT_COLOR[highlight] + : BRIEFING_MESSAGE_HIGHLIGHT_COLOR.primary, }; }; diff --git a/frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts b/frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts index 443ffe04..f588fed4 100644 --- a/frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts +++ b/frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts @@ -2,6 +2,8 @@ import { METRIC_TREND, type MetricTrend } from '@/constants/dashboard'; import { DAY_OF_WEEK_LIST, PERIOD_PRESETS } from '@/constants/shared'; import { assertNever, formatNumber, type ValueOf } from '@/utils/shared'; +import { createMessageToken, type MessageToken } from './createMessageToken'; + interface GetSalesCurrentComparisonMessageArgs { periodType: ValueOf; hasPreviousData: boolean; @@ -18,10 +20,7 @@ export const getSalesCurrentComparisonMessage = ({ metricLabel, comparisonAmount, unit, -}: GetSalesCurrentComparisonMessageArgs): { - commonText: string; - highlightText?: string; -} => { +}: GetSalesCurrentComparisonMessageArgs): MessageToken[] => { const weekday = DAY_OF_WEEK_LIST[new Date().getDay()]; const PERIOD_TEXT = { @@ -31,9 +30,11 @@ export const getSalesCurrentComparisonMessage = ({ }; if (!hasPreviousData) { - return { - commonText: `${PERIOD_TEXT[periodType]}에는 ${metricLabel}이 거의 없었어요.`, - }; + return [ + createMessageToken( + `${PERIOD_TEXT[periodType]}에는 ${metricLabel}이 거의 없었어요.`, + ), + ]; } const METRIC_TREND_TEXT = { @@ -47,25 +48,43 @@ export const getSalesCurrentComparisonMessage = ({ switch (periodType) { case PERIOD_PRESETS.dayWeekMonth.today: if (metricTrend === METRIC_TREND.SAME) { - return { - commonText: `${PERIOD_TEXT[periodType]} 이 시간과 ${METRIC_TREND_TEXT[metricTrend]}`, - }; + return [ + createMessageToken(`${PERIOD_TEXT[periodType]} 이 시간과 `), + createMessageToken( + `${METRIC_TREND_TEXT[metricTrend]}`, + true, + 'default', + ), + ]; } - return { - commonText: `${PERIOD_TEXT[periodType]} 이 시간보다 `, - highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TREND_TEXT[metricTrend]}`, - }; + return [ + createMessageToken(`${PERIOD_TEXT[periodType]} 이 시간보다 `), + createMessageToken( + `${formattedComparisonAmount}${unit} ${METRIC_TREND_TEXT[metricTrend]}`, + true, + metricTrend === METRIC_TREND.UP ? 'primary' : 'negative', + ), + ]; case PERIOD_PRESETS.dayWeekMonth.thisWeek: case PERIOD_PRESETS.dayWeekMonth.thisMonth: if (metricTrend === METRIC_TREND.SAME) { - return { - commonText: `${PERIOD_TEXT[periodType]}와 ${METRIC_TREND_TEXT[metricTrend]}`, - }; + return [ + createMessageToken(`${PERIOD_TEXT[periodType]}와 `), + createMessageToken( + `${METRIC_TREND_TEXT[metricTrend]}`, + true, + 'default', + ), + ]; } - return { - commonText: `${PERIOD_TEXT[periodType]}보다 `, - highlightText: `${formattedComparisonAmount}${unit} ${METRIC_TREND_TEXT[metricTrend]}`, - }; + return [ + createMessageToken(`${PERIOD_TEXT[periodType]}보다 `), + createMessageToken( + `${formattedComparisonAmount}${unit} ${METRIC_TREND_TEXT[metricTrend]}`, + true, + metricTrend === METRIC_TREND.UP ? 'primary' : 'negative', + ), + ]; default: return assertNever(periodType); } diff --git a/frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts b/frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts index 00c19780..b21ab7b4 100644 --- a/frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts +++ b/frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts @@ -26,8 +26,9 @@ export const getSalesIncomeStructureComparisionMessage = ({ return [ createMessageToken('최근 7일 대비 '), createMessageToken( - `${topType} 비중이 ${deltaShare >= 0 ? '+' : '-'}${formatNumber(deltaShare)}%p `, + `${topType} 비중이 ${deltaShare >= 0 && '+'}${formatNumber(deltaShare)}%p `, true, + deltaShare >= 0 ? 'primary' : 'negative', ), createMessageToken('변했어요.'), ]; From 293e16449faf47f611784bab87ee76447ba85544 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 17:58:29 +0900 Subject: [PATCH 59/96] =?UTF-8?q?feat:=20lineChart=20getClientBoundingRect?= =?UTF-8?q?=20=EB=8C=80=EC=8B=A0=20svg=20viewbox=20=EB=86=92=EC=9D=B4,=20?= =?UTF-8?q?=EB=84=88=EB=B9=84=EB=A5=BC=20=ED=99=9C=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared/line-chart/LineChart.tsx | 12 ++--- .../shared/line-chart/XGuideLine.tsx | 7 +-- .../shared/line-chart/YGuideLine.tsx | 10 ++-- .../hooks/shared/line-chart/useLineChart.ts | 53 ++++++++++--------- .../utils/shared/line-chart/getCoordinate.ts | 5 +- .../utils/shared/line-chart/getXCoordinate.ts | 6 +-- 6 files changed, 41 insertions(+), 52 deletions(-) diff --git a/frontend/src/components/shared/line-chart/LineChart.tsx b/frontend/src/components/shared/line-chart/LineChart.tsx index c28f2491..41d2a3d5 100644 --- a/frontend/src/components/shared/line-chart/LineChart.tsx +++ b/frontend/src/components/shared/line-chart/LineChart.tsx @@ -90,7 +90,7 @@ export const LineChart = ({ const { lineGradientId, backgroundGradientId, titleId, descId } = useLineChartId(); const { - svgRect, + svgWidth, adjustedHeight, xLabelList, xCoordinate, @@ -100,6 +100,8 @@ export const LineChart = ({ svgRef, xAxisRef, } = useLineChart({ + viewBoxWidth, + viewBoxHeight, primarySeries, secondarySeries, hasXAxis, @@ -132,17 +134,13 @@ export const LineChart = ({ )} {showYGuideLine && ( )} {showXGuideLine && ( - + )} {hasXAxis && ( <> diff --git a/frontend/src/components/shared/line-chart/XGuideLine.tsx b/frontend/src/components/shared/line-chart/XGuideLine.tsx index f1066fa3..2137796e 100644 --- a/frontend/src/components/shared/line-chart/XGuideLine.tsx +++ b/frontend/src/components/shared/line-chart/XGuideLine.tsx @@ -5,16 +5,11 @@ import type { Coordinate } from '@/types/shared'; interface XGuideLineProps { xCoordinate: Coordinate[]; - svgRect: DOMRect | null; adjustedHeight: number; } export const XGuideLine = memo( - ({ xCoordinate, svgRect, adjustedHeight }: XGuideLineProps) => { - if (svgRect === null) { - return null; - } - + ({ xCoordinate, adjustedHeight }: XGuideLineProps) => { const { TICK_HEIGHT, GUIDE_LINE_STROKE_WIDTH, GUIDE_LINE_DASH_ARRAY } = LINE_CHART; diff --git a/frontend/src/components/shared/line-chart/YGuideLine.tsx b/frontend/src/components/shared/line-chart/YGuideLine.tsx index 0952de61..3c79e1a7 100644 --- a/frontend/src/components/shared/line-chart/YGuideLine.tsx +++ b/frontend/src/components/shared/line-chart/YGuideLine.tsx @@ -3,17 +3,13 @@ import { memo } from 'react'; import { LINE_CHART } from '@/constants/shared'; interface YGuideLineProps { - svgRect: DOMRect | null; + svgWidth: number; adjustedHeight: number; yGuideLineCount: number; } export const YGuideLine = memo( - ({ svgRect, adjustedHeight, yGuideLineCount }: YGuideLineProps) => { - if (svgRect === null) { - return null; - } - + ({ svgWidth, adjustedHeight, yGuideLineCount }: YGuideLineProps) => { const { GUIDE_LINE_STROKE_WIDTH, GUIDE_LINE_DASH_ARRAY } = LINE_CHART; const intervalY = adjustedHeight / yGuideLineCount; @@ -29,7 +25,7 @@ export const YGuideLine = memo( ); const pathD = cordinateYGuideLine - .map(([x, y]) => `M ${x} ${y} h ${svgRect.width}`) + .map(([x, y]) => `M ${x} ${y} h ${svgWidth}`) .join(' '); return ( diff --git a/frontend/src/hooks/shared/line-chart/useLineChart.ts b/frontend/src/hooks/shared/line-chart/useLineChart.ts index fd0a68d5..6a3f1cd9 100644 --- a/frontend/src/hooks/shared/line-chart/useLineChart.ts +++ b/frontend/src/hooks/shared/line-chart/useLineChart.ts @@ -8,18 +8,21 @@ import { } from '@/utils/shared'; interface UseLineChartProps { + viewBoxWidth: number; + viewBoxHeight: number; primarySeries: LineChartSeries; secondarySeries?: LineChartSeries; hasXAxis?: boolean; } export const useLineChart = ({ + viewBoxWidth, + viewBoxHeight, primarySeries, secondarySeries, hasXAxis = false, }: UseLineChartProps) => { - const [svgRect, setSvgRect] = useState(null); - const [adjustedHeight, setAdjustedHeight] = useState(0); + const [adjustedHeight, setAdjustedHeight] = useState(viewBoxHeight); const svgRef = useRef(null); const xAxisRef = useRef(null); @@ -29,14 +32,14 @@ export const useLineChart = ({ }, [primarySeries.data.mainX]); const xCoordinate = useMemo(() => { - if (svgRect === null) { + if (primarySeries.data.mainX.length === 0) { return []; } return getXCoordinate({ - svgRect, + svgWidth: viewBoxWidth, xDataLength: primarySeries.data.mainX.length, }); - }, [svgRect, primarySeries.data.mainX.length]); + }, [viewBoxWidth, primarySeries.data.mainX.length]); const maximumY = useMemo(() => { const totalData = [ @@ -56,16 +59,16 @@ export const useLineChart = ({ }, [primarySeries.data.mainY, secondarySeries?.data.mainY]); const primaryCoordinate = useMemo(() => { - if (svgRect === null) { + if (primarySeries.data.mainX.length === 0) { return []; } return getCoordinate({ - svgRect, + svgWidth: viewBoxWidth, adjustedHeight, series: primarySeries, maximumY, }); - }, [svgRect, adjustedHeight, primarySeries, maximumY]); + }, [viewBoxWidth, adjustedHeight, primarySeries, maximumY]); const lastXCoordinate = useMemo(() => { const filteredCoordinate = filterCoordinate(primaryCoordinate); @@ -78,34 +81,34 @@ export const useLineChart = ({ }, [primaryCoordinate]); const secondaryCoordinate = useMemo(() => { - if (svgRect === null || secondarySeries === undefined) { + if ( + secondarySeries === undefined || + secondarySeries.data.mainX.length === 0 + ) { return []; } return getCoordinate({ - svgRect, + svgWidth: viewBoxWidth, adjustedHeight, series: secondarySeries, maximumY, }); - }, [svgRect, adjustedHeight, secondarySeries, maximumY]); + }, [viewBoxWidth, adjustedHeight, secondarySeries, maximumY]); useLayoutEffect(() => { - if (!svgRef.current) { - return; - } - setSvgRect(svgRef.current.getBoundingClientRect()); - setAdjustedHeight(svgRef.current.getBoundingClientRect().height); - if (hasXAxis && xAxisRef.current) { - setAdjustedHeight( - xAxisRef.current.getBoundingClientRect().y - - svgRef.current.getBoundingClientRect().y + - xAxisRef.current.getBoundingClientRect().height / 2, - ); - } - }, [svgRef, xAxisRef, hasXAxis]); + const updateAdjustedHeight = () => { + if (!hasXAxis || !xAxisRef.current) { + setAdjustedHeight(viewBoxHeight); + return; + } + const xAxisBBox = xAxisRef.current.getBBox(); + setAdjustedHeight(xAxisBBox.y + xAxisBBox.height / 2); + }; + updateAdjustedHeight(); + }, [hasXAxis, viewBoxHeight]); return { - svgRect, + svgWidth: viewBoxWidth, adjustedHeight, xLabelList, xCoordinate, diff --git a/frontend/src/utils/shared/line-chart/getCoordinate.ts b/frontend/src/utils/shared/line-chart/getCoordinate.ts index b0e4ec68..24d5cd91 100644 --- a/frontend/src/utils/shared/line-chart/getCoordinate.ts +++ b/frontend/src/utils/shared/line-chart/getCoordinate.ts @@ -1,7 +1,7 @@ import type { LineChartSeries } from '@/types/shared'; interface GetCoordinateArgs { - svgRect: DOMRect; + svgWidth: number; adjustedHeight: number; series: LineChartSeries; maximumY: number; @@ -13,12 +13,11 @@ interface Coordinate { } export const getCoordinate = ({ - svgRect, + svgWidth, adjustedHeight, series, maximumY, }: GetCoordinateArgs): Coordinate[] => { - const { width: svgWidth } = svgRect; const xDataLength = series.data.mainX.length; const intervalX = svgWidth / xDataLength; diff --git a/frontend/src/utils/shared/line-chart/getXCoordinate.ts b/frontend/src/utils/shared/line-chart/getXCoordinate.ts index e601ac49..cb738e66 100644 --- a/frontend/src/utils/shared/line-chart/getXCoordinate.ts +++ b/frontend/src/utils/shared/line-chart/getXCoordinate.ts @@ -1,14 +1,12 @@ import type { Coordinate } from '@/types/shared'; export const getXCoordinate = ({ - svgRect, + svgWidth, xDataLength, }: { - svgRect: DOMRect; + svgWidth: number; xDataLength: number; }): Coordinate[] => { - const { width: svgWidth } = svgRect; - const intervalX = svgWidth / xDataLength; const lastX = intervalX * (xDataLength - 1); const offsetX = (svgWidth - lastX) / 2; From 041077a78d20ec0010bf98d7f4f07d21f9d5fc81 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 18:34:14 +0900 Subject: [PATCH 60/96] =?UTF-8?q?refactor:=20sales=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20sub=20domain=20=EC=84=B8=EB=B6=84=ED=99=94?= =?UTF-8?q?=20=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{dashboard => dashboard-current-sales}/averagePrice.ts | 0 frontend/src/constants/sales/dashboard-current-sales/index.ts | 3 +++ .../sales/{dashboard => dashboard-current-sales}/orderCount.ts | 0 .../sales/{dashboard => dashboard-current-sales}/realSales.ts | 0 frontend/src/constants/sales/dashboard-sales-income/index.ts | 3 +++ .../sales/{dashboard => dashboard-sales-income}/orderMethod.ts | 0 .../{dashboard => dashboard-sales-income}/paymentMethod.ts | 0 .../sales/{dashboard => dashboard-sales-income}/salesType.ts | 0 8 files changed, 6 insertions(+) rename frontend/src/constants/sales/{dashboard => dashboard-current-sales}/averagePrice.ts (100%) create mode 100644 frontend/src/constants/sales/dashboard-current-sales/index.ts rename frontend/src/constants/sales/{dashboard => dashboard-current-sales}/orderCount.ts (100%) rename frontend/src/constants/sales/{dashboard => dashboard-current-sales}/realSales.ts (100%) create mode 100644 frontend/src/constants/sales/dashboard-sales-income/index.ts rename frontend/src/constants/sales/{dashboard => dashboard-sales-income}/orderMethod.ts (100%) rename frontend/src/constants/sales/{dashboard => dashboard-sales-income}/paymentMethod.ts (100%) rename frontend/src/constants/sales/{dashboard => dashboard-sales-income}/salesType.ts (100%) diff --git a/frontend/src/constants/sales/dashboard/averagePrice.ts b/frontend/src/constants/sales/dashboard-current-sales/averagePrice.ts similarity index 100% rename from frontend/src/constants/sales/dashboard/averagePrice.ts rename to frontend/src/constants/sales/dashboard-current-sales/averagePrice.ts diff --git a/frontend/src/constants/sales/dashboard-current-sales/index.ts b/frontend/src/constants/sales/dashboard-current-sales/index.ts new file mode 100644 index 00000000..529d36bf --- /dev/null +++ b/frontend/src/constants/sales/dashboard-current-sales/index.ts @@ -0,0 +1,3 @@ +export { AVERAGE_PRICE } from './averagePrice'; +export { ORDER_COUNT } from './orderCount'; +export { REAL_SALES } from './realSales'; diff --git a/frontend/src/constants/sales/dashboard/orderCount.ts b/frontend/src/constants/sales/dashboard-current-sales/orderCount.ts similarity index 100% rename from frontend/src/constants/sales/dashboard/orderCount.ts rename to frontend/src/constants/sales/dashboard-current-sales/orderCount.ts diff --git a/frontend/src/constants/sales/dashboard/realSales.ts b/frontend/src/constants/sales/dashboard-current-sales/realSales.ts similarity index 100% rename from frontend/src/constants/sales/dashboard/realSales.ts rename to frontend/src/constants/sales/dashboard-current-sales/realSales.ts diff --git a/frontend/src/constants/sales/dashboard-sales-income/index.ts b/frontend/src/constants/sales/dashboard-sales-income/index.ts new file mode 100644 index 00000000..29a6b99f --- /dev/null +++ b/frontend/src/constants/sales/dashboard-sales-income/index.ts @@ -0,0 +1,3 @@ +export { ORDER_METHOD } from './orderMethod'; +export { PAYMENT_METHOD } from './paymentMethod'; +export { SALES_TYPE } from './salesType'; diff --git a/frontend/src/constants/sales/dashboard/orderMethod.ts b/frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts similarity index 100% rename from frontend/src/constants/sales/dashboard/orderMethod.ts rename to frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts diff --git a/frontend/src/constants/sales/dashboard/paymentMethod.ts b/frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts similarity index 100% rename from frontend/src/constants/sales/dashboard/paymentMethod.ts rename to frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts diff --git a/frontend/src/constants/sales/dashboard/salesType.ts b/frontend/src/constants/sales/dashboard-sales-income/salesType.ts similarity index 100% rename from frontend/src/constants/sales/dashboard/salesType.ts rename to frontend/src/constants/sales/dashboard-sales-income/salesType.ts From 8036c58c564e8f8e03ebe6757c86b9f271b1f95e Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 18:35:32 +0900 Subject: [PATCH 61/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=20=ED=8C=A8?= =?UTF-8?q?=ED=84=B4=20=EB=B8=8C=EB=A6=AC=ED=95=91=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../getSalesPatternPeaktimeMessage.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 frontend/src/utils/sales/dashboard/getSalesPatternPeaktimeMessage.ts diff --git a/frontend/src/utils/sales/dashboard/getSalesPatternPeaktimeMessage.ts b/frontend/src/utils/sales/dashboard/getSalesPatternPeaktimeMessage.ts new file mode 100644 index 00000000..46e1ecf0 --- /dev/null +++ b/frontend/src/utils/sales/dashboard/getSalesPatternPeaktimeMessage.ts @@ -0,0 +1,29 @@ +import type { GetDashboardPeakTimeResponseDto } from '@/types/sales'; + +import { createMessageToken, type MessageToken } from './createMessageToken'; + +interface GetSalesPatternPeaktimeMessageArgs { + todayPeak: GetDashboardPeakTimeResponseDto['todayPeak']; + comparisonPeak: GetDashboardPeakTimeResponseDto['comparisonPeak']; + beforeComparisonPeak: GetDashboardPeakTimeResponseDto['beforeComparisonPeak']; +} + +export const getSalesPatternPeaktimeMessage = ({ + todayPeak, + comparisonPeak, + beforeComparisonPeak, +}: GetSalesPatternPeaktimeMessageArgs): MessageToken[] => { + if (beforeComparisonPeak) { + return [ + createMessageToken('오늘은 '), + createMessageToken(`${comparisonPeak}시대가 피크타임`, true, 'primary'), + createMessageToken('으로 예상돼요.'), + ]; + } + + return [ + createMessageToken('지금까지 주문이 가장 몰린 시간은 '), + createMessageToken(`${todayPeak}시대`, true, 'primary'), + createMessageToken('예요.'), + ]; +}; From 4e0c681f61cc7f9c34b62dbee2ff734e44716d17 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 18:36:06 +0900 Subject: [PATCH 62/96] =?UTF-8?q?feat:=20=ED=94=BC=ED=81=AC=ED=83=80?= =?UTF-8?q?=EC=9E=84=20line=20chart=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EB=B3=80=ED=99=98=20=EC=9C=A0=ED=8B=B8=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/dashboard/createPeakTimeSeries.ts | 21 +++++++++++++++++++ frontend/src/utils/sales/dashboard/index.ts | 1 + frontend/src/utils/sales/index.ts | 1 + 3 files changed, 23 insertions(+) create mode 100644 frontend/src/utils/sales/dashboard/createPeakTimeSeries.ts diff --git a/frontend/src/utils/sales/dashboard/createPeakTimeSeries.ts b/frontend/src/utils/sales/dashboard/createPeakTimeSeries.ts new file mode 100644 index 00000000..5a967832 --- /dev/null +++ b/frontend/src/utils/sales/dashboard/createPeakTimeSeries.ts @@ -0,0 +1,21 @@ +import type { GetDetailPeakTimeResponseDto } from '@/types/sales'; + +export const createPeakTimeSeries = ( + items: + | GetDetailPeakTimeResponseDto['todayItems'] + | GetDetailPeakTimeResponseDto['week4Items'], + color: string, + mainXUnit: string = '', + mainYUnit: string = '', +) => { + const data = { + mainX: items.map((item) => ({ amount: item.timeSlot2H, unit: mainXUnit })), + mainY: items.map((item) => ({ amount: item.orderCount, unit: mainYUnit })), + subX: [], + subY: [], + }; + return { + data, + color, + }; +}; diff --git a/frontend/src/utils/sales/dashboard/index.ts b/frontend/src/utils/sales/dashboard/index.ts index 4437b109..490b0937 100644 --- a/frontend/src/utils/sales/dashboard/index.ts +++ b/frontend/src/utils/sales/dashboard/index.ts @@ -1,3 +1,4 @@ export { getSalesPatternPeaktimeMessage } from './getSalesPatternPeaktimeMessage'; export { getSalesCurrentComparisonMessage } from './getSalesCurrentComparisonMessage'; export { getSalesIncomeStructureComparisionMessage } from './getSalesIncomeStructureComparisionMessage'; +export { createPeakTimeSeries } from './createPeakTimeSeries'; diff --git a/frontend/src/utils/sales/index.ts b/frontend/src/utils/sales/index.ts index bf6e70f4..a2d754ad 100644 --- a/frontend/src/utils/sales/index.ts +++ b/frontend/src/utils/sales/index.ts @@ -3,4 +3,5 @@ export { getSalesPatternPeaktimeMessage, getSalesCurrentComparisonMessage, getSalesIncomeStructureComparisionMessage, + createPeakTimeSeries, } from './dashboard'; From 17fee4bea7b555462b05307f051d5d960e2920ab Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 18:36:37 +0900 Subject: [PATCH 63/96] =?UTF-8?q?feat:=20=ED=94=BC=ED=81=AC=ED=83=80?= =?UTF-8?q?=EC=9E=84=20=EA=B4=80=EB=A0=A8=20=EC=83=81=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/dashboard-sales-pattern/index.ts | 1 + .../sales/dashboard-sales-pattern/peakTime.ts | 39 +++++++++++++++++++ frontend/src/constants/sales/index.ts | 7 +++- 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 frontend/src/constants/sales/dashboard-sales-pattern/index.ts create mode 100644 frontend/src/constants/sales/dashboard-sales-pattern/peakTime.ts diff --git a/frontend/src/constants/sales/dashboard-sales-pattern/index.ts b/frontend/src/constants/sales/dashboard-sales-pattern/index.ts new file mode 100644 index 00000000..a04ab1cc --- /dev/null +++ b/frontend/src/constants/sales/dashboard-sales-pattern/index.ts @@ -0,0 +1 @@ +export { PEAK_TIME } from './peakTime'; diff --git a/frontend/src/constants/sales/dashboard-sales-pattern/peakTime.ts b/frontend/src/constants/sales/dashboard-sales-pattern/peakTime.ts new file mode 100644 index 00000000..5de0f06b --- /dev/null +++ b/frontend/src/constants/sales/dashboard-sales-pattern/peakTime.ts @@ -0,0 +1,39 @@ +import type { GetDetailPeakTimeResponseDto } from '@/types/sales'; + +export const PEAK_TIME = { + EXAMPLE_DATA: { + todayPeak: 8, + comparisonPeak: 18, + diff: 10, + shiftDirection: 'EARLY', + beforeComparisonPeak: true, + todayItems: [ + { timeSlot2H: 0, orderCount: 12, netAmount: 300000 }, + { timeSlot2H: 2, orderCount: 8, netAmount: 180000 }, + { timeSlot2H: 4, orderCount: 5, netAmount: 120000 }, + { timeSlot2H: 6, orderCount: 18, netAmount: 420000 }, + { timeSlot2H: 8, orderCount: 42, netAmount: 980000 }, + { timeSlot2H: 10, orderCount: null, netAmount: null }, + { timeSlot2H: 12, orderCount: null, netAmount: null }, + { timeSlot2H: 14, orderCount: null, netAmount: null }, + { timeSlot2H: 16, orderCount: null, netAmount: null }, + { timeSlot2H: 18, orderCount: null, netAmount: null }, + { timeSlot2H: 20, orderCount: null, netAmount: null }, + { timeSlot2H: 22, orderCount: null, netAmount: null }, + ], + week4Items: [ + { timeSlot2H: 0, orderCount: 10, netAmount: 250000 }, + { timeSlot2H: 2, orderCount: 7, netAmount: 170000 }, + { timeSlot2H: 4, orderCount: 6, netAmount: 140000 }, + { timeSlot2H: 6, orderCount: 15, netAmount: 360000 }, + { timeSlot2H: 8, orderCount: 35, netAmount: 840000 }, + { timeSlot2H: 10, orderCount: 48, netAmount: 1160000 }, + { timeSlot2H: 12, orderCount: 62, netAmount: 1520000 }, + { timeSlot2H: 14, orderCount: 58, netAmount: 1430000 }, + { timeSlot2H: 16, orderCount: 54, netAmount: 1310000 }, + { timeSlot2H: 18, orderCount: 66, netAmount: 1650000 }, + { timeSlot2H: 20, orderCount: 40, netAmount: 990000 }, + { timeSlot2H: 22, orderCount: 22, netAmount: 540000 }, + ], + } satisfies GetDetailPeakTimeResponseDto, +}; diff --git a/frontend/src/constants/sales/index.ts b/frontend/src/constants/sales/index.ts index 5061f27c..644ab89c 100644 --- a/frontend/src/constants/sales/index.ts +++ b/frontend/src/constants/sales/index.ts @@ -8,10 +8,15 @@ export { SALES_UNIT } from './salesUnit'; export { BRIEFING_MESSAGE_HIGHLIGHT_COLOR, type BriefingMessageHighlightColor, +} from './dashboard'; +export { AVERAGE_PRICE, ORDER_COUNT, REAL_SALES, +} from './dashboard-current-sales'; +export { ORDER_METHOD, PAYMENT_METHOD, SALES_TYPE, -} from './dashboard'; +} from './dashboard-sales-income'; +export { PEAK_TIME } from './dashboard-sales-pattern'; From a4ffcc7a281a44ad06804889353f5a0fac8dbedc Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 18:36:55 +0900 Subject: [PATCH 64/96] =?UTF-8?q?feat:=20=ED=94=BC=ED=81=AC=ED=83=80?= =?UTF-8?q?=EC=9E=84=20=EA=B4=80=EB=A0=A8=20dto=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/types/sales/dto/getPeakTimeDto.ts | 29 +++++++++++++++++++ frontend/src/types/sales/dto/index.ts | 4 +++ frontend/src/types/sales/index.ts | 3 ++ 3 files changed, 36 insertions(+) create mode 100644 frontend/src/types/sales/dto/getPeakTimeDto.ts diff --git a/frontend/src/types/sales/dto/getPeakTimeDto.ts b/frontend/src/types/sales/dto/getPeakTimeDto.ts new file mode 100644 index 00000000..247b3036 --- /dev/null +++ b/frontend/src/types/sales/dto/getPeakTimeDto.ts @@ -0,0 +1,29 @@ +interface PeakTimeItem { + timeSlot2H: number; + orderCount: number | null; + netAmount: number | null; +} + +interface PeakTimeSummary { + todayPeak: number; // 오늘 피크 시간 + comparisonPeak: number; // 비교 시간 피크 시간 + diff: number; // 비교 시간 피크 시간 차이 + shiftDirection: ShiftDirection; // 피크 시간 방향성 + beforeComparisonPeak: boolean; // 비교 시간 피크 시간 이전 +} + +type ShiftDirection = 'EARLY' | 'LATE' | 'SAME' | 'UNKNOWN'; + +export interface GetDetailPeakTimeResponseDto extends PeakTimeSummary { + todayItems: PeakTimeItem[]; + week4Items: PeakTimeItem[]; +} + +/** + * 대시보드 피크 시간 DTO (SSE) + */ +export interface GetDashboardPeakTimeResponseDto extends PeakTimeSummary { + timeSlot2H: number; // 현재 시간 + orderCount: number; // 현재 시간 주문건수 + netAmount: number; // 현재 시간 실매출액 +} diff --git a/frontend/src/types/sales/dto/index.ts b/frontend/src/types/sales/dto/index.ts index a46380ae..834bc63f 100644 --- a/frontend/src/types/sales/dto/index.ts +++ b/frontend/src/types/sales/dto/index.ts @@ -4,3 +4,7 @@ export type { GetAveragePriceResponseDto } from './getAveragePriceDto'; export type { GetIncomStructureBySalesTypeResponseDto } from './getIncomStructureBySalesTypeDto'; export type { GetIncomStructureByOrderMethodResponseDto } from './getIncomStructureByOrderMethodDto'; export type { GetIncomStructureByPaymentMethodResponseDto } from './getIncomStructureByPaymentMethodDto'; +export type { + GetDetailPeakTimeResponseDto, + GetDashboardPeakTimeResponseDto, +} from './getPeakTimeDto'; diff --git a/frontend/src/types/sales/index.ts b/frontend/src/types/sales/index.ts index e1206fdf..60c08feb 100644 --- a/frontend/src/types/sales/index.ts +++ b/frontend/src/types/sales/index.ts @@ -6,4 +6,7 @@ export type { GetIncomStructureBySalesTypeResponseDto, GetIncomStructureByOrderMethodResponseDto, GetIncomStructureByPaymentMethodResponseDto, + GetDetailPeakTimeResponseDto, + GetDashboardPeakTimeResponseDto, } from './dto'; +export type { SalesIncomeStructureInsight } from './salesIncomeStructureInsight'; From d6fb0ea1dbfea32e49cfeb6c2d1e527b52c60786 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 18:37:14 +0900 Subject: [PATCH 65/96] =?UTF-8?q?feat:=20=ED=94=BC=ED=81=AC=ED=83=80?= =?UTF-8?q?=EC=9E=84=20card=20content=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PeakTimeChartCaption.tsx | 32 ++++++ .../PeakTimeContent.tsx | 99 +++++++++++++++++++ .../sales/dashboard-sales-pattern/index.ts | 0 3 files changed, 131 insertions(+) create mode 100644 frontend/src/components/sales/dashboard-sales-pattern/PeakTimeChartCaption.tsx create mode 100644 frontend/src/components/sales/dashboard-sales-pattern/PeakTimeContent.tsx create mode 100644 frontend/src/components/sales/dashboard-sales-pattern/index.ts diff --git a/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeChartCaption.tsx b/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeChartCaption.tsx new file mode 100644 index 00000000..07cdf9f8 --- /dev/null +++ b/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeChartCaption.tsx @@ -0,0 +1,32 @@ +import { cn } from '@/utils/shared'; + +interface PeakTimeChartCaptionProps { + label: string; + color: 'primary' | 'default'; +} + +export const PeakTimeChartCaption = ({ + label, + color, +}: PeakTimeChartCaptionProps) => { + return ( +
+
+ + {label} + +
+ ); +}; diff --git a/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeContent.tsx b/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeContent.tsx new file mode 100644 index 00000000..4c5c5ae5 --- /dev/null +++ b/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeContent.tsx @@ -0,0 +1,99 @@ +import { useMemo } from 'react'; + +import { LineChart } from '@/components/shared'; +import { PEAK_TIME } from '@/constants/sales'; +import { DAY_OF_WEEK_LIST } from '@/constants/shared'; +import type { GetDetailPeakTimeResponseDto } from '@/types/sales'; +import { + createPeakTimeSeries, + getSalesPatternPeaktimeMessage, +} from '@/utils/sales'; +import { cn } from '@/utils/shared'; + +import { PeakTimeChartCaption } from './PeakTimeChartCaption'; + +interface PeakTimeContentProps { + peakTimeData?: GetDetailPeakTimeResponseDto; + className?: string; +} + +export const PeakTimeContent = ({ + peakTimeData = PEAK_TIME.EXAMPLE_DATA, + className, +}: PeakTimeContentProps) => { + const weekday = DAY_OF_WEEK_LIST[new Date().getDay()]; + + const { + todayItems, + week4Items, + todayPeak, + comparisonPeak, + beforeComparisonPeak, + } = peakTimeData; + + const peakTimeBriefingMessage = getSalesPatternPeaktimeMessage({ + todayPeak, + comparisonPeak, + beforeComparisonPeak, + }); + + const primarySeries = useMemo(() => { + return { + ...createPeakTimeSeries(todayItems, 'var(--color-brand-main)'), + }; + }, [todayItems]); + + const secondarySeries = useMemo(() => { + return { + ...createPeakTimeSeries(week4Items, 'var(--color-grey-400)'), + }; + }, [week4Items]); + + return ( +
+
+ + +
+
+ +
+

+ {peakTimeBriefingMessage.map( + ({ text, isHighlight, highlightColor }, index) => { + return ( + + {text} + + ); + }, + )} +

+
+ ); +}; diff --git a/frontend/src/components/sales/dashboard-sales-pattern/index.ts b/frontend/src/components/sales/dashboard-sales-pattern/index.ts new file mode 100644 index 00000000..e69de29b From fca5483d9c5395193725dd34c8a41fdd821f6442 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 18:51:50 +0900 Subject: [PATCH 66/96] =?UTF-8?q?refactor:=20sales=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20util=20=ED=95=A8=EC=88=98=20=EC=84=9C=EB=B8=8C=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EC=84=B8=EB=B6=84=ED=99=94=20?= =?UTF-8?q?=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../getSalesCurrentComparisonMessage.ts | 2 +- frontend/src/utils/sales/dashboard-current-sales/index.ts | 1 + .../getSalesIncomeStructureComparisionMessage.ts | 2 +- frontend/src/utils/sales/dashboard-sales-income/index.ts | 1 + .../createPeakTimeSeries.ts | 0 .../getSalesPatternPeaktimeMessage.ts | 2 +- frontend/src/utils/sales/dashboard-sales-pattern/index.ts | 2 ++ frontend/src/utils/sales/dashboard/index.ts | 5 +---- frontend/src/utils/sales/index.ts | 6 +++--- 9 files changed, 11 insertions(+), 10 deletions(-) rename frontend/src/utils/sales/{dashboard => dashboard-current-sales}/getSalesCurrentComparisonMessage.ts (97%) create mode 100644 frontend/src/utils/sales/dashboard-current-sales/index.ts rename frontend/src/utils/sales/{dashboard => dashboard-sales-income}/getSalesIncomeStructureComparisionMessage.ts (94%) create mode 100644 frontend/src/utils/sales/dashboard-sales-income/index.ts rename frontend/src/utils/sales/{dashboard => dashboard-sales-pattern}/createPeakTimeSeries.ts (100%) rename frontend/src/utils/sales/{dashboard => dashboard-sales-pattern}/getSalesPatternPeaktimeMessage.ts (92%) create mode 100644 frontend/src/utils/sales/dashboard-sales-pattern/index.ts diff --git a/frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts b/frontend/src/utils/sales/dashboard-current-sales/getSalesCurrentComparisonMessage.ts similarity index 97% rename from frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts rename to frontend/src/utils/sales/dashboard-current-sales/getSalesCurrentComparisonMessage.ts index f588fed4..5579c97e 100644 --- a/frontend/src/utils/sales/dashboard/getSalesCurrentComparisonMessage.ts +++ b/frontend/src/utils/sales/dashboard-current-sales/getSalesCurrentComparisonMessage.ts @@ -2,7 +2,7 @@ import { METRIC_TREND, type MetricTrend } from '@/constants/dashboard'; import { DAY_OF_WEEK_LIST, PERIOD_PRESETS } from '@/constants/shared'; import { assertNever, formatNumber, type ValueOf } from '@/utils/shared'; -import { createMessageToken, type MessageToken } from './createMessageToken'; +import { createMessageToken, type MessageToken } from '../dashboard'; interface GetSalesCurrentComparisonMessageArgs { periodType: ValueOf; diff --git a/frontend/src/utils/sales/dashboard-current-sales/index.ts b/frontend/src/utils/sales/dashboard-current-sales/index.ts new file mode 100644 index 00000000..d8d3a8ab --- /dev/null +++ b/frontend/src/utils/sales/dashboard-current-sales/index.ts @@ -0,0 +1 @@ +export { getSalesCurrentComparisonMessage } from './getSalesCurrentComparisonMessage'; diff --git a/frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts b/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts similarity index 94% rename from frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts rename to frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts index b21ab7b4..e8150bfb 100644 --- a/frontend/src/utils/sales/dashboard/getSalesIncomeStructureComparisionMessage.ts +++ b/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts @@ -2,7 +2,7 @@ import { PERIOD_PRESETS } from '@/constants/shared'; import type { SalesIncomeStructureInsight } from '@/types/sales/salesIncomeStructureInsight'; import { formatNumber, type ValueOf } from '@/utils/shared'; -import { createMessageToken, type MessageToken } from './createMessageToken'; +import { createMessageToken, type MessageToken } from '../dashboard'; const DELTA_SHARE_THRESHOLD = 3; diff --git a/frontend/src/utils/sales/dashboard-sales-income/index.ts b/frontend/src/utils/sales/dashboard-sales-income/index.ts new file mode 100644 index 00000000..532c3670 --- /dev/null +++ b/frontend/src/utils/sales/dashboard-sales-income/index.ts @@ -0,0 +1 @@ +export { getSalesIncomeStructureComparisionMessage } from './getSalesIncomeStructureComparisionMessage'; diff --git a/frontend/src/utils/sales/dashboard/createPeakTimeSeries.ts b/frontend/src/utils/sales/dashboard-sales-pattern/createPeakTimeSeries.ts similarity index 100% rename from frontend/src/utils/sales/dashboard/createPeakTimeSeries.ts rename to frontend/src/utils/sales/dashboard-sales-pattern/createPeakTimeSeries.ts diff --git a/frontend/src/utils/sales/dashboard/getSalesPatternPeaktimeMessage.ts b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeaktimeMessage.ts similarity index 92% rename from frontend/src/utils/sales/dashboard/getSalesPatternPeaktimeMessage.ts rename to frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeaktimeMessage.ts index 46e1ecf0..12367be0 100644 --- a/frontend/src/utils/sales/dashboard/getSalesPatternPeaktimeMessage.ts +++ b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeaktimeMessage.ts @@ -1,6 +1,6 @@ import type { GetDashboardPeakTimeResponseDto } from '@/types/sales'; -import { createMessageToken, type MessageToken } from './createMessageToken'; +import { createMessageToken, type MessageToken } from '../dashboard'; interface GetSalesPatternPeaktimeMessageArgs { todayPeak: GetDashboardPeakTimeResponseDto['todayPeak']; diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/index.ts b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts new file mode 100644 index 00000000..03171eec --- /dev/null +++ b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts @@ -0,0 +1,2 @@ +export { getSalesPatternPeaktimeMessage } from './getSalesPatternPeaktimeMessage'; +export { createPeakTimeSeries } from './createPeakTimeSeries'; diff --git a/frontend/src/utils/sales/dashboard/index.ts b/frontend/src/utils/sales/dashboard/index.ts index 490b0937..b61c8769 100644 --- a/frontend/src/utils/sales/dashboard/index.ts +++ b/frontend/src/utils/sales/dashboard/index.ts @@ -1,4 +1 @@ -export { getSalesPatternPeaktimeMessage } from './getSalesPatternPeaktimeMessage'; -export { getSalesCurrentComparisonMessage } from './getSalesCurrentComparisonMessage'; -export { getSalesIncomeStructureComparisionMessage } from './getSalesIncomeStructureComparisionMessage'; -export { createPeakTimeSeries } from './createPeakTimeSeries'; +export { createMessageToken, type MessageToken } from './createMessageToken'; diff --git a/frontend/src/utils/sales/index.ts b/frontend/src/utils/sales/index.ts index a2d754ad..8f8e92a0 100644 --- a/frontend/src/utils/sales/index.ts +++ b/frontend/src/utils/sales/index.ts @@ -1,7 +1,7 @@ export { getPeriodComparisonMessage } from './sales-overview'; export { getSalesPatternPeaktimeMessage, - getSalesCurrentComparisonMessage, - getSalesIncomeStructureComparisionMessage, createPeakTimeSeries, -} from './dashboard'; +} from './dashboard-sales-pattern'; +export { getSalesCurrentComparisonMessage } from './dashboard-current-sales'; +export { getSalesIncomeStructureComparisionMessage } from './dashboard-sales-income'; From cf3879e7a098b41338337770a601d746f6ddf41a Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 18:52:15 +0900 Subject: [PATCH 67/96] =?UTF-8?q?feat:=20=EC=9A=94=EC=9D=BC=EB=B3=84=20?= =?UTF-8?q?=EB=A7=A4=EC=B6=9C=20=ED=8C=A8=ED=84=B4=20dto=20=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/types/sales/dto/getSalesByDayDto.ts | 17 +++++++++++++++++ frontend/src/types/sales/dto/index.ts | 4 ++++ frontend/src/types/sales/index.ts | 2 ++ 3 files changed, 23 insertions(+) create mode 100644 frontend/src/types/sales/dto/getSalesByDayDto.ts diff --git a/frontend/src/types/sales/dto/getSalesByDayDto.ts b/frontend/src/types/sales/dto/getSalesByDayDto.ts new file mode 100644 index 00000000..0a1b836d --- /dev/null +++ b/frontend/src/types/sales/dto/getSalesByDayDto.ts @@ -0,0 +1,17 @@ +interface SalesByDaySummary { + topDay: string; + isSignificant: boolean; +} + +interface SalesByDayItem { + day: string; + avgNetAmount: number; + orderCount: number; +} + +export interface GetDetailSalesByDayResponseDto extends SalesByDaySummary { + items: SalesByDayItem[]; +} + +export interface GetDashboardSalesByDayResponseDto + extends SalesByDaySummary, SalesByDayItem {} diff --git a/frontend/src/types/sales/dto/index.ts b/frontend/src/types/sales/dto/index.ts index 834bc63f..66acab03 100644 --- a/frontend/src/types/sales/dto/index.ts +++ b/frontend/src/types/sales/dto/index.ts @@ -8,3 +8,7 @@ export type { GetDetailPeakTimeResponseDto, GetDashboardPeakTimeResponseDto, } from './getPeakTimeDto'; +export type { + GetDetailSalesByDayResponseDto, + GetDashboardSalesByDayResponseDto, +} from './getSalesByDayDto'; diff --git a/frontend/src/types/sales/index.ts b/frontend/src/types/sales/index.ts index 60c08feb..28d04ffe 100644 --- a/frontend/src/types/sales/index.ts +++ b/frontend/src/types/sales/index.ts @@ -8,5 +8,7 @@ export type { GetIncomStructureByPaymentMethodResponseDto, GetDetailPeakTimeResponseDto, GetDashboardPeakTimeResponseDto, + GetDetailSalesByDayResponseDto, + GetDashboardSalesByDayResponseDto, } from './dto'; export type { SalesIncomeStructureInsight } from './salesIncomeStructureInsight'; From 95bb433b256f828c682399ea9366ff8876adfb1a Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 18:59:57 +0900 Subject: [PATCH 68/96] =?UTF-8?q?refactor:=20sales=20type=20=EC=84=9C?= =?UTF-8?q?=EB=B8=8C=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EC=84=B8=EB=B6=84?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../types/sales/dashboard-sales-income/index.ts | 4 ++++ .../salesIncomeStructureInsight.ts | 0 .../sales/dashboard-sales-pattern/peakTime.ts | 15 +++++++++++++++ .../dto/getIncomStructureByOrderMethodDto.ts | 2 +- .../dto/getIncomStructureByPaymentMethodDto.ts | 2 +- .../sales/dto/getIncomStructureBySalesTypeDto.ts | 2 +- frontend/src/types/sales/dto/getPeakTimeDto.ts | 16 +--------------- .../getSalesIncomeStructureComparisionMessage.ts | 2 +- .../createPeakTimeSeries.ts | 6 ++---- 9 files changed, 26 insertions(+), 23 deletions(-) create mode 100644 frontend/src/types/sales/dashboard-sales-income/index.ts rename frontend/src/types/sales/{ => dashboard-sales-income}/salesIncomeStructureInsight.ts (100%) create mode 100644 frontend/src/types/sales/dashboard-sales-pattern/peakTime.ts diff --git a/frontend/src/types/sales/dashboard-sales-income/index.ts b/frontend/src/types/sales/dashboard-sales-income/index.ts new file mode 100644 index 00000000..db536c49 --- /dev/null +++ b/frontend/src/types/sales/dashboard-sales-income/index.ts @@ -0,0 +1,4 @@ +export type { + SalesIncomeStructureInsight, + SalesIncomeStructureTopType, +} from './salesIncomeStructureInsight'; diff --git a/frontend/src/types/sales/salesIncomeStructureInsight.ts b/frontend/src/types/sales/dashboard-sales-income/salesIncomeStructureInsight.ts similarity index 100% rename from frontend/src/types/sales/salesIncomeStructureInsight.ts rename to frontend/src/types/sales/dashboard-sales-income/salesIncomeStructureInsight.ts diff --git a/frontend/src/types/sales/dashboard-sales-pattern/peakTime.ts b/frontend/src/types/sales/dashboard-sales-pattern/peakTime.ts new file mode 100644 index 00000000..3ed5a8fb --- /dev/null +++ b/frontend/src/types/sales/dashboard-sales-pattern/peakTime.ts @@ -0,0 +1,15 @@ +export interface PeakTimeItem { + timeSlot2H: number; + orderCount: number | null; + netAmount: number | null; +} + +type ShiftDirection = 'EARLY' | 'LATE' | 'SAME' | 'UNKNOWN'; + +export interface PeakTimeSummary { + todayPeak: number; // 오늘 피크 시간 + comparisonPeak: number; // 비교 시간 피크 시간 + diff: number; // 비교 시간 피크 시간 차이 + shiftDirection: ShiftDirection; // 피크 시간 방향성 + beforeComparisonPeak: boolean; // 비교 시간 피크 시간 이전 +} diff --git a/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts b/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts index 0411dacd..cc549417 100644 --- a/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts +++ b/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts @@ -1,7 +1,7 @@ import type { SalesIncomeStructureInsight, SalesIncomeStructureTopType, -} from '../salesIncomeStructureInsight'; +} from '../dashboard-sales-income'; interface OrderMethodItem { orderChannel: Extract< diff --git a/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts b/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts index 461a76ea..985cf351 100644 --- a/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts +++ b/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts @@ -1,7 +1,7 @@ import type { SalesIncomeStructureInsight, SalesIncomeStructureTopType, -} from '../salesIncomeStructureInsight'; +} from '../dashboard-sales-income'; interface PaymentMethodItem { payMethod: Extract< diff --git a/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts b/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts index 3a319de4..d2a49734 100644 --- a/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts +++ b/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts @@ -1,7 +1,7 @@ import type { SalesIncomeStructureInsight, SalesIncomeStructureTopType, -} from '../salesIncomeStructureInsight'; +} from '../dashboard-sales-income'; interface SalesTypeItem { salesType: Extract; diff --git a/frontend/src/types/sales/dto/getPeakTimeDto.ts b/frontend/src/types/sales/dto/getPeakTimeDto.ts index 247b3036..5f19e2b8 100644 --- a/frontend/src/types/sales/dto/getPeakTimeDto.ts +++ b/frontend/src/types/sales/dto/getPeakTimeDto.ts @@ -1,18 +1,4 @@ -interface PeakTimeItem { - timeSlot2H: number; - orderCount: number | null; - netAmount: number | null; -} - -interface PeakTimeSummary { - todayPeak: number; // 오늘 피크 시간 - comparisonPeak: number; // 비교 시간 피크 시간 - diff: number; // 비교 시간 피크 시간 차이 - shiftDirection: ShiftDirection; // 피크 시간 방향성 - beforeComparisonPeak: boolean; // 비교 시간 피크 시간 이전 -} - -type ShiftDirection = 'EARLY' | 'LATE' | 'SAME' | 'UNKNOWN'; +import type { PeakTimeItem, PeakTimeSummary } from '../dashboard-sales-pattern'; export interface GetDetailPeakTimeResponseDto extends PeakTimeSummary { todayItems: PeakTimeItem[]; diff --git a/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts b/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts index e8150bfb..c3d7d97d 100644 --- a/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts +++ b/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts @@ -1,5 +1,5 @@ import { PERIOD_PRESETS } from '@/constants/shared'; -import type { SalesIncomeStructureInsight } from '@/types/sales/salesIncomeStructureInsight'; +import type { SalesIncomeStructureInsight } from '@/types/sales/dashboard-sales-income/salesIncomeStructureInsight'; import { formatNumber, type ValueOf } from '@/utils/shared'; import { createMessageToken, type MessageToken } from '../dashboard'; diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/createPeakTimeSeries.ts b/frontend/src/utils/sales/dashboard-sales-pattern/createPeakTimeSeries.ts index 5a967832..ba6dba5d 100644 --- a/frontend/src/utils/sales/dashboard-sales-pattern/createPeakTimeSeries.ts +++ b/frontend/src/utils/sales/dashboard-sales-pattern/createPeakTimeSeries.ts @@ -1,9 +1,7 @@ -import type { GetDetailPeakTimeResponseDto } from '@/types/sales'; +import type { PeakTimeItem } from '@/types/sales'; export const createPeakTimeSeries = ( - items: - | GetDetailPeakTimeResponseDto['todayItems'] - | GetDetailPeakTimeResponseDto['week4Items'], + items: PeakTimeItem[], color: string, mainXUnit: string = '', mainYUnit: string = '', From f7550401099fa914c1fb017db5e769677aceadb4 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 19:02:41 +0900 Subject: [PATCH 69/96] =?UTF-8?q?feat:=20=EC=9A=94=EC=9D=BC=EB=B3=84=20?= =?UTF-8?q?=EB=A7=A4=EC=B6=9C=20=EA=B4=80=EB=A0=A8=20dto=20=EB=B0=8F=20typ?= =?UTF-8?q?e=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../types/sales/dashboard-sales-pattern/index.ts | 2 ++ .../sales/dashboard-sales-pattern/salesByDay.ts | 10 ++++++++++ frontend/src/types/sales/dto/getSalesByDayDto.ts | 14 ++++---------- 3 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 frontend/src/types/sales/dashboard-sales-pattern/index.ts create mode 100644 frontend/src/types/sales/dashboard-sales-pattern/salesByDay.ts diff --git a/frontend/src/types/sales/dashboard-sales-pattern/index.ts b/frontend/src/types/sales/dashboard-sales-pattern/index.ts new file mode 100644 index 00000000..890ad2b9 --- /dev/null +++ b/frontend/src/types/sales/dashboard-sales-pattern/index.ts @@ -0,0 +1,2 @@ +export type { PeakTimeItem, PeakTimeSummary } from './peakTime'; +export type { SalesByDaySummary, SalesByDayItem } from './salesByDay'; diff --git a/frontend/src/types/sales/dashboard-sales-pattern/salesByDay.ts b/frontend/src/types/sales/dashboard-sales-pattern/salesByDay.ts new file mode 100644 index 00000000..fcd3a377 --- /dev/null +++ b/frontend/src/types/sales/dashboard-sales-pattern/salesByDay.ts @@ -0,0 +1,10 @@ +export interface SalesByDaySummary { + topDay: string; + isSignificant: boolean; +} + +export interface SalesByDayItem { + day: string; + avgNetAmount: number; + orderCount: number; +} diff --git a/frontend/src/types/sales/dto/getSalesByDayDto.ts b/frontend/src/types/sales/dto/getSalesByDayDto.ts index 0a1b836d..5e8cba6f 100644 --- a/frontend/src/types/sales/dto/getSalesByDayDto.ts +++ b/frontend/src/types/sales/dto/getSalesByDayDto.ts @@ -1,13 +1,7 @@ -interface SalesByDaySummary { - topDay: string; - isSignificant: boolean; -} - -interface SalesByDayItem { - day: string; - avgNetAmount: number; - orderCount: number; -} +import type { + SalesByDayItem, + SalesByDaySummary, +} from '../dashboard-sales-pattern'; export interface GetDetailSalesByDayResponseDto extends SalesByDaySummary { items: SalesByDayItem[]; From 04135fc905babb9232bef08e3328aeef3b9a2473 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 19:03:05 +0900 Subject: [PATCH 70/96] =?UTF-8?q?feat:=20=EC=9A=94=EC=9D=BC=EB=B3=84=20?= =?UTF-8?q?=EB=A7=A4=EC=B6=9C=20=EA=B4=80=EB=A0=A8=20=EB=B8=8C=EB=A6=AC?= =?UTF-8?q?=ED=95=91=20=EB=A9=94=EC=84=B8=EC=A7=80=20=EB=B0=98=ED=99=98=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../getSalesPatternByDayMessage.ts | 28 +++++++++++++++++++ .../sales/dashboard-sales-pattern/index.ts | 1 + frontend/src/utils/sales/index.ts | 1 + 3 files changed, 30 insertions(+) create mode 100644 frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternByDayMessage.ts diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternByDayMessage.ts b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternByDayMessage.ts new file mode 100644 index 00000000..eed95495 --- /dev/null +++ b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternByDayMessage.ts @@ -0,0 +1,28 @@ +import type { SalesByDaySummary } from '@/types/sales'; + +import { + createMessageToken, + type MessageToken, +} from '../dashboard/createMessageToken'; + +interface GetSalesPatternByDayMessageArgs { + topDay: SalesByDaySummary['topDay']; + isSignificant: boolean; +} + +export const getSalesPatternByDayMessage = ({ + topDay, + isSignificant, +}: GetSalesPatternByDayMessageArgs): MessageToken[] => { + if (isSignificant) { + return [ + createMessageToken(`${topDay}요일`, true, 'primary'), + createMessageToken('이 다른 요일보다 확실히 매출이 높아요.'), + ]; + } + + return [ + createMessageToken('최근 4주 기준 '), + createMessageToken(`${topDay}요일`, true, 'primary'), + ]; +}; diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/index.ts b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts index 03171eec..e618cbad 100644 --- a/frontend/src/utils/sales/dashboard-sales-pattern/index.ts +++ b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts @@ -1,2 +1,3 @@ export { getSalesPatternPeaktimeMessage } from './getSalesPatternPeaktimeMessage'; export { createPeakTimeSeries } from './createPeakTimeSeries'; +export { getSalesPatternByDayMessage } from './getSalesPatternByDayMessage'; diff --git a/frontend/src/utils/sales/index.ts b/frontend/src/utils/sales/index.ts index 8f8e92a0..cac6e3bf 100644 --- a/frontend/src/utils/sales/index.ts +++ b/frontend/src/utils/sales/index.ts @@ -2,6 +2,7 @@ export { getPeriodComparisonMessage } from './sales-overview'; export { getSalesPatternPeaktimeMessage, createPeakTimeSeries, + getSalesPatternByDayMessage, } from './dashboard-sales-pattern'; export { getSalesCurrentComparisonMessage } from './dashboard-current-sales'; export { getSalesIncomeStructureComparisionMessage } from './dashboard-sales-income'; From fa1fa4486c5b372bb4cdcbf132628c41a6f59e3d Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 19:12:25 +0900 Subject: [PATCH 71/96] =?UTF-8?q?chore:=20font-bold=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/dashboard/briefingMessageHighlightColor.ts | 2 +- frontend/src/constants/sales/dashboard/index.ts | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/frontend/src/constants/sales/dashboard/briefingMessageHighlightColor.ts b/frontend/src/constants/sales/dashboard/briefingMessageHighlightColor.ts index 06425d41..17f986a3 100644 --- a/frontend/src/constants/sales/dashboard/briefingMessageHighlightColor.ts +++ b/frontend/src/constants/sales/dashboard/briefingMessageHighlightColor.ts @@ -1,7 +1,7 @@ export const BRIEFING_MESSAGE_HIGHLIGHT_COLOR = { primary: 'text-brand-main font-bold', negative: 'text-others-negative font-bold', - default: 'text-grey-500', + default: 'text-grey-500 font-bold', } as const; export type BriefingMessageHighlightColor = diff --git a/frontend/src/constants/sales/dashboard/index.ts b/frontend/src/constants/sales/dashboard/index.ts index 7c7e42c6..6d4f7f2c 100644 --- a/frontend/src/constants/sales/dashboard/index.ts +++ b/frontend/src/constants/sales/dashboard/index.ts @@ -2,9 +2,3 @@ export { BRIEFING_MESSAGE_HIGHLIGHT_COLOR, type BriefingMessageHighlightColor, } from './briefingMessageHighlightColor'; -export { AVERAGE_PRICE } from './averagePrice'; -export { ORDER_COUNT } from './orderCount'; -export { REAL_SALES } from './realSales'; -export { ORDER_METHOD } from './orderMethod'; -export { PAYMENT_METHOD } from './paymentMethod'; -export { SALES_TYPE } from './salesType'; From 6a70fb03a7572fe631bd4bf682493593d1b92acf Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 19:12:49 +0900 Subject: [PATCH 72/96] =?UTF-8?q?chore:=20=EB=88=84=EB=9D=BD=EB=90=9C=20?= =?UTF-8?q?=EB=B8=8C=EB=A6=AC=ED=95=91=20=EB=AC=B8=EA=B5=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard-sales-pattern/getSalesPatternByDayMessage.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternByDayMessage.ts b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternByDayMessage.ts index eed95495..7c0f65e8 100644 --- a/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternByDayMessage.ts +++ b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternByDayMessage.ts @@ -23,6 +23,7 @@ export const getSalesPatternByDayMessage = ({ return [ createMessageToken('최근 4주 기준 '), - createMessageToken(`${topDay}요일`, true, 'primary'), + createMessageToken(`${topDay}요일 매출`, true, 'primary'), + createMessageToken('이 가장 좋아요.'), ]; }; From fa327bf60cfdeba1e219340cbdb7817cb600af1f Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 19:13:30 +0900 Subject: [PATCH 73/96] =?UTF-8?q?feat:=20=EA=B0=81=20=EB=A7=A4=EC=B6=9C?= =?UTF-8?q?=EB=B6=84=EC=84=9D=20=EB=8C=80=EC=8B=9C=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=ED=8E=B8=EC=A7=91=20=EC=B9=B4=EB=93=9C=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard-edit/CardEditViewCard.tsx | 63 ++++++++++++++----- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx b/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx index 979d678a..2fc2636d 100644 --- a/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx +++ b/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx @@ -1,14 +1,59 @@ +import { + AveragePriceContent, + OrderCountContent, + OrderMethodContent, + RealSalesContent, + SalesTypeContent, +} from '@/components/sales'; +import { PaymentMethodContent } from '@/components/sales/dashboard-sales-income/PaymentMethodContent'; +import { PeakTimeContent } from '@/components/sales/dashboard-sales-pattern/PeakTimeContent'; +import { SalesByDayContent } from '@/components/sales/dashboard-sales-pattern/SalesByDayContent'; import { EditCardWrapper } from '@/components/shared'; import { DASHBOARD_METRIC_CARDS, type MetricCardCode, } from '@/constants/dashboard'; -import { RealSalesCardContent } from '../sales/RealSalesCardContent'; +const EditCardContent = ({ code }: { code: MetricCardCode }) => { + switch (code) { + case 'SLS_01_01': + case 'SLS_01_02': + case 'SLS_01_03': + return ; + case 'SLS_02_01': + case 'SLS_02_02': + case 'SLS_02_03': + return ; + case 'SLS_03_01': + case 'SLS_03_02': + case 'SLS_03_03': + return ; + case 'SLS_06_01': + case 'SLS_06_02': + case 'SLS_06_03': + return ; + case 'SLS_07_01': + case 'SLS_07_02': + case 'SLS_07_03': + return ; + case 'SLS_08_01': + case 'SLS_08_02': + case 'SLS_08_03': + return ; + + case 'SLS_13_01': + return ; + case 'SLS_14_06': + return ; + default: + return <>; + } +}; interface CardEditViewCardProps { cardCode: MetricCardCode; } + export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { const card = DASHBOARD_METRIC_CARDS[cardCode]; @@ -16,7 +61,7 @@ export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { return null; // 카드 정보가 없는 경우 렌더링하지 않음 } - const { code, label, type, period, sizeX, sizeY } = card; + const { code, period, sizeX } = card; return (
  • @@ -25,19 +70,9 @@ export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { period={period as string} className="min-w-full" sizeX={sizeX} - sizeY={sizeY} - innerClassName="items-start m-0!" + innerClassName="items-start" > - {label} -
    - {code} -
    - {type} -
    - {sizeX} x {sizeY} - {(code === 'SLS_01_01' || - code === 'SLS_01_02' || - code === 'SLS_01_03') && } +
  • ); From 15d3421ba36e15169c9af2bd15d3a6cb17d08c53 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 19:13:46 +0900 Subject: [PATCH 74/96] =?UTF-8?q?feat:=20edit=20card=20wrapper=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EC=A6=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared/edit-card-wrapper/EditCardWrapper.tsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx b/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx index eaf5d118..7863c3fb 100644 --- a/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx +++ b/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx @@ -19,7 +19,6 @@ interface EditCardWrapperProps { innerClassName?: string; // 자식 컴포넌트 클래스명 period: string; // 오늘, 이번주, 이번달 등 문구 sizeX?: number; // 가로 크기 - sizeY?: number; // 세로 크기 onClickDeleteButton?: () => void; // 대시보드에서 삭제하는 버튼 클릭 헨들러 onClickAddButton?: () => void; // 대시보드에 추가하는 버튼 클릭 핸들러 } @@ -32,7 +31,6 @@ export const EditCardWrapper = ({ className, innerClassName, sizeX = 1, - sizeY = 1, period = '기간없음', onClickDeleteButton, onClickAddButton, @@ -52,8 +50,7 @@ export const EditCardWrapper = ({ Math.max(EDIT_CARD_WRAPPER.MIN_WIDTH, computedCardWidth) * sizeX + GRID_GAP * (sizeX - 1), // 최소 너비 220px, gap 20px height: - Math.max(EDIT_CARD_WRAPPER.MIN_HEIGHT, computedCardHeight) * sizeY + - GRID_GAP * (sizeY - 1), // 최소 높이 147px, gap 20px + Math.max(EDIT_CARD_WRAPPER.MIN_HEIGHT, computedCardHeight) + GRID_GAP, // 최소 높이 147px, }} className={cn( 'bg-special-card-bg rounded-400 border-grey-300 relative flex flex-col overflow-hidden border p-3', @@ -78,10 +75,7 @@ export const EditCardWrapper = ({
    Date: Sun, 15 Feb 2026 19:14:11 +0900 Subject: [PATCH 75/96] =?UTF-8?q?feat:=20=EC=9A=94=EC=9D=BC=EB=B3=84=20?= =?UTF-8?q?=EB=A7=A4=EC=B6=9C=20=ED=8C=A8=ED=84=B4=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=9E=84=EC=8B=9C=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SalesByDayContent.tsx | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx diff --git a/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx b/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx new file mode 100644 index 00000000..b56e805d --- /dev/null +++ b/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx @@ -0,0 +1,46 @@ +import type { SalesByDayItem, SalesByDaySummary } from '@/types/sales'; +import { getSalesPatternByDayMessage } from '@/utils/sales'; +import { cn, type Nullable } from '@/utils/shared'; + +interface SalesByDayContentProps extends Nullable { + salesByDayItems?: SalesByDayItem[]; + className?: string; +} + +export const SalesByDayContent = ({ + // salesByDayItems = [], + topDay = '월', + isSignificant = false, + className, +}: SalesByDayContentProps) => { + const salesByDayBriefingMessage = getSalesPatternByDayMessage({ + topDay, + isSignificant, + }); + return ( +
    +

    + {salesByDayBriefingMessage.map( + ({ text, isHighlight, highlightColor }, index) => { + return ( + + {text} + + ); + }, + )} +

    +
    + ); +}; From 256c870a9c4dd8e6ce2eb3f535a7abb6124db256 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 19:14:23 +0900 Subject: [PATCH 76/96] =?UTF-8?q?feat:=20=EB=B0=B0=EB=9F=B4=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/shared/index.ts | 1 + frontend/src/types/sales/index.ts | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/shared/index.ts b/frontend/src/components/shared/index.ts index 474540a9..2ae1715e 100644 --- a/frontend/src/components/shared/index.ts +++ b/frontend/src/components/shared/index.ts @@ -17,3 +17,4 @@ export { MainLayout } from './main-layout'; export { PeriodTag, EditCardWrapper } from './edit-card-wrapper'; export { ButtonGroup } from './button-group'; export { PaginationBar } from './pagenation'; +export { LineChart } from './line-chart'; diff --git a/frontend/src/types/sales/index.ts b/frontend/src/types/sales/index.ts index 28d04ffe..6eacb189 100644 --- a/frontend/src/types/sales/index.ts +++ b/frontend/src/types/sales/index.ts @@ -11,4 +11,9 @@ export type { GetDetailSalesByDayResponseDto, GetDashboardSalesByDayResponseDto, } from './dto'; -export type { SalesIncomeStructureInsight } from './salesIncomeStructureInsight'; +export type { SalesIncomeStructureInsight } from './dashboard-sales-income'; +export type { PeakTimeItem, PeakTimeSummary } from './dashboard-sales-pattern'; +export type { + SalesByDaySummary, + SalesByDayItem, +} from './dashboard-sales-pattern'; From a977350a51e30d625632c02e7d1656a690276f03 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 19:14:40 +0900 Subject: [PATCH 77/96] =?UTF-8?q?chore:=20msw=20auth=20refresh=20=EB=B9=84?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/mocks/auth/authHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/mocks/auth/authHandler.ts b/frontend/src/mocks/auth/authHandler.ts index 42e9ff05..02ce2753 100644 --- a/frontend/src/mocks/auth/authHandler.ts +++ b/frontend/src/mocks/auth/authHandler.ts @@ -41,7 +41,7 @@ const getHandler = [ const postHandler = [ mswHttp.post('/auth/refresh', () => { - return HttpResponse.json>( + HttpResponse.json>( { success: true, message: 'Success', From c5a1c9f3a8d7c7f8691bb4b962ab4260608f1158 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 20:02:16 +0900 Subject: [PATCH 78/96] =?UTF-8?q?feat:=20bar=20chart=20=EC=83=89=EC=83=81?= =?UTF-8?q?=20=EA=B0=95=EC=A1=B0=20=EB=A7=89=EB=8C=80=EB=A5=BC=20=EC=A7=80?= =?UTF-8?q?=EC=A0=95=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared/bar-chart/BarChart.stories.tsx | 13 +++++++++++-- .../src/components/shared/bar-chart/BarChart.tsx | 8 ++++---- .../src/components/shared/bar-chart/BarSeries.tsx | 6 +++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/shared/bar-chart/BarChart.stories.tsx b/frontend/src/components/shared/bar-chart/BarChart.stories.tsx index 70f79413..4c7ef032 100644 --- a/frontend/src/components/shared/bar-chart/BarChart.stories.tsx +++ b/frontend/src/components/shared/bar-chart/BarChart.stories.tsx @@ -77,7 +77,7 @@ export const Default: Story = { chartTitle: '일별 매출 꺾은선 차트', chartDescription: '일별 매출 꺾은선 차트 설명', xAxisType: 'right-arrow', - activeLastData: true, + activeDataIndex: 3, barColorChangeOnHover: true, }, render: (args) => ( @@ -108,7 +108,7 @@ export const StackBar: Story = { chartTitle: '일별 매출 꺾은선 차트', chartDescription: '일별 매출 꺾은선 차트 설명', xAxisType: 'right-arrow', - activeLastData: true, + activeDataIndex: 3, barColorChangeOnHover: true, }, render: (args) => ( @@ -130,6 +130,10 @@ const RealtimeBarChart = (args: Story['args']) => { args.barChartSeries as BarChartSeries, ); + const [activeDataIndex, setActiveDataIndex] = useState( + args.barChartSeries.data.mainX.length - 1, + ); + const handleUpdateCurrentBarChartSeries = () => { let currentIndex = barChartSeries.data.mainY.filter((datum) => datum.amount !== null) @@ -139,6 +143,8 @@ const RealtimeBarChart = (args: Story['args']) => { currentIndex = 0; } + setActiveDataIndex(currentIndex); + setBarChartSeries((prev) => { const newMainY = [...prev.data.mainY]; //const newSubY = [...prev.data.subY]; @@ -177,6 +183,8 @@ const RealtimeBarChart = (args: Story['args']) => { // return; // } + setActiveDataIndex(nextIndex); + setBarChartSeries((prev) => ({ ...prev, data: { @@ -216,6 +224,7 @@ const RealtimeBarChart = (args: Story['args']) => {
    diff --git a/frontend/src/components/shared/bar-chart/BarChart.tsx b/frontend/src/components/shared/bar-chart/BarChart.tsx index 171c1ad2..f11d7655 100644 --- a/frontend/src/components/shared/bar-chart/BarChart.tsx +++ b/frontend/src/components/shared/bar-chart/BarChart.tsx @@ -72,9 +72,9 @@ interface BarChartProps { */ hasBarLabel?: boolean; /** - * 가장 우측 막대 바 색상 강조할 것인지 여부 + * 현재 포커스된 데이터의 인덱스 */ - activeLastData?: boolean; + activeDataIndex?: number; /** * 바 호버 시 색상 변경할 건지 */ @@ -96,7 +96,7 @@ export const BarChart = ({ chartDescription, hasBarLabel = true, xAxisType, - activeLastData = true, + activeDataIndex, barColorChangeOnHover = true, }: BarChartProps) => { const { titleId, descId } = useBarChartId(); @@ -169,7 +169,7 @@ export const BarChart = ({ xCoordinate={xCoordinate} hasXAxis={hasXAxis} hasBarLabel={hasBarLabel} - activeLastData={activeLastData} + activeDataIndex={activeDataIndex} barColorChangeOnHover={barColorChangeOnHover} /> diff --git a/frontend/src/components/shared/bar-chart/BarSeries.tsx b/frontend/src/components/shared/bar-chart/BarSeries.tsx index ecc342de..c8b3a421 100644 --- a/frontend/src/components/shared/bar-chart/BarSeries.tsx +++ b/frontend/src/components/shared/bar-chart/BarSeries.tsx @@ -25,7 +25,7 @@ interface BarSeriesProps { hasXAxis?: boolean; //현재 barchart에서 x축 사용하고 있는지 tooltipContent?: (...args: string[]) => string; xCoordinate: Coordinate[]; - activeLastData?: boolean; // 가장 우측 막대 바 색상 강조할 것인지 여부. 스택 바에는 적용 안됨. + activeDataIndex?: number; // 현재 포커스된 데이터의 인덱스 barColorChangeOnHover?: boolean; // 바 호버 시 색상 변경할 건지 } @@ -41,7 +41,7 @@ export const BarSeries = ({ xCoordinate, tooltipContent, activeTooltip, - activeLastData = true, + activeDataIndex, barColorChangeOnHover, }: BarSeriesProps) => { const { XAXIS_Y_OFFSET, XAXIS_STROKE_WIDTH, BAR_RADIUS } = BAR_CHART; // X축이 있을 때 X축의 Y좌표 오프셋 값 @@ -153,7 +153,7 @@ export const BarSeries = ({ activeTooltip={activeTooltip} tooltipContentText={tooltipContentText} // activeLastData가 true이라면 마지막 막대를 강조 표시 - isActive={activeLastData && index === coordinate.length - 1} + isActive={activeDataIndex === index} barColorChangeOnHover={barColorChangeOnHover} /> )} From ffa0371aa32aedaa27053848eaacd3b81f88d828 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 20:02:36 +0900 Subject: [PATCH 79/96] =?UTF-8?q?refactor:=20=EC=B0=A8=ED=8A=B8=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20data=20type=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/types/shared/bar-chart/barChartDataType.ts | 10 ++-------- .../src/types/shared/{ => chart}/chartDataType.ts | 0 frontend/src/types/shared/chart/index.ts | 1 + frontend/src/types/shared/index.ts | 3 +-- frontend/src/types/shared/line-chart/index.ts | 6 +----- .../types/shared/line-chart/lineChartDataType.ts | 13 +++++-------- 6 files changed, 10 insertions(+), 23 deletions(-) rename frontend/src/types/shared/{ => chart}/chartDataType.ts (100%) create mode 100644 frontend/src/types/shared/chart/index.ts diff --git a/frontend/src/types/shared/bar-chart/barChartDataType.ts b/frontend/src/types/shared/bar-chart/barChartDataType.ts index f141f520..7d2ab5f9 100644 --- a/frontend/src/types/shared/bar-chart/barChartDataType.ts +++ b/frontend/src/types/shared/bar-chart/barChartDataType.ts @@ -1,12 +1,6 @@ -import type { LineChartDatum } from '../line-chart'; +import type { ChartDatum } from '../chart'; -// LineChartDatum과 동일한 구조를 가짐 -// export interface LineChartDatum { -// amount: number | string | null; -// unit: string; -// } - -export type BarChartDatum = LineChartDatum; +export type BarChartDatum = ChartDatum; export interface BarChartData { mainX: BarChartDatum[]; // 시간 목록 diff --git a/frontend/src/types/shared/chartDataType.ts b/frontend/src/types/shared/chart/chartDataType.ts similarity index 100% rename from frontend/src/types/shared/chartDataType.ts rename to frontend/src/types/shared/chart/chartDataType.ts diff --git a/frontend/src/types/shared/chart/index.ts b/frontend/src/types/shared/chart/index.ts new file mode 100644 index 00000000..24fd610b --- /dev/null +++ b/frontend/src/types/shared/chart/index.ts @@ -0,0 +1 @@ +export type { ChartData, ChartSeries, ChartDatum } from './chartDataType'; diff --git a/frontend/src/types/shared/index.ts b/frontend/src/types/shared/index.ts index 0d023918..1fb4323a 100644 --- a/frontend/src/types/shared/index.ts +++ b/frontend/src/types/shared/index.ts @@ -8,7 +8,6 @@ export type { export type { RouteHandle } from './routeHandle'; export type { StoreInfo } from './storeInfo'; export type { - LineChartDatum, LineChartData, LineChartSeries, Coordinate, @@ -25,5 +24,5 @@ export type { StackBarChartSeries, AllBarChartSeries, } from './bar-chart'; -export type { ChartData, ChartSeries } from './chartDataType'; +export type { ChartData, ChartSeries, ChartDatum } from './chart'; export type { EventSourceMessage } from './eventSourceMessage'; diff --git a/frontend/src/types/shared/line-chart/index.ts b/frontend/src/types/shared/line-chart/index.ts index 0b28324f..e7d069ab 100644 --- a/frontend/src/types/shared/line-chart/index.ts +++ b/frontend/src/types/shared/line-chart/index.ts @@ -1,7 +1,3 @@ -export type { - LineChartDatum, - LineChartData, - LineChartSeries, -} from './lineChartDataType'; +export type { LineChartData, LineChartSeries } from './lineChartDataType'; export type { Coordinate } from './Coordinate'; export type { XAxisType } from './xAxis'; diff --git a/frontend/src/types/shared/line-chart/lineChartDataType.ts b/frontend/src/types/shared/line-chart/lineChartDataType.ts index d678d89b..8aac47d2 100644 --- a/frontend/src/types/shared/line-chart/lineChartDataType.ts +++ b/frontend/src/types/shared/line-chart/lineChartDataType.ts @@ -1,13 +1,10 @@ -export interface LineChartDatum { - amount: number | string | null; - unit: string; -} +import type { ChartDatum } from '../chart'; export interface LineChartData { - mainX: LineChartDatum[]; - subX: LineChartDatum[]; - mainY: LineChartDatum[]; - subY: LineChartDatum[]; + mainX: ChartDatum[]; + subX: ChartDatum[]; + mainY: ChartDatum[]; + subY: ChartDatum[]; } export interface LineChartSeries { From 16da1e6c7032870b647747eb66f66f8b4e4ebd22 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 20:02:58 +0900 Subject: [PATCH 80/96] =?UTF-8?q?feat:=20=EC=9A=94=EC=9D=BC=EB=B3=84=20?= =?UTF-8?q?=EB=A7=A4=EC=B6=9C=20=ED=8C=A8=ED=84=B4=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/dashboard-sales-pattern/index.ts | 1 + .../dashboard-sales-pattern/salesByDay.ts | 43 +++++++++++++++++++ frontend/src/constants/sales/index.ts | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts diff --git a/frontend/src/constants/sales/dashboard-sales-pattern/index.ts b/frontend/src/constants/sales/dashboard-sales-pattern/index.ts index a04ab1cc..a032dbb7 100644 --- a/frontend/src/constants/sales/dashboard-sales-pattern/index.ts +++ b/frontend/src/constants/sales/dashboard-sales-pattern/index.ts @@ -1 +1,2 @@ export { PEAK_TIME } from './peakTime'; +export { SALES_BY_DAY } from './salesByDay'; diff --git a/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts b/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts new file mode 100644 index 00000000..a4bc8749 --- /dev/null +++ b/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts @@ -0,0 +1,43 @@ +import type { SalesByDayItem } from '@/types/sales'; + +export const SALES_BY_DAY = { + EXAMPLE_TOP_DAY: '금', + EXAMPLE_IS_SIGNIFICANT: false, + EXAMPLE_SALES_BY_DAY_ITEMS: [ + { + day: '월', + avgNetAmount: 820000, + orderCount: 86, + }, + { + day: '화', + avgNetAmount: 790000, + orderCount: 82, + }, + { + day: '수', + avgNetAmount: 880000, + orderCount: 91, + }, + { + day: '목', + avgNetAmount: 940000, + orderCount: 97, + }, + { + day: '금', + avgNetAmount: 1320000, + orderCount: 141, + }, + { + day: '토', + avgNetAmount: 1110000, + orderCount: 118, + }, + { + day: '일', + avgNetAmount: 960000, + orderCount: 102, + }, + ] as const satisfies SalesByDayItem[], +}; diff --git a/frontend/src/constants/sales/index.ts b/frontend/src/constants/sales/index.ts index 644ab89c..9122a5ec 100644 --- a/frontend/src/constants/sales/index.ts +++ b/frontend/src/constants/sales/index.ts @@ -19,4 +19,4 @@ export { PAYMENT_METHOD, SALES_TYPE, } from './dashboard-sales-income'; -export { PEAK_TIME } from './dashboard-sales-pattern'; +export { PEAK_TIME, SALES_BY_DAY } from './dashboard-sales-pattern'; From 2af586be3d10621c274e26bcb286776666c100ba Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 20:07:28 +0900 Subject: [PATCH 81/96] =?UTF-8?q?feat:=20=EC=9A=94=EC=9D=BC=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/types/sales/dashboard-sales-pattern/salesByDay.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/types/sales/dashboard-sales-pattern/salesByDay.ts b/frontend/src/types/sales/dashboard-sales-pattern/salesByDay.ts index fcd3a377..7ec8fcb4 100644 --- a/frontend/src/types/sales/dashboard-sales-pattern/salesByDay.ts +++ b/frontend/src/types/sales/dashboard-sales-pattern/salesByDay.ts @@ -1,10 +1,12 @@ +type Day = '월' | '화' | '수' | '목' | '금' | '토' | '일'; + export interface SalesByDaySummary { - topDay: string; + topDay: Day; isSignificant: boolean; } export interface SalesByDayItem { - day: string; + day: Day; avgNetAmount: number; orderCount: number; } From bb900cf00e40207a09aac83c847c32a35aebee95 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 20:07:49 +0900 Subject: [PATCH 82/96] =?UTF-8?q?feat:=20=EC=9A=94=EC=9D=BC=EB=B3=84=20?= =?UTF-8?q?=EB=A7=A4=EC=B6=9C=20=ED=8C=A8=ED=84=B4=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EB=A7=A4=EC=A7=81=EB=84=98=EB=B2=84=20=EC=83=81=EC=88=98=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 --- .../constants/sales/dashboard-sales-pattern/salesByDay.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts b/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts index a4bc8749..15da0447 100644 --- a/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts +++ b/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts @@ -1,7 +1,10 @@ import type { SalesByDayItem } from '@/types/sales'; export const SALES_BY_DAY = { - EXAMPLE_TOP_DAY: '금', + CHART_X_UNIT: '요일', + CHART_Y_UNIT: '원', + CHART_COLOR: 'black', + EXAMPLE_TOP_DAY: '금' as const, EXAMPLE_IS_SIGNIFICANT: false, EXAMPLE_SALES_BY_DAY_ITEMS: [ { From fc81eca25eb21bd617db48ad9827b1834d59d865 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 20:08:08 +0900 Subject: [PATCH 83/96] =?UTF-8?q?feat:=20=EC=9A=94=EC=9D=BC=EB=B3=84=20?= =?UTF-8?q?=EB=A7=A4=EC=B6=9C=20=ED=8C=A8=ED=84=B4=20card=20content=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SalesByDayContent.tsx | 48 +++++++++++++++++-- .../sales/dashboard-sales-pattern/index.ts | 2 + 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx b/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx index b56e805d..88e05a7a 100644 --- a/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx @@ -1,22 +1,52 @@ +import { BarChart } from '@/components/shared/bar-chart'; +import { SALES_BY_DAY } from '@/constants/sales'; import type { SalesByDayItem, SalesByDaySummary } from '@/types/sales'; import { getSalesPatternByDayMessage } from '@/utils/sales'; import { cn, type Nullable } from '@/utils/shared'; +const { + CHART_X_UNIT, + CHART_Y_UNIT, + CHART_COLOR, + EXAMPLE_TOP_DAY, + EXAMPLE_IS_SIGNIFICANT, + EXAMPLE_SALES_BY_DAY_ITEMS, +} = SALES_BY_DAY; + interface SalesByDayContentProps extends Nullable { salesByDayItems?: SalesByDayItem[]; className?: string; } export const SalesByDayContent = ({ - // salesByDayItems = [], - topDay = '월', - isSignificant = false, + salesByDayItems = EXAMPLE_SALES_BY_DAY_ITEMS, + topDay = EXAMPLE_TOP_DAY, + isSignificant = EXAMPLE_IS_SIGNIFICANT, className, }: SalesByDayContentProps) => { const salesByDayBriefingMessage = getSalesPatternByDayMessage({ topDay, isSignificant, }); + + const salesByDaySeries = { + data: { + mainX: salesByDayItems.map((item) => ({ + amount: item.day, + unit: CHART_X_UNIT, + })), + mainY: salesByDayItems.map((item) => ({ + amount: item.avgNetAmount, + unit: CHART_Y_UNIT, + })), + }, + color: CHART_COLOR, + }; + + const activeDataIndex = salesByDayItems.findIndex( + (item) => item.day === topDay, + ); + return (
    +

    {salesByDayBriefingMessage.map( ({ text, isHighlight, highlightColor }, index) => { diff --git a/frontend/src/components/sales/dashboard-sales-pattern/index.ts b/frontend/src/components/sales/dashboard-sales-pattern/index.ts index e69de29b..025eb1f5 100644 --- a/frontend/src/components/sales/dashboard-sales-pattern/index.ts +++ b/frontend/src/components/sales/dashboard-sales-pattern/index.ts @@ -0,0 +1,2 @@ +export { PeakTimeContent } from './PeakTimeContent'; +export { SalesByDayContent } from './SalesByDayContent'; From a04068bed08612c2d4a71cf72dd9cca4ec865460 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 20:08:50 +0900 Subject: [PATCH 84/96] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B6=9C=20=EB=B6=84?= =?UTF-8?q?=EC=84=9D=20=EA=B4=80=EB=A0=A8=20=EB=8C=80=EC=8B=9C=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=ED=8E=B8=EC=A7=91=20=EC=B9=B4=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(=EB=A7=A4=EC=B6=9C=20=EC=B6=94=EC=9D=B4=20?= =?UTF-8?q?=EC=A0=9C=EC=99=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard-edit/CardEditViewCard.tsx | 9 ++-- .../dashboard-edit/EditCardContent.tsx | 50 +++++++++++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 frontend/src/components/dashboard/dashboard-edit/EditCardContent.tsx diff --git a/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx b/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx index 973cb2ce..325aef1a 100644 --- a/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx +++ b/frontend/src/components/dashboard/dashboard-edit/CardEditViewCard.tsx @@ -7,6 +7,8 @@ import { } from '@/constants/dashboard'; import { useEditCard } from '@/hooks/dashboard'; +import { EditCardContent } from './EditCardContent'; + interface CardEditViewCardProps { cardCode: MetricCardCode; } @@ -30,7 +32,7 @@ export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { return null; // 카드 정보가 없는 경우 렌더링하지 않음 } - const { code, period, sizeX } = card; + const { period, sizeX } = card; return (

  • @@ -42,10 +44,7 @@ export const CardEditViewCard = ({ cardCode }: CardEditViewCardProps) => { onClickAddButton={handleAddCard} onClickDeleteButton={handleDeleteCard} > -
    - {code} -
    -
    +
  • ); diff --git a/frontend/src/components/dashboard/dashboard-edit/EditCardContent.tsx b/frontend/src/components/dashboard/dashboard-edit/EditCardContent.tsx new file mode 100644 index 00000000..b31dd1e3 --- /dev/null +++ b/frontend/src/components/dashboard/dashboard-edit/EditCardContent.tsx @@ -0,0 +1,50 @@ +import { + AveragePriceContent, + OrderCountContent, + OrderMethodContent, + PaymentMethodContent, + PeakTimeContent, + RealSalesContent, + SalesByDayContent, + SalesTypeContent, +} from '@/components/sales'; +import type { MetricCardCode } from '@/constants/dashboard'; + +interface EditCardContentProps { + cardCode: MetricCardCode; +} + +export const EditCardContent = ({ cardCode }: EditCardContentProps) => { + switch (cardCode) { + case 'SLS_01_01': + case 'SLS_01_02': + case 'SLS_01_03': + return ; + case 'SLS_02_01': + case 'SLS_02_02': + case 'SLS_02_03': + return ; + case 'SLS_03_01': + case 'SLS_03_02': + case 'SLS_03_03': + return ; + case 'SLS_06_01': + case 'SLS_06_02': + case 'SLS_06_03': + return ; + case 'SLS_07_01': + case 'SLS_07_02': + case 'SLS_07_03': + return ; + case 'SLS_08_01': + case 'SLS_08_02': + case 'SLS_08_03': + return ; + case 'SLS_13_01': + return ; + case 'SLS_14_06': + return ; + default: + return null; + } +}; From ee3c325f8cfdc755c25fd6751b630c72f45a2f68 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 20:09:03 +0900 Subject: [PATCH 85/96] =?UTF-8?q?chore:=20=EB=B0=B0=EB=9F=B4=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/sales/dashboard-sales-income/index.ts | 1 + frontend/src/components/sales/index.ts | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/sales/dashboard-sales-income/index.ts b/frontend/src/components/sales/dashboard-sales-income/index.ts index 8886b175..108d2f0e 100644 --- a/frontend/src/components/sales/dashboard-sales-income/index.ts +++ b/frontend/src/components/sales/dashboard-sales-income/index.ts @@ -1,3 +1,4 @@ export { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; export { SalesTypeContent } from './SalesTypeContent'; export { OrderMethodContent } from './OrderMethodContent'; +export { PaymentMethodContent } from './PaymentMethodContent'; diff --git a/frontend/src/components/sales/index.ts b/frontend/src/components/sales/index.ts index 8a27ab0b..28b23e4f 100644 --- a/frontend/src/components/sales/index.ts +++ b/frontend/src/components/sales/index.ts @@ -8,4 +8,9 @@ export { RealSalesContent, } from './dashboard-current-sales'; export { DashboardSalesIncomeContent } from './dashboard-sales-income'; -export { SalesTypeContent, OrderMethodContent } from './dashboard-sales-income'; +export { + SalesTypeContent, + OrderMethodContent, + PaymentMethodContent, +} from './dashboard-sales-income'; +export { PeakTimeContent, SalesByDayContent } from './dashboard-sales-pattern'; From 34106d8f28043cc8ee1cb7fcc89851ddbafacca9 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Sun, 15 Feb 2026 20:28:35 +0900 Subject: [PATCH 86/96] =?UTF-8?q?refactor:=20=EB=A7=A4=EC=B6=9C=EB=B6=84?= =?UTF-8?q?=EC=84=9D=20=EC=B9=B4=EB=93=9C=20props=20required=20type?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=91=20=EC=B9=B4=EB=93=9C=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EC=97=90=EC=84=9C=20=EC=98=88=EC=8B=9C=20data?= =?UTF-8?q?=EB=A5=BC=20=EC=A0=84=EB=8B=AC=ED=95=98=EB=8A=94=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard-edit/EditCardContent.tsx | 123 ++++++++++++++++-- .../AveragePriceContent.tsx | 3 +- .../OrderCountContent.tsx | 6 +- .../RealSalesContent.tsx | 6 +- .../OrderMethodContent.tsx | 19 +-- .../PaymentMethodContent.tsx | 31 ++--- .../SalesTypeContent.tsx | 19 +-- .../PeakTimeContent.tsx | 5 +- .../SalesByDayContent.tsx | 21 +-- .../dashboard-sales-income/orderMethod.ts | 4 +- .../dashboard-sales-income/paymentMethod.ts | 4 +- .../sales/dashboard-sales-income/salesType.ts | 2 +- .../dashboard-sales-pattern/salesByDay.ts | 2 +- .../salesIncomeStructureInsight.ts | 4 +- 14 files changed, 166 insertions(+), 83 deletions(-) diff --git a/frontend/src/components/dashboard/dashboard-edit/EditCardContent.tsx b/frontend/src/components/dashboard/dashboard-edit/EditCardContent.tsx index b31dd1e3..7668a7eb 100644 --- a/frontend/src/components/dashboard/dashboard-edit/EditCardContent.tsx +++ b/frontend/src/components/dashboard/dashboard-edit/EditCardContent.tsx @@ -9,41 +9,148 @@ import { SalesTypeContent, } from '@/components/sales'; import type { MetricCardCode } from '@/constants/dashboard'; +import { + AVERAGE_PRICE, + ORDER_COUNT, + ORDER_METHOD, + PAYMENT_METHOD, + PEAK_TIME, + REAL_SALES, + SALES_BY_DAY, + SALES_TYPE, +} from '@/constants/sales'; interface EditCardContentProps { cardCode: MetricCardCode; } +const { + EXAMPLE_AMOUNT: REAL_SALES_EXAMPLE_AMOUNT, + EXAMPLE_CHANGE_RATE: REAL_SALES_EXAMPLE_CHANGE_RATE, + EXAMPLE_HAS_PREVIOUS_DATA: REAL_SALES_EXAMPLE_HAS_PREVIOUS_DATA, +} = REAL_SALES; +const { + EXAMPLE_AMOUNT: ORDER_COUNT_EXAMPLE_AMOUNT, + EXAMPLE_CHANGE_RATE: ORDER_COUNT_EXAMPLE_CHANGE_RATE, + EXAMPLE_HAS_PREVIOUS_DATA: ORDER_COUNT_EXAMPLE_HAS_PREVIOUS_DATA, +} = ORDER_COUNT; +const { + EXAMPLE_AMOUNT: AVERAGE_PRICE_EXAMPLE_AMOUNT, + EXAMPLE_COMPARISON_AMOUNT: AVERAGE_PRICE_EXAMPLE_COMPARISON_AMOUNT, + EXAMPLE_HAS_PREVIOUS_DATA: AVERAGE_PRICE_EXAMPLE_HAS_PREVIOUS_DATA, +} = AVERAGE_PRICE; +const { + EXAMPLE_TOP_TYPE: SALES_TYPE_EXAMPLE_TOP_TYPE, + EXAMPLE_TOP_SHARE: SALES_TYPE_EXAMPLE_TOP_SHARE, + EXAMPLE_DELTA_SHARE: SALES_TYPE_EXAMPLE_DELTA_SHARE, + EXAMPLE_SALES_SOURCE_DATA: SALES_TYPE_EXAMPLE_SALES_SOURCE_DATA, +} = SALES_TYPE; +const { + EXAMPLE_TOP_TYPE: ORDER_METHOD_EXAMPLE_TOP_TYPE, + EXAMPLE_TOP_SHARE: ORDER_METHOD_EXAMPLE_TOP_SHARE, + EXAMPLE_DELTA_SHARE: ORDER_METHOD_EXAMPLE_DELTA_SHARE, + EXAMPLE_ORDER_METHOD_DATA: ORDER_METHOD_EXAMPLE_ORDER_METHOD_DATA, +} = ORDER_METHOD; +const { + EXAMPLE_TOP_TYPE: PAYMENT_METHOD_EXAMPLE_TOP_TYPE, + EXAMPLE_TOP_SHARE: PAYMENT_METHOD_EXAMPLE_TOP_SHARE, + EXAMPLE_DELTA_SHARE: PAYMENT_METHOD_EXAMPLE_DELTA_SHARE, + EXAMPLE_PAYMENT_METHOD_DATA: PAYMENT_METHOD_EXAMPLE_PAYMENT_METHOD_DATA, +} = PAYMENT_METHOD; +const { EXAMPLE_DATA: PEAK_TIME_EXAMPLE_DATA } = PEAK_TIME; +const { + EXAMPLE_DATA: SALES_BY_DAY_EXAMPLE_DATA, + EXAMPLE_TOP_DAY: SALES_BY_DAY_EXAMPLE_TOP_DAY, + EXAMPLE_IS_SIGNIFICANT: SALES_BY_DAY_EXAMPLE_IS_SIGNIFICANT, +} = SALES_BY_DAY; + export const EditCardContent = ({ cardCode }: EditCardContentProps) => { switch (cardCode) { case 'SLS_01_01': case 'SLS_01_02': case 'SLS_01_03': - return ; + return ( + + ); case 'SLS_02_01': case 'SLS_02_02': case 'SLS_02_03': - return ; + return ( + + ); case 'SLS_03_01': case 'SLS_03_02': case 'SLS_03_03': - return ; + return ( + + ); case 'SLS_06_01': case 'SLS_06_02': case 'SLS_06_03': - return ; + return ( + + ); case 'SLS_07_01': case 'SLS_07_02': case 'SLS_07_03': - return ; + return ( + + ); case 'SLS_08_01': case 'SLS_08_02': case 'SLS_08_03': - return ; + return ( + + ); case 'SLS_13_01': - return ; + return ; case 'SLS_14_06': - return ; + return ( + + ); default: return null; } diff --git a/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx b/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx index d74e5ea6..72129e63 100644 --- a/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx @@ -7,7 +7,6 @@ import { AVERAGE_PRICE, SALES_UNIT } from '@/constants/sales'; import type { GetAveragePriceResponseDto } from '@/types/sales'; import { getMetricTrend } from '@/utils/dashboard'; import { getSalesCurrentComparisonMessage } from '@/utils/sales'; -import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; @@ -24,7 +23,7 @@ type AveragePriceCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.AVERAGE_PRICE >; -interface AveragePriceContentProps extends Nullable { +interface AveragePriceContentProps extends GetAveragePriceResponseDto { cardCode: AveragePriceCardCodes; className?: string; } diff --git a/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx b/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx index ba852121..cc8ae8d5 100644 --- a/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx @@ -7,7 +7,6 @@ import { ORDER_COUNT, SALES_UNIT } from '@/constants/sales'; import type { GetOrderCountResponseDto } from '@/types/sales'; import { getMetricTrend } from '@/utils/dashboard'; import { getSalesCurrentComparisonMessage } from '@/utils/sales'; -import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; @@ -24,7 +23,10 @@ type OrderCountCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.ORDER_COUNT >; -interface OrderCountContentProps extends Nullable { +interface OrderCountContentProps extends Omit< + GetOrderCountResponseDto, + 'differenceOrderCount' +> { cardCode: OrderCountCardCodes; className?: string; } diff --git a/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx b/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx index c6ac4ba3..271d29a3 100644 --- a/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx @@ -7,7 +7,6 @@ import { REAL_SALES, SALES_UNIT } from '@/constants/sales'; import type { GetRealTimeSalesResponseDto } from '@/types/sales'; import { getMetricTrend } from '@/utils/dashboard'; import { getSalesCurrentComparisonMessage } from '@/utils/sales'; -import type { Nullable } from '@/utils/shared'; import { CurrentSalesContent } from './CurrentSalesContent'; @@ -24,7 +23,10 @@ type RealSalesCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.CURRENT_SALES.items.REAL_SALES >; -interface RealSalesContentProps extends Nullable { +interface RealSalesContentProps extends Omit< + GetRealTimeSalesResponseDto, + 'differenceAmount' +> { cardCode: RealSalesCardCodes; className?: string; } diff --git a/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx index e5a20124..44ad4b1a 100644 --- a/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx @@ -5,23 +5,16 @@ import { } from '@/constants/dashboard'; import { ORDER_METHOD, SALES_SOURCE_COLORS } from '@/constants/sales'; import type { GetIncomStructureByOrderMethodResponseDto } from '@/types/sales'; -import { type Nullable } from '@/utils/shared'; import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; -const { - EXAMPLE_TOP_TYPE, - EXAMPLE_TOP_SHARE, - EXAMPLE_DELTA_SHARE, - EXAMPLE_ORDER_METHOD_DATA, - DOUGHNUT_CHART_TITLE, -} = ORDER_METHOD; +const { DOUGHNUT_CHART_TITLE } = ORDER_METHOD; type OrderMethodCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.INCOME_STRUCTURE.items.ORDER_METHOD >; -interface OrderMethodContentProps extends Nullable { +interface OrderMethodContentProps extends GetIncomStructureByOrderMethodResponseDto { cardCode: OrderMethodCardCodes; } @@ -32,7 +25,7 @@ export const OrderMethodContent = ({ }: OrderMethodContentProps) => { const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; - const orderMethodData = (items ?? EXAMPLE_ORDER_METHOD_DATA).map((item) => ({ + const orderMethodData = items.map((item) => ({ salesSourceType: item.orderChannel, revenue: item.salesAmount, count: item.orderCount, @@ -49,9 +42,9 @@ export const OrderMethodContent = ({ ; -interface PaymentMethodContentProps extends Nullable { +interface PaymentMethodContentProps extends GetIncomStructureByPaymentMethodResponseDto { cardCode: PaymentMethodCardCodes; } @@ -32,14 +25,12 @@ export const PaymentMethodContent = ({ }: PaymentMethodContentProps) => { const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; - const paymentMethodData = (items ?? EXAMPLE_PAYMENT_METHOD_DATA).map( - (item) => ({ - salesSourceType: item.payMethod, - revenue: item.salesAmount, - count: item.orderCount, - changeRate: item.deltaShare, - }), - ); + const paymentMethodData = items.map((item) => ({ + salesSourceType: item.payMethod, + revenue: item.salesAmount, + count: item.orderCount, + changeRate: item.deltaShare, + })); const chartData = paymentMethodData.map((data) => ({ label: data.salesSourceType, @@ -51,9 +42,9 @@ export const PaymentMethodContent = ({ ; -interface SalesTypeContentProps extends Nullable { +interface SalesTypeContentProps extends GetIncomStructureBySalesTypeResponseDto { cardCode: DashboardSalesIncomeCardCodes; } @@ -32,7 +25,7 @@ export const SalesTypeContent = ({ }: SalesTypeContentProps) => { const periodType = DASHBOARD_METRIC_CARDS[cardCode].period; - const salesTypeData = (items ?? EXAMPLE_SALES_SOURCE_DATA).map((item) => ({ + const salesTypeData = items.map((item) => ({ salesSourceType: item.salesType, revenue: item.salesAmount, count: item.orderCount, @@ -49,9 +42,9 @@ export const SalesTypeContent = ({ { const weekday = DAY_OF_WEEK_LIST[new Date().getDay()]; diff --git a/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx b/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx index 88e05a7a..1bf8f27d 100644 --- a/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-pattern/SalesByDayContent.tsx @@ -2,26 +2,19 @@ import { BarChart } from '@/components/shared/bar-chart'; import { SALES_BY_DAY } from '@/constants/sales'; import type { SalesByDayItem, SalesByDaySummary } from '@/types/sales'; import { getSalesPatternByDayMessage } from '@/utils/sales'; -import { cn, type Nullable } from '@/utils/shared'; +import { cn } from '@/utils/shared'; -const { - CHART_X_UNIT, - CHART_Y_UNIT, - CHART_COLOR, - EXAMPLE_TOP_DAY, - EXAMPLE_IS_SIGNIFICANT, - EXAMPLE_SALES_BY_DAY_ITEMS, -} = SALES_BY_DAY; +const { CHART_X_UNIT, CHART_Y_UNIT, CHART_COLOR } = SALES_BY_DAY; -interface SalesByDayContentProps extends Nullable { - salesByDayItems?: SalesByDayItem[]; +interface SalesByDayContentProps extends SalesByDaySummary { + salesByDayItems: SalesByDayItem[]; className?: string; } export const SalesByDayContent = ({ - salesByDayItems = EXAMPLE_SALES_BY_DAY_ITEMS, - topDay = EXAMPLE_TOP_DAY, - isSignificant = EXAMPLE_IS_SIGNIFICANT, + salesByDayItems, + topDay, + isSignificant, className, }: SalesByDayContentProps) => { const salesByDayBriefingMessage = getSalesPatternByDayMessage({ diff --git a/frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts b/frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts index 3b4fa4c5..30461e67 100644 --- a/frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts +++ b/frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts @@ -1,3 +1,5 @@ +import type { GetIncomStructureByOrderMethodResponseDto } from '@/types/sales'; + export const ORDER_METHOD = { EXAMPLE_TOP_TYPE: '키오스크', EXAMPLE_TOP_SHARE: 50, @@ -31,6 +33,6 @@ export const ORDER_METHOD = { share: 25, deltaShare: -1.8, }, - ], + ] as const satisfies GetIncomStructureByOrderMethodResponseDto['items'], DOUGHNUT_CHART_TITLE: '주문수단별 매출 관련 도넛 차트', } as const; diff --git a/frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts b/frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts index 13fa50c8..7ecc5e8b 100644 --- a/frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts +++ b/frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts @@ -1,3 +1,5 @@ +import type { GetIncomStructureByPaymentMethodResponseDto } from '@/types/sales'; + export const PAYMENT_METHOD = { EXAMPLE_TOP_TYPE: '현금', EXAMPLE_TOP_SHARE: 46, @@ -31,6 +33,6 @@ export const PAYMENT_METHOD = { share: 25, deltaShare: 2.4, }, - ], + ] as const satisfies GetIncomStructureByPaymentMethodResponseDto['items'], DOUGHNUT_CHART_TITLE: '결제수단별 매출 관련 도넛 차트', } as const; diff --git a/frontend/src/constants/sales/dashboard-sales-income/salesType.ts b/frontend/src/constants/sales/dashboard-sales-income/salesType.ts index 9b58f523..785d39c7 100644 --- a/frontend/src/constants/sales/dashboard-sales-income/salesType.ts +++ b/frontend/src/constants/sales/dashboard-sales-income/salesType.ts @@ -3,7 +3,7 @@ import type { GetIncomStructureBySalesTypeResponseDto } from '@/types/sales'; import { SALES_SOURCE } from '../salesSource'; export const SALES_TYPE = { - EXAMPLE_TOP_TYPE: '배달', + EXAMPLE_TOP_TYPE: '배달' as const, EXAMPLE_TOP_SHARE: 43, EXAMPLE_DELTA_SHARE: 6.8, EXAMPLE_SALES_SOURCE_DATA: [ diff --git a/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts b/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts index 15da0447..2e6c0ae4 100644 --- a/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts +++ b/frontend/src/constants/sales/dashboard-sales-pattern/salesByDay.ts @@ -6,7 +6,7 @@ export const SALES_BY_DAY = { CHART_COLOR: 'black', EXAMPLE_TOP_DAY: '금' as const, EXAMPLE_IS_SIGNIFICANT: false, - EXAMPLE_SALES_BY_DAY_ITEMS: [ + EXAMPLE_DATA: [ { day: '월', avgNetAmount: 820000, diff --git a/frontend/src/types/sales/dashboard-sales-income/salesIncomeStructureInsight.ts b/frontend/src/types/sales/dashboard-sales-income/salesIncomeStructureInsight.ts index f39f7da6..3612df04 100644 --- a/frontend/src/types/sales/dashboard-sales-income/salesIncomeStructureInsight.ts +++ b/frontend/src/types/sales/dashboard-sales-income/salesIncomeStructureInsight.ts @@ -14,6 +14,6 @@ export interface SalesIncomeStructureInsight { topType: SalesIncomeStructureTopType; topShare: number; deltaShare: number; - showDeltaText: boolean; - showFocusText: boolean; + showDeltaText?: boolean; + showFocusText?: boolean; } From 98f0e74f36915da469168bb1b317c5887cbfb6f1 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Mon, 16 Feb 2026 00:40:28 +0900 Subject: [PATCH 87/96] =?UTF-8?q?style:=20edit=20card=20wrapper=20transfor?= =?UTF-8?q?m=20origin=20=EB=A1=9C=EC=A7=81=20=EB=A1=A4=EB=B0=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/shared/edit-card-wrapper/EditCardWrapper.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx b/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx index 7863c3fb..86ca1b95 100644 --- a/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx +++ b/frontend/src/components/shared/edit-card-wrapper/EditCardWrapper.tsx @@ -75,7 +75,10 @@ export const EditCardWrapper = ({
    Date: Mon, 16 Feb 2026 00:41:12 +0900 Subject: [PATCH 88/96] =?UTF-8?q?chore:=20shadcn=20import=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/shared/edit-card-wrapper/PlusIconButton.tsx | 2 +- .../components/shared/edit-card-wrapper/TrashCanIconButton.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/shared/edit-card-wrapper/PlusIconButton.tsx b/frontend/src/components/shared/edit-card-wrapper/PlusIconButton.tsx index 753f865c..bd993c78 100644 --- a/frontend/src/components/shared/edit-card-wrapper/PlusIconButton.tsx +++ b/frontend/src/components/shared/edit-card-wrapper/PlusIconButton.tsx @@ -1,6 +1,6 @@ import { Plus } from 'lucide-react'; -import { Button } from '../shadcn-ui'; +import { Button } from '@/components/shared/shadcn-ui'; // 대시보드 편집 용 패널의 우측 위 + 버튼 interface PlusIconButtonProps { diff --git a/frontend/src/components/shared/edit-card-wrapper/TrashCanIconButton.tsx b/frontend/src/components/shared/edit-card-wrapper/TrashCanIconButton.tsx index 5095e6ff..ed835da0 100644 --- a/frontend/src/components/shared/edit-card-wrapper/TrashCanIconButton.tsx +++ b/frontend/src/components/shared/edit-card-wrapper/TrashCanIconButton.tsx @@ -1,6 +1,6 @@ import { Trash2 } from 'lucide-react'; -import { Button } from '../shadcn-ui'; +import { Button } from '@/components/shared/shadcn-ui'; // 대시보드 편집 용 패널의 우측 위 쓰래기통 버튼 interface TrashCanIconButtonProps { From 127ae41f040147c4cdcf3507691f4b1d3c7e1f2d Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Mon, 16 Feb 2026 00:44:20 +0900 Subject: [PATCH 89/96] =?UTF-8?q?chore:=20dto=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B0=8D=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/dashboard-sales-income/OrderMethodContent.tsx | 4 ++-- .../sales/dashboard-sales-income/PaymentMethodContent.tsx | 4 ++-- .../sales/dashboard-sales-income/SalesTypeContent.tsx | 4 ++-- .../constants/sales/dashboard-sales-income/orderMethod.ts | 4 ++-- .../constants/sales/dashboard-sales-income/paymentMethod.ts | 4 ++-- .../src/constants/sales/dashboard-sales-income/salesType.ts | 4 ++-- ...erMethodDto.ts => getIncomeStructureByOrderMethodDto.ts} | 2 +- ...MethodDto.ts => getIncomeStructureByPaymentMethodDto.ts} | 2 +- ...ySalesTypeDto.ts => getIncomeStructureBySalesTypeDto.ts} | 2 +- frontend/src/types/sales/dto/index.ts | 6 +++--- frontend/src/types/sales/index.ts | 6 +++--- 11 files changed, 21 insertions(+), 21 deletions(-) rename frontend/src/types/sales/dto/{getIncomStructureByOrderMethodDto.ts => getIncomeStructureByOrderMethodDto.ts} (86%) rename frontend/src/types/sales/dto/{getIncomStructureByPaymentMethodDto.ts => getIncomeStructureByPaymentMethodDto.ts} (86%) rename frontend/src/types/sales/dto/{getIncomStructureBySalesTypeDto.ts => getIncomeStructureBySalesTypeDto.ts} (86%) diff --git a/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx index 44ad4b1a..36d58b51 100644 --- a/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx @@ -4,7 +4,7 @@ import { type ExtractCardCodes, } from '@/constants/dashboard'; import { ORDER_METHOD, SALES_SOURCE_COLORS } from '@/constants/sales'; -import type { GetIncomStructureByOrderMethodResponseDto } from '@/types/sales'; +import type { GetIncomeStructureByOrderMethodResponseDto } from '@/types/sales'; import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; @@ -14,7 +14,7 @@ type OrderMethodCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.INCOME_STRUCTURE.items.ORDER_METHOD >; -interface OrderMethodContentProps extends GetIncomStructureByOrderMethodResponseDto { +interface OrderMethodContentProps extends GetIncomeStructureByOrderMethodResponseDto { cardCode: OrderMethodCardCodes; } diff --git a/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx b/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx index b313dd15..5173dced 100644 --- a/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx @@ -4,7 +4,7 @@ import { type ExtractCardCodes, } from '@/constants/dashboard'; import { PAYMENT_METHOD, SALES_SOURCE_COLORS } from '@/constants/sales'; -import type { GetIncomStructureByPaymentMethodResponseDto } from '@/types/sales'; +import type { GetIncomeStructureByPaymentMethodResponseDto } from '@/types/sales'; import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; @@ -14,7 +14,7 @@ type PaymentMethodCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.INCOME_STRUCTURE.items.PAYMENT_METHOD >; -interface PaymentMethodContentProps extends GetIncomStructureByPaymentMethodResponseDto { +interface PaymentMethodContentProps extends GetIncomeStructureByPaymentMethodResponseDto { cardCode: PaymentMethodCardCodes; } diff --git a/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx index 442d20ae..0440334f 100644 --- a/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx @@ -4,7 +4,7 @@ import { type ExtractCardCodes, } from '@/constants/dashboard'; import { SALES_SOURCE_COLORS, SALES_TYPE } from '@/constants/sales'; -import type { GetIncomStructureBySalesTypeResponseDto } from '@/types/sales'; +import type { GetIncomeStructureBySalesTypeResponseDto } from '@/types/sales'; import { DashboardSalesIncomeContent } from './DashboardSalesIncomeContent'; @@ -14,7 +14,7 @@ type DashboardSalesIncomeCardCodes = ExtractCardCodes< typeof DASHBOARD_METRICS.SALES.sections.INCOME_STRUCTURE.items.SALES_TYPE >; -interface SalesTypeContentProps extends GetIncomStructureBySalesTypeResponseDto { +interface SalesTypeContentProps extends GetIncomeStructureBySalesTypeResponseDto { cardCode: DashboardSalesIncomeCardCodes; } diff --git a/frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts b/frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts index 30461e67..4d2818f9 100644 --- a/frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts +++ b/frontend/src/constants/sales/dashboard-sales-income/orderMethod.ts @@ -1,4 +1,4 @@ -import type { GetIncomStructureByOrderMethodResponseDto } from '@/types/sales'; +import type { GetIncomeStructureByOrderMethodResponseDto } from '@/types/sales'; export const ORDER_METHOD = { EXAMPLE_TOP_TYPE: '키오스크', @@ -33,6 +33,6 @@ export const ORDER_METHOD = { share: 25, deltaShare: -1.8, }, - ] as const satisfies GetIncomStructureByOrderMethodResponseDto['items'], + ] as const satisfies GetIncomeStructureByOrderMethodResponseDto['items'], DOUGHNUT_CHART_TITLE: '주문수단별 매출 관련 도넛 차트', } as const; diff --git a/frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts b/frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts index 7ecc5e8b..8f8ad018 100644 --- a/frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts +++ b/frontend/src/constants/sales/dashboard-sales-income/paymentMethod.ts @@ -1,4 +1,4 @@ -import type { GetIncomStructureByPaymentMethodResponseDto } from '@/types/sales'; +import type { GetIncomeStructureByPaymentMethodResponseDto } from '@/types/sales'; export const PAYMENT_METHOD = { EXAMPLE_TOP_TYPE: '현금', @@ -33,6 +33,6 @@ export const PAYMENT_METHOD = { share: 25, deltaShare: 2.4, }, - ] as const satisfies GetIncomStructureByPaymentMethodResponseDto['items'], + ] as const satisfies GetIncomeStructureByPaymentMethodResponseDto['items'], DOUGHNUT_CHART_TITLE: '결제수단별 매출 관련 도넛 차트', } as const; diff --git a/frontend/src/constants/sales/dashboard-sales-income/salesType.ts b/frontend/src/constants/sales/dashboard-sales-income/salesType.ts index 785d39c7..dcff6687 100644 --- a/frontend/src/constants/sales/dashboard-sales-income/salesType.ts +++ b/frontend/src/constants/sales/dashboard-sales-income/salesType.ts @@ -1,4 +1,4 @@ -import type { GetIncomStructureBySalesTypeResponseDto } from '@/types/sales'; +import type { GetIncomeStructureBySalesTypeResponseDto } from '@/types/sales'; import { SALES_SOURCE } from '../salesSource'; @@ -28,6 +28,6 @@ export const SALES_TYPE = { share: 30, deltaShare: 6.8, }, - ] as GetIncomStructureBySalesTypeResponseDto['items'], + ] as GetIncomeStructureBySalesTypeResponseDto['items'], DOUGHNUT_CHART_TITLE: '판매 유형 관련 도넛 차트', } as const; diff --git a/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts b/frontend/src/types/sales/dto/getIncomeStructureByOrderMethodDto.ts similarity index 86% rename from frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts rename to frontend/src/types/sales/dto/getIncomeStructureByOrderMethodDto.ts index cc549417..2266ac0c 100644 --- a/frontend/src/types/sales/dto/getIncomStructureByOrderMethodDto.ts +++ b/frontend/src/types/sales/dto/getIncomeStructureByOrderMethodDto.ts @@ -14,7 +14,7 @@ interface OrderMethodItem { deltaShare: number; } -export interface GetIncomStructureByOrderMethodResponseDto { +export interface GetIncomeStructureByOrderMethodResponseDto { insight: SalesIncomeStructureInsight; items: OrderMethodItem[]; } diff --git a/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts b/frontend/src/types/sales/dto/getIncomeStructureByPaymentMethodDto.ts similarity index 86% rename from frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts rename to frontend/src/types/sales/dto/getIncomeStructureByPaymentMethodDto.ts index 985cf351..31de5c18 100644 --- a/frontend/src/types/sales/dto/getIncomStructureByPaymentMethodDto.ts +++ b/frontend/src/types/sales/dto/getIncomeStructureByPaymentMethodDto.ts @@ -14,7 +14,7 @@ interface PaymentMethodItem { deltaShare: number; } -export interface GetIncomStructureByPaymentMethodResponseDto { +export interface GetIncomeStructureByPaymentMethodResponseDto { insight: SalesIncomeStructureInsight; items: PaymentMethodItem[]; } diff --git a/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts b/frontend/src/types/sales/dto/getIncomeStructureBySalesTypeDto.ts similarity index 86% rename from frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts rename to frontend/src/types/sales/dto/getIncomeStructureBySalesTypeDto.ts index d2a49734..6aa77de1 100644 --- a/frontend/src/types/sales/dto/getIncomStructureBySalesTypeDto.ts +++ b/frontend/src/types/sales/dto/getIncomeStructureBySalesTypeDto.ts @@ -11,7 +11,7 @@ interface SalesTypeItem { deltaShare: number; } -export interface GetIncomStructureBySalesTypeResponseDto { +export interface GetIncomeStructureBySalesTypeResponseDto { insight: SalesIncomeStructureInsight; items: SalesTypeItem[]; } diff --git a/frontend/src/types/sales/dto/index.ts b/frontend/src/types/sales/dto/index.ts index 66acab03..2c9747f3 100644 --- a/frontend/src/types/sales/dto/index.ts +++ b/frontend/src/types/sales/dto/index.ts @@ -1,9 +1,9 @@ export type { GetRealTimeSalesResponseDto } from './getRealTimeSalesDto'; export type { GetOrderCountResponseDto } from './getOrderCountDto'; export type { GetAveragePriceResponseDto } from './getAveragePriceDto'; -export type { GetIncomStructureBySalesTypeResponseDto } from './getIncomStructureBySalesTypeDto'; -export type { GetIncomStructureByOrderMethodResponseDto } from './getIncomStructureByOrderMethodDto'; -export type { GetIncomStructureByPaymentMethodResponseDto } from './getIncomStructureByPaymentMethodDto'; +export type { GetIncomeStructureBySalesTypeResponseDto } from './getIncomeStructureBySalesTypeDto'; +export type { GetIncomeStructureByOrderMethodResponseDto } from './getIncomeStructureByOrderMethodDto'; +export type { GetIncomeStructureByPaymentMethodResponseDto } from './getIncomeStructureByPaymentMethodDto'; export type { GetDetailPeakTimeResponseDto, GetDashboardPeakTimeResponseDto, diff --git a/frontend/src/types/sales/index.ts b/frontend/src/types/sales/index.ts index 6eacb189..60ba30d7 100644 --- a/frontend/src/types/sales/index.ts +++ b/frontend/src/types/sales/index.ts @@ -3,9 +3,9 @@ export type { GetRealTimeSalesResponseDto, GetOrderCountResponseDto, GetAveragePriceResponseDto, - GetIncomStructureBySalesTypeResponseDto, - GetIncomStructureByOrderMethodResponseDto, - GetIncomStructureByPaymentMethodResponseDto, + GetIncomeStructureBySalesTypeResponseDto, + GetIncomeStructureByOrderMethodResponseDto, + GetIncomeStructureByPaymentMethodResponseDto, GetDetailPeakTimeResponseDto, GetDashboardPeakTimeResponseDto, GetDetailSalesByDayResponseDto, From 2a6e257c7fe09f5823b9c3f1961e19de373fe3f5 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Mon, 16 Feb 2026 00:45:58 +0900 Subject: [PATCH 90/96] =?UTF-8?q?chore:=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20?= =?UTF-8?q?=EC=98=A4=ED=83=80=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard-sales-income/DashboardSalesIncomeContent.tsx | 4 ++-- ...ssage.ts => getSalesIncomeStructureComparisonMessage.ts} | 6 +++--- frontend/src/utils/sales/dashboard-sales-income/index.ts | 2 +- frontend/src/utils/sales/index.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename frontend/src/utils/sales/dashboard-sales-income/{getSalesIncomeStructureComparisionMessage.ts => getSalesIncomeStructureComparisonMessage.ts} (86%) diff --git a/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx index 5ad50d0e..b72bbf7c 100644 --- a/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/DashboardSalesIncomeContent.tsx @@ -4,7 +4,7 @@ import { DoughnutChart } from '@/components/shared'; import { PERIOD_PRESETS } from '@/constants/shared'; import type { SalesIncomeStructureInsight, SalesSource } from '@/types/sales'; import type { DoughnutChartItem } from '@/types/shared'; -import { getSalesIncomeStructureComparisionMessage } from '@/utils/sales'; +import { getSalesIncomeStructureComparisonMessage } from '@/utils/sales'; import { cn, type ValueOf } from '@/utils/shared'; import { SalesSourceChartLegend } from '../sales-source'; @@ -43,7 +43,7 @@ export const DashboardSalesIncomeContentComparisonMessage = ({ topShare, deltaShare, }: DashboardSalesIncomeContentComparisonMessageProps) => { - const comparisonMessageTokens = getSalesIncomeStructureComparisionMessage({ + const comparisonMessageTokens = getSalesIncomeStructureComparisonMessage({ periodType, topType, topShare, diff --git a/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts b/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisonMessage.ts similarity index 86% rename from frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts rename to frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisonMessage.ts index c3d7d97d..cd954352 100644 --- a/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisionMessage.ts +++ b/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisonMessage.ts @@ -6,19 +6,19 @@ import { createMessageToken, type MessageToken } from '../dashboard'; const DELTA_SHARE_THRESHOLD = 3; -interface GetSalesIncomeStructureComparisionMessageArgs extends Omit< +interface GetSalesIncomeStructureComparisonMessageArgs extends Omit< SalesIncomeStructureInsight, 'showDeltaText' | 'showFocusText' > { periodType: ValueOf; } -export const getSalesIncomeStructureComparisionMessage = ({ +export const getSalesIncomeStructureComparisonMessage = ({ periodType, topType, topShare, deltaShare, -}: GetSalesIncomeStructureComparisionMessageArgs): MessageToken[] => { +}: GetSalesIncomeStructureComparisonMessageArgs): MessageToken[] => { if ( periodType === PERIOD_PRESETS.dayWeekMonth.today && Math.abs(deltaShare) >= DELTA_SHARE_THRESHOLD diff --git a/frontend/src/utils/sales/dashboard-sales-income/index.ts b/frontend/src/utils/sales/dashboard-sales-income/index.ts index 532c3670..aaf0c202 100644 --- a/frontend/src/utils/sales/dashboard-sales-income/index.ts +++ b/frontend/src/utils/sales/dashboard-sales-income/index.ts @@ -1 +1 @@ -export { getSalesIncomeStructureComparisionMessage } from './getSalesIncomeStructureComparisionMessage'; +export { getSalesIncomeStructureComparisonMessage } from './getSalesIncomeStructureComparisonMessage'; diff --git a/frontend/src/utils/sales/index.ts b/frontend/src/utils/sales/index.ts index cac6e3bf..9d31e573 100644 --- a/frontend/src/utils/sales/index.ts +++ b/frontend/src/utils/sales/index.ts @@ -5,4 +5,4 @@ export { getSalesPatternByDayMessage, } from './dashboard-sales-pattern'; export { getSalesCurrentComparisonMessage } from './dashboard-current-sales'; -export { getSalesIncomeStructureComparisionMessage } from './dashboard-sales-income'; +export { getSalesIncomeStructureComparisonMessage } from './dashboard-sales-income'; From 83d21cc20f9ca04fd64499ffb5c547b241e02b18 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Mon, 16 Feb 2026 00:46:19 +0900 Subject: [PATCH 91/96] =?UTF-8?q?chore:=20=EC=A1=B0=EA=B1=B4=EC=8B=9D=20?= =?UTF-8?q?=EC=82=BC=ED=95=AD=20=EC=97=B0=EC=82=B0=EC=9E=90=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../getSalesIncomeStructureComparisonMessage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisonMessage.ts b/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisonMessage.ts index cd954352..d8406a23 100644 --- a/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisonMessage.ts +++ b/frontend/src/utils/sales/dashboard-sales-income/getSalesIncomeStructureComparisonMessage.ts @@ -26,7 +26,7 @@ export const getSalesIncomeStructureComparisonMessage = ({ return [ createMessageToken('최근 7일 대비 '), createMessageToken( - `${topType} 비중이 ${deltaShare >= 0 && '+'}${formatNumber(deltaShare)}%p `, + `${topType} 비중이 ${deltaShare >= 0 ? '+' : ''}${formatNumber(deltaShare)}%p `, true, deltaShare >= 0 ? 'primary' : 'negative', ), From 247a210d7ecf8dfad4488d25cb708a556bd0b014 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Mon, 16 Feb 2026 00:48:24 +0900 Subject: [PATCH 92/96] =?UTF-8?q?chore:=20Peaktime=20->=20PeakTime=20?= =?UTF-8?q?=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/dashboard-sales-pattern/PeakTimeContent.tsx | 4 ++-- .../getSalesPatternPeaktimeMessage.ts | 6 +++--- frontend/src/utils/sales/dashboard-sales-pattern/index.ts | 2 +- frontend/src/utils/sales/index.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeContent.tsx b/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeContent.tsx index 0705c639..27b4508b 100644 --- a/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-pattern/PeakTimeContent.tsx @@ -5,7 +5,7 @@ import { DAY_OF_WEEK_LIST } from '@/constants/shared'; import type { GetDetailPeakTimeResponseDto } from '@/types/sales'; import { createPeakTimeSeries, - getSalesPatternPeaktimeMessage, + getSalesPatternPeakTimeMessage, } from '@/utils/sales'; import { cn } from '@/utils/shared'; @@ -30,7 +30,7 @@ export const PeakTimeContent = ({ beforeComparisonPeak, } = peakTimeData; - const peakTimeBriefingMessage = getSalesPatternPeaktimeMessage({ + const peakTimeBriefingMessage = getSalesPatternPeakTimeMessage({ todayPeak, comparisonPeak, beforeComparisonPeak, diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeaktimeMessage.ts b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeaktimeMessage.ts index 12367be0..0b5f9ea0 100644 --- a/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeaktimeMessage.ts +++ b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeaktimeMessage.ts @@ -2,17 +2,17 @@ import type { GetDashboardPeakTimeResponseDto } from '@/types/sales'; import { createMessageToken, type MessageToken } from '../dashboard'; -interface GetSalesPatternPeaktimeMessageArgs { +interface GetSalesPatternPeakTimeMessageArgs { todayPeak: GetDashboardPeakTimeResponseDto['todayPeak']; comparisonPeak: GetDashboardPeakTimeResponseDto['comparisonPeak']; beforeComparisonPeak: GetDashboardPeakTimeResponseDto['beforeComparisonPeak']; } -export const getSalesPatternPeaktimeMessage = ({ +export const getSalesPatternPeakTimeMessage = ({ todayPeak, comparisonPeak, beforeComparisonPeak, -}: GetSalesPatternPeaktimeMessageArgs): MessageToken[] => { +}: GetSalesPatternPeakTimeMessageArgs): MessageToken[] => { if (beforeComparisonPeak) { return [ createMessageToken('오늘은 '), diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/index.ts b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts index e618cbad..aec3990e 100644 --- a/frontend/src/utils/sales/dashboard-sales-pattern/index.ts +++ b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts @@ -1,3 +1,3 @@ -export { getSalesPatternPeaktimeMessage } from './getSalesPatternPeaktimeMessage'; +export { getSalesPatternPeakTimeMessage } from './getSalesPatternPeakTimeMessage'; export { createPeakTimeSeries } from './createPeakTimeSeries'; export { getSalesPatternByDayMessage } from './getSalesPatternByDayMessage'; diff --git a/frontend/src/utils/sales/index.ts b/frontend/src/utils/sales/index.ts index 9d31e573..3c90c909 100644 --- a/frontend/src/utils/sales/index.ts +++ b/frontend/src/utils/sales/index.ts @@ -1,6 +1,6 @@ export { getPeriodComparisonMessage } from './sales-overview'; export { - getSalesPatternPeaktimeMessage, + getSalesPatternPeakTimeMessage, createPeakTimeSeries, getSalesPatternByDayMessage, } from './dashboard-sales-pattern'; From bf4a4821eab7609ead7e8e90b316f27811341a88 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Mon, 16 Feb 2026 00:49:48 +0900 Subject: [PATCH 93/96] =?UTF-8?q?chore:=20type=20import=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sales/dashboard-current-sales/AveragePriceContent.tsx | 2 +- .../sales/dashboard-current-sales/OrderCountContent.tsx | 2 +- .../sales/dashboard-current-sales/RealSalesContent.tsx | 2 +- .../sales/dashboard-sales-income/OrderMethodContent.tsx | 2 +- .../sales/dashboard-sales-income/PaymentMethodContent.tsx | 2 +- .../sales/dashboard-sales-income/SalesTypeContent.tsx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx b/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx index 72129e63..8bf6c18e 100644 --- a/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/AveragePriceContent.tsx @@ -1,6 +1,6 @@ import { DASHBOARD_METRIC_CARDS, - type DASHBOARD_METRICS, + DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; import { AVERAGE_PRICE, SALES_UNIT } from '@/constants/sales'; diff --git a/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx b/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx index cc8ae8d5..82656ecc 100644 --- a/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/OrderCountContent.tsx @@ -1,6 +1,6 @@ import { DASHBOARD_METRIC_CARDS, - type DASHBOARD_METRICS, + DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; import { ORDER_COUNT, SALES_UNIT } from '@/constants/sales'; diff --git a/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx b/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx index 271d29a3..337b0762 100644 --- a/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx +++ b/frontend/src/components/sales/dashboard-current-sales/RealSalesContent.tsx @@ -1,6 +1,6 @@ import { DASHBOARD_METRIC_CARDS, - type DASHBOARD_METRICS, + DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; import { REAL_SALES, SALES_UNIT } from '@/constants/sales'; diff --git a/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx index 36d58b51..5ca7f662 100644 --- a/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/OrderMethodContent.tsx @@ -1,6 +1,6 @@ import { DASHBOARD_METRIC_CARDS, - type DASHBOARD_METRICS, + DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; import { ORDER_METHOD, SALES_SOURCE_COLORS } from '@/constants/sales'; diff --git a/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx b/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx index 5173dced..26e49de5 100644 --- a/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/PaymentMethodContent.tsx @@ -1,6 +1,6 @@ import { DASHBOARD_METRIC_CARDS, - type DASHBOARD_METRICS, + DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; import { PAYMENT_METHOD, SALES_SOURCE_COLORS } from '@/constants/sales'; diff --git a/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx index 0440334f..310cb20f 100644 --- a/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx +++ b/frontend/src/components/sales/dashboard-sales-income/SalesTypeContent.tsx @@ -1,6 +1,6 @@ import { DASHBOARD_METRIC_CARDS, - type DASHBOARD_METRICS, + DASHBOARD_METRICS, type ExtractCardCodes, } from '@/constants/dashboard'; import { SALES_SOURCE_COLORS, SALES_TYPE } from '@/constants/sales'; From 65ac399b1d060afa66e466e01e3c0c530258efc7 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Mon, 16 Feb 2026 00:50:41 +0900 Subject: [PATCH 94/96] =?UTF-8?q?chore:=20nullable=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/utils/shared/index.ts | 1 - frontend/src/utils/shared/nullable.ts | 3 --- 2 files changed, 4 deletions(-) delete mode 100644 frontend/src/utils/shared/nullable.ts diff --git a/frontend/src/utils/shared/index.ts b/frontend/src/utils/shared/index.ts index 467904d0..256dcb20 100644 --- a/frontend/src/utils/shared/index.ts +++ b/frontend/src/utils/shared/index.ts @@ -37,7 +37,6 @@ export { } from './doughnut-chart'; export { createPeriodTypeProvider } from './period-select'; -export type { Nullable } from './nullable'; export { assertNever } from './assertNever'; export { getCoordinate } from './getCoordinate'; export { diff --git a/frontend/src/utils/shared/nullable.ts b/frontend/src/utils/shared/nullable.ts deleted file mode 100644 index 4b1276e3..00000000 --- a/frontend/src/utils/shared/nullable.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type Nullable = { - [P in keyof T]?: T[P]; -}; From b7f33391fda5f50d8261b3148ab6d9ad3c497de0 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Mon, 16 Feb 2026 03:21:45 +0900 Subject: [PATCH 95/96] =?UTF-8?q?chore:=20git=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ernPeaktimeMessage.ts => getSalesPatternPeakTimeMessage1.ts} | 0 frontend/src/utils/sales/dashboard-sales-pattern/index.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename frontend/src/utils/sales/dashboard-sales-pattern/{getSalesPatternPeaktimeMessage.ts => getSalesPatternPeakTimeMessage1.ts} (100%) diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeaktimeMessage.ts b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeakTimeMessage1.ts similarity index 100% rename from frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeaktimeMessage.ts rename to frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeakTimeMessage1.ts diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/index.ts b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts index aec3990e..678077e6 100644 --- a/frontend/src/utils/sales/dashboard-sales-pattern/index.ts +++ b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts @@ -1,3 +1,3 @@ -export { getSalesPatternPeakTimeMessage } from './getSalesPatternPeakTimeMessage'; +export { getSalesPatternPeakTimeMessage } from './getSalesPatternPeakTimeMessage1'; export { createPeakTimeSeries } from './createPeakTimeSeries'; export { getSalesPatternByDayMessage } from './getSalesPatternByDayMessage'; From f405e8bdeeff4574afdc419ae0440d7571cb2436 Mon Sep 17 00:00:00 2001 From: lee0jae330 Date: Mon, 16 Feb 2026 03:22:10 +0900 Subject: [PATCH 96/96] =?UTF-8?q?chore:=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ernPeakTimeMessage1.ts => getSalesPatternPeakTimeMessage.ts} | 0 frontend/src/utils/sales/dashboard-sales-pattern/index.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename frontend/src/utils/sales/dashboard-sales-pattern/{getSalesPatternPeakTimeMessage1.ts => getSalesPatternPeakTimeMessage.ts} (100%) diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeakTimeMessage1.ts b/frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeakTimeMessage.ts similarity index 100% rename from frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeakTimeMessage1.ts rename to frontend/src/utils/sales/dashboard-sales-pattern/getSalesPatternPeakTimeMessage.ts diff --git a/frontend/src/utils/sales/dashboard-sales-pattern/index.ts b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts index 678077e6..aec3990e 100644 --- a/frontend/src/utils/sales/dashboard-sales-pattern/index.ts +++ b/frontend/src/utils/sales/dashboard-sales-pattern/index.ts @@ -1,3 +1,3 @@ -export { getSalesPatternPeakTimeMessage } from './getSalesPatternPeakTimeMessage1'; +export { getSalesPatternPeakTimeMessage } from './getSalesPatternPeakTimeMessage'; export { createPeakTimeSeries } from './createPeakTimeSeries'; export { getSalesPatternByDayMessage } from './getSalesPatternByDayMessage';