diff --git a/wtm-api/src/main/java/kr/co/accura/wtm/api/ProjectController.java b/wtm-api/src/main/java/kr/co/accura/wtm/api/ProjectController.java index bf376ec..ebc1a26 100644 --- a/wtm-api/src/main/java/kr/co/accura/wtm/api/ProjectController.java +++ b/wtm-api/src/main/java/kr/co/accura/wtm/api/ProjectController.java @@ -8,6 +8,8 @@ import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import kr.co.accura.wbx.spring.auth.WbxUserDetails; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import jakarta.validation.Valid; import java.util.List; import java.util.Map; @@ -45,8 +47,11 @@ public class ProjectController { } @GetMapping("/my") - public ResponseEntity> myProjects(@RequestParam Long userId) { - return ResponseEntity.ok(projectService.findMyProjects(userId)); + public ResponseEntity> myProjects( + @AuthenticationPrincipal WbxUserDetails user, + @RequestParam(required = false) Long userId) { + Long resolvedUserId = userId != null ? userId : user.getId(); + return ResponseEntity.ok(projectService.findMyProjects(resolvedUserId)); } @GetMapping("/{id}/members") diff --git a/wtm-api/src/main/resources/application.yml b/wtm-api/src/main/resources/application.yml index 1e78b44..077bbfa 100644 --- a/wtm-api/src/main/resources/application.yml +++ b/wtm-api/src/main/resources/application.yml @@ -36,7 +36,7 @@ wbx: admin-ui: enabled: true cors: - allowed-origins: ${CORS_ORIGINS:http://localhost:5173} + allowed-origins: ${CORS_ORIGINS:http://localhost:5173,http://localhost:5174} notification: sse-enabled: true diff --git a/wtm-frontend-react/src/core/api/utils.ts b/wtm-frontend-react/src/core/api/utils.ts new file mode 100644 index 0000000..a18b77d --- /dev/null +++ b/wtm-frontend-react/src/core/api/utils.ts @@ -0,0 +1,14 @@ +/** + * API 응답에서 안전하게 배열을 추출합니다. + * - 응답이 배열이면 그대로 반환 + * - 응답이 { items: [...] } 형태면 items 반환 + * - 그 외 빈 배열 반환 + */ +export function toArray(data: unknown): T[] { + if (Array.isArray(data)) return data as T[]; + if (data && typeof data === 'object' && 'items' in data) { + const items = (data as Record).items; + if (Array.isArray(items)) return items as T[]; + } + return []; +} diff --git a/wtm-frontend-react/src/core/components/AppSidebar.scss b/wtm-frontend-react/src/core/components/AppSidebar.scss index 1810f72..ea7ec25 100644 --- a/wtm-frontend-react/src/core/components/AppSidebar.scss +++ b/wtm-frontend-react/src/core/components/AppSidebar.scss @@ -59,4 +59,28 @@ border: none; background: transparent; } + + &__menu .p-panelmenu-panel { + .p-panelmenu-header-content, + .p-menuitem-content { + white-space: nowrap; + overflow: visible; + } + + .p-panelmenu-content { + overflow: visible; + } + + .p-menuitem-text { + display: inline !important; + } + } + + // 모바일에서 서브메뉴 텍스트 표시 보장 + &--mobile &__nav { + .p-menuitem-text, + .p-panelmenu-header-content span { + display: inline !important; + } + } } diff --git a/wtm-frontend-react/src/core/components/AppSidebar.tsx b/wtm-frontend-react/src/core/components/AppSidebar.tsx index e14a375..f0ad6d9 100644 --- a/wtm-frontend-react/src/core/components/AppSidebar.tsx +++ b/wtm-frontend-react/src/core/components/AppSidebar.tsx @@ -34,8 +34,6 @@ export default function AppSidebar({ visible, collapsed, mobile }: Props) { })); }, [currentUser, navigate]); - const sidebarWidth = collapsed ? `${LAYOUT.sidebarCollapsedWidth}px` : `${LAYOUT.sidebarWidth}px`; - const classNames = [ 'app-sidebar', visible && 'app-sidebar--visible', @@ -45,8 +43,12 @@ export default function AppSidebar({ visible, collapsed, mobile }: Props) { .filter(Boolean) .join(' '); + const style = mobile + ? undefined + : { width: collapsed ? `${LAYOUT.sidebarCollapsedWidth}px` : `${LAYOUT.sidebarWidth}px` }; + return ( -