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

[Feat]: Improve AddManuel with form handling and error check #3426

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from

Conversation

Innocent-Akim
Copy link
Contributor

@Innocent-Akim Innocent-Akim commented Dec 13, 2024

Description

Please include a summary of the changes and the related issue.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my 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

Previous screenshots

Please add here videos or images of previous status

Current screenshots

Please add here videos or images of previous status

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced form management in the Add Task modal, including improved validation and error handling.
    • New date manipulation functions (toLocal, toUTC) for better date handling.
    • Updated time option formatting to include seconds in the Timelog filter options.
    • Modifications to the CustomSelect component for improved option handling and styling flexibility.
  • Bug Fixes

    • Improved error handling in the Add Task modal for shift data validation.
  • Refactor

    • Transitioned to manual data handling in the DataTableTimeSheet component, simplifying task display logic.

Copy link
Contributor

coderabbitai bot commented Dec 13, 2024

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.

apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx

Oops! Something went wrong! :(

ESLint: 8.46.0

ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct.

The config "next/core-web-vitals" was referenced from the config file in "/apps/web/.eslintrc.json".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

Walkthrough

This pull request introduces modifications across several files related to timesheet management and UI components. The changes primarily focus on enhancing form state management, date handling, and time-related functionalities. Key updates include a new FormState interface in AddTaskModal.tsx, additional date conversion utilities in date.ts, time option generation improvements in useTimelogFilterOptions.ts, and significant refactoring of the DataTableTimeSheet component to simplify table management.

Changes

File Change Summary
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx Added FormState interface, enhanced error handling in handleAddTimesheet, updated shift timing and validation logic
apps/web/app/helpers/date.ts Introduced toLocal and toUTC functions for date conversion and manipulation
apps/web/app/hooks/features/useTimelogFilterOptions.ts Modified generateTimeOptions to append :00 to time strings
apps/web/lib/features/integrations/calendar/table-time-sheet.tsx Removed @tanstack/react-table dependencies, simplified table management, introduced direct handling of sorting and status updates
apps/web/lib/features/multiple-select/index.tsx Updated CustomSelect to use option index as key, added classNameGroup property

Sequence Diagram

sequenceDiagram
    participant User
    participant AddTaskModal
    participant DateHelper
    participant TimelogFilterOptions
    
    User->>AddTaskModal: Open Modal
    AddTaskModal->>DateHelper: Convert Dates
    AddTaskModal->>TimelogFilterOptions: Generate Time Options
    User->>AddTaskModal: Fill Form
    AddTaskModal->>AddTaskModal: Validate Shifts
    AddTaskModal->>AddTaskModal: Create Timesheet Entry
Loading

Possibly related PRs

Suggested reviewers

  • evereq

Poem

🐰 Timesheets dance with grace and might,
Shifts align, dates take flight!
Seconds tick, moments gleam,
In CodeRabbit's coding dream 🕰️
Validation's magic, clear and bright! 🌟

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. This feature will be included in our Pro Plan when released.


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. (Beta)
  • @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.

@Innocent-Akim Innocent-Akim self-assigned this Dec 13, 2024
@Innocent-Akim Innocent-Akim changed the title [Feat]: Improve AddTaskModal with form handling and error check [Feat]: Improve AddManuel with form handling and error check Dec 13, 2024
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 (4)
apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (1)

Line range hint 86-99: Handle No Selection in handleButtonClick Function

In the Approved case of handleButtonClick, no action is taken if selectTimesheetId.length is zero. Consider providing user feedback or disabling the action buttons when no timesheets are selected to enhance user experience.

Apply this diff to provide user feedback:

 case 'Approved':
     if (selectTimesheetId.length > 0) {
         await updateTimesheetStatus({
             status: 'APPROVED',
             ids: selectTimesheetId
         });
+    } else {
+        toast({
+            title: 'No Timesheets Selected',
+            description: 'Please select at least one timesheet to approve.',
+            variant: 'warning',
+        });
     }
     break;
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (3)

185-187: Ensure Readability with Proper Theming in CustomSelect

The classNameGroup='max-h-[40vh] !text-white ' and className='w-full font-medium text-white' additions ensure that text is visible in dark mode. Consider verifying that these class names align with your theming strategy.

Apply this diff to ensure consistent theming:

 classNameGroup='max-h-[40vh] !text-white '
 className='w-full font-medium text-white'
+ // Ensure the text color adapts based on the theme

354-354: Initialize totalHours with Correct Format

When adding a new shift, the totalHours is initialized with '00:00:00 h'. Ensure it matches the format used elsewhere, such as '00:00h'.

Apply this diff:

- { startTime: '', endTime: '', totalHours: '00:00:00 h', dateFrom: new Date() }
+ { startTime: '', endTime: '', totalHours: '00:00h', dateFrom: new Date() }

468-476: Update Placeholders to Reflect Time Format

The placeholders in ShiftTimingSelect have been updated to '00:00:00', but since time options are in the format 'HH:MM', consider updating them to '00:00' for consistency.

Apply this diff:

- placeholder="00:00:00"
+ placeholder="00:00"
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3a15c2f and 921f9f6.

📒 Files selected for processing (6)
  • apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (10 hunks)
  • apps/web/app/helpers/date.ts (1 hunks)
  • apps/web/app/hooks/features/useTimelogFilterOptions.ts (1 hunks)
  • apps/web/app/interfaces/timer/ITimerLog.ts (1 hunks)
  • apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (7 hunks)
  • apps/web/lib/features/multiple-select/index.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/app/hooks/features/useTimelogFilterOptions.ts
🔇 Additional comments (13)
apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (3)

4-4: Appropriate Import of 'MoreHorizontal' Icon

The import of MoreHorizontal from 'lucide-react' is necessary for the TaskActionMenu component to display the menu icon.


30-30: Importing 'ConfirmStatusChange' and 'statusOptions'

The addition of ConfirmStatusChange and statusOptions imports is appropriate, as they are used within the SelectFilter component.


51-51: Correct Use of Imported Interfaces

The imported interfaces IUser, TimeLogType, TimesheetLog, and TimesheetStatus are appropriately used for type annotations across the component.

apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (5)

26-37: Define FormState Interface for Form Management

The introduction of the FormState interface enhances form state management by providing strong typing for form fields, improving code readability and maintainability.


94-98: Encapsulate Date Conversion with createUtcDate Function

Moving the createUtcDate function inside handleAddTimesheet encapsulates its usage and prevents unnecessary exposure, promoting better function scope management.


99-140: Enhance Error Handling in handleAddTimesheet

The updated handleAddTimesheet function includes comprehensive error handling and validation, ensuring shifts are provided and time entries are valid.


268-268: Pass Correct Parameters to handleAddTimesheet

The onClick handler now correctly passes formState to handleAddTimesheet, ensuring that the form data is submitted as intended.


Line range hint 362-373: Validate Shift Times to Prevent Overlaps and Invalid Durations

The shift change handler now includes validation to prevent overlapping shifts and ensure the end time is after the start time. This enhances data integrity.

apps/web/app/interfaces/timer/ITimerLog.ts (1)

91-92: Update logType and source Properties to Use Enums

Changing the logType and source properties to use the TimeLogType and TimerSource enums allows for greater flexibility and type safety.

apps/web/lib/features/multiple-select/index.tsx (3)

Line range hint 22-23: Add classNameGroup to CustomSelectProps

Including classNameGroup in the CustomSelectProps interface allows for additional styling flexibility of the SelectGroup component.


Line range hint 146-149: Set Default ariaLabel for Accessibility

Setting the ariaLabel to default to "Select an option" improves accessibility for screen readers when no label is provided.


161-162: Avoid Duplicate Keys When Options Have Identical Values

If value is not unique across options, using it as a key may cause rendering issues. Ensure that each value is unique or consider using another unique property.

Run the following script to check for duplicate value entries in options:

apps/web/app/helpers/date.ts (1)

230-236: Consider modernizing date handling approach

While the implementation is functional, there are some architectural considerations:

  1. Moment.js is in maintenance mode and not recommended for new projects. Consider using modern alternatives like:

    • date-fns for functional date manipulation
    • luxon for timezone handling
    • Native Temporal API (when it becomes stable)
  2. The current implementation might have inconsistent behavior with different input types. Consider:

    • Documenting expected behavior for each input type
    • Adding JSDoc comments with examples
    • Adding type guards for more precise type safety
  3. These functions should be part of a broader timezone strategy. Consider:

    • Documenting the project's timezone handling approach
    • Ensuring consistent timezone handling across the application
    • Adding tests for various timezone scenarios

Let's verify the usage of these functions:

apps/web/app/helpers/date.ts Show resolved Hide resolved
apps/web/app/helpers/date.ts Outdated Show resolved Hide resolved
@Innocent-Akim Innocent-Akim marked this pull request as draft December 13, 2024 20:51
@Innocent-Akim Innocent-Akim marked this pull request as ready for review December 14, 2024 10:58
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: 2

🧹 Outside diff range and nitpick comments (5)
apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (2)

Line range hint 88-105: Complete the 'Denied' status handling in handleButtonClick

While the function handles 'Approved' and 'Deleted' cases well, the 'Denied' case only opens a modal without implementing the actual status update.

Apply this diff to complete the implementation:

 case 'Denied':
-  openModal();
+  if (selectTimesheetId.length > 0) {
+    openModal();
+    // Handle the actual status update after modal confirmation
+    // This should be implemented in the RejectSelectedModal's onReject callback
+  }
   break;

Line range hint 489-517: Enhance sort indicators in HeaderColumn component

The sort indicators (arrows) are currently static. Consider making them dynamic based on the current sort state for better user experience.

Apply this diff to enhance the indicators:

 <MdKeyboardArrowUp
   style={{
     height: 10,
-    color: "#71717A",
+    color: currentSort === "DESC" ? "#000000" : "#71717A",
   }}
 />
 <MdKeyboardArrowDown
   style={{
     height: 10,
-    color: "#71717A",
+    color: currentSort === "ASC" ? "#000000" : "#71717A",
   }}
 />
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (3)

26-37: Consider enhancing type safety in FormState interface

The interface structure is good, but could be improved with:

  • More specific types for time strings
  • Required/optional markers for fields
  • Validation constraints through branded types
 interface FormState {
-    isBillable: boolean;
-    notes: string;
-    projectId: string;
-    taskId: string;
-    employeeId: string;
-    shifts: {
-        dateFrom: Date;
-        startTime: string;
-        endTime: string;
-    }[];
+    isBillable: boolean;
+    notes: string;
+    projectId: string;
+    taskId: string;
+    employeeId: string;
+    shifts: Array<{
+        dateFrom: Date;
+        startTime: `${number}:${number}`;  // HH:mm format
+        endTime: `${number}:${number}`;    // HH:mm format
+    }>;
 }

Line range hint 374-392: Refactor time overlap validation logic

The time overlap checking logic should be extracted into a separate function for better maintainability and reusability.

+const isTimeOverlapping = (
+  currentStart: number,
+  currentEnd: number,
+  shiftStart: number,
+  shiftEnd: number
+): boolean => {
+  return (
+    (currentStart < shiftEnd && currentEnd > shiftStart) ||
+    (currentStart === shiftStart && currentEnd === shiftEnd)
+  );
+};

 if (convertToMinutesHour(startTime) >= convertToMinutesHour(endTime)) {
     return;
 }
 updatedShifts[index].totalHours = calculateTotalHoursHour(startTime, endTime);
-const isOverlapping = shifts.some((shift, i) => {
-    if (i === index || !shift.startTime || !shift.endTime) return false;
-
-    const currentStart = convertToMinutesHour(startTime);
-    const currentEnd = convertToMinutesHour(endTime);
-    const shiftStart = convertToMinutesHour(shift.startTime);
-    const shiftEnd = convertToMinutesHour(shift.endTime);
-    return (
-        (currentStart < shiftEnd && currentEnd > shiftStart) ||
-        (currentStart === shiftStart && currentEnd === shiftEnd)
-    );
-});
+const isOverlapping = shifts.some((shift, i) => 
+  i !== index && 
+  shift.startTime && 
+  shift.endTime && 
+  isTimeOverlapping(
+    convertToMinutesHour(startTime),
+    convertToMinutesHour(endTime),
+    convertToMinutesHour(shift.startTime),
+    convertToMinutesHour(shift.endTime)
+  )
+);

469-477: Improve accessibility for time selection controls

Add appropriate aria-labels and roles to improve accessibility.

 <ShiftTimingSelect
     label="Start"
     timeOptions={timeOptions}
     placeholder="00:00:00"
+    aria-label={t('aria.START_TIME_SELECTOR')}
     className="bg-[#30B3661A]"
     value={value.startTime}
     onChange={(value) => onChange(index, 'startTime', value)}
 />
 <ShiftTimingSelect
     label="End"
     timeOptions={timeOptions}
     placeholder="00:00:00"
+    aria-label={t('aria.END_TIME_SELECTOR')}
     className="bg-[#DA27271A]"
     value={value.endTime}
     onChange={(value) => onChange(index, 'endTime', value)}
 />
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 921f9f6 and 3931774.

📒 Files selected for processing (3)
  • apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (9 hunks)
  • apps/web/app/helpers/date.ts (1 hunks)
  • apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (5 hunks)
🔇 Additional comments (5)
apps/web/app/helpers/date.ts (2)

238-240: 🛠️ Refactor suggestion

Add input validation to maintain consistency with toLocal

The toUTC function should validate input dates consistently with the toLocal function to maintain a uniform error handling approach across the codebase.

Apply this diff to add validation:

 export function toUTC(date: string | Date | moment.Moment): moment.Moment {
-  return moment(date).utc();
+  const utcDate = moment(date);
+  if (!utcDate.isValid()) {
+    throw new Error('Invalid date provided to toUTC');
+  }
+  return utcDate.utc();
 }

230-240: Verify the impact of these date conversion functions

Let's ensure that the changes to these date conversion functions won't cause breaking changes in the codebase.

apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (2)

Line range hint 83-87: Implement sorting logic in handleSort function

The function currently only logs the sorting action without implementing the actual sorting logic.


Line range hint 519-597: Consider lifting sort state management

The sort state is currently managed locally in the HeaderRow component. Consider lifting it up to maintain sort state across re-renders and enable server-side sorting.

Let's verify if the parent components are prepared for this change:

apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (1)

355-355: ⚠️ Potential issue

Fix inconsistent time format

The totalHours format '00:00:00 h' is inconsistent with the rest of the application.

-{ startTime: '', endTime: '', totalHours: '00:00:00 h', dateFrom: new Date() },
+{ startTime: '', endTime: '', totalHours: '00:00h', dateFrom: new Date() },

Likely invalid or redundant comment.

@Innocent-Akim Innocent-Akim requested a review from evereq December 14, 2024 11:11
@@ -381,41 +258,6 @@ export function DataTableTimeSheet({ data, user }: { data?: GroupedTimesheet[],
}
)}
</div>
<div className="flex items-center justify-end p-4 space-x-2">
Copy link
Member

Choose a reason for hiding this comment

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

@Innocent-Akim why that whole block was added and now removed? What was function of it? Did you replaced it with something else or it was not needed at all or what?

Copy link
Contributor Author

@Innocent-Akim Innocent-Akim Dec 19, 2024

Choose a reason for hiding this comment

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

@evereq I removed this code because it was related to the pagination functions of this Shadcn table.

@@ -183,28 +80,7 @@ export function DataTableTimeSheet({ data, user }: { data?: GroupedTimesheet[],
};

const t = useTranslations();
const [sorting, setSorting] = React.useState<SortingState>([]);
Copy link
Member

Choose a reason for hiding this comment

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

@Innocent-Akim why that whole block was added and now removed? What was function of it? Did you replaced it with something else or it was not needed at all or what?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@evereq It's almost the same, except that when I used the hook to dispatch the data to the table, I analyzed how to reuse the same code. I realized it was impossible because it was tailored to the Shadcn table. Then, I understood that it was very important to remove it to make the code clearer.

@@ -67,94 +52,6 @@ import { IUser, TimesheetLog, TimesheetStatus } from '@/app/interfaces';
import { toast } from '@components/ui/use-toast';
import { ToastAction } from '@components/ui/toast';

export const columns: ColumnDef<TimeSheet>[] = [
Copy link
Member

Choose a reason for hiding this comment

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

@Innocent-Akim why that whole block was added and now removed? What was function of it? Did you replaced it with something else or it was not needed at all or what?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@evereq Here, I simply removed the table headers. With the new design, I realized that using a Shadcn table was no longer necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants