[Feature/#78] 워크스페이스 로고 이미지 업로드 API 연동 - #90
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough워크스페이스 로고 파일 업로드 기능을 추가했습니다. 클라이언트 미리보기와 FormData 기반 Changes
Sequence DiagramsequenceDiagram
participant User as 사용자
participant UI as 클라이언트(UI)
participant UploadAPI as 업로드 헬퍼
participant WorkspaceAPI as 워크스페이스 API
participant Server as 백엔드
rect rgba(0,128,0,0.5)
User->>UI: 이미지 파일 선택
UI->>UI: Object URL 생성(미리보기)
end
rect rgba(0,0,255,0.5)
User->>UI: 생성/저장 요청
UI->>UploadAPI: uploadImage(file) (FormData POST)
UploadAPI->>Server: POST /api/images/upload (FormData)
Server-->>UploadAPI: { data: { url: logoUrl } }
UploadAPI-->>UI: logoUrl 반환
end
rect rgba(128,0,128,0.5)
UI->>WorkspaceAPI: createWorkspace/updateWorkspace { logoUrl, ... }
WorkspaceAPI->>Server: 워크스페이스 생성/수정 요청
Server-->>WorkspaceAPI: 성공 응답
WorkspaceAPI-->>UI: 성공
UI->>UI: Object URL 해제 및 상태 정리
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
📚 Storybook 배포 완료
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/pages/workspace/Workspace.tsx (2)
56-59:⚠️ Potential issue | 🟡 Minor성공 시에도 모달 정리 로직을 공통으로 타게 해주세요.
여기서는
setCreateOpen(false)만 호출해서logoPreviewrevoke와 파일 상태 초기화가 빠집니다. 성공 경로도onCloseCreate()나 별도resetCreateForm()을 재사용해야 object URL과 숨겨진 폼 상태가 남지 않습니다.💡 제안
onSuccess: () => { void queryClient.invalidateQueries({ queryKey: ["my-workspaces"] }); - setCreateOpen(false); + onCloseCreate(); },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/workspace/Workspace.tsx` around lines 56 - 59, The success handler currently only calls setCreateOpen(false) which skips cleanup of object URLs and hidden form state; update the onSuccess path to call the shared cleanup routine (e.g., onCloseCreate() or resetCreateForm()) instead of or in addition to setCreateOpen(false) so logoPreview is revoked and file state is reset—locate the onSuccess block in Workspace.tsx and replace the direct setCreateOpen(false) with the existing cleanup function (onCloseCreate or resetCreateForm) to ensure consistent teardown.
226-262:⚠️ Potential issue | 🟡 Minor생성 중에는 파일 선택 UI도 같이 잠가두는 게 안전합니다.
mutationFn이 시작된 뒤에도 업로드 버튼과 미리보기 버튼이 살아 있어서, 사용자가 파일을 다시 고르면 화면에 보이는 preview와 실제로 업로드 중인 파일이 달라질 수 있습니다.creating동안 hidden input과 업로드 트리거도 함께 비활성화하는 편이 맞아요.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/pages/workspace/Workspace.tsx` around lines 226 - 262, Disable the file input and upload triggers while the mutation is in progress: when the mutation state variable creating is true, set the hidden file input (ref fileRef) to disabled, prevent/ignore clicks on the Upload Button (onClick openFile) and the preview button (the <button> that currently calls openFile), and add an appropriate aria-busy/aria-disabled state for accessibility; ensure onPickLogo cannot run when creating is true (guard at start of onPickLogo) so the visible logoPreview cannot diverge from the in-flight upload. Reference: fileRef, onPickLogo, openFile, logoPreview and the creating mutation state.
🧹 Nitpick comments (1)
src/lib/getImageUrl.ts (1)
6-8:new URL()조합 규칙을 한 번만 검증해주세요.
url이/uploads/...같은 루트 상대경로이고VITE_API_BASE_URL이https://api.example.com/v1/처럼 path prefix를 포함하면,new URL(url, BASE_URL)은/v1를 버린 URL을 만듭니다. 업로드 API가 절대경로/루트 상대경로/상대경로 중 어떤 형태를 돌려주는지 계약을 고정하거나, origin 기준 조합과 base-path 기준 조합을 분리하는 편이 더 안전해 보여요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/getImageUrl.ts` around lines 6 - 8, The current getImageUrl logic uses new URL(url, BASE_URL) unconditionally which mis-resolves root-relative paths when BASE_URL includes a path prefix; update getImageUrl to first classify url: if it is an absolute URL (starts with http:// or https://) return it as-is; if it is a root-relative path (starts with "/" but not "//") resolve it against the origin of BASE_URL (use new URL(url, new URL(BASE_URL).origin)) so the BASE_URL path prefix is not dropped; otherwise (relative paths like "./img.png" or "img.png") resolve them against the full BASE_URL as before (new URL(url, BASE_URL)); keep using the BASE_URL constant and new URL but branch based on url form to ensure correct composition.
🤖 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/api/workspace/org.ts`:
- Around line 52-60: Currently uploadImage(file) returns only the uploaded URL
and leaves no way to clean up if later createWorkspace() or updateWorkspace()
fails; modify the flow so uploadImage returns an identifier (e.g., imageId or
uploadToken) and implement/call an image delete/abort API when downstream save
fails, or change the server to provide an atomic upload+save endpoint; update
uploadImage to return the id/token and update callers
(createWorkspace/updateWorkspace) to call the new delete/abort API on failure so
uploaded files are cleaned up and no orphaned storage remains.
In `@src/components/workspace/WorkspaceCard.tsx`:
- Around line 22-29: WorkspaceCard currently only logs image load errors in the
img onError handler so a broken image icon is shown; add a local React state
(e.g., imageLoadFailed) in the WorkspaceCard component, set it to true inside
the img onError handler (reference the img element using getImageUrl and the
w.logoUrl prop), and use that state to hide the <img> and render the existing
placeholder instead; also reset imageLoadFailed to false when w.logoUrl changes
(useEffect watching w.logoUrl) so new logos will attempt to load again.
---
Outside diff comments:
In `@src/pages/workspace/Workspace.tsx`:
- Around line 56-59: The success handler currently only calls
setCreateOpen(false) which skips cleanup of object URLs and hidden form state;
update the onSuccess path to call the shared cleanup routine (e.g.,
onCloseCreate() or resetCreateForm()) instead of or in addition to
setCreateOpen(false) so logoPreview is revoked and file state is reset—locate
the onSuccess block in Workspace.tsx and replace the direct setCreateOpen(false)
with the existing cleanup function (onCloseCreate or resetCreateForm) to ensure
consistent teardown.
- Around line 226-262: Disable the file input and upload triggers while the
mutation is in progress: when the mutation state variable creating is true, set
the hidden file input (ref fileRef) to disabled, prevent/ignore clicks on the
Upload Button (onClick openFile) and the preview button (the <button> that
currently calls openFile), and add an appropriate aria-busy/aria-disabled state
for accessibility; ensure onPickLogo cannot run when creating is true (guard at
start of onPickLogo) so the visible logoPreview cannot diverge from the
in-flight upload. Reference: fileRef, onPickLogo, openFile, logoPreview and the
creating mutation state.
---
Nitpick comments:
In `@src/lib/getImageUrl.ts`:
- Around line 6-8: The current getImageUrl logic uses new URL(url, BASE_URL)
unconditionally which mis-resolves root-relative paths when BASE_URL includes a
path prefix; update getImageUrl to first classify url: if it is an absolute URL
(starts with http:// or https://) return it as-is; if it is a root-relative path
(starts with "/" but not "//") resolve it against the origin of BASE_URL (use
new URL(url, new URL(BASE_URL).origin)) so the BASE_URL path prefix is not
dropped; otherwise (relative paths like "./img.png" or "img.png") resolve them
against the full BASE_URL as before (new URL(url, BASE_URL)); keep using the
BASE_URL constant and new URL but branch based on url form to ensure correct
composition.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 433bdd93-08f8-4865-a400-86f3bbd9650e
📒 Files selected for processing (7)
src/api/workspace/org.tssrc/components/workspace/WorkspaceCard.tsxsrc/lib/axiosInstance.tssrc/lib/getImageUrl.tssrc/pages/workspace/Workspace.tsxsrc/pages/workspace/WorkspaceSetting.tsxsrc/types/workspace/workspace.ts
💤 Files with no reviewable changes (1)
- src/lib/axiosInstance.ts
📚 Storybook 배포 완료
|
|
P3: 이미지 미리보기 영역이 |
Seojegyeong
left a comment
There was a problem hiding this comment.
P4: 확인했습니다. 수고하셨습니다!
📚 Storybook 배포 완료
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
src/components/common/textarea/TextareaField.tsx (1)
42-55: 향후 개선 제안: 접근성 속성 추가 고려현재 변경과는 무관하지만,
Input.tsx와 비교했을 때 이 컴포넌트에는aria-invalid,aria-describedby같은 접근성 속성이 없어요. 만약 이 컴포넌트에도 에러 상태나 도움말 텍스트 기능이 필요하다면,Input.tsx와 동일한 패턴으로 확장하는 것을 고려해 주세요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/common/textarea/TextareaField.tsx` around lines 42 - 55, The TextareaField textarea lacks accessibility attributes present in Input.tsx; update the TextareaField component to accept and forward props for aria-invalid and aria-describedby (or a single props object like error and helpId similar to Input.tsx), add these props to the textarea element (e.g., aria-invalid={ariaInvalid} aria-describedby={ariaDescribedBy}), and update the component's prop types/interface and any places that render help/error text so the IDs used in aria-describedby match the help/error elements.src/pages/workspace/WorkspaceSetting.tsx (4)
75-77:useEffect의존성 배열에fetchWorkspaceDetail누락 검토 필요
fetchWorkspaceDetail이 컴포넌트 내부에 정의되어 있지만 의존성 배열에 포함되어 있지 않습니다. 현재는orgId가 의존성에 있어 동작에 문제는 없지만, ESLintreact-hooks/exhaustive-deps규칙에서 경고가 발생할 수 있습니다.
useCallback으로 감싸거나, 향후 유지보수를 위해 명시적으로 의존성을 관리하는 것을 권장합니다.♻️ useCallback 적용 예시
+ const fetchWorkspaceDetail = useCallback(async () => { + if (orgId === null) { + setErrorMsg("잘못된 워크스페이스ID 입니다"); + return; + } + // ... 기존 로직 + }, [orgId]); useEffect(() => { void fetchWorkspaceDetail(); - }, [orgId]); + }, [fetchWorkspaceDetail]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/workspace/WorkspaceSetting.tsx` around lines 75 - 77, The useEffect currently calls fetchWorkspaceDetail but doesn't list it in the dependency array, which will trigger react-hooks/exhaustive-deps warnings; fix by memoizing fetchWorkspaceDetail with useCallback (e.g., wrap the existing fetchWorkspaceDetail definition in useCallback and include its dependencies), then keep [orgId, fetchWorkspaceDetail] (or just fetchWorkspaceDetail if it already closes over orgId) as the useEffect dependency array so ESLint is satisfied and the effect updates correctly when the callback changes.
204-210: 숨겨진 파일 입력 필드에 접근성 속성 추가 권장화면 리더 사용자를 위해 hidden file input에도
aria-label또는id와 연결된<label>을 추가하면 접근성이 향상됩니다.♿ 접근성 개선 예시
<input ref={fileRef} type="file" accept="image/jpeg,image/jpg,image/png,image/webp" className="hidden" onChange={onPickLogo} + aria-label="워크스페이스 로고 이미지 선택" />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/workspace/WorkspaceSetting.tsx` around lines 204 - 210, The hidden file input referenced by fileRef with onChange={onPickLogo} lacks an accessibility label; add an accessible name by either adding aria-label (e.g., aria-label="Upload workspace logo") to the input or give it an id and render a visible or screen-reader-only <label htmlFor="..."> that triggers the input, ensuring screen reader users can activate the file picker; update the JSX around the input and any UI element that opens the file dialog to reference the new id/label.
23-165: 커스텀 훅으로 비즈니스 로직 분리 권장페이지 컴포넌트에 상태 관리, API 호출, 파일 처리 등 비즈니스 로직이 많이 포함되어 있습니다. 코딩 가이드라인에 따라
useWorkspaceSetting과 같은 커스텀 훅으로 분리하면 테스트 용이성과 재사용성이 향상됩니다.또한, 서버 상태 관리를 위해 React Query(
useMutation,useQuery)를 도입하면 캐싱, 리페치, 로딩/에러 상태 관리가 더 효율적으로 처리됩니다.As per coding guidelines, "페이지에 비즈니스 로직이 과도하지 않은지 확인. 커스텀 훅으로의 분리 여부 검토."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/workspace/WorkspaceSetting.tsx` around lines 23 - 165, The component currently mixes UI and business logic; extract state, API calls and file handling into a custom hook (e.g., useWorkspaceSetting) that encapsulates orgId derivation, fetchWorkspaceDetail, onSave, onDelete, onPickLogo, onResetLogo and related state (name, desc, loading, saving, deleting, serverLogoUrl, logoFile, logoPreview, uploading, errorMsg, fileRef) and return handlers and state for the WorkspaceSetting component to consume; inside the hook replace manual fetch/update/delete with React Query useQuery/useMutation for getWorkspace, updateWorkspace, deleteWorkspace and use a stable cleanup for URL.revokeObjectURL to avoid leaks, ensure the hook accepts workspaceId (or reads it via useParams) and exposes a ref or openFilePicker function for the file input.
92-96: 이미지 업로드 실패 시 에러 메시지 구체화 권장현재 이미지 업로드가 실패해도 "변경사항 저장에 실패했습니다"라는 일반적인 에러 메시지가 표시됩니다. 사용자가 어떤 단계에서 실패했는지 알기 어렵습니다.
업로드와 저장 단계를 분리하여 에러 메시지를 구체화하면 UX가 개선됩니다.
♻️ 에러 메시지 구체화 예시
if (logoFile) { setUploading(true); - nextLogoUrl = await uploadImage(logoFile); + try { + nextLogoUrl = await uploadImage(logoFile); + } catch (uploadError) { + toast.error(getAxiosMessage(uploadError, "이미지 업로드에 실패했습니다")); + return; + } finally { + setUploading(false); + } - setUploading(false); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/workspace/WorkspaceSetting.tsx` around lines 92 - 96, The image upload and workspace save are lumped together, so failed uploads surface as a generic "변경사항 저장에 실패했습니다" message; modify the save flow to call uploadImage(logoFile) inside its own try/catch/finally around the code that sets setUploading(true)/setUploading(false), capture and display a specific upload error (e.g., "이미지 업로드 실패: <error message>") and abort the save if upload fails, then perform the workspace save (e.g., saveWorkspace or the existing submit handler) in a separate try/catch that shows a distinct save failure message; reference the logoFile check, nextLogoUrl assignment, setUploading, and uploadImage when making these changes.
🤖 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/pages/workspace/WorkspaceSetting.tsx`:
- Around line 272-274: The TextareaField currently sets disabled using only
saving || deleting; update the disabled prop on the TextareaField component to
also include the uploading state (i.e., disabled={saving || deleting ||
uploading}) so it matches other inputs—locate the TextareaField instance in
WorkspaceSetting (the component with className="min-h-55 xl:min-h-93") and add
the uploading symbol to the disabled expression.
- Around line 218-226: The img element using getImageUrl(serverLogoUrl) has an
onError that only logs and leaves a broken image; update the onError handler in
the component rendering (the img near getImageUrl/serverLogoUrl) to set a
fallback state or src to the BuildingIcon (or render the BuildingIcon component)
when the image fails to load: capture e.currentTarget and replace its src with a
local fallback data URL or toggle a piece of state (e.g., logoLoadError) so the
JSX renders <BuildingIcon /> instead of the img; ensure you still use name for
alt text and avoid infinite onError loops by checking the current src before
replacing.
---
Nitpick comments:
In `@src/components/common/textarea/TextareaField.tsx`:
- Around line 42-55: The TextareaField textarea lacks accessibility attributes
present in Input.tsx; update the TextareaField component to accept and forward
props for aria-invalid and aria-describedby (or a single props object like error
and helpId similar to Input.tsx), add these props to the textarea element (e.g.,
aria-invalid={ariaInvalid} aria-describedby={ariaDescribedBy}), and update the
component's prop types/interface and any places that render help/error text so
the IDs used in aria-describedby match the help/error elements.
In `@src/pages/workspace/WorkspaceSetting.tsx`:
- Around line 75-77: The useEffect currently calls fetchWorkspaceDetail but
doesn't list it in the dependency array, which will trigger
react-hooks/exhaustive-deps warnings; fix by memoizing fetchWorkspaceDetail with
useCallback (e.g., wrap the existing fetchWorkspaceDetail definition in
useCallback and include its dependencies), then keep [orgId,
fetchWorkspaceDetail] (or just fetchWorkspaceDetail if it already closes over
orgId) as the useEffect dependency array so ESLint is satisfied and the effect
updates correctly when the callback changes.
- Around line 204-210: The hidden file input referenced by fileRef with
onChange={onPickLogo} lacks an accessibility label; add an accessible name by
either adding aria-label (e.g., aria-label="Upload workspace logo") to the input
or give it an id and render a visible or screen-reader-only <label
htmlFor="..."> that triggers the input, ensuring screen reader users can
activate the file picker; update the JSX around the input and any UI element
that opens the file dialog to reference the new id/label.
- Around line 23-165: The component currently mixes UI and business logic;
extract state, API calls and file handling into a custom hook (e.g.,
useWorkspaceSetting) that encapsulates orgId derivation, fetchWorkspaceDetail,
onSave, onDelete, onPickLogo, onResetLogo and related state (name, desc,
loading, saving, deleting, serverLogoUrl, logoFile, logoPreview, uploading,
errorMsg, fileRef) and return handlers and state for the WorkspaceSetting
component to consume; inside the hook replace manual fetch/update/delete with
React Query useQuery/useMutation for getWorkspace, updateWorkspace,
deleteWorkspace and use a stable cleanup for URL.revokeObjectURL to avoid leaks,
ensure the hook accepts workspaceId (or reads it via useParams) and exposes a
ref or openFilePicker function for the file input.
- Around line 92-96: The image upload and workspace save are lumped together, so
failed uploads surface as a generic "변경사항 저장에 실패했습니다" message; modify the save
flow to call uploadImage(logoFile) inside its own try/catch/finally around the
code that sets setUploading(true)/setUploading(false), capture and display a
specific upload error (e.g., "이미지 업로드 실패: <error message>") and abort the save
if upload fails, then perform the workspace save (e.g., saveWorkspace or the
existing submit handler) in a separate try/catch that shows a distinct save
failure message; reference the logoFile check, nextLogoUrl assignment,
setUploading, and uploadImage when making these changes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5050264f-cf9b-44e1-80ac-8531078333d6
📒 Files selected for processing (3)
src/components/common/input/Input.tsxsrc/components/common/textarea/TextareaField.tsxsrc/pages/workspace/WorkspaceSetting.tsx
📚 Storybook 배포 완료
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/pages/workspace/WorkspaceSetting.tsx (1)
48-76: 서버 상태와 업로드 상태 로직은 커스텀 훅으로 한 번 분리해두면 좋겠습니다.
fetchWorkspaceDetail,onSave,onPickLogo, object URL 정리,loading/saving/uploading/imageError까지 페이지 컴포넌트 안에 모여 있어서 상태 전이를 따라가기가 조금 무거워졌습니다.useWorkspaceSetting같은 훅으로 분리하고 서버 요청은 query/mutation 계층으로 옮기면 테스트와 재사용, 에러 처리가 더 단순해질 것 같습니다. As per coding guidelines, "상태 관리: 서버 상태(React Query)와 전역 상태(Zustand)의 분리 여부 확인. useMutation, useQuery의 올바른 사용 확인." 및 "구조와 책임 분리: 페이지에 비즈니스 로직이 과도하지 않은지 확인. 커스텀 훅으로의 분리 여부 검토."Also applies to: 81-166
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/workspace/WorkspaceSetting.tsx` around lines 48 - 76, The page component contains mixed UI and business logic—extract fetching/updating and upload state into a custom hook (e.g., create useWorkspaceSetting) that encapsulates fetchWorkspaceDetail, onSave, onPickLogo, image uploading state (loading/saving/uploading/imageError), and object URL cleanup; move server calls to React Query hooks (useQuery for getWorkspace and useMutation for update/upload) and have useWorkspaceSetting compose those hooks and expose state and handlers to the component, ensure object URLs are revoked in the hook’s cleanup/teardown logic, and update the component to only consume the hook’s returned state and methods.
🤖 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/pages/workspace/WorkspaceSetting.tsx`:
- Around line 220-229: Compute a resolvedLogoUrl by calling
getImageUrl(serverLogoUrl) before the JSX and use that value in the render
condition instead of serverLogoUrl; update the branch that currently renders
<img> to require resolvedLogoUrl && !imageError, use resolvedLogoUrl as the img
src, and keep the BuildingIcon fallback when resolvedLogoUrl is falsy (also
preserve the onError handler that calls setImageError). This touches
getImageUrl, serverLogoUrl, resolvedLogoUrl, imageError, setImageError, and
BuildingIcon.
- Around line 94-103: The current flow uploads via uploadImage before calling
updateWorkspace which can fail and leave an orphaned image; wrap the
upload+update sequence in a try/catch so that if updateWorkspace(orgId, {...})
throws, you call the image cleanup function (e.g., deleteImage or
removeUploadedImage) using nextLogoUrl to delete the just-uploaded file, and
rethrow or surface the original error; ensure
setUploading(true)/setUploading(false) are properly paired (use finally to clear
uploading) and only set nextLogoUrl into the payload when uploadImage succeeded
so the rollback path has the proper URL to delete.
---
Nitpick comments:
In `@src/pages/workspace/WorkspaceSetting.tsx`:
- Around line 48-76: The page component contains mixed UI and business
logic—extract fetching/updating and upload state into a custom hook (e.g.,
create useWorkspaceSetting) that encapsulates fetchWorkspaceDetail, onSave,
onPickLogo, image uploading state (loading/saving/uploading/imageError), and
object URL cleanup; move server calls to React Query hooks (useQuery for
getWorkspace and useMutation for update/upload) and have useWorkspaceSetting
compose those hooks and expose state and handlers to the component, ensure
object URLs are revoked in the hook’s cleanup/teardown logic, and update the
component to only consume the hook’s returned state and methods.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ff1f9214-2b86-494e-a962-951ff7dbb954
📒 Files selected for processing (1)
src/pages/workspace/WorkspaceSetting.tsx
📚 Storybook 배포 완료
|
🚨 관련 이슈
Closed #78
✨ 변경사항
✏️ 작업 내용
😅 미완성 작업
N/A
📢 논의 사항 및 참고 사항
Summary by CodeRabbit
New Features
Improvements
Style