Skip to content

Conversation

@evaain706
Copy link
Contributor

@evaain706 evaain706 commented Jul 25, 2025

📌 변경 사항 개요

  • 체험 등록/수정 페이지 로직 및 레이아웃

📝 상세 내용

  • 다음 주소api를 사용한 주소선택 가능
  • ImagePreview,ImageUpload 컴포넌트를 통한 배너,소개이미지 업로드및 미리보기
  • 체험 가능 시간대 선택 구현
  • Mock데이터를 통한 수정시 데이터 불러오기 확인완료

🔗 관련 이슈

🖼️ 스크린샷(선택사항)

screencapture-localhost-3000-myactivity-2025-07-25-16_25_52

💡 참고 사항

  • 상세 UI수정은 api연결후 마무리할 예정입니다

Summary by CodeRabbit

  • 신규 기능

    • 체험/이벤트 등록을 위한 예약 폼과 관련 입력 UI(주소, 카테고리, 이미지 업로드 및 미리보기, 일정 선택 등) 추가
    • 주소 검색 기능(다음 우편번호 서비스 연동) 및 카테고리 선택 드롭다운 제공
    • 메인/서브 이미지 업로드 및 미리보기, 최대 4장 제한 기능 제공
    • 일정(날짜, 시작/종료 시간) 추가 및 삭제 기능 제공
  • 스타일

    • 스크롤바 등장 시 레이아웃 변화 방지를 위한 글로벌 스타일(scrollbar-gutter) 추가
  • 기타

    • 외부 라이브러리 react-daum-postcode 의존성 추가

@evaain706 evaain706 self-assigned this Jul 25, 2025
@evaain706 evaain706 added the ✨ Feature 기능구현 label Jul 25, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 25, 2025

Caution

Review failed

The pull request is closed.

"""

Walkthrough

이번 변경에서는 새로운 예약(체험 등록) 폼 기능이 추가되었습니다. 이를 위해 다양한 입력 컴포넌트, 이미지 업로드, 일정 선택, 주소 입력 등 여러 React 컴포넌트가 신설되었으며, 관련 의존성(react-daum-postcode)과 전역 CSS도 일부 수정되었습니다. 새로운 페이지가 생성되어 해당 폼을 렌더링합니다.

Changes

파일/경로 요약 변경 내용 요약
package.json react-daum-postcode 패키지 의존성 추가
src/app/(with-header)/myactivity/components/AddressInput.tsx 주소 입력 및 검색 모달 컴포넌트 신설
src/app/(with-header)/myactivity/components/CategoryInput.tsx 카테고리 선택 드롭다운 컴포넌트 신설
src/app/(with-header)/myactivity/components/FormSection.tsx 제목, 설명, 콘텐츠 구획용 폼 섹션 컴포넌트 신설
src/app/(with-header)/myactivity/components/ImagePreview.tsx 이미지 미리보기 및 삭제 버튼 컴포넌트 신설
src/app/(with-header)/myactivity/components/ImageSection.tsx 메인/서브 이미지 선택 UI 관리 컴포넌트 신설
src/app/(with-header)/myactivity/components/ImageUpload.tsx 이미지 파일 업로드 컴포넌트 신설
src/app/(with-header)/myactivity/components/InfoSection.tsx 체험 정보 입력(제목, 카테고리, 가격, 설명, 주소) 섹션 컴포넌트 신설
src/app/(with-header)/myactivity/components/MainImageSelect.tsx 메인 이미지 업로드/미리보기 컴포넌트 신설
src/app/(with-header)/myactivity/components/ReservationForm.tsx 예약(체험 등록) 폼 전체 구현, 상태 관리 및 하위 컴포넌트 조합
src/app/(with-header)/myactivity/components/ScheduleSelect.tsx 단일 일정 입력(날짜, 시작/종료시간) 컴포넌트 신설
src/app/(with-header)/myactivity/components/ScheduleSelectForm.tsx 여러 일정 추가/삭제/수정 관리 컴포넌트 신설
src/app/(with-header)/myactivity/components/SubImageSelect.tsx 서브 이미지 최대 4장 업로드/미리보기/삭제 컴포넌트 신설
src/app/(with-header)/myactivity/page.tsx 예약 폼 페이지 컴포넌트 신설
src/app/globals.css scrollbar-gutter: stable; CSS 속성 추가

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Page
    participant ReservationForm
    participant InfoSection
    participant ScheduleSelectForm
    participant ImageSection
    participant AddressInput
    participant CategoryInput

    User->>Page: 페이지 접근
    Page->>ReservationForm: ReservationForm 렌더링
    ReservationForm->>InfoSection: 체험 정보 입력 렌더링
    InfoSection->>CategoryInput: 카테고리 선택
    InfoSection->>AddressInput: 주소 검색 및 입력
    ReservationForm->>ScheduleSelectForm: 일정 입력 폼 렌더링
    ReservationForm->>ImageSection: 이미지 업로드/미리보기 렌더링
    User->>ReservationForm: 입력값 변경 (제목, 카테고리, 가격, 설명, 주소, 일정, 이미지 등)
    User->>ReservationForm: 폼 제출
    ReservationForm->>ReservationForm: 입력값 로깅/처리
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20분

Suggested reviewers

  • BokyungCodes
  • LeeCh0129

Poem

🐰
새로운 폼이 폴짝, 주소도 척척
이미지는 번쩍, 일정은 착착
카테고리 고르고, 설명도 쓰고
토끼는 신나서 귀를 쫑긋
체험 등록, 이제 걱정 끝!

"""

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.

src/app/(with-header)/myactivity/components/CategoryInput.tsx

Oops! Something went wrong! :(

ESLint: 9.30.1

ESLint couldn't find the plugin "eslint-plugin-react-hooks".

(The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react-hooks@latest --save-dev

The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/eslint-config-next/index.js".

If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.

src/app/(with-header)/myactivity/components/ScheduleSelect.tsx

Oops! Something went wrong! :(

ESLint: 9.30.1

ESLint couldn't find the plugin "eslint-plugin-react-hooks".

(The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react-hooks@latest --save-dev

The plugin "eslint-plugin-react-hooks" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/[email protected][email protected][email protected][email protected]/node_modules/eslint-config-next/index.js".

If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b6e930d and a0fa0d0.

📒 Files selected for processing (2)
  • src/app/(with-header)/myactivity/components/CategoryInput.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/ScheduleSelect.tsx (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/70

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.

❤️ Share
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @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: 18

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between dfa49a4 and a740d3f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (15)
  • package.json (1 hunks)
  • src/app/(with-header)/myactivity/components/AddressInput.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/CategoryInput.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/FormSection.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/ImagePreview.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/ImageSection.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/ImageUpload.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/InfoSection.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/MainImageSelect.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/ReservationForm.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/ScheduleSelect.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/ScheduleSelectForm.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/SubImageSelect.tsx (1 hunks)
  • src/app/(with-header)/myactivity/page.tsx (1 hunks)
  • src/app/globals.css (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (8)
src/app/(with-header)/myactivity/page.tsx (1)
src/app/(with-header)/myactivity/components/ReservationForm.tsx (1)
  • ReservationForm (37-164)
src/app/(with-header)/myactivity/components/InfoSection.tsx (3)
src/components/Input.tsx (1)
  • Input (17-61)
src/app/(with-header)/myactivity/components/CategoryInput.tsx (1)
  • CategoryInput (7-37)
src/app/(with-header)/myactivity/components/AddressInput.tsx (1)
  • AddressInput (14-70)
src/app/(with-header)/myactivity/components/ImageSection.tsx (2)
src/app/(with-header)/myactivity/components/MainImageSelect.tsx (1)
  • MainImageSelect (13-42)
src/app/(with-header)/myactivity/components/SubImageSelect.tsx (1)
  • SubImageSelect (10-47)
src/app/(with-header)/myactivity/components/SubImageSelect.tsx (2)
src/app/(with-header)/myactivity/components/ImageUpload.tsx (1)
  • ImageUpload (12-50)
src/app/(with-header)/myactivity/components/ImagePreview.tsx (1)
  • ImagePreview (12-39)
src/app/(with-header)/myactivity/components/ScheduleSelect.tsx (1)
src/components/Input.tsx (1)
  • Input (17-61)
src/app/(with-header)/myactivity/components/MainImageSelect.tsx (2)
src/app/(with-header)/myactivity/components/ImageUpload.tsx (1)
  • ImageUpload (12-50)
src/app/(with-header)/myactivity/components/ImagePreview.tsx (1)
  • ImagePreview (12-39)
src/app/(with-header)/myactivity/components/ScheduleSelectForm.tsx (1)
src/app/(with-header)/myactivity/components/ScheduleSelect.tsx (1)
  • ScheduleSelect (19-78)
src/app/(with-header)/myactivity/components/AddressInput.tsx (2)
src/components/Input.tsx (1)
  • Input (17-61)
src/components/Button.tsx (1)
  • Button (18-49)
🪛 GitHub Actions: CI
src/app/(with-header)/myactivity/components/ImageUpload.tsx

[warning] 43-45: react/jsx-sort-props: Props should be sorted alphabetically.

src/app/(with-header)/myactivity/components/InfoSection.tsx

[warning] 3-81: Multiple react/jsx-sort-props and simple-import-sort/imports warnings: Props should be sorted alphabetically; Callbacks must be listed after all other props; Run autofix to sort these imports.

src/app/(with-header)/myactivity/components/ImageSection.tsx

[warning] 28-34: react/jsx-sort-props: Props should be sorted alphabetically.

src/app/(with-header)/myactivity/components/SubImageSelect.tsx

[warning] 34-36: react/no-array-index-key and react/jsx-sort-props warnings: Do not use Array index in keys; Callbacks must be listed after all other props.

src/app/(with-header)/myactivity/components/CategoryInput.tsx

[warning] 15-22: react/jsx-sort-props: Props should be sorted alphabetically.

src/app/(with-header)/myactivity/components/ScheduleSelect.tsx

[error] 22-22: @typescript-eslint/no-unused-vars: 'onAddDate' is defined but never used. Allowed unused args must match /^_/u.


[warning] 39-68: react/jsx-sort-props: Props should be sorted alphabetically; Callbacks must be listed after all other props.

src/app/(with-header)/myactivity/components/MainImageSelect.tsx

[error] 3-3: unused-imports/no-unused-imports: 'IconClose' is defined but never used.


[warning] 31-31: react/jsx-sort-props: Callbacks must be listed after all other props.

src/app/(with-header)/myactivity/components/ScheduleSelectForm.tsx

[warning] 42-44: react/jsx-key: Missing "key" prop for element in iterator; react/no-array-index-key: Do not use Array index in keys.


[warning] 34-53: Multiple react/jsx-sort-props, react/jsx-key and react/no-array-index-key warnings: Callbacks must be listed after all other props; Missing "key" prop for element in iterator; Do not use Array index in keys; Props should be sorted alphabetically.

src/app/(with-header)/myactivity/components/ReservationForm.tsx

[warning] 104-111: no-console: Unexpected console statement. Only these console methods are allowed: warn, error.

src/app/(with-header)/myactivity/components/AddressInput.tsx

[error] 20-20: @typescript-eslint/no-explicit-any: Unexpected any. Specify a different type.

src/app/(with-header)/myactivity/components/ImagePreview.tsx

[warning] 23-23: @next/next/no-img-element: Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image or a custom image loader.

🪛 Biome (2.1.2)
src/app/(with-header)/myactivity/components/ScheduleSelectForm.tsx

[error] 42-43: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

🔇 Additional comments (13)
package.json (1)

21-21: 새 의존성의 peer-dependency 호환성 확인 필요
react-daum-postcode@^3.2.0는 React 18까지를 peer로 선언하고 있어 React 19(실험 버전)과 함께 사용 시 경고가 발생할 수 있습니다. 실제 실행에 문제는 없지만 CI 출력 또는 브라우저 콘솔에서 peer 경고가 계속 노출될 수 있으니 버전 호환 여부를 한 번 더 확인해 주세요.

src/app/(with-header)/myactivity/components/FormSection.tsx (1)

15-26: 구조·스타일 모두 명료, 별도 의견 없습니다
컴포넌트가 단순하고 재사용성도 좋아 보입니다.

src/app/(with-header)/myactivity/components/CategoryInput.tsx (1)

27-27: 옵션 값과 표시 텍스트 일관성 검토 필요

'문화예술' 값과 '문화/예술' 표시 텍스트가 다릅니다. API나 백엔드에서 어떤 형식을 기대하는지 확인이 필요합니다.

백엔드 API 스펙을 확인하여 카테고리 값의 정확한 형식을 검증해주세요.

src/app/(with-header)/myactivity/components/ReservationForm.tsx (1)

37-164: 우수한 컴포넌트 구조와 상태 관리

전체적으로 컴포넌트가 잘 분리되어 있고, 상태 관리가 체계적으로 구현되었습니다. 단방향 데이터 플로우를 잘 따르고 있으며, 각 기능별로 적절히 모듈화되어 있습니다.

src/app/(with-header)/myactivity/components/ScheduleSelectForm.tsx (1)

22-27: 컴포넌트 구조와 인터페이스 설계가 우수함

props 인터페이스가 명확하고 컴포넌트의 책임이 잘 분리되어 있습니다. 일정 관리 로직이 적절히 구현되었습니다.

src/app/(with-header)/myactivity/components/InfoSection.tsx (3)

20-31: 컴포넌트 구조와 레이아웃이 잘 설계됨

반응형 그리드 레이아웃과 controlled component 패턴이 적절히 적용되었고, 각 입력 필드가 명확한 목적을 가지고 있습니다.


52-66: InfoSection 컴포넌트 검토 결과

  • 가격 핸들링 타입 일관성
    ReservationForm에서 onPriceChange={(value) => setPrice(Number(value))}로 문자열을 숫자로 변환해 상태에 반영하고 있으므로, 타입 불일치 이슈가 없습니다.
  • 전반적 구조 및 설계
    제어 컴포넌트 패턴, Prop 인터페이스, Grid 레이아웃 모두 적절하게 적용되어 있어 컴포넌트 디자인은 문제없습니다.
  • 추가 확인 필요 사항
    • Input 컴포넌트가 type="textarea"를 올바르게 지원하는지 확인이 필요합니다.

위 사항 검토 후 머지 진행 부탁드립니다.


70-78: Input 컴포넌트의 textarea 타입 지원 여부 확인 요청

src/app/(with-header)/myactivity/components/InfoSection.tsx 72번째 줄에서 아래와 같이 <Input type='textarea' />를 사용하고 있습니다:

<Input
  label='설명'
  type='textarea'
  placeholder='체험에 대한 자세한 설명을 입력해주세요'
  className='w-full'
  value={description}
  onChange={(e) => onDescriptionChange(e.target.value)}
/>

Input 컴포넌트 정의 파일(src/components/Input.tsx 또는 src/components/Input/index.tsx)에 type === 'textarea'일 때 <textarea>를 렌더링하도록 분기 처리가 구현되어 있는지 확인해 주세요. 지원 로직이 없다면 필요에 따라 해당 분기와 스타일을 추가해 주시기 바랍니다.

src/app/(with-header)/myactivity/components/AddressInput.tsx (2)

24-33: 한국 주소 형식 처리 로직이 적절함

건물명과 동/읍/면 정보를 포함한 상세 주소 구성 로직이 한국 주소 체계에 맞게 잘 구현되었습니다.


48-67: Modal 통합과 UI 구성이 우수함

Modal 컴포넌트와의 통합이 적절하고, 사용자 경험을 고려한 UI 구성이 잘 되어 있습니다.

src/app/(with-header)/myactivity/components/SubImageSelect.tsx (2)

15-19: 이미지 개수 제한 로직이 잘 구현됨

4장 제한과 조건부 업로드 허용 로직이 명확하고 사용자 친화적입니다.


28-31: ImageUpload 조건부 렌더링 로직이 우수함

최대 이미지 개수에 도달했을 때 업로드 UI를 숨기는 로직이 적절합니다.

src/app/(with-header)/myactivity/components/ImageUpload.tsx (1)

25-49: 접근성과 사용자 경험이 우수함

라벨 기반 파일 선택, hover 효과, 시각적 피드백이 잘 구현되어 있고 접근성도 고려되었습니다.

Comment on lines 13 to 22
<label
htmlFor='category'
className='font-regular flex flex-col text-lg text-black'
>
카테고리
</label>
<div>
<select
id='category'
className='w-full rounded-md border border-gray-800 bg-white px-20 py-17 placeholder-gray-600'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Props 정렬 및 옵션 값 일관성 문제 수정 필요

파이프라인에서 지적한 props 정렬 문제를 해결하고, 옵션 값과 표시 텍스트의 일관성을 검토해야 합니다.

다음 diff를 적용하여 문제를 해결하세요:

      <label
-        htmlFor='category'
-        className='font-regular flex flex-col text-lg text-black'
+        className='font-regular flex flex-col text-lg text-black'
+        htmlFor='category'
      >
        카테고리
      </label>
      <div>
        <select
-          id='category'
-          className='w-full rounded-md border border-gray-800 bg-white px-20 py-17 placeholder-gray-600'
+          className='w-full rounded-md border border-gray-800 bg-white px-20 py-17 placeholder-gray-600'
+          id='category'
          value={category}
          onChange={(e) => onCategoryChange(e.target.value)}
        >
📝 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
<label
htmlFor='category'
className='font-regular flex flex-col text-lg text-black'
>
카테고리
</label>
<div>
<select
id='category'
className='w-full rounded-md border border-gray-800 bg-white px-20 py-17 placeholder-gray-600'
<label
className='font-regular flex flex-col text-lg text-black'
htmlFor='category'
>
카테고리
</label>
<div>
<select
className='w-full rounded-md border border-gray-800 bg-white px-20 py-17 placeholder-gray-600'
id='category'
value={category}
onChange={(e) => onCategoryChange(e.target.value)}
>
🧰 Tools
🪛 GitHub Actions: CI

[warning] 15-22: react/jsx-sort-props: Props should be sorted alphabetically.

🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/CategoryInput.tsx around lines 13
to 22, fix the props sorting by arranging the JSX attributes in a consistent
order, typically starting with id, then className, followed by other props.
Also, review the option elements inside the select to ensure that the option
values and their displayed text are consistent and correctly matched. Adjust the
code to apply these changes for better readability and correctness.

alt,
className = '',
}: ImagePreviewProps) {
const src = typeof image === 'string' ? image : URL.createObjectURL(image);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

메모리 누수 방지를 위한 URL cleanup 필요

URL.createObjectURL로 생성된 URL은 메모리 누수를 방지하기 위해 URL.revokeObjectURL로 정리해야 합니다.

다음과 같이 useEffect를 사용하여 cleanup을 구현하세요:

'use client';

+import { useEffect } from 'react';
import IconClose from '@assets/svg/close';

// ... in component
export function ImagePreview({
  image,
  onRemove,
  alt,
  className = '',
}: ImagePreviewProps) {
  const src = typeof image === 'string' ? image : URL.createObjectURL(image);

+  useEffect(() => {
+    return () => {
+      if (typeof image !== 'string') {
+        URL.revokeObjectURL(src);
+      }
+    };
+  }, [src, image]);
📝 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
const src = typeof image === 'string' ? image : URL.createObjectURL(image);
'use client';
import { useEffect } from 'react';
import IconClose from '@assets/svg/close';
// ... other imports
export function ImagePreview({
image,
onRemove,
alt,
className = '',
}: ImagePreviewProps) {
const src = typeof image === 'string' ? image : URL.createObjectURL(image);
useEffect(() => {
return () => {
if (typeof image !== 'string') {
URL.revokeObjectURL(src);
}
};
}, [src, image]);
return (
<div className={className}>
<img src={src} alt={alt} />
<button onClick={onRemove}>
<IconClose />
</button>
</div>
);
}
🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/ImagePreview.tsx at line 18, the
URL created by URL.createObjectURL when image is not a string needs to be
revoked to prevent memory leaks. Wrap the URL creation in a useEffect hook that
sets the src state and returns a cleanup function calling URL.revokeObjectURL on
the created URL when the component unmounts or the image changes.

Comment on lines +23 to +27
<img
src={src || '/placeholder.svg'}
className='h-full w-full object-cover'
alt={alt}
/>
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Next.js Image 컴포넌트 사용 권장

파이프라인에서 지적한 대로 <img> 태그 대신 Next.js의 <Image> 컴포넌트를 사용하면 성능과 LCP를 개선할 수 있습니다.

+import Image from 'next/image';

-        <img
+        <Image
           src={src || '/placeholder.svg'}
           className='h-full w-full object-cover'
           alt={alt}
+          fill
+          sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
-        />
+        />
🧰 Tools
🪛 GitHub Actions: CI

[warning] 23-23: @next/next/no-img-element: Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image or a custom image loader.

🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/ImagePreview.tsx around lines 23
to 27, replace the standard <img> tag with Next.js's <Image> component to
improve performance and LCP. Import the Image component from 'next/image', then
update the JSX to use <Image> with equivalent props: set src to src or
'/placeholder.svg', provide alt text, and apply the same styling using the
appropriate layout or className props supported by Next.js Image.

Comment on lines +6 to +13
interface ImagesSectionProps {
mainImage: string | File | null;
subImage: (string | File)[];
onMainImageSelect: (file: File) => void;
onMainImageRemove: () => void;
onSubImageAdd: (files: File[]) => void;
onSubImageRemove: (index: number) => void;
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

타입 이름과 컴포넌트 이름 불일치
interface ImagesSectionProps { ... }export function ImageSection 간 복수형/단수형이 달라 가독성이 떨어집니다. 이름을 맞추어 주세요.

-interface ImagesSectionProps {
+interface ImageSectionProps {
...
-}: ImagesSectionProps) {
+}: ImageSectionProps) {

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

🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/ImageSection.tsx around lines 6
to 13, the interface name ImagesSectionProps uses a plural form while the
component is named ImageSection in singular, causing inconsistency. Rename the
interface to ImageSectionProps to match the component name for better
readability and consistency.

Comment on lines +41 to +61
{dates.map((dateSlot, idx) => (
<div className='flex'>
<ScheduleSelect
key={idx}
index={idx}
isRemovable={dates.length > 1}
onAddDate={onAddDate}
onRemove={onRemoveDate}
onDateChange={(index, value) => onDateChange(index, 'date', value)}
onStartTimeChange={(index, value) =>
onDateChange(index, 'startTime', value)
}
onEndTimeChange={(index, value) =>
onDateChange(index, 'endTime', value)
}
date={dateSlot.date}
startTime={dateSlot.startTime}
endTime={dateSlot.endTime}
/>
</div>
))}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

React key 최적화 및 불필요한 wrapper 제거 필요

배열 인덱스를 key로 사용하면 항목이 재정렬되거나 제거될 때 렌더링 문제가 발생할 수 있습니다. 또한 불필요한 div wrapper가 있습니다.

다음과 같이 수정하세요:

-      {dates.map((dateSlot, idx) => (
-        <div className='flex'>
-          <ScheduleSelect
-            key={idx}
+      {dates.map((dateSlot, idx) => (
+          <ScheduleSelect
+            key={`${dateSlot.date}-${dateSlot.startTime}-${idx}`}
             index={idx}
             isRemovable={dates.length > 1}
             onAddDate={onAddDate}
             onRemove={onRemoveDate}
             onDateChange={(index, value) => onDateChange(index, 'date', value)}
             onStartTimeChange={(index, value) =>
               onDateChange(index, 'startTime', value)
             }
             onEndTimeChange={(index, value) =>
               onDateChange(index, 'endTime', value)
             }
             date={dateSlot.date}
             startTime={dateSlot.startTime}
             endTime={dateSlot.endTime}
           />
-        </div>
-      ))}
+      ))}
📝 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
{dates.map((dateSlot, idx) => (
<div className='flex'>
<ScheduleSelect
key={idx}
index={idx}
isRemovable={dates.length > 1}
onAddDate={onAddDate}
onRemove={onRemoveDate}
onDateChange={(index, value) => onDateChange(index, 'date', value)}
onStartTimeChange={(index, value) =>
onDateChange(index, 'startTime', value)
}
onEndTimeChange={(index, value) =>
onDateChange(index, 'endTime', value)
}
date={dateSlot.date}
startTime={dateSlot.startTime}
endTime={dateSlot.endTime}
/>
</div>
))}
{dates.map((dateSlot, idx) => (
<ScheduleSelect
key={`${dateSlot.date}-${dateSlot.startTime}-${idx}`}
index={idx}
isRemovable={dates.length > 1}
onAddDate={onAddDate}
onRemove={onRemoveDate}
onDateChange={(index, value) => onDateChange(index, 'date', value)}
onStartTimeChange={(index, value) =>
onDateChange(index, 'startTime', value)
}
onEndTimeChange={(index, value) =>
onDateChange(index, 'endTime', value)
}
date={dateSlot.date}
startTime={dateSlot.startTime}
endTime={dateSlot.endTime}
/>
))}
🧰 Tools
🪛 Biome (2.1.2)

[error] 42-43: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

🪛 GitHub Actions: CI

[warning] 42-44: react/jsx-key: Missing "key" prop for element in iterator; react/no-array-index-key: Do not use Array index in keys.

🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/ScheduleSelectForm.tsx between
lines 41 and 61, replace the array index used as the React key with a unique and
stable identifier from the dateSlot object to prevent rendering issues during
reordering or removal. Also, remove the unnecessary div wrapper around the
ScheduleSelect component to simplify the JSX structure.

Comment on lines +32 to +40
{subImage.map((img, idx) => (
<ImagePreview
key={idx}
image={img}
onRemove={() => onImageRemove(idx)}
alt={`소개 이미지 ${idx + 1}`}
/>
))}
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

React key로 배열 인덱스 사용 문제

이미지가 제거될 때 배열 인덱스를 key로 사용하면 렌더링 문제가 발생할 수 있습니다.

File 객체의 고유 속성을 사용하거나 UUID를 생성하여 key로 사용하세요:

       {subImage.map((img, idx) => (
         <ImagePreview
-          key={idx}
+          key={typeof img === 'string' ? img : `${img.name}-${img.size}-${idx}`}
           image={img}
           onRemove={() => onImageRemove(idx)}
           alt={`소개 이미지 ${idx + 1}`}
         />
       ))}
📝 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
{subImage.map((img, idx) => (
<ImagePreview
key={idx}
image={img}
onRemove={() => onImageRemove(idx)}
alt={`소개 이미지 ${idx + 1}`}
/>
))}
</div>
{subImage.map((img, idx) => (
<ImagePreview
key={typeof img === 'string' ? img : `${img.name}-${img.size}-${idx}`}
image={img}
onRemove={() => onImageRemove(idx)}
alt={`소개 이미지 ${idx + 1}`}
/>
))}
</div>
🧰 Tools
🪛 GitHub Actions: CI

[warning] 34-36: react/no-array-index-key and react/jsx-sort-props warnings: Do not use Array index in keys; Callbacks must be listed after all other props.

🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/SubImageSelect.tsx around lines
32 to 40, the React key prop currently uses the array index, which can cause
rendering issues when images are removed. To fix this, use a unique identifier
from the File object if available, or generate a UUID for each image and use
that as the key instead of the index. This ensures stable keys and prevents
rendering problems during updates.

Comment on lines +3 to +8
export default function Page() {
return (
<div>
<ReservationForm />
</div>
);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

페이지 컴포넌트에 'use client' 선언 여부 재검토
부모 페이지가 서버 컴포넌트이고 자식 ReservationForm이 클라이언트 컴포넌트라면 현재 구조로도 동작은 합니다. 다만 페이지 레벨에서도 클라이언트 전용 훅(예: useSearchParams)을 추가할 가능성이 있다면 미리 'use client' 를 선언해 두는 것이 추후 변경 시 혼란을 줄입니다.

🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/page.tsx around lines 3 to 8, the page
component currently lacks a 'use client' directive. If you plan to use
client-only hooks like useSearchParams in this page or want to avoid confusion
when adding such hooks later, add the 'use client' directive at the top of this
file to explicitly mark it as a client component.

Comment on lines 68 to 71
html {
font-family: 'Pretendard-Regular', sans-serif;
scrollbar-gutter: stable;
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

scrollbar-gutter 브라우저 지원 범위 확인 권장
해당 속성은 Chromium 94+, Safari 16.2+만 지원합니다. 구형 브라우저(특히 Firefox)에서는 무시되므로 레이아웃 점프가 재발할 수 있습니다. 주요 타깃 브라우저가 이 범위를 벗어나면 폴백 CSS(예: padding 보정)를 같이 두는 편이 안전합니다.

🤖 Prompt for AI Agents
In src/app/globals.css around lines 68 to 71, the scrollbar-gutter property is
used but it is only supported in Chromium 94+ and Safari 16.2+, so older
browsers like Firefox will ignore it causing potential layout jumps. To fix
this, add fallback CSS such as padding adjustments to maintain layout stability
in unsupported browsers, ensuring consistent appearance across all target
browsers.

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: 4

♻️ Duplicate comments (5)
src/app/(with-header)/myactivity/components/MainImageSelect.tsx (1)

28-32: Props 순서를 수정해주세요.

콜백 함수 props는 다른 props 뒤에 위치해야 합니다.

          <ImagePreview
+            alt='메인 이미지'
             image={mainImage}
-            onRemove={onImageRemove}
-            alt='메인 이미지'
+            onRemove={onImageRemove}
           />
src/app/(with-header)/myactivity/components/ScheduleSelect.tsx (4)

6-17: 인터페이스에서 미사용 props 제거 필요

onAddDate props가 여전히 인터페이스에 정의되어 있지만 컴포넌트에서 사용되지 않습니다. 과거 리뷰에서 지적된 문제가 해결되지 않았습니다.

다음 diff를 적용하여 미사용 props를 제거하세요:

interface ScheduleSelectProps {
  index: number;
  isRemovable: boolean;
-  onAddDate: () => void;
  onRemove: (index: number) => void;
  onDateChange: (index: number, value: string) => void;
  onStartTimeChange: (index: number, value: string) => void;
  onEndTimeChange: (index: number, value: string) => void;
  date: string;
  startTime: string;
  endTime: string;
}

35-41: Input 컴포넌트의 props 순서 개선 필요

과거 리뷰에서 지적된 props 순서 문제가 여전히 존재합니다. classNameonChange 콜백 앞에 위치해야 합니다.

          <Input
            label='날짜'
            type='date'
+            className='w-full'
            value={date}
-            className='w-full'
            onChange={(e) => onDateChange(index, e.target.value)}
          />

55-61: 종료시간 Input의 props 순서 수정 필요

종료시간 Input에도 동일한 props 순서 수정이 필요합니다.

          <Input
            label='종료시간'
            type='time'
+            className='w-full'
            value={endTime}
-            className='w-full'
            onChange={(e) => onEndTimeChange(index, e.target.value)}
          />

45-51: 시작시간 Input의 props 순서 수정 필요

동일한 props 순서 문제가 시작시간 Input에도 적용되어야 합니다.

          <Input
            label='시작시간'
            type='time'
+            className='w-full'
            value={startTime}
-            className='w-full'
            onChange={(e) => onStartTimeChange(index, e.target.value)}
          />
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a740d3f and b6e930d.

📒 Files selected for processing (3)
  • src/app/(with-header)/myactivity/components/AddressInput.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/MainImageSelect.tsx (1 hunks)
  • src/app/(with-header)/myactivity/components/ScheduleSelect.tsx (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/app/(with-header)/myactivity/components/ScheduleSelect.tsx (1)
src/components/Input.tsx (1)
  • Input (17-61)
src/app/(with-header)/myactivity/components/AddressInput.tsx (2)
src/components/Input.tsx (1)
  • Input (17-61)
src/components/Button.tsx (1)
  • Button (18-49)
src/app/(with-header)/myactivity/components/MainImageSelect.tsx (2)
src/app/(with-header)/myactivity/components/ImageUpload.tsx (1)
  • ImageUpload (12-50)
src/app/(with-header)/myactivity/components/ImagePreview.tsx (1)
  • ImagePreview (12-39)
🔇 Additional comments (5)
src/app/(with-header)/myactivity/components/MainImageSelect.tsx (3)

1-4: 임포트 정리가 잘 되었습니다.

미사용 임포트 문제가 해결되었고, 필요한 컴포넌트들만 임포트하고 있습니다.


6-10: 인터페이스 설계가 우수합니다.

다양한 이미지 소스 타입(File, string, null)을 지원하고 콜백 함수들의 시그니처가 명확하게 정의되어 있습니다.


17-41: 컴포넌트 구조와 UX가 잘 설계되었습니다.

  • 반응형 그리드 레이아웃으로 다양한 화면 크기를 지원
  • 명확한 사용자 안내 메시지와 제약 사항 표시
  • 컴포넌트 분리를 통한 관심사 분리가 잘 이루어짐
  • 조건부 렌더링으로 적절한 상태 관리

전반적으로 사용자 친화적이고 유지보수하기 좋은 코드입니다.

src/app/(with-header)/myactivity/components/ScheduleSelect.tsx (2)

19-30: 함수 파라미터에서 onAddDate 제거 완료

함수 파라미터에서 onAddDate가 제거된 것을 확인했습니다. 22번 라인의 공백이 이를 나타냅니다. 좋은 수정입니다.


64-74: 제거 버튼 로직이 잘 구현됨

isRemovable 조건부 렌더링과 제거 버튼의 스타일링이 적절하게 구현되었습니다. 접근성과 사용자 경험을 고려한 hover 효과도 잘 적용되었습니다.

Comment on lines +14 to +21
interface PostcodeData {
address: string;
addressType: 'R' | 'J';
bname: string;
buildingName: string;
zonecode: string;
userSelectedType: string;
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

userSelectedType 타입을 구체화하세요

userSelectedType 역시 'R' | 'J' 로 고정된 값만 들어오므로 string 대신 동일한 유니온 타입을 부여하면 타입 안정성이 한층 올라갑니다.

-  userSelectedType: string;
+  userSelectedType: 'R' | 'J';
📝 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
interface PostcodeData {
address: string;
addressType: 'R' | 'J';
bname: string;
buildingName: string;
zonecode: string;
userSelectedType: string;
}
interface PostcodeData {
address: string;
addressType: 'R' | 'J';
bname: string;
buildingName: string;
zonecode: string;
userSelectedType: 'R' | 'J';
}
🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/AddressInput.tsx between lines 14
and 21, the userSelectedType property in the PostcodeData interface is currently
typed as string, which is too general. Change its type to the union type 'R' |
'J' to match the addressType property and improve type safety by restricting it
to these specific string literals.

Comment on lines +29 to +46
const handleComplete = (data: PostcodeData) => {
let fullAddress = data.address;
let extraAddress = '';

if (data.addressType === 'R') {
if (data.bname !== '') {
extraAddress += data.bname;
}
if (data.buildingName !== '') {
extraAddress +=
extraAddress !== '' ? `, ${data.buildingName}` : data.buildingName;
}
fullAddress += extraAddress !== '' ? ` (${extraAddress})` : '';
}

onAddressChange(fullAddress);
setIsOpen(false);
};
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

handleCompleteuseCallback으로 감싸 성능 최적화

매 렌더마다 새로운 함수가 생성되어 DaumPostcode-> 리렌더 트리거 가능성이 있습니다.

-  const handleComplete = (data: PostcodeData) => {
+  const handleComplete = useCallback((data: PostcodeData) => {-  };
+  }, [onAddressChange]);

불필요한 재생성을 줄여 컴포넌트 트리 성능을 개선할 수 있습니다.

📝 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
const handleComplete = (data: PostcodeData) => {
let fullAddress = data.address;
let extraAddress = '';
if (data.addressType === 'R') {
if (data.bname !== '') {
extraAddress += data.bname;
}
if (data.buildingName !== '') {
extraAddress +=
extraAddress !== '' ? `, ${data.buildingName}` : data.buildingName;
}
fullAddress += extraAddress !== '' ? ` (${extraAddress})` : '';
}
onAddressChange(fullAddress);
setIsOpen(false);
};
const handleComplete = useCallback((data: PostcodeData) => {
let fullAddress = data.address;
let extraAddress = '';
if (data.addressType === 'R') {
if (data.bname !== '') {
extraAddress += data.bname;
}
if (data.buildingName !== '') {
extraAddress +=
extraAddress !== '' ? `, ${data.buildingName}` : data.buildingName;
}
fullAddress += extraAddress !== '' ? ` (${extraAddress})` : '';
}
onAddressChange(fullAddress);
setIsOpen(false);
}, [onAddressChange]);
🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/AddressInput.tsx around lines 29
to 46, the handleComplete function is recreated on every render, which may cause
unnecessary re-renders of the DaumPostcode component. To optimize performance,
wrap the handleComplete function with React's useCallback hook, providing
appropriate dependencies to prevent unnecessary recreations while ensuring it
updates correctly when needed.

Comment on lines +51 to +56
label='주소'
id='address'
value={address}
onClick={() => setIsOpen(true)}
readOnly
/>
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

id prop 전달은 의미 없습니다

Input 컴포넌트 내부에서 useId()로 자체 id를 생성하여 전달된 id를 무시합니다.
id='address' 속성을 제거해 코드 노이즈를 줄여주세요.

🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/AddressInput.tsx around lines 51
to 56, the id='address' prop passed to the Input component is ignored because
the component generates its own id internally using useId(). Remove the
id='address' prop from the Input component to eliminate unnecessary code noise.

Comment on lines +32 to +33
<div className='rounded-lg bg-gray-50 p-4'>
<div className='grid grid-cols-1 items-center gap-10 sm:grid-cols-4'>
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

반응형 그리드 레이아웃 개선 제안

현재 그리드 레이아웃이 sm:grid-cols-4로 설정되어 있는데, 제거 버튼이 있을 때와 없을 때의 공간 활용을 더 효율적으로 할 수 있습니다.

-      <div className='grid grid-cols-1 items-center gap-10 sm:grid-cols-4'>
+      <div className={`grid grid-cols-1 items-center gap-10 ${isRemovable ? 'sm:grid-cols-4' : 'sm:grid-cols-3'}`}>

그리고 각 Input div의 colspan도 조건부로 조정:

-        <div className='sm:col-span-1'>
+        <div className={isRemovable ? 'sm:col-span-1' : 'sm:col-span-1'}>

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

🤖 Prompt for AI Agents
In src/app/(with-header)/myactivity/components/ScheduleSelect.tsx around lines
32 to 33, the current responsive grid layout uses a fixed sm:grid-cols-4 which
does not optimize space when the remove button is present or absent. Adjust the
grid template columns dynamically based on the presence of the remove button to
better utilize space. Also, update the colspan of each input div conditionally
to reflect these layout changes for improved responsiveness and alignment.

Copy link
Contributor

@minimo-9 minimo-9 left a comment

Choose a reason for hiding this comment

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

만드시느라 고생많으셨습니다! 양이 굉장히 많은데 금방 구현하시고 대단합니다!

return (
<div className={`group relative ${className}`}>
<div className='aspect-square w-full overflow-hidden rounded-lg'>
<img
Copy link
Contributor

Choose a reason for hiding this comment

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

요 부분은 Image 태그말고 img를 쓰신 이유가 있으신가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

리팩토링 과정에서 변경하도록하겠습니다!

Copy link
Contributor

@LeeCh0129 LeeCh0129 left a comment

Choose a reason for hiding this comment

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

체험 등록/수정 페이지 로직 및 레이아웃 구현 고생 많으셨습니다. 역시 우리팀 에이스 👍

@evaain706 evaain706 merged commit 8651d64 into develop Jul 27, 2025
1 of 2 checks passed
@evaain706 evaain706 deleted the feat/70 branch July 27, 2025 01:12
@coderabbitai coderabbitai bot mentioned this pull request Aug 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능구현

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants