Skip to content

[Refactor/#111] 사이드바 워크스페이스 영역 추가 및 리팩토링#150

Open
YermIm wants to merge 18 commits intodevelopfrom
refactor/#111
Open

[Refactor/#111] 사이드바 워크스페이스 영역 추가 및 리팩토링#150
YermIm wants to merge 18 commits intodevelopfrom
refactor/#111

Conversation

@YermIm
Copy link
Copy Markdown
Collaborator

@YermIm YermIm commented Mar 30, 2026

🚨 관련 이슈

close #111

✨ 변경사항

  • 🐞 BugFix Something isn't working
  • 💻 CrossBrowsing Browser compatibility
  • 🌏 Deploy Deploy
  • 🎨 Design Markup & styling
  • 📃 Docs Documentation writing and editing (README.md, etc.)
  • ✨ Feature Feature
  • 🔨 Refactor Code refactoring
  • ⚙️ Setting Development environment setup
  • ✅ Test Test related (storybook, jest, etc.)

✏️ 작업 내용

확장 상태 축소 상태
스크린샷 2026-03-31 오전 3 55 30 스크린샷 2026-03-31 오전 3 55 55

1. 선택한 워크스페이스 조회

  • 워크스페이스 영역 클릭 시 드롭다운으로 워크스페이스 리스트 확인 가능
  • 저장된 워크스페이스 id -> isCurrentWorkspace(조직 조회) -> 첫 번째 워크스페이스 순으로 선택한 워크스페이스 조회
  • savedWorkspaceQuery.isFetched를 추가하여 모든 데이터가 완벽히 로드된 시점에만 초기 상태 결정하도록 개선

2. 워크스페이스 선택 기능 및 동기화

  • 새로운 워크스페이스 선택 시, onSuccess 시점에만 UI 변경
  • 워크스페이스 변경 성공 시 관련 쿼리 동시에 무효화

3. 사이드바 UI/UX 리팩토링

  • 사이드바 관련 폴더명 소문자로 통일
  • 기본 상태 변경 (축소)
  • 서브메뉴 가려지는 현상 해결

😅 미완성 작업

N/A

📢 논의 사항 및 참고 사항

N/A

💬 리뷰어 가이드 (P-Rules)
P1: 필수 반영 (Critical) - 버그 가능성, 컨벤션 위반. 해결 전 머지 불가.
P2: 적극 권장 (Recommended) - 더 나은 대안 제시. 가급적 반영 권장.
P3: 제안 (Suggestion) - 아이디어 공유. 반영 여부는 드라이버 자율.
P4: 단순 확인/칭찬 (Nit) - 사소한 오타, 칭찬 등 피드백.

Summary by CodeRabbit

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 사이드바에 작업 공간 전환기 추가 — 드롭다운으로 현재/다른 작업 공간 선택 및 전환 지원
    • 선택 상태 저장·복원 기능 추가 — 서버에 저장된 이전 선택을 불러와 초기 선택에 반영
  • 스타일

    • 사이드바 기본 상태를 축소로 변경
    • 사이드바 레이아웃·간격·토글 위치 등 미세조정, 스택 순서(z-index) 조정
  • 버그 픽스 / 동작 개선

    • 초기 작업 공간 선택 로직 개선 — 저장된 선택, 현재 표시 플래그, 기본 순서로 우선순위 결정
    • 전환 시 상태 동기화 및 에러 처리(알림 표시) 개선

@YermIm YermIm self-assigned this Mar 30, 2026
@YermIm YermIm added ✨ Feature 기능 개발 🔨 Refactor 코드 리팩토링 📬 API 서버 API 통신 labels Mar 30, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 30, 2026

📚 Storybook 배포 완료

항목 링크
📖 Storybook https://69a147b60a56365d9e2185ef-cxvyriydhf.chromatic.com/
🔍 Chromatic https://www.chromatic.com/build?appId=69a147b60a56365d9e2185ef&number=175

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

사이드바 상단에 워크스페이스 전환 UI(WorkspaceSwitcher)를 추가하고, 저장된 워크스페이스 조회/저장 API를 도입했으며, 워크스페이스 선택 우선순위 및 사이드바 기본 축소 상태를 변경했습니다.

Changes

Cohort / File(s) Summary
API 클라이언트 확장
src/api/workspace/org.ts
getSavedWorkspace(GET /api/org/my/workspace) 및 saveSelectedWorkspace(POST /api/org/${orgId}/workspace) 추가. 반환형: saved 조회는 payload 반환, 저장은 Promise<void>.
레이아웃 / 워크스페이스 선택 로직
src/layout/main/MainLayout.tsx
savedWorkspace 쿼리 분리(["savedWorkspace"]) 및 ["my-workspaces"] 분리. 초기 선택 로직을 saved orgId → isCurrentWorkspace → 첫번째 순으로 변경하고 useEffect 의존성 업데이트.
타입 변경
src/types/workspace/workspace.ts
TWorkspaceisCurrentWorkspace: boolean 필드가 필수로 추가됨(타입 계약 변경).
사이드바 UI 추가/조정
src/components/sidebar/Sidebar.tsx, src/components/sidebar/WorkspaceSwitcher.tsx
WorkspaceSwitcher 컴포넌트 추가 및 사이드바 상단 렌더링. z-index·레이아웃·토글 위치 조정. 드롭다운에서 워크스페이스 선택 시 saveSelectedWorkspace 호출, 성공 시 전역 selectedOrgId 갱신 및 쿼리 무효화.
훅 초기 상태 변경
src/hooks/sidebar/useSidebar.ts
사이드바 기본 isCollapsed 초기값을 true로 변경(초기 축소 상태).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MainLayout
    participant API
    participant WorkspaceStore
    participant Sidebar
    participant WorkspaceSwitcher

    User->>MainLayout: 페이지 진입
    MainLayout->>API: getMyWorkspaces()
    MainLayout->>API: getSavedWorkspace()
    API-->>MainLayout: workspaces, savedWorkspace(orgId)
    MainLayout->>WorkspaceStore: setSelectedOrgId(resolvedOrgId)
    WorkspaceStore-->>Sidebar: selectedOrgId 반영
    Sidebar->>WorkspaceSwitcher: isCollapsed prop 전달
    User->>WorkspaceSwitcher: 드롭다운에서 워크스페이스 선택
    WorkspaceSwitcher->>API: saveSelectedWorkspace(newOrgId)
    API-->>WorkspaceSwitcher: 200 OK
    WorkspaceSwitcher->>WorkspaceStore: setSelectedOrgId(newOrgId)
    WorkspaceSwitcher->>API: invalidate ["my-workspaces","savedWorkspace"]
    WorkspaceSwitcher-->>User: UI 업데이트
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • jjjsun
  • Seojegyeong

세부 리뷰 포인트(요약)

  • API/타입: 서버가 실제로 isCurrentWorkspace를 반환하는지 확인하세요. 반환하지 않으면 클라이언트 가정에 의존하므로 백엔드와 계약을 맞추거나 클라이언트에서 안전한 폴백(예: falsy 처리)으로 방어하세요.
  • useEffect: MainLayout의 useEffect에 selectedOrgId가 포함되어 있어 불필요한 재실행 루프가 발생할 수 있습니다. 초기화 전용 로직으로 분리하거나 의존성 최소화(예: 로컬 초기화 플래그)로 재실행을 방지하세요.
  • WorkspaceSwitcher: mutation 실패 시 현재는 콘솔 로깅 및 토스트만 수행합니다. 네트워크/권한 오류에 대한 롤백(선택 복원) 또는 재시도 정책과 명확한 에러 UI를 추가하세요.
  • 초기 상태 변경: useSidebar의 기본 isCollapsed=true는 레이아웃·접근성·포커스 흐름에 영향이 큽니다. 회귀 테스트 수행하고 필요시 사용자 설정이나 저장된 상태로 초기값을 대체하세요.
  • 파일 경로 대소문자: @/components/sidebar/...로 import 경로 변경이 파일시스템 민감성(CI)에서 문제를 일으킬 수 있으니 실제 디렉토리명과 정확히 일치하는지 확인하세요.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 요약하고 있으며, 워크스페이스 영역 추가와 사이드바 리팩토링이라는 핵심 내용을 포함하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고 관련 이슈, 변경사항 유형, 상세한 작업 내용을 포함하고 있으며, 스크린샷으로 UI 변경을 시각적으로 설명하고 있습니다.
Linked Issues check ✅ Passed 코드 변경사항이 #111의 요구사항을 충족하고 있습니다: 사이드바 기본 상태 축소, 워크스페이스 선택 UI 추가, 워크스페이스 조회/선택 API 연동이 모두 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #111 이슈의 요구사항 범위 내에 있으며, 사이드바 UI/UX 리팩토링과 워크스페이스 선택 기능 구현에 필요한 변경들입니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/#111

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/Sidebar/WorkspaceSwitcher.tsx`:
- Around line 74-98: The dropdown trigger button that toggles isOpen (the
onClick using setIsOpen) must expose its state to assistive tech: add
aria-expanded (bound to isOpen) and aria-controls referencing a unique id on the
dropdown container (give the dropdown div an id, e.g. workspace-switcher-list or
similar) so screen readers know when it’s open; ensure the id used in
aria-controls matches the dropdown div id and keep current elements
(renderImage, ChevronIcon, currentWorkspace) unchanged.
- Around line 33-40: The saveWorkspace useMutation currently updates UI state
immediately and only invalidates ["my-workspaces"], leaving ["savedWorkspace"]
stale and providing no user feedback on failure; change the logic in the
useMutation defined around mutate/saveWorkspace so that UI state updates (calls
to setSelectedOrgId and setIsOpen) occur in onSuccess, call
queryClient.invalidateQueries for both ["my-workspaces"] and ["savedWorkspace"],
and implement onError to show a user-facing toast/alert (instead of only
console.error) to allow rollback/notification when saveSelectedWorkspace fails.

In `@src/layout/main/MainLayout.tsx`:
- Line 6: The import path casing for the Sidebar component in MainLayout.tsx is
incorrect: update the import of Sidebar (currently
"@/components/sidebar/Sidebar") to match the actual file casing
"@/components/Sidebar/Sidebar" so the module resolves on case-sensitive CI/OS;
locate the import statement in MainLayout.tsx and correct the path string to
exactly match the directory and filename casing used by the component
(Sidebar/Sidebar).
- Around line 19-22: The parallel queries getMyWorkspaces and getSavedWorkspace
cause the fallback selection to run before savedData arrives; update the
useCoreQuery call for getSavedWorkspace to also return its isFetched flag (e.g.,
const { data: savedData, isFetched: isSavedFetched } = useCoreQuery(...)) and
change the useEffect that sets the initial selectedOrgId (the block checking
selectedOrgId and applying fallback) so the fallback branch only runs when
isSavedFetched is true (i.e., guard the fallback logic with isSavedFetched) to
ensure savedData is applied when it resolves.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9b4e54a7-f9de-423b-b72f-4edd3330fb97

📥 Commits

Reviewing files that changed from the base of the PR and between bca2f66 and ef5ca9c.

📒 Files selected for processing (5)
  • src/api/workspace/org.ts
  • src/components/Sidebar/Sidebar.tsx
  • src/components/Sidebar/WorkspaceSwitcher.tsx
  • src/layout/main/MainLayout.tsx
  • src/types/workspace/workspace.ts

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/sidebar/Sidebar.tsx`:
- Line 10: The import of WorkspaceSwitcher in Sidebar.tsx fails because there is
no ./WorkspaceSwitcher file; fix by either creating a new WorkspaceSwitcher
component file exporting the component (e.g., export default function
WorkspaceSwitcher(...) or named export) in
src/components/sidebar/WorkspaceSwitcher.tsx and then importing it as used in
Sidebar.tsx, or update the import in Sidebar.tsx to point to the correct
existing module path/name (and adjust default vs named import to match the
export). If you use a barrel index export for the sidebar folder, ensure
WorkspaceSwitcher is exported there and update Sidebar.tsx to import from that
barrel instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0c797164-185c-4ace-9db8-485d0db99d3f

📥 Commits

Reviewing files that changed from the base of the PR and between ef5ca9c and f71ab47.

📒 Files selected for processing (4)
  • src/components/sidebar/Sidebar.tsx
  • src/components/sidebar/SidebarItem.tsx
  • src/components/sidebar/SubMenu.tsx
  • src/hooks/sidebar/useSidebar.ts

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/components/sidebar/WorkspaceSwitcher.tsx (3)

94-119: 드롭다운 외부 클릭 시 닫힘 처리가 없습니다.

현재 드롭다운이 열린 상태에서 외부 영역을 클릭해도 드롭다운이 닫히지 않습니다. UX 개선을 위해 외부 클릭 감지 로직을 추가하는 것을 권장합니다.

💡 외부 클릭 감지 구현 예시
import { useRef, useEffect, useState } from "react";

// 컴포넌트 내부에 추가
const dropdownRef = useRef<HTMLDivElement>(null);

useEffect(() => {
  const handleClickOutside = (event: MouseEvent) => {
    if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
      setIsOpen(false);
    }
  };

  if (isOpen) {
    document.addEventListener("mousedown", handleClickOutside);
  }
  return () => {
    document.removeEventListener("mousedown", handleClickOutside);
  };
}, [isOpen]);

// JSX에서 ref 연결
<div ref={dropdownRef} className="relative font-body1 mb-4">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/sidebar/WorkspaceSwitcher.tsx` around lines 94 - 119, The
dropdown in WorkspaceSwitcher.tsx doesn't close on outside clicks; add an
element ref (e.g., dropdownRef) and a useEffect that registers a mousedown
listener when isOpen is true which calls setIsOpen(false) if the event target is
outside the ref.current, and removes the listener on cleanup; attach the ref to
the wrapping div that renders the menu (the div using twMerge and mapping
otherWorkspaces) so clicking outside that element will close the dropdown.

49-61: 이미지 alt 속성이 구체적이지 않아 접근성이 부족합니다.

스크린 리더 사용자를 위해 alt 텍스트에 워크스페이스 이름을 포함해야 합니다.

♿ 접근성 개선 제안
  const renderImage = (workspace: TWorkspace) => (
    <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-component-sm overflow-hidden bg-bg-disabled/80 text-text-sub font-bold">
      {workspace?.logoUrl ? (
        <img
          src={workspace.logoUrl}
          className="w-full h-full object-cover"
-         alt="logo"
+         alt={`${workspace.name} 로고`}
        />
      ) : (
        workspace?.name?.[0] || "W"
      )}
    </div>
  );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/sidebar/WorkspaceSwitcher.tsx` around lines 49 - 61, The img
alt text in renderImage is not descriptive; update the <img> alt to include the
workspace name (e.g., `${workspace.name} logo` or `${workspace.name} avatar`)
and provide a sensible fallback when workspace.name is missing so screen readers
get context; modify the renderImage function to use workspace.name when
workspace.logoUrl is present and ensure the non-image branch still outputs an
accessible label (e.g., first letter with aria-label or similarly descriptive
text).

65-91: 드롭다운 토글 버튼에 ARIA 속성이 누락되었습니다.

스크린 리더 사용자가 드롭다운 상태를 인지할 수 있도록 aria-expandedaria-haspopup 속성을 추가해야 합니다. 또한 키보드로 Escape 키를 눌러 드롭다운을 닫을 수 있도록 지원하면 좋습니다.

♿ 접근성 속성 추가 제안
  <button
    type="button"
    onClick={() => setIsOpen(!isOpen)}
+   aria-expanded={isOpen}
+   aria-haspopup="listbox"
+   onKeyDown={(e) => {
+     if (e.key === "Escape" && isOpen) {
+       setIsOpen(false);
+     }
+   }}
    className={twMerge(
      "flex items-center rounded-component-md transition-colors hover:bg-bg-surface",
      isCollapsed
        ? "h-[55px] w-[55px] justify-center p-0 mx-auto"
        : "w-full p-3 gap-3",
    )}
  >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/sidebar/WorkspaceSwitcher.tsx` around lines 65 - 91, Add ARIA
attributes and Escape-key handling to the dropdown toggle: set
aria-expanded={isOpen} and aria-haspopup="true" on the button that calls
setIsOpen(!isOpen) (the same element rendering renderImage, currentWorkspace,
ChevronIcon and using isCollapsed), and implement an Escape key handler that
closes the menu by calling setIsOpen(false) when isOpen is true (either via an
onKeyDown on the button or a useEffect window keydown listener that checks for
"Escape"); ensure the aria attributes reflect the isOpen state and do not alter
existing visual logic around isCollapsed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/sidebar/WorkspaceSwitcher.tsx`:
- Around line 104-117: In WorkspaceSwitcher (the otherWorkspaces.map rendering),
the button elements lack an explicit type so they default to "submit" and can
trigger unintended form submits; update the mapped <button> used in the
otherWorkspaces loop (the handler that calls setSelectedOrgId, saveWorkspace,
setIsOpen and uses renderImage) to include type="button" so clicks do not submit
surrounding forms.
- Around line 25-31: currentWorkspace can be undefined when workspaces is empty,
which may cause runtime errors when renderImage(currentWorkspace) or other
accesses occur; update the WorkspaceSwitcher component to explicitly handle the
empty-workspaces case by early-returning a safe fallback UI (e.g., a placeholder
button or "No workspaces" message) or by deriving a non-undefined
currentWorkspace default before usage; adjust derivation around
workspaces.find(...) for currentWorkspace and otherWorkspaces and guard calls to
renderImage, workspace?.logoUrl, and workspace?.name in the render path so all
usages of currentWorkspace, otherWorkspaces, renderImage, workspaces, and
selectedOrgId are safe when workspaces.length === 0.
- Around line 33-41: The saveWorkspace mutation currently only console.error(s)
on failure and the UI is optimistically updated via setSelectedOrgId before the
mutation, so failures leave UI/server out of sync; update the onError handler of
the useMutation for saveWorkspace to show user-facing feedback (e.g., call your
toast/notification API with a clear message) and perform rollback by resetting
setSelectedOrgId to the previous org id (capture previous id before calling
setSelectedOrgId), and keep the onSuccess invalidation
(queryClient.invalidateQueries(["my-workspaces"])) as-is; reference
saveWorkspace (mutation), saveSelectedWorkspace (mutationFn), setSelectedOrgId
(state updater), onError (mutation option), and
onSuccess/queryClient.invalidateQueries when making these changes.

---

Nitpick comments:
In `@src/components/sidebar/WorkspaceSwitcher.tsx`:
- Around line 94-119: The dropdown in WorkspaceSwitcher.tsx doesn't close on
outside clicks; add an element ref (e.g., dropdownRef) and a useEffect that
registers a mousedown listener when isOpen is true which calls setIsOpen(false)
if the event target is outside the ref.current, and removes the listener on
cleanup; attach the ref to the wrapping div that renders the menu (the div using
twMerge and mapping otherWorkspaces) so clicking outside that element will close
the dropdown.
- Around line 49-61: The img alt text in renderImage is not descriptive; update
the <img> alt to include the workspace name (e.g., `${workspace.name} logo` or
`${workspace.name} avatar`) and provide a sensible fallback when workspace.name
is missing so screen readers get context; modify the renderImage function to use
workspace.name when workspace.logoUrl is present and ensure the non-image branch
still outputs an accessible label (e.g., first letter with aria-label or
similarly descriptive text).
- Around line 65-91: Add ARIA attributes and Escape-key handling to the dropdown
toggle: set aria-expanded={isOpen} and aria-haspopup="true" on the button that
calls setIsOpen(!isOpen) (the same element rendering renderImage,
currentWorkspace, ChevronIcon and using isCollapsed), and implement an Escape
key handler that closes the menu by calling setIsOpen(false) when isOpen is true
(either via an onKeyDown on the button or a useEffect window keydown listener
that checks for "Escape"); ensure the aria attributes reflect the isOpen state
and do not alter existing visual logic around isCollapsed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f2a87372-68d1-4edf-b931-ea428429b5fc

📥 Commits

Reviewing files that changed from the base of the PR and between f71ab47 and 5e8fd14.

📒 Files selected for processing (1)
  • src/components/sidebar/WorkspaceSwitcher.tsx

@YermIm YermIm requested review from Seojegyeong and jjjsun March 30, 2026 18:54
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/sidebar/WorkspaceSwitcher.tsx`:
- Around line 70-74: 현재 WorkspaceSwitcher 컴포넌트의 img 태그에 고정된 alt="logo"를 사용해
스크린리더 맥락이 부족하니, 이미지가 의미적(브랜딩)을 전달하면 workspace.name을 이용해 alt={`${workspace.name}
로고` 또는 `${workspace.name} logo`}처럼 동적으로 설정하고, 단순 장식용이면 빈 alt=""로 처리하도록 수정하세요; 대상
식별자는 WorkspaceSwitcher 컴포넌트의 img (src={workspace.logoUrl})와 workspace.name 변수를
사용하세요.
- Around line 26-30: The UI falls back to a different currentWorkspace when the
selectedOrgId is missing from workspaces, but the global selectedOrgId remains
stale; update the global state whenever selectedOrgId !== null but no matching
workspace exists. In WorkspaceSwitcher, after computing currentWorkspace (from
workspaces.find(...) || ... || workspaces[0]), if selectedOrgId !== null and no
workspace matched the original selectedOrgId, call the global setter used for
the org selection (e.g. setSelectedOrgId) with the fallback orgId
(currentWorkspace.orgId or workspaces[0].orgId) to synchronize global state and
UI. Ensure this runs only when workspaces is non-empty and avoid triggering if
selectedOrgId is already null.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a4f962ad-70c1-459c-a8b3-585cdc9a3ffa

📥 Commits

Reviewing files that changed from the base of the PR and between 6d43444 and 1de9c30.

📒 Files selected for processing (1)
  • src/components/sidebar/WorkspaceSwitcher.tsx

Comment on lines +26 to +30
const currentWorkspace =
workspaces.find((w) => w.orgId === selectedOrgId) ||
workspaces.find((w) => w.isCurrentWorkspace) ||
workspaces[0];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

선택된 워크스페이스가 목록에서 사라질 때 전역 상태와 UI가 불일치할 수 있어요

현재는 Line 26-30에서 표시용 currentWorkspace만 fallback으로 바꾸고, 전역 selectedOrgId는 그대로 남습니다. 이 상태가 유지되면 다른 화면/쿼리가 오래된 orgId를 계속 사용할 수 있습니다. selectedOrgId !== null인데 목록에 없는 경우에만 fallback orgId로 동기화해 주세요.

🔧 제안 코드
   const currentWorkspace =
     workspaces.find((w) => w.orgId === selectedOrgId) ||
     workspaces.find((w) => w.isCurrentWorkspace) ||
     workspaces[0];

+  useEffect(() => {
+    if (selectedOrgId === null || workspaces.length === 0) return;
+
+    const exists = workspaces.some((w) => w.orgId === selectedOrgId);
+    if (exists) return;
+
+    const fallback =
+      workspaces.find((w) => w.isCurrentWorkspace) || workspaces[0];
+    setSelectedOrgId(fallback.orgId);
+  }, [selectedOrgId, workspaces, setSelectedOrgId]);
+

As per coding guidelines, src/**: 1. 상태 관리: 서버 상태(React Query)와 전역 상태(Zustand)의 분리 여부 확인. useMutation, useQuery의 올바른 사용 확인.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/sidebar/WorkspaceSwitcher.tsx` around lines 26 - 30, The UI
falls back to a different currentWorkspace when the selectedOrgId is missing
from workspaces, but the global selectedOrgId remains stale; update the global
state whenever selectedOrgId !== null but no matching workspace exists. In
WorkspaceSwitcher, after computing currentWorkspace (from workspaces.find(...)
|| ... || workspaces[0]), if selectedOrgId !== null and no workspace matched the
original selectedOrgId, call the global setter used for the org selection (e.g.
setSelectedOrgId) with the fallback orgId (currentWorkspace.orgId or
workspaces[0].orgId) to synchronize global state and UI. Ensure this runs only
when workspaces is non-empty and avoid triggering if selectedOrgId is already
null.

Comment on lines +70 to +74
<img
src={workspace.logoUrl}
className="w-full h-full object-cover"
alt="logo"
/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

이미지 alt가 고정값("logo")이라 스크린리더 맥락이 부족합니다

워크스페이스별 의미를 전달하도록 alt를 이름 기반으로 넣거나, 장식용이면 alt=""로 처리해 주세요.

🔧 제안 코드
-        <img
-          src={workspace.logoUrl}
-          className="w-full h-full object-cover"
-          alt="logo"
-        />
+        <img
+          src={workspace.logoUrl}
+          className="w-full h-full object-cover"
+          alt={`${workspace.name} 로고`}
+        />

As per coding guidelines, src/**: 7. 접근성: 시맨틱 HTML, ARIA 속성 사용 확인.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<img
src={workspace.logoUrl}
className="w-full h-full object-cover"
alt="logo"
/>
<img
src={workspace.logoUrl}
className="w-full h-full object-cover"
alt={`${workspace.name} 로고`}
/>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/sidebar/WorkspaceSwitcher.tsx` around lines 70 - 74, 현재
WorkspaceSwitcher 컴포넌트의 img 태그에 고정된 alt="logo"를 사용해 스크린리더 맥락이 부족하니, 이미지가
의미적(브랜딩)을 전달하면 workspace.name을 이용해 alt={`${workspace.name} 로고` 또는
`${workspace.name} logo`}처럼 동적으로 설정하고, 단순 장식용이면 빈 alt=""로 처리하도록 수정하세요; 대상 식별자는
WorkspaceSwitcher 컴포넌트의 img (src={workspace.logoUrl})와 workspace.name 변수를 사용하세요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📬 API 서버 API 통신 ✨ Feature 기능 개발 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

♻️ [Refactor] 사이드바 워크스페이스 영역 추가 및 리팩토링

1 participant