[Setting/#130] ESLint warning 정리 및 any 타입 제거 리팩토링#133
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 14 seconds. ⌛ 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타입 안정성 강화와 에러 처리 개선 중심의 리팩터: Changes
Sequence Diagram(s)(해당 변경은 주로 타입·에러 처리 및 UI 리팩터 중심이며, 새로운 멀티-컴포넌트 제어 흐름을 도입하지 않아 다이어그램을 생략합니다.) Estimated code review effort🎯 4 (Complex) | ⏱️ ~60분 Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 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 |
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (13)
src/pages/payment/FailPage.tsx (1)
78-79:⚠️ Potential issue | 🔴 CriticalJSX 내에서 세미콜론 제거 필요
JSX 표현식 뒤에 세미콜론(
;)이 있으면 화면에 그대로 렌더링되거나 구문 오류를 발생시킬 수 있어요. JSX 내부의 JavaScript 표현식 뒤에는 세미콜론이 필요하지 않습니다.🔧 수정 제안
<div className="mt-2 text-xs text-gray-500 break-all space-y-1"> - {code ? `code: ${code}` : null}; - {message ? `message: ${message}` : null}; + {code ? <div>code: {code}</div> : null} + {message ? <div>message: {message}</div> : null} </div>또는 더 간결하게:
<div className="mt-2 text-xs text-gray-500 break-all space-y-1"> - {code ? `code: ${code}` : null}; - {message ? `message: ${message}` : null}; + {code && <div>code: {code}</div>} + {message && <div>message: {message}</div>} </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/payment/FailPage.tsx` around lines 78 - 79, Remove the stray semicolons rendered inside JSX: locate the JSX where the expressions using the variables code and message are rendered (the expressions showing `{code ? `code: ${code}` : null}` and `{message ? `message: ${message}` : null}`) and delete the trailing `;` characters so the expressions render normally (or convert them to a single combined expression or conditional fragment if you prefer a more concise output).src/components/reservation/modals/PaymentModal.tsx (1)
130-145:⚠️ Potential issue | 🟡 Minor
initedRef조건문이 항상 참이라 의미가 없어 보여요Line 130에서
initedRef.current = false로 설정한 직후 Line 134에서!initedRef.current를 체크하니까 항상true가 됩니다. 원래 의도가 중복 렌더링 방지였다면 현재 로직으로는 동작하지 않고, 만약 불필요한 코드라면 제거하는 게 가독성에 좋을 것 같아요.💡 불필요하다면 제거 제안
widgetsRef.current = widgets; - initedRef.current = false; - await widgets.setAmount({ value: payOrder.amount, currency: "KRW" }); + await widgets.setAmount({ value: payOrder.amount, currency: "KRW" }); - if (!initedRef.current) { - initedRef.current = true; - paymentMethodWidgetRef.current = await widgets.renderPaymentMethods({ - selector: "#toss-payment-method-widget", - variantKey: "DEFAULT", - }); + paymentMethodWidgetRef.current = await widgets.renderPaymentMethods({ + selector: "#toss-payment-method-widget", + variantKey: "DEFAULT", + }); - agreementWidgetRef.current = await widgets.renderAgreement({ - selector: "#toss-agreement-widget", - variantKey: "AGREEMENT", - }); - } + agreementWidgetRef.current = await widgets.renderAgreement({ + selector: "#toss-agreement-widget", + variantKey: "AGREEMENT", + });혹시 다른 의도가 있었다면 알려주세요!
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/reservation/modals/PaymentModal.tsx` around lines 130 - 145, The code resets initedRef.current to false right before checking it, so the condition (!initedRef.current) is always true and the duplicate-render guard is ineffective; remove the immediate initedRef.current = false assignment (or move it to initial useRef(false) setup) so that the subsequent guard around widgets.renderPaymentMethods and widgets.renderAgreement using initedRef.current, paymentMethodWidgetRef.current, and agreementWidgetRef.current actually prevents double-rendering—ensure the flow sets initedRef.current = true only after successful render and only resets it on unmount/cleanup if needed.src/pages/myPage/reservationPage.tsx (1)
28-81:⚠️ Potential issue | 🟠 Major탭을 빠르게 전환하면 이전 응답이 최신 목록을 덮어쓸 수 있어요.
fetchReservations가 중첩 실행될 때, 늦게 도착한 이전 요청 결과가setReservations를 실행하면 현재activeTab과 다른 데이터가 렌더링될 수 있습니다. 요청 순서를 가드해서 최신 요청만 상태를 반영하도록 막아주세요.예시 수정 코드 (요청 순서 가드)
-import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; export default function ReservationPage() { + const requestSeqRef = useRef(0); const [activeTab, setActiveTab] = useState<ReservationStatus>("전체"); const [reservations, setReservations] = useState<Reservation[]>([]); const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const fetchReservations = useCallback(async () => { + const requestSeq = ++requestSeqRef.current; try { setLoading(true); setError(null); @@ const data = await getBookings(apiStatus); + if (requestSeq !== requestSeqRef.current) return; const mapped: Reservation[] = (data.bookingList ?? []).map((b) => ({ @@ setReservations(mapped); } catch (error) { + if (requestSeq !== requestSeqRef.current) return; console.error("예약 내역 조회 실패", error); setError("예약 내역을 불러오는 데 실패했습니다. 다시 시도해주세요."); } finally { - setLoading(false); + if (requestSeq === requestSeqRef.current) { + setLoading(false); + } } }, [activeTab]);As per coding guidelines
src/pages/**: 라우팅/레이아웃 영향, 로딩/에러/empty 상태 UX 확인.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/myPage/reservationPage.tsx` around lines 28 - 81, The fetchReservations function can apply a request-order guard so stale responses don't overwrite newer tab data: add a ref like latestRequestIdRef (useRef<number>(0)), increment it at start of fetchReservations and capture the current id in a local variable before awaiting getBookings, then only call setReservations (and setError) if the captured id matches latestRequestIdRef.current; also ensure loading state is cleared only for the latest request (or manage a separate in-flight counter) so the UI reflects the correct request lifecycle. Update references to fetchReservations, setReservations, setError, and setLoading accordingly to implement this guard.src/components/auth/ChangePasswordDiaLog.tsx (1)
112-125:⚠️ Potential issue | 🟡 Minor접근성: 새 비밀번호 입력 필드에
id와htmlFor연결이 빠져 있어요.
currentPassword필드는 잘 연결되어 있는데,newPassword와newPasswordConfirm필드는 label과 input 연결이 안 되어 있습니다.♿ 수정 제안
<div className="space-y-1"> - <label className="text-sm font-medium">새 비밀번호</label> + <label htmlFor="newPassword" className="text-sm font-medium">새 비밀번호</label> <input + id="newPassword" type="password" ... /> </div> <div className="space-y-1"> - <label className="text-sm font-medium">새 비밀번호 확인</label> + <label htmlFor="newPasswordConfirm" className="text-sm font-medium">새 비밀번호 확인</label> <input + id="newPasswordConfirm" type="password" ... /> </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/auth/ChangePasswordDiaLog.tsx` around lines 112 - 125, The new password and confirmation fields lack accessible label/input associations: update the label for the new password and newPasswordConfirm controls to include htmlFor and add matching id attributes on their inputs (e.g., id="newPassword" for the input using form.register("newPassword") and id="newPasswordConfirm" for the input using form.register("newPasswordConfirm")), mirroring how currentPassword is wired so screen readers and form controls are properly linked.src/components/reservation/modals/ReservationConfirmModal.tsx (1)
69-80:⚠️ Potential issue | 🔴 Critical타입 에러:
draft.time이undefined일 수 있어서 빌드가 실패해요.
ReservationDraft.time이 optional로 변경되면서CreateBookingBody와 타입이 맞지 않습니다. 예약 생성 전에time값을 검증하거나 기본값을 제공해야 합니다.🐛 수정 제안
const onClickConfirm = async () => { if (booking) { onConfirm(booking); return; } const tableId = draft.tableId; if (!restaurant.id) return; if (createBookingMutation.isPending) return; if (typeof tableId !== "number" || tableId <= 0) { alert("테이블을 먼저 선택해주세요"); return; } + if (!draft.time) { + alert("예약 시간을 선택해주세요"); + return; + } const body = { date: toYmd(draft.date), time: draft.time, // ... };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/reservation/modals/ReservationConfirmModal.tsx` around lines 69 - 80, The build fails because draft.time (ReservationDraft.time) is now optional and may be undefined when constructing the CreateBookingBody object (the body constant used in ReservationConfirmModal.tsx); before building body, validate draft.time (or supply a sensible default) and handle the error path—e.g., in the handler that uses toYmd(draft.date) and tableId, ensure draft.time is defined or return/throw/show validation UI, then set body.time to the validated value so CreateBookingBody typing is satisfied (adjust any callers that expect body to be created only after time is present).src/components/owner/BreakTimeModal.tsx (1)
60-82:⚠️ Potential issue | 🟡 Minor접근성:
<label>과<input>연결이 되어 있지 않아요.
htmlFor와id속성을 통해 레이블과 입력 필드를 연결해주시면 스크린 리더 사용자와 클릭 영역 확장에 도움이 됩니다.♿ label-input 연결 제안
<div> - <label className="text-sm font-bold text-gray-600">시작 시간</label> + <label htmlFor="breaktime-start" className="text-sm font-bold text-gray-600">시작 시간</label> <input + id="breaktime-start" type="time" ... /> </div> <div> - <label className="text-sm font-bold text-gray-600">종료 시간</label> + <label htmlFor="breaktime-end" className="text-sm font-bold text-gray-600">종료 시간</label> <input + id="breaktime-end" type="time" ... /> </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/owner/BreakTimeModal.tsx` around lines 60 - 82, The labels in BreakTimeModal.tsx are not associated with their inputs; add unique id attributes to the start and end time inputs (e.g., "break-start" and "break-end") and set the corresponding label htmlFor attributes to those ids so the <label> elements (for the inputs bound to state vars start and end) are properly connected for screen readers and click targeting; update the two <label> elements and the two <input type="time"> elements (the ones using value={start} / onChange={setStart} and value={end} / onChange={setEnd}) to include the matching id/htmlFor pairs.src/types/restaurant.ts (1)
13-22:⚠️ Potential issue | 🔴 Critical
time을 optional로 변경하면서 파이프라인 실패가 발생하고 있어요.
ReservationConfirmModal.tsx에서CreateBookingBody에time: draft.time을 전달할 때 타입 불일치(TS2322)가 발생합니다.CreateBookingBody.time은string을 기대하는데draft.time이string | undefined가 되었기 때문이에요.해결 방안:
time을 다시 required로 유지 (예약에 시간이 필수라면)- 또는 사용처에서 undefined 체크 추가 (ReservationConfirmModal.tsx에서)
💡 옵션 2: 사용처에서 처리하는 방법
ReservationConfirmModal.tsx에서:const body = { date: toYmd(draft.date), - time: draft.time, + time: draft.time ?? "", // 또는 유효성 검사 후 early return partySize: draft.people, ... };또는 시간이 없으면 예약을 진행하지 않도록:
if (!draft.time) { alert("시간을 선택해주세요"); return; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/types/restaurant.ts` around lines 13 - 22, ReservationDraft.time was made optional causing a type mismatch when passing draft.time to CreateBookingBody.time (expects string) in ReservationConfirmModal (TS2322). Fix by either reverting ReservationDraft.time back to required (make time: string) in the ReservationDraft type, or add a runtime/compile-time guard in ReservationConfirmModal before constructing CreateBookingBody: ensure draft.time is defined (e.g., throw/return/alert if undefined or narrow the type) so only a string is passed to CreateBookingBody.time. Update the chosen location (ReservationDraft or ReservationConfirmModal) and ensure CreateBookingBody usage compiles without allowing undefined.src/components/reservation/modals/ReservationCompleteModal.tsx (1)
38-40:⚠️ Potential issue | 🟡 Minor디버깅용
console.log가 남아있어요.PR 체크리스트에 console.log 제거가 포함되어 있는데, 디버깅용 로그가 아직 남아있네요. 배포 전에 제거해주세요.
🧹 제안하는 수정
const { people, date, time } = draft; - console.log("[complete] draft=", draft); - console.log("[complete] time=", draft.time); const timeText = toHHmm(time);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/reservation/modals/ReservationCompleteModal.tsx` around lines 38 - 40, Remove the leftover debugging console.log calls in ReservationCompleteModal.tsx: delete the two lines logging "[complete] draft=" and "[complete] time=" (the logs referencing draft and draft.time) and keep the calculation of timeText using toHHmm(time) intact; if runtime visibility is required, replace with the app's standard logging mechanism instead of console.log.src/components/reservation/modals/ReservationMenuModal.tsx (1)
66-82:⚠️ Potential issue | 🟡 Minor
OTHER로 분류된 메뉴는 지금 UI에서 아예 안 보입니다.
mapMenuCategory()는 미지원 값을OTHER로 보내는데, 렌더링은MAIN/SIDE/BEVERAGE/ALCOHOL만 순회하고 있습니다. 새 카테고리나 예외 데이터가 오면 메뉴가 선택 모달에서 사라지니OTHER도 같이 렌더링하는 쪽이 안전해요.예시 수정
- (["MAIN", "SIDE", "BEVERAGE", "ALCOHOL"] as MenuCategory[]).map((cat) => { + (["MAIN", "SIDE", "BEVERAGE", "ALCOHOL", "OTHER"] as UiCategory[]).map((cat) => { const list = grouped[cat]; if (list.length === 0) return null; - const safeLabel = MenuCategoryLabel[cat] ?? "기타"; + const safeLabel = + cat === "OTHER" ? "기타" : MenuCategoryLabel[cat] ?? "기타";Also applies to: 85-97, 186-190
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/reservation/modals/ReservationMenuModal.tsx` around lines 66 - 82, mapMenuCategory currently maps unknown/unsupported inputs to "OTHER", but the modal only iterates and renders MAIN/SIDE/BEVERAGE/ALCOHOL, causing OTHER items to be hidden; update the rendering logic in ReservationMenuModal so the categories iteration (the array or map used to render groups around lines referencing rendering at 85-97 and 186-190) includes "OTHER" (or falls back to dynamically collect categories from the mapped menu items) and ensure any category-ordering constant or rendering switch uses the "OTHER" category; keep mapMenuCategory as-is but make the render path (the category list/array and any switch/case that builds menu groups) include "OTHER" so unknown categories appear in the selection modal.src/pages/SearchPage.tsx (1)
199-230:⚠️ Potential issue | 🔴 Critical이 effect는 geocoding 완료 후 무한 루프에 빠질 수 있어요.
targets필터링이r.location유효성만 체크하고geoMap은 무시하기 때문에, 같은results에서 재실행될 때도 대상 목록이 동일합니다. 그래서 이미 캐시된 항목들이next.has(r.id)로 모두 건너뛰어져도setGeoMap(new Map(geoMap))는 매번 새로운 Map 인스턴스를 전달하고, React가 reference 변화를 감지해 state를 업데이트하고 effect가 다시 실행되는 사이클이 반복됩니다.실제로 새 좌표가 추가된 경우에만 state를 갱신하도록 수정해 주세요.
수정 제안
const next = new Map(geoMap); + let changed = false; for (const r of targets) { if (next.has(r.id)) continue; const loc = await geocodeAddress(r.address); - if (loc) next.set(r.id, loc); + if (loc) { + next.set(r.id, loc); + changed = true; + } } - if (!cancelled) { + if (!cancelled && changed) { setGeoMap(next); }src/components/owner/tableDashboard.tsx (2)
399-405:⚠️ Potential issue | 🟠 Major
seatsType변경이 성공해도 현재 화면은 갱신되지 않아요.이번 변경으로 payload에는
seatsType를 담을 수 있게 됐는데, 성공 후tableData와placedTables를 갱신할 때 이 필드는 빠져 있습니다. 그래서 좌석 타입을 바꿔도 화면의SEATS_TYPE_LABEL은 이전 값을 계속 보여주게 됩니다.응답에 `seatsType`가 포함된다면 그 값을 우선 쓰고, 없으면 `changes.seatsType`를 fallback으로 쓰는 방식이 가장 안전해 보여요.예시 수정
if (slotKey && next[slotKey]) { next[slotKey] = { ...next[slotKey], tableId: ut.tableId, minCapacity: ut.minSeatCount ?? next[slotKey].minCapacity, maxCapacity: ut.maxSeatCount ?? next[slotKey].maxCapacity, numValue: displayNum ?? next[slotKey].numValue, + seatsType: + ut.tableId === tableId && changes.seatsType !== undefined + ? changes.seatsType + : next[slotKey].seatsType, isSaved: true, }; } ... tableInfo: { ...pt.tableInfo, minCapacity: match.minSeatCount ?? pt.tableInfo.minCapacity, maxCapacity: match.maxSeatCount ?? pt.tableInfo.maxCapacity, numValue: extractLeadingNumber(match.tableNumber) ?? pt.tableInfo.numValue, + seatsType: + match.tableId === tableId && changes.seatsType !== undefined + ? changes.seatsType + : pt.tableInfo.seatsType, },Also applies to: 425-504
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/owner/tableDashboard.tsx` around lines 399 - 405, The UI isn't updating SEATS_TYPE_LABEL because buildPatchPayload can send seatsType but the update logic for tableData and placedTables doesn't apply it; when handling the successful PATCH response (the code paths around buildPatchPayload, and the update blocks that modify tableData and placedTables between lines ~425-504), set the new seatsType from the server response if present, otherwise fall back to changes.seatsType (i.e., use response.seatsType ?? changes.seatsType) when you construct the updated table objects so SEATS_TYPE_LABEL reflects the change.
221-279:⚠️ Potential issue | 🔴 Critical이
useEffect는 현재 레이아웃 API를 반복 호출할 수 있어요.dependency에
tableData가 포함돼 있는데 effect 내부에서 다시setTableData(...)를 호출하고 있습니다. 한 번 로드된 뒤에도 state 변경마다fetchLayout()이 재실행돼서 요청 루프가 생기고, 로컬에서 막 수정한 값도 서버 응답으로 덮일 수 있어요.예시 수정
- setTableData( - mapTablesFromApi(layout.tables, layout.gridInfo.gridCol, tableData), - ); + setTableData((prev) => + mapTablesFromApi(layout.tables, layout.gridInfo.gridCol, prev), + ); ... - }, [storeId, tableData]); + }, [storeId]);
setPlacedTables(...)쪽의tableImageUrlfallback도 같은 이유로tableData클로저 대신 이전 state나ref를 읽도록 같이 정리하는 편이 안전합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/owner/tableDashboard.tsx` around lines 221 - 279, The effect starting in useEffect that defines fetchLayout is re-triggering because tableData is in the dependency array while you call setTableData inside the effect; remove tableData from the dependency list and only depend on storeId (useEffect(..., [storeId])) so fetchLayout runs only when storeId changes; to preserve the desired tableImageUrl fallback and avoid reading the stale tableData closure, read the latest tableData via a ref (e.g., tableDataRef.current) or compute the fallback inside mapTablesFromApi prior to calling setTableData, and update setPlacedTables to use that ref/derived value instead of directly referencing the tableData variable.src/components/owner/MenuManagement.tsx (1)
72-99:⚠️ Potential issue | 🟠 Major로컬 캐시를 바로
MenuItem[]로 단정하면 구버전 데이터에서 깨질 수 있어요.
JSON.parse결과를 검증하지 않은 채m.id.startsWith("MENU_")를 호출하고 있어서, 예전 캐시에id: 12처럼 숫자가 남아 있으면 메뉴 조회 성공 후에도 여기서 예외가 납니다. 이 경우 사용자에게는 네트워크 오류처럼 보이기도 해서 원인 추적이 더 어려워집니다.예시 수정
- parsedSavedMenus = JSON.parse(savedMenus) as MenuItem[]; + const parsed = JSON.parse(savedMenus); + parsedSavedMenus = Array.isArray(parsed) + ? (parsed as MenuItem[]) + : []; setMenus(parsedSavedMenus); ... - const localTempMenus = parsedSavedMenus.filter((m) => - m.id.startsWith("MENU_"), - ); + const localTempMenus = parsedSavedMenus.filter((m) => + String(m.id).startsWith("MENU_"), + );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/owner/MenuManagement.tsx` around lines 72 - 99, parsedSavedMenus is being cast to MenuItem[] and later you call m.id.startsWith("MENU_") without validating parsed data; this can throw if an old cache has numeric ids. Fix by validating parsed JSON before treating as MenuItem[]: in the try block, ensure the parsed value is an array and filter/map its elements to only include objects with a string id (e.g. typeof item === "object" && item !== null && typeof item.id === "string") before calling setMenus; and change the localTempMenus filter to guard on typeof m.id === "string" && m.id.startsWith("MENU_") so mapServerToLocal/getMenus flow is safe against legacy cached shapes.
🧹 Nitpick comments (8)
src/components/reservation/modals/PaymentModal.tsx (1)
81-86:_payAmount상태가 설정만 되고 사용되지 않는 것 같아요
_payAmount는 언더스코어 prefix로 unused를 나타내는데,setPayAmount로 값을 업데이트하고 있어요. 만약 렌더링에 필요 없다면 상태 자체를 제거하거나, 필요하다면_prefix를 제거하고 실제로 사용하는 게 좋을 것 같습니다.현재 렌더에서는
amount(Line 59의booking?.totalDeposit)를 사용하고 있는데,payOrder.amount와 다를 수 있으니 의도를 확인해주세요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/reservation/modals/PaymentModal.tsx` around lines 81 - 86, The _payAmount state is created and updated (useState, setPayAmount, useEffect) but never used in rendering—either remove the unused state and effect entirely (delete _payAmount, setPayAmount, and the useEffect) or make it the single source of truth by renaming _payAmount to payAmount and replacing usages of booking?.totalDeposit / amount with payAmount (and ensure payOrder.amount is synchronized with payAmount where intended); update PaymentModal to consistently use payAmount (or remove the state) and verify that payOrder.amount and booking?.totalDeposit reflect the intended value.src/api/axios.ts (1)
39-44: 선택적 개선: 기존 API 타입과 통합 고려현재
ApiResponseWithFlags가 독립적으로 정의되어 있는데,@/types/api에 이미 유사한 타입이 있다면 통합하거나 확장(extends)하는 것도 고려해볼 수 있어요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/api/axios.ts` around lines 39 - 44, ApiResponseWithFlags is defined standalone but may duplicate types in "@/types/api"; update the code to import and reuse or extend the existing API type instead of redefining it: locate the ApiResponseWithFlags type in src/api/axios.ts and either replace it with an import from "@/types/api" or declare it as extending the canonical type (e.g., export type ApiResponseWithFlags = ExistingApiType & { isSuccess?: boolean } ), ensuring you remove the redundant local definition and update any usages to the unified type.src/components/owner/TableCreateModal.tsx (1)
18-20:w-full로 변경 시 대형 화면에서 모달이 과도하게 넓어질 수 있어요.기존
w-[400px]에서w-full로 변경되면서max-width제한이 없어졌네요. 대형 모니터에서 모달이 화면 전체로 늘어나 UX가 저하될 수 있습니다.💡 max-width 추가 제안
- className="bg-white w-full rounded-3xl p-8 relative" + className="bg-white w-full max-w-md rounded-3xl p-8 relative"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/owner/TableCreateModal.tsx` around lines 18 - 20, The modal root div in TableCreateModal (the element with className "bg-white w-full rounded-3xl p-8 relative" and the onClick handler) was changed from a fixed width to w-full and lost its max-width constraint; restore a sensible width cap by adding a max-width utility (e.g., max-w-[400px] or an appropriate Tailwind max-w-{size}) alongside w-full so the modal stays responsive on small screens but does not stretch across very large displays.src/vite-env.d.ts (1)
1-3: 중복된/// <reference types="vite/client" />지시문이 있어요.Line 1과 Line 3에 동일한 reference 지시문이 중복되어 있네요. 하나만 남기고 제거하면 좋겠습니다.
🧹 제안하는 수정
/// <reference types="vite/client" /> -/// <reference types="vite/client" /> - interface ImportMetaEnv {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/vite-env.d.ts` around lines 1 - 3, Remove the duplicated triple-slash reference directive by keeping a single occurrence of "/// <reference types=\"vite/client\" />" and deleting the extra one so the file contains only one reference comment; locate the duplicate lines containing that exact directive and remove the redundant line.src/api/owner/storeLayout.ts (1)
81-84:createLayout함수의 에러 핸들링도 동일한 패턴으로 개선하면 좋겠어요.다른 함수들은
catch (e: unknown)으로 변경되었는데,createLayout은 아직 타입 없이catch (e)로 남아있네요. PR 목표인 ESLint 경고 정리와 일관성을 위해 이 함수도 동일하게 적용하는 것을 권장드려요.♻️ 제안하는 수정
- } catch (e) { - console.error("배치도 생성 실패:", e); + } catch (e: unknown) { + if (axios.isAxiosError(e)) { + console.error("배치도 생성 실패:", e?.response?.data ?? e); + } else { + console.error("배치도 생성 실패:", e); + } throw e; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/api/owner/storeLayout.ts` around lines 81 - 84, The catch block in createLayout uses an untyped catch (catch (e))—change it to catch (e: unknown) and update the logging/throw to handle unknown safely: in the catch for createLayout check if (e instanceof Error) then console.error("배치도 생성 실패:", e) and rethrow e, otherwise console.error("배치도 생성 실패:", String(e)) and rethrow e; this uses the createLayout function's catch block to satisfy ESLint typing and preserve error details.src/components/owner/StoreSettings.tsx (1)
90-92: 여기 catch들은 rawconsole.error대신 공통 에러 파싱으로 맞추는 편이 안전합니다.지금처럼 브라우저 콘솔에 에러 객체를 그대로 남기면
AxiosError의config/response가 같이 노출될 수 있고, 이 파일만 에러 처리 방식이 다시 갈립니다.unknown으로 받아getErrorMessage(error)로 사용자 메시지를 통일하고, 상세 로그가 정말 필요하면 중앙 로거로 보내는 쪽이 더 안전해 보여요.예시 수정안
+import { getErrorMessage } from "@/utils/error"; ... - } catch (e) { - alert("가게 정보를 불러오는데 실패했습니다."); - console.error(e); + } catch (error: unknown) { + alert(getErrorMessage(error) || "가게 정보를 불러오는데 실패했습니다."); return; }Based on learnings, 이 프로젝트의 axios 인터셉터는 401/API 실패만
ApiError로 바꾸고 나머지는AxiosError를 유지합니다.Also applies to: 439-441, 454-458, 465-467, 474-476
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/owner/StoreSettings.tsx` around lines 90 - 92, Replace raw console.error usage in the catch blocks in StoreSettings.tsx with the project's standardized error parsing and logging: call getErrorMessage(e as unknown) to produce the user-facing alert message (replace the hardcoded alert text with that message), and send the full error to the central logger instead of console.error (e.g., processLogger.error or your app's error reporting utility) so sensitive Axios fields aren't leaked; update all catch sites referenced (the blocks around the existing alert + console.error and the other catch ranges called out) to follow this pattern.src/types/booking.ts (1)
1-5: 타입 레이어가 API 함수 구현에 직접 결합돼 있어요현재 방식은 타입 안정성은 좋지만, API 함수 시그니처 변경 시
types레이어까지 함께 흔들릴 수 있어요. 공용 응답 DTO 타입(예:GetUserBookingsResponse)을 별도 타입 모듈에서 export해서 참조하면 결합도를 낮출 수 있습니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/types/booking.ts` around lines 1 - 5, The current UserBookingItem type is tightly coupled to the implementation of getUserBookings; instead, introduce and export a shared DTO (e.g., GetUserBookingsResponse) from the API layer and use that in the types file. Replace the import of getUserBookings with an import of GetUserBookingsResponse and change the alias UserBookingItem to reference GetUserBookingsResponse["bookingList"][number]; ensure the API endpoint function getUserBookings still returns or uses that DTO so the types remain decoupled.src/types/map.ts (1)
6-9:KaKaoMapInstancecasing만KakaoMapInstance로 맞춰두면 좋아요.같은 파일의
KakaoMarkerInstance/KakaoInfoWindowInstance와 표기가 달라서 import 자동완성이나 검색할 때 놓치기 쉬워 보여요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/types/map.ts` around lines 6 - 9, Rename the exported type alias KaKaoMapInstance to KakaoMapInstance to match the casing of KakaoMarkerInstance and KakaoInfoWindowInstance; update the declaration that uses KakaoMaps (the existing line export type KaKaoMapInstance = InstanceType<KakaoMaps["Map"]>) to export type KakaoMapInstance = InstanceType<KakaoMaps["Map"]>, and then update any imports/usages across the codebase that reference KaKaoMapInstance to the new KakaoMapInstance identifier to keep naming consistent with KakaoMarkerInstance and KakaoInfoWindowInstance.
🤖 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/owner/BreakTimeModal.tsx`:
- Around line 39-42: The modal container in BreakTimeModal is missing
accessibility attributes: add role="dialog" and aria-modal="true" to the outer
modal element (the div with className "bg-white w-105 rounded-2xl p-6 relative"
that currently uses onClick={(e) => e.stopPropagation()}); also give the modal
title element a stable id (e.g., breakTimeModalTitle) and add
aria-labelledby="that-id" on the same modal container so screen readers announce
the title (ensure the title element inside BreakTimeModal uses that id).
- Line 40: The class "w-105" used in the BreakTimeModal component (see the
className on the modal root in BreakTimeModal.tsx) is not a standard Tailwind
utility and will be ignored; fix it by either adding a width extension in
tailwind.config (extend theme.width with a 105 key mapping to the desired pixel
value, then rebuild) or replace "w-105" in the BreakTimeModal className with a
standard Tailwind width (e.g., "w-96") so the modal size is applied correctly.
In `@src/components/owner/menuFormModal.tsx`:
- Around line 100-114: The submitted payload and the object passed to onSubmit
when editing (in the isEditing && editingMenu branch inside updateMenu handling)
are missing the description field, so include formData.description in both the
payload sent to updateMenu and the object passed to onSubmit (the
MenuItem-shaped object) — update the payload variable and the onSubmit call (the
object with
id/restaurantId/name/category/price/imageUrl/imageKey/isActive/isSoldOut) to
include description: formData.description (or undefined when empty) so the
parent receives the description immediately.
In `@src/components/owner/MenuManagement.tsx`:
- Around line 17-24: The ServerMenu-to-local mapping is dropping imageKey which
breaks onImageDelete and image replace/delete flows; update the conversion where
server menus are mapped into MenuItem (and any local state initialization of s
or menu items) to carry over s.imageKey into the MenuItem shape (preserve
imageKey field), and ensure any place that reads/writes image info (e.g.,
onImageDelete, image upload handlers, and the component state that holds menu
items) uses that imageKey property. Locate the type ServerMenu and the mapping
that builds MenuItem from server objects and add imageKey propagation so
existing images can be correctly identified for replace/delete.
In `@src/components/owner/tableDetailModal.tsx`:
- Around line 374-382: In the catch block handling errors in
tableDetailModal.tsx (where axios.isAxiosError(error) and error.response?.status
are used and getErrorMessage(error) is called), prevent duplicate alerts by
returning immediately after handling status-specific cases (e.g., after
alert("접근 권한이 없습니다") for 403 and alert("예약 정보를 찾을 수 없습니다") for 404) or by
wrapping the generic alert in an else branch so the generic alert only runs when
status is not 403/404; update that catch block to use either early returns or an
if/else chain to avoid showing two alerts for the same error.
- Around line 414-415: Replace non-standard Tailwind class tokens with Tailwind
4 arbitrary-value syntax: in the modal container (the JSX element with className
starting "fixed inset-0 ... z-25 p-4" in tableDetailModal.tsx) change z-25 to
z-[25]; in the modal content wrapper (the element with "space-y-2 max-h-87
overflow-y-auto pr-1") change max-h-87 to a pixel based arbitrary value such as
max-h-[348px]; also update other occurrences across the codebase: change
max-w-480 → max-w-[480px], sm:max-w-110 → sm:max-w-[440px], and min-h-50 →
min-h-[200px] so Tailwind 4 will apply these styles without needing custom
config.
In `@src/components/reservation/modals/ReservationModal.tsx`:
- Line 267: The Tailwind classes z-2500 and min-w-125 are invalid in standard
Tailwind; update the two usages in ReservationModal: replace the PopoverContent
className value that contains "z-2500" with an arbitrary value like "z-[2500]"
(or a supported z-* such as "z-50"), and replace the element using "min-w-125"
(the table/map element around line 358) with an arbitrary width like
"min-w-[125px]" to restore layering and min-width behavior; ensure you update
the className strings on PopoverContent and the table/map container in
ReservationModal accordingly.
In `@src/components/store-registration/CompleteModal.tsx`:
- Line 55: Currently the UI uses {data.category ?
storeCategoryLabel[data.category] : "-"} which still shows undefined if
storeCategoryLabel lacks the key; update the rendering logic in
CompleteModal.tsx to fallback when the lookup returns undefined by checking the
mapped value itself (e.g., use storeCategoryLabel[data.category] ?? "-" or
equivalent) so that any missing mapping for data.category yields "-" instead of
undefined; locate this expression in the CompleteModal component and replace the
conditional to use the mapped-value fallback.
- Line 37: The class "sm:max-w-110" used on DialogContent in CompleteModal.tsx
is not a valid Tailwind utility and falls back to the default; replace it with a
supported size (recommended: use a bracketed arbitrary value like
sm:max-w-[440px] or an existing scale like sm:max-w-96) in the DialogContent
className, or alternatively add a custom max-w-110 entry in tailwind.config.ts
if you want that exact token; apply the same change to the identical usages in
ConfirmModal.tsx and LoginDialog.tsx to keep sizing consistent.
In `@src/components/store-registration/StepBusinessAuth.tsx`:
- Around line 149-159: The onChange handlers registered in register("name", ...)
and the similar block at 238-247 are using e.target.value as businessNumber,
which corrupts the parent state when editing name or startDate; fix by using the
current field's value from e.target.value (e.g., const name = e.target.value for
the name handler, or const startDate = e.target.value for the startDate handler)
and read only the other fields from getValues(), then call setIsVerified(false)
and onComplete with the correct payload
(name/startDate/businessNumber/isVerified) so businessNumber is not overwritten
incorrectly; also update the businessNumber handler (the block at 238-247)
similarly to compose the payload from e.target.value for businessNumber and
getValues() for the rest.
In `@src/components/ui/checkbox.tsx`:
- Line 15: The class list in the Checkbox component contains an invalid Tailwind
class "rounded-1"; locate the className/string in the Checkbox component (the
string that includes "peer border-input ... rounded-1 border shadow-xs ...") and
replace "rounded-1" with "rounded-md" so the checkbox corners match the rest of
the UI and use a valid Tailwind v4 utility.
In `@src/types/menus.ts`:
- Around line 23-31: The MenuCategoryLabel map currently includes the special
UiCategory value "OTHER", which can expose an option that
MenuCreateItemDto.category (typed as MenuCategory) doesn't accept; change
MenuCategoryLabel to only map MenuCategory keys (e.g., export const
MenuCategoryLabel: Record<MenuCategory, string> = { ... }) and remove the
"OTHER" entry, and if you need a label for the unknown case keep a separate
constant (e.g., OtherCategoryLabel or UiCategoryLabel) for display-only usage;
update any UI code that renders creation/edit dropdowns to use MenuCategoryLabel
(not the UiCategory map) so "OTHER" is never offered as a selectable option.
---
Outside diff comments:
In `@src/components/auth/ChangePasswordDiaLog.tsx`:
- Around line 112-125: The new password and confirmation fields lack accessible
label/input associations: update the label for the new password and
newPasswordConfirm controls to include htmlFor and add matching id attributes on
their inputs (e.g., id="newPassword" for the input using
form.register("newPassword") and id="newPasswordConfirm" for the input using
form.register("newPasswordConfirm")), mirroring how currentPassword is wired so
screen readers and form controls are properly linked.
In `@src/components/owner/BreakTimeModal.tsx`:
- Around line 60-82: The labels in BreakTimeModal.tsx are not associated with
their inputs; add unique id attributes to the start and end time inputs (e.g.,
"break-start" and "break-end") and set the corresponding label htmlFor
attributes to those ids so the <label> elements (for the inputs bound to state
vars start and end) are properly connected for screen readers and click
targeting; update the two <label> elements and the two <input type="time">
elements (the ones using value={start} / onChange={setStart} and value={end} /
onChange={setEnd}) to include the matching id/htmlFor pairs.
In `@src/components/owner/MenuManagement.tsx`:
- Around line 72-99: parsedSavedMenus is being cast to MenuItem[] and later you
call m.id.startsWith("MENU_") without validating parsed data; this can throw if
an old cache has numeric ids. Fix by validating parsed JSON before treating as
MenuItem[]: in the try block, ensure the parsed value is an array and filter/map
its elements to only include objects with a string id (e.g. typeof item ===
"object" && item !== null && typeof item.id === "string") before calling
setMenus; and change the localTempMenus filter to guard on typeof m.id ===
"string" && m.id.startsWith("MENU_") so mapServerToLocal/getMenus flow is safe
against legacy cached shapes.
In `@src/components/owner/tableDashboard.tsx`:
- Around line 399-405: The UI isn't updating SEATS_TYPE_LABEL because
buildPatchPayload can send seatsType but the update logic for tableData and
placedTables doesn't apply it; when handling the successful PATCH response (the
code paths around buildPatchPayload, and the update blocks that modify tableData
and placedTables between lines ~425-504), set the new seatsType from the server
response if present, otherwise fall back to changes.seatsType (i.e., use
response.seatsType ?? changes.seatsType) when you construct the updated table
objects so SEATS_TYPE_LABEL reflects the change.
- Around line 221-279: The effect starting in useEffect that defines fetchLayout
is re-triggering because tableData is in the dependency array while you call
setTableData inside the effect; remove tableData from the dependency list and
only depend on storeId (useEffect(..., [storeId])) so fetchLayout runs only when
storeId changes; to preserve the desired tableImageUrl fallback and avoid
reading the stale tableData closure, read the latest tableData via a ref (e.g.,
tableDataRef.current) or compute the fallback inside mapTablesFromApi prior to
calling setTableData, and update setPlacedTables to use that ref/derived value
instead of directly referencing the tableData variable.
In `@src/components/reservation/modals/PaymentModal.tsx`:
- Around line 130-145: The code resets initedRef.current to false right before
checking it, so the condition (!initedRef.current) is always true and the
duplicate-render guard is ineffective; remove the immediate initedRef.current =
false assignment (or move it to initial useRef(false) setup) so that the
subsequent guard around widgets.renderPaymentMethods and widgets.renderAgreement
using initedRef.current, paymentMethodWidgetRef.current, and
agreementWidgetRef.current actually prevents double-rendering—ensure the flow
sets initedRef.current = true only after successful render and only resets it on
unmount/cleanup if needed.
In `@src/components/reservation/modals/ReservationCompleteModal.tsx`:
- Around line 38-40: Remove the leftover debugging console.log calls in
ReservationCompleteModal.tsx: delete the two lines logging "[complete] draft="
and "[complete] time=" (the logs referencing draft and draft.time) and keep the
calculation of timeText using toHHmm(time) intact; if runtime visibility is
required, replace with the app's standard logging mechanism instead of
console.log.
In `@src/components/reservation/modals/ReservationConfirmModal.tsx`:
- Around line 69-80: The build fails because draft.time (ReservationDraft.time)
is now optional and may be undefined when constructing the CreateBookingBody
object (the body constant used in ReservationConfirmModal.tsx); before building
body, validate draft.time (or supply a sensible default) and handle the error
path—e.g., in the handler that uses toYmd(draft.date) and tableId, ensure
draft.time is defined or return/throw/show validation UI, then set body.time to
the validated value so CreateBookingBody typing is satisfied (adjust any callers
that expect body to be created only after time is present).
In `@src/components/reservation/modals/ReservationMenuModal.tsx`:
- Around line 66-82: mapMenuCategory currently maps unknown/unsupported inputs
to "OTHER", but the modal only iterates and renders MAIN/SIDE/BEVERAGE/ALCOHOL,
causing OTHER items to be hidden; update the rendering logic in
ReservationMenuModal so the categories iteration (the array or map used to
render groups around lines referencing rendering at 85-97 and 186-190) includes
"OTHER" (or falls back to dynamically collect categories from the mapped menu
items) and ensure any category-ordering constant or rendering switch uses the
"OTHER" category; keep mapMenuCategory as-is but make the render path (the
category list/array and any switch/case that builds menu groups) include "OTHER"
so unknown categories appear in the selection modal.
In `@src/pages/myPage/reservationPage.tsx`:
- Around line 28-81: The fetchReservations function can apply a request-order
guard so stale responses don't overwrite newer tab data: add a ref like
latestRequestIdRef (useRef<number>(0)), increment it at start of
fetchReservations and capture the current id in a local variable before awaiting
getBookings, then only call setReservations (and setError) if the captured id
matches latestRequestIdRef.current; also ensure loading state is cleared only
for the latest request (or manage a separate in-flight counter) so the UI
reflects the correct request lifecycle. Update references to fetchReservations,
setReservations, setError, and setLoading accordingly to implement this guard.
In `@src/pages/payment/FailPage.tsx`:
- Around line 78-79: Remove the stray semicolons rendered inside JSX: locate the
JSX where the expressions using the variables code and message are rendered (the
expressions showing `{code ? `code: ${code}` : null}` and `{message ? `message:
${message}` : null}`) and delete the trailing `;` characters so the expressions
render normally (or convert them to a single combined expression or conditional
fragment if you prefer a more concise output).
In `@src/types/restaurant.ts`:
- Around line 13-22: ReservationDraft.time was made optional causing a type
mismatch when passing draft.time to CreateBookingBody.time (expects string) in
ReservationConfirmModal (TS2322). Fix by either reverting ReservationDraft.time
back to required (make time: string) in the ReservationDraft type, or add a
runtime/compile-time guard in ReservationConfirmModal before constructing
CreateBookingBody: ensure draft.time is defined (e.g., throw/return/alert if
undefined or narrow the type) so only a string is passed to
CreateBookingBody.time. Update the chosen location (ReservationDraft or
ReservationConfirmModal) and ensure CreateBookingBody usage compiles without
allowing undefined.
---
Nitpick comments:
In `@src/api/axios.ts`:
- Around line 39-44: ApiResponseWithFlags is defined standalone but may
duplicate types in "@/types/api"; update the code to import and reuse or extend
the existing API type instead of redefining it: locate the ApiResponseWithFlags
type in src/api/axios.ts and either replace it with an import from "@/types/api"
or declare it as extending the canonical type (e.g., export type
ApiResponseWithFlags = ExistingApiType & { isSuccess?: boolean } ), ensuring you
remove the redundant local definition and update any usages to the unified type.
In `@src/api/owner/storeLayout.ts`:
- Around line 81-84: The catch block in createLayout uses an untyped catch
(catch (e))—change it to catch (e: unknown) and update the logging/throw to
handle unknown safely: in the catch for createLayout check if (e instanceof
Error) then console.error("배치도 생성 실패:", e) and rethrow e, otherwise
console.error("배치도 생성 실패:", String(e)) and rethrow e; this uses the createLayout
function's catch block to satisfy ESLint typing and preserve error details.
In `@src/components/owner/StoreSettings.tsx`:
- Around line 90-92: Replace raw console.error usage in the catch blocks in
StoreSettings.tsx with the project's standardized error parsing and logging:
call getErrorMessage(e as unknown) to produce the user-facing alert message
(replace the hardcoded alert text with that message), and send the full error to
the central logger instead of console.error (e.g., processLogger.error or your
app's error reporting utility) so sensitive Axios fields aren't leaked; update
all catch sites referenced (the blocks around the existing alert + console.error
and the other catch ranges called out) to follow this pattern.
In `@src/components/owner/TableCreateModal.tsx`:
- Around line 18-20: The modal root div in TableCreateModal (the element with
className "bg-white w-full rounded-3xl p-8 relative" and the onClick handler)
was changed from a fixed width to w-full and lost its max-width constraint;
restore a sensible width cap by adding a max-width utility (e.g., max-w-[400px]
or an appropriate Tailwind max-w-{size}) alongside w-full so the modal stays
responsive on small screens but does not stretch across very large displays.
In `@src/components/reservation/modals/PaymentModal.tsx`:
- Around line 81-86: The _payAmount state is created and updated (useState,
setPayAmount, useEffect) but never used in rendering—either remove the unused
state and effect entirely (delete _payAmount, setPayAmount, and the useEffect)
or make it the single source of truth by renaming _payAmount to payAmount and
replacing usages of booking?.totalDeposit / amount with payAmount (and ensure
payOrder.amount is synchronized with payAmount where intended); update
PaymentModal to consistently use payAmount (or remove the state) and verify that
payOrder.amount and booking?.totalDeposit reflect the intended value.
In `@src/types/booking.ts`:
- Around line 1-5: The current UserBookingItem type is tightly coupled to the
implementation of getUserBookings; instead, introduce and export a shared DTO
(e.g., GetUserBookingsResponse) from the API layer and use that in the types
file. Replace the import of getUserBookings with an import of
GetUserBookingsResponse and change the alias UserBookingItem to reference
GetUserBookingsResponse["bookingList"][number]; ensure the API endpoint function
getUserBookings still returns or uses that DTO so the types remain decoupled.
In `@src/types/map.ts`:
- Around line 6-9: Rename the exported type alias KaKaoMapInstance to
KakaoMapInstance to match the casing of KakaoMarkerInstance and
KakaoInfoWindowInstance; update the declaration that uses KakaoMaps (the
existing line export type KaKaoMapInstance = InstanceType<KakaoMaps["Map"]>) to
export type KakaoMapInstance = InstanceType<KakaoMaps["Map"]>, and then update
any imports/usages across the codebase that reference KaKaoMapInstance to the
new KakaoMapInstance identifier to keep naming consistent with
KakaoMarkerInstance and KakaoInfoWindowInstance.
In `@src/vite-env.d.ts`:
- Around line 1-3: Remove the duplicated triple-slash reference directive by
keeping a single occurrence of "/// <reference types=\"vite/client\" />" and
deleting the extra one so the file contains only one reference comment; locate
the duplicate lines containing that exact directive and remove the redundant
line.
🪄 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: 13ef2ee6-b67e-435a-b490-0426bce608dd
📒 Files selected for processing (52)
src/api/axios.tssrc/api/bookings.tssrc/api/owner/menus.tssrc/api/owner/storeLayout.tssrc/api/owner/stores.tssrc/api/owner/table.tssrc/components/auth/ChangePasswordDiaLog.tsxsrc/components/auth/LoginDialog.tsxsrc/components/auth/SignupDialog.tsxsrc/components/auth/WithdrawDialog.tsxsrc/components/customer-support/SupportContact.tsxsrc/components/customer-support/SupportFAQ.tsxsrc/components/customer-support/SupportHero.tsxsrc/components/map/KakaoMap.tsxsrc/components/owner/BreakTimeModal.tsxsrc/components/owner/MenuManagement.tsxsrc/components/owner/StoreSettings.tsxsrc/components/owner/TableCreateModal.tsxsrc/components/owner/menuFormModal.tsxsrc/components/owner/tableDashboard.tsxsrc/components/owner/tableDetailModal.tsxsrc/components/reservation/modals/PaymentModal.tsxsrc/components/reservation/modals/ReservationCompleteModal.tsxsrc/components/reservation/modals/ReservationConfirmModal.tsxsrc/components/reservation/modals/ReservationMenuModal.tsxsrc/components/reservation/modals/ReservationModal.tsxsrc/components/restaurant/RestaurantCard.tsxsrc/components/store-registration/CompleteModal.tsxsrc/components/store-registration/ConfirmModal.tsxsrc/components/store-registration/MenuItemInput.tsxsrc/components/store-registration/RegistrationStepper.tsxsrc/components/store-registration/StepBusinessAuth.tsxsrc/components/store-registration/StepMenuRegistration.tsxsrc/components/store-registration/StepStoreInfo.tsxsrc/components/store-registration/StoreInfo.schema.tssrc/components/ui/checkbox.tsxsrc/lib/kakao.tssrc/pages/CustomerSupportPage.tsxsrc/pages/ReservationCompletePage.tsxsrc/pages/SearchPage.tsxsrc/pages/myPage/StoreRegistrationPage.tsxsrc/pages/myPage/reservationPage.tsxsrc/pages/payment/FailPage.tsxsrc/pages/payment/SuccessPage.tsxsrc/styles/globals.csssrc/types/booking.tssrc/types/kakao.d.tssrc/types/map.tssrc/types/menus.tssrc/types/restaurant.tssrc/types/store.tssrc/vite-env.d.ts
💤 Files with no reviewable changes (1)
- src/lib/kakao.ts
There was a problem hiding this comment.
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/store-registration/StoreTransform.utils.ts`:
- Line 101: The current bookingIntervalMinutes assignment uses
Number(step2Data.bookingIntervalMinutes || 0) which hides invalid inputs by
coercing falsy values to 0; change this to use the nullish coalescing operator
and explicit validation: use Number(step2Data.bookingIntervalMinutes ??
undefined) (or parseFloat) then verify the result is a finite number and within
your allowed range (e.g., >0 and <= max) before assigning to
bookingIntervalMinutes; if invalid, fallback to a safe default or surface an
error. Ensure you update the code around the bookingIntervalMinutes expression
and any related validation functions to perform the numeric check.
🪄 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: 49c4354d-d0a4-48fd-8f6a-de87b62e0b9f
📒 Files selected for processing (3)
src/components/reservation/modals/ReservationConfirmModal.tsxsrc/components/reservation/modals/ReservationModal.tsxsrc/components/store-registration/StoreTransform.utils.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/components/reservation/modals/ReservationModal.tsx
- src/components/reservation/modals/ReservationConfirmModal.tsx
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/owner/tableDetailModal.tsx (1)
420-427:⚠️ Potential issue | 🟠 Major모달 접근성 속성(
role,aria-modal)을 추가해 주세요.현재 모달 컨테이너에 대화상자 시맨틱이 없어 스크린리더가 모달 컨텍스트를 정확히 인지하기 어렵습니다.
예시 수정안
<div + role="dialog" + aria-modal="true" + aria-label={`${tableNumber}번 테이블 상세`} className="bg-white w-full max-w-2xl rounded-lg shadow-2xl overflow-hidden flex flex-col max-h-[90vh] animate-in zoom-in-95 duration-200" onClick={(e) => e.stopPropagation()} >As per coding guidelines:
src/components/**: 컴포넌트는 단일 책임, props 타입/네이밍 명확히, 접근성(aria) 체크.Also applies to: 429-452
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/owner/tableDetailModal.tsx` around lines 420 - 427, Add dialog semantics to the modal by adding role="dialog" and aria-modal="true" to the modal container (the outer div with className "fixed inset-0 bg-black/50..." or the inner content div "bg-white w-full max-w-2xl...") and ensure the dialog has an accessible name: reference an existing header element via aria-labelledby (create an id on the title element) or add aria-label if no header id exists; keep the existing onClick and stopPropagation logic (uploading/detailLoading checks) intact when making these changes.
♻️ Duplicate comments (1)
src/components/owner/tableDetailModal.tsx (1)
420-420:⚠️ Potential issue | 🟠 Major
z-25,max-h-87은 Tailwind에서 설정 없으면 적용되지 않습니다.이 클래스들은 기본 유틸리티가 아니라서(설정 미정의 시) 조용히 무시되고, 모달 레이어/높이 UI가 의도와 다르게 렌더링될 수 있어요.
arbitrary value문법으로 바꾸는 쪽이 안전합니다.예시 수정안
- className="fixed inset-0 bg-black/50 flex items-center justify-center z-25 p-4" + className="fixed inset-0 bg-black/50 flex items-center justify-center z-[25] p-4"- <div className="space-y-2 max-h-87 overflow-y-auto pr-1 custom-scrollbar"> + <div className="space-y-2 max-h-[348px] overflow-y-auto pr-1 custom-scrollbar">#!/bin/bash set -euo pipefail echo "== Tailwind version ==" fd -HI 'package\.json$' -E node_modules -E dist -E build -x sh -c ' v=$(jq -r ".dependencies.tailwindcss // .devDependencies.tailwindcss // empty" "$1") if [ -n "$v" ] && [ "$v" != "null" ]; then echo "$1: $v" fi ' sh {} echo echo "== Tailwind config files ==" fd -HI 'tailwind\.config\.(js|cjs|mjs|ts)$' -E node_modules -E dist -E build echo echo "== Config contains custom utility definitions? ==" fd -HI 'tailwind\.config\.(js|cjs|mjs|ts)$' -E node_modules -E dist -E build -x sh -c ' echo "--- $1 ---" rg -n "extend|zIndex|maxHeight|spacing|87|25" "$1" || true ' sh {} echo echo "== Usage of suspect classes ==" rg -n 'z-25|max-h-87' -g '!**/node_modules/**' -g '!**/dist/**' -g '!**/build/**'Also applies to: 846-846
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/owner/tableDetailModal.tsx` at line 420, The Tailwind classes "z-25" and "max-h-87" are not default utilities and will be ignored unless defined in tailwind.config; replace them with arbitrary-value syntax in the JSX className(s) in tableDetailModal.tsx (the modal container/className string that currently contains "z-25" and any element using "max-h-87"), e.g. change "z-25" → "z-[25]" and "max-h-87" → "max-h-[87px]" (or another explicit unit you expect), and update the other occurrence noted around the file (the second instance at the later comment) so all uses use the arbitrary-value form and confirm the chosen units are correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/components/owner/tableDetailModal.tsx`:
- Around line 420-427: Add dialog semantics to the modal by adding role="dialog"
and aria-modal="true" to the modal container (the outer div with className
"fixed inset-0 bg-black/50..." or the inner content div "bg-white w-full
max-w-2xl...") and ensure the dialog has an accessible name: reference an
existing header element via aria-labelledby (create an id on the title element)
or add aria-label if no header id exists; keep the existing onClick and
stopPropagation logic (uploading/detailLoading checks) intact when making these
changes.
---
Duplicate comments:
In `@src/components/owner/tableDetailModal.tsx`:
- Line 420: The Tailwind classes "z-25" and "max-h-87" are not default utilities
and will be ignored unless defined in tailwind.config; replace them with
arbitrary-value syntax in the JSX className(s) in tableDetailModal.tsx (the
modal container/className string that currently contains "z-25" and any element
using "max-h-87"), e.g. change "z-25" → "z-[25]" and "max-h-87" → "max-h-[87px]"
(or another explicit unit you expect), and update the other occurrence noted
around the file (the second instance at the later comment) so all uses use the
arbitrary-value form and confirm the chosen units are correct.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4c0363cd-473d-4a74-a0ad-6462f90accac
📒 Files selected for processing (11)
src/components/customer-support/SupportHero.tsxsrc/components/owner/BreakTimeModal.tsxsrc/components/owner/menuFormModal.tsxsrc/components/owner/tableDetailModal.tsxsrc/components/reservation/modals/ReservationModal.tsxsrc/components/store-registration/CompleteModal.tsxsrc/components/store-registration/StepBusinessAuth.tsxsrc/components/store-registration/StoreTransform.utils.tssrc/components/ui/checkbox.tsxsrc/pages/CustomerSupportPage.tsxsrc/types/menus.ts
✅ Files skipped from review due to trivial changes (5)
- src/pages/CustomerSupportPage.tsx
- src/components/customer-support/SupportHero.tsx
- src/components/store-registration/CompleteModal.tsx
- src/components/ui/checkbox.tsx
- src/components/owner/BreakTimeModal.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
- src/components/store-registration/StoreTransform.utils.ts
- src/components/reservation/modals/ReservationModal.tsx
- src/components/store-registration/StepBusinessAuth.tsx
- src/components/owner/menuFormModal.tsx
- src/types/menus.ts
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 (1)
src/components/owner/tableDetailModal.tsx (1)
185-194:⚠️ Potential issue | 🔴 Critical슬롯 조회 실패 시 이전 날짜 데이터가 그대로 남습니다.
새 날짜를 선택한 뒤 요청이 실패해도
slots를 비우지 않아서, 화면에는 이전 날짜 슬롯이 계속 남습니다. 문제는 이후 토글이 현재selectedFullDate기준으로 실행된다는 점이라, 실패 직후 사용자가 보이는 슬롯을 누르면 잘못된 날짜 상태를 바꿀 수 있어요. 실패 시slots를 비우고, 가능하면error가 있는 동안은 슬롯 리스트를 렌더링하지 않는 쪽이 안전합니다.예시 수정안
const fetchSlots = async (date: Date) => { try { setLoading(true); setError(null); const res = await getTableSlots(storeId, tableId, formatDate(date)); setSlots(res.data.result.slots); } catch (error: unknown) { + setSlots([]); const message = getErrorMessage(error) || "예약 정보를 불러오지 못했습니다"; setError(message); } finally { setLoading(false); } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/owner/tableDetailModal.tsx` around lines 185 - 194, The fetchSlots function leaves previous slots on failure; update the catch block in fetchSlots to call setSlots([]) (and still setError(message) and setLoading(false)) so the UI doesn't show stale data, and ensure the component's rendering logic that maps/uses slots (including any handlers that use selectedFullDate) skips or hides the slots list when error is set to prevent interaction with outdated entries.
🤖 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/owner/tableDetailModal.tsx`:
- Around line 164-167: Create a small helper in this module (e.g., const
UNKNOWN_ERROR_MESSAGE = "알 수 없는 오류가 발생했습니다."; and function
getActionErrorMessage(error: unknown, fallback: string)) that calls
getErrorMessage(error) and returns the provided fallback only if
getErrorMessage(...) === UNKNOWN_ERROR_MESSAGE; then replace direct uses of
getErrorMessage(...) || "…실패했습니다" in the catch blocks (the instances around the
alert calls referencing the table edit/delete actions) with
getActionErrorMessage(error, "<action-specific fallback>") so each alert keeps
the action-specific text unless getErrorMessage returns the util default.
- Around line 383-385: When handling the cancel API 404 branch, clear the stale
detail state instead of only alerting: call the same setters used to hide/clear
the modal (e.g., setShowBookingDetail(false) or showBookingDetail(false)), clear
bookingDetail and bookingDetailBookingId to null/undefined, and trigger the slot
list refresh by calling the existing slot reload function (e.g.,
fetchSlots/loadSlots/reloadSlots) so the UI reflects the deleted booking; keep
the alert but ensure state is reset and slots reloaded in the status === 404
branch.
---
Outside diff comments:
In `@src/components/owner/tableDetailModal.tsx`:
- Around line 185-194: The fetchSlots function leaves previous slots on failure;
update the catch block in fetchSlots to call setSlots([]) (and still
setError(message) and setLoading(false)) so the UI doesn't show stale data, and
ensure the component's rendering logic that maps/uses slots (including any
handlers that use selectedFullDate) skips or hides the slots list when error is
set to prevent interaction with outdated entries.
🪄 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: 7799759a-d1fa-4888-bada-b35695f60775
📒 Files selected for processing (3)
src/components/owner/tableDetailModal.tsxsrc/components/reservation/modals/ReservationModal.tsxsrc/styles/globals.css
✅ Files skipped from review due to trivial changes (1)
- src/styles/globals.css
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/reservation/modals/ReservationModal.tsx
dew102938
left a comment
There was a problem hiding this comment.
any 타입이 생각보다 많이 사용되고 있었네요... 개선된 코드도 확인했습니다 수고하셨습니다!
* [Docs/#118] Issue/PR 템플릿 수정 (프로젝트 재정비) (#119) * docs: PR 템플릿 수정 * docs: issue/PR template 수정 * docs: 템플릿 수정에 맞게 Readme변경 * refactor: 사용되지 않는 파일 삭제 * refactor: 미사용 ProfileAvatar 컴포넌트를 MyInfoPage에 적용 * refactor: 사용되지 않는 패키지 삭제 * refactor: 사용되지 않는 export 정리 * 사용되지 않는 함수 toRestaurantSummary 삭제 * refactor: 좌석 타입 라벨을 table.ts 공통 상수로 통합 * refactor: 사용되지 않는 export 타입, 인터페이스 정리 * refactor: 사용되지 않는 타입, 인터페이스 삭제 * [Setting/#121] ESLint/Prettier 설정 및 useEffect 비동기 랜더링 에러 수정 (#123) * setting: ESLint/Prettier 설정 및 useEffect 비동기 랜더링 에러 수정 * fix: vercel build에러 수정 * fix: 코드래빗 일부수정 * fix: 코드래빗 수정사항 반영 * fix: lint error 수정 (#126) * [Setting/#124] Husky 및 lint-staged 기반 pre-commit 자동 검사 환경 설정 (#127) * fix: lint error 수정 * setting: Husky 도입 및 pre-commit lint 검사 설정 * setting: lint-staged 및 자동 포맷 검사 설정 * fix: coderabbit 반영 * fix: coderabbit 수정사항 반영 * [Setting/#128] GitHub Actions CI 환경설정 추가 (#129) * setting: GitHub Actions CI 설정 추가 * fix: GitHub Actions pnpm 버전 중복 지정으로 인한 오류 수정 * fix: node버전 기존 24에서 22로 수정 * [Setting/#130] ESLint warning 정리 및 any 타입 제거 리팩토링 (#133) * fix:any타입 에러 수정중 * fix: lint 에러 수정중(중간저장목적) * fix: lint에러 수정중(중간저장목적) * fix: lint에러 수정중 중간 저장 * fix: lint에러 수정중 중간점검 * fix: lint 에러 수정완료 * fix: build 에러 수정 * fix: 코드래빗 수정사항 반영 * fix: 화면 오류확인해서 삭제했던 globals.css 복구 * fix: 코드래빗 수정사항 반영 * fix: 예약금결제 스크롤 에러 수정 (#135) --------- Co-authored-by: Dew <eidnwq@gmail.com>
🔢 관련 이슈 링크
📌 변경사항PR
💻 작업내용
any타입 제거 후 구체적인 타입으로 변경🪧 미완성 작업
N/A
🤔 논의 사항 및 참고 사항
lint 에러 수정 진행하면서 전체적으로 확인하다보니 필요한 작업이 몇개있는것같습니다!
types/hooks/utils가 파일 내에서 역할이 섞여있습니다! 분리작업 필요할듯합니다 (type + 로직 + 컴포넌트)✅ 체크리스트
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항
품질 개선