Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ์ฝ”๋“œ๋ฆฌ๋ทฐ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ #123

Open
wants to merge 253 commits into
base: init
Choose a base branch
from

Conversation

seoyoonyi
Copy link
Contributor

@seoyoonyi seoyoonyi commented Sep 9, 2024

๐Ÿ”ฅ์ฝ”๋“œ๋ฆฌ๋ทฐ ์ž˜๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค๐Ÿ”ฅ

Sourcery์— ์˜ํ•œ ์š”์•ฝ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํฌ๊ด„์ ์ธ ๊ฐœํŽธ์„ ๊ตฌํ˜„ํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ธ์ฆ, ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ๊ด€๋ฆฌ ๋ฐ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ๊ณผ ๊ฐ™์€ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์‹  React ๋ฐ TypeScript ๊ด€ํ–‰์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ๋ฆฌํŒฉํ„ฐ๋งํ•˜๊ณ , ๋นŒ๋“œ ๋ฐ CI ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ฐœ์„ ํ•˜๋ฉฐ, Firebase Hosting์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐํฌ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ:

  • react-router-dom์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž…, ํ™ˆ, ํ”„๋กœํ•„, ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ ๋“ฑ์„ ์œ„ํ•œ ๊ฒฝ๋กœ๋ฅผ ํฌํ•จํ•˜๋Š” ์ƒˆ๋กœ์šด ๋ผ์šฐํŒ… ์‹œ์Šคํ…œ์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.
  • YouTube ๋งํฌ์™€ ํƒœ๊ทธ๋กœ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” CreatePlaylistPage ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž ์ •๋ณด์™€ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ๋ฅผ ํ‘œ์‹œํ•˜๊ณ  ํŒ”๋กœ์šฐ/์–ธํŒ”๋กœ์šฐ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ ProfilePage ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋ฉ”์ผ/๋น„๋ฐ€๋ฒˆํ˜ธ ๋ฐ Google ๋กœ๊ทธ์ธ ์˜ต์…˜์„ ์‚ฌ์šฉํ•œ ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์œ„ํ•œ LoginPage ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.
  • ํƒœ๊ทธ๋กœ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์ถ”์ฒœ ํ‚ค์›Œ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” SearchPage ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ํ‘œ์‹œํ•˜๊ณ  ๋น„๋””์˜ค ์„ ํƒ ๋ฐ ๋Œ“๊ธ€์„ ํ—ˆ์šฉํ•˜๋Š” PlaylistPage ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐœ๋ฐœ ์ค‘์ธ ๊ธฐ๋Šฅ์„ ๋‚˜ํƒ€๋‚ด๋Š” ChatPage ์ปดํฌ๋„ŒํŠธ ํ”Œ๋ ˆ์ด์Šคํ™€๋”๋ฅผ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ์ข‹์•„์š”๋ฅผ ๋ˆ„๋ฅผ ์ˆ˜ ์žˆ๋Š” LikeButton ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‹ค์–‘ํ•œ ์„น์…˜ ๊ฐ„ ํƒ์ƒ‰์„ ์œ„ํ•œ Navbar ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „๋ฐ˜์— ๊ฑธ์ณ ์ผ๊ด€๋œ ์Šคํƒ€์ผ๋ง์„ ์œ„ํ•œ Emotion์„ ์‚ฌ์šฉํ•œ ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ๋ง ์‹œ์Šคํ…œ์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ์„  ์‚ฌํ•ญ:

  • ๊ฒฝ๋กœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ RouterProvider๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก App ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌํŒฉํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค.
  • ์—„๊ฒฉํ•œ ํƒ€์ž… ๊ฒ€์‚ฌ ๋ฐ ์ตœ์‹  JavaScript ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๋„๋ก TypeScript ๊ตฌ์„ฑ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
  • ๋” ๋‚˜์€ ์ฝ”๋“œ ํ’ˆ์งˆ์„ ์œ„ํ•œ ์ถ”๊ฐ€ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ฐ ๊ทœ์น™์„ ํฌํ•จํ•˜๋„๋ก ESLint ๊ตฌ์„ฑ์„ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ—ค๋” ๋ฐ ํƒ์ƒ‰์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ RootLayout ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ์ƒˆ๋กœ์šด ๋ ˆ์ด์•„์›ƒ ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž ID ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐ ์ธ์ฆ ํ™•์ธ์„ ํฌํ•จํ•œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋นŒ๋“œ:

  • ๋” ๊น”๋”ํ•œ ์ž„ํฌํŠธ๋ฅผ ์œ„ํ•œ ๊ฒฝ๋กœ ๋ณ„์นญ์„ ํฌํ•จํ•˜๋„๋ก Vite ๊ตฌ์„ฑ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
  • ์ตœ์‹  JavaScript ๊ธฐ๋Šฅ ๋ฐ ์—„๊ฒฉํ•œ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ์ง€์›ํ•˜๋„๋ก tsconfig.json์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

CI:

  • ๋ฉ”์ธ ๋ธŒ๋žœ์น˜๋กœ์˜ ํ’€ ๋ฆฌํ€˜์ŠคํŠธ ๋ณ‘ํ•ฉ ์‹œ ์ž๋™ ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ ์ƒˆ๋กœ์šด GitHub Actions ์›Œํฌํ”Œ๋กœ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • ๋งค ํ‘ธ์‹œ๋งˆ๋‹ค๊ฐ€ ์•„๋‹Œ ์ˆ˜๋™ ๋””์ŠคํŒจ์น˜ ์‹œ ํŠธ๋ฆฌ๊ฑฐ๋˜๋„๋ก SonarQube CI ์›Œํฌํ”Œ๋กœ๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

๋ฐฐํฌ:

  • Firebase ๋ฐ YouTube API ํ‚ค์— ๋Œ€ํ•œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ํฌํ•จํ•˜์—ฌ ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ Firebase Hosting์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์„œํ™”:

  • ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ ์ด๋ฆ„์„ ๋ฐ˜์˜ํ•˜๊ณ  ์˜ค๋ž˜๋œ ์„ค์ • ์ง€์นจ์„ ์ œ๊ฑฐํ•˜๋„๋ก README.md๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ:

  • ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ, ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ๋ฐ ์ธ์ฆ ๊ธฐ๋Šฅ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•œ ์ƒˆ๋กœ์šด ํ…Œ์ŠคํŠธ ์ปดํฌ๋„ŒํŠธ ๋ฐ ํ›…์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์žก์ผ:

  • ์˜ค๋ž˜๋œ CSS ํŒŒ์ผ ๋ฐ ์˜ค๋ž˜๋œ GitHub ์›Œํฌํ”Œ๋กœ๋ฅผ ํฌํ•จํ•œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ ๋ฐ ๊ตฌ์„ฑ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
Original summary in English

Summary by Sourcery

Implement a comprehensive overhaul of the application, introducing new features such as user authentication, playlist management, and search functionality. Refactor the codebase to use modern React and TypeScript practices, enhance the build and CI processes, and set up deployment with Firebase Hosting.

New Features:

  • Introduce a new routing system using react-router-dom, including routes for login, signup, home, profile, playlist creation, and more.
  • Add a CreatePlaylistPage component allowing users to create playlists with YouTube links and tags.
  • Implement a ProfilePage component to display user information and playlists, with follow/unfollow functionality.
  • Introduce a LoginPage component for user authentication with email/password and Google login options.
  • Add a SearchPage component for searching playlists by tags, with recommended keywords.
  • Implement a PlaylistPage component to display playlist details and allow video selection and comments.
  • Introduce a ChatPage component placeholder indicating a feature under development.
  • Add a LikeButton component to allow users to like playlists.
  • Implement a Navbar component for navigation between different sections of the application.
  • Introduce a global styling system using Emotion for consistent styling across the application.

Enhancements:

  • Refactor the App component to use a RouterProvider for managing routes.
  • Update the TypeScript configuration to enable strict type checking and modern JavaScript features.
  • Enhance ESLint configuration to include additional plugins and rules for better code quality.
  • Implement a new layout system with a RootLayout component to manage headers and navigation.
  • Add utility functions for user data management, including fetching user IDs and authentication checks.

Build:

  • Update the Vite configuration to include path aliases for cleaner imports.
  • Modify the tsconfig.json to support modern JavaScript features and strict type checking.

CI:

  • Add a new GitHub Actions workflow for automatic deployment on pull request merges to the main branch.
  • Modify the SonarQube CI workflow to trigger on manual dispatch instead of every push.

Deployment:

  • Configure Firebase Hosting for deployment, including environment variables for Firebase and YouTube API keys.

Documentation:

  • Update the README.md to reflect the new project name and remove outdated setup instructions.

Tests:

  • Add new test components and hooks to ensure the functionality of playlist creation, user profiles, and authentication.

Chores:

  • Remove unused files and configurations, including old CSS files and outdated GitHub workflows.

kimpra2989 and others added 30 commits August 21, 2024 13:11
Feat/convention #4 - ๊นƒ๋ชจ์ง€์— ํ—ˆ์Šคํ‚ค ์ ์šฉํ•ด์„œ ์ปค๋ฐ‹์ฒดํฌ
Feat/router #3 ๋ผ์šฐํ„ฐ ์ดˆ๊ธฐ์„ค์ •
โœจ #15 firebase ์ดˆ๊ธฐ์„ค์ •
Feat/layout #9 ํ—ค๋”, ๋„ค๋น„๋ฐ” ์„ค์ •
โœจ #17 ์ ˆ๋Œ€๊ฒฝ๋กœ ์„ค์ •
Copy link

sourcery-ai bot commented Sep 9, 2024

๋ฆฌ๋ทฐ์–ด ๊ฐ€์ด๋“œ by Sourcery

์ด ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋Š” ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ์˜ ๋Œ€๋Œ€์ ์ธ ๊ฐœํŽธ์„ ๊ตฌํ˜„ํ•˜๊ณ  React ๊ธฐ๋ฐ˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์—๋Š” ๋ผ์šฐํŒ… ์„ค์ •, ์ธ์ฆ ํ๋ฆ„ ๊ตฌํ˜„, ๋‹ค์–‘ํ•œ ํŽ˜์ด์ง€ ๋ฐ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ, ๋ฐฑ์—”๋“œ ์„œ๋น„์Šค๋ฅผ ์œ„ํ•œ Firebase ํ†ตํ•ฉ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

ํŒŒ์ผ ์ˆ˜์ค€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ

๋ณ€๊ฒฝ ์‚ฌํ•ญ ์„ธ๋ถ€ ์‚ฌํ•ญ ํŒŒ์ผ
๋ผ์šฐํŒ… ๋ฐ ํŽ˜์ด์ง€ ๊ตฌ์กฐ ๊ตฌํ˜„
  • ๋„ค๋น„๊ฒŒ์ด์…˜์„ ์œ„ํ•œ React Router ์„ค์ •
  • ๋‹ค์–‘ํ•œ ํŽ˜์ด์ง€ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ (LoginPage, ProfilePage, PlaylistPage ๋“ฑ)
  • ์ •์˜๋˜์ง€ ์•Š์€ ๊ฒฝ๋กœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ 404 ํŽ˜์ด์ง€ ๊ตฌํ˜„
src/App.tsx
src/pages/LoginPage.tsx
src/pages/ProfilePage.tsx
src/pages/PlaylistPage.tsx
src/pages/Page404.tsx
Firebase๋ฅผ ํ†ตํ•œ ์ธ์ฆ ๋ฐ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ ํ†ตํ•ฉ
  • Firebase ๊ตฌ์„ฑ ์„ค์ •
  • ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ ๋ฐ ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • Firestore ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•œ ์„œ๋น„์Šค ์ƒ์„ฑ
src/firebase/firebaseConfig.ts
src/service/auth/login.ts
src/service/auth/logout.ts
src/service/auth/googleLogin.ts
์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ UI ๊ตฌ์„ฑ ์š”์†Œ ๊ฐœ๋ฐœ
  • Button ๋ฐ ButtonLink ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ
  • Input ๋ฐ LineInput ๊ตฌ์„ฑ ์š”์†Œ ๊ตฌํ˜„
  • ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ์‚ฌ์ง„์„ ์œ„ํ•œ Avatar ๊ตฌ์„ฑ ์š”์†Œ ๊ฐœ๋ฐœ
src/components/common/Button/Button.tsx
src/components/common/Button/ButtonLink.tsx
src/components/common/Input/Input.tsx
src/components/common/Input/LineInput.tsx
src/components/common/Avatar.tsx
ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์„œ๋น„์Šค ์ƒ์„ฑ
  • ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ํ•ญ๋ชฉ์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ์„ฑ ์š”์†Œ ๊ฐœ๋ฐœ
  • ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ตฌํ˜„
src/service/playlist/getUserPlaylists.ts
src/components/playlist/MusicItem.tsx
src/service/search/searchTag.ts
ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ๋Œ€ํ•œ ๋Œ“๊ธ€ ์‹œ์Šคํ…œ ์ถ”๊ฐ€
  • ๋Œ“๊ธ€ ์ƒ์„ฑ ๋ฐ ์‚ญ์ œ ๊ตฌํ˜„
  • ๋Œ“๊ธ€์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ
  • ๋Œ“๊ธ€์— ๋Œ€ํ•œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์„ค์ •
src/service/comment/createComment.ts
src/service/comment/deleteComment.ts
src/components/comments/Comments.tsx
src/service/comment/getPaginatedCommentsByPlaylistId.ts
๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ ๋ฐ ํ…Œ๋งˆ ์„ค์ •
  • ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ
  • ์ƒ‰์ƒ ๋ฐ ํฐํŠธ ์ƒ์ˆ˜ ์ •์˜
  • ์Šคํƒ€์ผ๋“œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์œ„ํ•œ emotion ๊ตฌํ˜„
src/styles/GlobalStyles.tsx
src/constants/color.ts
src/constants/font.ts
์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ํ”„๋กœํ•„ ํŽ˜์ด์ง€ ์ƒ์„ฑ
  • ํŒ”๋กœ์šฐ/์–ธํŒ”๋กœ์šฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ์‚ฌ์šฉ์ž์˜ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณด๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€
src/pages/ProfilePage.tsx
src/service/profile/followService.ts
src/hooks/useFollowStatus.ts
์ง€์†์  ๋ฐฐํฌ ์„ค์ •
  • PR ์ž๋™ ํ˜ธ์ŠคํŒ…์„ ์œ„ํ•œ GitHub Actions ์›Œํฌํ”Œ๋กœ ์ถ”๊ฐ€
  • ์ˆ˜๋™ ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ ์›Œํฌํ”Œ๋กœ ์ƒ์„ฑ
  • Firebase ํ˜ธ์ŠคํŒ… ๊ตฌ์„ฑ ์„ค์ •
.github/workflows/pr_auto_cd.yml
.github/workflows/click_cd.yml
firebase.json

ํŒ
  • ํ’€ ๋ฆฌํ€˜์ŠคํŠธ์— @sourcery-ai review๋ผ๊ณ  ๋Œ“๊ธ€์„ ๋‹ฌ์•„ ์ƒˆ๋กœ์šด Sourcery ๋ฆฌ๋ทฐ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜์„ธ์š”.
  • ๋ฆฌ๋ทฐ ๋Œ“๊ธ€์— ์ง์ ‘ ๋‹ต๋ณ€ํ•˜์—ฌ Sourcery์™€์˜ ๋…ผ์˜๋ฅผ ๊ณ„์†ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋Œ€์‹œ๋ณด๋“œ์—์„œ ์–ธ์ œ๋“ ์ง€ ๋ฆฌ๋ทฐ ์„ค์ •์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
    • Sourcery๊ฐ€ ์ƒ์„ฑํ•œ ํ’€ ๋ฆฌํ€˜์ŠคํŠธ ์š”์•ฝ ๋˜๋Š” ๋ฆฌ๋ทฐ์–ด ๊ฐ€์ด๋“œ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ฑฐ๋‚˜ ๋น„ํ™œ์„ฑํ™”;
    • ๋ฆฌ๋ทฐ ์–ธ์–ด ๋ณ€๊ฒฝ;
  • ์งˆ๋ฌธ์ด๋‚˜ ํ”ผ๋“œ๋ฐฑ์ด ์žˆ์œผ๋ฉด ์–ธ์ œ๋“ ์ง€ ๋ฌธ์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Original review guide in English

Reviewer's Guide by Sourcery

This pull request implements a significant overhaul of the project structure and introduces new features for a React-based web application. The changes include setting up routing, implementing authentication flows, creating various pages and components, and integrating with Firebase for backend services.

File-Level Changes

Change Details Files
Implemented routing and page structure
  • Set up React Router for navigation
  • Created various page components (LoginPage, ProfilePage, PlaylistPage, etc.)
  • Implemented a 404 page for handling undefined routes
src/App.tsx
src/pages/LoginPage.tsx
src/pages/ProfilePage.tsx
src/pages/PlaylistPage.tsx
src/pages/Page404.tsx
Integrated Firebase for authentication and data storage
  • Set up Firebase configuration
  • Implemented login, logout, and signup functionality
  • Created services for interacting with Firestore database
src/firebase/firebaseConfig.ts
src/service/auth/login.ts
src/service/auth/logout.ts
src/service/auth/googleLogin.ts
Developed reusable UI components
  • Created Button and ButtonLink components
  • Implemented Input and LineInput components
  • Developed Avatar component for user profile pictures
src/components/common/Button/Button.tsx
src/components/common/Button/ButtonLink.tsx
src/components/common/Input/Input.tsx
src/components/common/Input/LineInput.tsx
src/components/common/Avatar.tsx
Implemented playlist functionality
  • Created services for fetching and managing playlists
  • Developed components for displaying playlist items
  • Implemented playlist search functionality
src/service/playlist/getUserPlaylists.ts
src/components/playlist/MusicItem.tsx
src/service/search/searchTag.ts
Added comment system for playlists
  • Implemented comment creation and deletion
  • Created components for displaying comments
  • Set up pagination for comments
src/service/comment/createComment.ts
src/service/comment/deleteComment.ts
src/components/comments/Comments.tsx
src/service/comment/getPaginatedCommentsByPlaylistId.ts
Set up global styles and theme
  • Created a global styles component
  • Defined color and font constants
  • Implemented emotion for styled components
src/styles/GlobalStyles.tsx
src/constants/color.ts
src/constants/font.ts
Implemented user profile functionality
  • Created profile page with user information
  • Implemented follow/unfollow functionality
  • Added ability to view and manage user's playlists
src/pages/ProfilePage.tsx
src/service/profile/followService.ts
src/hooks/useFollowStatus.ts
Set up continuous deployment
  • Added GitHub Actions workflow for PR auto-hosting
  • Created workflow for manual deployment
  • Set up Firebase hosting configuration
.github/workflows/pr_auto_cd.yml
.github/workflows/click_cd.yml
firebase.json

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • Continue your discussion with Sourcery by replying directly to review comments.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

์•ˆ๋…•ํ•˜์„ธ์š” @seoyoonyi - ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฒ€ํ† ํ–ˆ์Šต๋‹ˆ๋‹ค - ๋‹ค์Œ์€ ํ”ผ๋“œ๋ฐฑ์ž…๋‹ˆ๋‹ค:

์ „๋ฐ˜์ ์ธ ์˜๊ฒฌ:

  • ํ”„๋กœ์ ํŠธ๊ฐ€ ์„ฑ์žฅํ•จ์— ๋”ฐ๋ผ ์‹ ๋ขฐ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ์™€ ํ›…์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.
  • ํŠนํžˆ ๋„คํŠธ์›Œํฌ ์š”์ฒญ๊ณผ Firebase ์ž‘์—…์— ๋Œ€ํ•ด ๋” ํฌ๊ด„์ ์ธ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ๋ฐ ๋กœ๊น…์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์œ ์ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ฒ€ํ†  ์ค‘์— ์‚ดํŽด๋ณธ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค
  • ๐ŸŸก ์ผ๋ฐ˜ ๋ฌธ์ œ: 10๊ฐœ์˜ ๋ฌธ์ œ ๋ฐœ๊ฒฌ
  • ๐ŸŸก ๋ณด์•ˆ: 1๊ฐœ์˜ ๋ฌธ์ œ ๋ฐœ๊ฒฌ
  • ๐ŸŸข ํ…Œ์ŠคํŠธ: ๋ชจ๋‘ ์–‘ํ˜ธ
  • ๐ŸŸข ๋ณต์žก์„ฑ: ๋ชจ๋‘ ์–‘ํ˜ธ
  • ๐ŸŸก ๋ฌธ์„œํ™”: 3๊ฐœ์˜ ๋ฌธ์ œ ๋ฐœ๊ฒฌ

Sourcery๋Š” ์˜คํ”ˆ ์†Œ์Šค์— ๋ฌด๋ฃŒ์ž…๋‹ˆ๋‹ค - ๋ฆฌ๋ทฐ๊ฐ€ ๋งˆ์Œ์— ๋“œ์…จ๋‹ค๋ฉด ๊ณต์œ ๋ฅผ ๊ณ ๋ คํ•ด ์ฃผ์„ธ์š” โœจ
๋” ์œ ์šฉํ•˜๊ฒŒ ๋„์™€์ฃผ์„ธ์š”! ๊ฐ ๋Œ“๊ธ€์— ๋Œ€ํ•ด ๐Ÿ‘ ๋˜๋Š” ๐Ÿ‘Ž๋ฅผ ํด๋ฆญํ•˜์—ฌ ๋„์›€์ด ๋˜์—ˆ๋Š”์ง€ ์•Œ๋ ค์ฃผ์„ธ์š”.
Original comment in English

Hey @seoyoonyi - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding unit tests for the new components and hooks to ensure reliability as the project grows.
  • It might be beneficial to implement more comprehensive error handling and logging throughout the application, especially for network requests and Firebase operations.
Here's what I looked at during the review
  • ๐ŸŸก General issues: 10 issues found
  • ๐ŸŸก Security: 1 issue found
  • ๐ŸŸข Testing: all looks good
  • ๐ŸŸข Complexity: all looks good
  • ๐ŸŸก Documentation: 3 issues found

Sourcery is free for open source - if you like our reviews please consider sharing them โœจ
Help me be more useful! Please click ๐Ÿ‘ or ๐Ÿ‘Ž on each comment to tell me if it was helpful.

src/App.tsx Outdated
<p className="read-the-docs">Click on the Vite and React logos to learn more</p>
</>
)
const PrivateRoute = () => {
Copy link

Choose a reason for hiding this comment

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

suggestion: ๋” ๋‚˜์€ ์กฐ์งํ™”๋ฅผ ์œ„ํ•ด PrivateRoute๋ฅผ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฝ”๋“œ ์กฐ์ง์ด ๊ฐœ์„ ๋˜๊ณ  PrivateRoute ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณ„๋„๋กœ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์œ ์ง€ ๊ด€๋ฆฌํ•˜๊ธฐ๊ฐ€ ๋” ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

// src/components/PrivateRoute.tsx
import { Navigate, Outlet } from 'react-router-dom';
import { checkAuth } from '../utils/auth';
import { PATH } from '../constants/paths';

export const PrivateRoute = () => {
  return checkAuth() ? <Outlet /> : <Navigate to={PATH.LOGIN} replace />;
};
Original comment in English

suggestion: Consider moving PrivateRoute to a separate file for better organization

This would improve code organization and make it easier to test and maintain the PrivateRoute component separately.

// src/components/PrivateRoute.tsx
import { Navigate, Outlet } from 'react-router-dom';
import { checkAuth } from '../utils/auth';
import { PATH } from '../constants/paths';

export const PrivateRoute = () => {
  return checkAuth() ? <Outlet /> : <Navigate to={PATH.LOGIN} replace />;
};

import { useNavigate } from 'react-router-dom'
import { getLoggedInUserUID, getUserIdFromUID } from '@/utils/userDataUtils'

const CreatePlaylistPage = () => {
Copy link

Choose a reason for hiding this comment

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

suggestion: ์ด ํฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋” ์ž‘๊ณ  ์ง‘์ค‘๋œ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”

์ด ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ, ํผ ์ฒ˜๋ฆฌ, API ํ˜ธ์ถœ ๋“ฑ ์—ฌ๋Ÿฌ ์ฑ…์ž„์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๋‚˜๋ˆ„๋ฉด ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€ ๊ด€๋ฆฌ๊ฐ€ ๊ฐœ์„ ๋ฉ๋‹ˆ๋‹ค.

import { CreatePlaylistForm } from '@/components/CreatePlaylistForm'
import { PlaylistMetadata } from '@/components/PlaylistMetadata'

const CreatePlaylistPage = () => {
  return (
    <>
      <PlaylistMetadata />
      <CreatePlaylistForm />
    </>
  )
}
Original comment in English

suggestion: Consider breaking down this large component into smaller, more focused components

This component is handling multiple responsibilities including state management, form handling, and API calls. Breaking it down would improve readability and maintainability.

import { CreatePlaylistForm } from '@/components/CreatePlaylistForm'
import { PlaylistMetadata } from '@/components/PlaylistMetadata'

const CreatePlaylistPage = () => {
  return (
    <>
      <PlaylistMetadata />
      <CreatePlaylistForm />
    </>
  )
}

import { BasicVideoProps } from '@/types/playlistType'
import { useState } from 'react'

const usePLItem = () => {
Copy link

Choose a reason for hiding this comment

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

suggestion: ์ด ์ปค์Šคํ…€ ํ›…์˜ ๋ณต์žกํ•œ ๋กœ์ง์„ ์„ค๋ช…ํ•˜๋Š” ์ฃผ์„์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”

์ด ํ›…์˜ ๋กœ์ง์€ ๊ฝค ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํ•จ์ˆ˜์™€ ์ƒํƒœ ๋ณ€์ˆ˜์˜ ๋ชฉ์ ์„ ์„ค๋ช…ํ•˜๋Š” ์ฃผ์„์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€ ๊ด€๋ฆฌ๊ฐ€ ํฌ๊ฒŒ ๊ฐœ์„ ๋ฉ๋‹ˆ๋‹ค.

Original comment in English

suggestion: Add comments explaining the complex logic in this custom hook

The logic in this hook is quite complex. Adding comments to explain the purpose of each function and state variable would greatly improve its readability and maintainability.

import { getLoggedInUserUID } from '@/utils/userDataUtils'
import { addDoc, collection, getDoc, doc } from 'firebase/firestore'

const createNewPlaylist = async (
Copy link

Choose a reason for hiding this comment

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

suggestion: ๋„คํŠธ์›Œํฌ ์‹คํŒจ๋‚˜ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์‘๋‹ต์— ๋Œ€ํ•œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”

ํ˜„์žฌ ํ•จ์ˆ˜๋Š” ์˜ค๋ฅ˜๋ฅผ ์ฝ˜์†”์—๋งŒ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋„คํŠธ์›Œํฌ ์‹คํŒจ๋‚˜ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์„œ๋ฒ„ ์‘๋‹ต์— ๋Œ€ํ•ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

const createNewPlaylist = async (
  title: string,
  tags: string[],
): Promise<string | null> => {
  try {
    // Existing function body...
  } catch (error) {
    console.error('Failed to create playlist:', error);
    throw new Error('Failed to create playlist. Please try again later.');
  }
}
Original comment in English

suggestion: Consider adding error handling for network failures or unexpected responses

The function currently only logs errors to the console. Consider how to handle and communicate errors to the user, especially for network failures or unexpected server responses.

const createNewPlaylist = async (
  title: string,
  tags: string[],
): Promise<string | null> => {
  try {
    // Existing function body...
  } catch (error) {
    console.error('Failed to create playlist:', error);
    throw new Error('Failed to create playlist. Please try again later.');
  }
}

playlistId: string
}

const Comments: React.FC<CommentsProps> = ({ playlistId }) => {
Copy link

Choose a reason for hiding this comment

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

suggestion (performance): ๋Œ“๊ธ€์— ๋Œ€ํ•ด ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋˜๋Š” ๋ฌดํ•œ ์Šคํฌ๋กค์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”

ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ๋งŽ์€ ๋Œ“๊ธ€์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์ด๋ฅผ ํ•œ ๋ฒˆ์— ๋ชจ๋‘ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์€ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋˜๋Š” ๋ฌดํ•œ ์Šคํฌ๋กค์„ ๊ตฌํ˜„ํ•˜๋ฉด ๋งŽ์€ ๋Œ“๊ธ€์ด ์žˆ๋Š” ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์˜ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜๊ณผ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const Comments: React.FC<CommentsProps> = ({ playlistId }) => {
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);
  const { data: comments, fetchNextPage, isFetchingNextPage } = useInfiniteQuery(
    ['comments', playlistId],
    ({ pageParam = 1 }) => fetchComments(playlistId, pageParam),
    {
      getNextPageParam: (lastPage, pages) => lastPage.nextPage,
    }
  );
Original comment in English

suggestion (performance): Consider implementing pagination or infinite scrolling for comments

If a playlist can have many comments, loading them all at once could impact performance. Implementing pagination or infinite scrolling could improve the user experience and performance for playlists with many comments.

const Comments: React.FC<CommentsProps> = ({ playlistId }) => {
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);
  const { data: comments, fetchNextPage, isFetchingNextPage } = useInfiniteQuery(
    ['comments', playlistId],
    ({ pageParam = 1 }) => fetchComments(playlistId, pageParam),
    {
      getNextPageParam: (lastPage, pages) => lastPage.nextPage,
    }
  );

// ํ˜„์žฌ ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ํŒ”๋กœ์šฐํ•œ ์‚ฌ์šฉ์ž๋“ค์˜ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
const getFollowingUsersPlaylists = async () => {
try {
const currentUser = auth.currentUser
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): ์†์„ฑ์„ ์•ก์„ธ์Šคํ•˜๊ณ  ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ์ฒด ๊ตฌ์กฐ ๋ถ„ํ•ด๋ฅผ ์„ ํ˜ธํ•˜์„ธ์š”. (use-object-destructuring)

Suggested change
const currentUser = auth.currentUser
const {currentUser} = auth


Explanation๊ฐ์ฒด ๊ตฌ์กฐ ๋ถ„ํ•ด๋Š” ๋ถˆํ•„์š”ํ•œ ์ž„์‹œ ์ฐธ์กฐ๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฝ”๋“œ๋ฅผ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

Airbnb Javascript Style Guide์—์„œ ๋ฐœ์ทŒ

Original comment in English

suggestion (code-quality): Prefer object destructuring when accessing and using properties. (use-object-destructuring)

Suggested change
const currentUser = auth.currentUser
const {currentUser} = auth


ExplanationObject destructuring can often remove an unnecessary temporary reference, as well as making your code more succinct.

From the Airbnb Javascript Style Guide

throw new Error('User is not logged in')
}

const uid = currentUser.uid
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): ์†์„ฑ์„ ์•ก์„ธ์Šคํ•˜๊ณ  ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ์ฒด ๊ตฌ์กฐ ๋ถ„ํ•ด๋ฅผ ์„ ํ˜ธํ•˜์„ธ์š”. (use-object-destructuring)

Suggested change
const uid = currentUser.uid
const {uid} = currentUser


Explanation๊ฐ์ฒด ๊ตฌ์กฐ ๋ถ„ํ•ด๋Š” ๋ถˆํ•„์š”ํ•œ ์ž„์‹œ ์ฐธ์กฐ๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฝ”๋“œ๋ฅผ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

Airbnb Javascript Style Guide์—์„œ ๋ฐœ์ทŒ

Original comment in English

suggestion (code-quality): Prefer object destructuring when accessing and using properties. (use-object-destructuring)

Suggested change
const uid = currentUser.uid
const {uid} = currentUser


ExplanationObject destructuring can often remove an unnecessary temporary reference, as well as making your code more succinct.

From the Airbnb Javascript Style Guide

Comment on lines 26 to 33
const followingPlaylists = await Promise.all(
followingUserIds.map(async (userId: string) => {
const userPlaylists = await getUserPlaylists(userId)
return { userId, playlists: userPlaylists }
})
)

return followingPlaylists
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋˜๋Š” ๋ณ€์ˆ˜๋ฅผ ์ธ๋ผ์ธํ•˜์„ธ์š” (inline-immediately-returned-variable)

Suggested change
const followingPlaylists = await Promise.all(
followingUserIds.map(async (userId: string) => {
const userPlaylists = await getUserPlaylists(userId)
return { userId, playlists: userPlaylists }
})
)
return followingPlaylists
return await Promise.all(
followingUserIds.map(async (userId: string) => {
const userPlaylists = await getUserPlaylists(userId)
return { userId, playlists: userPlaylists }
})
);


Explanation์‚ฌ๋žŒ๋“ค์˜ ์ฝ”๋“œ์—์„œ ์ž์ฃผ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๊ฒฐ๊ณผ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•œ ํ›„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ๋ฅผ ์ง์ ‘ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋‹จ์ถ•ํ•˜๊ณ  ๋ถˆํ•„์š”ํ•œ ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์ฝ๋Š” ๋ฐ ๋“œ๋Š” ์ •์‹ ์  ๋ถ€๋‹ด์„ ์ค„์ž…๋‹ˆ๋‹ค.

์ค‘๊ฐ„ ๋ณ€์ˆ˜๊ฐ€ ์œ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋‚˜ ์กฐ๊ฑด์œผ๋กœ ์‚ฌ์šฉ๋  ๋•Œ์ด๋ฉฐ, ๋ณ€์ˆ˜ ์ด๋ฆ„์ด ๋ณ€์ˆ˜์˜ ์˜๋ฏธ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์ฃผ์„์ฒ˜๋Ÿผ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ ํ•จ์ˆ˜ ์ด๋ฆ„์ด ๊ฒฐ๊ณผ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ๋ ค์ฃผ๋ฏ€๋กœ ๋ณ€์ˆ˜ ์ด๋ฆ„์ด ๋ถˆํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Original comment in English

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
const followingPlaylists = await Promise.all(
followingUserIds.map(async (userId: string) => {
const userPlaylists = await getUserPlaylists(userId)
return { userId, playlists: userPlaylists }
})
)
return followingPlaylists
return await Promise.all(
followingUserIds.map(async (userId: string) => {
const userPlaylists = await getUserPlaylists(userId)
return { userId, playlists: userPlaylists }
})
);


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

Comment on lines +26 to +58
const videos = await Promise.all(
videoSnapshot.docs.map(async (videoDoc) => {
try {
const videoData = videoDoc.data()
return {
channelTitle: videoData.channelTitle,
title: videoData.title,
thumbnail: videoData.thumbnail,
url: videoData.url,
author: userData?.id,
authorImg: userData?.img,
uploadDate: playlistData.createdAt ? formatDate(playlistData.createdAt) : '',
tags: playlistData.tags,
playlistTitle: playlistData.title,
}
} catch (error) {
console.error(`Error fetching video data for ${videoDoc.id}:`, error)
return {
channelTitle: 'Unknown',
title: 'Unknown Video',
thumbnail: 'not valid thumbnail',
url: '',
author: userData?.id,
authorImg: userData?.img,
uploadDate: '',
tags: [],
playlistTitle: playlistData.title,
}
}
})
)

return videos
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋˜๋Š” ๋ณ€์ˆ˜๋ฅผ ์ธ๋ผ์ธํ•˜์„ธ์š” (inline-immediately-returned-variable)

Suggested change
const videos = await Promise.all(
videoSnapshot.docs.map(async (videoDoc) => {
try {
const videoData = videoDoc.data()
return {
channelTitle: videoData.channelTitle,
title: videoData.title,
thumbnail: videoData.thumbnail,
url: videoData.url,
author: userData?.id,
authorImg: userData?.img,
uploadDate: playlistData.createdAt ? formatDate(playlistData.createdAt) : '',
tags: playlistData.tags,
playlistTitle: playlistData.title,
}
} catch (error) {
console.error(`Error fetching video data for ${videoDoc.id}:`, error)
return {
channelTitle: 'Unknown',
title: 'Unknown Video',
thumbnail: 'not valid thumbnail',
url: '',
author: userData?.id,
authorImg: userData?.img,
uploadDate: '',
tags: [],
playlistTitle: playlistData.title,
}
}
})
)
return videos
return await Promise.all(
videoSnapshot.docs.map(async (videoDoc) => {
try {
const videoData = videoDoc.data()
return {
channelTitle: videoData.channelTitle,
title: videoData.title,
thumbnail: videoData.thumbnail,
url: videoData.url,
author: userData?.id,
authorImg: userData?.img,
uploadDate: playlistData.createdAt ? formatDate(playlistData.createdAt) : '',
tags: playlistData.tags,
playlistTitle: playlistData.title,
}
} catch (error) {
console.error(`Error fetching video data for ${videoDoc.id}:`, error)
return {
channelTitle: 'Unknown',
title: 'Unknown Video',
thumbnail: 'not valid thumbnail',
url: '',
author: userData?.id,
authorImg: userData?.img,
uploadDate: '',
tags: [],
playlistTitle: playlistData.title,
}
}
})
);


Explanation์‚ฌ๋žŒ๋“ค์˜ ์ฝ”๋“œ์—์„œ ์ž์ฃผ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๊ฒฐ๊ณผ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•œ ํ›„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ๋ฅผ ์ง์ ‘ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋‹จ์ถ•ํ•˜๊ณ  ๋ถˆํ•„์š”ํ•œ ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์ฝ๋Š” ๋ฐ ๋“œ๋Š” ์ •์‹ ์  ๋ถ€๋‹ด์„ ์ค„์ž…๋‹ˆ๋‹ค.

์ค‘๊ฐ„ ๋ณ€์ˆ˜๊ฐ€ ์œ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋‚˜ ์กฐ๊ฑด์œผ๋กœ ์‚ฌ์šฉ๋  ๋•Œ์ด๋ฉฐ, ๋ณ€์ˆ˜ ์ด๋ฆ„์ด ๋ณ€์ˆ˜์˜ ์˜๋ฏธ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์ฃผ์„์ฒ˜๋Ÿผ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ ํ•จ์ˆ˜ ์ด๋ฆ„์ด ๊ฒฐ๊ณผ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ๋ ค์ฃผ๋ฏ€๋กœ ๋ณ€์ˆ˜ ์ด๋ฆ„์ด ๋ถˆํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Original comment in English

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
const videos = await Promise.all(
videoSnapshot.docs.map(async (videoDoc) => {
try {
const videoData = videoDoc.data()
return {
channelTitle: videoData.channelTitle,
title: videoData.title,
thumbnail: videoData.thumbnail,
url: videoData.url,
author: userData?.id,
authorImg: userData?.img,
uploadDate: playlistData.createdAt ? formatDate(playlistData.createdAt) : '',
tags: playlistData.tags,
playlistTitle: playlistData.title,
}
} catch (error) {
console.error(`Error fetching video data for ${videoDoc.id}:`, error)
return {
channelTitle: 'Unknown',
title: 'Unknown Video',
thumbnail: 'not valid thumbnail',
url: '',
author: userData?.id,
authorImg: userData?.img,
uploadDate: '',
tags: [],
playlistTitle: playlistData.title,
}
}
})
)
return videos
return await Promise.all(
videoSnapshot.docs.map(async (videoDoc) => {
try {
const videoData = videoDoc.data()
return {
channelTitle: videoData.channelTitle,
title: videoData.title,
thumbnail: videoData.thumbnail,
url: videoData.url,
author: userData?.id,
authorImg: userData?.img,
uploadDate: playlistData.createdAt ? formatDate(playlistData.createdAt) : '',
tags: playlistData.tags,
playlistTitle: playlistData.title,
}
} catch (error) {
console.error(`Error fetching video data for ${videoDoc.id}:`, error)
return {
channelTitle: 'Unknown',
title: 'Unknown Video',
thumbnail: 'not valid thumbnail',
url: '',
author: userData?.id,
authorImg: userData?.img,
uploadDate: '',
tags: [],
playlistTitle: playlistData.title,
}
}
})
);


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

Comment on lines +34 to +47
const unsubscribe = onSnapshot(targetUserDocRef, (docSnapshot) => {
if (docSnapshot.exists()) {
const data = docSnapshot.data()
onUpdate(
{
followers: data.followers || [],
following: data.followings || [],
},
data.followers?.includes(currentUID) || false
)
}
})

return unsubscribe
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋˜๋Š” ๋ณ€์ˆ˜๋ฅผ ์ธ๋ผ์ธํ•˜์„ธ์š” (inline-immediately-returned-variable)

Suggested change
const unsubscribe = onSnapshot(targetUserDocRef, (docSnapshot) => {
if (docSnapshot.exists()) {
const data = docSnapshot.data()
onUpdate(
{
followers: data.followers || [],
following: data.followings || [],
},
data.followers?.includes(currentUID) || false
)
}
})
return unsubscribe
return onSnapshot(targetUserDocRef, (docSnapshot) => {
if (docSnapshot.exists()) {
const data = docSnapshot.data()
onUpdate(
{
followers: data.followers || [],
following: data.followings || [],
},
data.followers?.includes(currentUID) || false
)
}
});


Explanation์‚ฌ๋žŒ๋“ค์˜ ์ฝ”๋“œ์—์„œ ์ž์ฃผ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๊ฒฐ๊ณผ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•œ ํ›„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ๋ฅผ ์ง์ ‘ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋‹จ์ถ•ํ•˜๊ณ  ๋ถˆํ•„์š”ํ•œ ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์ฝ๋Š” ๋ฐ ๋“œ๋Š” ์ •์‹ ์  ๋ถ€๋‹ด์„ ์ค„์ž…๋‹ˆ๋‹ค.

์ค‘๊ฐ„ ๋ณ€์ˆ˜๊ฐ€ ์œ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋‚˜ ์กฐ๊ฑด์œผ๋กœ ์‚ฌ์šฉ๋  ๋•Œ์ด๋ฉฐ, ๋ณ€์ˆ˜ ์ด๋ฆ„์ด ๋ณ€์ˆ˜์˜ ์˜๋ฏธ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์ฃผ์„์ฒ˜๋Ÿผ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ ํ•จ์ˆ˜ ์ด๋ฆ„์ด ๊ฒฐ๊ณผ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ๋ ค์ฃผ๋ฏ€๋กœ ๋ณ€์ˆ˜ ์ด๋ฆ„์ด ๋ถˆํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Original comment in English

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
const unsubscribe = onSnapshot(targetUserDocRef, (docSnapshot) => {
if (docSnapshot.exists()) {
const data = docSnapshot.data()
onUpdate(
{
followers: data.followers || [],
following: data.followings || [],
},
data.followers?.includes(currentUID) || false
)
}
})
return unsubscribe
return onSnapshot(targetUserDocRef, (docSnapshot) => {
if (docSnapshot.exists()) {
const data = docSnapshot.data()
onUpdate(
{
followers: data.followers || [],
following: data.followings || [],
},
data.followers?.includes(currentUID) || false
)
}
});


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

jizerozz and others added 3 commits September 9, 2024 14:33
โœจ #85 ํ™ˆํ”ผ๋“œ ๊ตฌํ˜„ ๋ฐ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ํƒ€์ž… ์ •๋ฆฌ
โ˜ ๏ธ #124 ํ”„๋กœํ•„ ํŽ˜์ด์ง€ ํ”Œ๋ฆฌ ์ด๋ฏธ์ง€ ๊ทธ๋ฆฌ๋“œ ์ •์‚ฌ๊ฐํ˜•์œผ๋กœ ๋ Œ๋”๋ง ๋˜๋„๋ก ์ˆ˜์ •
Copy link

@iamidlek iamidlek left a comment

Choose a reason for hiding this comment

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

๊ณ ์ƒํ•˜์…จ์Šต๋‹ˆ๋‹ค.

์ „๋ฐ˜์ ์œผ๋กœ ํฐ ๋ฌธ์ œ ์—†์ด ๊น”๋”ํ•˜๊ฒŒ ์ž˜ ์ž‘์„ฑํ•˜์‹œ๊ณ  ๊ตฌํ˜„ํ•˜์—ฌ ์ฃผ์…จ์Šต๋‹ˆ๋‹ค.
์ผ๋ถ€ ๋กœ๋”ฉ์ด ์—†์–ด ์š”์ฒญ์ด ๊ฐ€๋Š”์ง€ ํ™•์ธ์ด ์–ด๋ ค์šด ๋ถ€๋ถ„์ด๋‚˜
๋กœ์ง์ด ์• ๋งคํ•œ ๋ถ€๋ถ„ ๊ฐ™์€ ๊ธฐ๋Šฅ์ธ๋ฐ ๊ตฌํ˜„ ๋ฐฉ์‹์ด ์ผ๊ด€ ๋˜์ง€ ์•Š์€ ๋ถ€๋ถ„
๋“ฑ ์— ๋Œ€ํ•œ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค. ์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„์€ ์ƒ๋žตํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋ฐฑ์—”๋“œ๊ฐ€ ์—†๋‹ค๋ณด๋‹ˆ ์š”์ฒญ ์ฒ˜๋ฆฌ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ๋ถ€๋ถ„์— ๋Œ€ํ•œ ๋ฆฌ๋ทฐ๋Š” ์ง„ํ–‰ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ผ๋ถ€ ๊นจ์ง€๋Š” ํ™”๋ฉด๋„ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
image

๊ณตํ†ต๋œ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋ถ„๋ฆฌ, ๊ตฌํ˜„ ๋ฐฉ์‹ ํ†ต์ผ, ์ •ํ™•ํ•œ ๋ช…์นญ ๋“ฑ
์กฐ๊ธˆ ๋” ๋‹ค๋“ฌ์–ด ์ฃผ์‹œ๋ฉด ์ •๋ง ์ข‹์€ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@@ -0,0 +1,57 @@
import { Global, css } from '@emotion/react'
import 'normalize.css'
import { colors } from '@/constants/color'

Choose a reason for hiding this comment

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

์˜๋ฏธ์ ์œผ๋กœ css variable๋กœ ํ™œ์šฉ๋˜์–ด constants ํด๋” ๋ณด๋‹ค๋Š” ์Šคํƒ€์ผ์ชฝ์— ์žˆ๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
font ๋™์ผ

const GlobalStyles = () => (
<Global
styles={css`
@import url('https://cdn.jsdelivr.net/gh/orioncactus/[email protected]/dist/web/variable/pretendardvariable.min.css');

Choose a reason for hiding this comment

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

https://careerly.co.kr/qnas/8085
orioncactus/pretendard#177
๊ฐ€๋ณ€ ํฐํŠธ ์‚ฌ์šฉ ์‹œ ๊ฐ„ํ˜น OS๋‚˜ ๋ธŒ๋ผ์šฐ์ € ๋ฒ„์ „ ๋“ฑ์— ๋”ฐ๋ผ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์–ด
์ฐธ๊ณ ๋กœ ์•Œ์•„๋‘์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ํ•ด๋‹น ๊ธ€์„ ํ™•์ธํ•œ ํ›„, ์ €ํฌ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”์ง€ ๊ฒ€ํ† ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ํ”„๋ฆฌํ…๋‹ค๋“œ ํฐํŠธ ๋ฌธ์ œ๋Š” ์ฃผ๋กœ Flutter ๊ฐœ๋ฐœ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์˜€์œผ๋‚˜, ์ €ํฌ๊ฐ€ ๋ฐฐํฌํ•œ ์‚ฌ์ดํŠธ๋ฅผ ๋ชจ๋ฐ”์ผ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•œ ๊ฒฐ๊ณผ, ํฐํŠธ๊ฐ€ ๊นจ์ง€๋Š” ํ˜„์ƒ์€ ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐ€๋ณ€ ํฐํŠธ๋Š” ๊ทธ๋Œ€๋กœ ์ ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์•Œ๋ ค์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

src/App.tsx Outdated
},
])

const App = () => <RouterProvider router={router} />

Choose a reason for hiding this comment

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

์ž‘์„ฑ ์Šคํƒ€์ผ์˜ ์ฐจ์ด์—ฌ์„œ ์ฐธ๊ณ ๋งŒ ํ•ด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
main.tsx์— ์žˆ๋Š” query, style๋“ฑ ์„ App.tsx์— ์ž‘์„ฑํ•˜๊ณ 
router๋ฅผ ๋ณ„๋„ routerํŒŒ์ผ ๋‚ด์— ์ž‘์„ฑํ•ด๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

router์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๋‚ด์šฉ๋„ ์ƒ๊ธธ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ถ„๋ฆฌ๋˜๋Š” ๊ฒƒ์ด
๊ด€๋ฆฌํ•˜๊ธฐ ์šฉ์ดํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

src/App.tsx Outdated
},

{ path: PATH.EDITPW, element: <EditPwPage /> },
{

Choose a reason for hiding this comment

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

๋กœ๊ทธ์ธ ํ›„ ํ•ด๋‹น path๋กœ ๋“ค์–ด์˜จ ํ›„์—๋Š” ๋‹ค์‹œ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
RootLayout์—์„œ๋Š” useLocation ๋•Œ๋ฌธ์— checkAuth๊ฐ€ ๊ณ„์† ์ฒดํฌ๋˜์–ด
PrivateRoute์˜ checkAuth๊ณผ ๊ฒฐ๊ณผ์ ์œผ๋ก  ๋‹ค๋ฅธ ๊ฐ’์„ ๊ฐ€์ง€๊ฒŒ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

}

return (
<Form title={'ํšŒ์›๊ฐ€์ž…'} getDataForm={handleSignupAndLogin} firebaseError={firebaseError} />

Choose a reason for hiding this comment

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

title์ด ์•„๋‹Œ button์˜ text๋กœ ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.
prop ๋„ค์ด๋ฐ๋„ ์‹ ๊ฒฝ์“ฐ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Comment on lines 49 to 62
const filterBtns = [
{
label: '์ „์ฒด',
value: 'all' as filterPlaylist,
},
{
label: '๊ณต๊ฐœ',
value: 'public' as filterPlaylist,
},
{
label: '๋น„๊ณต๊ฐœ',
value: 'private' as filterPlaylist,
},
]

Choose a reason for hiding this comment

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

์ปดํฌ๋„ŒํŠธ ๋ฐ–์— ์ž‘์„ฑํ•˜์—ฌ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Comment on lines 126 to 135
{filteredLists.length > 4 && !isOpen && (
<Button variant="text" onClick={handleToggleOpen}>
ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ๋ชจ๋‘ ๋ณด๊ธฐ
</Button>
)}
{filteredLists.length > 4 && isOpen && (
<Button variant="text" onClick={handleToggleOpen}>
ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ๋ชจ๋‘ ์ ‘๊ธฐ
</Button>
)}

Choose a reason for hiding this comment

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

text๋ฅผ isOpen์œผ๋กœ ๋ถ„๊ธฐํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import NPProfile from '@/assets/np_logo.svg'
import { useUserData } from '@/hooks/useUserData'
import { usePlaylistData } from '@/hooks/usePlaylistData'
import { filterPlaylist, PlaylistBaseProps } from '@/types/playlistType'

Choose a reason for hiding this comment

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

import type ์œผ๋กœ ๊ด€๋ฆฌ๋˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

setFilter(newFilter)
}

const filteredMap: Record<filterPlaylist, (playlistData: PlaylistBaseProps) => boolean> = {

Choose a reason for hiding this comment

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

all ์— ๋Œ€ํ•œ ํƒ€์ž…์ด ๋งž์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
์ถ”๊ฐ€๋กœ eslint์˜ ๋ฃฐ์—
'no-unused-vars': 'warn' ๋ฅผ
'@typescript-eslint/no-unused-vars': 'error' ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ์—๋Ÿฌ๊ฐ€ ์•ˆ ๋œฐ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

onChange={(e) => setCurrentTag(e.target.value)}
onKeyDown={handleAddTag}
/>
<TagList tags={tags} onTagDelete={handleDeleteTag} />

Choose a reason for hiding this comment

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

์—”ํ„ฐ๋ฅผ ์ณ์•ผ tag๊ฐ€ ์ƒ๊ธด๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ธฐ ์–ด๋ ค์šด ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

export default MusicItem

export const Container = styled.div<{ variant: 'profilePL' | 'createPL'; isPrivate?: boolean }>`
.item-video {

Choose a reason for hiding this comment

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

container ๋‚ด๋ถ€์— class๋กœ ์ž‘์„ฑํ•˜์‹œ๋ฉด
class ๋ช… ๋งˆ๋‹ค ์–ด๋–ค ์†์„ฑ์ด ์ ์šฉ๋˜๋Š”์ง€ ์ถ”์ธกํ•˜๊ธฐ ์–ด๋ ค์šธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

jizerozz and others added 20 commits September 11, 2024 17:10
๐Ÿ”จ ๋ผ์šฐํ„ฐ๊ณผ layout ๋“ฑ ํ”„๋กœ์ ํŠธ ๊ณตํ†ต๋ถ€๋ถ„ ์ฝ”๋“œ๋ฆฌ๋ทฐ์ˆ˜์ •
[refactor] ํ”„๋กœํ•„ ํŽ˜์ด์ง€ pr ๋ฆฌ๋ทฐ ์ฐธ๊ณ ํ•˜์—ฌ ์ˆ˜์ •
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants