Conversation
Walkthrough마스터 가게 조회/관리 기능과 인증 흐름을 추가하고, 관련 API·타입·쿼리 훅·라우트·유틸리티 및 UI 컴포넌트를 도입·수정했습니다. 공유 복사 로직과 이미지 업로드/미리보기, React Query 캐시 정리, 일부 네비게이션·레이아웃 변경이 포함됩니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant FindMyStore
participant useMasterStores
participant getMasterRestaurant
participant API as BackendAPI
User->>FindMyStore: 컴포넌트 마운트
FindMyStore->>useMasterStores: useQuery(['masterStores'])
useMasterStores->>getMasterRestaurant: 호출
getMasterRestaurant->>API: GET /ownerRestaurant/my
API-->>getMasterRestaurant: MasterStoreResponse[]
getMasterRestaurant-->>useMasterStores: 데이터 반환
useMasterStores-->>FindMyStore: 데이터 제공
FindMyStore-->>User: 가게 목록 렌더링
sequenceDiagram
participant User
participant AuthMaster
participant submitCertificate
participant API as BackendAPI
User->>AuthMaster: 이미지 선택
AuthMaster->>AuthMaster: ObjectURL 생성 및 미리보기 표시
User->>AuthMaster: 제출 클릭
AuthMaster->>submitCertificate: 파일 전달
submitCertificate->>API: PUT /users/registration (FormData)
API-->>submitCertificate: 성공 응답
submitCertificate-->>AuthMaster: 완료
AuthMaster->>AuthMaster: isPending 해제 및 onNext 호출
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✏️ 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: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/shared/components/myPage/MyReviewItem.tsx (1)
105-105:⚠️ Potential issue | 🟠 Major하드코딩된 레스토랑 이름을
review.restaurantName으로 교체해야 합니다.
MyReviewResponse타입에restaurantName필드가 존재하므로, 다음 위치들에서 하드코딩된 값들을 해당 필드로 교체하세요:
- 105줄:
엔비햄버거→review.restaurantName- 75, 76줄:
빵빵→review.restaurantName- 191줄:
restName={'빵빵'}→restName={review.restaurantName}- 212줄:
restName={'빵빵'}→restName={review.restaurantName}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/MyReviewItem.tsx` at line 105, Replace hardcoded restaurant names with the restaurantName field from the review object: update the JSX in MyReviewItem.tsx to use review.restaurantName (the MyReviewResponse.restaurantName property) where the static strings appear — specifically change the <h3> title currently rendering "엔비햄버거", the two earlier occurrences rendering "빵빵", and the restName props currently set as '빵빵' to restName={review.restaurantName}; ensure the component references the existing review variable/prop and that review.restaurantName is used consistently for display and prop passing.src/shared/components/myPage/AuthMaster.tsx (1)
23-29:⚠️ Potential issue | 🟠 Major파일을 여러 번 선택하면 이전 Object URL이 해제되지 않아 메모리 누수가 발생합니다.
새 파일을 선택할 때 이전
previewUrl에 대해URL.revokeObjectURL을 호출해야 합니다.🐛 수정 제안
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const file = e.target.files?.[0]; if (file) { + if (previewUrl !== '') URL.revokeObjectURL(previewUrl); setSelectedFile(file); setPreviewUrl(URL.createObjectURL(file)); } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/AuthMaster.tsx` around lines 23 - 29, The handleChange in AuthMaster sets a new preview URL without revoking the previous one, causing memory leaks; update handleChange to, before calling URL.createObjectURL(file), check the current previewUrl (state used by setPreviewUrl) and if present call URL.revokeObjectURL(previewUrl) to release it, then create and set the new object URL and selected file (and also ensure any cleanup on unmount revokes the last previewUrl if still set).
🧹 Nitpick comments (14)
src/pages/add/StoreCheck.tsx (1)
4-8: 주석 처리된 코드 블록을 제거해 주세요.전체 파일에 걸쳐 임포트, 상태 구조 분해, 핸들러, JSX 마크업 등 대량의 코드가 주석으로만 남아 있습니다. 이력이 필요하다면 Git 히스토리로 충분히 추적 가능하므로, 주석 처리된 코드를 모두 삭제하면 가독성과 유지보수성이 크게 향상됩니다.
Also applies to: 13-20, 25-36, 41-77
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/add/StoreCheck.tsx` around lines 4 - 8, Remove all commented-out code throughout StoreCheck.tsx—this includes the commented import lines (e.g., the svg imports commented above Header), any commented state/destructuring, handlers, and JSX fragments left as comments between the import block and the component body (areas noted around the Header import and the commented blocks spanning the rest of the file). Delete those commented lines rather than leaving them in place; if history is needed, rely on Git history. Keep only active imports (like Header) and the live component code to improve readability and maintainability.src/pages/myPage/MyReview.tsx (1)
16-24:fixed포지셔닝에서width: calc(100% - 32px)는 뷰포트 기준으로 계산됩니다.
position: fixed는 부모의relative를 무시하고 뷰포트를 기준으로 배치됩니다. 따라서width: calc(100% - 32px)에서100%는 부모가 아닌 뷰포트 너비입니다. 모바일에서는 앱 컨테이너가 전체 화면이므로 문제없지만, 데스크톱에서 앱이 중앙 정렬될 경우 헤더가 앱 영역을 벗어날 수 있습니다.
maxWidth로 어느 정도 방어되지만, 헤더가 앱 컨테이너 내에서 중앙 정렬되지 않을 수 있습니다.sticky포지셔닝이 이 경우 더 적합할 수 있습니다.♻️ `sticky` 사용 제안
- <div className="relative px-4"> + <div className="px-4"> <Header type="back" title="리뷰관리" backFn={() => navigate(-1)} - className="fixed top-0 z-[5] bg-white" - style={{ width: 'calc(100% - 32px)', maxWidth: 'calc(var(--app-width) - 32px)' }} + className="sticky top-0 z-[5] bg-white" /> - <section className="mt-12 flex flex-col gap-5 py-2">{renderReviews()}</section> + <section className="flex flex-col gap-5 py-2">{renderReviews()}</section> </div>
sticky는 부모 컨테이너 내에서 동작하므로 별도의 width 계산이나 margin-top 보정이 불필요합니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/myPage/MyReview.tsx` around lines 16 - 24, The Header is using position: fixed with an inline style width: 'calc(100% - 32px)' which is viewport-based and can make the header escape the centered app container on wide screens; change the Header from fixed to sticky (remove the "fixed top-0" class and use "sticky top-0" or equivalent) and remove the inline width calc so it inherits the parent container width (you can keep the maxWidth prop or class for limits); update references in this file to the Header component and its className/style usage to ensure the header remains contained and aligned within the parent .relative wrapper.src/pages/myPage/MainMyPage.tsx (2)
14-15:useAuthStore()를 두 번 호출할 필요 없이 하나로 합칠 수 있습니다.♻️ 리팩터링 제안
- const { user } = useAuthStore(); - const { logout } = useAuthStore(); + const { user, logout } = useAuthStore();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/myPage/MainMyPage.tsx` around lines 14 - 15, Call useAuthStore() only once and destructure both user and logout from that single call instead of calling useAuthStore() twice; locate the two separate calls to useAuthStore in MainMyPage.tsx and replace them with a single const { user, logout } = useAuthStore() to avoid duplicate store subscriptions.
30-35: 로그아웃 처리 전에navigate를 먼저 호출하면 상태 초기화 전에 라우팅이 시작됩니다.
logout()및queryClient.clear()완료 후navigate를 호출하는 것이 의미상 더 명확합니다.♻️ 순서 개선 제안
onClick={() => { - navigate('/home'); logout(); queryClient.clear(); setFooterProps(0); + navigate('/home'); }}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/myPage/MainMyPage.tsx` around lines 30 - 35, The current onClick calls navigate('/home') before clearing state; change the order so logout(), await any async logout (if logout returns a Promise), and call/await queryClient.clear() and setFooterProps(0) first, then call navigate('/home'); reference the onClick handler and functions navigate, logout, queryClient.clear, and setFooterProps to locate and update the sequence and add awaits if those functions are asynchronous.src/shared/utils/operatingHours.ts (1)
1-1: 파라미터 이름에 오타가 있습니다:opStirng→opString✏️ 수정 제안
-export const getTodayOperatingHours = (opStirng: string) => { +export const getTodayOperatingHours = (opString: string) => { const todayDay = new Date().getDay(); const dayMapper = ['일', '월', '화', '수', '목', '금', '토']; - if (!opStirng.includes(',')) return opStirng; + if (!opString.includes(',')) return opString; - const todayOperation = opStirng.split(',').find((x) => x.startsWith(`${dayMapper[todayDay]}:`)); + const todayOperation = opString.split(',').find((x) => x.startsWith(`${dayMapper[todayDay]}:`)); return todayOperation; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/utils/operatingHours.ts` at line 1, The parameter name in getTodayOperatingHours is misspelled as opStirng; rename it to opString throughout the function signature, all internal references, and any callers to remove the typo and keep naming consistent (update any type annotations or JSDoc referring to opStirng as well).src/shared/components/myPage/MyStoreItem.tsx (1)
21-39:clipLink함수가DetailHeader.tsx와 중복됩니다.
DetailHeader.tsx의 리뷰에서도 언급했듯이, 모바일 감지 + Web Share API + 클립보드 폴백 로직이 두 파일에 거의 동일하게 존재합니다. 공유 유틸리티로 추출하면 중복을 제거하고 일관성을 유지할 수 있습니다.또한 Line 32의
console.log는console.error로, Line 35의navigator.clipboard.writeText는await을 추가하는 것이 좋습니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/MyStoreItem.tsx` around lines 21 - 39, Extract the duplicate share logic from MyStoreItem.tsx's clipLink (and the matching code in DetailHeader.tsx) into a shared utility function (e.g., shareOrCopyUrl) that encapsulates mobile detection, Web Share API usage, clipboard fallback, and returns status/errors so callers can handle UI state; update MyStoreItem's clipLink to call that util and only manage modal state, change the catch logging from console.log to console.error, and make navigator.clipboard.writeText awaited (i.e., await navigator.clipboard.writeText(...)) so errors propagate to the utility's catch handling.src/pages/myPage/MasterStoreList.tsx (1)
7-20: 로딩 및 에러 상태 처리가 없습니다.
useMasterStores()에서data만 구조 분해하고 있어, 네트워크 오류나 로딩 중 상태에 대한 사용자 피드백이 없습니다.isLoading,isError등을 활용해 최소한의 로딩/에러 UI를 제공하는 것을 권장합니다.♻️ 로딩/에러 처리 예시
const MasterStoreList = () => { const navigate = useNavigate(); - const { data: stores } = useMasterStores(); + const { data: stores, isLoading, isError } = useMasterStores(); + + if (isLoading) return <div className="px-4">로딩 중...</div>; + if (isError) return <div className="px-4">가게 목록을 불러오는데 실패했습니다.</div>; const renderStores = () =>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/myPage/MasterStoreList.tsx` around lines 7 - 20, MasterStoreList currently only destructures data from useMasterStores and lacks loading/error handling; update the component to also destructure isLoading and isError (and error if available) from useMasterStores, render a minimal loading state (e.g., a spinner or "Loading..." placeholder) when isLoading is true, and render an error message or retry UI when isError is true using the error details if provided; ensure renderStores/MyStoreItem still handles empty arrays and keep Header/navigation behavior unchanged.src/shared/components/myPage/FindMyStore.tsx (4)
16-18:useEffect의존성 배열에getRestaurant가 누락되어 있습니다.
getRestaurant가 컴포넌트 본문에 정의되어 있어 ESLintreact-hooks/exhaustive-deps규칙 위반이 발생할 수 있습니다.useEffect내부로 함수를 이동하거나useCallback으로 감싸는 것을 권장합니다.♻️ 수정 제안: useEffect 내부로 이동
- useEffect(() => { - getRestaurant(); - }, []); - - const getRestaurant = async () => { - try { - const res = await getMasterRestaurant(); - setRestaurants(res); - setIsComplete(true); - } catch (e) { - console.error('사장님 가게 가져오기 실패: ' + e); - } - }; + useEffect(() => { + const getRestaurant = async () => { + try { + const res = await getMasterRestaurant(); + setRestaurants(res); + setIsComplete(true); + } catch (e) { + console.error('사장님 가게 가져오기 실패: ' + e); + } + }; + getRestaurant(); + }, []);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/FindMyStore.tsx` around lines 16 - 18, The useEffect in the FindMyStore component calls getRestaurant without listing it in the dependency array, which breaks react-hooks/exhaustive-deps; fix by either moving the getRestaurant implementation inside the useEffect so nothing external is referenced, or wrap getRestaurant in useCallback and add getRestaurant to the useEffect dependency array (i.e., useEffect(() => { getRestaurant(); }, [getRestaurant])); ensure the chosen approach preserves any closures/state used by getRestaurant.
83-90:SearchInput이 렌더링되지만 기능이 없습니다.
onKeyDown과onSearch핸들러가 모두 주석 처리되어 있어 검색 입력 필드가 아무 동작도 하지 않습니다. 이제 마운트 시 자동으로 데이터를 불러오는 방식으로 변경되었으므로, 검색 입력 UI를 제거하거나 클라이언트 사이드 필터링 용도로 활용하는 것을 고려해 주세요.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/FindMyStore.tsx` around lines 83 - 90, SearchInput is rendered but inert because onKeyDown and onSearch are commented out; either remove the input or wire it up for client-side filtering: re-enable or implement the event handlers in FindMyStore by connecting SearchInput's onChange (already using setSearchQuery) to a debounced filter function that filters the mounted data set (use the searchQuery state) or call the existing handleKeyDown/onSearch handlers (uncomment and adapt them) to trigger the same fetch/filter logic; ensure SearchInput's props include onKeyDown={handleKeyDown} and/or onSearch={onSearch} and that those functions reference searchQuery and the store list to perform filtering or re-fetching.
14-14: 주석 처리된 코드를 정리해 주세요.
isFirstSearch,handleKeyDown,onSearch등 이전 검색 로직이 주석으로 남아 있습니다. 버전 관리 시스템에서 히스토리를 확인할 수 있으므로, 사용하지 않는 코드는 제거하는 것이 좋습니다.Also applies to: 29-45
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/FindMyStore.tsx` at line 14, Remove the leftover commented-out legacy search logic to clean up the file: delete the commented declarations and functions including isFirstSearch (useRef), handleKeyDown, onSearch and any other commented search-related blocks between the indicated ranges (e.g., the commented lines around 14 and 29-45) so only active, current search logic remains; ensure imports or references to these symbols are also removed if they become unused (e.g., remove unused useRef import).
97-97: CSScalc()표현식에 연산자 앞 공백이 누락되었습니다.
calc(var(--app-width)* 0.8)에서*앞에 공백이 없습니다. CSS 사양에서calc()내*,/연산자 양쪽에 공백이 필요하진 않지만,+,-는 공백이 필수입니다. 다만 일관성과 가독성을 위해calc(var(--app-width) * 0.8)로 수정하는 것을 권장합니다.♻️ 수정 제안
- style={{ maxWidth: 'calc(var(--app-width)* 0.8)' }} + style={{ maxWidth: 'calc(var(--app-width) * 0.8)' }}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/FindMyStore.tsx` at line 97, In FindMyStore.tsx update the inline style expression that sets maxWidth: find the JSX style prop containing "style={{ maxWidth: 'calc(var(--app-width)* 0.8)' }}" and add spacing around the multiplication operator so the value becomes "calc(var(--app-width) * 0.8)"; this improves readability and consistency while keeping the same computation.src/shared/components/detail/DetailHeader.tsx (1)
80-98:clipLink로직이MyStoreItem.tsx와 거의 동일하게 중복됩니다.이 함수의 모바일 감지, Web Share API 호출, 클립보드 폴백 로직이
src/shared/components/myPage/MyStoreItem.tsx(lines 21-39)와 사실상 동일합니다. 공유 유틸리티 함수로 추출하면 유지보수가 쉬워집니다.추가로 몇 가지 사소한 문제가 있습니다:
- Line 91: 에러 로깅에
console.log대신console.error를 사용하는 것이 적절합니다.- Line 94:
navigator.clipboard.writeText는 Promise를 반환하지만await없이 호출되어, 클립보드 쓰기 실패 시 에러가 무시됩니다.♻️ 에러 처리 개선 예시 (최소 수정)
} catch (err) { - console.log('공유 중 에러 발생 : ' + err); + console.error('공유 중 에러 발생 : ', err); } } else { - navigator.clipboard.writeText(window.location.href); + await navigator.clipboard.writeText(window.location.href); setIsShareModalOpen(false);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/detail/DetailHeader.tsx` around lines 80 - 98, Extract the sharing logic from clipLink in DetailHeader (the mobile detection, navigator.share call and clipboard fallback) into a shared utility used by both DetailHeader.tsx and MyStoreItem.tsx to remove duplication; in that refactor, ensure error logging uses console.error instead of console.log for the catch branch around navigator.share, and await navigator.clipboard.writeText (with try/catch) so clipboard write failures are handled and you can reliably call setIsShareModalOpen(false) / setIsCopiedModalOpen(true) only after a successful write; reference the existing symbols clipLink, navigator.share, navigator.clipboard.writeText, setIsShareModalOpen and setIsCopiedModalOpen and the other copy in MyStoreItem.tsx when moving the logic.src/shared/components/myPage/AuthMaster.tsx (2)
64-68:img태그에alt속성이 누락되어 있습니다.접근성을 위해
alt속성을 추가하세요.♻️ 수정 제안
{previewUrl ? ( - <img src={previewUrl} className="size-[80%]" /> + <img src={previewUrl} className="size-[80%]" alt="사업자 등록증 미리보기" /> ) : ( - <img src={upload} className="h-[35%] w-[40%]" /> + <img src={upload} className="h-[35%] w-[40%]" alt="이미지 업로드" /> )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/AuthMaster.tsx` around lines 64 - 68, The two <img> elements render either previewUrl or upload but are missing alt attributes; update both <img> tags (the one using previewUrl and the fallback using upload) to include meaningful alt text (e.g., alt describing the uploaded/preview image or "uploaded file preview") and ensure the values are properly passed as string literals or from a prop/variable as needed to satisfy accessibility and linter requirements in AuthMaster.tsx.
80-87: 제출 중(isPending) 상태에서 버튼이 비활성화 표시되지 않습니다.
isPending이true일 때handVerification내부에서 early return하지만, 사용자에게는 아무런 시각적 피드백이 없습니다.disabled속성과 스타일을 추가하는 것을 권장합니다.♻️ 수정 제안
<button - className="fixed bottom-4 left-[10%] right-[10%] mx-auto h-[48px] w-[80%] max-w-[480px] rounded-[10px] bg-[var(--primary)] font-bold text-white" - onClick={handVerification} + className="fixed bottom-4 left-[10%] right-[10%] mx-auto h-[48px] w-[80%] max-w-[480px] rounded-[10px] bg-[var(--primary)] font-bold text-white disabled:opacity-50" + onClick={handleVerification} + disabled={isPending} > - 다음 + {isPending ? '제출 중...' : '다음'} </button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/AuthMaster.tsx` around lines 80 - 87, The "다음" button lacks disabled styling when isPending is true; update the button rendered when selectedFile to include a disabled attribute driven by isPending (or by (!selectedFile || isPending)) and add conditional classes on the same element (e.g., apply opacity-50 and cursor-not-allowed when isPending) so users see it is inactive; keep the existing handVerification early-return logic but ensure the button cannot be clicked when disabled by binding disabled and toggling visual styles in the JSX where selectedFile and handVerification are referenced.
🤖 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/add/StoreCheck.tsx`:
- Around line 22-24: Remove the debug useEffect that calls console.log(location)
and then remove the now-unused useLocation import and the const location =
useLocation() declaration; specifically delete the useEffect block referencing
location, remove the import of useLocation at the top, and remove the location
variable (so no unused symbols remain).
In `@src/pages/myPage/MasterStoreList.tsx`:
- Line 12: The list-rendered component returned by renderStores is missing the
required React key prop; update the map in renderStores so each <MyStoreItem>
receives a stable unique key (e.g., key={store.id} or
key={`store-${store.id}`}), falling back to the array index only if no unique id
exists, ensuring the change is applied where renderStores maps over stores and
passes store into MyStoreItem.
In `@src/shared/components/myPage/AuthMaster.tsx`:
- Line 31: Rename the misspelled function handVerification to handleVerification
to match existing handler naming (like handleUpload, handleChange); update the
function declaration name and all references/call sites (e.g., the onClick
handler that currently invokes handVerification) to call handleVerification
instead so the component uses consistent names.
- Around line 13-17: The cleanup in useEffect is capturing a stale previewUrl
because its dependency array is empty; change to track the latest value via a
ref (e.g., create previewUrlRef and update previewUrlRef.current whenever
previewUrl changes or inside handleChange), then in the useEffect cleanup call
URL.revokeObjectURL(previewUrlRef.current) if it is non-empty; update
handleChange to set both previewUrl state and previewUrlRef.current so the
cleanup sees the latest URL and revokes it on unmount or replacement.
In `@src/shared/components/myPage/FindMyStore.tsx`:
- Around line 59-60: The placeholder string '주소주소주소주소' in the FindMyStore
component should be replaced with real data or removed: update the
MasterStoreResponse type to include an address field (e.g., address or
fullAddress), populate that field where the store data is constructed/fetched,
and then render it instead of the hardcoded text (replace the <p> that uses the
hardcoded value to use rest.address or rest.fullAddress); alternatively, if
address is intentionally unavailable, remove the placeholder <p> entirely from
the FindMyStore component.
In `@src/shared/components/myPage/MyStoreItem.tsx`:
- Around line 42-43: The renderImages function is missing a key on the <img>
elements; update renderImages (the urls.map callback) to add a unique, stable
key prop to each <img> (e.g., key={url} and if urls might not be unique use
key={`${url}-${index}`} or use the map index as a fallback) and also include an
appropriate alt attribute for accessibility; target the renderImages function
and the <img> elements in that map callback when making the change.
- Line 57: The component MyStoreItem currently renders a hardcoded review count
"(333)"; replace that static value with the real data by reading the
totalReviewCount field from the MasterStoreResponse prop/state passed into
MyStoreItem (refer to the prop/variable that holds MasterStoreResponse in this
file), and render it inside the span (e.g., format as `({totalReviewCount})`);
ensure you handle missing/undefined values (fallback to 0 or hide) and keep the
existing className "text-sm font-medium text-[var(--gray-5)]" on the span.
- Around line 64-66: The image gallery container is using overflow-y-auto which
prevents horizontal scrolling; update the className on the element that renders
the images (the div wrapping renderImages(store.mainImages) in MyStoreItem.tsx)
to use overflow-x-auto (and optionally keep overflow-y-hidden or remove vertical
overflow) so the flex row of images can scroll horizontally.
In `@src/shared/icons/Bookmark.tsx`:
- Line 13: In the Bookmark.tsx component replace the SVG attribute stroke-width
with the JSX/TypeScript-friendly camelCase strokeWidth on the <circle> element
(and any other SVG elements using hyphenated attributes) so the prop names match
React's expectations; also make the same replacement in Share.tsx where the same
hyphenated SVG attributes appear to eliminate the TypeScript/JSX errors.
In `@src/shared/icons/Share.tsx`:
- Line 13: The SVG circle in Share.tsx uses the kebab-case attribute
stroke-width which React ignores; update the <circle> element (the circle with
cx="12.5" cy="12.5" r="12.25" fill="white" stroke="#DBDDE1" ...) to use the
React prop name strokeWidth instead of stroke-width (same fix applied in
Bookmark.tsx) so the stroke renders correctly and React warnings are eliminated.
In `@src/shared/queries/user/useMasterStores.ts`:
- Around line 4-10: The query in useMasterStores sets staleTime to 24h and
gcTime to 1h which causes the cache to be garbage-collected before the stale
period ends; update useMasterStores so gcTime is at least as large as staleTime
(e.g., set gcTime to 24h or greater) to ensure cached data persists for the full
staleTime and the intended caching behavior works.
In `@src/shared/store/useAuthStore.ts`:
- Around line 36-37: The auth store is initialized with a hardcoded user object
(user: { userId: 1, role: 'OWNER' }) which must be removed; update the initial
state in useAuthStore (the store creator that defines user) to use null instead
of the hardcoded object so new sessions don't start as OWNER and so the persist
middleware writes a neutral auth state; also remove or replace the commented
line (// user: null) so the default is explicitly null.
In `@src/shared/utils/operatingHours.ts`:
- Around line 7-9: Fix the typo opStirng → opString and make the return explicit
and safe: ensure the variable todayOperation (and the surrounding function) uses
an explicit return type of string and when using opString.split(...).find(...)
coerce a fallback with ?? '' so find’s possible undefined becomes an empty
string; reference todayOperation, opString, and dayMapper when making the
change.
---
Outside diff comments:
In `@src/shared/components/myPage/AuthMaster.tsx`:
- Around line 23-29: The handleChange in AuthMaster sets a new preview URL
without revoking the previous one, causing memory leaks; update handleChange to,
before calling URL.createObjectURL(file), check the current previewUrl (state
used by setPreviewUrl) and if present call URL.revokeObjectURL(previewUrl) to
release it, then create and set the new object URL and selected file (and also
ensure any cleanup on unmount revokes the last previewUrl if still set).
In `@src/shared/components/myPage/MyReviewItem.tsx`:
- Line 105: Replace hardcoded restaurant names with the restaurantName field
from the review object: update the JSX in MyReviewItem.tsx to use
review.restaurantName (the MyReviewResponse.restaurantName property) where the
static strings appear — specifically change the <h3> title currently rendering
"엔비햄버거", the two earlier occurrences rendering "빵빵", and the restName props
currently set as '빵빵' to restName={review.restaurantName}; ensure the component
references the existing review variable/prop and that review.restaurantName is
used consistently for display and prop passing.
---
Nitpick comments:
In `@src/pages/add/StoreCheck.tsx`:
- Around line 4-8: Remove all commented-out code throughout StoreCheck.tsx—this
includes the commented import lines (e.g., the svg imports commented above
Header), any commented state/destructuring, handlers, and JSX fragments left as
comments between the import block and the component body (areas noted around the
Header import and the commented blocks spanning the rest of the file). Delete
those commented lines rather than leaving them in place; if history is needed,
rely on Git history. Keep only active imports (like Header) and the live
component code to improve readability and maintainability.
In `@src/pages/myPage/MainMyPage.tsx`:
- Around line 14-15: Call useAuthStore() only once and destructure both user and
logout from that single call instead of calling useAuthStore() twice; locate the
two separate calls to useAuthStore in MainMyPage.tsx and replace them with a
single const { user, logout } = useAuthStore() to avoid duplicate store
subscriptions.
- Around line 30-35: The current onClick calls navigate('/home') before clearing
state; change the order so logout(), await any async logout (if logout returns a
Promise), and call/await queryClient.clear() and setFooterProps(0) first, then
call navigate('/home'); reference the onClick handler and functions navigate,
logout, queryClient.clear, and setFooterProps to locate and update the sequence
and add awaits if those functions are asynchronous.
In `@src/pages/myPage/MasterStoreList.tsx`:
- Around line 7-20: MasterStoreList currently only destructures data from
useMasterStores and lacks loading/error handling; update the component to also
destructure isLoading and isError (and error if available) from useMasterStores,
render a minimal loading state (e.g., a spinner or "Loading..." placeholder)
when isLoading is true, and render an error message or retry UI when isError is
true using the error details if provided; ensure renderStores/MyStoreItem still
handles empty arrays and keep Header/navigation behavior unchanged.
In `@src/pages/myPage/MyReview.tsx`:
- Around line 16-24: The Header is using position: fixed with an inline style
width: 'calc(100% - 32px)' which is viewport-based and can make the header
escape the centered app container on wide screens; change the Header from fixed
to sticky (remove the "fixed top-0" class and use "sticky top-0" or equivalent)
and remove the inline width calc so it inherits the parent container width (you
can keep the maxWidth prop or class for limits); update references in this file
to the Header component and its className/style usage to ensure the header
remains contained and aligned within the parent .relative wrapper.
In `@src/shared/components/detail/DetailHeader.tsx`:
- Around line 80-98: Extract the sharing logic from clipLink in DetailHeader
(the mobile detection, navigator.share call and clipboard fallback) into a
shared utility used by both DetailHeader.tsx and MyStoreItem.tsx to remove
duplication; in that refactor, ensure error logging uses console.error instead
of console.log for the catch branch around navigator.share, and await
navigator.clipboard.writeText (with try/catch) so clipboard write failures are
handled and you can reliably call setIsShareModalOpen(false) /
setIsCopiedModalOpen(true) only after a successful write; reference the existing
symbols clipLink, navigator.share, navigator.clipboard.writeText,
setIsShareModalOpen and setIsCopiedModalOpen and the other copy in
MyStoreItem.tsx when moving the logic.
In `@src/shared/components/myPage/AuthMaster.tsx`:
- Around line 64-68: The two <img> elements render either previewUrl or upload
but are missing alt attributes; update both <img> tags (the one using previewUrl
and the fallback using upload) to include meaningful alt text (e.g., alt
describing the uploaded/preview image or "uploaded file preview") and ensure the
values are properly passed as string literals or from a prop/variable as needed
to satisfy accessibility and linter requirements in AuthMaster.tsx.
- Around line 80-87: The "다음" button lacks disabled styling when isPending is
true; update the button rendered when selectedFile to include a disabled
attribute driven by isPending (or by (!selectedFile || isPending)) and add
conditional classes on the same element (e.g., apply opacity-50 and
cursor-not-allowed when isPending) so users see it is inactive; keep the
existing handVerification early-return logic but ensure the button cannot be
clicked when disabled by binding disabled and toggling visual styles in the JSX
where selectedFile and handVerification are referenced.
In `@src/shared/components/myPage/FindMyStore.tsx`:
- Around line 16-18: The useEffect in the FindMyStore component calls
getRestaurant without listing it in the dependency array, which breaks
react-hooks/exhaustive-deps; fix by either moving the getRestaurant
implementation inside the useEffect so nothing external is referenced, or wrap
getRestaurant in useCallback and add getRestaurant to the useEffect dependency
array (i.e., useEffect(() => { getRestaurant(); }, [getRestaurant])); ensure the
chosen approach preserves any closures/state used by getRestaurant.
- Around line 83-90: SearchInput is rendered but inert because onKeyDown and
onSearch are commented out; either remove the input or wire it up for
client-side filtering: re-enable or implement the event handlers in FindMyStore
by connecting SearchInput's onChange (already using setSearchQuery) to a
debounced filter function that filters the mounted data set (use the searchQuery
state) or call the existing handleKeyDown/onSearch handlers (uncomment and adapt
them) to trigger the same fetch/filter logic; ensure SearchInput's props include
onKeyDown={handleKeyDown} and/or onSearch={onSearch} and that those functions
reference searchQuery and the store list to perform filtering or re-fetching.
- Line 14: Remove the leftover commented-out legacy search logic to clean up the
file: delete the commented declarations and functions including isFirstSearch
(useRef), handleKeyDown, onSearch and any other commented search-related blocks
between the indicated ranges (e.g., the commented lines around 14 and 29-45) so
only active, current search logic remains; ensure imports or references to these
symbols are also removed if they become unused (e.g., remove unused useRef
import).
- Line 97: In FindMyStore.tsx update the inline style expression that sets
maxWidth: find the JSX style prop containing "style={{ maxWidth:
'calc(var(--app-width)* 0.8)' }}" and add spacing around the multiplication
operator so the value becomes "calc(var(--app-width) * 0.8)"; this improves
readability and consistency while keeping the same computation.
In `@src/shared/components/myPage/MyStoreItem.tsx`:
- Around line 21-39: Extract the duplicate share logic from MyStoreItem.tsx's
clipLink (and the matching code in DetailHeader.tsx) into a shared utility
function (e.g., shareOrCopyUrl) that encapsulates mobile detection, Web Share
API usage, clipboard fallback, and returns status/errors so callers can handle
UI state; update MyStoreItem's clipLink to call that util and only manage modal
state, change the catch logging from console.log to console.error, and make
navigator.clipboard.writeText awaited (i.e., await
navigator.clipboard.writeText(...)) so errors propagate to the utility's catch
handling.
In `@src/shared/utils/operatingHours.ts`:
- Line 1: The parameter name in getTodayOperatingHours is misspelled as
opStirng; rename it to opString throughout the function signature, all internal
references, and any callers to remove the typo and keep naming consistent
(update any type annotations or JSDoc referring to opStirng as well).
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
src/shared/queries/user/useMasterStores.ts (1)
4-8: 사장님 가게 목록에 적절한staleTime설정을 권장합니다.현재
staleTime이 없으면 React Query 기본값인0이 적용되어 컴포넌트 마운트·윈도우 포커스 때마다 불필요한 API 요청이 발생합니다./ownerRestaurant/my는 자주 바뀌지 않는 데이터이므로 적절한 캐시 유효 시간을 설정하는 것이 좋습니다.♻️ 제안된 변경
export const useMasterStores = () => useQuery({ queryKey: ['masterStores'], queryFn: getMasterRestaurant, + staleTime: 1000 * 60 * 5, // 5분 });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/queries/user/useMasterStores.ts` around lines 4 - 8, The useMasterStores React Query hook lacks a staleTime, causing refetches on mount/window focus; update useMasterStores (the exported function that calls useQuery with queryKey ['masterStores'] and queryFn getMasterRestaurant) to include an appropriate staleTime (e.g., several minutes) in the options so the owner restaurant list is cached and not refetched unnecessarily; add the staleTime property to the useQuery call and consider also setting cacheTime or refetchOnWindowFocus if further control is needed.src/shared/utils/operatingHours.ts (1)
1-1: 명시적 반환 타입 어노테이션 추가를 권장합니다.이전 리뷰에서 지적된 오타(
opStirng)와undefined폴백 누락은 모두 해결되었습니다. TypeScript가string을 정확히 추론하므로 런타임 문제는 없지만, 함수 시그니처에: string을 명시하면 의도를 더 명확히 전달할 수 있습니다.♻️ 제안된 변경
-export const getTodayOperatingHours = (opString: string) => { +export const getTodayOperatingHours = (opString: string): string => {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/utils/operatingHours.ts` at line 1, The function getTodayOperatingHours currently relies on TypeScript's inferred return type—add an explicit return type annotation to its signature (e.g., getTodayOperatingHours = (opString: string): string => ...) so the function intent is clear; locate the getTodayOperatingHours declaration and append the explicit ": string" return type to the function signature without changing implementation logic.src/shared/store/useAuthStore.ts (1)
36-36: 디버그용 주석을 제거하세요.이전 리뷰에서 지적된 하드코딩된 인증 상태(
user: null이 아닌 활성 값) 문제는 해결되었습니다. 다만 개발 편의를 위해 남겨진// user: { userId: 1, role: 'OWNER' }주석은 불필요한 코드 노이즈이므로 삭제하는 것이 좋습니다.♻️ 제안된 변경
- // user: { userId: 1, role: 'OWNER' }, user: null,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/store/useAuthStore.ts` at line 36, Remove the leftover debug comment "// user: { userId: 1, role: 'OWNER' }" from the auth store initialization in useAuthStore (the initial state where `user` is set), so the file no longer contains hardcoded/dev-only sample user data; update the initial state block inside the useAuthStore definition to only include production-relevant fields.src/shared/components/myPage/AuthMaster.tsx (1)
80-87:isPending상태가 버튼에 반영되지 않아 제출 중 사용자 피드백이 없습니다.
handleVerification내부에서isPending시 조기 반환 처리는 되어 있으나, 버튼에disabled처리나 로딩 인디케이터가 없어 사용자는 제출이 진행 중인지 알 수 없습니다.♻️ 리팩터 제안: 버튼에 pending 상태 반영
{selectedFile && ( <button className="fixed bottom-4 left-[10%] right-[10%] mx-auto h-[48px] w-[80%] max-w-[480px] rounded-[10px] bg-[var(--primary)] font-bold text-white" + disabled={isPending} onClick={handleVerification} > - 다음 + {isPending ? '제출 중...' : '다음'} </button> )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/components/myPage/AuthMaster.tsx` around lines 80 - 87, The submit button doesn't reflect the isPending state so users get no feedback during submission; update the JSX around the conditional-rendered button (the element currently using selectedFile and onClick={handleVerification}) to disable the button when isPending is true and show a loading indicator/text (e.g., replace "다음" with "로딩..." or a spinner) while isPending; ensure handleVerification and the isPending state (wherever isPending is defined) remain the single source of truth so clicks are prevented during pending by using the disabled prop and visually indicate progress.
🤖 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/shared/components/myPage/AuthMaster.tsx`:
- Around line 64-68: The two <img> tags in AuthMaster.tsx (the conditional using
previewUrl and the fallback using upload) are missing alt attributes; update
both <img> elements to include meaningful alt text (e.g., alt describing the
previewed image when previewUrl is present and a descriptive or empty alt for
the decorative/upload placeholder) so screen readers receive appropriate
information, ensuring you reference previewUrl and upload to set
context-specific alt values.
- Around line 38-40: The catch in submitCertificate only logs to console and
loses stack trace; add a component state (e.g., const [submitError,
setSubmitError] = useState<string | null>(null)) and in the catch of
submitCertificate call setSubmitError with a user-friendly message (and any
error.message), and log the error preserving stack (console.error('사업자 등록증 등록
실패:', e)); then render submitError in the component JSX (near the submit button)
so users see feedback and clear or update submitError on retry/success.
---
Nitpick comments:
In `@src/shared/components/myPage/AuthMaster.tsx`:
- Around line 80-87: The submit button doesn't reflect the isPending state so
users get no feedback during submission; update the JSX around the
conditional-rendered button (the element currently using selectedFile and
onClick={handleVerification}) to disable the button when isPending is true and
show a loading indicator/text (e.g., replace "다음" with "로딩..." or a spinner)
while isPending; ensure handleVerification and the isPending state (wherever
isPending is defined) remain the single source of truth so clicks are prevented
during pending by using the disabled prop and visually indicate progress.
In `@src/shared/queries/user/useMasterStores.ts`:
- Around line 4-8: The useMasterStores React Query hook lacks a staleTime,
causing refetches on mount/window focus; update useMasterStores (the exported
function that calls useQuery with queryKey ['masterStores'] and queryFn
getMasterRestaurant) to include an appropriate staleTime (e.g., several minutes)
in the options so the owner restaurant list is cached and not refetched
unnecessarily; add the staleTime property to the useQuery call and consider also
setting cacheTime or refetchOnWindowFocus if further control is needed.
In `@src/shared/store/useAuthStore.ts`:
- Line 36: Remove the leftover debug comment "// user: { userId: 1, role:
'OWNER' }" from the auth store initialization in useAuthStore (the initial state
where `user` is set), so the file no longer contains hardcoded/dev-only sample
user data; update the initial state block inside the useAuthStore definition to
only include production-relevant fields.
In `@src/shared/utils/operatingHours.ts`:
- Line 1: The function getTodayOperatingHours currently relies on TypeScript's
inferred return type—add an explicit return type annotation to its signature
(e.g., getTodayOperatingHours = (opString: string): string => ...) so the
function intent is clear; locate the getTodayOperatingHours declaration and
append the explicit ": string" return type to the function signature without
changing implementation logic.
📝 작업 내용
📢 PR Point
이미지 첨부
🔧 다음 할 일
Summary by CodeRabbit
새로운 기능
개선 사항