Skip to content

feat: Signup pages#19

Merged
heeeeyong merged 2 commits into
developfrom
feature/signup
Jun 30, 2025
Merged

feat: Signup pages#19
heeeeyong merged 2 commits into
developfrom
feature/signup

Conversation

@heeeeyong
Copy link
Copy Markdown
Collaborator

@heeeeyong heeeeyong commented Jun 26, 2025

#️⃣연관된 이슈

ex) #이슈번호, #이슈번호
close #15
close #20

📝작업 내용 & 스크린샷

이전 PR 작업내용까지 합쳐서 올립니당~

  • 로그인화면

image
- 설정1 (닉네임)
image
-설정2 (칭호)
image
image
- 회원가입 완료 화면
image
- 네비바 구현 image image 클릭시 해당 경로로 이동 및 경로에 따른 활성화 여부 판단을 하도록 구현했습니다.

💬리뷰 요구사항(선택)

  1. 닉네임 유효성 검증을 당연히 서버로 요청을 보내서 하겠지만, 프론트단에서도 처리를 해야할 것 같아서 로직을 짜놓기는 했는데 한글 단자음을 작성하는 경우에도 허용이 되는데 이걸 어떻게 처리하면 좋을까요? composing하는 로직을 추가하면 되는걸까요?

  2. 설정2 화면에서 css를 figma랑 똑같이 구현하기가 힘든데 (linear-gradient 속성 등) 어떻게하면 좋을까요?

기타

  1. 현재 설정2 화면과 회원가입 완료화면 사이에 튜토리얼 슬라이드를 띄워야하는데 해당부분이 아직 만들어지지 않아서 나중에 만들어야할듯 합니다.

  2. 유저 칭호마다 다른 색을 가져와야하는데 이걸 서버에서 매번 가져오는게 맞을지... 좋은방법이 없을까 고민이 되네요...

  3. 오늘 저녁에 네비바 만들 예정입니다.

  4. 반응형으로 구현을 하긴 했는데 이 부분 설정도 전역으로 해야할듯합니다..

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • 로그인 페이지가 추가되었습니다.
    • 회원가입 완료 페이지가 추가되었습니다.
    • 장르 선택 단계에서 장르 데이터를 동적으로 불러오고, 장르 카드를 선택할 수 있습니다.
    • 하단 네비게이션 바가 새롭게 도입되었습니다.
  • 버그 수정 및 개선

    • 회원가입 닉네임 입력 시 허용된 문자(한글, 영문, 숫자)만 입력할 수 있도록 개선되었습니다.
    • 회원가입 단계별 버튼 활성화 상태가 입력값에 따라 동적으로 반영됩니다.
  • 스타일

    • 회원가입 관련 페이지와 버튼, 장르 카드, 네비게이션 바 등 다양한 UI 요소의 스타일이 개선되었습니다.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 26, 2025

"""

Walkthrough

로그인, 회원가입, 온보딩 UI를 위한 주요 컴포넌트와 스타일이 추가 및 수정되었습니다. 새로운 장르 데이터 JSON 파일이 도입되었고, 각 단계별 회원가입 페이지와 로그인 페이지가 구현되었습니다. 라우팅 설정이 업데이트되어 신규 페이지 진입점이 추가되었습니다.

Changes

파일/그룹 변경 요약
public/genres.json 장르 데이터가 포함된 신규 JSON 파일 추가
src/pages/index.tsx 라우터에 로그인 및 회원가입 완료(온보딩) 경로 추가
src/pages/login/Login.tsx 로그인 UI 컴포넌트 신규 구현
src/pages/signup/Header.tsx Header 컴포넌트: NextButton 스타일 및 활성화 prop 추가, props 타입 변경
src/pages/signup/Signup.styled.ts 회원가입/온보딩 UI를 위한 Container 및 내부 요소 스타일 대폭 확장
src/pages/signup/SignupDone.tsx 회원가입 완료(온보딩) UI 컴포넌트 신규 구현
src/pages/signup/SignupGenre.tsx 장르 선택: 장르 데이터 fetch, 선택 로직, 동적 렌더링, Header prop 확장
src/pages/signup/SignupNickname.tsx 닉네임 입력값 필터링(한글/영문/숫자), Header prop 확장
src/components/NavBar.tsx 하단 고정 네비게이션 바 신규 컴포넌트 구현

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Router
    participant Login
    participant SignupNickname
    participant SignupGenre
    participant SignupDone

    User->>Router: "/" 접속
    Router->>Login: Login 컴포넌트 렌더링
    User->>Login: 소셜 로그인 버튼 클릭
    Login->>Router: 회원가입 페이지로 이동

    User->>SignupNickname: 닉네임 입력 및 Next 클릭
    SignupNickname->>SignupGenre: 장르 선택 화면 이동
    User->>SignupGenre: 장르 선택 및 Next 클릭
    SignupGenre->>SignupDone: 선택 장르와 함께 온보딩 완료 화면 이동
    User->>SignupDone: "지금 바로 Thip 시작하기" 클릭
    SignupDone->>Router: /feed로 이동
Loading

Assessment against linked issues

Objective Addressed Explanation
로그인 UI 구현 (#15)
회원가입 UI 구현 (#15)
온보딩 UI 구현 (#15)

Assessment against linked issues: Out-of-scope changes

(해당 변경사항 내에서는 이슈 목표와 직접적으로 관련 없는 기능적 코드 변경이 발견되지 않았습니다.)

Suggested labels

✨ Feature, 🎨 Html&css

Poem

🐰
로그인 창에 햇살이 비치고,
장르 카드가 춤을 추네.
닉네임도 반짝, 온보딩은 설렘,
이제 Thip 세상에 뛰어들 시간!
토끼도 로그인, 오늘은 우리 모두 주인공!
🎉
"""

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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 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
Copy Markdown

@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: 9

🧹 Nitpick comments (6)
src/pages/signup/Signup.styled.ts (1)

164-165: 주석 처리된 CSS 코드를 제거하거나 설명을 추가하세요.

주석 처리된 CSS 코드가 남아있는데, 이를 제거하거나 왜 주석 처리했는지 설명을 추가해야 합니다.

        border: 1px solid #fefefe;
-        /* background: linear-gradient(0deg, rgba(18, 18, 18, 0.3) 0%, rgba(18, 18, 18, 0.3) 100%);
-        background-color: lightgray; */

또는 필요하다면 다음과 같이 설명을 추가:

+        /* 배경 그라데이션은 디자인 검토 후 추후 적용 예정 */
+        /* background: linear-gradient(0deg, rgba(18, 18, 18, 0.3) 0%, rgba(18, 18, 18, 0.3) 100%); */
src/pages/index.tsx (1)

7-7: 라우팅 구조가 적절하게 구성되었습니다.

Login 컴포넌트를 루트 경로로 설정하고 SignupDone을 독립 경로로 추가한 것이 적절합니다. 기존 중첩 라우팅 구조도 잘 유지되었습니다.

일관성을 위해 라우트 경로 네이밍을 고려해보세요:

-        <Route path="signupdone" element={<SignupDone />} />
+        <Route path="signup/done" element={<SignupDone />} />

이렇게 하면 모든 회원가입 관련 경로가 /signup 하위에 위치하게 됩니다.

Also applies to: 11-11, 17-17, 22-22

src/pages/signup/SignupDone.tsx (2)

25-25: 이미지에 alt 속성을 추가하세요.

접근성을 위해 프로필 이미지에 적절한 alt 속성을 추가해야 합니다.

-            <img src={art} />
+            <img src={art} alt="프로필 이미지" />

25-25: 이미지에 alt 속성이 누락되었습니다.

접근성을 위해 프로필 이미지에 적절한 alt 속성을 추가해야 합니다.

-<img src={art} />
+<img src={art} alt="프로필 이미지" />
src/pages/signup/SignupGenre.tsx (1)

20-25: 네트워크 요청에 AbortController를 추가하세요.

컴포넌트가 언마운트될 때 진행 중인 요청을 취소할 수 있도록 AbortController를 사용하는 것이 좋습니다.

useEffect(() => {
+ const abortController = new AbortController();
  setLoading(true);
- fetch('/genres.json')
+ fetch('/genres.json', { signal: abortController.signal })
    .then(res => res.json())
    .then((data: Genre[]) => {
      setGenres(data);
      setError(null);
    })
    .catch((err) => {
+     if (err.name === 'AbortError') return;
      console.error(err);
      setError('장르 정보를 불러오는데 실패했습니다.');
    })
    .finally(() => setLoading(false));
+
+ return () => abortController.abort();
}, []);
src/pages/signup/Header.tsx (1)

20-36: 주석 처리된 CSS 코드를 제거하세요.

더 이상 사용하지 않는 주석 처리된 .next CSS 클래스 코드를 정리하는 것이 좋겠습니다.

-  /* 
-  .next {
-    width: 49px;
-    height: 28px;
-    padding: 4px 12px;
-    align-items: center;
-    border-radius: 20px;
-    background: #888;
-
-    color: #fefefe;
-    text-align: center;
-    font-size: 14px;
-    font-style: normal;
-    font-weight: 600;
-    line-height: 20px;
-  } */
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1212b and f30d1ed.

⛔ Files ignored due to path filters (13)
  • public/assets/genre/art.svg is excluded by !**/*.svg
  • public/assets/genre/humanity.svg is excluded by !**/*.svg
  • public/assets/genre/literature.svg is excluded by !**/*.svg
  • public/assets/genre/science.svg is excluded by !**/*.svg
  • public/assets/genre/socialScience.svg is excluded by !**/*.svg
  • src/assets/genre/art.svg is excluded by !**/*.svg
  • src/assets/genre/humanity.svg is excluded by !**/*.svg
  • src/assets/genre/literature.svg is excluded by !**/*.svg
  • src/assets/genre/science.svg is excluded by !**/*.svg
  • src/assets/genre/socialScience.svg is excluded by !**/*.svg
  • src/assets/login/google.svg is excluded by !**/*.svg
  • src/assets/login/kakao.svg is excluded by !**/*.svg
  • src/assets/login/logo.svg is excluded by !**/*.svg
📒 Files selected for processing (8)
  • public/genres.json (1 hunks)
  • src/pages/index.tsx (1 hunks)
  • src/pages/login/Login.tsx (1 hunks)
  • src/pages/signup/Header.tsx (3 hunks)
  • src/pages/signup/Signup.styled.ts (2 hunks)
  • src/pages/signup/SignupDone.tsx (1 hunks)
  • src/pages/signup/SignupGenre.tsx (2 hunks)
  • src/pages/signup/SignupNickname.tsx (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/pages/signup/SignupDone.tsx (1)
src/pages/signup/Signup.styled.ts (1)
  • Container (3-175)
src/pages/signup/SignupGenre.tsx (1)
src/pages/signup/Signup.styled.ts (1)
  • Container (3-175)
🔇 Additional comments (12)
public/genres.json (1)

1-37: JSON 구조와 데이터가 올바르게 구성되어 있습니다.

장르 데이터의 구조가 일관되고 올바르게 형성되어 있습니다. 각 장르 객체가 동일한 속성들을 가지고 있으며, 한국어 제목과 부제목이 적절하게 설정되어 있습니다.

아이콘 파일들이 실제로 존재하는지 확인해보겠습니다:

#!/bin/bash
# 장르 아이콘 파일들이 존재하는지 확인
echo "장르 아이콘 파일 존재 여부 확인:"
for genre in literature science socialScience art humanity; do
  if [ -f "public/assets/genre/${genre}.svg" ]; then
    echo "${genre}.svg 존재"
  else
    echo "${genre}.svg 없음"
  fi
done
src/pages/signup/Signup.styled.ts (2)

104-174: 장르 카드 스타일링이 잘 구현되었습니다.

반응형 그리드 레이아웃과 호버/선택 상태 스타일링이 적절하게 구현되어 있습니다. CSS 트랜지션과 z-index를 활용한 레이어링도 잘 처리되었습니다.


8-8: ```shell
#!/bin/bash
echo "768px 사용 여부 재확인 (.ts, .tsx, .css, .scss):"
rg -F "768px" -g ".ts" -g ".tsx" -g ".css" -g ".scss"


</details>
<details>
<summary>src/pages/signup/SignupNickname.tsx (1)</summary>

`35-35`: **Header 컴포넌트에 isNextActive prop 전달이 적절합니다.**

다음 버튼의 활성화 상태를 관리하는 방식이 일관되고 직관적입니다.

</details>
<details>
<summary>src/pages/signup/Header.tsx (3)</summary>

`38-53`: **잘 구현된 조건부 스타일링입니다.**

NextButton 컴포넌트가 active 상태에 따라 적절히 스타일링되고 있습니다. 커서와 배경색 변경이 사용자 경험을 향상시킵니다.

---

`87-93`: **조건부 렌더링 로직이 적절합니다.**

rightButton의 유무에 따른 조건부 렌더링과 NextButton에 isNextActive prop 전달이 올바르게 구현되었습니다.

---

`38-53`: **NextButton 컴포넌트와 Header 업데이트가 잘 구현되었습니다.**

새로운 `NextButton` 스타일드 컴포넌트는 `active` prop을 통한 조건부 스타일링이 잘 구현되어 있고, Header 컴포넌트의 props 인터페이스도 적절하게 업데이트되었습니다. 사용자 경험을 개선하는 좋은 변경사항입니다.




Also applies to: 73-96

</details>
<details>
<summary>src/pages/signup/SignupGenre.tsx (5)</summary>

`32-34`: **조건부 네비게이션 로직이 적절합니다.**

selectedId가 없을 때 early return하는 로직이 올바르게 구현되었습니다. 선택된 장르 ID를 state로 전달하는 것도 좋습니다.

---

`50-66`: **장르 카드 렌더링 로직이 잘 구현되었습니다.**

동적 클래스명 적용, 선택 상태 관리, 그리고 장르별 색상 적용이 적절히 구현되었습니다.

---

`7-13`: **Genre 인터페이스가 잘 정의되었습니다.**

TypeScript 인터페이스를 통한 타입 안전성 확보가 잘 되어 있습니다.

---

`50-66`: **장르 선택 UI가 잘 구현되었습니다.**

동적 데이터 렌더링, 선택 상태 관리, 조건부 스타일링이 모두 적절하게 구현되어 있습니다. 사용자 경험이 직관적이고 접근성도 고려되어 있습니다.

---

`31-34`: **내비게이션 로직과 Header 통합이 잘 구현되었습니다.**

선택된 장르가 있을 때만 다음 단계로 진행할 수 있도록 하는 로직과 `isNextActive` prop을 통한 Header와의 통합이 훌륭합니다.




Also applies to: 44-44

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread src/pages/login/Login.tsx

return (
<Wrapper>
<img src={logo} />
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

이미지에 alt 속성을 추가하여 접근성을 개선하세요.

스크린 리더 사용자를 위해 모든 이미지에 적절한 alt 텍스트를 제공해야 합니다.

-      <img src={logo} />
+      <img src={logo} alt="THIP 로고" />
📝 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
<img src={logo} />
<img src={logo} alt="THIP 로고" />
🤖 Prompt for AI Agents
In src/pages/login/Login.tsx at line 63, the img tag lacks an alt attribute,
which reduces accessibility for screen reader users. Add a meaningful alt
attribute to the img element, describing the image content appropriately to
improve accessibility.

Comment thread src/pages/login/Login.tsx
Comment on lines +53 to +59
const handleKakaoLogin = () => {
return;
};

const handleGoogleLogin = () => {
return;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

빈 핸들러 함수들을 TODO 코멘트로 표시하거나 실제 구현을 추가하세요.

현재 로그인 핸들러들이 단순히 return만 하고 있어서 실제 기능이 구현되지 않았습니다.

  const handleKakaoLogin = () => {
-    return;
+    // TODO: 카카오 로그인 구현
+    console.log('카카오 로그인 시도');
  };

  const handleGoogleLogin = () => {
-    return;
+    // TODO: 구글 로그인 구현  
+    console.log('구글 로그인 시도');
  };
📝 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 handleKakaoLogin = () => {
return;
};
const handleGoogleLogin = () => {
return;
};
const handleKakaoLogin = () => {
// TODO: 카카오 로그인 구현
console.log('카카오 로그인 시도');
};
const handleGoogleLogin = () => {
// TODO: 구글 로그인 구현
console.log('구글 로그인 시도');
};
🤖 Prompt for AI Agents
In src/pages/login/Login.tsx around lines 53 to 59, the login handler functions
handleKakaoLogin and handleGoogleLogin are empty and only return immediately.
Add TODO comments inside these functions to indicate that implementation is
pending, or preferably implement the actual login logic for Kakao and Google
authentication to replace the empty handlers.

Comment thread src/pages/login/Login.tsx
Comment on lines +23 to 26
const inputValue = e.target.value;
const filteredValue = inputValue.replace(/[^ㄱ-ㅎ가-힣a-zA-Z0-9]/g, '');
setNickname(filteredValue);
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

한글 입력 검증 로직을 개선하세요.

현재 정규식이 한글 자음(ㄱ-ㅎ)을 허용하고 있는데, PR 목표에서 언급한 것처럼 단일 자음 입력을 방지하려면 더 정교한 검증이 필요합니다.

한글 조합 상태를 고려한 검증 로직을 제안합니다:

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const inputValue = e.target.value;
-    const filteredValue = inputValue.replace(/[^ㄱ-ㅎ가-힣a-zA-Z0-9]/g, '');
+    // 완성된 한글 음절, 영어, 숫자만 허용 (단일 자음/모음 제외)
+    const filteredValue = inputValue.replace(/[^가-힣a-zA-Z0-9]/g, '');
    setNickname(filteredValue);
  };

또는 더 정교한 한글 조합 검증을 원한다면:

const isValidKorean = (char: string) => {
  const code = char.charCodeAt(0);
  // 완성된 한글 음절 범위 (가-힣)
  return (code >= 0xAC00 && code <= 0xD7A3);
};

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  const inputValue = e.target.value;
  const filteredValue = inputValue
    .split('')
    .filter(char => 
      isValidKorean(char) || 
      /[a-zA-Z0-9]/.test(char)
    )
    .join('');
  setNickname(filteredValue);
};
🤖 Prompt for AI Agents
In src/pages/signup/SignupNickname.tsx around lines 23 to 26, the current regex
allows single Korean consonants (ㄱ-ㅎ), which should be disallowed. Replace the
regex-based filtering with a character-by-character validation that only permits
fully composed Korean syllables (Unicode range 가-힣) and alphanumeric characters.
Implement a helper function to check if a character is a valid Korean syllable
and filter the input string accordingly before setting the nickname state.

Comment on lines +27 to +28
<div className="username">희용희용</div>
<div className="subname">예술가</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

사용자 정보를 동적으로 처리해야 합니다.

사용자 이름과 역할(예술가)이 하드코딩되어 있습니다. 이전 회원가입 단계에서 선택한 정보를 활용해야 합니다.

-          <div className="username">희용희용</div>
-          <div className="subname">예술가</div>
+          <div className="username">{username}</div>
+          <div className="subname">{userRole}</div>
🤖 Prompt for AI Agents
In src/pages/signup/SignupDone.tsx around lines 27 to 28, the username and role
are hardcoded as static text. To fix this, replace the hardcoded values with
dynamic data passed as props or obtained from state/context that holds the
user's signup information. Ensure the component renders the actual username and
role selected in the previous signup step instead of fixed strings.

Comment on lines +20 to +21
<div className="title">안녕하세요, 희용희용님</div>
<div className="subtitle">이제 Thip에서 활동할 준비를 모두 마쳤어요!</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

하드코딩된 사용자 데이터를 동적으로 처리해야 합니다.

현재 사용자 이름이 하드코딩되어 있습니다. 이전 단계에서 입력된 닉네임이나 사용자 정보를 받아와서 동적으로 표시해야 합니다.

-      <div className="title">안녕하세요, 희용희용님</div>
+      <div className="title">안녕하세요, {username}님</div>
🤖 Prompt for AI Agents
In src/pages/signup/SignupDone.tsx around lines 20 to 21, the username is
hardcoded as "희용희용". To fix this, modify the component to accept the user's
nickname or relevant user data as a prop or retrieve it from context or state,
then replace the hardcoded name with this dynamic value so the greeting displays
the actual user's name.

🛠️ Refactor suggestion

하드코딩된 사용자 데이터를 동적으로 처리해야 합니다.

현재 사용자 이름("희용희용")과 역할("예술가")이 하드코딩되어 있습니다. 이전 단계에서 전달받은 사용자 데이터나 전역 상태를 사용하여 동적으로 표시해야 합니다.

다음과 같이 수정을 제안합니다:

+import { useLocation } from 'react-router-dom';
+
+const SignupDone = () => {
+  const location = useLocation();
+  const { userName, userRole } = location.state || { userName: '사용자', userRole: '역할' };
  const navigate = useNavigate();
  
-  <div className="title">안녕하세요, 희용희용님</div>
+  <div className="title">안녕하세요, {userName}님</div>
  
-  <div className="username">희용희용</div>
-  <div className="subname">예술가</div>
+  <div className="username">{userName}</div>
+  <div className="subname">{userRole}</div>

Also applies to: 25-28

🤖 Prompt for AI Agents
In src/pages/signup/SignupDone.tsx around lines 20 to 21 and also lines 25 to
28, the user name and role are hardcoded as "희용희용" and "예술가". Replace these
hardcoded values with dynamic data by accessing the user information passed from
the previous step or from a global state/store. Update the JSX to render the
user name and role dynamically instead of static strings.

Comment on lines +20 to +25
useEffect(() => {
fetch('/genres.json')
.then(res => res.json())
.then((data: Genre[]) => setGenres(data))
.catch(console.error);
}, []);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

에러 처리와 로딩 상태를 개선하세요.

현재 에러 처리가 console.error로만 되어 있고 로딩 상태가 없습니다. 사용자 경험 향상을 위해 개선이 필요합니다.

const SignupGenre = () => {
  const [genres, setGenres] = useState<Genre[]>([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState<string | null>(null);
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const navigate = useNavigate();

  useEffect(() => {
+   setLoading(true);
    fetch('/genres.json')
      .then(res => res.json())
-     .then((data: Genre[]) => setGenres(data))
-     .catch(console.error);
+     .then((data: Genre[]) => {
+       setGenres(data);
+       setError(null);
+     })
+     .catch((err) => {
+       console.error(err);
+       setError('장르 정보를 불러오는데 실패했습니다.');
+     })
+     .finally(() => setLoading(false));
  }, []);
📝 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
useEffect(() => {
fetch('/genres.json')
.then(res => res.json())
.then((data: Genre[]) => setGenres(data))
.catch(console.error);
}, []);
const SignupGenre = () => {
const [genres, setGenres] = useState<Genre[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [selectedId, setSelectedId] = useState<string | null>(null);
const navigate = useNavigate();
useEffect(() => {
setLoading(true);
fetch('/genres.json')
.then(res => res.json())
.then((data: Genre[]) => {
setGenres(data);
setError(null);
})
.catch((err) => {
console.error(err);
setError('장르 정보를 불러오는데 실패했습니다.');
})
.finally(() => setLoading(false));
}, []);
// ...rest of the component
}
🤖 Prompt for AI Agents
In src/pages/signup/SignupGenre.tsx around lines 20 to 25, improve error
handling by replacing the simple console.error with state management to capture
and display errors to the user. Additionally, add a loading state that is set to
true before the fetch call and false after data is loaded or an error occurs, so
the UI can reflect the loading status and enhance user experience.

🛠️ Refactor suggestion

에러 처리와 로딩 상태를 개선해야 합니다.

현재 데이터 페칭 로직에 충분한 에러 처리와 로딩 상태 관리가 부족합니다.

다음과 같이 개선을 제안합니다:

+const [loading, setLoading] = useState(true);
+const [error, setError] = useState<string | null>(null);

useEffect(() => {
+  setLoading(true);
  fetch('/genres.json')
    .then(res => {
+      if (!res.ok) throw new Error('데이터를 불러올 수 없습니다');
      return res.json();
    })
-    .then((data: Genre[]) => setGenres(data))
-    .catch(console.error);
+    .then((data: Genre[]) => {
+      if (!Array.isArray(data)) throw new Error('잘못된 데이터 형식입니다');
+      setGenres(data);
+      setError(null);
+    })
+    .catch(err => {
+      console.error(err);
+      setError(err.message);
+    })
+    .finally(() => setLoading(false));
}, []);
📝 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
useEffect(() => {
fetch('/genres.json')
.then(res => res.json())
.then((data: Genre[]) => setGenres(data))
.catch(console.error);
}, []);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
setLoading(true);
fetch('/genres.json')
.then(res => {
if (!res.ok) throw new Error('데이터를 불러올 수 없습니다');
return res.json();
})
.then((data: Genre[]) => {
if (!Array.isArray(data)) throw new Error('잘못된 데이터 형식입니다');
setGenres(data);
setError(null);
})
.catch(err => {
console.error(err);
setError(err.message);
})
.finally(() => setLoading(false));
}, []);
🤖 Prompt for AI Agents
In src/pages/signup/SignupGenre.tsx around lines 20 to 25, the current useEffect
fetch logic lacks proper error handling and loading state management. Introduce
a loading state variable to track the fetch status and update it accordingly
before and after the fetch. Enhance error handling by setting an error state
when the fetch fails and display appropriate feedback to the user. This will
improve user experience by clearly indicating loading progress and any errors
encountered.

Copy link
Copy Markdown
Member

@Nico1eKim Nico1eKim left a comment

Choose a reason for hiding this comment

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

잘 구경하고 갑니다 ~ 극악무도한 css 정말 오랜만이고 .. 이렇게 보니 안드가 선녀같네요 .. 좋댓구 합니다 ~

Comment thread src/pages/login/Login.tsx
display: flex;
flex-direction: column;
position: absolute;
bottom: 129.75px;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

아 michin ㅋㅋㅋ 안드는 이런거 그냥 냅다 4배수로 때려박기로했는데 웹은 그렇게 하면 좀 그런가요 ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

4배수로 때린다는게 그냥 나눠떨어지게 버림한단뜻인가여

Comment thread src/pages/login/Login.tsx Outdated
Comment on lines +65 to +68
<SocialButton onClick={handleKakaoLogin} bg="#fee500">
<img src={KaKao} /> 카카오계정 로그인
</SocialButton>
<SocialButton bg="#fefefe">
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

컬러변수 공통으로 안뺐나여 ? (시비거는거 아님)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 빼야죠... 아마 안드처럼 폰트사이즈랑 다 묶어서 한번에 해야할듯?

font-style: normal;
font-weight: 600;
line-height: 24px;
letter-spacing: 0.018px;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

진챠 극악무도하다

Comment on lines +164 to +165
/* background: linear-gradient(0deg, rgba(18, 18, 18, 0.3) 0%, rgba(18, 18, 18, 0.3) 100%);
background-color: lightgray; */
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

아미친 진짜 극악무도하다 .. ㅋㅎㅋㅎㅋ ㅠㅠㅠ 엉엉

Copy link
Copy Markdown
Collaborator Author

@heeeeyong heeeeyong Jun 27, 2025

Choose a reason for hiding this comment

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

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ이거 피그마랑 똑같이 안돼요ㅠㅠㅠㅠㅠ

Copy link
Copy Markdown
Collaborator Author

@heeeeyong heeeeyong left a comment

Choose a reason for hiding this comment

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

@coderabbitai review

@heeeeyong
Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 27, 2025

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@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: 0

♻️ Duplicate comments (6)
src/pages/login/Login.tsx (3)

63-63: 이미지에 alt 속성을 추가하세요.

로고 이미지에 alt 속성이 누락되어 있어 스크린 리더 사용자에게 접근성 문제가 발생할 수 있습니다.

-      <img src={logo} />
+      <img src={logo} alt="THIP 로고" />

53-59: 빈 핸들러 함수들에 TODO 주석을 추가하거나 실제 구현을 제공하세요.

현재 로그인 핸들러들이 빈 구현으로 되어 있어 실제 기능이 동작하지 않습니다.

  const handleKakaoLogin = () => {
-    return;
+    // TODO: 카카오 로그인 API 연동 구현
+    console.log('카카오 로그인 시도');
  };

  const handleGoogleLogin = () => {
-    return;
+    // TODO: 구글 로그인 API 연동 구현
+    console.log('구글 로그인 시도');
  };

66-69: 소셜 로그인 버튼 이미지에 alt 속성을 추가하세요.

접근성 향상을 위해 소셜 로그인 버튼 이미지들에도 적절한 alt 텍스트를 제공해야 합니다.

-          <img src={KaKao} /> 카카오계정 로그인
+          <img src={KaKao} alt="카카오 로고" /> 카카오계정 로그인
-          <img src={Google} /> 구글계정 로그인
+          <img src={Google} alt="구글 로고" /> 구글계정 로그인
src/pages/signup/SignupNickname.tsx (1)

23-26: 한글 입력 검증 로직을 개선하세요.

현재 정규식이 한글 단일 자음(ㄱ-ㅎ)을 허용하고 있는데, PR 목표에서 언급하신 것처럼 단일 자음 입력을 방지하려면 더 정교한 검증이 필요합니다.

완성된 한글 음절만 허용하는 검증 로직을 제안합니다:

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const inputValue = e.target.value;
-    const filteredValue = inputValue.replace(/[^ㄱ-ㅎ가-힣a-zA-Z0-9]/g, '');
+    // 완성된 한글 음절, 영어, 숫자만 허용 (단일 자음/모음 제외)
+    const filteredValue = inputValue.replace(/[^가-힣a-zA-Z0-9]/g, '');
    setNickname(filteredValue);
  };
src/pages/signup/SignupDone.tsx (1)

20-21: 하드코딩된 사용자 데이터를 동적으로 처리해야 합니다.

사용자 이름과 역할이 하드코딩되어 있어 실제 회원가입 과정에서 입력된 정보가 반영되지 않습니다. 이전 단계에서 전달받은 사용자 정보를 사용해야 합니다.

Also applies to: 27-28

src/pages/signup/SignupGenre.tsx (1)

20-25: 에러 처리와 로딩 상태 관리를 개선해야 합니다.

현재 기본적인 console.error만 사용하고 있어 사용자에게 적절한 피드백을 제공하지 못합니다. 로딩 상태도 관리되지 않아 사용자 경험이 저하될 수 있습니다.

🧹 Nitpick comments (6)
src/pages/signup/SignupDone.tsx (1)

25-25: 프로필 이미지에 대체 텍스트를 추가하세요.

접근성 향상을 위해 img 태그에 alt 속성이 필요합니다.

-            <img src={art} />
+            <img src={art} alt="프로필 이미지" />
src/pages/signup/SignupGenre.tsx (1)

50-66: 장르 카드 렌더링과 선택 로직을 개선하세요.

동적 장르 데이터 렌더링이 잘 구현되었지만, 키보드 접근성을 위한 개선이 필요합니다.

            <div
              key={g.id}
              className={`genreCard ${g.id === selectedId ? 'active' : ''}`}
              onClick={() => setSelectedId(g.id)}
+             onKeyDown={(e) => {
+               if (e.key === 'Enter' || e.key === ' ') {
+                 e.preventDefault();
+                 setSelectedId(g.id);
+               }
+             }}
+             tabIndex={0}
+             role="button"
+             aria-pressed={g.id === selectedId}
            >
src/pages/signup/Signup.styled.ts (2)

163-164: 주석 처리된 그라데이션 CSS를 정리하세요.

PR 목표에서 언급하신 Figma 디자인 구현의 어려움과 관련된 부분으로 보입니다. 사용하지 않는다면 주석을 제거하거나, 필요하다면 대안을 구현해보세요.

다음과 같은 대안을 고려해보세요:

      &.active {
        border: 1px solid #fefefe;
-       /* background: linear-gradient(0deg, rgba(18, 18, 18, 0.3) 0%, rgba(18, 18, 18, 0.3) 100%);
-       background-color: lightgray; */
+       background: rgba(254, 254, 254, 0.05);
        .genreTitle {
          color: #fefefe;
        }

106-173: 장르 그리드 스타일에서 매직 넘버를 상수로 추출하세요.

반복되는 크기 값들을 상수로 관리하면 유지보수성이 향상됩니다.

+const GENRE_CARD = {
+  MIN_WIDTH: 130,
+  MAX_WIDTH: 180,
+  HEIGHT: 100,
+  ICON_SIZE: { width: 80, height: 70 }
+} as const;

    .genreCard {
-     height: 100px;
-     min-width: 130px;
-     max-width: 180px;
+     height: ${GENRE_CARD.HEIGHT}px;
+     min-width: ${GENRE_CARD.MIN_WIDTH}px;
+     max-width: ${GENRE_CARD.MAX_WIDTH}px;
src/pages/signup/Header.tsx (2)

64-71: HeaderProps 인터페이스 개선을 제안합니다.

타입 정의가 개선되었지만 props에 대한 설명을 추가하면 더 좋겠습니다.

type HeaderProps = {
+  /** 헤더 제목 (선택적) */
  title?: string;
+  /** 왼쪽 아이콘 요소 */
  leftIcon?: React.ReactNode;
+  /** 오른쪽 버튼 요소 */
  rightButton?: React.ReactNode;
+  /** 다음 버튼 활성화 상태 */
  isNextActive?: boolean;
+  /** 왼쪽 클릭 핸들러 */
  onLeftClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
+  /** 오른쪽 클릭 핸들러 */
  onRightClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
};

87-93: NextButton 접근성을 개선하세요.

키보드 네비게이션과 스크린 리더 지원을 위한 속성을 추가해보세요.

      {rightButton ? (
-       <NextButton onClick={onRightClick} active={isNextActive}>
+       <NextButton 
+         onClick={onRightClick} 
+         active={isNextActive}
+         role="button"
+         tabIndex={isNextActive ? 0 : -1}
+         onKeyDown={(e) => {
+           if ((e.key === 'Enter' || e.key === ' ') && isNextActive) {
+             e.preventDefault();
+             onRightClick?.(e as any);
+           }
+         }}
+       >
          {rightButton}
        </NextButton>
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3b1212b and 9982300.

⛔ Files ignored due to path filters (21)
  • public/assets/genre/art.svg is excluded by !**/*.svg
  • public/assets/genre/humanity.svg is excluded by !**/*.svg
  • public/assets/genre/literature.svg is excluded by !**/*.svg
  • public/assets/genre/science.svg is excluded by !**/*.svg
  • public/assets/genre/socialScience.svg is excluded by !**/*.svg
  • src/assets/genre/art.svg is excluded by !**/*.svg
  • src/assets/genre/humanity.svg is excluded by !**/*.svg
  • src/assets/genre/literature.svg is excluded by !**/*.svg
  • src/assets/genre/science.svg is excluded by !**/*.svg
  • src/assets/genre/socialScience.svg is excluded by !**/*.svg
  • src/assets/login/google.svg is excluded by !**/*.svg
  • src/assets/login/kakao.svg is excluded by !**/*.svg
  • src/assets/login/logo.svg is excluded by !**/*.svg
  • src/assets/navbar/feed-active.svg is excluded by !**/*.svg
  • src/assets/navbar/feed.svg is excluded by !**/*.svg
  • src/assets/navbar/group-active.svg is excluded by !**/*.svg
  • src/assets/navbar/group.svg is excluded by !**/*.svg
  • src/assets/navbar/my-active.svg is excluded by !**/*.svg
  • src/assets/navbar/my.svg is excluded by !**/*.svg
  • src/assets/navbar/search-active.svg is excluded by !**/*.svg
  • src/assets/navbar/search.svg is excluded by !**/*.svg
📒 Files selected for processing (9)
  • public/genres.json (1 hunks)
  • src/components/NavBar.tsx (1 hunks)
  • src/pages/index.tsx (1 hunks)
  • src/pages/login/Login.tsx (1 hunks)
  • src/pages/signup/Header.tsx (4 hunks)
  • src/pages/signup/Signup.styled.ts (2 hunks)
  • src/pages/signup/SignupDone.tsx (1 hunks)
  • src/pages/signup/SignupGenre.tsx (2 hunks)
  • src/pages/signup/SignupNickname.tsx (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/pages/signup/SignupDone.tsx (1)
src/pages/signup/Signup.styled.ts (1)
  • Container (3-174)
src/pages/signup/SignupGenre.tsx (1)
src/pages/signup/Signup.styled.ts (1)
  • Container (3-174)
🔇 Additional comments (10)
public/genres.json (1)

1-37: 장르 데이터 구조가 잘 정의되어 있습니다.

JSON 구조가 일관되고 명확하며, 각 장르별로 필요한 모든 속성(id, title, subTitle, iconUrl, color)이 포함되어 있습니다. 색상 코드도 올바른 hex 형식으로 정의되어 있어 좋습니다.

src/components/NavBar.tsx (1)

1-89: 네비게이션 바 구현이 잘 되어 있습니다.

React Router hooks를 올바르게 사용하여 현재 경로를 감지하고 네비게이션을 처리하고 있습니다. 타입 정의가 명확하고, 접근성을 위한 alt 속성도 포함되어 있어 좋습니다. 반응형 디자인을 고려한 스타일링도 적절합니다.

src/pages/index.tsx (1)

7-7: 라우팅 구조가 적절하게 설정되었습니다.

새로운 Login 컴포넌트를 루트 경로로 설정하고, SignupDone 컴포넌트를 별도 경로로 분리한 것이 사용자 흐름에 맞는 좋은 구조입니다.

Also applies to: 11-11, 17-17, 22-22

src/pages/signup/SignupNickname.tsx (1)

35-35: Header 컴포넌트와의 연동이 잘 구현되었습니다.

isNextActive prop을 통해 버튼 상태를 적절히 제어하고 있어 사용자 경험이 개선되었습니다.

src/pages/signup/SignupDone.tsx (1)

8-15: 네비게이션 로직이 올바르게 구현되었습니다.

뒤로가기와 피드 페이지로의 이동이 적절하게 처리되었습니다.

src/pages/signup/SignupGenre.tsx (2)

7-13: 장르 인터페이스가 잘 정의되었습니다.

타입 안전성을 위한 Genre 인터페이스가 적절하게 정의되어 API 응답 구조와 일치합니다.


32-34: 조건부 네비게이션이 올바르게 구현되었습니다.

선택된 장르가 있을 때만 다음 단계로 진행하도록 하는 로직이 사용자 경험을 향상시킵니다.

src/pages/signup/Signup.styled.ts (2)

8-8: 컨테이너 최대 너비 조정이 일관성을 개선합니다.

다른 컴포넌트들과 일치하도록 최대 너비를 767px로 조정한 것이 좋습니다.


37-104: 사용자 정보 및 버튼 스타일링이 잘 구성되었습니다.

SignupDone 컴포넌트를 위한 스타일이 일관된 디자인 시스템을 따르고 있습니다.

src/pages/signup/Header.tsx (1)

38-53: 조건부 스타일링을 가진 NextButton 컴포넌트가 잘 구현되었습니다.

활성 상태에 따른 시각적 피드백과 상호작용이 사용자 경험을 크게 개선합니다.

@heeeeyong heeeeyong added ✨ Feature 기능 개발 🎨 Html&css 마크업 & 스타일링 labels Jun 29, 2025
Copy link
Copy Markdown
Collaborator

@ho0010 ho0010 left a comment

Choose a reason for hiding this comment

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

고생많으셨습니다!

  • 피그마
image
  • 개발
image

헤더 텍스트가 정 가운데가 아니라서 수정이 필요할 것 같아요!

@ho0010
Copy link
Copy Markdown
Collaborator

ho0010 commented Jun 30, 2025

  1. 닉네임 유효성 검증을 당연히 서버로 요청을 보내서 하겠지만, 프론트단에서도 처리를 해야할 것 같아서 로직을 짜놓기는 했는데 한글 단자음을 작성하는 경우에도 허용이 되는데 이걸 어떻게 처리하면 좋을까요? composing하는 로직을 추가하면 되는걸까요?
    우선 FE에서는 허용되는걸로 유지해도 괜찮다고 생각합니다. 기획 측면에서 요구사항처럼 제시하지 않는다면요!

  2. 설정2 화면에서 css를 figma랑 똑같이 구현하기가 힘든데 (linear-gradient 속성 등) 어떻게하면 좋을까요?
    우선 가능한 유사하게 작업하고 화면 로직이 구현되면 컨펌받는식으로 가는게 좋아보입니다!

@ho0010
Copy link
Copy Markdown
Collaborator

ho0010 commented Jun 30, 2025

styled 파일로 분리한거랑 안한거랑 기준이 있을까요?

@heeeeyong
Copy link
Copy Markdown
Collaborator Author

@ho0010
안그래도 헤더는 어제 늦게발견해서 오늘 수정하려고 했습니당...ㅎ
css 코드가 길어지거나 재사용할 것 같은 애들을 styled파일로 분리한 상태인데, 혹시 분리할지말지 결정하는 더 좋은 기준이 있을까요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발 🎨 Html&css 마크업 & 스타일링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[UI] 네비게이션 바 [UI] 로그인, 회원가입 화면

3 participants