Skip to content

스프린트 미션 11 제출 - 김윤기#83

Merged
pers0n4 merged 113 commits intocodeit-sprint-fullstack:next-김윤기from
rklpoi5678:next-김윤기
Jan 11, 2026

Hidden character warning

The head ref may contain hidden characters: "next-\uae40\uc724\uae30"
Merged

스프린트 미션 11 제출 - 김윤기#83
pers0n4 merged 113 commits intocodeit-sprint-fullstack:next-김윤기from
rklpoi5678:next-김윤기

Conversation

@rklpoi5678
Copy link
Collaborator

요구사항

[x] Github에 위클리 미션 PR을 만들어 주세요.

[x] React 및 Express를 사용해 진행합니다.

[x] TypeScript를 활용해 프로젝트의 필요한 곳에 타입을 명시해 주세요.

[x] any 타입의 사용은 최소화해 주세요.

[x] 복잡한 객체 구조나 배열 구조를 가진 변수에 인터페이스 또는 타입 별칭을 사용하세요.

[x] Union, Intersection, Generics 등 고급 타입을 적극적으로 사용해 주세요.

[x] 타입 별칭 또는 유틸리티 타입을 사용해 타입 복잡성을 줄여주세요.

[x] 타입스크립트 컴파일러가 에러 없이 정상적으로 작동해야 합니다.

프론트엔드

[x] 기존 React(혹은 Next) 프로젝트를 타입스크립트 프로젝트로 마이그레이션 해주세요.
[x] TypeScript를 활용해 프로젝트의 필요한 곳에 타입을 명시해 주세요.

백엔드 (참고:tsx사용하였습니다)

[x] 기존 Express.js 프로젝트를 타입스크립트 프로젝트로 마이그레이션 해주세요.
[x] tsconfig.json 파일을 생성하고, 필요한 컴파일러 옵션을 설정해야 합니다. (예: outDir).
[x] TypeScript 관련 명령어를 package.json에 설정해 주세요. (예: 빌드 및 개발 서버 실행 명령어).
[x] ts-node와 nodemon을 사용하여 개발 환경을 구성합니다.
[x] nodemon과 함께 ts-node를 사용하여 . ts 파일이 변경될 때 서버를 자동으로 재시작하도록 설정합니다.
[x] Mongoose나 Prisma 등 ORM을 사용하는 경우, 모델에 대한 인터페이스 또는 타입을 정의합니다.
[x] 필요한 경우, declare를 사용하여 타입을 오버라이드하거나 확장합니다.

  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

@rklpoi5678 rklpoi5678 requested a review from devbini December 24, 2025 11:05
@rklpoi5678 rklpoi5678 self-assigned this Dec 24, 2025
@devbini devbini requested review from pers0n4 and removed request for devbini January 8, 2026 07:39
Comment on lines 34 to 36
const handlePasswordVisible = () => {
setPasswordVisible(!passwordVisible);
setPasswordVisible((prev) => !prev);
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. handlePasswordVisible 함수의 이름이 동작을 충분히 서술하지 못하고 있습니다. 수행하는 역할을 명확하게 드러낼 수 있게 이름을 바꿔보면 좋을 것 같습니다.
  2. 토글은 하나의 동작으로 보일 수 있지만, 사실은 on과 off 2가지 동작이 조합으로 구성됩니다. UI 바인딩을 위해서 함수 하나로 정의하게 되지만, 내부 로직은 명확하게 구분하는 게 좋습니다. 현재 상태가 무엇인지 모르는 상태에서 !prev 같은 구문을 사용하면 의도와는 반대로 동작하는 위험이 발생할 가능성이 높습니다.

import { Modal } from '@/components/ui/dialog';
import { cn } from '@/libs/cn';
import { signupFormSchema } from '@/libs/schemas/auth.schema';
import { type signupFormSchema, signupSchema } from '@/libs/schemas/auth.schema';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signupFormSchema, signupSchema 둘 다 유사한 네이밍 패턴인데 signupFormSchema은 타입이고 signupSchema은 객체인가요?
추상화 수준이 다르다면 파일 계층 자체를 분리하거나, 같은 파일에 있다면 네이밍 패턴을 다르게 해서 어떤 것이 타입이고 어떤 것이 객체인지 명확하게 인식할 수 있도록 하는 게 좋습니다.
e.g. lib/schemas.ts 파일 내 signupFormSchemaInterface와 signupFormSchema vs interfaces.ts 파일 내 signupFormSchema와 schemas.ts 파일 내 signupFormSchema

Comment on lines +20 to +30
const {
register,
handleSubmit,
reset,
formState: { errors, isSubmitting }
} = useForm<ArticleCommentValues>({
resolver: zodResolver(articleCommentSchema),
defaultValues: {
context: ""
}
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

유사한 형태로 반복되는 패턴이 여러 번 보이는데, 이 부분을 커스텀 hook으로 정의해서 사용하면 반복을 줄일 수 있습니다.

Comment on lines +65 to +70
<Button
type="submit"
disabled={isSubmitting}
className="flex justify-center items-center py-3 px-5.75 grow-0 bg-gray-400 border-none rounded-md text-white whitespace-nowrap cursor-pointer hover:bg-primary-100">
등록
</Button>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컴포넌트로 정의한 것 치고는 className이 과하게 많이 들어가는 느낌이긴 하네요. 🤔
기본값으로 넣을 수 있는 스타일이라면 Button 컴포넌트 자체에 넣고, 유형으로 구분할 수 있는 조합이라면 variants 같은 느낌으로 사전에 정의한 유형을 지정하는 형태로 사용할 수 있다면 더 좋을 것 같습니다.

Comment on lines +19 to +65
{comments.length > 0 ? (
comments.map((comment: ArticleComment) => (
<li
key={comment.id}
className="border-2.5 flex flex-col gap-6 border border-t-0 border-r-0 border-l-0 border-solid border-gray-300 bg-gray-50 px-0 py-3"
>
<div className="flex justify-between">
<p className="font-pretendard flex-1 px-2 text-gray-800">
{comment.context}
</p>
<DropdownContent articleId={article.id} comment={comment} />
</div>
<div className="mb-1.5 flex items-center gap-2">
<Image
src={comment.author?.userProfile?.photoUrl || DefaultImg}
alt="avatar"
width={32}
height={32}
className="h-8 w-8 shrink-0 rounded-full object-cover"
/>
<div>
<span className="font-pretendard text-xs leading-4.5 text-gray-600">
{comment.author?.nickname}
</span>
<p className="text-xs leading-4.5 text-gray-400">
{formatDate(comment.createdAt)}
</p>
</div>
</div>
</li>
))
) : (
<>
<Image
className="mb-4 self-center"
width={140}
height={140}
src={CommentEmptyImg}
alt="comment-empty-img"
/>
<p className="font-pretendard text-center leading-6.5 text-gray-400">
아직 댓글이 없어요,
<br />
지금 댓글을 달아보세요!
</p>
</>
)}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

최종 render 영역은 간결하게 유지하는 편이 좋습니다.
데이터가 없을 때 노출하는 이미지 영역과 데이터가 있는 경우 구성하는 UI를 분리해서 생각해보면 어떨까요?

Comment on lines +31 to +35
export type ArticleFormValues = z.infer<typeof articleFormSchema>;
export type ArticleCommentValues = z.infer<typeof articleCommentSchema>;
export type UpdateCommentFormValues = z.infer<
typeof updateArticleCommentSchema
>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이전에도 네이밍에 관해서 코멘트를 남기긴 했는데, zod에서 z.infer를 사용하는 example이나 다른 사람들이 사용할 때 나타나는 패턴을 참고해보세요.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

프로젝트 내에서 여러 번 사용될 것 같은 함수들을 모아두는 건 좋네요.


export const articleService = {
getBestArticles: () =>
cookieFetch<CommonResponse<Article[]>>(`/api/v1/articles/best`, {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반복되는 url path는 상수로 정의해서 사용하면 좋을 것 같습니다.

@pers0n4 pers0n4 merged commit 1d5d4f9 into codeit-sprint-fullstack:next-김윤기 Jan 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants