Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[refactor] 모노레포 구조로 폴더 구조 리팩토링 #34

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from

Conversation

jinoo0306
Copy link
Member

@jinoo0306 jinoo0306 commented Jan 14, 2025

#️⃣연관된 이슈

#28

📝작업 내용

  1. 폴더 구조 변경
  • 기존 프로젝트를 모노레포 구조로 변경.
  • client 폴더 내부에 user와 admin 프로젝트를 분리.
  • packages 폴더 내부에 공통 모듈(shared, components, styles, utils, config) 추가.
  1. 공통 설정 및 모듈 관리
  • packages/shared를 통해 공통 설정(tailwind, eslint, prettier, typescript 등)을 관리.
  • 절대 경로로 패키지를 참조할 수 있도록 설정:
    @shared/tailwind, @shared/eslint, @shared/prettier 등.
  • client 하위의 user와 admin 프로젝트에서 공통 모듈을 활용.
  1. 워크스페이스 설정
  • workspaces에 모든 패키지 및 클라이언트를 추가.
  • client/* 및 packages/*를 참조하도록 설정.
  1. 의존성 정리
  • root package.json에서 공통 의존성 관리.
  • user, admin 개별 package.json은 특화된 의존성만 포함.
  1. 빌드 및 실행
  • yarn workspace user dev 및 yarn workspace admin dev 명령으로 프로젝트 실행 가능.
  • yarn build:user, yarn build:admin으로 빌드 프로세스 분리.

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 사용자 및 관리자 클라이언트를 위한 모노레포 구조 도입
    • 공유 컴포넌트, 유틸리티, 구성 파일 중앙화
    • 새로운 입력 필드, 동의 레이블 등 UI 컴포넌트 추가
  • 개선 사항

    • 통합된 ESLint, Prettier, Tailwind CSS 구성
    • 컴포넌트 및 유틸리티 라이브러리 구조화
    • 프로젝트 전반의 일관된 스타일링 및 타입스크립트 설정
  • 마이그레이션

    • 컴포넌트 가져오기 경로를 중앙 라이브러리로 업데이트
    • 전역 스타일 및 레이아웃 구성 재구성

@jinoo0306 jinoo0306 added the 🧹 Refactor 코드 리팩토링 label Jan 14, 2025
@jinoo0306 jinoo0306 self-assigned this Jan 14, 2025
@jinoo0306 jinoo0306 linked an issue Jan 14, 2025 that may be closed by this pull request
Copy link

coderabbitai bot commented Jan 14, 2025

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

client/user/eslint.config.mjs

Oops! Something went wrong! :(

ESLint: 9.18.0

ESLint couldn't find an eslint.config.(js|mjs|cjs) file.

From ESLint v9.0.0, the default configuration file is now eslint.config.js.
If you are using a .eslintrc.* file, please follow the migration guide
to update your configuration file to the new format:

https://eslint.org/docs/latest/use/configure/migration-guide

If you still have problems after following the migration guide, please stop by
https://eslint.org/chat/help to chat with the team.

개요

워크스루

이 풀 리퀘스트는 프로젝트의 구조를 대대적으로 리팩토링하고 있습니다. 주요 변경 사항은 모노레포 접근 방식으로의 전환, 공유 구성 요소 및 유틸리티 패키지 도입, 그리고 컴포넌트 및 구성 파일의 경로 재구성을 포함합니다. 이러한 변경은 코드 재사용성과 일관성을 향상시키는 것을 목표로 합니다.

변경 사항

파일/디렉토리 변경 요약
.gitignore 빌드 아티팩트 및 캐시 디렉토리 무시 규칙 업데이트
package.json 프로젝트 이름, 워크스페이스, 스크립트, 의존성 대규모 수정
client/user Next.js, ESLint, Prettier, Tailwind CSS 구성 파일 추가 및 컴포넌트 경로 리팩토링
packages/ 공유 컴포넌트, 유틸리티, 구성 패키지 추가

시퀀스 다이어그램

sequenceDiagram
    participant Dev as 개발자
    participant Monorepo as 모노레포 구조
    participant Components as 공유 컴포넌트
    participant Config as 공유 구성

    Dev->>Monorepo: 코드 변경
    Monorepo->>Components: 컴포넌트 참조
    Monorepo->>Config: 구성 파일 참조
    Components-->>Dev: 일관된 UI 제공
    Config-->>Dev: 표준화된 설정 적용
Loading

관련 가능한 PR

토끼의 시 🐰

모노레포의 길을 걷네
컴포넌트들 손에 손을 잡고
설정은 하나로 모여
코드의 꽃을 피워내네
🌈✨

Finishing Touches

  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 15

🔭 Outside diff range comments (3)
client/user/src/app/(nonRoot)/profile/(order)/orderHistory/page.tsx (1)

Line range hint 48-63: 페이지네이션 로직 개선 필요

현재 구현된 청크 기반 페이지네이션은 다음과 같은 제한사항이 있습니다:

  • 고정된 청크 크기 (4페이지)
  • 하드코딩된 최대 청크 수 (2개)
  • 전체 아이템 수에 기반한 동적 계산 부재

더 유연한 구현을 위해 다음과 같은 개선을 제안합니다:

interface PaginationProps {
  totalItems: number;
  itemsPerPage: number;
  currentPage: number;
  onPageChange: (page: number) => void;
}

const calculatePageCount = (totalItems: number, itemsPerPage: number) => 
  Math.ceil(totalItems / itemsPerPage);

const calculateVisiblePages = (currentPage: number, totalPages: number) => {
  // 동적으로 표시할 페이지 범위 계산 로직
};
client/user/src/app/_components/ScrollPages/3stPage.tsx (1)

Line range hint 8-99: 인라인 스타일을 Tailwind 클래스로 마이그레이션 필요

인라인 스타일을 사용하면 일관성 있는 스타일 관리가 어렵고, 반응형 디자인 구현이 복잡해집니다.

다음과 같은 개선사항을 제안드립니다:

  1. 고정 크기를 Tailwind의 유틸리티 클래스로 변환
  2. 반응형 디자인을 위한 Tailwind의 브레이크포인트 활용
  3. 공통 스타일을 Tailwind 설정에 추가

예시:

-style={{
-  height: 'calc(100vh - 90px)',
-}}
+className="min-h-[calc(100vh-90px)]"
client/user/src/app/(nonRoot)/(auth)/password/reset/page.tsx (1)

Line range hint 44-51: 보안 취약점: 하드코딩된 인증 코드

인증 코드가 하드코딩되어 있어 보안상 취약점이 될 수 있습니다.

if (verificationCode === '111') { // 하드코딩된 값

서버 측 검증을 구현하고 환경 변수나 API를 통해 안전하게 처리하는 것을 강력히 권장드립니다.

🧹 Nitpick comments (22)
client/user/src/app/(nonRoot)/layout.tsx (1)

6-6: clsx 사용 최적화가 필요합니다.

단일 문자열만 사용하는 경우 clsx는 불필요합니다. 직접 className을 사용하는 것이 더 간단합니다.

다음과 같이 수정하는 것을 추천드립니다:

-    <div className={clsx('min-h-screen w-full bg-blue-secondary')}>
+    <div className="min-h-screen w-full bg-blue-secondary">
client/user/src/app/(nonRoot)/apply/layout.tsx (1)

7-7: 불필요한 빈 className을 제거해주세요.

빈 문자열로 된 className은 불필요합니다.

다음과 같이 수정하는 것을 추천드립니다:

-    <div className={clsx('')}>
+    <div>
client/user/src/app/(nonRoot)/apply/page.tsx (1)

11-13: 컴포넌트 구조 개선이 필요합니다.

빈 div 대신 의미 있는 시맨틱 태그를 사용하고, 접근성을 고려한 구조로 개선하는 것이 좋습니다.

-    <div>
+    <section aria-label="도서 구매">
       <Purchase books={books} onDelete={handleRemoveBook} />
-    </div>
+    </section>
client/user/src/app/layout.tsx (1)

19-19: 하드코딩된 패딩 값을 CSS 변수로 관리하는 것이 좋습니다.

pt-[90px]와 같은 하드코딩된 값은 유지보수를 어렵게 만들 수 있습니다. 헤더 높이가 변경될 경우 여러 곳을 수정해야 할 수 있습니다.

-            <main className="flex-1 overflow-hidden pt-[90px]">{children}</main>
+            <main className="flex-1 overflow-hidden pt-[--header-height]">{children}</main>

CSS 변수는 @tookscan/styles/globals.css에 추가하시면 됩니다:

:root {
  --header-height: 90px;
}
client/user/src/app/(nonRoot)/apply/_components/Purchase.tsx (1)

30-30: 가격 포맷팅을 개선해주세요.

현재 가격이 단순히 숫자와 '원'으로 표시되고 있습니다. 천 단위 구분자를 추가하고 통화 포맷팅을 적용하면 사용자 경험이 향상될 것입니다.

-        <p className="text-sm text-gray-500">{calculateTotalPrice()}원</p>
+        <p className="text-sm text-gray-500">
+          {calculateTotalPrice().toLocaleString('ko-KR')}원
+        </p>
packages/components/ui/Banner/Banner3.tsx (1)

1-26: 컴포넌트 구조가 명확하고 일관성이 있습니다.

모노레포 구조로의 리팩토링 과정에서 컴포넌트의 구조와 스타일링이 잘 유지되었습니다. 다만, 재사용성 향상을 위한 제안사항이 있습니다.

배너의 텍스트 콘텐츠를 props로 받도록 개선하는 것을 고려해보세요:

-const Banner3 = () => {
+interface Banner3Props {
+  title: string;
+  description: string;
+}
+
+const Banner3 = ({ title, description }: Banner3Props) => {
   return (
     <div className="flex h-full w-[1135px] items-center justify-between px-6">
       <div className="flex flex-col justify-center text-left">
-        <p className="text-[32px] font-bold leading-[1.5]">신청하기</p>
+        <p className="text-[32px] font-bold leading-[1.5]">{title}</p>
         <p className="mt-2 text-[12px] leading-[1.5] opacity-50">
-          툭은 안전하고 편리한 스캔서비스를 제공합니다. <br />
-          지금 스캔 신청하기를 통해 빠르게 견적을 확인해보세요.
+          {description}
         </p>
client/user/src/types/svg.d.ts (1)

1-4: SVG 모듈 타입 선언 개선 제안

SVG 파일의 타입을 더 구체적으로 정의하면 좋을 것 같습니다. React 컴포넌트로 사용할 수 있도록 타입을 확장하는 것을 고려해보세요.

declare module '*.svg' {
-  const content: string; // 경로를 문자열로 가져오기
-  export default content;
+  import { FunctionComponent, SVGProps } from 'react';
+  const content: FunctionComponent<SVGProps<SVGSVGElement>>;
+  export default content;
}
packages/shared/eslint/eslint.config.mjs (1)

6-9: ESLint 규칙 확장 제안

현재 설정된 기본 규칙들이 적절해 보입니다. 다음과 같은 추가 규칙들도 고려해보시면 좋을 것 같습니다:

  rules: {
    semi: ["error", "never"],
    quotes: ["error", "single"],
+   "no-unused-vars": "error",
+   "no-console": "warn",
+   "@typescript-eslint/explicit-function-return-type": "warn",
  },
client/user/eslint.config.mjs (1)

4-10: 환경별 ESLint 설정 추가 제안

현재 설정은 잘 되어있지만, 개발 환경과 프로덕션 환경에 따라 다른 규칙을 적용하는 것을 고려해보세요.

export default {
  ...sharedConfig,
  rules: {
    ...sharedConfig.rules,
    'no-console': 'warn',
+   ...(process.env.NODE_ENV === 'production' ? {
+     'no-console': 'error',
+     'no-debugger': 'error',
+   } : {
+     'no-console': 'warn',
+     'no-debugger': 'warn',
+   }),
  },
}
client/user/next.config.ts (2)

6-8: 이미지 도메인 설정을 환경 변수로 관리하는 것을 고려해보세요.

프로덕션과 개발 환경에서 유연하게 대응할 수 있도록 이미지 도메인을 환경 변수로 관리하는 것이 좋습니다.

 images: {
-  domains: ['ibb.co'],
+  domains: process.env.NEXT_PUBLIC_IMAGE_DOMAINS?.split(',') ?? ['ibb.co'],
   formats: ['image/webp'],
 },

10-16: 웹팩 캐시 디렉토리 경로를 모노레포 구조에 맞게 조정하세요.

현재 캐시 디렉토리가 각 프로젝트 내부에 생성되고 있습니다. 모노레포 구조에서는 루트 레벨에서 캐시를 관리하는 것이 더 효율적일 수 있습니다.

 webpack: (config) => {
   config.cache = {
     type: 'filesystem',
-    cacheDirectory: path.resolve(__dirname, '.webpack-cache'),
+    cacheDirectory: path.resolve(__dirname, '../../.webpack-cache'),
   };
   return config;
 },
package.json (1)

11-14: 빌드 스크립트에 타입 체크와 린트 과정을 추가하세요.

현재 빌드 스크립트는 단순 빌드만 수행합니다. 안정적인 빌드를 위해 타입 체크와 린트 과정을 포함하는 것이 좋습니다.

 "scripts": {
   "dev:user": "yarn workspace user dev",
   "dev:admin": "yarn workspace admin dev",
-  "build:user": "yarn workspace user build",
-  "build:admin": "yarn workspace admin build",
+  "build:user": "yarn lint && yarn workspace user tsc && yarn workspace user build",
+  "build:admin": "yarn lint && yarn workspace admin tsc && yarn workspace admin build",
client/user/src/app/(nonRoot)/profile/(order)/orderHistory/page.tsx (2)

Line range hint 7-45: 주문 데이터 모킹 분리 필요

현재 컴포넌트 내부에 하드코딩된 주문 데이터를 별도의 mock 파일로 분리하는 것이 좋습니다. 이는 테스트와 유지보수를 용이하게 만들 것입니다.

+// mocks/orderData.ts
+export const mockOrders: OrderInfo[] = [
+  {
+    userName: '민경훈',
+    dateTime: '2024.12.15 (12시 45분)',
+    // ... 나머지 데이터
+  },
+  // ... 나머지 주문들
+]

Line range hint 76-89: 정렬 기능 구현 및 확장 필요

현재 정렬 기능에 대한 개선사항:

  1. 실제 정렬 로직이 구현되어 있지 않습니다.
  2. 정렬 옵션이 최신순/오래된순으로만 제한되어 있습니다.

추가적인 정렬 옵션(가격순, 상품명순 등)과 함께 실제 정렬 로직을 구현하는 것이 좋습니다.

const sortOrders = (orders: OrderInfo[], option: string) => {
  switch (option) {
    case 'latest':
      return [...orders].sort((a, b) => new Date(b.dateTime).getTime() - new Date(a.dateTime).getTime());
    case 'oldest':
      return [...orders].sort((a, b) => new Date(a.dateTime).getTime() - new Date(b.dateTime).getTime());
    // 추가 정렬 옵션들...
    default:
      return orders;
  }
};
packages/components/ui/Label/ConsentLabel.tsx (2)

5-11: 인터페이스에 JSDoc 문서화를 추가하면 좋을 것 같습니다.

각 prop의 용도와 제약사항을 명확히 설명하는 JSDoc 주석을 추가하면 컴포넌트 사용자의 이해를 도울 수 있습니다.

예시:

+/**
+ * 동의 레이블 컴포넌트의 속성을 정의합니다.
+ */
 interface ConsentLabelProps {
+  /** 레이블에 표시될 텍스트 내용 */
   content: string;
+  /** 현재 동의 상태 */
   consentStatus: boolean;
+  /** 동의 상태를 변경하는 콜백 함수 */
   setConsentStatus: (status: boolean) => void;
+  /** 레이블 크기 - "sm": 작은 크기, "lg": 큰 크기 */
   size: "sm" | "lg";
+  /** 선택적으로 제공되는 클릭 핸들러 */
   onClick?: () => void;
 }

21-31: 사용자 상호작용 상태에 대한 스타일을 추가하면 좋을 것 같습니다.

hover, focus 상태에 대한 스타일이 없어 사용자 피드백이 부족할 수 있습니다.

       <div
         className={clsx(
           "flex flex-row items-center",
           "font-normal leading-[1.25rem] tracking-[-0.00438rem]",
           "text-black-600",
+          "transition-colors duration-200",
+          "hover:opacity-80",
           size === "sm" && "text-2xs",
           size === "lg" && "text-sm",
           consentStatus ? "text-blue-primary" : "text-black-600"
         )}
packages/shared/tailwind/tailwind.config.ts (2)

2-2: 상대 경로 대신 별칭(alias) 경로 사용을 권장합니다.

현재 colors 파일을 가져오는 방식이 상대 경로를 사용하고 있습니다. 모노레포 구조에서는 @shared/config/color와 같은 별칭 경로를 사용하는 것이 더 안정적입니다.

-import { colors } from "../../config/color";
+import { colors } from "@shared/config/color";

28-28: 필요한 Tailwind 플러그인이 누락되지 않았는지 확인해주세요.

현재 플러그인이 비어있습니다. 프로젝트에서 필요할 수 있는 다음 플러그인들의 사용을 고려해보세요:

  • @tailwindcss/forms
  • @tailwindcss/typography
  • @tailwindcss/aspect-ratio
packages/utils/cn.ts (1)

1-4: JSDoc 문서화 추가 필요

유틸리티 함수의 용도와 사용 방법에 대한 문서화가 필요합니다.

다음과 같이 JSDoc을 추가하는 것을 추천드립니다:

 import classNames from 'classnames'
 
+/**
+ * CSS 클래스명들을 조건부로 결합하는 유틸리티 함수
+ * @param classes - 결합할 클래스명들 (문자열, undefined, null, 또는 false)
+ * @returns 결합된 클래스명 문자열
+ * @example
+ * cn('foo', 'bar') // => 'foo bar'
+ * cn('foo', undefined, 'bar') // => 'foo bar'
+ */
 export const cn = (...classes: (string | undefined | null | false)[]): string =>
   classNames(classes)
client/user/src/app/_components/ScrollPages/3stPage.tsx (1)

Line range hint 71-79: 접근성 개선 필요

비밀번호 표시/숨김 토글 버튼에 접근성 속성이 누락되었습니다.

다음과 같은 접근성 속성 추가를 제안드립니다:

-<button onClick={() => setIsPasswordVisible(!isPasswordVisible)}>
+<button
+  onClick={() => setIsPasswordVisible(!isPasswordVisible)}
+  type="button"
+  aria-label={isPasswordVisible ? "비밀번호 숨기기" : "비밀번호 표시"}
+>
packages/components/ui/InputField.tsx (1)

8-18: 타입 안전성 개선 필요

InputField 컴포넌트의 타입 정의를 더 안전하게 개선할 수 있습니다.

다음과 같은 개선사항을 제안드립니다:

+type InputType = "simple" | "number" | "suffix" | "search" | "password";
+
 interface InputFieldProps {
-  type: "simple" | "number" | "suffix" | "search" | "password";
+  type: InputType;
   value?: string;
   inputRef?: React.RefObject<HTMLInputElement>;
   onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
   placeholder?: string;
   helperText?: string;
   disabled?: boolean;
   isError?: boolean;
   isSuccess?: boolean;
+  'aria-label'?: string;
+  'aria-describedby'?: string;
 }
client/user/src/app/(nonRoot)/(auth)/password/reset/page.tsx (1)

Line range hint 9-19: 상태 관리 최적화 필요

여러 개의 독립적인 상태들이 useState로 관리되고 있어 복잡성이 증가할 수 있습니다.

다음과 같이 관련 상태들을 그룹화하여 관리하는 것을 추천드립니다:

interface VerificationState {
  code: string;
  timeLeft: number;
  isVerified: boolean;
  result: string | null;
}

interface UserInputState {
  id: string;
  name: string;
  phone: string;
}

const [verificationState, setVerificationState] = useState<VerificationState>({
  code: '',
  timeLeft: 0,
  isVerified: false,
  result: null,
});

const [userInput, setUserInput] = useState<UserInputState>({
  id: '',
  name: '',
  phone: '',
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ee8d64 and 9981cb6.

⛔ Files ignored due to path filters (12)
  • client/user/.yarn/install-state.gz is excluded by !**/.yarn/**, !**/*.gz
  • client/user/src/assets/images/landing/Book.svg is excluded by !**/*.svg
  • client/user/src/assets/images/landing/Hammer.svg is excluded by !**/*.svg
  • client/user/src/assets/images/landing/MainCard.svg is excluded by !**/*.svg
  • client/user/src/assets/images/login/Copy.svg is excluded by !**/*.svg
  • client/user/src/assets/images/login/GoogleCircle.svg is excluded by !**/*.svg
  • client/user/src/assets/images/login/KakaoCircle.svg is excluded by !**/*.svg
  • client/user/src/assets/images/signup/Google.svg is excluded by !**/*.svg
  • client/user/src/assets/images/signup/Kakao.svg is excluded by !**/*.svg
  • client/user/src/assets/images/signup/asdf.png is excluded by !**/*.png
  • packages/assets/fonts/PretendardVariable.ttf is excluded by !**/*.ttf
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (62)
  • .gitignore (2 hunks)
  • client/user/.prettierrc (1 hunks)
  • client/user/eslint.config.mjs (1 hunks)
  • client/user/next.config.ts (1 hunks)
  • client/user/package.json (1 hunks)
  • client/user/postcss.config.mjs (1 hunks)
  • client/user/src/app/(nonRoot)/(auth)/id/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/(auth)/id/reset/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/(auth)/layout.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/(auth)/login/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/(auth)/password/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/(auth)/password/reset/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/(auth)/signUp/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/apply/_components/Purchase.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/apply/layout.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/apply/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/guest/(order)/layout.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/guest/(order)/order/check/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/guest/(order)/order/list/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/layout.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/profile/(order)/orderHistory/page.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/profile/layout.tsx (1 hunks)
  • client/user/src/app/(nonRoot)/welcome/page.tsx (1 hunks)
  • client/user/src/app/_components/Modal.tsx (1 hunks)
  • client/user/src/app/_components/ReviewCard.tsx (1 hunks)
  • client/user/src/app/_components/ScrollPages/1stPage.tsx (1 hunks)
  • client/user/src/app/_components/ScrollPages/3stPage.tsx (1 hunks)
  • client/user/src/app/_components/ScrollPages/5stPage.tsx (1 hunks)
  • client/user/src/app/_components/SmallCard.tsx (1 hunks)
  • client/user/src/app/layout.tsx (1 hunks)
  • client/user/src/types/common.ts (1 hunks)
  • client/user/src/types/svg.d.ts (1 hunks)
  • client/user/tailwind.config.ts (1 hunks)
  • client/user/tsconfig.json (1 hunks)
  • eslint.config.mjs (0 hunks)
  • next.config.ts (0 hunks)
  • package.json (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/components/ui/Banner/Banner.tsx (2 hunks)
  • packages/components/ui/Banner/Banner1.tsx (2 hunks)
  • packages/components/ui/Banner/Banner2.tsx (2 hunks)
  • packages/components/ui/Banner/Banner3.tsx (1 hunks)
  • packages/components/ui/Button.tsx (1 hunks)
  • packages/components/ui/InputField.tsx (1 hunks)
  • packages/components/ui/Label/ConsentLabel.tsx (1 hunks)
  • packages/config/package.json (1 hunks)
  • packages/shared/eslint/eslint.config.mjs (1 hunks)
  • packages/shared/prettier/package.json (1 hunks)
  • packages/shared/tailwind/package.json (1 hunks)
  • packages/shared/tailwind/tailwind.config.ts (1 hunks)
  • packages/shared/typescript/package.json (1 hunks)
  • packages/shared/typescript/tsconfig.base.json (1 hunks)
  • packages/styles/package.json (1 hunks)
  • packages/utils/cn.ts (1 hunks)
  • packages/utils/package.json (1 hunks)
  • src/app/(user)/layout.tsx (0 hunks)
  • src/app/_components/ui/InputField.tsx (0 hunks)
  • src/app/_components/ui/Label/ConsentLabel.tsx (0 hunks)
  • src/app/layout.tsx (0 hunks)
  • src/types/common.ts (0 hunks)
  • tailwind.config.ts (0 hunks)
  • tsconfig.json (0 hunks)
💤 Files with no reviewable changes (9)
  • eslint.config.mjs
  • src/app/layout.tsx
  • src/types/common.ts
  • src/app/_components/ui/Label/ConsentLabel.tsx
  • tailwind.config.ts
  • src/app/_components/ui/InputField.tsx
  • next.config.ts
  • tsconfig.json
  • src/app/(user)/layout.tsx
✅ Files skipped from review due to trivial changes (30)
  • client/user/.prettierrc
  • packages/shared/prettier/package.json
  • packages/components/ui/Banner/Banner1.tsx
  • packages/shared/tailwind/package.json
  • packages/styles/package.json
  • packages/config/package.json
  • packages/utils/package.json
  • packages/components/ui/Banner/Banner.tsx
  • packages/shared/typescript/package.json
  • packages/components/ui/Button.tsx
  • packages/components/package.json
  • client/user/src/app/_components/Modal.tsx
  • client/user/src/app/(nonRoot)/(auth)/layout.tsx
  • client/user/src/app/(nonRoot)/(auth)/id/page.tsx
  • client/user/src/app/(nonRoot)/guest/(order)/layout.tsx
  • client/user/src/app/(nonRoot)/guest/(order)/order/check/page.tsx
  • client/user/src/app/_components/ScrollPages/5stPage.tsx
  • client/user/src/app/_components/ReviewCard.tsx
  • client/user/tsconfig.json
  • client/user/src/app/(nonRoot)/(auth)/password/page.tsx
  • client/user/package.json
  • client/user/src/app/(nonRoot)/guest/(order)/order/list/page.tsx
  • client/user/src/app/_components/SmallCard.tsx
  • packages/components/ui/Banner/Banner2.tsx
  • packages/shared/typescript/tsconfig.base.json
  • client/user/src/app/(nonRoot)/welcome/page.tsx
  • client/user/src/app/_components/ScrollPages/1stPage.tsx
  • client/user/src/app/(nonRoot)/(auth)/signUp/page.tsx
  • client/user/src/app/(nonRoot)/(auth)/id/reset/page.tsx
  • client/user/src/app/(nonRoot)/(auth)/login/page.tsx
🔇 Additional comments (13)
client/user/src/app/(nonRoot)/profile/layout.tsx (1)

3-3: 모노레포 구조에 맞게 import 경로가 수정되었습니다.

공통 컴포넌트를 @tookscan/components로 이동한 것이 모노레포 구조화에 적절해 보입니다.

새로운 import 경로가 올바르게 구성되어 있는지 확인이 필요합니다:

✅ Verification successful

import 경로가 올바르게 구성되어 있습니다.

  • @tookscan/components 패키지가 올바르게 설정되어 있습니다
  • Banner 컴포넌트가 packages/components/ui/Banner/Banner.tsx에 존재합니다
  • 여러 레이아웃 파일에서 일관되게 사용되고 있습니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the new import path configuration

# Check tsconfig paths configuration
echo "Checking tsconfig paths..."
fd -e json tsconfig. | xargs cat | jq '.compilerOptions.paths'

# Check package.json workspace configuration
echo "Checking workspace configuration..."
cat package.json | jq '.workspaces'

# Verify Banner component exists in the new location
echo "Verifying Banner component location..."
fd -e tsx -e ts Banner packages/

Length of output: 644


Script:

#!/bin/bash
# Check package.json in components package
echo "Checking components package configuration..."
cat packages/components/package.json | jq '{name, main, types}'

# Verify the import is used correctly
echo "Checking Banner import usage..."
rg "@tookscan/components/ui/Banner/Banner" -A 2

Length of output: 1404

client/user/src/types/common.ts (1)

3-13: 인터페이스 구조가 잘 설계되었습니다!

타입 정의가 명확하고 재사용 가능하게 잘 구성되어 있습니다. restoreOption에 리터럴 타입을 사용한 것이 특히 좋습니다.

client/user/src/app/layout.tsx (1)

16-18: 헤더의 고정 위치 처리 방식을 검토해주세요.

고정 위치로 설정된 헤더는 다음과 같은 잠재적인 문제를 일으킬 수 있습니다:

  • 모바일 브라우저에서 주소 표시줄이 보이거나 숨겨질 때 레이아웃 깨짐
  • iOS Safari에서 스크롤 시 헤더가 사라지는 문제

스크롤 동작과 모바일 환경에서의 테스트가 필요합니다.

packages/components/ui/Banner/Banner3.tsx (2)

1-2: clsx 라이브러리 사용이 적절합니다.

조건부 클래스네임 관리를 위한 clsx 라이브러리 도입이 코드 가독성과 유지보수성을 향상시킵니다.


8-12: 텍스트 스타일링이 개선되었습니다.

opacity-50 클래스를 활용한 부가 설명 텍스트의 시각적 계층 구조가 사용자 경험을 향상시킵니다.

client/user/postcss.config.mjs (1)

5-5: 설정이 적절해 보입니다!

autoprefixer 플러그인 추가는 크로스 브라우저 호환성을 위해 좋은 선택입니다.

client/user/src/app/(nonRoot)/profile/(order)/orderHistory/page.tsx (1)

3-3: 모노레포 패키지 경로 설정 확인 필요

새로운 import 경로가 올바르게 설정되어 있는지 확인이 필요합니다.

✅ Verification successful

모노레포 패키지 구조가 올바르게 구성되어 있음을 확인했습니다

  • @tookscan/components 패키지가 정상적으로 등록되어 있습니다
  • OrderCard 컴포넌트가 packages/components/ui 디렉토리에 올바르게 위치해 있습니다
  • import 경로가 모노레포 구조에 맞게 정확하게 설정되어 있습니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the package alias configuration in tsconfig and package.json

# Check tsconfig paths configuration
cat $(fd -t f tsconfig.json) | jq -r 'select(.compilerOptions.paths != null) | .compilerOptions.paths'

# Check package.json workspace configuration
cat package.json | jq -r '.workspaces'

Length of output: 251


Script:

#!/bin/bash
# Find OrderCard component file
fd OrderCard

# Check if @tookscan exists in packages
ls -la packages/@tookscan 2>/dev/null || echo "No @tookscan directory found"

# Search for package.json files that might define @tookscan scope
fd -t f package.json -x cat {} | jq -r 'select(.name != null) | select(.name | startswith("@tookscan"))'

Length of output: 558

packages/components/ui/Label/ConsentLabel.tsx (1)

1-3: 모노레포 구조에 맞게 잘 구성된 import문입니다!

절대 경로를 사용한 import 구조가 모노레포 설계 의도와 잘 부합합니다.

client/user/tailwind.config.ts (2)

1-3: 공유 설정을 올바르게 가져오고 타입을 정의했습니다!

설정 파일의 기본 구조가 깔끔하며, TypeScript 타입이 잘 정의되어 있습니다.


4-7: 컨텐츠 경로가 user 프로젝트에 특화되어 있는지 확인이 필요합니다.

현재 설정된 경로 './src/**/*.{js,ts,jsx,tsx}'가 user 프로젝트의 실제 소스 코드 위치와 일치하는지 확인해주세요.

✅ Verification successful

설정된 컨텐츠 경로가 정확합니다.

현재 설정된 './src/**/*.{js,ts,jsx,tsx}' 경로가 user 프로젝트의 실제 소스 코드 위치와 정확히 일치하는 것을 확인했습니다. 모든 컴포넌트, 페이지 및 유틸리티 파일들이 이 경로 패턴에 포함되어 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of source files in the specified path
fd -e js -e ts -e jsx -e tsx . client/user/src/

Length of output: 2071

packages/shared/tailwind/tailwind.config.ts (1)

23-25: fontSize 설정이 디자인 시스템과 일치하는지 확인해주세요.

추가된 2xs 사이즈(0.625rem = 10px)가 디자인 시스템의 타이포그래피 스케일과 일치하는지 확인이 필요합니다.

client/user/src/app/_components/ScrollPages/3stPage.tsx (1)

5-5: 임포트 경로가 올바르게 업데이트됨

모노레포 구조에 맞게 Button 컴포넌트의 임포트 경로가 정확하게 변경되었습니다.

client/user/src/app/(nonRoot)/(auth)/password/reset/page.tsx (1)

5-7: 임포트 경로가 올바르게 업데이트됨

모노레포 구조에 맞게 컴포넌트들의 임포트 경로가 정확하게 변경되었습니다.

Comment on lines +6 to +9
const [books, setBooks] = useState<Books[]>([])
const handleRemoveBook = (id: number) => {
setBooks((prev) => prev.filter((book) => book.id !== id))
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

상태 관리 개선이 필요합니다.

다음 사항들을 고려해주시기 바랍니다:

  1. 초기 상태 유효성 검증
  2. 에러 처리 추가
  3. 로딩 상태 관리

예시 구현:

const [books, setBooks] = useState<Books[]>([])
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<Error | null>(null)

const handleRemoveBook = async (id: number) => {
  try {
    setIsLoading(true)
    setBooks((prev) => prev.filter((book) => book.id !== id))
  } catch (err) {
    setError(err instanceof Error ? err : new Error('알 수 없는 오류가 발생했습니다'))
  } finally {
    setIsLoading(false)
  }
}


export default function RootLayout({ children }: LayoutProps) {
return (
<html lang="en">
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

HTML 언어 속성을 한국어로 변경해주세요.

현재 lang 속성이 "en"으로 설정되어 있지만, 애플리케이션이 한국어를 사용하는 것으로 보입니다. 웹 접근성과 SEO를 위해 적절한 언어 설정이 필요합니다.

-    <html lang="en">
+    <html lang="ko">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<html lang="en">
<html lang="ko">

}

const Purchase = ({ books, onDelete }: PurchaseProps) => {
const PRICE_PER_PAGE = 10
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

상수 값들을 별도의 상수 파일로 분리해주세요.

가격과 관련된 매직 넘버들(PRICE_PER_PAGE, 5000, 2500)을 상수 파일로 분리하여 관리하면 유지보수가 용이해집니다.

// constants/pricing.ts
export const PRICE_PER_PAGE = 10;
export const RESTORE_COSTS = {
  loose: 5000,
  spiral: 2500,
  default: 0,
} as const;

또한 restoreOption의 타입 안전성을 위해 다음과 같이 타입을 정의하는 것이 좋습니다:

export type RestoreOption = keyof typeof RESTORE_COSTS;

Also applies to: 15-20

Comment on lines +12 to +24
const calculateTotalPrice = () => {
return books.reduce((total, book) => {
const pageCost = book.pages * PRICE_PER_PAGE
const restoreCost =
book.restoreOption === 'loose'
? 5000
: book.restoreOption === 'spiral'
? 2500
: 0

return total + pageCost + restoreCost
}, 0)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

가격 계산 로직에 대한 에러 처리가 필요합니다.

현재 calculateTotalPrice 함수는 다음과 같은 엣지 케이스를 처리하지 않고 있습니다:

  • 음수 페이지 수
  • 유효하지 않은 restoreOption
  • undefined 또는 null

다음과 같이 개선하는 것을 추천드립니다:

const calculateTotalPrice = () => {
  return books.reduce((total, book) => {
    if (!book.pages || book.pages < 0) {
      console.error(`Invalid page count for book: ${book.id}`);
      return total;
    }

    const pageCost = book.pages * PRICE_PER_PAGE;
    const restoreCost = RESTORE_COSTS[book.restoreOption as RestoreOption] ?? RESTORE_COSTS.default;

    return total + pageCost + restoreCost;
  }, 0);
};

Comment on lines +15 to +20
<Icon
id="logo"
width={150}
height={66}
className={clsx("opacity-60")}
/>
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

로고의 접근성 개선이 필요합니다

현재 구현상의 문제점:

  • opacity-60 클래스로 인한 시각적 대비 저하
  • 스크린리더 사용자를 위한 aria-label 부재

개선 제안:

 <Icon
   id="logo"
   width={150}
   height={66}
-  className={clsx("opacity-60")}
+  className={clsx("opacity-75")}
+  aria-label="툭스캔 로고"
 />
  • opacity 값을 0.75로 높여 가시성 개선
  • aria-label 추가로 스크린리더 지원
🔗 Analysis chain

아이콘 투명도 적용이 적절합니다만, 접근성 고려가 필요합니다.

opacity-60 클래스 적용으로 시각적 효과는 개선되었으나, 로고의 가시성이 저하될 수 있습니다. 접근성 관점에서 검토가 필요합니다.

다음 사항들을 확인해주세요:

  • 로고의 대비율(contrast ratio)이 WCAG 기준을 충족하는지
  • 스크린리더 사용자를 위한 적절한 대체 텍스트가 제공되는지

아이콘에 aria-label 속성을 추가하는 것을 고려해보세요:

 <Icon
   id="logo"
   width={150}
   height={66}
   className={clsx("opacity-60")}
+  aria-label="툭스캔 로고"
 />
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Find Icon component implementation
ast-grep --pattern 'export $_ function Icon' 

# Find other Icon usages with aria-label
rg "aria-label.*Icon" -A 2 -B 2

# Check Banner3 component's full implementation for background context
cat packages/components/ui/Banner/Banner3.tsx

# Find similar logo implementations
rg "id=\"logo\"" -A 2 -B 2

Length of output: 3680

Comment on lines +5 to +9
content: [
"./client/user/src/**/*.{js,ts,jsx,tsx,mdx}",
"./client/admin/src/**/*.{js,ts,jsx,tsx,mdx}",
"./packages/**/*.{js,ts,jsx,tsx,mdx}",
],
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Tailwind 설정에서 수정이 필요한 부분이 있습니다.

  • client/admin/src 디렉토리가 존재하지 않습니다. 해당 경로를 제거하거나 올바른 경로로 수정해주세요.
  • 현재 codebase에서 .mdx 파일이 사용되지 않고 있습니다. 불필요한 경우 확장자 목록에서 제거하는 것을 고려해주세요.
🔗 Analysis chain

컨텐츠 경로 설정이 올바른지 확인이 필요합니다.

현재 설정된 경로들이 모노레포 구조의 실제 파일 위치와 일치하는지 확인해주세요. 특히 mdx 확장자 파일의 사용 여부를 확인해주세요.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of source files in the specified paths
echo "Checking user client files..."
fd -e js -e ts -e jsx -e tsx -e mdx . client/user/src/

echo "Checking admin client files..."
fd -e js -e ts -e jsx -e tsx -e mdx . client/admin/src/

echo "Checking package files..."
fd -e js -e ts -e jsx -e tsx -e mdx . packages/

Length of output: 3329

Comment on lines +13 to +22
fontFamily: {
sans: [
"Pretendard",
"ui-sans-serif",
"system-ui",
"Arial",
"sans-serif",
],
pretendard: ["Pretendard", "sans-serif"],
},
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

폰트 설정에서 몇 가지 개선이 필요합니다.

  1. 폰트 파일 경로가 일치하지 않습니다:
    • 현재 @font-face에서는 /src/assets/fonts/를 참조하지만, 실제 파일은 packages/assets/fonts/에 있습니다.
  2. 최적화 제안:
    • PretendardVariable.ttf (가변 폰트)를 활용하여 더 효율적인 폰트 제공이 가능합니다.
    • 폰트 preload 태그 추가를 고려해주세요.
  3. 한글 폰트 대체(fallback) 제안:
    • 'Malgun Gothic', '맑은 고딕'을 fallback으로 추가해주세요.

예시:

fontFamily: {
  sans: [
    "Pretendard",
    "Malgun Gothic",
    "맑은 고딕",
    "ui-sans-serif",
    "system-ui",
    "Arial",
    "sans-serif",
  ],
}
🔗 Analysis chain

폰트 패밀리 설정에 대한 검토가 필요합니다.

  1. Pretendard 폰트가 프로젝트에 포함되어 있는지 확인해주세요.
  2. 폰트 로딩 전략(font loading strategy)을 고려해보세요.
  3. 한글 폰트를 위한 추가적인 대체 폰트(fallback)를 고려해보세요.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for font files and font loading configuration
echo "Checking for font files..."
fd -e woff -e woff2 -e ttf -e otf . packages/

echo "Checking for font loading configuration..."
rg -l "font-face" .

Length of output: 300


Script:

#!/bin/bash
# Check font-face declaration and loading strategy
echo "Font-face declaration in globals.css:"
cat packages/styles/globals.css | grep -A 5 "@font-face"

echo -e "\nChecking for font preload tags:"
rg "rel=.preload.*font" .

echo -e "\nChecking for Korean fallback fonts:"
rg "Malgun Gothic|맑은 고딕|Nanum|나눔|Dotum|돋움|Gulim|굴림" .

Length of output: 806

Comment on lines +3 to +4
export const cn = (...classes: (string | undefined | null | false)[]): string =>
classNames(classes)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

classNames 함수 사용 방식 개선 필요

classNames 함수에 배열을 직접 전달하면 예상치 못한 결과가 발생할 수 있습니다.

다음과 같이 수정하는 것을 추천드립니다:

-export const cn = (...classes: (string | undefined | null | false)[]): string =>
-  classNames(classes)
+export const cn = (...classes: (string | undefined | null | false)[]): string =>
+  classNames(...classes)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const cn = (...classes: (string | undefined | null | false)[]): string =>
classNames(classes)
export const cn = (...classes: (string | undefined | null | false)[]): string =>
classNames(...classes)

Comment on lines +70 to +79
{type === "password" && (
<button onClick={() => setIsPasswordVisible(!isPasswordVisible)}>
<Icon
id={isPasswordVisible ? "openEyes" : "closeEyes"}
width={24}
height={24}
className="text-black-800"
/>
</button>
)}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

비밀번호 토글 버튼 접근성 개선 필요

비밀번호 표시/숨김 토글 버튼에 접근성 속성이 누락되었습니다.

다음과 같은 개선사항을 제안드립니다:

 {type === "password" && (
-  <button onClick={() => setIsPasswordVisible(!isPasswordVisible)}>
+  <button
+    type="button"
+    onClick={() => setIsPasswordVisible(!isPasswordVisible)}
+    aria-label={isPasswordVisible ? "비밀번호 숨기기" : "비밀번호 표시"}
+    aria-pressed={isPasswordVisible}
+  >
     <Icon
       id={isPasswordVisible ? "openEyes" : "closeEyes"}
       width={24}
       height={24}
-      className="text-black-800"
+      className="text-black-800" 
+      aria-hidden="true"
     />
   </button>
 )}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{type === "password" && (
<button onClick={() => setIsPasswordVisible(!isPasswordVisible)}>
<Icon
id={isPasswordVisible ? "openEyes" : "closeEyes"}
width={24}
height={24}
className="text-black-800"
/>
</button>
)}
{type === "password" && (
<button
type="button"
onClick={() => setIsPasswordVisible(!isPasswordVisible)}
aria-label={isPasswordVisible ? "비밀번호 숨기기" : "비밀번호 표시"}
aria-pressed={isPasswordVisible}
>
<Icon
id={isPasswordVisible ? "openEyes" : "closeEyes"}
width={24}
height={24}
className="text-black-800"
aria-hidden="true"
/>
</button>
)}

Comment on lines +58 to +68
<input
ref={inputRef}
value={value}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
onChange={onChange}
disabled={disabled}
type={isPasswordVisible ? "text" : "password"}
placeholder={placeholder}
className="w-full bg-transparent text-black-800 outline-none"
/>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

input 요소의 타입 속성 개선 필요

현재 구현은 모든 input 타입을 text나 password로만 처리하고 있습니다.

다음과 같이 input 타입을 올바르게 매핑하는 것을 추천드립니다:

+const getInputType = (type: InputType, isPasswordVisible: boolean) => {
+  if (type === "password") return isPasswordVisible ? "text" : "password";
+  if (type === "number") return "number";
+  return "text";
+};

 <input
   ref={inputRef}
   value={value}
   onFocus={() => setIsFocused(true)}
   onBlur={() => setIsFocused(false)}
   onChange={onChange}
   disabled={disabled}
-  type={isPasswordVisible ? "text" : "password"}
+  type={getInputType(type, isPasswordVisible)}
   placeholder={placeholder}
   className="w-full bg-transparent text-black-800 outline-none"
 />

Committable suggestion skipped: line range outside the PR's diff.

@jinoo0306 jinoo0306 marked this pull request as draft January 14, 2025 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🧹 Refactor 코드 리팩토링
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[design] 스캔 신청 페이지 퍼블리싱
1 participant