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

Refactor JavaScript: Reduce Redundancy and Implement Modern Practices #367

Merged
merged 2 commits into from
Oct 21, 2024

Conversation

Aayush2308
Copy link
Contributor

@Aayush2308 Aayush2308 commented Oct 20, 2024

Issues Identification

Closes: #364

Description

This PR refactors our JavaScript codebase to improve efficiency and adopt modern practices. Key changes include:

  • Consolidated form validation functions to reduce redundancy
  • Streamlined event listeners under a single DOMContentLoaded event
  • Implemented optional chaining for safer property access
  • Optimized DOM manipulations and calculations
  • Enhanced error handling in forms
  • Utilized modern JS features (arrow functions, template literals)
  • Improved eco-tips slider logic

These changes maintain existing functionality while making the code more maintainable, performant, and aligned with current JavaScript best practices. The refactoring reduces potential errors and improves overall code quality.
Testing

All existing functionalities have been manually tested
Unit tests updated to reflect new code structure
Cross-browser compatibility verified

Summary

Provide a brief description of what this pull request does and why it is needed.

This issue addresses the need to enhance our JavaScript codebase's efficiency and maintainability. The proposed changes include consolidating redundant functions, optimizing event listeners and DOM manipulations, implementing modern JavaScript features, enhancing error handling in forms, and streamlining calculations. These improvements aim to reduce code complexity and boost performance without altering functionality. Motivated by the codebase's organic growth and future scalability needs, this refactoring will reduce potential bugs, improve load times, and align with modern best practices. Specific issues to be fixed include duplicate form validation code, inefficient DOM operations, lack of error prevention in property access, suboptimal event listener usage, and overly complex UI calculations. While no new dependencies are introduced, the changes require ECMAScript 2020 support and modern browser compatibility. The implementation will be incremental, accompanied by updated unit tests and documentation. Potential impacts include improved page load times and developer onboarding, with some consideration needed for older browser compatibility. Next steps involve reviewing the changes, assigning developers, setting up a testing plan, scheduling code reviews, and planning a progressive rollout.

Details

Include any detailed information about the changes in this pull request.

Types of Changes

*Code Redundancy/ Efficiency and minimizing lines of code

Please check the boxes that apply

  • Bugfix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update (Documentation content changed)
  • Other (Code Efficiency and Maintainability):

Checklist

Please check the boxes that apply

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • My changes do not break the current system and pass all existing test cases
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Screenshots

Before:
image
image
image
image
image

After:
image
image
image
image
image

You can see that before changes there were 279 lines of code which has is now 187 lines after making changes in it.

Please add #hacktoberfest-accpted, #hacktoberfest, #level2 labels

Additional Information

Please provide any other information that is relevant to this pull request.

Summary by CodeRabbit

  • New Features

    • Introduced smooth scrolling functionality for improved user experience.
    • Consolidated form validation into a single function for both signup and login forms.
    • Enhanced event listeners for form submissions to improve error handling and readability.
    • Improved slider functionality for eco-tips with better navigation controls.
  • Bug Fixes

    • Reduced risk of errors in event listeners through safer element access methods.

Copy link
Contributor

coderabbitai bot commented Oct 20, 2024

Walkthrough

The changes in this pull request focus on enhancing the structure and functionality of the script.js file. Key modifications include the introduction of a unified form validation function, improvements to event listener handling, and the implementation of smooth scrolling functionality. The code has been refactored for better readability and maintainability, consolidating similar functionalities and employing modern JavaScript practices such as optional chaining. Additionally, the slider functionality for eco-tips has been encapsulated within its own event listener, improving its management.

Changes

File Change Summary
script.js - Refactored smoothScrolling function and its event listener for consistency.
- Replaced validateSignup with a generic validateForm(formType) for enhanced form validation.
- Updated event listeners for form submissions using optional chaining for safer access.
- Modified DOMContentLoaded event to include additional elements for image uploads and forms.
- Encapsulated eco-tips slider functionality within its own DOMContentLoaded event listener.

Assessment against linked issues

Objective Addressed Explanation
Combine similar functions to reduce redundancy (364)
Consolidate event listeners under a single DOMContentLoaded event (364)
Implement optional chaining for safer property access (364)
Enhance form validation logic (364)
Improve error handling and user feedback (364) No specific enhancements made to error handling.

Possibly related PRs

  • Add smooth scrolling functionality #355: The changes in this PR involve the smoothScrolling function in script.js, which is directly related to the modifications made in the main PR regarding the reformatting of the smoothScrolling function and its event listener.

Poem

In the code where rabbits play,
We’ve tidied up the fray,
With forms that validate with glee,
And smooth scrolling, oh so free!
Our scripts now dance and twirl,
A joyful, organized code world! 🐇✨


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 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

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Thank you, Aayush2308, for creating this pull request and contributing to WasteManagement! 💗

The maintainers will review this Pull Request and provide feedback as soon as possible! 😇
We appreciate your patience and contribution, Keep up the great work! 😀

Copy link

netlify bot commented Oct 20, 2024

Deploy Preview for manageyourwaste failed. Why did it fail? →

Name Link
🔨 Latest commit 8db5a87
🔍 Latest deploy log https://app.netlify.com/sites/manageyourwaste/deploys/67163de987b33a0008a213b7

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: 4

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 388d133 and ed7bde2.

📒 Files selected for processing (1)
  • script.js (1 hunks)
🧰 Additional context used
🔇 Additional comments (1)
script.js (1)

161-187: 🛠️ Refactor suggestion

Consolidate multiple 'DOMContentLoaded' event listeners

There are two separate DOMContentLoaded event listeners in the script, which can lead to potential conflicts and increased overhead.

Combine the code within both DOMContentLoaded event listeners into a single listener to improve performance and maintainability:

 document.addEventListener('DOMContentLoaded', () => {
     // Existing code...
+    // Ecotips slider functionality
+    const tipsSlider = document.querySelector('.eco-tips-content');
+    const slides = document.querySelectorAll('.eco-tip');
+    const prevSlide = document.getElementById('prev-slide');
+    const nextSlide = document.getElementById('next-slide');
+    let currentIndex = 0;
+
+    const updateSlider = () => {
+        if (slides.length === 0) return;
+        const slideWidth = slides[0].clientWidth;
+        tipsSlider.style.transform = `translateX(-${currentIndex * slideWidth}px)`;
+    };
+
+    tipsSlider.style.transition = 'transform 0.3s ease-in-out';
+
+    nextSlide?.addEventListener('click', () => {
+        currentIndex = (currentIndex + 1) % slides.length;
+        updateSlider();
+    });
+
+    prevSlide?.addEventListener('click', () => {
+        currentIndex = (currentIndex - 1 + slides.length) % slides.length;
+        updateSlider();
+    });
+
+    window.addEventListener('resize', updateSlider);
+    window.addEventListener('load', updateSlider);
 });

Likely invalid or redundant comment.

console.log(e);
});
lenis.on('scroll', (e) => {
console.log(e);
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

Remove unnecessary console logging

The console.log(e); statement in the smoothScrolling function may not be needed in production code and could clutter the console output.

Consider removing or commenting out the console.log statement:

-        console.log(e);
📝 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
console.log(e);

Comment on lines +169 to +170
const slideWidth = slides[0].clientWidth;
tipsSlider.style.transform = `translateX(-${currentIndex * slideWidth}px)`;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add check for empty slides array to prevent errors

In the updateSlider function, accessing slides[0] without confirming that slides contains elements may result in a runtime error if the array is empty.

Add a check to ensure slides is not empty before proceeding:

         const updateSlider = () => {
+            if (slides.length === 0) return;
             const slideWidth = slides[0].clientWidth;
             tipsSlider.style.transform = `translateX(-${currentIndex * slideWidth}px)`;
         };

This prevents potential errors when the slides are not available.

📝 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 slideWidth = slides[0].clientWidth;
tipsSlider.style.transform = `translateX(-${currentIndex * slideWidth}px)`;
if (slides.length === 0) return;
const slideWidth = slides[0].clientWidth;
tipsSlider.style.transform = `translateX(-${currentIndex * slideWidth}px)`;

Comment on lines +112 to +130
feedbackForm?.addEventListener('submit', (event) => {
event.preventDefault();
const [name, email, message] = ['input[type="text"]', 'input[type="email"]', 'textarea']
.map(selector => feedbackForm.querySelector(selector)?.value.trim());

const nameValid = name?.length >= 2;
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const messageValid = message?.length >= 10;

if (nameValid && emailValid && messageValid) {
alert('Feedback submitted successfully!');
feedbackForm.reset();
} else {
if (!nameValid) feedbackForm.querySelector('input[type="text"]').setCustomValidity('Name must be at least 2 characters long.');
if (!emailValid) feedbackForm.querySelector('input[type="email"]').setCustomValidity('Please enter a valid email address.');
if (!messageValid) alert('Message must be at least 10 characters long.');
feedbackForm.reportValidity();
}
});
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

Ensure consistent validation feedback

In the feedback form validation, setCustomValidity is used for the name and email fields, but an alert is used for the message field. This inconsistency may confuse users.

Use setCustomValidity for the message field to provide consistent validation feedback:

+        // Reset custom validity messages
+        feedbackForm.querySelector('input[type="text"]').setCustomValidity('');
+        feedbackForm.querySelector('input[type="email"]').setCustomValidity('');
+        feedbackForm.querySelector('textarea').setCustomValidity('');

         if (nameValid && emailValid && messageValid) {
             alert('Feedback submitted successfully!');
             feedbackForm.reset();
         } else {
             if (!nameValid) feedbackForm.querySelector('input[type="text"]').setCustomValidity('Name must be at least 2 characters long.');
             if (!emailValid) feedbackForm.querySelector('input[type="email"]').setCustomValidity('Please enter a valid email address.');
-            if (!messageValid) alert('Message must be at least 10 characters long.');
+            if (!messageValid) feedbackForm.querySelector('textarea').setCustomValidity('Message must be at least 10 characters long.');
             feedbackForm.reportValidity();
         }

This approach ensures all validation messages are displayed uniformly.

📝 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
feedbackForm?.addEventListener('submit', (event) => {
event.preventDefault();
const [name, email, message] = ['input[type="text"]', 'input[type="email"]', 'textarea']
.map(selector => feedbackForm.querySelector(selector)?.value.trim());
const nameValid = name?.length >= 2;
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const messageValid = message?.length >= 10;
if (nameValid && emailValid && messageValid) {
alert('Feedback submitted successfully!');
feedbackForm.reset();
} else {
if (!nameValid) feedbackForm.querySelector('input[type="text"]').setCustomValidity('Name must be at least 2 characters long.');
if (!emailValid) feedbackForm.querySelector('input[type="email"]').setCustomValidity('Please enter a valid email address.');
if (!messageValid) alert('Message must be at least 10 characters long.');
feedbackForm.reportValidity();
}
});
feedbackForm?.addEventListener('submit', (event) => {
event.preventDefault();
const [name, email, message] = ['input[type="text"]', 'input[type="email"]', 'textarea']
.map(selector => feedbackForm.querySelector(selector)?.value.trim());
const nameValid = name?.length >= 2;
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const messageValid = message?.length >= 10;
// Reset custom validity messages
feedbackForm.querySelector('input[type="text"]').setCustomValidity('');
feedbackForm.querySelector('input[type="email"]').setCustomValidity('');
feedbackForm.querySelector('textarea').setCustomValidity('');
if (nameValid && emailValid && messageValid) {
alert('Feedback submitted successfully!');
feedbackForm.reset();
} else {
if (!nameValid) feedbackForm.querySelector('input[type="text"]').setCustomValidity('Name must be at least 2 characters long.');
if (!emailValid) feedbackForm.querySelector('input[type="email"]').setCustomValidity('Please enter a valid email address.');
if (!messageValid) feedbackForm.querySelector('textarea').setCustomValidity('Message must be at least 10 characters long.');
feedbackForm.reportValidity();
}
});

script.js Outdated
Comment on lines 17 to 44
function validateForm(formType) {
const form = document.getElementById(formType === 'signup' ? 'form1' : 'form2');
const errorMessage = document.getElementById('error-message');
const fields = Array.from(form.querySelectorAll('input'));

errorMessage.innerText = '';

// Check if fields are empty
if (!fullName || !email || !password1 || !password2) {
if (fields.some(field => !field.value)) {
errorMessage.innerText = 'Please fill all the details.';
return false; // Prevent form submission
}

// Password validation: at least 8 characters, one uppercase, one lowercase, and one special character
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).{8,}$/;
if (!passwordRegex.test(password1)) {
errorMessage.innerText = 'Password must be at least 8 characters long, including uppercase, lowercase, and special characters.';
return false; // Prevent form submission
}

// Check if passwords match
if (password1 !== password2) {
errorMessage.innerText = 'Passwords do not match.';
return false; // Prevent form submission
return false;
}

return true; // Allow form submission
}

function validateLogin() {
const email = document.querySelector('input[name="email"]').value;
const password1 = document.querySelector('input[name="password1"]').value;
const errorMessage = document.getElementById('error-message');
if (formType === 'signup') {
const [password1, password2] = fields.slice(-2).map(field => field.value);
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_]).{8,}$/;

// Clear previous error message
errorMessage.innerText = '';
if (!passwordRegex.test(password1)) {
errorMessage.innerText = 'Password must be at least 8 characters long, including uppercase, lowercase, and special characters.';
return false;
}

// Check if fields are empty
if (!email || !password1) {
errorMessage.innerText = 'Please fill all the details.';
return false; // Prevent form submission
if (password1 !== password2) {
errorMessage.innerText = 'Passwords do not match.';
return false;
}
}

return true; // Allow form submission
return true;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add checks for null elements to prevent runtime errors

In the validateForm function, accessing form and errorMessage without verifying their existence could lead to runtime errors if these elements are not found in the DOM.

Add checks to ensure that form and errorMessage are not null before using them:

         const form = document.getElementById(formType === 'signup' ? 'form1' : 'form2');
+        if (!form) {
+            console.error(`Form with ID '${formType === 'signup' ? 'form1' : 'form2'}' not found.`);
+            return false;
+        }
         const errorMessage = document.getElementById('error-message');
+        if (!errorMessage) {
+            console.error("Error message element not found.");
+            return false;
+        }

Additionally, to prevent conflicts when both forms are present on the same page, consider using form-specific error messages:

-        const errorMessage = document.getElementById('error-message');
+        const errorMessage = form.querySelector('.error-message');

Ensure that each form contains an element with the class error-message to display validation errors.

Committable suggestion was skipped due to low confidence.

@GarimaSingh0109 GarimaSingh0109 merged commit aad9762 into GarimaSingh0109:main Oct 21, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

"Refactor JavaScript: Reduce Redundancy and Implement Modern Practices"
2 participants