Skip to content

Conversation

@klmhyeonwoo
Copy link
Collaborator

@klmhyeonwoo klmhyeonwoo commented Dec 11, 2024

목적

  • 커뮤니티 기능을 재활성화하고 기타 오류를 픽스합니다.

필수 리뷰어

작업 내용

  • src/app/community/index.tsx
    • profile이 존재하지 않았을 때에 대한 오류 처리
  • src/app/home/index.tsx
    src/components/layout/header.tsx
    • 커뮤니티 진입 전, 로그인 확인에 대한 함수 추가
  • src/app/signin/index.tsx
    • 로그인 시에 계정 정보가 틀렸을 때에 대한 알림 처리
  • src/utils/globalNavigate.ts
    src/components/layout/index.tsx
    src/api/index.ts
    • Axios Interceptor에서 글로벌 네비게이션을 사용할 수 있도록 수정
    • 401 일 경우, 로그인 페이지로 이동할 수 있도록 이동

테스트

  • 로컬 테스트 및 스테이징 테스트

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced navigation logic for authentication errors, directing users to the sign-in page.
    • Added user authentication checks in the community access flow.
    • Introduced a global navigation management system.
  • Bug Fixes

    • Improved null safety in profile data handling.
  • Documentation

    • Added comments for clarity on new constants and functions.
  • Style

    • Updated SVG attributes for consistency with JSX syntax.
    • Improved formatting and readability in several components.
  • Chores

    • Streamlined component logic by removing unnecessary hooks and simplifying navigation handling.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 11, 2024

Walkthrough

The pull request introduces significant modifications to the navigation and error handling logic across various components in the application. Key changes include the removal of the useNavigate hook in favor of a new navigateTo function for handling navigation upon authentication errors. Enhancements in null safety and user authentication checks are implemented in components like CommunityCreateBtn and HomePage. Additionally, several components undergo syntax corrections and structural adjustments, ensuring consistent use of JSX conventions. Overall, the changes streamline navigation and improve the handling of user states throughout the application.

Changes

File Change Summary
src/api/index.ts Removed useNavigate hook; replaced with navigateTo function for navigation on 401 errors; updated error handling in onError function.
src/app/community/index.tsx Enhanced null safety for profile prop using optional chaining.
src/app/home/index.tsx Added COMMUNITY_URL import; integrated useAtom for login state management; defined validateLoginState for user authentication checks.
src/app/predict/index.tsx Updated SVG attributes for JSX compliance; no change in component logic.
src/app/signin/index.tsx Introduced useEffect to check local storage on mount; added handleSignIn function for sign-in logic.
src/components/app/community/community-board.tsx Updated function signature and JSX structure; rendered content in a div with dangerouslySetInnerHTML.
src/components/app/community/community-tab.tsx Changed SVG attributes to camelCase for JSX compliance; no change in component logic.
src/components/common/modal/Modal.tsx Activated "Cancel" and "Confirm" buttons in the modal; removed commented-out code.
src/components/layout/header.tsx Added LOGIN_URL and REGISTER_URL; integrated validateLoginState for navigation based on user login state.
src/components/layout/index.tsx Integrated useNavigate for global navigation; simplified scroll event listener setup.
src/components/layout/sidebar.tsx Removed hooks and simplified navigation logic for the "커뮤니티" link; adjusted CSS properties.
src/hooks/api/community/UseApiComminity.ts Changed UseApiCommunity and UseInfiniteApiCommunity from exported to non-exported functions; re-exported at the end of the file.
src/hooks/api/member/useApiSignIn.ts Changed signIn from exported to locally scoped constant; updated export statement.
src/hooks/api/member/useApiSignUp.ts Updated default values in signUp function to include random integers; removed console log statement.
src/utils/common.ts Introduced new constant ACT with value "FLOWBIT_ACT" for use in other modules.
src/utils/globalNavigate.ts Defined globalNavigate for managing global navigation; added setGlobalNavigate and navigateTo functions for navigation handling.

Possibly related PRs

Suggested reviewers

  • joeunSong

🐇 In the code we hop and play,
With navigation brightening our way.
From sign-in checks to community calls,
We streamline paths, let no one fall.
With every click, our users cheer,
A smoother journey, oh so near! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Experiment)
  • @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
Contributor

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

🧹 Outside diff range and nitpick comments (10)
src/utils/globalNavigate.ts (1)

1-1: Consider using a more robust state management solution

Using a mutable global variable for navigation state could lead to race conditions and make the code harder to test.

Consider using React Context or a state management library like Redux/Zustand instead:

import { createContext, useContext } from 'react';
import { NavigateFunction } from 'react-router-dom';

const NavigateContext = createContext<NavigateFunction | null>(null);
export const NavigateProvider = NavigateContext.Provider;
export const useGlobalNavigate = () => {
  const navigate = useContext(NavigateContext);
  if (!navigate) throw new Error('NavigateProvider not found');
  return navigate;
};
src/components/layout/index.tsx (2)

15-18: Optimize scroll event listener with debouncing

The scroll event can fire frequently and impact performance.

Consider implementing debouncing:

+import { debounce } from 'lodash';
+
 useEffect(() => {
-  window.addEventListener("scroll", handleScroll);
-  return () => window.removeEventListener("scroll", handleScroll);
+  const debouncedHandleScroll = debounce(handleScroll, 150);
+  window.addEventListener("scroll", debouncedHandleScroll);
+  return () => {
+    debouncedHandleScroll.cancel();
+    window.removeEventListener("scroll", debouncedHandleScroll);
+  };
 }, []);

Line range hint 27-33: Translate Korean comments to English for consistency

Consider translating the Korean comment for better maintainability in an international team context.

-  // 사용자의 scroll 동작 여부에 따라 상태 값 변경
+  // Update state based on user scroll position
src/api/index.ts (1)

33-34: Consider using type-safe localStorage operations

While the logic is correct, consider using a type-safe wrapper for localStorage operations to prevent potential runtime errors.

-    localStorage.removeItem("FLOWBIT_ACT");
+    const FLOWBIT_ACT = "FLOWBIT_ACT" as const;
+    localStorage.removeItem(FLOWBIT_ACT);
src/app/signin/index.tsx (1)

31-36: Add missing dependency to useEffect

The effect uses setLogin but doesn't include it in the dependency array. While setLogin is stable (from jotai), it's best practice to include all dependencies.

-  }, []);
+  }, [setLogin]);
src/components/layout/header.tsx (2)

35-52: Add type definitions for modal parameters

Consider defining an interface for the modal parameters to improve type safety and maintainability.

+interface ModalParams {
+  title: string;
+  content: string;
+  callBack: () => void;
+}

 const validateLoginState = () => {
   if (isLogin) {
     navigate(COMMUNITY_URL);
   } else {
-    open({
+    open<ModalParams>({
       title: "로그인을 먼저 진행해주세요",
       content:
         "플로우빗 커뮤니티 기능은 회원을 위한 기능입니다.\n원활한 서비스 이용을 위해 로그인을 먼저 진행해주세요",
       callBack: () => {
         close();
         navigate("/signin");
       },
     });
   }
 };

223-298: Extract styles and add loading state for logout

Consider these improvements:

  1. Extract repeated styles to reusable constants
  2. Add loading state for logout operation
  3. Consider moving user options to a separate component for better maintainability

Example of extracting styles:

+const userOptionStyles = css`
+  ${DESIGN_SYSTEM_TEXT.CAPTION}
+  color: ${(props) => props.isScroll ? DESIGN_SYSTEM_COLOR.GRAY_800 : "white"};
+  font-weight: 300;
+`;

-          css={css`
-            ${DESIGN_SYSTEM_TEXT.CAPTION}
-            color: ${isScroll ? DESIGN_SYSTEM_COLOR.GRAY_800 : "white"};
-            font-weight: 300;
-          `}
+          css={userOptionStyles}
src/components/app/community/community-board.tsx (1)

390-401: Consider enhancing comment validation

While the length check is good, consider trimming whitespace and preventing empty comments.

-if (comment.length > 0) {
+const trimmedComment = comment.trim();
+if (trimmedComment.length > 0) {
   postComment({
     boardId: props.boardId,
-    content: comment,
+    content: trimmedComment,
   });
 }
src/app/home/index.tsx (2)

94-111: Consider improving modal content accessibility

While the login validation logic is correct, the modal content could be more accessible.

 content:
-  "플로우빗 커뮤니티 기능은 회원을 위한 기능입니다.\n원활한 서비스 이용을 위해 로그인을 먼저 진행해주세요",
+  "플로우빗 커뮤니티 기능은 회원을 위한 기능입니다.\n\n원활한 서비스 이용을 위해 로그인을 먼저 진행해주세요.\n\n계속하시겠습니까?",

45-45: Fix eslint warning about unused variable

The underscore variable is unused.

-const [isLogin, _] = useAtom(loginState);
+const [isLogin] = useAtom(loginState);
🧰 Tools
🪛 eslint

[error] 45-45: '_' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a421f48 and f0c5ef9.

⛔ Files ignored due to path filters (2)
  • src/assets/lock.svg is excluded by !**/*.svg
  • src/assets/mail.svg is excluded by !**/*.svg
📒 Files selected for processing (16)
  • src/api/index.ts (2 hunks)
  • src/app/community/index.tsx (1 hunks)
  • src/app/home/index.tsx (10 hunks)
  • src/app/predict/index.tsx (1 hunks)
  • src/app/signin/index.tsx (3 hunks)
  • src/components/app/community/community-board.tsx (8 hunks)
  • src/components/app/community/community-tab.tsx (1 hunks)
  • src/components/common/modal/Modal.tsx (1 hunks)
  • src/components/layout/header.tsx (4 hunks)
  • src/components/layout/index.tsx (1 hunks)
  • src/components/layout/sidebar.tsx (2 hunks)
  • src/hooks/api/community/UseApiComminity.ts (3 hunks)
  • src/hooks/api/member/useApiSignIn.ts (1 hunks)
  • src/hooks/api/member/useApiSignUp.ts (0 hunks)
  • src/utils/common.ts (1 hunks)
  • src/utils/globalNavigate.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/hooks/api/member/useApiSignUp.ts
✅ Files skipped from review due to trivial changes (3)
  • src/utils/common.ts
  • src/components/app/community/community-tab.tsx
  • src/app/predict/index.tsx
🧰 Additional context used
🪛 eslint
src/app/home/index.tsx

[error] 45-45: '_' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

🪛 Biome (1.9.4)
src/components/app/community/community-board.tsx

[error] 235-236: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🔇 Additional comments (8)
src/components/layout/index.tsx (1)

22-24: LGTM! Proper useEffect dependency handling

The useEffect correctly includes navigate in its dependency array, ensuring the global navigation stays in sync with any navigation function updates.

src/hooks/api/community/UseApiComminity.ts (1)

21-21: LGTM! Clean refactor of exports

The consolidation of exports at the end of the file improves code organization while maintaining the same functionality. This follows the common pattern of grouping exports together.

Also applies to: 43-43, 70-71

src/components/layout/sidebar.tsx (1)

118-129: LGTM! Consistent styling for mypage section

The mypage section styling follows the design system correctly using DESIGN_SYSTEM_TEXT and DESIGN_SYSTEM_COLOR constants.

src/components/common/modal/Modal.tsx (2)

105-114: LGTM! Clean implementation of modal buttons

The cancel and confirm buttons are properly implemented with consistent styling using the design system.


105-114: Verify login notification modal content

The PR mentions adding login notifications, but the modal content for incorrect login attempts isn't visible in this change.

src/app/community/index.tsx (1)

199-199: LGTM: Enhanced null safety with optional chaining

The addition of optional chaining operators (?.) provides better protection against undefined values in the data object.

src/components/app/community/community-board.tsx (1)

257-266: LGTM: Well-implemented like functionality

The like button handler correctly manages state and handles both like and unlike scenarios.

src/app/home/index.tsx (1)

475-475: LGTM: Proper login validation before community access

The click handler correctly uses validateLoginState to ensure users are logged in before accessing community features.

Comment on lines +7 to 13
const signIn = ({ email, password }: signInProps) => {
const res = api.post(`/user-service/api/v1/member/login`, {
userId: email,
password: password,
});
return res;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and improve type safety

The signIn function should include proper error handling and type definitions for the response.

Consider applying these improvements:

-const signIn = ({ email, password }: signInProps) => {
+interface SignInResponse {
+  accessToken: string;
+  // add other expected response fields
+}
+
+const signIn = async ({ email, password }: signInProps): Promise<SignInResponse> => {
+  try {
   const res = api.post(`/user-service/api/v1/member/login`, {
     userId: email,
     password: password,
   });
-  return res;
+    return (await res).data;
+  } catch (error) {
+    throw new Error('Failed to sign in: ' + (error instanceof Error ? error.message : 'Unknown error'));
+  }
 };
📝 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 signIn = ({ email, password }: signInProps) => {
const res = api.post(`/user-service/api/v1/member/login`, {
userId: email,
password: password,
});
return res;
};
interface SignInResponse {
accessToken: string;
// add other expected response fields
}
const signIn = async ({ email, password }: signInProps): Promise<SignInResponse> => {
try {
const res = api.post(`/user-service/api/v1/member/login`, {
userId: email,
password: password,
});
return (await res).data;
} catch (error) {
throw new Error('Failed to sign in: ' + (error instanceof Error ? error.message : 'Unknown error'));
}
};

Comment on lines +7 to +13
export const navigateTo = (path: string) => {
if (globalNavigate) {
globalNavigate(path);
} else {
console.error("navigateTo was called before navigate was initialized");
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and type safety for navigation

The current implementation uses console.error which might not be sufficient for production environments.

Consider these improvements:

+type NavigationPath = '/signin' | '/community' | '/home'; // add all valid paths
+
-export const navigateTo = (path: string) => {
+export const navigateTo = (path: NavigationPath) => {
   if (globalNavigate) {
     globalNavigate(path);
   } else {
-    console.error("navigateTo was called before navigate was initialized");
+    // Consider using a proper error tracking service
+    const error = new Error("Navigation attempted before initialization");
+    // reportError(error); // Use your error tracking service
+    throw error;
   }
 };

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

Comment on lines +111 to +113
<NavLink to={COMMUNITY_URL}>
<li onClick={setIsOpen}>커뮤니티</li>
</NavLink>
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Login verification is missing in sidebar navigation

The codebase shows that login verification is properly implemented in both header.tsx and home/index.tsx using the validateLoginState function, which checks isLogin before allowing community access. However, the sidebar implementation allows direct navigation without this check, creating an inconsistency in authentication logic.

  • src/components/layout/sidebar.tsx: Add login verification to the community link using the existing validateLoginState pattern
<NavLink to={COMMUNITY_URL}>
  <li onClick={setIsOpen}>커뮤니티</li>
</NavLink>
🔗 Analysis chain

Verify login check implementation for community access

According to the PR objectives, there should be login verification before accessing the community feature. However, the current implementation allows direct navigation without checking login status.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for login verification implementation
rg -l "validateLoginState.*community" 

Length of output: 39


Script:

#!/bin/bash
# Let's search for any login-related checks or authentication guards for community routes
rg -A 3 "community.*route|route.*community|COMMUNITY_URL" 

# Also search for any authentication-related hooks or components
rg -l "useAuth|isAuthenticated|requireAuth|PrivateRoute|AuthGuard"

Length of output: 1849


Script:

#!/bin/bash
# Let's check the validateLoginState function implementation since we see it's used in header.tsx
ast-grep --pattern 'function validateLoginState' -A 10

# Also check for any other login validation functions
rg -A 5 "validateLoginState|checkLogin|isLoggedIn"

Length of output: 1462

alert("에러가 발생했습니다.");
});
}}
onClick={handleSignIn}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Disable button during sign-in process

The button should be disabled while the sign-in request is in progress to prevent multiple submissions.

-        onClick={handleSignIn}
+        disabled={isLoading}
+        onClick={handleSignIn}

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

Comment on lines +38 to +52
const handleSignIn = async () => {
signIn({ email, password })
.then((res) => {
localStorage.setItem("FLOWBIT_ACT", res.data.accessToken);
setLogin(true);
navigate("/community");
})
.catch(({ status }) => {
if (status === 401) {
alert("잘못된 계정입니다, 다시 입력해주세요.");
} else {
alert("에러가 발생했습니다, 관리자에게 문의해주세요.");
}
});
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling and add loading state

The sign-in handler could benefit from several improvements:

  1. Consistent async/await usage
  2. Proper error typing
  3. Loading state to prevent multiple submissions
+  const [isLoading, setIsLoading] = useState(false);
+
+  const handleSignIn = async () => {
+    if (isLoading) return;
+    
+    try {
+      setIsLoading(true);
+      const res = await signIn({ email, password });
+      localStorage.setItem("FLOWBIT_ACT", res.data.accessToken);
+      setLogin(true);
+      navigate("/community");
+    } catch (error) {
+      if (error?.status === 401) {
+        alert("잘못된 계정입니다, 다시 입력해주세요.");
+      } else {
+        alert("에러가 발생했습니다, 관리자에게 문의해주세요.");
+      }
+    } finally {
+      setIsLoading(false);
+    }
+  };

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

Comment on lines +232 to +240
<div
id="content"
contentEditable={false}
dangerouslySetInnerHTML={{ __html: content }}
css={css`
${DESIGN_SYSTEM_TEXT.B1}
color: ${DESIGN_SYSTEM_COLOR.GRAY_700};
`}
>
{content}
</span>
></div>
Copy link
Contributor

@coderabbitai coderabbitai bot Dec 11, 2024

Choose a reason for hiding this comment

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

⚠️ Potential issue

Security Risk: Unsafe HTML rendering

Using dangerouslySetInnerHTML without sanitization exposes the application to XSS attacks.

Consider using a sanitization library:

+import DOMPurify from 'dompurify';

-dangerouslySetInnerHTML={{ __html: content }}
+dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content) }}

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

🧰 Tools
🪛 Biome (1.9.4)

[error] 235-236: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sanitize 이런게 있었구나?!

Copy link
Contributor

Choose a reason for hiding this comment

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

@klmhyeonwoo 네, DOMPurifysanitize 함수를 사용하여 dangerouslySetInnerHTML 사용 시 보안 위험을 최소화할 수 있습니다. 이는 XSS 공격으로부터 애플리케이션을 보호하는 데 도움이 됩니다. 다음과 같이 적용하실 수 있습니다:

import DOMPurify from 'dompurify';

// ...

<div
  id="content"
  contentEditable={false}
  dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content) }}
  css={css`
    ${DESIGN_SYSTEM_TEXT.B1}
    color: ${DESIGN_SYSTEM_COLOR.GRAY_700};
  `}
/>

이를 통해 외부로부터 입력된 HTML 콘텐츠를 안전하게 렌더링할 수 있습니다.

@klmhyeonwoo klmhyeonwoo merged commit 9333338 into main Dec 11, 2024
2 of 3 checks passed
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.

3 participants