Skip to content

Conversation

harley
Copy link
Contributor

@harley harley commented May 9, 2025

Summary by Sourcery

Improve the user experience of the Pulse application by enhancing the UI/UX of multiple screens with more interactive and responsive design elements

New Features:

  • Added keyboard shortcut (Shift + Enter) for quick navigation across screens
  • Implemented previous week's manager and project suggestion feature
  • Added animated transitions and interactions using Framer Motion

Enhancements:

  • Refined UI components with more modern and responsive design
  • Added loading and suggestion states for manager selection
  • Improved form validation and user feedback
  • Enhanced accessibility with better aria labels and keyboard interactions

Chores:

  • Updated component styling to use more consistent design patterns
  • Refactored screen components to improve readability and maintainability

Summary by CodeRabbit

  • New Features

    • Manager selection now suggests last week's manager automatically, with badges indicating if the suggestion is used or overridden.
    • Added animated transitions, improved styling, and a fixed bottom navigation bar with "Back" and "Next" buttons in project selection screens.
    • Introduced Shift+Enter keyboard shortcut to quickly advance steps in relevant screens, with visual hints and accessible labels.
    • Added asynchronous fetching of previous week's manager data to enhance form suggestions.
    • Project selection now advances automatically after submitting an "other" project name.
  • Bug Fixes

    • Enhanced keyboard accessibility and form state synchronization for smoother user interaction.
  • Style

    • Refined UI with consistent button styles, animations, and improved layout for better visual hierarchy and accessibility.

Copy link
Contributor

⏳ I'm reviewing this pull request for security vulnerabilities and code quality issues. I'll provide an update when I'm done

Copy link

vercel bot commented May 9, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
pulse ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 9, 2025 10:22am

Copy link
Contributor

sourcery-ai bot commented May 9, 2025

Reviewer's Guide

This pull request enhances the user experience of the weekly pulse feature. Implementation involved integrating framer-motion for UI animations, refactoring component styles using Card elements and updated CSS for a modern aesthetic, and adding a global 'Shift + Enter' keyboard shortcut for navigation. A new backend action, getPreviousWeekManager, was created to query Supabase for the previous week's manager, which is then used in the ManagerScreen to suggest and pre-fill the manager's email, streamlining the input process.

File-Level Changes

Change Details Files
Enhanced AdditionalProjectsScreen UI with animations and modern styling.
  • Integrated framer-motion for animated transitions and element appearance.
  • Replaced existing layout structures with Card components for improved visual hierarchy.
  • Updated styles for inputs, buttons, project displays, and overall screen layout.
  • Relocated navigation buttons to a fixed, blurred footer for consistent access.
src/components/screens/AdditionalProjectsScreen.tsx
Added functionality to suggest and pre-fill manager based on previous week's data.
  • Developed getPreviousWeekManager server action in actions.ts to fetch manager data from the submissions table via Supabase.
  • Modified ManagerScreen.tsx to call this new action, pre-fill the manager input, and handle loading states.
  • Added UI elements to indicate the source of the suggested manager (e.g., 'Last week's choice', 'Overridden suggestion').
src/components/screens/ManagerScreen.tsx
src/app/actions.ts
Implemented 'Shift + Enter' keyboard shortcut for screen progression.
  • Added useEffect hooks in each specified screen component to attach keydown event listeners.
  • Implemented logic to call the onNext() navigation function when the 'Shift + Enter' key combination is detected.
src/components/screens/AdditionalProjectsScreen.tsx
src/components/screens/ManagerScreen.tsx
src/components/screens/HoursWorkedScreen.tsx
Standardized navigation button appearance and behavior, including conditional enabling.
  • Applied consistent styling (e.g., size, shape, gradients) to 'Back' and 'Next' buttons across the affected screens.
  • Implemented conditional disabling of 'Next' buttons based on whether required form inputs are valid and present.
  • Added a visual hint for the 'Shift + Enter' shortcut directly on the 'Next' buttons.
src/components/screens/AdditionalProjectsScreen.tsx
src/components/screens/ManagerScreen.tsx
src/components/screens/HoursWorkedScreen.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

coderabbitai bot commented May 9, 2025

Caution

Review failed

The pull request is closed.

"""

Walkthrough

A new asynchronous function for fetching the previous week's manager was added. The ManagerScreen component now suggests the prior week's manager email, with UI badges and keyboard shortcut support. The AdditionalProjectsScreen and HoursWorkedScreen components received UI polish, animations, accessibility enhancements, and Shift+Enter keyboard shortcut handling. The ProjectSelectionScreen was updated to proceed automatically after submitting an "other" project.

Changes

File(s) Change Summary
src/app/actions.ts Added getPreviousWeekManager, an async function that retrieves the previous week's manager for a user, handling week/year rollover and querying Supabase.
src/components/screens/AdditionalProjectsScreen.tsx Refactored UI with animations, consistent styling, enhanced accessibility, and a fixed bottom navigation bar. Added Shift+Enter keyboard shortcut for navigation. Improved project selection, input forms, and button feedback.
src/components/screens/HoursWorkedScreen.tsx Added Shift+Enter keyboard shortcut to trigger "Next" when hours are set. Updated "Next" button with shortcut hint, accessibility label, and styling adjustments.
src/components/screens/ManagerScreen.tsx Enhanced to fetch and suggest previous week's manager email. Added state for suggestion and loading, conditional badges, automatic form update, and Shift+Enter shortcut for navigation. Updated button and input feedback. Component signature now accepts userId, currentWeekNumber, and currentYear as optional props.
src/components/screens/ProjectSelectionScreen.tsx Modified to call onNext() immediately after submitting an "other" project name, advancing the flow automatically.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ManagerScreen
    participant Actions as actions.ts (getPreviousWeekManager)
    participant Supabase

    User->>ManagerScreen: Mounts or changes user/week/year
    ManagerScreen->>Actions: getPreviousWeekManager(userId, week, year)
    Actions->>Supabase: Query submissions for previous week/year
    Supabase-->>Actions: Return manager field
    Actions-->>ManagerScreen: Return previous manager email or null
    ManagerScreen->>ManagerScreen: Update state, suggest manager
    User->>ManagerScreen: Inputs manager email or presses Shift+Enter
    ManagerScreen->>ManagerScreen: Validate and trigger onNext if valid
Loading

Possibly related PRs

  • CoderPush/pulse#54: Introduced getPreviousWeekManager and its integration into ManagerScreen, extending the pattern used for fetching previous week's primary project.

Poem

In the warren of code, a new path appears,
Last week’s manager now hops near!
With Shift and Enter, we leap ahead,
Animated screens and badges spread.
UI polished, shortcuts in bloom—
The rabbits rejoice in the coder’s room!
🐇✨
"""

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/components/screens/ProjectSelectionScreen.tsx

Oops! Something went wrong! :(

ESLint: 9.25.1

ESLint couldn't find the plugin "@next/eslint-plugin-next".

(The package "@next/eslint-plugin-next" 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 @next/eslint-plugin-next@latest --save-dev

The plugin "@next/eslint-plugin-next" was referenced from the config file in " » eslint-config-next/core-web-vitals » /node_modules/.pnpm/eslint-config-next@15.3.1_eslint@9.25.1_jiti@2.4.2__typescript@5.8.3/node_modules/eslint-config-next/index.js".

If you still can't figure out the problem, please see https://eslint.org/docs/latest/use/troubleshooting.

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a22018 and 06e8f64.

📒 Files selected for processing (1)
  • src/components/screens/ProjectSelectionScreen.tsx (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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

CodeRabbit Commands (Invoked using PR comments)

  • @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 generate sequence diagram to generate a sequence diagram of the changes in this 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
Contributor

✅ I finished the code review, and left comments with the issues I found. I will now generate code fix suggestions.

Copy link
Contributor

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

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

  • The Shift + Enter keyboard navigation logic is repeated in multiple screen components; consider creating a custom hook for this functionality.
  • The bottom navigation bar is implemented differently across screens (fixed positioning in AdditionalProjectsScreen vs. flexbox mt-auto in others); consider standardizing this approach for consistency.
Here's what I looked at during the review
  • 🟢 General issues: all looks good
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Documentation: all looks good

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 and I'll use the feedback to improve your reviews.

Copy link

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

🔭 Outside diff range comments (1)
src/components/screens/AdditionalProjectsScreen.tsx (1)

44-48: ⚠️ Potential issue

Validate hours > 0 before adding “other” projects

handleOtherProjectSubmit only checks that hoursInput is truthy. A user could enter 0, negative numbers (via copy-paste) or non-numeric text and still bypass UI validation by calling the function programmatically.

- if (otherProject.trim() && hoursInput) {
-   addAdditionalProject(otherProject.trim(), parseInt(hoursInput, 10));
- }
+const hours = parseInt(hoursInput, 10);
+if (otherProject.trim() && Number.isFinite(hours) && hours > 0) {
+  addAdditionalProject(otherProject.trim(), hours);
+}
🧹 Nitpick comments (9)
src/app/actions.ts (1)

61-101: Consider deduplicating “previous-week” logic and tighten parameter checks

getPreviousWeekManager is almost a copy-paste of getPreviousWeekPrimaryProject, differing only in the selected column. Two quick wins:

  1. Extract the week/year rollover calculation and the Supabase fetch into a small helper that receives the column name to select; this keeps actions.ts maintainable and eliminates the risk that one function gets patched while the twin is forgotten.

  2. The guard if (!userId || !currentWeekNumber || !currentYear) treats 0 as “missing”. It would be clearer (and safer for possible future callers) to test for undefined / null explicitly:

- if (!userId || !currentWeekNumber || !currentYear) {
+ if (!userId || currentWeekNumber === undefined || currentYear === undefined) {

Sample refactor skeleton (truncated for brevity):

async function getPreviousWeekValue(
  userId: string,
  week: number,
  year: number,
  field: 'primary_project_name' | 'manager'
): Promise<string | null> {
  /* shared logic … */
}

export const getPreviousWeekManager = (
  id: string, w: number, y: number
) => getPreviousWeekValue(id, w, y, 'manager');

This keeps one source of truth for week arithmetic and error handling.

src/components/screens/HoursWorkedScreen.tsx (2)

19-33: Avoid re-registering the global key listener on every slider tick

Because formData.primaryProject.hours is a dependency, moving the slider from 0 → 80 re-creates the keydown handler up to 80 times. The removal in return avoids leaks, but the churn is unnecessary and may hurt performance on low-powered devices.

A common pattern is to register once on mount and consult a ref to get the latest value:

+import { useEffect, useRef } from 'react';

 const hoursRef = useRef(formData.primaryProject.hours);
 useEffect(() => { hoursRef.current = formData.primaryProject.hours }, [formData.primaryProject.hours]);

 useEffect(() => {
   const handleKeyDown = (e: KeyboardEvent) => {
-    if (e.shiftKey && e.key === 'Enter' && hoursRef.current) {
+    if (e.shiftKey && e.key === 'Enter' && hoursRef.current) {
       e.preventDefault();
       onNext();
     }
   };
   document.addEventListener('keydown', handleKeyDown);
   return () => document.removeEventListener('keydown', handleKeyDown);
-}, [onNext, formData.primaryProject.hours]);
+}, [onNext]);

This keeps the listener stable while still reacting to updated hours.


130-137: Minor a11y nit – “Shift + Enter” hint is invisible to screen readers

Visually the shortcut hint is great, but assistive tech won’t pick it up.
Consider adding aria-describedby linking to a visually-hidden element, or include the shortcut in the button’s aria-label itself, e.g.:

-aria-label="Next step, or press Shift + Enter"
+aria-label="Next step (Shortcut: Shift + Enter)"
src/components/screens/ManagerScreen.tsx (3)

7-7: Redundant prop intersection – ScreenProps already contains these fields

ScreenProps (see types/weekly-pulse.ts) declares userId, currentWeekNumber, and currentYear as optional. The extra & { … } intersection duplicates them:

-export default function ManagerScreen({ … }: ScreenProps & { userId?: string; currentWeekNumber?: number; currentYear?: number }) {
+export default function ManagerScreen({ … }: ScreenProps) {

This keeps the signature concise and avoids drift if the base type changes.


32-40: Trim effect dependencies to avoid unnecessary re-runs

Including the whole formData object causes this effect to fire on unrelated form changes, producing needless renders. Depend only on what you read:

-}, [isLoadingPreviousManager, fetchedPreviousManager, formData.manager, setFormData, formData]);
+}, [isLoadingPreviousManager, fetchedPreviousManager, formData.manager, setFormData]);

96-111: Case-insensitive comparison will make badges more reliable

Emails are not case-sensitive, yet the equality checks use ===, so Alice@corp.com versus alice@corp.com will incorrectly show “Overridden suggestion”. Normalise both sides:

- formData.manager === fetchedPreviousManager
+ formData.manager?.toLowerCase() === fetchedPreviousManager?.toLowerCase()

Do the same for the “overridden” case.

src/components/screens/AdditionalProjectsScreen.tsx (3)

194-202: Always provide a radix to parseInt & avoid implicit NaN handling in the disabled check

parseInt(projectHours) is invoked without a radix, which causes implementation-defined behaviour in non-decimal strings and throws an eslint warning (radix = 10 rule).

In addition, the disabled check parseInt(projectHours) <= 0 silently treats NaN as false, so the “Add” button may become enabled for invalid input like "abc".

- disabled={!projectHours || parseInt(projectHours) <=0}
+ disabled={
+   !projectHours ||
+   Number.isNaN(Number(projectHours)) ||
+   parseInt(projectHours, 10) <= 0
+ }

Apply the same fix to the hoursInput check a few lines below (≈257–258).


91-96: Add type="button" to actionable buttons

By default, a <button> inside a form (or nested future form) submits the form when pressed. Although the current layout doesn’t use a <form> element, adding type="button" is a low-cost safeguard that prevents accidental submissions if the markup changes later, and helps accessibility tools infer intent.

- <button onClick={onNext} …>
+ <button type="button" onClick={onNext} …>

Please update all interactive buttons in this component (Skip, grid items, Add, Other, Back, Next).

Also applies to: 164-176, 195-202, 208-220, 256-261, 276-288


185-194: Set an explicit step attribute on numeric inputs for better UX

The hours inputs currently use type="number" but no step. Adding step="0.5" (or 1) communicates the expected granularity to native pickers and assistive technologies.

- <Input type="number" … min="1" max="80" … />
+ <Input type="number" step="0.5" min="0.5" max="80" … />

Align the same step on both “select from existing” and “other project” paths.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 539cc69 and 548cf73.

📒 Files selected for processing (4)
  • src/app/actions.ts (1 hunks)
  • src/components/screens/AdditionalProjectsScreen.tsx (2 hunks)
  • src/components/screens/HoursWorkedScreen.tsx (3 hunks)
  • src/components/screens/ManagerScreen.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/components/screens/AdditionalProjectsScreen.tsx (2)
src/components/ui/card.tsx (1)
  • Card (85-85)
src/components/ui/input.tsx (1)
  • Input (21-21)
src/components/screens/ManagerScreen.tsx (2)
src/types/weekly-pulse.ts (1)
  • ScreenProps (49-59)
src/app/actions.ts (1)
  • getPreviousWeekManager (61-101)

Comment on lines 13 to +30
useEffect(() => {
if (shouldNavigate) {
onNext();
setShouldNavigate(false);
if (userId && currentWeekNumber && currentYear) {
setIsLoadingPreviousManager(true);
getPreviousWeekManager(userId, currentWeekNumber, currentYear)
.then(manager => {
setFetchedPreviousManager(manager);
})
.catch(error => {
console.error("Failed to fetch previous week's manager:", error);
setFetchedPreviousManager(null);
})
.finally(() => {
setIsLoadingPreviousManager(false);
});
} else {
setIsLoadingPreviousManager(false);
}
}, [shouldNavigate, onNext]);
}, [userId, currentWeekNumber, currentYear]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Prevent state updates after unmount / race conditions when fetching

If the component unmounts (or props change) before the Supabase promise resolves, calling setFetchedPreviousManager or setIsLoadingPreviousManager will warn in React 18. Guard with an “isMounted” flag or abort controller:

 useEffect(() => {
-  if (userId && currentWeekNumber && currentYear) {
+  let cancelled = false;
+  if (userId && currentWeekNumber && currentYear) {
     setIsLoadingPreviousManager(true);
     getPreviousWeekManager(userId, currentWeekNumber, currentYear)
       .then(manager => {
-        setFetchedPreviousManager(manager);
+        if (!cancelled) setFetchedPreviousManager(manager);
       })
       .catch(err => {
-        console.error(…);
-        setFetchedPreviousManager(null);
+        if (!cancelled) {
+          console.error(…);
+          setFetchedPreviousManager(null);
+        }
       })
       .finally(() => {
-        setIsLoadingPreviousManager(false);
+        if (!cancelled) setIsLoadingPreviousManager(false);
       });
   } else {
     setIsLoadingPreviousManager(false);
   }
-}, [userId, currentWeekNumber, currentYear]);
+  return () => { cancelled = true; };
+}, [userId, currentWeekNumber, currentYear]);
📝 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
useEffect(() => {
if (shouldNavigate) {
onNext();
setShouldNavigate(false);
if (userId && currentWeekNumber && currentYear) {
setIsLoadingPreviousManager(true);
getPreviousWeekManager(userId, currentWeekNumber, currentYear)
.then(manager => {
setFetchedPreviousManager(manager);
})
.catch(error => {
console.error("Failed to fetch previous week's manager:", error);
setFetchedPreviousManager(null);
})
.finally(() => {
setIsLoadingPreviousManager(false);
});
} else {
setIsLoadingPreviousManager(false);
}
}, [shouldNavigate, onNext]);
}, [userId, currentWeekNumber, currentYear]);
useEffect(() => {
let cancelled = false;
if (userId && currentWeekNumber && currentYear) {
setIsLoadingPreviousManager(true);
getPreviousWeekManager(userId, currentWeekNumber, currentYear)
.then(manager => {
if (!cancelled) {
setFetchedPreviousManager(manager);
}
})
.catch(error => {
if (!cancelled) {
console.error("Failed to fetch previous week's manager:", error);
setFetchedPreviousManager(null);
}
})
.finally(() => {
if (!cancelled) {
setIsLoadingPreviousManager(false);
}
});
} else {
setIsLoadingPreviousManager(false);
}
return () => { cancelled = true; };
}, [userId, currentWeekNumber, currentYear]);

Copy link
Contributor

⏳ I'm reviewing this pull request for security vulnerabilities and code quality issues. I'll provide an update when I'm done

Copy link
Contributor

✅ I finished the code review, and left comments with the issues I found. I will now generate code fix suggestions.

Copy link
Contributor

⏳ I'm reviewing this pull request for security vulnerabilities and code quality issues. I'll provide an update when I'm done

.maybeSingle();

if (error) {
console.error('Error fetching previous week manager:', error.message);
Copy link
Contributor

Choose a reason for hiding this comment

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

Warning

Description: Log Injection occurs when untrusted user input is directly written to log files without proper sanitization. This can allow attackers to manipulate log entries, potentially leading to security issues like log forging or cross-site scripting. To prevent this, always sanitize user input before logging by removing or encoding newline characters, using string encoding functions, and leveraging built-in sanitization features of logging libraries when available. Learn more - https://cwe.mitre.org/data/definitions/117.html

Severity: High

Copy link
Contributor

Choose a reason for hiding this comment

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

The vulnerability in the original code is Log Injection, which occurs when untrusted user input is directly written to log files without proper sanitization. This can allow attackers to manipulate log entries, potentially leading to security issues like log forging or cross-site scripting.

To address this vulnerability, the following changes were made:

  1. For the error logging from the Supabase query:

    • We assume the existence of a sanitizeLogMessage utility function that sanitizes log messages.
    • The error message is passed through this sanitization function before being logged.
  2. For the catch block:

    • Instead of directly logging the error object, we check if it's an instance of Error and log the message property if so.
    • If it's not an Error instance, we convert it to a string before logging.

These changes help prevent log injection by ensuring that potentially malicious input is sanitized before being written to the logs. The sanitizeLogMessage function (which would need to be implemented separately) should remove or encode newline characters and other potentially dangerous characters.

It's important to note that the actual implementation of sanitizeLogMessage would depend on the specific requirements and the logging system being used. A typical implementation might include:

  • Removing or encoding newline characters
  • Escaping special characters
  • Truncating overly long messages
  • Using string encoding functions

References:

Other examples of log sanitization:

function sanitizeLogMessage(message: string): string {
  return message.replace(/[\r\n]+/g, ' ').slice(0, 1000);
}

// Or using a library like validator.js
import validator from 'validator';

function sanitizeLogMessage(message: string): string {
  return validator.escape(message).slice(0, 1000);
}
Suggested change
console.error('Error fetching previous week manager:', error.message);
.maybeSingle();
if (error) {
// import { sanitizeLogMessage } from './logUtils'; // Utility function to sanitize log messages
console.error('Error fetching previous week manager:', sanitizeLogMessage(error.message));
return null;
}
return data ? data.manager : null;
} catch (err) {
console.error('Unexpected error in getPreviousWeekManager:', err instanceof Error ? err.message : String(err));
return null;
}

Copy link
Contributor

✅ I finished the code review, and left comments with the issues I found. I will now generate code fix suggestions.

setFetchedPreviousManager(manager);
})
.catch(error => {
console.error("Failed to fetch previous week's manager:", error);
Copy link
Contributor

Choose a reason for hiding this comment

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

Warning

Description: Log Injection occurs when untrusted user input is directly written to log files without proper sanitization. This can allow attackers to manipulate log entries, potentially leading to security issues like log forging or cross-site scripting. To prevent this, always sanitize user input before logging by removing or encoding newline characters, using string encoding functions, and leveraging built-in sanitization features of logging libraries when available. Learn more - https://cwe.mitre.org/data/definitions/117.html

Severity: High

Copy link
Contributor

Choose a reason for hiding this comment

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

The vulnerability in the original code is Log Injection, which occurs when untrusted user input is directly written to log files without proper sanitization. This can allow attackers to manipulate log entries, potentially leading to security issues like log forging or cross-site scripting.

To address this vulnerability, the fix involves sanitizing the error message before logging it. The remediation is made by introducing a utility function sanitizeLogMessage that sanitizes the log message before it's passed to console.error.

The fix is implemented as follows:

  1. We assume the existence of a utility function sanitizeLogMessage in the @/utils/logSanitizer module. This function would be responsible for sanitizing the log message.
  2. The error object is converted to a string using error.toString() to ensure we're working with a string value.
  3. The resulting string is then passed through the sanitizeLogMessage function before being logged.

This approach ensures that any potentially malicious content in the error message is sanitized before being written to the log, preventing log injection attacks. The sanitization function would typically remove or encode special characters, newlines, and other potentially harmful elements from the log message.

It's important to note that the actual implementation of sanitizeLogMessage would depend on the specific requirements and potential threats in your application. Common sanitization techniques include:

  • Removing newline characters
  • Encoding special characters
  • Truncating overly long messages
  • Using built-in sanitization features of logging libraries

References:

  1. OWASP Log Injection: https://owasp.org/www-community/attacks/Log_Injection
  2. CWE-117: Improper Output Neutralization for Logs: https://cwe.mitre.org/data/definitions/117.html
  3. NIST: Security and Privacy Controls for Information Systems and Organizations: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-53r5.pdf

Other examples of log sanitization:

// Using a regular expression to remove newlines and limit length
function sanitizeLog(message) {
  return message.replace(/[\r\n]+/g, ' ').substring(0, 1000);
}

// Using a library like DOMPurify for more comprehensive sanitization
import DOMPurify from 'dompurify';

function sanitizeLog(message) {
  return DOMPurify.sanitize(message, { ALLOWED_TAGS: [] });
}
Suggested change
console.error("Failed to fetch previous week's manager:", error);
setFetchedPreviousManager(manager);
})
.catch(error => {
// import { sanitizeLogMessage } from '@/utils/logSanitizer'; // Utility function to sanitize log messages
console.error("Failed to fetch previous week's manager:", sanitizeLogMessage(error.toString()));
})
.finally(() => {
setIsLoadingPreviousManager(false);

Copy link
Contributor

⏳ I'm reviewing this pull request for security vulnerabilities and code quality issues. I'll provide an update when I'm done

@harley harley merged commit 072e924 into main May 9, 2025
1 of 3 checks passed
@harley harley deleted the continue-improving-pulse-ux branch May 9, 2025 10:22
setFetchedPreviousManager(manager);
})
.catch(error => {
console.error("Failed to fetch previous week's manager:", error);
Copy link
Contributor

Choose a reason for hiding this comment

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

Warning

Description: Log Injection occurs when untrusted user input is directly written to log files without proper sanitization. This can allow attackers to manipulate log entries, potentially leading to security issues like log forging or cross-site scripting. To prevent this, always sanitize user input before logging by removing or encoding newline characters, using string encoding functions, and leveraging built-in sanitization features of logging libraries when available. Learn more - https://cwe.mitre.org/data/definitions/117.html

Severity: High

Copy link
Contributor

Choose a reason for hiding this comment

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

The vulnerability in the original code is Log Injection, which occurs when untrusted user input is directly written to log files without proper sanitization. In this case, the error object is being logged directly, which could potentially contain malicious content if manipulated by an attacker.

To fix this vulnerability, we've introduced a sanitization step before logging the error message. The fix involves using a hypothetical utility function called sanitizeLogMessage to clean the error message before it's logged. This function would typically:

  1. Convert the error object to a string
  2. Remove or encode any potentially harmful characters (e.g., newlines, control characters)
  3. Limit the length of the message to prevent log flooding

The remediation is made by replacing:

console.error("Failed to fetch previous week's manager:", error);

with:

console.error("Failed to fetch previous week's manager:", sanitizeLogMessage(error.toString()));

This approach ensures that even if an attacker manages to inject malicious content into the error object, it will be sanitized before being logged, preventing log injection attacks.

It's important to note that the actual implementation of sanitizeLogMessage would depend on the specific requirements and potential threats in your application. In a real-world scenario, you might use a well-tested library for log sanitization or implement a custom function that adheres to your organization's security policies.

References:

  1. OWASP Log Injection: https://owasp.org/www-community/attacks/Log_Injection
  2. CWE-117: Improper Output Neutralization for Logs: https://cwe.mitre.org/data/definitions/117.html

Other examples of log sanitization:

  1. Using a regular expression to remove newlines:
    const sanitizeLog = (message) => message.replace(/[\r\n]+/g, ' ');
  2. Using a library like DOMPurify to sanitize HTML content in logs:
    import DOMPurify from 'dompurify';
    const sanitizeLog = (message) => DOMPurify.sanitize(message);
Suggested change
console.error("Failed to fetch previous week's manager:", error);
setFetchedPreviousManager(manager);
})
.catch(error => {
// import { sanitizeLogMessage } from '@/utils/logSanitizer'; // Utility function to sanitize log messages
console.error("Failed to fetch previous week's manager:", sanitizeLogMessage(error.toString()));
})
.finally(() => {
setIsLoadingPreviousManager(false);

.maybeSingle();

if (error) {
console.error('Error fetching previous week manager:', error.message);
Copy link
Contributor

Choose a reason for hiding this comment

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

Warning

Description: Log Injection occurs when untrusted user input is directly written to log files without proper sanitization. This can allow attackers to manipulate log entries, potentially leading to security issues like log forging or cross-site scripting. To prevent this, always sanitize user input before logging by removing or encoding newline characters, using string encoding functions, and leveraging built-in sanitization features of logging libraries when available. Learn more - https://cwe.mitre.org/data/definitions/117.html

Severity: High

Copy link
Contributor

Choose a reason for hiding this comment

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

The vulnerability in the original code is Log Injection, which occurs when untrusted user input is directly written to log files without proper sanitization. This can allow attackers to manipulate log entries, potentially leading to security issues like log forging or cross-site scripting.

To address this vulnerability, the following changes were made:

  1. For the error logging from the Supabase query:

    • A sanitization function sanitizeLogMessage is used to clean the error message before logging.
    • This function should be implemented to remove or encode any potentially harmful characters or sequences.
  2. For the catch block:

    • Instead of directly logging the error object, we check if it's an instance of Error and log only the message.
    • If it's not an Error instance, we convert it to a string before logging.

These changes help prevent log injection by ensuring that the logged content is properly sanitized and doesn't contain any malicious data that could be interpreted as log commands or script content.

The sanitizeLogMessage function (which should be implemented separately) could use techniques such as:

  • Removing or encoding newline characters
  • Escaping special characters
  • Truncating overly long messages
  • Using string encoding functions

It's important to note that the specific implementation of sanitizeLogMessage would depend on the logging system being used and the potential attack vectors relevant to your application.

References:

Other examples of log sanitization:

// Using a regular expression to remove newlines and limit length
function sanitizeLog(message: string): string {
  return message.replace(/[\r\n]+/g, ' ').substring(0, 1000);
}

// Using a library like validator.js
import validator from 'validator';

function sanitizeLog(message: string): string {
  return validator.escape(message).substring(0, 1000);
}

Always ensure that your logging practices are secure and that you're not inadvertently exposing sensitive information through your logs.

Suggested change
console.error('Error fetching previous week manager:', error.message);
.maybeSingle();
if (error) {
// import { sanitizeLogMessage } from './logUtils'; // Utility function to sanitize log messages
console.error('Error fetching previous week manager:', sanitizeLogMessage(error.message));
return null;
}
return data ? data.manager : null;
} catch (err) {
console.error('Unexpected error in getPreviousWeekManager:', err instanceof Error ? err.message : String(err));
return null;
}

Copy link
Contributor

✅ I finished the code review, and left comments with the issues I found. I will now generate code fix suggestions.

@harley harley restored the continue-improving-pulse-ux branch June 5, 2025 07:39
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.

1 participant