Skip to content
Merged
Show file tree
Hide file tree
Changes from 117 commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
c23463b
chore: 임시커밋
mskwon02 Feb 13, 2026
8b25224
feat: dashboard metric card 상수 변경 및 관련 타입 제너릭 정의
lee0jae330 Feb 13, 2026
be20d12
chore: cherry-pick 오류 해결(타입가드)
mskwon02 Feb 13, 2026
62ec726
feat: 식자재 소진량 매출 랭킹 카드
mskwon02 Feb 15, 2026
c448d48
feat: 메뉴 주문 건수 카드
mskwon02 Feb 15, 2026
1c7d312
feat: 주문건수 가장 많은 메뉴 카드
mskwon02 Feb 15, 2026
a376748
feat: 메뉴별 매출 랭킹 카드
mskwon02 Feb 15, 2026
20ee6d2
chore: 랭킹 배지에 size 7인 smmd이름의 사이즈 속성 추가
mskwon02 Feb 15, 2026
df7f858
feat: nullable 타입 추가
mskwon02 Feb 15, 2026
ef370cb
feat: 대시보드의 메뉴파트에서 메뉴랭킹, 식자재 랭킹 UI에서 공통으로 사용되는 랭킹 아이템 타입 정의
mskwon02 Feb 15, 2026
98a4895
feat: 메뉴별 매출 랭킹 DTO 타입 정의
mskwon02 Feb 15, 2026
4809bbf
feat: 대시보드의 메뉴파트에서 메뉴랭킹, 식자재 랭킹 UI에서 공통으로 사용되는 랭킹 아이템 컴포넌트 구현
mskwon02 Feb 15, 2026
0bd7d6a
feat: 대시보드 메뉴의 메뉴별 매출 랭킹 카드 구현
mskwon02 Feb 15, 2026
9d8b24b
feat: 백엔드에서 보내주는 식자재별 소진량 dto 정의
mskwon02 Feb 15, 2026
9d591e5
chore: 대시보드 랭킹 테이블에서 사용하는 행 아이템 컴포넌트 주석 수정
mskwon02 Feb 15, 2026
33ab632
chore: 메뉴 매출 랭킹에서 사용하던 랭킹 테이블 컴포넌트를 식재료 소진량 랭킹에서도 사용할 수 있도록 수정
mskwon02 Feb 15, 2026
94d8af2
feat: 대시보드 메뉴분석에서 식재료 사용량 랭킹 카드 구현
mskwon02 Feb 15, 2026
065551a
chore: nullable한 특징에 맞게 유틸 함수의 파라미터 타입도 변형
mskwon02 Feb 15, 2026
5cec2f1
chore: 식자재별 소진량 랭킹 카드 DTO 주석 수정
mskwon02 Feb 15, 2026
9650a63
feat: 인기 메뉴 조합 랭킹에 사용되는 dto 정의
mskwon02 Feb 15, 2026
c952c16
feat: 인기 메뉴 조합 카드 콘텐츠 컴포넌트 구현
mskwon02 Feb 15, 2026
4145ea3
feat: 시간대별 메뉴 주문 건수, 인기 메뉴 조합 카드 새로 바뀐 dto 정의
mskwon02 Feb 15, 2026
f28e5d0
feat: 다음 시간 구하는 유틸 함수 정의
mskwon02 Feb 15, 2026
bc7f262
feat: 대시보드>메뉴분석>현재 주문건수 가장 많은 메뉴 카드
mskwon02 Feb 15, 2026
e321250
chore: 대시보드 랭킹 컴포넌트 css 일부 수정
mskwon02 Feb 15, 2026
88118f3
chore: 인기메뉴 조합 랭킹 카드를 새로 바뀐 대시보드용 dto(SSE용)를 사용하는 방식으로 변경ㅇ
mskwon02 Feb 15, 2026
5d34697
chore: 식재료 소진량 DTO 구조 변경에 맞추어 카드 수정
mskwon02 Feb 15, 2026
3e322ff
chore: 대시보드 카드 랭킹 테이블에서 양 옆 여백 생기는 문제 해결
mskwon02 Feb 15, 2026
709410b
chore: 폴더 구조 및 파일 위치 변경. 상수 분리
mskwon02 Feb 15, 2026
2e94468
chore: editCardWrapper 수정
mskwon02 Feb 15, 2026
2b9a00d
chore: 대시보드 메뉴분석 상수들 as const로 export
mskwon02 Feb 15, 2026
7627ae7
Merge remote-tracking branch 'origin/develop' into feature/#262-fe-da…
mskwon02 Feb 15, 2026
6335aef
chore: 편집모드 패널에 대시보드 메뉴분석 컨텐츠 사용
mskwon02 Feb 15, 2026
a699e1e
chore: null값이 props로 들어올 수 없기 때문에 불필요한 null 체크 제거
mskwon02 Feb 15, 2026
6bf2446
chore: PR리뷰반영-오타 수정
mskwon02 Feb 15, 2026
f7306a1
feat: 매출 추이 관련 DTO 추가
lee0jae330 Feb 16, 2026
4c5edbf
feat: 툴팁이 없는 bar line chart의 경우, hover 효과 제거
lee0jae330 Feb 17, 2026
f762ac0
feat: 매출 추이 type 수정
lee0jae330 Feb 17, 2026
b29662a
feat: 매출 추이 content 관련 상수 추가
lee0jae330 Feb 17, 2026
64083f2
feat: 매출 추이 content 관련 상수 추가
lee0jae330 Feb 17, 2026
f342e78
feat: 대시보드 편집 카드 wrapper 크기 계산 변경 및 css 수정
lee0jae330 Feb 17, 2026
0358dd4
feat: 대시보드 편집 카드에 매출 추이 관련 컴포넌트 추가
lee0jae330 Feb 17, 2026
6f3ea5a
chore: 배럴 파일 추가
lee0jae330 Feb 17, 2026
d588755
chore: nullish 연산자 관련 우선순위 변경
lee0jae330 Feb 17, 2026
57ae2c6
feat: 대시보드 목록 및 카드 레이아웃 조회 API 및 타입 정의 추가
lwjmcn Feb 17, 2026
28ec3f3
feat: 대시보드 목록 및 카드 조회를 위한 query option 정의
lwjmcn Feb 17, 2026
b9bff7a
feat: 대시보드 이름 수정 요청 API 및 타입 정의 추가
lwjmcn Feb 17, 2026
2042839
feat: 대시보드 삭제 API 및 타입 정의 추가
lwjmcn Feb 17, 2026
5048799
feat: 대시보드 탭 추가 API 및 타입 정의 추가
lwjmcn Feb 17, 2026
cf01d26
feat: 대시보드 카드 레이아웃 업데이트 API 및 타입 정의 추가
lwjmcn Feb 17, 2026
97548f8
chore: dto, query 타입 배럴 파일 추가
lwjmcn Feb 17, 2026
75fda4c
refactor: 대시보드 타입 dto에서 일반 타입으로 분리
lwjmcn Feb 17, 2026
897835e
feat: 대시보드 API 배럴 파일 추가 및 함수명 변경
lwjmcn Feb 17, 2026
c38887d
chore: 불필요한 코드 제거
lee0jae330 Feb 17, 2026
cdaa459
feat: Merge branch 'feature/#287-fe-dashboard-sales-trend' into featu…
lee0jae330 Feb 17, 2026
63716fc
fix: merge 도중 누락된 변경사항 반영
lee0jae330 Feb 17, 2026
09bbc71
feat: 대시보드 query option명 변경
lwjmcn Feb 17, 2026
1c160e8
feat: 대시보드 context에서 서버 상태 삭제 및 대시보드 목록 query 패치
lwjmcn Feb 17, 2026
c04c223
feat: 대시보드 탭 및 카드 목록 조회 API 연동
lwjmcn Feb 17, 2026
994befe
feat: 대시보드 페이지에 FetchBoundary 추가
lwjmcn Feb 17, 2026
93c29f0
fix: import 경로 단축
lwjmcn Feb 17, 2026
918f7aa
style: fallback이 전체 화면의 중앙에 뜨도록 스타일 변경
lwjmcn Feb 17, 2026
c15a7bd
feat: 대시보드 탭 추가/삭제/편집 mutation 기능 추가
lwjmcn Feb 17, 2026
f89ac3f
feat: shadcn skeleton 컴포넌트 추가
lwjmcn Feb 17, 2026
bd00d83
feat: 대시보드 메인 카드 레이아웃 suspense 추가
lwjmcn Feb 17, 2026
3b53f05
feat: 기본 대시보드 isDefault 값으로 초기화
lwjmcn Feb 17, 2026
d66369d
style: 불필요한 스타일 삭제
lwjmcn Feb 17, 2026
c2faa0a
chore: 불필요한 undefined 처리 삭제
lwjmcn Feb 17, 2026
59036be
fix: Promise.all에 undefined가 아닌 resolve 전달
lwjmcn Feb 17, 2026
d9b7fc1
fix: options에 잘못된 key 사용
lwjmcn Feb 17, 2026
2f90800
refactor: Array -> []로 코드 스타일 통일
lwjmcn Feb 17, 2026
b757428
chore: import 경로 단축
lwjmcn Feb 17, 2026
cf2e10e
style: error fallback 중간 정렬
lwjmcn Feb 17, 2026
d43c9a6
feat: Merge branch 'feature/#43-fe-dashboard-tabs-api' into feature/#…
lee0jae330 Feb 17, 2026
f15fba8
feat: 각 지표 상세분석 api query type 추가
lee0jae330 Feb 17, 2026
57376b9
feat: 상세분석 도메인 각 지표 GET 요청 추가
lee0jae330 Feb 17, 2026
bb7299d
feat: 각 탭별 대시보드 카드 각각의 query key 및 query option 추가
lee0jae330 Feb 17, 2026
3bbd798
feat: 각 지표별 카드 code 타입 가드 및 카테고리별 지표 카드 code 타입 가드 추가
lee0jae330 Feb 17, 2026
9346faa
feat: 각 지표별 query option 생성 커스텀훅 추가
lee0jae330 Feb 17, 2026
db28ed7
refactor: 매출 DTO 명칭과 메뉴 조합 타입명을 일관되게 정리
lee0jae330 Feb 17, 2026
5c8b876
feat: 대시보드 지표별 카드 컴포넌트와 API 조회 연결 추가
lee0jae330 Feb 17, 2026
0d95517
refactor: 기존에 있는 타입을 재사용하도록 변경
lee0jae330 Feb 18, 2026
6742968
refactor: orderMethod -> orderChannel로 통일
lee0jae330 Feb 18, 2026
d6e6135
chore: PR 리뷰 반영 - bar height 주석 정리
lee0jae330 Feb 18, 2026
e23c2be
chore: bar-line 차트 툴팁 활성화 관련 path 태그 주석 추가
lee0jae330 Feb 18, 2026
a1b74de
chore: 매출 추이 관련 지표 카드에서 라벨 제거
lee0jae330 Feb 18, 2026
6fae95f
chore: 요일별 매출 패턴 yGuideLine 제거
lee0jae330 Feb 18, 2026
4ee4580
feat: Merge branch 'develop' into feature/#302-fe-dashbard-card-ui
lee0jae330 Feb 18, 2026
f1845a0
feat: 매출 유입 구조 관련 api 대응을 위해 msw 핸들러 추가
lee0jae330 Feb 18, 2026
522488d
refactor: orderMethod -> orderChannel로 통일
lee0jae330 Feb 18, 2026
001cb3b
chore: takeout 단어 사이 언더바 추가
lee0jae330 Feb 18, 2026
71abc8d
feat: 각 지표 dto로 sales source의 value가 아닌 key가 옴에 따른 변경
lee0jae330 Feb 18, 2026
29c01e7
feat: 대시보드 지표 카드 조회 훅 추가
lee0jae330 Feb 18, 2026
7fbd6cd
feat: 대시보드 각 지표 구독 및 해지 dto 및 api 정의
lee0jae330 Feb 18, 2026
df988bc
feat: 대시보드 각 지표 구독, 해지 관련 커스텀 훅 추가
lee0jae330 Feb 18, 2026
65521a1
chore: 중복된 코드 제거 및 nullable하게 변경
lee0jae330 Feb 19, 2026
7e455be
feat: 시간대별 주문 관련 dto 추가
lee0jae330 Feb 19, 2026
8bbc320
feat: sse client 서로 다른 탭을 빠르게 전환할 시 발생하는 race condition 방지 코드 추가
lee0jae330 Feb 19, 2026
f52e6cf
style: 대시보드 지표 카드 스타일 수정
lee0jae330 Feb 19, 2026
47d2110
refactor: 인기 메뉴 조합 컴포넌트 관련 props 수정
lee0jae330 Feb 19, 2026
5c03411
refactor: 시간대별 주문 관련 컴포넌트 props 수정
lee0jae330 Feb 19, 2026
25cd8fd
feat: 인기메뉴 조합 empty view 추가
lee0jae330 Feb 19, 2026
4f32bd5
feat: 시간대별 주문 empty view 추가
lee0jae330 Feb 19, 2026
8cfb029
style: 대시보드 매출추이 컴포넌트 width, height 설정 및 상수 분리
lee0jae330 Feb 19, 2026
ec5ef88
feat: 요일별 매출 관련 Y값이 null인 경우 0으로 설정되게끔 코드 추가
lee0jae330 Feb 19, 2026
82ed7fe
feat: 피크타임 차트 데이터 생성 관련 로직 추가
lee0jae330 Feb 19, 2026
9a44535
feat: 매출추이 차트를 감싸는 div 추가
lee0jae330 Feb 19, 2026
95bc97b
fix: 요일 관련 index 계산 수정
lee0jae330 Feb 19, 2026
687a922
feat: sse 연결을 명시적으로 해제하는 api 메서드 추가
lee0jae330 Feb 19, 2026
c1291dd
feat: dashboard 지표들을 구독하는 커스텀 훅 추가 및 연동
lee0jae330 Feb 19, 2026
ae9776e
feat: 대시보드 sse 연결 및 각 지표들 실시간 데이터 업데이트 기능 추가 및 연동
lee0jae330 Feb 19, 2026
50a4b5c
feat: line chart 데이터 업데이트 순서 변경
lee0jae330 Feb 19, 2026
25ec448
chore: 간편결제 key값 수정
lee0jae330 Feb 19, 2026
e7d0df1
feat: 상세 분석 관련 msw 핸들러 추가
lee0jae330 Feb 19, 2026
0789a03
chore: 배럴 파일 추가
lee0jae330 Feb 19, 2026
9209c95
chore: auth 핸들러 수정
lee0jae330 Feb 19, 2026
5f255fa
chore: 간편결제 key값 변경에 따른 수정
lee0jae330 Feb 19, 2026
e1f1464
fix: merge conflict
lee0jae330 Feb 19, 2026
1bc70fe
chore: props interface로 정의
lee0jae330 Feb 19, 2026
da21d0c
feat: 매출 유입 구조 관련 empty 추가
lee0jae330 Feb 20, 2026
7f7411d
feat: 대시보드 매출 패턴 관련 폰트 사이즈 조정
lee0jae330 Feb 20, 2026
952eebe
feat: 메뉴 랭킹 관련 컴포넌트 empty view 추가
lee0jae330 Feb 20, 2026
dc6a5da
feat: 대시보드 매출패턴 관련 empty view 메세지 추가
lee0jae330 Feb 20, 2026
d72980f
feat: 메뉴 관련 랭킹 empty view 연동
lee0jae330 Feb 20, 2026
d324f4e
feat: 폰트 수정
lee0jae330 Feb 20, 2026
44da987
feat: 매장 등록 msw 수정
lee0jae330 Feb 20, 2026
d84fa7a
chore: 배럴 파일 추가
lee0jae330 Feb 20, 2026
d9bd344
feat: default card wrapper ux 수정
lee0jae330 Feb 20, 2026
b84d0cb
feat: fetchBoundary 변경
lee0jae330 Feb 20, 2026
a63c0a8
refactor: 불필요한 중복 제거
lee0jae330 Feb 20, 2026
a8eb63d
feat: 피크타임 캡션 스타일링 변경
lee0jae330 Feb 20, 2026
c0b5f26
chore: 버튼 padding 제거
lee0jae330 Feb 20, 2026
7fb67b0
feat: 불필요한 조건문 제거
lee0jae330 Feb 20, 2026
7d8af19
feat: path 수정
lee0jae330 Feb 20, 2026
8501cd4
fix: resolve merge conflict
lee0jae330 Feb 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
} from '@/components/menu';
import {
AveragePriceContent,
OrderChannelContent,
OrderCountContent,
OrderMethodContent,
PaymentMethodContent,
PeakTimeContent,
RealSalesContent,
Expand All @@ -24,16 +24,15 @@ import {
} from '@/constants/menu';
import {
AVERAGE_PRICE,
ORDER_CHANNEL,
ORDER_COUNT,
ORDER_METHOD,
PAYMENT_METHOD,
PEAK_TIME,
REAL_SALES,
SALES_BY_DAY,
SALES_TREND,
SALES_TYPE,
} from '@/constants/sales';

interface EditCardContentProps {
cardCode: MetricCardCode;
}
Expand All @@ -60,11 +59,11 @@ const {
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;
EXAMPLE_TOP_TYPE: ORDER_CHANNEL_EXAMPLE_TOP_TYPE,
EXAMPLE_TOP_SHARE: ORDER_CHANNEL_EXAMPLE_TOP_SHARE,
EXAMPLE_DELTA_SHARE: ORDER_CHANNEL_EXAMPLE_DELTA_SHARE,
EXAMPLE_ORDER_CHANNEL_DATA: ORDER_CHANNEL_EXAMPLE_ORDER_CHANNEL_DATA,
} = ORDER_CHANNEL;
const {
EXAMPLE_TOP_TYPE: PAYMENT_METHOD_EXAMPLE_TOP_TYPE,
EXAMPLE_TOP_SHARE: PAYMENT_METHOD_EXAMPLE_TOP_SHARE,
Expand Down Expand Up @@ -138,14 +137,14 @@ export const EditCardContent = ({ cardCode }: EditCardContentProps) => {
case 'SLS_07_02':
case 'SLS_07_03':
return (
<OrderMethodContent
<OrderChannelContent
cardCode={cardCode}
insight={{
topType: ORDER_METHOD_EXAMPLE_TOP_TYPE,
topShare: ORDER_METHOD_EXAMPLE_TOP_SHARE,
deltaShare: ORDER_METHOD_EXAMPLE_DELTA_SHARE,
topType: ORDER_CHANNEL_EXAMPLE_TOP_TYPE,
topShare: ORDER_CHANNEL_EXAMPLE_TOP_SHARE,
deltaShare: ORDER_CHANNEL_EXAMPLE_DELTA_SHARE,
}}
items={ORDER_METHOD_EXAMPLE_ORDER_METHOD_DATA}
items={ORDER_CHANNEL_EXAMPLE_ORDER_CHANNEL_DATA}
/>
);
case 'SLS_08_01':
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { Link } from 'react-router-dom';

import { useSuspenseQuery } from '@tanstack/react-query';

import CardsIcon from '@/assets/icons/cards.svg?react';
import { ROUTE_PATHS } from '@/constants/shared';
import { useDashboardTabsContext } from '@/hooks/dashboard';
import { dashboardOptions } from '@/services/dashboard/options';

export const DashboardEditButton = () => {
const { tabs, currentTabIndex } = useDashboardTabsContext();
const { data: tabs } = useSuspenseQuery(dashboardOptions.list);

const { currentDashboardId } = useDashboardTabsContext();

return (
<Link
to={{
pathname: ROUTE_PATHS.DASHBOARD.EDIT,
search: `?tab=${tabs[currentTabIndex]}`,
search: `?tab=${tabs.find((tab) => tab.id === currentDashboardId)?.name}`,
}}
aria-label="현재 탭의 지표카드 편집"
className="bg-grey-0 text-grey-700 body-medium-medium rounded-200 flex w-fit gap-200 border-none p-300 pl-250 shadow-none"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import { Suspense } from 'react';

import { Tabs } from '@/components/shared/shadcn-ui';
import { useDashboardTabsContext } from '@/hooks/dashboard';
import {
useDashboardSseConnection,
useDashboardTabsContext,
} from '@/hooks/dashboard';

import { DashboardHeader } from '../dashboard-header';
import { DashboardMain } from '../dashboard-main';
import { DashboardMainSuspense } from '../dashboard-main';

export const DashboardLayout = () => {
const { tabs, currentTabIndex, setCurrentTabIndex } =
const { currentDashboardId, setCurrentDashboardId } =
useDashboardTabsContext();
useDashboardSseConnection();

return (
<Tabs
value={tabs[currentTabIndex]}
onValueChange={(tabName) => setCurrentTabIndex(tabs.indexOf(tabName))}
value={currentDashboardId.toString()}
onValueChange={(value) => setCurrentDashboardId(Number(value))}
className="mt-8 w-265"
>
<DashboardHeader />
<DashboardMain />
<Suspense fallback={<DashboardMainSuspense />}>
<DashboardMain />
</Suspense>
</Tabs>
);
};
68 changes: 68 additions & 0 deletions frontend/src/components/dashboard/dashboard-main/DashboardCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { MetricCardCode } from '@/constants/dashboard';

import {
DashboardIngredientUsageRankingCard,
DashboardMenuSalesRankingCard,
DashboardPopularMenuCombinationCard,
DashboardTimeSlotMenuOrderCountCard,
} from '../dashboard-menu';
import {
DashboardAveragePriceCard,
DashboardIncomeStructureOrderChannelCard,
DashboardIncomeStructurePaymentMethodCard,
DashboardIncomeStructureSalesTypeCard,
DashboardOrderCountCard,
DashboardPeakTimeCard,
DashboardRealSalesCard,
DashboardSalesByDayCard,
DashboardSalesTrendCard,
} from '../dashboard-sales';

export const DashboardCard = ({ cardCode }: { cardCode: MetricCardCode }) => {
switch (cardCode) {
case 'SLS_01_01':
case 'SLS_01_02':
case 'SLS_01_03':
return <DashboardRealSalesCard cardCode={cardCode} />;
case 'SLS_02_01':
case 'SLS_02_02':
case 'SLS_02_03':
return <DashboardOrderCountCard cardCode={cardCode} />;
case 'SLS_03_01':
case 'SLS_03_02':
case 'SLS_03_03':
return <DashboardAveragePriceCard cardCode={cardCode} />;
case 'SLS_06_01':
case 'SLS_06_02':
case 'SLS_06_03':
return <DashboardIncomeStructureSalesTypeCard cardCode={cardCode} />;
case 'SLS_07_01':
case 'SLS_07_02':
case 'SLS_07_03':
return <DashboardIncomeStructureOrderChannelCard cardCode={cardCode} />;
case 'SLS_08_01':
case 'SLS_08_02':
case 'SLS_08_03':
return <DashboardIncomeStructurePaymentMethodCard cardCode={cardCode} />;
case 'SLS_09_04':
case 'SLS_10_07':
case 'SLS_11_07':
return <DashboardSalesTrendCard cardCode={cardCode} />;
case 'SLS_13_01':
return <DashboardPeakTimeCard cardCode={cardCode} />;
case 'SLS_14_06':
return <DashboardSalesByDayCard cardCode={cardCode} />;
case 'MNU_01_01':
case 'MNU_01_04':
case 'MNU_01_05':
return <DashboardMenuSalesRankingCard cardCode={cardCode} />;
case 'MNU_03_01':
return <DashboardTimeSlotMenuOrderCountCard cardCode={cardCode} />;
case 'MNU_04_01':
return <DashboardIngredientUsageRankingCard cardCode={cardCode} />;
case 'MNU_05_04':
return <DashboardPopularMenuCombinationCard cardCode={cardCode} />;
default:
return null;
}
};
25 changes: 11 additions & 14 deletions frontend/src/components/dashboard/dashboard-main/DashboardMain.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import { useDashboardTabsContext } from '@/hooks/dashboard';
import { gridItems } from '@/mocks/data/dashboard';
import {
useDashboardCardList,
useDashboardCardSubscription,
} from '@/hooks/dashboard';

import { DashboardEmptyContent } from './DashboardEmptyContent';
import { DashboardMainContent } from './DashboardMainContent';

export const DashboardMain = () => {
const { tabs, currentTabIndex } = useDashboardTabsContext();
const { cardList } = useDashboardCardList();

const mockedGridItems =
tabs[currentTabIndex] === '홈 대시보드' ? gridItems : null;
useDashboardCardSubscription({ cardList });

return (
<>
{mockedGridItems ? (
<DashboardMainContent cards={mockedGridItems} />
) : (
<DashboardEmptyContent />
)}
</>
);
if (!cardList || cardList.length === 0) {
return <DashboardEmptyContent />;
}

return <DashboardMainContent cards={cardList} />;
};
Original file line number Diff line number Diff line change
@@ -1,26 +1,58 @@
import { DASHBOARD_METRIC_CARDS } from '@/constants/dashboard';
import { useNavigate } from 'react-router-dom';

import { DefaultCardWrapper, FetchBoundary } from '@/components/shared';
import {
DASHBOARD_METRIC_CARDS,
isMenuMetricCardCode,
isSalesMetricCardCode,
type MetricCardCode,
} from '@/constants/dashboard';
import { ROUTE_PATHS } from '@/constants/shared';
import type { DashboardCard } from '@/types/dashboard';

import { DashboardCard as DashboardCardComponent } from './DashboardCard';

interface DashboardMainContentProps {
cards: DashboardCard[];
}

export const DashboardMainContent = ({ cards }: DashboardMainContentProps) => {
const navigate = useNavigate();

const handleClickChevronRightIcon = (cardCode: MetricCardCode) => {
const analysisPath = ROUTE_PATHS.ANALYSIS.BASE;
if (isSalesMetricCardCode(cardCode)) {
navigate(`${analysisPath}/${ROUTE_PATHS.ANALYSIS.SALES}`);
return;
}
if (isMenuMetricCardCode(cardCode)) {
navigate(`${analysisPath}/${ROUTE_PATHS.ANALYSIS.MENU}`);
return;
}
};

return (
<div className="mb-10 grid h-181 w-full grid-cols-3 grid-rows-3 gap-5">
{cards.map((item) => {
const card = DASHBOARD_METRIC_CARDS[item.cardCode];

return (
<div
key={`dashboard-card-${item.cardCode}`}
className="rounded-400 bg-special-card-bg p-5"
style={{
gridColumn: `${item.colNo} / span ${card.sizeX}`,
gridRow: `${item.rowNo} / span ${card.sizeY}`,
}}
>
카드 {item.cardCode}
</div>
<FetchBoundary key={`dashboard-card-${item.cardCode}`}>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[p4] 여기에 DefaultCardFetchBoundary 컴포넌트 사용할 수 있을 것 같네요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다

<DefaultCardWrapper
className="rounded-400 bg-special-card-bg size-full p-5"
style={{
gridColumn: `${item.colNo} / span ${card.sizeX}`,
gridRow: `${item.rowNo} / span ${card.sizeY}`,
}}
title={card.label}
hasChevronRightIcon
onClickChevronRightIcon={() =>
handleClickChevronRightIcon(item.cardCode)
}
>
<DashboardCardComponent cardCode={item.cardCode} />
</DefaultCardWrapper>
</FetchBoundary>
);
})}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Skeleton } from '@/components/shared/shadcn-ui';

export const DashboardMainSuspense = () => {
return (
<div className="mb-10 grid h-181 w-full grid-cols-3 grid-rows-3 gap-5">
{Array.from({ length: 9 }).map((_, index) => {
return (
<Skeleton
key={`dashboard-card-${index}`}
className="rounded-400 bg-special-card-bg"
/>
);
})}
</div>
);
};
1 change: 1 addition & 0 deletions frontend/src/components/dashboard/dashboard-main/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { DashboardMain } from './DashboardMain';
export { DashboardMainSuspense } from './DashboardMainSuspense';
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useSuspenseQuery } from '@tanstack/react-query';

import { IngredientUsageRankingCardContent } from '@/components/menu';
import {
DASHBOARD_METRICS,
type ExtractCardCodes,
} from '@/constants/dashboard';
import { useDashboardCardDetailQueryOption } from '@/hooks/dashboard';
import type { GetIngredientUsageRankingResponseDto } from '@/types/menu';

type DashboardIngredientUsageRankingCardCodes = ExtractCardCodes<
typeof DASHBOARD_METRICS.MENU.sections.INGREDIENT_CONSUMPTION_RANK.items.INGREDIENT_CONSUMPTION_RANK
>;
interface DashboardIngredientUsageRankingCardProps {
cardCode: DashboardIngredientUsageRankingCardCodes;
}

export const DashboardIngredientUsageRankingCard = ({
cardCode,
}: DashboardIngredientUsageRankingCardProps) => {
const { createCardDetailQuery } = useDashboardCardDetailQueryOption();

const queryOption =
createCardDetailQuery<GetIngredientUsageRankingResponseDto>(cardCode);

const { data } = useSuspenseQuery(queryOption);

return (
<IngredientUsageRankingCardContent
hasIngredient={data.hasIngredient}
items={data.items}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useSuspenseQuery } from '@tanstack/react-query';

import { MenuSalesRankingCardContent } from '@/components/menu';
import {
DASHBOARD_METRICS,
type ExtractCardCodes,
} from '@/constants/dashboard';
import { useDashboardCardDetailQueryOption } from '@/hooks/dashboard';
import type { GetMenuSalesRankingResponseDto } from '@/types/menu';

type DashboardMenuSalesRankingCardCodes = ExtractCardCodes<
typeof DASHBOARD_METRICS.MENU.sections.POPULAR_MENU.items.MENU_SALES_RANKING
>;

interface DashboardMenuSalesRankingCardProps {
cardCode: DashboardMenuSalesRankingCardCodes;
}

export const DashboardMenuSalesRankingCard = ({
cardCode,
}: DashboardMenuSalesRankingCardProps) => {
const { createCardDetailQuery } = useDashboardCardDetailQueryOption();

const queryOption =
createCardDetailQuery<GetMenuSalesRankingResponseDto>(cardCode);

const { data } = useSuspenseQuery(queryOption);

return <MenuSalesRankingCardContent items={data.items} />;
};
Loading