feat: Signup pages#19
Conversation
|
""" Walkthrough로그인, 회원가입, 온보딩 UI를 위한 주요 컴포넌트와 스타일이 추가 및 수정되었습니다. 새로운 장르 데이터 JSON 파일이 도입되었고, 각 단계별 회원가입 페이지와 로그인 페이지가 구현되었습니다. 라우팅 설정이 업데이트되어 신규 페이지 진입점이 추가되었습니다. Changes
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로 이동
Assessment against linked issues
Assessment against linked issues: Out-of-scope changes(해당 변경사항 내에서는 이슈 목표와 직접적으로 관련 없는 기능적 코드 변경이 발견되지 않았습니다.) Suggested labels
Poem
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
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 코드를 제거하세요.더 이상 사용하지 않는 주석 처리된
.nextCSS 클래스 코드를 정리하는 것이 좋겠습니다.- /* - .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
⛔ Files ignored due to path filters (13)
public/assets/genre/art.svgis excluded by!**/*.svgpublic/assets/genre/humanity.svgis excluded by!**/*.svgpublic/assets/genre/literature.svgis excluded by!**/*.svgpublic/assets/genre/science.svgis excluded by!**/*.svgpublic/assets/genre/socialScience.svgis excluded by!**/*.svgsrc/assets/genre/art.svgis excluded by!**/*.svgsrc/assets/genre/humanity.svgis excluded by!**/*.svgsrc/assets/genre/literature.svgis excluded by!**/*.svgsrc/assets/genre/science.svgis excluded by!**/*.svgsrc/assets/genre/socialScience.svgis excluded by!**/*.svgsrc/assets/login/google.svgis excluded by!**/*.svgsrc/assets/login/kakao.svgis excluded by!**/*.svgsrc/assets/login/logo.svgis 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 donesrc/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 -->
|
|
||
| return ( | ||
| <Wrapper> | ||
| <img src={logo} /> |
There was a problem hiding this comment.
🛠️ 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.
| <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.
| const handleKakaoLogin = () => { | ||
| return; | ||
| }; | ||
|
|
||
| const handleGoogleLogin = () => { | ||
| return; | ||
| }; |
There was a problem hiding this comment.
🛠️ 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.
| 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.
| const inputValue = e.target.value; | ||
| const filteredValue = inputValue.replace(/[^ㄱ-ㅎ가-힣a-zA-Z0-9]/g, ''); | ||
| setNickname(filteredValue); | ||
| }; |
There was a problem hiding this comment.
🛠️ 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.
| <div className="username">희용희용</div> | ||
| <div className="subname">예술가</div> |
There was a problem hiding this comment.
🛠️ 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.
| <div className="title">안녕하세요, 희용희용님</div> | ||
| <div className="subtitle">이제 Thip에서 활동할 준비를 모두 마쳤어요!</div> |
There was a problem hiding this comment.
🛠️ 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.
| useEffect(() => { | ||
| fetch('/genres.json') | ||
| .then(res => res.json()) | ||
| .then((data: Genre[]) => setGenres(data)) | ||
| .catch(console.error); | ||
| }, []); |
There was a problem hiding this comment.
🛠️ 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.
| 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.
| 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.
Nico1eKim
left a comment
There was a problem hiding this comment.
잘 구경하고 갑니다 ~ 극악무도한 css 정말 오랜만이고 .. 이렇게 보니 안드가 선녀같네요 .. 좋댓구 합니다 ~
| display: flex; | ||
| flex-direction: column; | ||
| position: absolute; | ||
| bottom: 129.75px; |
There was a problem hiding this comment.
아 michin ㅋㅋㅋ 안드는 이런거 그냥 냅다 4배수로 때려박기로했는데 웹은 그렇게 하면 좀 그런가요 ?
There was a problem hiding this comment.
4배수로 때린다는게 그냥 나눠떨어지게 버림한단뜻인가여
| <SocialButton onClick={handleKakaoLogin} bg="#fee500"> | ||
| <img src={KaKao} /> 카카오계정 로그인 | ||
| </SocialButton> | ||
| <SocialButton bg="#fefefe"> |
There was a problem hiding this comment.
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 빼야죠... 아마 안드처럼 폰트사이즈랑 다 묶어서 한번에 해야할듯?
| font-style: normal; | ||
| font-weight: 600; | ||
| line-height: 24px; | ||
| letter-spacing: 0.018px; |
| /* background: linear-gradient(0deg, rgba(18, 18, 18, 0.3) 0%, rgba(18, 18, 18, 0.3) 100%); | ||
| background-color: lightgray; */ |
There was a problem hiding this comment.
아미친 진짜 극악무도하다 .. ㅋㅎㅋㅎㅋ ㅠㅠㅠ 엉엉
There was a problem hiding this comment.
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ이거 피그마랑 똑같이 안돼요ㅠㅠㅠㅠㅠ
heeeeyong
left a comment
There was a problem hiding this comment.
@coderabbitai review
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (21)
public/assets/genre/art.svgis excluded by!**/*.svgpublic/assets/genre/humanity.svgis excluded by!**/*.svgpublic/assets/genre/literature.svgis excluded by!**/*.svgpublic/assets/genre/science.svgis excluded by!**/*.svgpublic/assets/genre/socialScience.svgis excluded by!**/*.svgsrc/assets/genre/art.svgis excluded by!**/*.svgsrc/assets/genre/humanity.svgis excluded by!**/*.svgsrc/assets/genre/literature.svgis excluded by!**/*.svgsrc/assets/genre/science.svgis excluded by!**/*.svgsrc/assets/genre/socialScience.svgis excluded by!**/*.svgsrc/assets/login/google.svgis excluded by!**/*.svgsrc/assets/login/kakao.svgis excluded by!**/*.svgsrc/assets/login/logo.svgis excluded by!**/*.svgsrc/assets/navbar/feed-active.svgis excluded by!**/*.svgsrc/assets/navbar/feed.svgis excluded by!**/*.svgsrc/assets/navbar/group-active.svgis excluded by!**/*.svgsrc/assets/navbar/group.svgis excluded by!**/*.svgsrc/assets/navbar/my-active.svgis excluded by!**/*.svgsrc/assets/navbar/my.svgis excluded by!**/*.svgsrc/assets/navbar/search-active.svgis excluded by!**/*.svgsrc/assets/navbar/search.svgis 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 컴포넌트가 잘 구현되었습니다.활성 상태에 따른 시각적 피드백과 상호작용이 사용자 경험을 크게 개선합니다.
|
|
styled 파일로 분리한거랑 안한거랑 기준이 있을까요? |
|
@ho0010 |


#️⃣연관된 이슈
📝작업 내용 & 스크린샷
이전 PR 작업내용까지 합쳐서 올립니당~
- 설정1 (닉네임)
-설정2 (칭호)
- 회원가입 완료 화면
- 네비바 구현
💬리뷰 요구사항(선택)
닉네임 유효성 검증을 당연히 서버로 요청을 보내서 하겠지만, 프론트단에서도 처리를 해야할 것 같아서 로직을 짜놓기는 했는데 한글 단자음을 작성하는 경우에도 허용이 되는데 이걸 어떻게 처리하면 좋을까요? composing하는 로직을 추가하면 되는걸까요?
설정2 화면에서 css를 figma랑 똑같이 구현하기가 힘든데 (linear-gradient 속성 등) 어떻게하면 좋을까요?
기타
현재 설정2 화면과 회원가입 완료화면 사이에 튜토리얼 슬라이드를 띄워야하는데 해당부분이 아직 만들어지지 않아서 나중에 만들어야할듯 합니다.
유저 칭호마다 다른 색을 가져와야하는데 이걸 서버에서 매번 가져오는게 맞을지... 좋은방법이 없을까 고민이 되네요...
오늘 저녁에 네비바 만들 예정입니다.
반응형으로 구현을 하긴 했는데 이 부분 설정도 전역으로 해야할듯합니다..
Summary by CodeRabbit
Summary by CodeRabbit
New Features
버그 수정 및 개선
스타일