8bdc9a958f
사이드바 leaf 메뉴 옆 별표로 토글하고, 사이드바 최상단 '즐겨찾기'
섹션에 등록된 메뉴를 모아 보여준다. 테넌트 DB 별로 격리.
- V020 + StartupSchemaMigrator: USER_MENU_FAVORITES (USER_ID,
MENU_OBJID UNIQUE) 메타·테넌트 DB 동기 멱등 생성
- 백엔드: GET/POST /api/favorites/menus, DELETE
/api/favorites/menus/{menuObjid} — FavoritesController/Service
+ mapper/favorites.xml (MENU_INFO JOIN)
- 프론트: favoritesAPI 클라이언트 + FavoritesContext (낙관적
toggle/롤백) + (main)/layout 에 Provider 마운트
- AppLayout: leaf/sub-item 옆 Star 토글 (등록 시 primary 컬러,
미등록 시 0.35 dimmed) + 사이드바 최상단 favorites 섹션. uiMenus
의 leaf 평탄화 결과를 isFavorite 으로 필터링해 권한 필터/메뉴
클릭 핸들러를 그대로 재사용
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
31 lines
1.0 KiB
TypeScript
31 lines
1.0 KiB
TypeScript
import { apiClient } from "./client";
|
|
import { ApiResponse } from "@/types/commonCode";
|
|
|
|
/**
|
|
* 즐겨찾기 메뉴 API
|
|
*
|
|
* 백엔드 엔드포인트 ↔ DB-per-tenant 의 USER_MENU_FAVORITES 테이블.
|
|
* 응답 행은 MENU_INFO 와 JOIN 된 형태 (menu_name_kor / menu_url / menu_icon 등 포함).
|
|
*/
|
|
export const favoritesAPI = {
|
|
getList: async (): Promise<ApiResponse<Record<string, any>[]>> => {
|
|
const res = await apiClient.get<ApiResponse<Record<string, any>[]>>("/favorites/menus");
|
|
return res.data;
|
|
},
|
|
|
|
add: async (menuObjid: string | number): Promise<ApiResponse<Record<string, any>>> => {
|
|
const res = await apiClient.post<ApiResponse<Record<string, any>>>(
|
|
"/favorites/menus",
|
|
{ menu_objid: String(menuObjid) },
|
|
);
|
|
return res.data;
|
|
},
|
|
|
|
remove: async (menuObjid: string | number): Promise<ApiResponse<Record<string, any>>> => {
|
|
const res = await apiClient.delete<ApiResponse<Record<string, any>>>(
|
|
`/favorites/menus/${encodeURIComponent(String(menuObjid))}`,
|
|
);
|
|
return res.data;
|
|
},
|
|
};
|