Skip to content

Feature/issue 2346 #1563

Open
YaroslavRosnovskyi wants to merge 2 commits intorelease/1.2.3from
feature/issue-2346
Open

Feature/issue 2346 #1563
YaroslavRosnovskyi wants to merge 2 commits intorelease/1.2.3from
feature/issue-2346

Conversation

@YaroslavRosnovskyi
Copy link
Copy Markdown
Collaborator

@YaroslavRosnovskyi YaroslavRosnovskyi commented Mar 27, 2025

dev

JIRA

Summary of issue

  1. Confirmation email is not sent after successful registration.
  2. Emails do not have an expiration mechanism.

Summary of change

  1. Added email confirmation after registration or login with an unconfirmed email.
  2. Implemented custom tokens that expire after 15 minutes.

Back-end PR

ita-social-projects/StreetCode#2637

Summary by CodeRabbit

  • New Features

    • Enhanced account authentication with email verification and token validation, ensuring secure user flows.
    • Introduced a dedicated email confirmation page to streamline the verification process.
    • Improved the password reset experience by validating tokens before form submission.
    • Registration now provides clear success notifications when a confirmation email is sent.
  • Refactor

    • Streamlined login error handling for clearer user feedback.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 27, 2025

Walkthrough

This pull request enhances the authentication system by introducing new API methods for email confirmation and token validation. It updates API route constants and user model interfaces accordingly. The AuthService now includes an asynchronous token validation method with improved error logging. Additionally, a new React route and component for confirming emails have been added. The forgot password reset flow is modified to incorporate asynchronous token validation, while the login and registration components have been updated for streamlined error handling and user feedback.

Changes

Files Change Summary
src/app/api/…/auth.api.ts, src/app/common/constants/api-routes.constants.ts, src/models/user/user.model.ts Added confirmEmail and validateToken methods in AuthApi, new API route constants (CONFIRM_EMAIL, VALIDATE_TOKEN), and new interfaces (ConfirmEmail, ValidateToken) for authentication data.
src/app/common/services/auth-service/AuthService.ts Introduced ValidateTokenAsync method for asynchronous token validation and adjusted formatting in existing method(s).
src/app/router/Routes.tsx, src/features/Auth/ConfirmEmail/ConfirmEmail.component.tsx Added a new route /confirm-email and the corresponding ConfirmEmail React component to handle email confirmations.
src/features/Auth/ForgotPassword/ForgotPasswordReset.component.tsx, src/features/Auth/Login/Login.component.tsx, src/features/Auth/RegistrationPage/RegistrationPage.component.tsx Enhanced forgot password flow with asynchronous token validation, updated login error handling, and improved registration feedback with success messaging.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant B as Browser
    participant C as ConfirmEmail Component
    participant A as AuthApi
    participant M as Message Display

    U->>B: Navigate to /confirm-email?token=...&username=...
    B->>C: Render ConfirmEmail component
    C->>C: Extract token & username from URL
    alt Missing parameters
        C->>B: Redirect to Login Page
    else Valid parameters
        C->>A: Call confirmEmail({ userName, token })
        A-->>C: Return boolean result
        C->>M: Display success or error message
        C->>B: Redirect to Login Page
    end
Loading
sequenceDiagram
    participant U as User
    participant B as Browser
    participant F as ForgotPasswordReset Component
    participant S as AuthService

    U->>B: Open password reset link with token & username
    B->>F: Render ForgotPasswordReset component
    F->>F: Extract token & username from URL
    alt Missing parameters
        F->>B: Redirect to Login Page
    else Valid parameters
        F->>S: Call ValidateTokenAsync(request)
        S-->>F: Return validation result
        F->>F: Update isOkResult state (enable/disable form submit)
    end
Loading

Suggested reviewers

  • ilko-dev
  • vlad-zhadan
  • YuliiaAndreieva
  • Michael-Kolpakov
  • lisaaksionova

Poem

In the realm of code so bright,
New routes and methods take their flight.
Tokens validated, emails confirmed with cheer,
Async adventures now are crystal clear.
Our code sings a joyful tune, innovation near! 🎉

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it’s a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/features/Auth/RegistrationPage/RegistrationPage.component.tsx

Oops! Something went wrong! :(

ESLint: 8.42.0

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

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

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

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

The plugin "eslint-plugin-react-hooks" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

src/features/Auth/ConfirmEmail/ConfirmEmail.component.tsx

Oops! Something went wrong! :(

ESLint: 8.42.0

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

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

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

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

The plugin "eslint-plugin-react-hooks" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9356978 and 04dcc4c.

📒 Files selected for processing (2)
  • src/features/Auth/ConfirmEmail/ConfirmEmail.component.tsx (1 hunks)
  • src/features/Auth/RegistrationPage/RegistrationPage.component.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/features/Auth/ConfirmEmail/ConfirmEmail.component.tsx
  • src/features/Auth/RegistrationPage/RegistrationPage.component.tsx

🪧 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.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
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: 4

🧹 Nitpick comments (7)
src/app/common/services/auth-service/AuthService.ts (2)

90-97: Follow camelCase naming convention for method names

The ValidateTokenAsync method uses PascalCase naming, which is inconsistent with other methods in this class that use camelCase (e.g., loginAsync, registerAsync).

-public static async ValidateTokenAsync(request: ValidateToken) {
+public static async validateTokenAsync(request: ValidateToken) {
    try {
        await AuthApi.validateToken(request);
    } catch (error) {
        console.error(error);
        return Promise.reject(error);
    }
}

90-97: Clarify return value for the successful case

The current implementation doesn't explicitly return a value on success. This could confuse developers who expect a consistent return value from the method.

public static async ValidateTokenAsync(request: ValidateToken) {
    try {
        await AuthApi.validateToken(request);
+       return true; // Explicitly return a success indicator
    } catch (error) {
        console.error(error);
        return Promise.reject(error);
    }
}
src/features/Auth/ConfirmEmail/ConfirmEmail.component.tsx (1)

15-38: Add more user feedback during the validation process

Currently, the component only shows a loader without any contextual information about what's happening. Consider adding a loading state and more informative feedback.

const ConfirmEmail = () => {
    const location = useLocation();
    const navigate = useNavigate();
    const hasRun = useRef(false);
+   const [status, setStatus] = useState('loading'); // 'loading', 'success', 'error'

    useAsync(async () => {
        if (hasRun.current) return;
        hasRun.current = true;

        const searchParams = new URLSearchParams(location.search);

        const token = searchParams.get('token');
        const userName = searchParams.get('username');

        if (!token || !userName) {
            navigate(FRONTEND_ROUTES.AUTH.LOGIN);
            return;
        }

        try {
            await AuthApi.confirmEmail({ userName, token });
+           setStatus('success');
            message.success('Ваш акаунт успішно створено. Тепер ви можете увійти в систему.');
        } catch (error) {
+           setStatus('error');
            message.error('Це посилання недійсне або протерміноване. '
                + 'Будь ласка, перейдіть на сторінку входу і спробуйте зареєструватися ще раз.');
        }

-       navigate(FRONTEND_ROUTES.AUTH.LOGIN);
+       setTimeout(() => navigate(FRONTEND_ROUTES.AUTH.LOGIN), 3000); // Give user time to read the message
    }, []);

-   return <Loader />;
+   return (
+       <div className="confirm-email-container">
+           {status === 'loading' && <Loader />}
+           {status === 'loading' && <p>Підтверджуємо вашу електронну адресу...</p>}
+       </div>
+   );
src/features/Auth/ForgotPassword/ForgotPasswordReset.component.tsx (2)

22-51: Add loading state for token validation

The component doesn't provide any visual feedback during token validation. Users won't know that validation is in progress.

const ForgotPasswordResetComponent: React.FC = () => {
    const [form] = Form.useForm();
    const location = useLocation();
    const navigator = useNavigate();
    const [isValid, setIsValid] = useState<boolean>(true);
    const [isOkResult, setIsOkResult] = useState(false);
+   const [isValidating, setIsValidating] = useState(true);
    const hasRun = useRef(false);

    useAsync(async () => {
        if (hasRun.current) return;
        hasRun.current = true;

        const searchParams = new URLSearchParams(location.search);

        const token = searchParams.get('token');
        const userName = searchParams.get('username');

        if (!token || !userName) {
            navigator(FRONTEND_ROUTES.AUTH.LOGIN);
            return;
        }

        const request: ValidateToken = {
            token,
            purpose: 'ResetPassword',
            userName,
            tokenProvider: 'CustomResetPassword',
        };

        try {
            await AuthService.ValidateTokenAsync(request);
            setIsOkResult(true);
        } catch (error) {
            message.error('Це посилання недійсне або протерміноване. '
                + 'Поверніться на сторінку відновлення паролю і спробуйте ще раз.', 5);
            setIsOkResult(false);
        } finally {
+           setIsValidating(false);
        }
    }, []);

Then update the button to show loading state:

<Button
    htmlType="submit"
-   disabled={!isValid && !isOkResult}
+   disabled={!isValid || !isOkResult || isValidating}
+   loading={isValidating}
    className="streetcode-custom-button forgotPasswordResetButton"
>

53-68: Avoid URL parameter duplication

The token and username are extracted twice from the URL - once in the useAsync hook and again in the handleUpdatePassword function.

Store these values in state variables to avoid duplication:

const ForgotPasswordResetComponent: React.FC = () => {
    const [form] = Form.useForm();
    const location = useLocation();
    const navigator = useNavigate();
    const [isValid, setIsValid] = useState<boolean>(true);
    const [isOkResult, setIsOkResult] = useState(false);
    const [isValidating, setIsValidating] = useState(true);
+   const [token, setToken] = useState<string | null>(null);
+   const [username, setUsername] = useState<string | null>(null);
    const hasRun = useRef(false);

    useAsync(async () => {
        if (hasRun.current) return;
        hasRun.current = true;

        const searchParams = new URLSearchParams(location.search);

        const tokenParam = searchParams.get('token');
        const userNameParam = searchParams.get('username');
+       setToken(tokenParam);
+       setUsername(userNameParam);

        if (!tokenParam || !userNameParam) {
            navigator(FRONTEND_ROUTES.AUTH.LOGIN);
            return;
        }
        // ...rest of the validation code
    }, []);

    const handleUpdatePassword = async () => {
-       const searchParams = new URLSearchParams(location.search);
-
-       const token = searchParams.get('token');
-       const username = searchParams.get('username');

        const newPassword = form.getFieldValue('password');
        const confirmPassword = form.getFieldValue('passwordConfirmation');

        await AuthService.sendForgotPasswordUpdate(newPassword, confirmPassword, username, token).then(() => {
src/app/api/authentication/auth.api.ts (2)

41-43: Add .then((response) => response.data) for consistency with other methods

Your implementation of confirmEmail is missing the data extraction that's present in all other methods in this file. This will cause the method to return a full Axios response object instead of just the boolean value.

confirmEmail: (confirmEmailRequest: ConfirmEmail) => (
    instance.post<boolean>(API_ROUTES.AUTH.CONFIRM_EMAIL, confirmEmailRequest)
+       .then((response) => response.data)
),

44-46: Add .then((response) => response.data) for consistency with other methods

Similar to the confirmEmail method, the validateToken method should extract the data from the response to maintain consistency with the other methods in this file.

validateToken: (validateTokenRequest: ValidateToken) => (
    instance.post<boolean>(API_ROUTES.AUTH.VALIDATE_TOKEN, validateTokenRequest)
+       .then((response) => response.data)
),
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8dea32a and 9356978.

📒 Files selected for processing (9)
  • src/app/api/authentication/auth.api.ts (2 hunks)
  • src/app/common/constants/api-routes.constants.ts (1 hunks)
  • src/app/common/services/auth-service/AuthService.ts (3 hunks)
  • src/app/router/Routes.tsx (2 hunks)
  • src/features/Auth/ConfirmEmail/ConfirmEmail.component.tsx (1 hunks)
  • src/features/Auth/ForgotPassword/ForgotPasswordReset.component.tsx (3 hunks)
  • src/features/Auth/Login/Login.component.tsx (2 hunks)
  • src/features/Auth/RegistrationPage/RegistrationPage.component.tsx (1 hunks)
  • src/models/user/user.model.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (4)
src/app/router/Routes.tsx (1)
src/models/user/user.model.ts (1)
  • ConfirmEmail (64-67)
src/features/Auth/ConfirmEmail/ConfirmEmail.component.tsx (1)
src/models/user/user.model.ts (1)
  • ConfirmEmail (64-67)
src/app/common/services/auth-service/AuthService.ts (1)
src/models/user/user.model.ts (1)
  • ValidateToken (69-74)
src/app/api/authentication/auth.api.ts (2)
src/models/user/user.model.ts (2)
  • ConfirmEmail (64-67)
  • ValidateToken (69-74)
src/app/common/constants/api-routes.constants.ts (1)
  • API_ROUTES (2-272)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Jenkins
🔇 Additional comments (7)
src/app/router/Routes.tsx (2)

4-4: Good addition of the ConfirmEmail component import.

The import is properly placed with other authentication-related imports, maintaining organization within the file.


125-125: Route implementation looks good.

The new route for email confirmation is correctly added and follows the same pattern as other authentication routes in the application. This provides users with a dedicated path to confirm their email addresses.

src/app/common/constants/api-routes.constants.ts (1)

215-216: API route constants properly defined.

The new constants for email confirmation and token validation are correctly placed in the AUTH section and follow the established naming conventions. These endpoints will support the email confirmation functionality as outlined in the PR objectives.

src/models/user/user.model.ts (2)

64-67: Interface for ConfirmEmail is well structured.

The interface contains all necessary fields for email confirmation. The naming is clear and follows TypeScript best practices.


69-74: ValidateToken interface is properly defined.

This interface includes all required fields for token validation. The inclusion of fields like purpose and tokenProvider suggests good flexibility for different token validation scenarios.

src/app/api/authentication/auth.api.ts (2)

6-7: Nice work updating the imports

The import changes correctly include the new interfaces needed for email confirmation and token validation functionality. This supports the PR's goal of enhancing the authentication system with email confirmation capabilities.

Also applies to: 12-13


41-46: Great implementation of email confirmation methods

The addition of these two methods aligns perfectly with the PR objectives of implementing email confirmation functionality. The API routes and request structures match the backend endpoints defined in the constants file.

Comment thread src/features/Auth/RegistrationPage/RegistrationPage.component.tsx
Comment thread src/features/Auth/Login/Login.component.tsx
Comment thread src/features/Auth/ConfirmEmail/ConfirmEmail.component.tsx Outdated
Comment thread src/features/Auth/ForgotPassword/ForgotPasswordReset.component.tsx
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
2.8% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

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