[Feature/#385] 캠페인 상세 플랫폼 예산 수정 및 ads 훅 패턴 정리 - #392
Conversation
📝 WalkthroughWalkthrough플랫폼별 캠페인 예산 수정 API와 편집 모달을 추가했습니다. 예산 검증과 payload 생성을 플랫폼별로 분리했습니다. 광고 조회와 상태 변경은 React Query 기반 훅으로 전환했습니다. 캠페인 상세에 예산 편집과 일괄 상태 변경을 연결했습니다. Changes광고 관리 기능
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant CampaignDetail
participant EditPlatformBudgetModal
participant useUpdatePlatformBudget
participant BudgetAPI
participant QueryCache
CampaignDetail->>EditPlatformBudgetModal: 예산과 식별자 전달
EditPlatformBudgetModal->>useUpdatePlatformBudget: 검증된 예산 변수 제출
useUpdatePlatformBudget->>BudgetAPI: 플랫폼별 예산 수정 요청
BudgetAPI-->>useUpdatePlatformBudget: 수정된 예산 데이터 반환
useUpdatePlatformBudget->>QueryCache: 캠페인 상세 쿼리 무효화
QueryCache-->>CampaignDetail: 최신 예산 데이터 조회
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 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: 9
🧹 Nitpick comments (11)
src/hooks/ads/useUpdatePlatformBudget.ts (1)
33-52: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMETA와 GOOGLE 분기를 합칠 수 있습니다.
두 분기는 API 함수만 다릅니다. 검증과 payload 생성 로직은 같습니다. 맵으로 API 함수를 선택하면 중복이 줄고, 향후 검증 규칙을 한 곳에서 바꿀 수 있습니다.
♻️ 제안 리팩터
+ case "META": + case "GOOGLE": { + if (!vars.adCampaignId || !vars.activeBudgetType) { + throw new Error( + `${vars.providerType} 예산 수정 정보가 부족합니다.`, + ); + } + const updateBudget = + vars.providerType === "META" + ? updateMetaCampaignBudget + : updateGoogleCampaignBudget; + await updateBudget( + vars.adCampaignId, + buildMetaGoogleBudgetPayload(vars.activeBudgetType, vars), + ); + return; + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/ads/useUpdatePlatformBudget.ts` around lines 33 - 52, Refactor the META and GOOGLE branches in the update flow to share the existing validation and payload construction, selecting only the appropriate API function through a platform-to-function map. Preserve the current missing-information errors and invoke updateMetaCampaignBudget or updateGoogleCampaignBudget based on the selected platform.src/utils/ads/budgetEdit.ts (2)
107-115: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winnon-null assertion 대신 값 검증을 넣어 주세요.
values.dailyBudget!와values.lifetimeBudget!는 타입 검사만 통과시킵니다. 값이 실제로undefined이면 payload 필드가undefined가 되고, axios 직렬화에서 해당 키가 빠집니다. 결과적으로 빈 body가 PATCH로 전송됩니다.useUpdatePlatformBudget의 META/GOOGLE 분기에는 금액 검증이 없어서 이 경로가 열려 있습니다. NAVER 분기처럼 명시적으로 막는 편이 안전합니다.♻️ 제안 리팩터
export function buildMetaGoogleBudgetPayload( activeBudgetType: TPlatformBudgetType, values: { dailyBudget?: number; lifetimeBudget?: number }, ): IMetaGoogleBudgetUpdateRequest { if (activeBudgetType === "DAILY") { - return { dailyBudget: values.dailyBudget! }; + if (values.dailyBudget === undefined) { + throw new Error("일일 예산을 입력해 주세요."); + } + return { dailyBudget: values.dailyBudget }; } - return { lifetimeBudget: values.lifetimeBudget! }; + if (values.lifetimeBudget === undefined) { + throw new Error("전체 예산을 입력해 주세요."); + } + return { lifetimeBudget: values.lifetimeBudget }; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/ads/budgetEdit.ts` around lines 107 - 115, Replace the non-null assertions in buildMetaGoogleBudgetPayload with explicit validation that the selected dailyBudget or lifetimeBudget is defined before constructing the payload. Reject missing amounts using the same established validation behavior as the NAVER branch, while preserving the existing DAILY versus lifetimeBudget payload selection.
44-47: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
naverBudgetFormSchema는dailyBudgetFormSchema와 동일합니다.두 스키마의 shape가 완전히 같습니다. 지금은 중복입니다. NAVER 전용 규칙이 확정되기 전까지는 별칭으로 두거나
dailyBudgetFormSchema를 재사용해도 됩니다. 다만 향후 NAVER 규칙이 달라질 계획이라면 현재 분리가 타당합니다. 판단해 주세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/ads/budgetEdit.ts` around lines 44 - 47, Update naverBudgetFormSchema to reuse or alias dailyBudgetFormSchema because both currently have the same shape; preserve the naverBudgetFormSchema export for existing callers, unless a confirmed NAVER-specific validation rule requires keeping a separate schema.src/components/ads/EditPlatformBudgetModal.tsx (3)
190-195: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
form의key는 폼 상태를 초기화하지 않습니다.
useForm은 부모 컴포넌트에 있습니다.key를 바꾸면formDOM 요소와Controller하위 트리만 재생성됩니다. React Hook Form의 내부 상태는 유지됩니다. 실제 초기화는 Line 137-140의reset호출이 담당합니다.
BudgetAmountInput의 로컬 상태를 초기화하는 목적이라면 지금 코드로 충분합니다. 그 외 목적이라면key를 제거해도 동작이 같습니다. 의도를 확인해 주세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ads/EditPlatformBudgetModal.tsx` around lines 190 - 195, Review the purpose of the form key in the EditPlatformBudgetModal form around handleSubmit and onSubmit: do not rely on key changes to reset useForm state, since reset is handled by the existing reset call around the form initialization logic. Remove the key if it is only intended to reset form state; retain it only if it is specifically required to remount BudgetAmountInput local state.
137-140: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value모달을 다시 열 때 이전 값이 남을 수 있는지 확인해 주세요.
reset은isOpen이true이고budget이 있을 때만 실행됩니다. 같은budget으로 모달을 닫고 다시 열면isOpen이false → true로 바뀌므로 effect가 다시 실행됩니다. 이 경로는 정상입니다.다만 저장 실패 후 모달을 닫지 않은 상태에서는 입력값이 그대로 유지됩니다. 이 동작이 의도된 것인지 확인해 주세요. 재시도를 위해 값을 유지하는 편이 보통 더 좋습니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ads/EditPlatformBudgetModal.tsx` around lines 137 - 140, Verify the reset behavior in the useEffect around resolveBudgetEditDefaultValues: reopening the modal with the same budget must reset values when isOpen changes to true, while keeping user-entered values intact after a save failure when the modal remains open. Preserve the current dependency behavior unless it violates these requirements.
44-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReact 19 ref prop 방식으로 단순화하자.
프로젝트가 React 19.2+라서
forwardRef없이ref를 명시적인 props로 받을 수 있다. 새 컴포넌트에서는IBudgetAmountInputProps에ref?: React.Ref<HTMLInputElement>을 잡고,BudgetAmountInput파라미터에서{ ref, ... }로 전달하는 방식이 더 간편하다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ads/EditPlatformBudgetModal.tsx` around lines 44 - 48, Update BudgetAmountInput to use the React 19 ref prop pattern instead of forwardRef: add an optional React.Ref<HTMLInputElement> ref to IBudgetAmountInputProps, receive ref alongside the other destructured props in BudgetAmountInput, and remove the forwardRef wrapper while preserving the existing input ref behavior.src/components/ads/CampaignPlatformSection.tsx (2)
46-52: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
budgetEditDisabledReason계산을 단순화할 수 있습니다.3중 삼항 연산자를 쓰고 있습니다.
editCheck.ok가false일 때만 사유가 필요합니다. 조건을 하나로 합치면 읽기 쉬워집니다.♻️ 제안 리팩터
- const budgetEditDisabledReason = !onEditBudget - ? undefined - : editCheck.ok - ? undefined - : BUDGET_EDIT_BLOCK_MESSAGES[editCheck.reason]; + const budgetEditDisabledReason = + onEditBudget && !editCheck.ok + ? BUDGET_EDIT_BLOCK_MESSAGES[editCheck.reason] + : undefined;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ads/CampaignPlatformSection.tsx` around lines 46 - 52, Update budgetEditDisabledReason in the CampaignPlatformSection logic to return a reason only when onEditBudget is present and editCheck.ok is false; otherwise return undefined. Replace the nested ternary with a single combined condition while preserving the existing BUDGET_EDIT_BLOCK_MESSAGES[editCheck.reason] lookup.
84-104: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value게이지가 2개 이상이면 동일한 수정 버튼이 반복됩니다.
onEditBudget은 플랫폼 단위 콜백입니다. 그런데 버튼을gauges.map안에서 렌더합니다. 현재mapPlatformProjectBudgetToGauges는 슬라이스 1개만 반환하므로 문제가 없습니다. 다만 향후 게이지가 여러 개로 늘어나면 같은 동작의 버튼이 중복 렌더됩니다.첫 번째 게이지에만
headerAction을 전달하거나, 버튼을 섹션header로 옮기는 방법을 고려해 주세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ads/CampaignPlatformSection.tsx` around lines 84 - 104, Update the gauges.map rendering in CampaignPlatformSection so the platform-level onEditBudget action is rendered only once, such as by passing headerAction to the first gauge and omitting it from subsequent PlatformBudgetItem instances. Preserve the existing disabled state, title, and button behavior.src/pages/ads/list/CampaignDetail.tsx (1)
364-371: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value
onEditBudget콜백을useCallback으로 감싸는 것을 검토해 주세요.지금 인라인 화살표 함수가 매 렌더마다 새로 생성됩니다.
CampaignPlatformSection은memo가 아니므로 현재 렌더 비용 차이는 없습니다. 다만platform을 인자로 받는 핸들러 하나를useCallback으로 만들면, 향후memo를 적용할 때 그대로 효과를 얻습니다.♻️ 제안 리팩터
+ const handleEditBudget = useCallback( + (platform: TPlatform) => { + const budget = budgetByPlatform.get(platform); + if (budget) setBudgetEditTarget(budget); + }, + [budgetByPlatform], + );- onEditBudget={() => { - const budget = budgetByPlatform.get(platform); - if (budget) setBudgetEditTarget(budget); - }} + onEditBudget={() => handleEditBudget(platform)}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/ads/list/CampaignDetail.tsx` around lines 364 - 371, Update the CampaignDetail render flow to create the budget edit handler with useCallback instead of defining the onEditBudget inline for each CampaignPlatformSection. Make the callback accept the platform, retrieve the matching budget from budgetByPlatform, and preserve the existing setBudgetEditTarget behavior, then pass the stable handler to the section.src/utils/ads/projectBudget.ts (1)
90-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuemock 데이터의
activeBudgetType결정 방식을 확인해 주세요.
index % 2로DAILY와LIFETIME을 번갈아 지정합니다. 플랫폼 배열의 순서에 따라 결과가 바뀝니다. 두 타입을 모두 확인하려는 의도라면 적절합니다. 다만 mock이므로 실데이터 연동 시 제거 대상임을 주석으로 남겨 두면 좋습니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/ads/projectBudget.ts` around lines 90 - 94, Review the mock-data assignment of activeBudgetType in the surrounding budget-item construction and confirm that alternating DAILY and LIFETIME by index is intentional for covering both types. Add a concise comment marking this mock-only behavior as something to remove when real data integration is implemented, without changing the current assignment.src/components/ads/AdDetailContent.tsx (1)
9-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win내부 import에
@/alias를 사용하세요.Line 9부터 Line 12까지는 상대 경로를 사용합니다.
@/components/common/...경로로 변경하세요. 이 변경은 프로젝트 import 규칙을 위반합니다.수정 예시
-import Badge from "../common/badge/Badge"; -import Button from "../common/button/Button"; -import Modal from "../common/modal/Modal"; -import ModalContent from "../common/modal/ModalContent"; +import Badge from "`@/components/common/badge/Badge`"; +import Button from "`@/components/common/button/Button`"; +import Modal from "`@/components/common/modal/Modal`"; +import ModalContent from "`@/components/common/modal/ModalContent`";As per coding guidelines, use
@/alias for all imports.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/ads/AdDetailContent.tsx` around lines 9 - 12, Update the internal imports in AdDetailContent.tsx for Badge, Button, Modal, and ModalContent to use the "`@/components/common/`..." alias paths instead of relative paths, while preserving the existing imported symbols.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/ads/CampaignPlatformSection.tsx`:
- Around line 89-103: Move the disabled-state explanation from the Button’s
title to an accessible wrapper or visible helper text so
budgetEditDisabledReason remains available when isBudgetEditDisabled is true.
Update the budget edit control around onEditBudget without changing the existing
disabled behavior or styling.
In `@src/components/ads/EditPlatformBudgetModal.tsx`:
- Around line 174-180: Update the visible h2 in EditPlatformBudgetModal to
include aria-hidden so screen readers do not announce the title twice; keep the
Modal title prop as the sole accessible name.
In `@src/hooks/ads/useUpdateAdStatus.ts`:
- Around line 26-30: Update the batch status mutation in
src/hooks/ads/useUpdateAdStatus.ts lines 26-30 and
src/hooks/ads/useUpdateCampaignStatus.ts lines 30-34 so partial failures do not
leave successfully updated items with stale list caches. Replace the per-item
Promise.all approach with an atomic batch API, or track successful items and
individually refetch/update their caches after a failure while preserving
useCoreMutation invalidation behavior.
In `@src/pages/ads/list/CampaignDetail.tsx`:
- Around line 422-433: Update the batch mutation used by useUpdateAdStatus to
await parallel updateAdStatus calls with Promise.allSettled instead of
Promise.all, and return or propagate both success and failure counts. Adjust the
CampaignDetail onConfirm/useControlModal flow to consume these counts and
clearly notify the page of partial or complete success/failure while preserving
the existing ad selection and status payload logic.
- Around line 477-487: Update the CampaignDetail modal state flow so closing
EditPlatformBudgetModal does not immediately clear budgetEditTarget: introduce
or reuse separate open-state control, set it false in onClose, and clear the
target only after the modal’s exit animation completes. Preserve the existing
budget, orgId, and projectId values until unmount so Modal can restore focus and
run its closing animation.
In `@src/types/ads/budget.ts`:
- Around line 2-5: Update IMetaGoogleBudgetUpdateRequest to model an exclusive
union of the budget fields: require either dailyBudget or lifetimeBudget, while
disallowing the other field in each variant. Ensure empty requests and requests
containing both fields fail TypeScript validation.
In `@src/utils/ads/budgetEdit.ts`:
- Around line 107-115: Prevent undefined budget amounts in both update paths: in
src/utils/ads/budgetEdit.ts lines 107-115, update buildMetaGoogleBudgetPayload
to remove the non-null assertions and explicitly throw when the field matching
activeBudgetType is undefined; in src/hooks/ads/useUpdatePlatformBudget.ts lines
33-52, add the same activeBudgetType-specific amount validation to the META and
GOOGLE branches as the existing NAVER validation.
- Around line 93-99: Update the NAVER branch in the budget edit decision to
return a new NAVER-specific reason instead of NOT_EDITABLE. Add the
corresponding reason to the relevant reason type/enum and map it to a
user-facing message indicating that budget editing is currently being prepared
or unavailable pending backend specification confirmation. Keep the existing
commented NAVER context checks unchanged.
In `@src/utils/ads/projectBudget.ts`:
- Around line 51-66: 공통 활성 예산 타입 판정 함수를 추가하고, resolvePlatformBudgetDisplaySlice와
resolveBudgetEditFieldMeta가 모두 이를 사용하도록 변경하세요. activeBudgetType과 daily/lifetime
데이터 존재 여부를 동일하게 반영해 두 함수가 같은 예산 종류, 라벨, payload 필드를 선택하도록 하며, 기존 게이지와 모달의 반환 형식은
유지하세요.
---
Nitpick comments:
In `@src/components/ads/AdDetailContent.tsx`:
- Around line 9-12: Update the internal imports in AdDetailContent.tsx for
Badge, Button, Modal, and ModalContent to use the "`@/components/common/`..."
alias paths instead of relative paths, while preserving the existing imported
symbols.
In `@src/components/ads/CampaignPlatformSection.tsx`:
- Around line 46-52: Update budgetEditDisabledReason in the
CampaignPlatformSection logic to return a reason only when onEditBudget is
present and editCheck.ok is false; otherwise return undefined. Replace the
nested ternary with a single combined condition while preserving the existing
BUDGET_EDIT_BLOCK_MESSAGES[editCheck.reason] lookup.
- Around line 84-104: Update the gauges.map rendering in CampaignPlatformSection
so the platform-level onEditBudget action is rendered only once, such as by
passing headerAction to the first gauge and omitting it from subsequent
PlatformBudgetItem instances. Preserve the existing disabled state, title, and
button behavior.
In `@src/components/ads/EditPlatformBudgetModal.tsx`:
- Around line 190-195: Review the purpose of the form key in the
EditPlatformBudgetModal form around handleSubmit and onSubmit: do not rely on
key changes to reset useForm state, since reset is handled by the existing reset
call around the form initialization logic. Remove the key if it is only intended
to reset form state; retain it only if it is specifically required to remount
BudgetAmountInput local state.
- Around line 137-140: Verify the reset behavior in the useEffect around
resolveBudgetEditDefaultValues: reopening the modal with the same budget must
reset values when isOpen changes to true, while keeping user-entered values
intact after a save failure when the modal remains open. Preserve the current
dependency behavior unless it violates these requirements.
- Around line 44-48: Update BudgetAmountInput to use the React 19 ref prop
pattern instead of forwardRef: add an optional React.Ref<HTMLInputElement> ref
to IBudgetAmountInputProps, receive ref alongside the other destructured props
in BudgetAmountInput, and remove the forwardRef wrapper while preserving the
existing input ref behavior.
In `@src/hooks/ads/useUpdatePlatformBudget.ts`:
- Around line 33-52: Refactor the META and GOOGLE branches in the update flow to
share the existing validation and payload construction, selecting only the
appropriate API function through a platform-to-function map. Preserve the
current missing-information errors and invoke updateMetaCampaignBudget or
updateGoogleCampaignBudget based on the selected platform.
In `@src/pages/ads/list/CampaignDetail.tsx`:
- Around line 364-371: Update the CampaignDetail render flow to create the
budget edit handler with useCallback instead of defining the onEditBudget inline
for each CampaignPlatformSection. Make the callback accept the platform,
retrieve the matching budget from budgetByPlatform, and preserve the existing
setBudgetEditTarget behavior, then pass the stable handler to the section.
In `@src/utils/ads/budgetEdit.ts`:
- Around line 107-115: Replace the non-null assertions in
buildMetaGoogleBudgetPayload with explicit validation that the selected
dailyBudget or lifetimeBudget is defined before constructing the payload. Reject
missing amounts using the same established validation behavior as the NAVER
branch, while preserving the existing DAILY versus lifetimeBudget payload
selection.
- Around line 44-47: Update naverBudgetFormSchema to reuse or alias
dailyBudgetFormSchema because both currently have the same shape; preserve the
naverBudgetFormSchema export for existing callers, unless a confirmed
NAVER-specific validation rule requires keeping a separate schema.
In `@src/utils/ads/projectBudget.ts`:
- Around line 90-94: Review the mock-data assignment of activeBudgetType in the
surrounding budget-item construction and confirm that alternating DAILY and
LIFETIME by index is intentional for covering both types. Add a concise comment
marking this mock-only behavior as something to remove when real data
integration is implemented, without changing the current assignment.
🪄 Autofix
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 Plus
Run ID: e06ede7e-c6e6-462c-8db5-411160ca829b
📒 Files selected for processing (20)
src/api/ads/budget.tssrc/components/ads/AdDetailContent.tsxsrc/components/ads/AdListTable.tsxsrc/components/ads/CampaignPlatformSection.tsxsrc/components/ads/EditPlatformBudgetModal.tsxsrc/components/ads/PlatformBudgetItem.tsxsrc/components/ads/skeleton/AdsSkeleton.tsxsrc/hooks/ads/useAdList.tssrc/hooks/ads/useCreateTrackingUrl.tssrc/hooks/ads/useUpdateAdStatus.tssrc/hooks/ads/useUpdateCampaignStatus.tssrc/hooks/ads/useUpdatePlatformBudget.tssrc/lib/queryKeys.tssrc/pages/ads/list/AdsListPage.tsxsrc/pages/ads/list/CampaignDetail.tsxsrc/types/ads/budget.tssrc/types/ads/campaign.tssrc/utils/ads/budgetEdit.tssrc/utils/ads/formatBudgetInput.tssrc/utils/ads/projectBudget.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/utils/ads/projectBudget.ts`:
- Around line 62-76: Update the mock budget construction in the NAVER and
supportsDailyBudget(providerType) branches to stop exposing mock entries as
editable by removing or setting canEditBudget to a non-editable value. Keep the
existing budget data and mock identifiers unchanged, and do not add API fallback
states or edit UI behavior.
🪄 Autofix
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 Plus
Run ID: 0c2c34f2-55ce-4884-894e-1344d83254ac
📒 Files selected for processing (13)
src/api/ads/budget.tssrc/components/ads/CampaignPlatformSection.tsxsrc/components/ads/EditPlatformBudgetModal.tsxsrc/components/common/modal/Modal.tsxsrc/hooks/ads/useUpdateAdStatus.tssrc/hooks/ads/useUpdateCampaignStatus.tssrc/hooks/ads/useUpdatePlatformBudget.tssrc/pages/ads/list/CampaignDetail.tsxsrc/types/ads/budget.tssrc/types/ads/campaign.tssrc/utils/ads/budgetEdit.tssrc/utils/ads/projectBudget.tssrc/utils/ads/settleBulkRequests.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- src/types/ads/campaign.ts
- src/api/ads/budget.ts
- src/components/ads/CampaignPlatformSection.tsx
- src/hooks/ads/useUpdatePlatformBudget.ts
- src/pages/ads/list/CampaignDetail.tsx
- src/hooks/ads/useUpdateCampaignStatus.ts
- src/components/ads/EditPlatformBudgetModal.tsx
🚨 관련 이슈
close #385
✨ 변경사항
✏️ 작업 내용
플랫폼 예산 수정
캠페인 상세에서 Meta / Google / Naver별 예산을 확인하고, 수정 버튼으로 바로 변경할 수 있게 했습니다.
ads 훅 패턴 통일
추가 훅
useUpdateCampaignStatus— 캠페인 일괄/선택 중단·재개useUpdateAdStatus— 광고 소재 일괄/선택 중단·재개useCreateTrackingUrl— 트래킹 URL 발급수정
useAdList—useCoreQuery전환queryKeys.ts—campaign.ads키 추가AdsListPage,CampaignDetail,AdDetailContent,AdListTable😅 미완성 작업
platformBudgets실데이터 연동 전 mock fallback 사용 중📢 논의 사항 및 참고 사항
Summary by CodeRabbit
새로운 기능
새로운 기능
개선