Create Week8 Mission1, 2, 3#68
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ 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: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthrough주요 기능을 갖춘 완전한 React 클라이언트 애플리케이션 초기화입니다. Vite + TypeScript + React Router + React Query 기반으로 인증 토큰 자동 갱신, LP(게시글) CRUD, 댓글 시스템, 무한 스크롤, 프로필 관리 기능이 통합되어 있습니다. 모든 API 호출은 axios 인터셉터로 인증 헤더를 관리하고, React Query로 상태와 캐시를 동기화하며, Tailwind와 Lucide 아이콘으로 UI를 구성합니다. Changes전체 플랫폼 구현
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 18
🧹 Nitpick comments (5)
Week08/chulee-53/mission01-02-03/README.md (1)
1-74: ⚡ Quick winREADME를 실제 구현 내용 기준으로 갱신해 주세요.
현재 문서는 템플릿 안내 중심이라, 이번 PR의 핵심 기능(검색 디바운스, 무한스크롤 스로틀, 사이드바 리팩터링)을 바로 파악하기 어렵습니다. 실행 방법/핵심 기능/주요 페이지를 프로젝트 기준으로 정리해 두는 게 좋습니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Week08/chulee-53/mission01-02-03/README.md` around lines 1 - 74, Update README.md to replace the generic Vite React template text with project-specific documentation: add a Setup/Run section with exact install and start commands (how to run dev server and build), a "Key Features" list describing "search debounce" (component SearchBar or SearchInput), "infinite-scroll throttle" (component InfiniteScrollList or useInfiniteScroll), and "sidebar refactor" (Sidebar or SidebarContainer) including short usage notes and any important props; add a "Pages / Components" section that lists main pages and components (e.g., Home, Search results, Sidebar) and a short sentence on how to exercise each feature, plus a "Development Notes" section with lint/test commands and any noteworthy implementation details or caveats (debounce/throttle timings, accessibility notes). Ensure the README clearly surfaces the three PR highlights so reviewers can immediately find and run those features.Week08/chulee-53/mission01-02-03/src/components/AddLpModal.tsx (1)
83-88: ⚡ Quick win아이콘 전용 버튼들에 접근성 이름을 추가해 주세요.
닫기/태그 제거 버튼이 아이콘만 있어 보조기기에서 의미가 불명확합니다.
♻️ 제안 코드
<button + type="button" + aria-label="모달 닫기" onClick={onClose} className="absolute top-4 right-4 text-gray-400 hover:text-white transition-colors cursor-pointer" > @@ <button type="button" + aria-label={`태그 ${tag} 제거`} onClick={() => removeTag(tag)} className="hover:text-white" >Also applies to: 163-169
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Week08/chulee-53/mission01-02-03/src/components/AddLpModal.tsx` around lines 83 - 88, The icon-only buttons in AddLpModal (e.g., the close button using the X component and other tag-remove buttons referenced around the same file) lack accessible names; add an accessible label by setting an appropriate aria-label (e.g., aria-label="Close" or aria-label="Remove tag") or include a visually-hidden text node (sr-only) inside the button so assistive technologies can convey the button's purpose; update the button elements that call onClose and the tag removal handler(s) to include these labels while preserving existing classes and handlers.Week08/chulee-53/mission01-02-03/src/pages/HomePage.tsx (1)
35-46: ⚡ Quick win정렬 토글의 선택 상태를 접근성 속성으로 노출해 주세요.
현재 토글 상태가 시각적으로만 표현되어 보조기기 사용자가 현재 정렬 상태를 알기 어렵습니다.
♻️ 제안 코드
<button + aria-pressed={order === "asc"} onClick={() => setOrder("asc")} className={`border px-3 py-1 rounded-l-lg transition-colors cursor-pointer ${order === "asc" ? "bg-white text-black" : "bg-black text-white"}`} > 오래된순 </button> <button + aria-pressed={order === "desc"} onClick={() => setOrder("desc")} className={`border px-3 py-1 rounded-r-lg transition-colors cursor-pointer ${order === "desc" ? "bg-white text-black" : "bg-black text-white"}`} > 최신순 </button>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Week08/chulee-53/mission01-02-03/src/pages/HomePage.tsx` around lines 35 - 46, The two sort buttons ("오래된순" and "최신순") only show selected state visually; add accessibility states so assistive tech can detect selection by setting aria-pressed on each button based on the order state (e.g., aria-pressed={order === "asc"} for the 오래된순 button and aria-pressed={order === "desc"} for the 최신순 button) and keep the existing onClick handlers (setOrder) and class toggles; optionally add a concise aria-label that includes the selection (e.g., "정렬: 오래된순 선택됨") to those same button elements to further clarify the current state to screen readers.Week08/chulee-53/mission01-02-03/src/components/Input.tsx (1)
11-22: ⚡ Quick win에러 메시지를 입력 필드와 접근성으로 연결해 주세요.
현재 오류 텍스트가 시각적으로만 표시되어 보조기기에서 오류 맥락을 놓칠 수 있습니다.
aria-invalid/aria-describedby를 같이 설정하는 편이 좋습니다.♻️ 제안 코드
const Input = ({ errorMessage, className, ...props }: InputProps) => { + const errorId = React.useId(); return ( <div className="flex flex-col gap-2"> <input + aria-invalid={Boolean(errorMessage)} + aria-describedby={errorMessage ? errorId : undefined} className={cn("bg-transparent text-white text-sm px-4 py-3 rounded-md outline-none border transition-colors", errorMessage ? 'border-red-500 focus:border-blue-500' : 'border-gray-500 hover:border-gray-400 focus:border-blue-500', className || '' )} {...props} /> - {errorMessage && <p className="text-red-500 text-xs">{errorMessage}</p>} + {errorMessage && <p id={errorId} className="text-red-500 text-xs">{errorMessage}</p>} </div> ); };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Week08/chulee-53/mission01-02-03/src/components/Input.tsx` around lines 11 - 22, The Input component currently renders an error paragraph visually but doesn't expose it to assistive tech; update the Input function to set aria-invalid={Boolean(errorMessage)} on the <input> and add aria-describedby pointing to the error element when errorMessage exists. Use an id for the error node derived from the input id (e.g., if props.id use `${props.id}-error`) or generate one with React's useId inside Input, and render the <p> error element with that id so screen readers can associate the message; ensure you still spread {...props} so existing id/presentational props are preserved.Week08/chulee-53/mission01-02-03/src/components/LpComments.tsx (1)
36-50: ⚡ Quick win현재 사용자 조회를 쿼리 훅으로 통합해주세요.
직접
getMyInfo()호출은 캐시를 우회해 중복 요청/상태 분산을 만듭니다.useGetMyInfo로 통합하는 편이 안정적입니다.♻️ Proposed refactor
-import { useState, useEffect } from "react"; +import { useState, useEffect } from "react"; ... -import { useAuth } from "../context/AuthContext"; -import { getMyInfo } from "../api/auth"; +import useGetMyInfo from "../hooks/queries/useGetMyInfo"; ... - const { accessToken } = useAuth(); - const [currentUserId, setCurrentUserId] = useState<number | null>(null); + const { data: me } = useGetMyInfo(); + const currentUserId = me?.data?.id ?? null; ... - useEffect(() => { - const fetchUserId = async () => { - if (accessToken) { - try { - const response = await getMyInfo(); - if (response?.data?.id) { - setCurrentUserId(response.data.id); - } - } catch (error) { - console.error("유저 정보를 불러오는데 실패했습니다.", error); - } - } - }; - fetchUserId(); - }, [accessToken]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Week08/chulee-53/mission01-02-03/src/components/LpComments.tsx` around lines 36 - 50, The current useEffect/fetchUserId calls getMyInfo() directly which bypasses the app's query caching and causes duplicate requests; replace that logic with the centralized query hook useGetMyInfo: import and call useGetMyInfo() (or the existing hook name) instead of getMyInfo(), read the returned data/isSuccess/isLoading flags from the hook, and when the hook's data contains an id call setCurrentUserId(data.id) (remove fetchUserId and the direct getMyInfo call); also remove accessToken from the dependency array and rely on the hook to handle auth state so the component stays in sync with the global query cache.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Week08/chulee-53/mission01-02-03/index.html`:
- Line 7: Update the HTML document's <title> element so the visible tab name
matches the current mission scope: change the existing
<title>mission01-02</title> to the correct mission label (e.g.,
<title>mission01-02-03</title>) in the index.html file; locate the <title> tag
and replace its text to reflect the actual mission range.
In `@Week08/chulee-53/mission01-02-03/package.json`:
- Line 2: package.json의 "name" 필드("name": "mission01-02")가 PR 범위(01-02-03)와
불일치합니다; package.json의 name 값을 프로젝트 범위와 일치하도록 "mission01-02-03"으로 업데이트하세요 (수정 대상:
package.json의 "name" 키).
In `@Week08/chulee-53/mission01-02-03/src/api/axios.ts`:
- Around line 35-41: The interceptor accesses error.config and headers without
guards which can throw for network/cancelled errors; update the axios error
interceptor to defensively check that error and error.config exist before
reading originalRequest (the variable originalRequest) and verify
originalRequest.headers (and error.response) are defined before indexing into
headers or checking status; if any of these are missing, short-circuit by
returning Promise.reject(error) (or skip retry logic) so the interceptor never
performs property access on undefined — update the sections around
originalRequest usage and the headers access to perform null/undefined checks
and create safe defaults only when present.
In `@Week08/chulee-53/mission01-02-03/src/components/AddLpModal.tsx`:
- Around line 91-118: Replace the clickable div thumbnail with a semantic,
keyboard-focusable control by using a <label> tied to the hidden <input> (give
the input an id and use htmlFor on the label) or wrap the input inside the label
so Enter/Space and screen readers will open the file picker; keep using
fileInputRef and handleFileChange for the input's onChange, preserve previewUrl
rendering inside the label, add an accessible label text/aria-label (e.g.,
"Select LP image") and visible focus styles, and remove the div's onClick in
favor of the label/htmlFor behavior so keyboard users can open the file dialog.
In `@Week08/chulee-53/mission01-02-03/src/components/HamburgerButton.tsx`:
- Around line 7-8: The icon-only button in HamburgerButton is missing an
explicit type and accessible name; update the <button> element in the
HamburgerButton component to include type="button" to avoid accidental form
submission and add an accessible label (e.g., aria-label="Open menu" or
aria-expanded tied to state) so assistive technologies can convey the button
purpose; locate the button that uses the onClick prop in the HamburgerButton
component and add the type and appropriate aria attributes there.
In `@Week08/chulee-53/mission01-02-03/src/components/LpCard.tsx`:
- Around line 11-14: Replace the clickable <div> in LpCard.tsx with an
accessible interactive element: either a <button type="button"> that calls
navigate(`/lp/${lp.id}`) in its onClick, or a <Link to={`/lp/${lp.id}`}> (from
react-router-dom) wrapping the card content; keep the same className and
visuals, remove the div's onClick, and add an explicit accessible name (e.g.,
aria-label using lp.title or lp.id) so keyboard users can focus and activate the
card. Ensure to import Link if chosen, or set type="button" on the button to
avoid form submit behavior.
In `@Week08/chulee-53/mission01-02-03/src/components/LpComments.tsx`:
- Around line 122-124: The Enter key handler on the input currently calls
handlePostComment on any Enter press without checking IME composition; update
the component to ignore Enter while composition is active by either (A) checking
e.nativeEvent.isComposing inside the onKeyDown handler and returning early if
true before calling handlePostComment, or (B) add an isComposing state plus
onCompositionStart and onCompositionEnd handlers to set/clear that flag and have
onKeyDown return early when isComposing is true; reference the onKeyDown prop,
handlePostComment, and add onCompositionStart/onCompositionEnd or isComposing
state as needed.
In `@Week08/chulee-53/mission01-02-03/src/components/Navbar.tsx`:
- Around line 64-68: The search toggle icons (X and Search) inside the Navbar
component currently have onClick handlers directly on the SVG components
(referenced as X, Search and using isSearchOpen and toggleSearch); wrap each
icon in a <button type="button" aria-label="검색 열기/닫기"> and move the
onClick={toggleSearch} to that button so it becomes keyboard-focusable and
activated by Enter/Space, keep the existing className styling (apply to the
button or icon as appropriate) and preserve size props on the X/Search
components.
In `@Week08/chulee-53/mission01-02-03/src/hooks/mutations/usePostLogin.ts`:
- Around line 13-21: The onSuccess handler currently returns silently when
response?.data?.accessToken is missing; update the onSuccess in usePostLogin.ts
to detect the missing token and treat it as a failure by showing an error alert
(e.g., alert("로그인에 실패했습니다: 토큰이 없습니다.")), clearing any partial state (call
setAccessToken(null) and remove token from storage via
setAccessTokenInStorage(null) or the existing removal helper), and avoid
navigating to "/" so the user stays on the login page; keep the existing success
branch (setAccessTokenInStorage(token); setAccessToken(token); alert success;
navigate("/")) unchanged and only add the explicit failure branch for when
response?.data?.accessToken is falsy.
In `@Week08/chulee-53/mission01-02-03/src/hooks/queries/useGetInfiniteLpList.ts`:
- Around line 11-14: The queryKey used in useGetInfiniteLpList incorrectly omits
the limit parameter, causing cache pollution because queryFn calls getLpList({
cursor: pageParam, limit, ... }) but queryKey only includes QUERY_KEY.lps,
search, order; update the queryKey in useGetInfiniteLpList to include limit
(e.g., [QUERY_KEY.lps, search, order, limit]) so different page sizes generate
separate caches and prevent stale/incorrect results from getLpList called by
queryFn.
In `@Week08/chulee-53/mission01-02-03/src/hooks/useForm.ts`:
- Around line 3-6: The generic contract UseFormProps<T> and the useForm update
logic diverge because the updater always writes string values; either constrain
the hook to string-only forms by changing UseFormProps<T> to UseFormProps<T
extends Record<string, string>> and reflect that in useForm, or make the field
updater accept the actual field type by typing the setter/update function to use
Partial<T> (or value: T[K]) and avoid coercing to string; update the validate
signature and any usages of initialValues, validate, and the useForm
setFieldValue/setValues handlers to match the chosen approach (i.e., remove
forced string casts in useForm or restrict T to string fields).
In `@Week08/chulee-53/mission01-02-03/src/hooks/useThrottle.ts`:
- Around line 14-24: The hook useThrottle currently resets the timeout on every
value change (timerId) and uses an initial lastExecuted that causes the first
update to be delayed, making it behave like debounce; change the logic to
compute remaining = interval - (Date.now() - lastExecuted.current), if remaining
<= 0 then immediately setThrottledValue(value) and set lastExecuted.current =
Date.now(), otherwise schedule a timeout for remaining (do not restart it on
each value change in a way that violates the throttle window) and clear that
timeout in the returned cleanup; also initialize lastExecuted.current to 0 (or
Date.now() - interval) so the first call can fire immediately. Ensure you
reference useThrottle, lastExecuted, setThrottledValue, interval, and timerId
when locating and updating the code.
In `@Week08/chulee-53/mission01-02-03/src/layouts/ProtectedLayout.tsx`:
- Around line 11-15: In ProtectedLayout, the call to the hook useSidebar()
happens after an early return based on accessToken, violating Rules of Hooks;
move the useSidebar() call (const { isOpen, toggle, close } = useSidebar()) to
the top of the component so all hooks are called unconditionally (before the if
(!accessToken) return and any other conditional returns) to ensure consistent
hook order during renders.
In `@Week08/chulee-53/mission01-02-03/src/pages/LpDetailPage.tsx`:
- Around line 93-95: The edit button (the button wrapping the Pencil icon in
LpDetailPage.tsx) is currently clickable but has no handler; either hide it or
render it disabled when no edit action exists: check for the presence of the
edit handler/permission (e.g., an onEdit prop, isEditable flag, or currentUser
check) and if absent, replace the interactive button with a non-interactive
element or a disabled button (add aria-disabled="true", a visually-disabled
style such as cursor-not-allowed and reduced opacity, and remove any onClick) so
it no longer appears clickable or triggers confusion.
In `@Week08/chulee-53/mission01-02-03/src/pages/MyPage.tsx`:
- Around line 81-86: The icon-only <button> that calls handleOpenEditModal and
contains the <Settings /> icon (and the other icon-only button referenced later)
lack accessible names; add an aria-label attribute to each icon-only button
(e.g., aria-label="Open settings" for the button wrapping <Settings /> and an
appropriate descriptive label for the other icon button) so screen readers can
convey their purpose; update the JSX for the button elements that render only
icons to include these aria-labels.
- Around line 117-172: The modal rendered when isEditModalOpen is true lacks
dialog semantics; update the outer modal container (the div that is shown when
isEditModalOpen) to include role="dialog" and aria-modal="true", add an id on
the <h3> title (e.g., editProfileTitle) and set aria-labelledby on the dialog to
that id, and add accessible labels for interactive controls (e.g., give the
close button an aria-label="Close profile editor"); ensure these changes are
applied around the elements referenced (isEditModalOpen modal container, the h3
title, and the close button) so screen readers can identify the dialog and its
title.
- Around line 23-26: The guard for the infinite-scroll sentinel currently uses
the general isLikedFetching (from useGetInfiniteLikedLpList), causing triggers
during background refetch; update the hook destructure to also pull
isFetchingNextPage (e.g., isFetchingNextPage: isLikedFetchingNextPage) from
useGetInfiniteLikedLpList and change the sentinel guard (the check that decides
whether to call fetchNextPage) to use that isLikedFetchingNextPage flag instead
of isLikedFetching so fetchNextPage is only suppressed while the next page is
actively loading.
In `@Week08/chulee-53/mission01-02-03/src/utils/validate.ts`:
- Around line 5-6: The empty-value checks in the validators currently return an
empty string (e.g., the `if (!value) return "";` in validate.ts), allowing
required fields to pass; change those checks in the email and password
validation functions (e.g., the functions used by `validateSignin`, such as
validateEmail and validatePassword) to return a clear required-field error (for
example "필수 입력 항목입니다." or "이메일을 입력해주세요."/"비밀번호를 입력해주세요.") instead of "" so empty
email/password fail validation, and keep the existing regex/strength checks
after that early return.
---
Nitpick comments:
In `@Week08/chulee-53/mission01-02-03/README.md`:
- Around line 1-74: Update README.md to replace the generic Vite React template
text with project-specific documentation: add a Setup/Run section with exact
install and start commands (how to run dev server and build), a "Key Features"
list describing "search debounce" (component SearchBar or SearchInput),
"infinite-scroll throttle" (component InfiniteScrollList or useInfiniteScroll),
and "sidebar refactor" (Sidebar or SidebarContainer) including short usage notes
and any important props; add a "Pages / Components" section that lists main
pages and components (e.g., Home, Search results, Sidebar) and a short sentence
on how to exercise each feature, plus a "Development Notes" section with
lint/test commands and any noteworthy implementation details or caveats
(debounce/throttle timings, accessibility notes). Ensure the README clearly
surfaces the three PR highlights so reviewers can immediately find and run those
features.
In `@Week08/chulee-53/mission01-02-03/src/components/AddLpModal.tsx`:
- Around line 83-88: The icon-only buttons in AddLpModal (e.g., the close button
using the X component and other tag-remove buttons referenced around the same
file) lack accessible names; add an accessible label by setting an appropriate
aria-label (e.g., aria-label="Close" or aria-label="Remove tag") or include a
visually-hidden text node (sr-only) inside the button so assistive technologies
can convey the button's purpose; update the button elements that call onClose
and the tag removal handler(s) to include these labels while preserving existing
classes and handlers.
In `@Week08/chulee-53/mission01-02-03/src/components/Input.tsx`:
- Around line 11-22: The Input component currently renders an error paragraph
visually but doesn't expose it to assistive tech; update the Input function to
set aria-invalid={Boolean(errorMessage)} on the <input> and add aria-describedby
pointing to the error element when errorMessage exists. Use an id for the error
node derived from the input id (e.g., if props.id use `${props.id}-error`) or
generate one with React's useId inside Input, and render the <p> error element
with that id so screen readers can associate the message; ensure you still
spread {...props} so existing id/presentational props are preserved.
In `@Week08/chulee-53/mission01-02-03/src/components/LpComments.tsx`:
- Around line 36-50: The current useEffect/fetchUserId calls getMyInfo()
directly which bypasses the app's query caching and causes duplicate requests;
replace that logic with the centralized query hook useGetMyInfo: import and call
useGetMyInfo() (or the existing hook name) instead of getMyInfo(), read the
returned data/isSuccess/isLoading flags from the hook, and when the hook's data
contains an id call setCurrentUserId(data.id) (remove fetchUserId and the direct
getMyInfo call); also remove accessToken from the dependency array and rely on
the hook to handle auth state so the component stays in sync with the global
query cache.
In `@Week08/chulee-53/mission01-02-03/src/pages/HomePage.tsx`:
- Around line 35-46: The two sort buttons ("오래된순" and "최신순") only show selected
state visually; add accessibility states so assistive tech can detect selection
by setting aria-pressed on each button based on the order state (e.g.,
aria-pressed={order === "asc"} for the 오래된순 button and aria-pressed={order ===
"desc"} for the 최신순 button) and keep the existing onClick handlers (setOrder)
and class toggles; optionally add a concise aria-label that includes the
selection (e.g., "정렬: 오래된순 선택됨") to those same button elements to further
clarify the current state to screen readers.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e9d37bb6-6bf3-490f-8596-aae26d58047e
⛔ Files ignored due to path filters (3)
Week08/chulee-53/mission01-02-03/package-lock.jsonis excluded by!**/package-lock.jsonWeek08/chulee-53/mission01-02-03/src/images/defaultavatar.pngis excluded by!**/*.pngWeek08/chulee-53/mission01-02-03/src/images/google_logo.pngis excluded by!**/*.png
📒 Files selected for processing (66)
Week08/chulee-53/mission01-02-03/.gitignoreWeek08/chulee-53/mission01-02-03/README.mdWeek08/chulee-53/mission01-02-03/eslint.config.jsWeek08/chulee-53/mission01-02-03/index.htmlWeek08/chulee-53/mission01-02-03/package.jsonWeek08/chulee-53/mission01-02-03/src/App.cssWeek08/chulee-53/mission01-02-03/src/App.tsxWeek08/chulee-53/mission01-02-03/src/api/auth.tsWeek08/chulee-53/mission01-02-03/src/api/axios.tsWeek08/chulee-53/mission01-02-03/src/api/comments.tsWeek08/chulee-53/mission01-02-03/src/api/lp.tsWeek08/chulee-53/mission01-02-03/src/components/AddLpModal.tsxWeek08/chulee-53/mission01-02-03/src/components/CommentsSkeleton.tsxWeek08/chulee-53/mission01-02-03/src/components/HamburgerButton.tsxWeek08/chulee-53/mission01-02-03/src/components/Input.tsxWeek08/chulee-53/mission01-02-03/src/components/LpCard.tsxWeek08/chulee-53/mission01-02-03/src/components/LpCardSkeleton.tsxWeek08/chulee-53/mission01-02-03/src/components/LpComments.tsxWeek08/chulee-53/mission01-02-03/src/components/Navbar.tsxWeek08/chulee-53/mission01-02-03/src/components/Sidebar.tsxWeek08/chulee-53/mission01-02-03/src/constants/delay.tsWeek08/chulee-53/mission01-02-03/src/constants/key.tsWeek08/chulee-53/mission01-02-03/src/context/AuthContext.tsxWeek08/chulee-53/mission01-02-03/src/hooks/mutations/useDeleteAccount.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/useDeleteComment.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/useDeleteLike.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/useDeleteLp.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/usePatchComment.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/usePatchMyInfo.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/usePostComment.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/usePostLike.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/usePostLogin.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/usePostLogout.tsWeek08/chulee-53/mission01-02-03/src/hooks/mutations/usePostLp.tsWeek08/chulee-53/mission01-02-03/src/hooks/queries/useGetInfiniteLikedLpList.tsWeek08/chulee-53/mission01-02-03/src/hooks/queries/useGetInfiniteLpComment.tsWeek08/chulee-53/mission01-02-03/src/hooks/queries/useGetInfiniteLpList.tsWeek08/chulee-53/mission01-02-03/src/hooks/queries/useGetLpComment.tsWeek08/chulee-53/mission01-02-03/src/hooks/queries/useGetLpDetail.tsWeek08/chulee-53/mission01-02-03/src/hooks/queries/useGetLpList.tsWeek08/chulee-53/mission01-02-03/src/hooks/queries/useGetMyInfo.tsWeek08/chulee-53/mission01-02-03/src/hooks/useDebounce.tsWeek08/chulee-53/mission01-02-03/src/hooks/useForm.tsWeek08/chulee-53/mission01-02-03/src/hooks/useLocalStorage.tsWeek08/chulee-53/mission01-02-03/src/hooks/useSidebar.tsxWeek08/chulee-53/mission01-02-03/src/hooks/useThrottle.tsWeek08/chulee-53/mission01-02-03/src/index.cssWeek08/chulee-53/mission01-02-03/src/layouts/Layout.tsxWeek08/chulee-53/mission01-02-03/src/layouts/ProtectedLayout.tsxWeek08/chulee-53/mission01-02-03/src/main.tsxWeek08/chulee-53/mission01-02-03/src/pages/GoogleLoginRedirectPage.tsxWeek08/chulee-53/mission01-02-03/src/pages/HomePage.tsxWeek08/chulee-53/mission01-02-03/src/pages/LoginPage.tsxWeek08/chulee-53/mission01-02-03/src/pages/LpDetailPage.tsxWeek08/chulee-53/mission01-02-03/src/pages/MyPage.tsxWeek08/chulee-53/mission01-02-03/src/pages/SignupPage.tsxWeek08/chulee-53/mission01-02-03/src/types/auth.tsWeek08/chulee-53/mission01-02-03/src/types/comments.tsWeek08/chulee-53/mission01-02-03/src/types/common.tsWeek08/chulee-53/mission01-02-03/src/types/lp.tsWeek08/chulee-53/mission01-02-03/src/utils/validate.tsWeek08/chulee-53/mission01-02-03/src/vite-env.d.tsWeek08/chulee-53/mission01-02-03/tsconfig.app.jsonWeek08/chulee-53/mission01-02-03/tsconfig.jsonWeek08/chulee-53/mission01-02-03/tsconfig.node.jsonWeek08/chulee-53/mission01-02-03/vite.config.ts
📝 미션 번호
8주차 Misson 1, 2, 3
📋 구현 사항
📎 스크린샷
mission01.mp4
mission02.mp4
mission03.mp4
✅ 체크리스트
🤔 질문 사항
Summary by CodeRabbit
릴리스 노트