feat: [sidebar] 사이드바 메뉴 즐겨찾기 기능 추가

- MenuFavorite 모델 생성 (menu_favorites 테이블)
- SidebarMenuService에 즐겨찾기 CRUD 메서드 추가
- MenuFavoriteController 생성 (toggle/reorder API)
- 사이드바 상단에 즐겨찾기 섹션 표시
- 메뉴 아이템에 별 아이콘 추가 (hover 시 표시, 토글)
- 최대 10개 제한, 리프 메뉴만 대상
This commit is contained in:
김보곤
2026-03-06 14:34:27 +09:00
parent ecd813c0b7
commit efd8d96156
8 changed files with 296 additions and 1 deletions

View File

@@ -4,6 +4,7 @@
use App\Models\Boards\Board;
use App\Models\Commons\Menu;
use App\Models\Commons\MenuFavorite;
use App\Models\Tenants\Department;
use App\Models\User;
use Illuminate\Support\Collection;
@@ -297,6 +298,100 @@ private static function hasMoreSpecificPrefixMenu(string $currentPath, string $m
return $result;
}
// ─── 즐겨찾기 기능 ───
private const MAX_FAVORITES = 10;
/**
* 사용자의 즐겨찾기 메뉴 목록 조회
*/
public function getFavoriteMenus(?int $userId = null): Collection
{
$userId = $userId ?? auth()->id();
if (! $userId) {
return collect();
}
$tenantId = auth()->user()?->tenant_id ?? 1;
return MenuFavorite::where('tenant_id', $tenantId)
->forUser($userId)
->with(['menu' => fn ($q) => $q->withoutGlobalScopes()])
->get()
->filter(fn ($fav) => $fav->menu && $fav->menu->is_active)
->values();
}
/**
* 즐겨찾기 메뉴 ID 배열 (별 아이콘 활성 판단용)
*/
public function getFavoriteMenuIds(?int $userId = null): array
{
$userId = $userId ?? auth()->id();
if (! $userId) {
return [];
}
$tenantId = auth()->user()?->tenant_id ?? 1;
return MenuFavorite::where('tenant_id', $tenantId)
->where('user_id', $userId)
->pluck('menu_id')
->toArray();
}
/**
* 즐겨찾기 토글 (추가/제거)
*/
public function toggleFavorite(int $userId, int $menuId): array
{
$tenantId = auth()->user()?->tenant_id ?? 1;
$existing = MenuFavorite::where('tenant_id', $tenantId)
->where('user_id', $userId)
->where('menu_id', $menuId)
->first();
if ($existing) {
$existing->delete();
return ['action' => 'removed'];
}
// 최대 개수 체크
$count = MenuFavorite::where('tenant_id', $tenantId)
->where('user_id', $userId)
->count();
if ($count >= self::MAX_FAVORITES) {
return ['action' => 'max_reached', 'max' => self::MAX_FAVORITES];
}
MenuFavorite::create([
'tenant_id' => $tenantId,
'user_id' => $userId,
'menu_id' => $menuId,
'sort_order' => $count,
]);
return ['action' => 'added'];
}
/**
* 즐겨찾기 순서 변경
*/
public function reorderFavorites(int $userId, array $menuIds): void
{
$tenantId = auth()->user()?->tenant_id ?? 1;
foreach ($menuIds as $order => $menuId) {
MenuFavorite::where('tenant_id', $tenantId)
->where('user_id', $userId)
->where('menu_id', $menuId)
->update(['sort_order' => $order]);
}
}
/**
* 메뉴 또는 자식 메뉴가 활성 상태인지 확인
*/