Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
a707163
feat: 메뉴, 카테고리 관련 api 작성
chaeyun-sim Jan 26, 2026
ba4f5fc
feat: 메뉴 관련 훅 구현
chaeyun-sim Jan 26, 2026
af6e426
feat: 메뉴 및 카테고리 api 연결 및 훅 분리
chaeyun-sim Jan 26, 2026
d18a15e
feat: MainMenuPage에서 카테고리가 없을때의 컴포넌트 분리
chaeyun-sim Jan 26, 2026
3497aaa
feat: queryOptions에 select 추가
chaeyun-sim Jan 26, 2026
bc42f68
fix: 메뉴 query, mutation 수정
chaeyun-sim Jan 26, 2026
911e10f
feat: 전체 메뉴 추출 구현
chaeyun-sim Jan 26, 2026
9c85113
feat: 메뉴 삭제 구현
chaeyun-sim Jan 26, 2026
796fa46
feat: 메뉴 등록 및 수정 구현
chaeyun-sim Jan 26, 2026
6460765
feat: 메뉴 상세 api 연결 및 css 수정
chaeyun-sim Jan 26, 2026
1f4eb3a
fix: 메뉴 카드 이미지 수정
chaeyun-sim Jan 26, 2026
115f35b
fix: Rootlayout 수정
chaeyun-sim Jan 26, 2026
d81a7ed
feat: 메뉴 추가 및 수정 함수 분리
chaeyun-sim Jan 27, 2026
65a9265
feat: Skeleton 추가
chaeyun-sim Jan 27, 2026
d7e7096
feat: 메뉴 순서 변경 코드 수정
chaeyun-sim Jan 27, 2026
97102ba
feat: 컴포넌트에 Skeleton 추가
chaeyun-sim Jan 27, 2026
f4c4ec1
Merge branch 'develop' into feature/menu-api
chaeyun-sim Jan 27, 2026
eeaa080
feat: 메뉴 이미지 lazy loading 구현
chaeyun-sim Jan 27, 2026
49768ab
fix: 순서변경 시 이미지 재렌더링 버그 수정
chaeyun-sim Jan 27, 2026
1e4349e
feat: 카테고리 버튼 hover 시 데이터 prefetch 구현
chaeyun-sim Jan 27, 2026
7600b44
feat: aria-label 추가 및 Image loading props 추가
chaeyun-sim Jan 27, 2026
9575d83
feat: queryClient에 staleTime과 gcTime 추가
chaeyun-sim Jan 27, 2026
1cad781
fix: Button loading props 삭제
chaeyun-sim Jan 27, 2026
8d4074d
fix: 이미지 수정
chaeyun-sim Jan 27, 2026
d60b164
feat: 사이드바 로고 크기 고정
chaeyun-sim Jan 28, 2026
7196822
fix: 로그아웃 구현, 이메일 표시
chaeyun-sim Jan 28, 2026
ad02f3d
fix: account queries에 select 추가
chaeyun-sim Jan 28, 2026
95de785
style: 코드 포맷팅 및 위치 수정
chaeyun-sim Jan 28, 2026
846e815
fix: 불필요한 컴포넌트 삭제
chaeyun-sim Jan 28, 2026
602adf9
fix: svg 및 json 압축
chaeyun-sim Jan 28, 2026
0de7b7a
fix: 무의미한 query select 삭제
chaeyun-sim Jan 29, 2026
ddfd95a
fix: 사업자등록증 이미지 크기 수정
chaeyun-sim Jan 29, 2026
acb6508
Merge branch 'develop' into feature/menu-api
chaeyun-sim Jan 29, 2026
6a4f6a8
fix: useStoreId 적용
chaeyun-sim Jan 30, 2026
f8ea561
fix: 모바일용 메뉴 상세와 생성 페이지 분리 및 라우팅 수정
chaeyun-sim Feb 1, 2026
08c6ec9
style: 타입 단언 수정
chaeyun-sim Feb 1, 2026
3c0499c
fix: 불필요한 타입 삭제 및 주석 삭제
chaeyun-sim Feb 1, 2026
2a12697
fix: 순서변경 시 에러 수정
chaeyun-sim Feb 1, 2026
de0ae09
fix: 메뉴 순서 변경 안내 수정
chaeyun-sim Feb 1, 2026
7ea8f2b
fix: CategoryModal 카테고리 목록과 버튼 사이 패딩 추가
chaeyun-sim Feb 2, 2026
5084aee
Merge branch 'develop' into feature/menu-api
chaeyun-sim Feb 2, 2026
28712e6
fix: DragList에 contents 적용해 메뉴 카드 그리드 레이아웃 복구
chaeyun-sim Feb 2, 2026
a345827
feat: DragList에 prepend 추가 및 카테고리 모달에 flex 추가
chaeyun-sim Feb 2, 2026
a5377bd
fix: useMenu 리팩토링
chaeyun-sim Feb 2, 2026
b2d5ea7
feat: 메뉴 페이지에 스켈레톤 추가
chaeyun-sim Feb 2, 2026
0d868ff
fix: 카테고리 수정 및 삭제 연결
chaeyun-sim Feb 2, 2026
3a11d77
fix: Sidebar에서 storeId 사용 수정
chaeyun-sim Feb 2, 2026
0190a2d
style: console.log 삭제
chaeyun-sim Feb 2, 2026
60e5864
fix: 메뉴 옵션 툴팁 위치 계산 수정
chaeyun-sim Feb 2, 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
6 changes: 4 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import GuestCreatePage from "@/pages/main/guest/create/GuestCreatePage";
import GuestPage from "@/pages/main/guest/GuestPage";
import MainDevicePage from "@/pages/main/owner/devices/MainDevicePage";
import MainInfoPage from "@/pages/main/owner/info/MainInfoPage";
import MenuDetailPage from "@/pages/main/owner/menus/[menuId]/MenuDetailPage";
import MenuDetailPage from "@/pages/main/owner/menus/[menuId]/[categoryId]/MenuDetailPage";
import MainMenuCategoryPage from "@/pages/main/owner/menus/category/MainMenuCategoryPage";
import MenuCreatePage from "@/pages/main/owner/menus/create/MenuCreatePage";
import MainMenuPage from "@/pages/main/owner/menus/MainMenuPage";
import MainSettingsPage from "@/pages/main/owner/settings/MainSettingsPage";
import PrivateRouteGuard from "@/pages/main/PrivateRouteGuard";
Expand Down Expand Up @@ -57,7 +58,8 @@ const router = createBrowserRouter(
<Route path="/devices" element={<MainDevicePage />} />
<Route path="/menus" element={<MainMenuPage />} />
<Route path="/menus/category" element={<MainMenuCategoryPage />} />
<Route path="/menus/:menuId" element={<MenuDetailPage />} />
<Route path="/menus/create" element={<MenuCreatePage />} />
<Route path="/menus/:menuId/:categoryId" element={<MenuDetailPage />} />
<Route path="/settings" element={<MainSettingsPage />} />
</Route>
<Route path="/guest/application" element={<GuestApplicationPage />} />
Expand Down
6 changes: 6 additions & 0 deletions src/api/categories/keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const CATEGORY = "CATEGORY";

export const CATEGORY_KEY = {
category: () => [CATEGORY],
categories: () => [CATEGORY, "list"],
};
31 changes: 31 additions & 0 deletions src/api/categories/mutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { mutationOptions } from '@tanstack/react-query';
import { instance } from '@/api';
import type { MoveRequest } from '@/types/api';
import type { Category } from '@/types/domain/menu';

export const categoryMutations = {
createCategory: () => mutationOptions({
mutationFn: async ({ storeId, data }: { storeId: string; data: Pick<Category, 'name'> }) => {
const response = await instance.post(`/stores/${storeId}/categories`, data);
return response.data;
},
}),
updateCategory: () => mutationOptions({
mutationFn: async ({storeId, categoryId, data}: {storeId: string; categoryId: string; data: Pick<Category, 'name'> }) => {
const response = await instance.put(`/stores/${storeId}/categories/${categoryId}`, data);
return response.data;
},
}),
deleteCategory: () => mutationOptions({
mutationFn: async ({storeId, categoryId}: {storeId: string; categoryId: string}) => {
const response = await instance.delete(`/stores/${storeId}/categories/${categoryId}`);
return response.data;
},
}),
moveCategories: () => mutationOptions({
mutationFn: async ({ storeId, sourceId, targetId, where }: { storeId: string; } & MoveRequest) => {
const response = await instance.post(`/stores/${storeId}/categories/${sourceId}/move/${targetId}`, { where });
return response.data;
},
}),
};
17 changes: 17 additions & 0 deletions src/api/categories/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { queryOptions } from '@tanstack/react-query';
import { instance } from '@/api';
import { CATEGORY_KEY } from '@/api/categories/keys';
import type { Category } from '@/types/domain/menu';

export const categoryQueries = {
getCategories: ({ storeId }: { storeId: string }) =>
queryOptions<{ categories: Category[] }, Error, Category[]>({
queryKey: CATEGORY_KEY.category(),
queryFn: async () => {
const response = await instance.get(`/stores/${storeId}/categories`);
return response.data;
},
enabled: !!storeId,
select: data => data?.categories
}),
};
7 changes: 7 additions & 0 deletions src/api/menus/keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const MENU = "MENU";

export const MENUS_KEY = {
menu: [MENU],
menus: (categoryId: string) => [MENU, categoryId],
menuDetail: (menuId: string) => [MENU, "detail", menuId],
};
61 changes: 61 additions & 0 deletions src/api/menus/mutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { mutationOptions } from '@tanstack/react-query';
import { instance } from '@/api';
import type { MoveRequest, PropsWithStoreId } from '@/types/api';
import type { MenuDetail, MenuOptionGroup } from '@/types/domain/menu';

type MenuDetailPayload = Omit<MenuDetail, 'menuId' | 'image' | 'menuOptionGroups'> & {menuOptionGroups: Omit<MenuOptionGroup, 'menuOptionGroupId'>[]};

export const menuMutations = {
createMenu: () => mutationOptions({
mutationFn: async ({ storeId, categoryId, data }: PropsWithStoreId<{ categoryId: string; data: { file: File, request: MenuDetailPayload; } }>) => {
const formData = new FormData();
formData.append("file", data.file);
formData.append("request", JSON.stringify(data.request));

const response = await instance.post(`/stores/${storeId}/categories/${categoryId}/menus`, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
return response.data;
},
}),
updateMenu: () => mutationOptions({
mutationFn: async ({ storeId, menuId, data }: PropsWithStoreId<{ menuId: string; data: MenuDetailPayload; }>) => {
const response = await instance.put(`/stores/${storeId}/menus/${menuId}`, data);
return response.data;
},
}),
updateMenuWithImage: () => mutationOptions({
mutationFn: async ({ storeId, menuId, data }: PropsWithStoreId<{ menuId: string; data: {file: File, request: MenuDetailPayload; } }>) => {
const formData = new FormData();
formData.append("file", data.file);
formData.append("request", JSON.stringify(data.request));

const response = await instance.put(`/stores/${storeId}/menus/${menuId}/with-image`, data, {
headers: {
"Content-Type": "multipart/form-data",
},
});
return response.data;
},
}),
deleteMenu: () => mutationOptions({
mutationFn: async ({ storeId, menuId, categoryId }: PropsWithStoreId<{ menuId: string; categoryId: string }>) => {
const response = await instance.delete(`/stores/${storeId}/categories/${categoryId}/menus/${menuId}`);
return response.data;
},
}),
multiDeleteMenus: () => mutationOptions({
mutationFn: async ({ storeId, data }: PropsWithStoreId<{ data: { menuIds: string[]} }>) => {
const response = await instance.delete(`/stores/${storeId}/menus/delete`, { data });
return response.data;
},
}),
moveMenus: () => mutationOptions({
mutationFn: async ({ storeId, sourceId, targetId, where }: PropsWithStoreId<MoveRequest>) => {
const response = await instance.post(`/stores/${storeId}/menus/${sourceId}/move/${targetId}`, { where });
return response.data;
},
}),
};
36 changes: 36 additions & 0 deletions src/api/menus/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { queryOptions } from "@tanstack/react-query";
import { instance } from "@/api";
import { MENUS_KEY } from "@/api/menus/keys";
import type { Menu, MenuDetail } from "@/types/domain/menu";

export const menuQueries = {
getMenus: ({ storeId, categoryId }: { storeId: string; categoryId: string }) =>
queryOptions<{ menus: Menu[] }, Error, Menu[]>({
queryKey: MENUS_KEY.menus(categoryId),
queryFn: async () => {
const response = await instance.get(`/stores/${storeId}/categories/${categoryId}/menus`);
return response.data;
},
enabled: !!storeId && !!categoryId && categoryId !== "all",
select: (data) => data?.menus,
}),
getMenuDetail: ({
storeId,
menuId,
categoryId,
}: {
storeId: string;
menuId: string;
categoryId: string;
}) =>
queryOptions<MenuDetail>({
queryKey: MENUS_KEY.menuDetail(menuId),
queryFn: async () => {
const response = await instance.get(
`/stores/${storeId}/categories/${categoryId}/menus/${menuId}`
);
return response.data;
},
enabled: !!storeId && !!menuId && !!categoryId,
}),
};
25 changes: 0 additions & 25 deletions src/assets/images/not-found.svg

This file was deleted.

Binary file added src/assets/images/not-found.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading