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]: Add time Entry Modal and Update Timesheet Status based on API response #3365

Merged
merged 7 commits into from
Nov 24, 2024

Conversation

Innocent-Akim
Copy link
Contributor

@Innocent-Akim Innocent-Akim commented Nov 23, 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 AddTaskModal with improved time entry options and a new layout for managing shifts.
    • Introduced ShiftTimingSelect for selecting start and end times.
    • Added ViewToggleButton for switching between "ListView" and "CalendarView" in the timesheet.
    • Implemented error handling for date selection in TimesheetFilterDate.
  • Improvements

    • Updated UI elements in EditTaskModal for better visual consistency.
    • Improved accessibility with updated labels and aria attributes.
    • Refined filtering logic for tasks in the timesheet to support case-insensitive searches.
    • Enhanced StatusTask component to link status updates directly to timesheet IDs.
    • Added optional classNameTitle property to ManageOrMemberComponent for customizable styling.
  • Bug Fixes

    • Fixed date range selection logic to prevent invalid ranges.

Copy link
Contributor

coderabbitai bot commented Nov 23, 2024

Walkthrough

The changes in this pull request enhance the functionality and user experience of the timesheet management components within the application. Key modifications include the introduction of new components and hooks for managing time entries, updating modal interfaces, improving date selection logic, and implementing status updates for timesheets. These updates also involve refining UI elements for better accessibility and visual consistency across different themes. Overall, the changes streamline the interactions related to timesheet management.

Changes

File Change Summary
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx Added useTimelogFilterOptions hook, implemented state management for dateRange, updated modal title, integrated OptimizedAccordion for managing shifts, and refined UI elements for better accessibility and styling.
apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx Modified state initialization for date and time, updated button styles, and adjusted label colors for improved visual consistency.
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx Enhanced date selection logic with error handling for date ranges, updated isDateDisabled checks, and improved handlePresetClick functionality for custom date ranges.
apps/web/app/[locale]/timesheet/[memberId]/page.tsx Adjusted count prop for TimesheetCard, refined filtering logic for tasks, and updated breadcrumb navigation.
apps/web/app/api/timer/timesheet/status/route.ts Introduced a new asynchronous PUT function to update timesheet status with authentication checks and request handling.
apps/web/app/hooks/features/useTimelogFilterOptions.ts Added state atom timesheetUpdateStatus, introduced generateTimeOptions function for time slot generation, and updated the return object of the hook.
apps/web/app/hooks/features/useTimesheet.ts Added updateTimesheetStatus function for updating timesheet statuses, integrated puTimesheetStatus into the return object, and updated dependencies in useEffect.
apps/web/app/hooks/useScrollListener.ts Introduced a new useInfinityScroll hook for managing infinite scrolling functionality with state management for items and loading status.
apps/web/app/interfaces/IDailyPlan.ts Added a new interface IUpdateTimesheetStatus to define properties for updating timesheet statuses.
apps/web/app/interfaces/timer/ITimerLog.ts Introduced UpdateTimesheetStatus interface extending BaseEntity for better timesheet management.
apps/web/app/services/client/api/timer/timer-log.ts Added updateStatusTimesheetFromApi function for updating timesheet status via API, with necessary imports and request handling.
apps/web/app/services/server/requests/timesheet.ts Introduced updateStatusTimesheetRequest function for constructing requests to update timesheet statuses.
apps/web/app/stores/time-logs.ts Added timesheetUpdateStatus atom for managing timesheet update states and updated imports accordingly.
apps/web/components/ui/accordion.tsx Modified AccordionTrigger to adjust the rendering of the ChevronDown icon for visual orientation.
apps/web/lib/features/integrations/calendar/table-time-sheet.tsx Updated StatusTask component to accept ids for linking timesheet updates to selected statuses, enhancing status management functionality.
apps/web/lib/features/manual-time/manage-member-component.tsx Added optional classNameTitle property to ManageOrMemberComponentProps for customizable styling of label elements.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant AddTaskModal
    participant TimesheetFilterDate
    participant TimesheetAPI

    User->>AddTaskModal: Open modal
    AddTaskModal->>TimesheetFilterDate: Request date options
    TimesheetFilterDate-->>AddTaskModal: Return valid date range
    User->>AddTaskModal: Select date and enter task details
    AddTaskModal->>TimesheetAPI: Send task data
    TimesheetAPI-->>AddTaskModal: Confirm task creation
    AddTaskModal-->>User: Close modal and show confirmation
Loading

Possibly related PRs

Suggested reviewers

  • evereq
  • Cedric921

🐇 In the land of tasks and time,
A modal shines, oh so sublime!
With shifts and dates all in a row,
Adding entries, watch them grow!
From gray to bright, the buttons gleam,
In our timesheet world, we dream! 🌟

Warning

Rate limit exceeded

@Innocent-Akim has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 21 minutes and 30 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 4028c8b and c586bff.

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 (1.23.1)

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.


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.

@Innocent-Akim Innocent-Akim assigned Innocent-Akim and evereq and unassigned evereq Nov 23, 2024
@Innocent-Akim Innocent-Akim added feature WEB Web app Improvement Improvement Don't Merge Do not merge this PR until label not removed Ever Teams labels Nov 23, 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: 20

🧹 Outside diff range and nitpick comments (25)
apps/web/app/stores/time-logs.ts (1)

21-21: LGTM! New atom aligns with feature requirements

The timesheetUpdateStatus atom is well-structured for managing timesheet status updates:

  • Follows consistent naming convention with other atoms
  • Properly typed with UpdateTimesheetStatus[]
  • Initialized with a safe empty array default

Consider documenting the shape of UpdateTimesheetStatus and the purpose of this atom in a comment, as it plays a crucial role in the new time entry modal feature.

apps/web/app/api/timer/timesheet/status/route.ts (1)

6-28: Consider adding rate limiting for this sensitive endpoint.

Since this endpoint modifies timesheet statuses, it should be protected against potential abuse through rate limiting. This is especially important for endpoints that modify data.

Consider implementing rate limiting using Next.js middleware or a service like Redis to track and limit requests per user/IP.

apps/web/app/hooks/useScrollListener.ts (3)

Line range hint 14-14: Remove debugging console.log statement

This console.log statement appears to be debugging code that should be removed from production code.

-    console.log(window.scrollY);

27-31: Add TypeScript return type definition

The hook's return type should be explicitly defined for better type safety and documentation.

-export const useInfinityScroll = (timesheet: TimesheetLog[]) => {
+export const useInfinityScroll = (timesheet: TimesheetLog[]): {
+  items: TimesheetLog[];
+  page: number;
+  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
+  setItems: React.Dispatch<React.SetStateAction<TimesheetLog[]>>;
+} => {

24-48: Clean up unnecessary empty lines

Remove excessive empty lines to improve code readability while maintaining a clear separation between hooks.

 }
-
-
-
 export const useInfinityScroll = (timesheet: TimesheetLog[]) => {
-
   const [items, setItems] = React.useState<TimesheetLog[]>(timesheet);
   const [page, setPage] = React.useState(1);
   const [isLoading, setIsLoading] = React.useState(false);
-
-
   React.useEffect(() => {
     // ... effect implementation
   }, [isLoading]);
-
-
   return { items, page, setIsLoading, setItems }
 }
apps/web/app/interfaces/IDailyPlan.ts (1)

41-46: Consider splitting the interface for better type safety.

The ids field accepting both array and single ID could lead to inconsistent handling in implementations. Consider creating separate interfaces for single and bulk updates.

export interface IUpdateTimesheetStatusBase {
  organizationId?: ID,
  status: ID,
  tenantId?: ID
}

export interface IUpdateSingleTimesheetStatus extends IUpdateTimesheetStatusBase {
  id: ID
}

export interface IUpdateBulkTimesheetStatus extends IUpdateTimesheetStatusBase {
  ids: ID[]
}

// Usage example:
type IUpdateTimesheetStatus = IUpdateSingleTimesheetStatus | IUpdateBulkTimesheetStatus;
apps/web/app/hooks/features/useTimelogFilterOptions.ts (1)

Line range hint 1-51: Consider splitting the hook for better separation of concerns

The hook is handling multiple responsibilities:

  1. Timesheet filtering
  2. Time slot generation
  3. Status management
  4. Group by days functionality

Consider splitting this into more focused hooks:

  • useTimesheetFilters for filter-related state
  • useTimeSlots for time generation
  • useTimesheetStatus for status management

This would improve maintainability and make the code more modular. Would you like assistance in implementing this separation?

apps/web/app/services/server/requests/timesheet.ts (1)

101-109: Consider adding specific error handling

While the implementation is correct and follows the established patterns, consider adding specific error handling for status update failures, as they might need special handling in the UI.

 export function updateStatusTimesheetRequest(params: IUpdateTimesheetStatus, bearer_token: string) {
-	return serverFetch<UpdateTimesheetStatus[]>({
+	return serverFetch<UpdateTimesheetStatus[]>({
 		path: '/timesheet/status',
 		method: 'PUT',
 		body: { ...params },
 		bearer_token,
 		tenantId: params.tenantId,
-	})
+	}).catch(error => {
+		// Handle specific status update errors
+		console.error('Failed to update timesheet status:', error);
+		throw error;
+	});
 }
apps/web/app/interfaces/timer/ITimerLog.ts (2)

115-117: Remove redundant property declarations

The properties isActive, isArchived, and archivedAt are already inherited from BaseEntity. Remove these redundant declarations to avoid potential inconsistencies.


129-135: Extract status type for reusability

The status union type could be useful in other parts of the codebase. Consider extracting it into a separate type declaration.

export type TimesheetStatus = "DRAFT" | "PENDING" | "IN REVIEW" | "DENIED" | "APPROVED";
apps/web/app/services/client/api/timer/timer-log.ts (1)

125-129: Consider architectural improvements for robustness

For production-grade reliability, consider these architectural improvements:

  1. Add retry logic for transient failures
  2. Implement rate limiting for bulk status updates
  3. Add request cancellation support for pending requests

This would make the function more resilient to network issues and prevent potential API abuse.

apps/web/lib/features/manual-time/manage-member-component.tsx (2)

97-97: Add JSDoc documentation for the new prop.

The new classNameTitle prop should be documented in the interface's JSDoc comments to maintain consistency with other props.

Add the following documentation:

     */
    itemToValue: (item: T | null, valueKey: string) => string;

+    /**
+     * Optional CSS class name to be applied to the label title.
+     * @type {string}
+     */
    classNameTitle?: string

121-121: Consider extracting the default text size to a theme constant.

The hardcoded text size "text-[14px]" could be moved to a theme constant or CSS variable for better maintainability and consistency across the application.

Consider refactoring to use a theme constant:

-<span className={clsxm("text-[14px]", classNameTitle)}>{field.label}</span>
+<span className={clsxm("text-default", classNameTitle)}>{field.label}</span>

Then define the size in your theme or CSS:

.text-default {
  font-size: 14px;
}
apps/web/app/[locale]/timesheet/[memberId]/page.tsx (3)

51-52: Consider removing unnecessary empty lines.

These consecutive empty lines don't improve readability and could be removed to maintain better code density.


122-122: Good improvement using dynamic count, but add a safety check.

The change from a hardcoded value to a dynamic count is a good improvement. However, consider adding a null/undefined check for better reliability.

-count={statusTimesheet.PENDING.length}
+count={statusTimesheet?.PENDING?.length ?? 0}

Line range hint 54-67: Add optional chaining for safer object access in filter logic.

The search implementation is well-optimized with useMemo, but could benefit from additional null checks using optional chaining for better reliability.

 const filterDataTimesheet = useMemo(() => {
   const filteredTimesheet =
     timesheet
       .filter((v) =>
         v.tasks.some(
           (task) =>
-            task.task?.title?.toLowerCase()?.includes(lowerCaseSearch) ||
-            task.employee?.fullName?.toLowerCase()?.includes(lowerCaseSearch) ||
-            task.project?.name?.toLowerCase()?.includes(lowerCaseSearch)
+            task?.task?.title?.toLowerCase()?.includes(lowerCaseSearch) ||
+            task?.employee?.fullName?.toLowerCase()?.includes(lowerCaseSearch) ||
+            task?.project?.name?.toLowerCase()?.includes(lowerCaseSearch)
         )
       );

   return filteredTimesheet;
 }, [
   timesheet,
   lowerCaseSearch,
 ]);
apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx (3)

Line range hint 39-57: Add null checks and improve date handling

The state initialization logic needs improvement in several areas:

  1. Missing null checks could lead to runtime errors
  2. Time formatting doesn't handle invalid dates
  3. No explicit timezone handling which could cause inconsistencies

Consider applying these improvements:

 const [dateRange, setDateRange] = useState<{ from: Date | null }>({
-  from: dataTimesheet.timesheet?.startedAt ? new Date(dataTimesheet.timesheet.startedAt) : new Date(),
+  from: dataTimesheet.timesheet?.startedAt 
+    ? new Date(dataTimesheet.timesheet.startedAt) 
+    : new Date(),
 });

+const formatTimeWithFallback = (dateString: string | undefined): string => {
+  if (!dateString) return '';
+  try {
+    const date = new Date(dateString);
+    if (isNaN(date.getTime())) return '';
+    return date.toLocaleTimeString('en-US', { 
+      hour12: false,
+      timeZone: 'UTC' // Or your preferred timezone
+    }).slice(0, 5);
+  } catch {
+    return '';
+  }
+};

 const [endTime, setEndTime] = useState<string>(
-  dataTimesheet.timesheet?.stoppedAt
-    ? new Date(dataTimesheet.timesheet.stoppedAt).toLocaleTimeString('en-US', { hour12: false }).slice(0, 5)
-    : ''
+  formatTimeWithFallback(dataTimesheet.timesheet?.stoppedAt)
 );

 const [startTime, setStartTime] = useState<string>(
-  dataTimesheet.timesheet?.startedAt
-    ? new Date(dataTimesheet.timesheet.startedAt).toLocaleTimeString('en-US', { hour12: false }).slice(0, 5)
-    : ''
+  formatTimeWithFallback(dataTimesheet.timesheet?.startedAt)
 );

Line range hint 175-223: Improve form validation and user experience

The current form validation has several issues:

  1. Empty notes show error state immediately without user interaction
  2. No error messages are displayed for required fields
  3. Required attributes are set but no form element exists

Consider these improvements:

+ const [touched, setTouched] = useState({
+   notes: false,
+   startTime: false,
+   endTime: false
+ });
+
+ const handleSubmit = (e: React.FormEvent) => {
+   e.preventDefault();
+   // Add form submission logic
+ };

- <div className="flex flex-col w-full">
+ <form onSubmit={handleSubmit} className="flex flex-col w-full">
    {/* ... */}
    <textarea
      value={notes}
-     onChange={(e) => setNotes(e.target.value)}
+     onChange={(e) => {
+       setNotes(e.target.value);
+       setTouched(prev => ({ ...prev, notes: true }));
+     }}
+     onBlur={() => setTouched(prev => ({ ...prev, notes: true }))}
      placeholder="Insert notes here..."
      className={clsxm(
        "bg-transparent focus:border-transparent focus:ring-2 focus:ring-transparent",
        "placeholder-gray-300 placeholder:font-normal resize-none p-2 grow w-full",
        "border border-gray-200 dark:border-slate-600 dark:bg-dark--theme-light rounded-md h-40 bg-[#FBB6500D]",
-       notes.trim().length === 0 && "border-red-500"
+       touched.notes && notes.trim().length === 0 && "border-red-500"
      )}
      maxLength={120}
      minLength={0}
      aria-label="Insert notes here"
      required
    />
+   {touched.notes && notes.trim().length === 0 && (
+     <span className="text-red-500 text-sm mt-1">Notes are required</span>
+   )}
    {/* ... */}
- </div>
+ </form>

Line range hint 58-67: Implement error handling and complete empty handlers

The component has empty handler functions and lacks error handling for user interactions.

Consider implementing proper error handling and completing the handlers:

const handleSelectedValuesChange = (values: { [key: string]: Item | null }) => {
  try {
    // Validate values
    if (!values.Project) {
      throw new Error('Project is required');
    }
    
    // Update state or call API
    // Handle success
  } catch (error) {
    // Show error message to user
    console.error('Failed to update values:', error);
  }
};

const handleChange = (field: string, selectedItem: Item | null) => {
  try {
    // Validate field and selectedItem
    if (!field || !selectedItem) {
      throw new Error('Invalid selection');
    }
    
    // Update state or call API
    // Handle success
  } catch (error) {
    // Show error message to user
    console.error('Failed to handle change:', error);
  }
};
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx (3)

Line range hint 52-57: Inconsistent onChange behavior between handleFromChange and handleToChange

The handleFromChange function immediately triggers the onChange callback, while handleToChange only updates local state. This inconsistency could lead to unexpected behavior when users are selecting date ranges.

Consider applying this fix:

 const handleToChange = (toDate: Date | null) => {
   if (dateRange.from && toDate && toDate < dateRange.from) {
     return;
   }
   setDateRange((prev) => ({ ...prev, to: toDate }));
+  onChange?.({ ...dateRange, to: toDate });
 };

Line range hint 59-89: Add validation against minDate/maxDate in preset selections

The handlePresetClick function doesn't validate the preset dates against the minDate and maxDate props, which could lead to invalid date selections.

Consider adding validation:

 const handlePresetClick = (preset: string) => {
   const today = new Date();
+  const validateDate = (date: Date) => {
+    if (maxDate && date > maxDate) return maxDate;
+    if (minDate && date < minDate) return minDate;
+    return date;
+  };
   switch (preset) {
     case t('common.FILTER_TODAY'):
-      setDateRange({ from: today, to: today });
+      setDateRange({ 
+        from: validateDate(today), 
+        to: validateDate(today) 
+      });
     // Apply similar validation to other cases

Line range hint 93-121: Enhance accessibility for date picker controls

While basic ARIA attributes are present, the date picker controls could benefit from additional accessibility improvements:

Consider these enhancements:

 <PopoverTrigger asChild>
   <Button
     variant={'outline'}
     role="combobox"
     aria-label="Select date range"
     aria-expanded="false"
+    aria-haspopup="dialog"
+    aria-controls="date-range-picker"
     className={cn(
       'w-44 justify-start dark:bg-dark--theme-light dark:text-gray-300 h-[2.2rem]',
       !dateRange.from && 'text-muted-foreground'
     )}
   >
apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (2)

494-496: Rename prop to match its usage

The prop name ids suggests multiple IDs, but it accepts a single string. Consider renaming it to timesheetId for better clarity.

-export const StatusTask = ({ ids }: { ids: string }) => {
+export const StatusTask = ({ timesheetId }: { timesheetId: string }) => {

Consider implementing status transition validation in the backend

Based on the codebase analysis, there's no validation logic for timesheet status transitions. The frontend allows any status change through the updateTimesheetStatus function without restrictions. While the UI shows a clear progression (DRAFT → PENDING → IN REVIEW → APPROVED/DENIED), there's no enforcement of this flow.

Key findings:

  • Status types are well-defined but transitions between them are not validated
  • Direct status updates are possible through updateTimesheetStatus API call
  • No state machine or workflow rules exist for controlling transitions

Recommendation:

  • Implement status transition validation in the backend API
  • Consider using a state machine pattern to enforce valid transitions:
    • DRAFT → PENDING
    • PENDING → IN REVIEW
    • IN REVIEW → APPROVED/DENIED
    • DENIED → DRAFT (for resubmission)
🔗 Analysis chain

Line range hint 494-543: Consider adding type safety for status transitions

The current implementation allows any status transition without validation. Consider adding validation for allowed status transitions (e.g., DRAFT can only move to PENDING, etc.).

Let's check if there are any existing status transition validations in the codebase:


Let me gather more information about the status transitions by checking the implementation details:


Let me check if there are any validation rules or state machine definitions for these status transitions:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for status transition validations
rg -g '!*.{json,lock}' -i "status.*transition|status.*validation|timesheet.*status" --type ts

Length of output: 9401


Script:

#!/bin/bash
# Check the TimesheetStatus type definition and any related validation logic
ast-grep --pattern 'type TimesheetStatus = $$$'

# Check the updateStatusTimesheetFromApi implementation
rg -A 10 "updateStatusTimesheetFromApi" --type ts

Length of output: 2839


Script:

#!/bin/bash
# Look for any status transition validation logic
rg -B 5 -A 10 "DRAFT|PENDING|IN REVIEW|DENIED|APPROVED" --type ts

# Check for any state machine or workflow definitions
rg -i "workflow|state.*machine|transition.*rule|status.*flow" --type ts

Length of output: 20341

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

48-51: Use translation function for static label text

The label 'Link to Project' is hardcoded, which may hinder localization efforts. Using the translation function ensures consistency across different languages.

Apply this diff to utilize the translation function:

const fields = [
  {
-   label: 'Link to Project',
+   label: t('pages.timesheet.LINK_TO_PROJECT'),
    placeholder: 'Select a project',
    isRequired: true,
    valueKey: 'id',
    displayKey: 'name',
    element: 'Project',
  },
];

Remember to add 'LINK_TO_PROJECT' to your localization files.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8f6352d and 313f891.

📒 Files selected for processing (16)
  • apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (7 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx (3 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx (1 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/page.tsx (2 hunks)
  • apps/web/app/api/timer/timesheet/status/route.ts (1 hunks)
  • apps/web/app/hooks/features/useTimelogFilterOptions.ts (3 hunks)
  • apps/web/app/hooks/features/useTimesheet.ts (5 hunks)
  • apps/web/app/hooks/useScrollListener.ts (2 hunks)
  • apps/web/app/interfaces/IDailyPlan.ts (1 hunks)
  • apps/web/app/interfaces/timer/ITimerLog.ts (1 hunks)
  • apps/web/app/services/client/api/timer/timer-log.ts (2 hunks)
  • apps/web/app/services/server/requests/timesheet.ts (2 hunks)
  • apps/web/app/stores/time-logs.ts (2 hunks)
  • apps/web/components/ui/accordion.tsx (1 hunks)
  • apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (3 hunks)
  • apps/web/lib/features/manual-time/manage-member-component.tsx (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/components/ui/accordion.tsx
🧰 Additional context used
📓 Learnings (2)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3208
File: apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx:30-35
Timestamp: 2024-11-12T14:06:02.202Z
Learning: In the `TimesheetFilter` component, the `Add Time` button does not need to use the `AddManualTimeModal` component, as per the user's decision.
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3208
File: apps/web/app/[locale]/timesheet/components/FrequencySelect.tsx:67-79
Timestamp: 2024-11-12T14:06:02.202Z
Learning: The date range selection functionality for the date range options in the `FilterTaskActionMenu` component will be implemented in a future PR.
🪛 Biome (1.9.4)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx

[error] 274-274: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

🔇 Additional comments (15)
apps/web/app/stores/time-logs.ts (1)

3-3: LGTM! Import statement follows consistent pattern

The addition of UpdateTimesheetStatus to the existing imports is clean and follows the established import pattern.

apps/web/app/api/timer/timesheet/status/route.ts (1)

1-4: LGTM! Imports are well-organized.

The imports are properly structured and include all necessary dependencies.

apps/web/app/hooks/features/useTimelogFilterOptions.ts (2)

1-1: LGTM: Clean state management implementation

The addition of new state atoms for timesheet grouping and status updates follows good practices and maintains consistency with the existing state management pattern.

Also applies to: 11-12


46-49: LGTM: Clean interface extension

The new properties are well-organized and follow the established naming conventions.

apps/web/app/services/server/requests/timesheet.ts (2)

4-5: LGTM! Imports are properly organized

The new imports support both existing functionality (TimesheetLog) and the new timesheet status update feature.


101-109: Verify API endpoint and response type

Please verify that:

  1. The API endpoint /timesheet/status exists and accepts PUT requests
  2. The response type is indeed an array (UpdateTimesheetStatus[]) and not a single object
✅ Verification successful

Let me gather more information about the API endpoint by checking the backend routes and the actual usage of this function.


Based on the gathered information, I can now provide the final response:

API endpoint and response type are correctly implemented

The verification confirms:

  1. The /timesheet/status endpoint exists and accepts PUT requests as evidenced by:
    • The API route definition in apps/web/app/api/timer/timesheet/status/route.ts
    • Consistent usage in both client and server-side code
  2. The response type UpdateTimesheetStatus[] is correct as:
    • The interface is defined in apps/web/app/interfaces/timer/ITimerLog.ts
    • It's consistently used across the codebase in both client (timer-log.ts) and server implementations
    • The endpoint is used to update multiple timesheet statuses at once (bulk update) as seen in the route implementation where ids is passed as a parameter
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for API route definitions and interface implementations

# Check for API route definition
echo "Checking for API route definition..."
fd -e ts -e tsx "route.ts$" | xargs rg -l "/timesheet/status"

# Check for UpdateTimesheetStatus interface usage
echo "Checking UpdateTimesheetStatus interface usage..."
rg -A 5 "interface UpdateTimesheetStatus" 

Length of output: 738


Script:

#!/bin/bash
# Search for backend route definitions
echo "Checking backend route definitions..."
rg -A 5 "timesheet/status" packages/ apps/

# Search for usage of updateStatusTimesheetRequest
echo "Checking function usage..."
rg -A 5 "updateStatusTimesheetRequest" apps/

# Search for any similar timesheet status endpoints
echo "Checking similar endpoints..."
rg -B 2 -A 2 "timesheet.*status" packages/ apps/

Length of output: 9848

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

129-135: Verify consistent usage of timesheet status values

Let's verify that these status values are used consistently across the codebase.

✅ Verification successful

Let me gather more information about the status usage in assignments and function calls.


Let me try a different approach to check status usage.


Status values are consistently used across the codebase

Based on the verification results:

  • The status values ("DRAFT", "PENDING", "IN REVIEW", "DENIED", "APPROVED") are consistently defined in both ITimerLog.ts and ITask.ts
  • The values are correctly used in the timesheet hook (useTimesheet.ts)
  • The UI components in TimesheetAction.tsx use the same status values with proper descriptions
  • The only variation found is a UI display where "DENIED" is shown as "REJECTED" for display purposes only, but the underlying type remains consistent
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any inconsistent status values that might not match our defined types
rg -t typescript '"(DRAFT|PENDING|IN REVIEW|DENIED|APPROVED)"' --type-add 'typescript:*.{ts,tsx}'

# Search for timesheet status assignments to ensure type safety
ast-grep --pattern 'status = "$_"' 

Length of output: 1713


Script:

#!/bin/bash
# Search for status assignments and comparisons in TypeScript files
rg -t typescript 'status\s*(===|==|=|!=|!==)\s*(["'\''])(DRAFT|PENDING|IN REVIEW|DENIED|APPROVED)\2' --type-add 'typescript:*.{ts,tsx}' -A 2

# Search for function calls or object literals with status field
ast-grep --pattern '{ $$$, status: "$_", $$$ }'

Length of output: 514


Script:

#!/bin/bash
# Search for status assignments and comparisons with --pcre2 flag
rg --pcre2 -t typescript 'status\s*(===|==|=|!=|!==)\s*["\x27](DRAFT|PENDING|IN REVIEW|DENIED|APPROVED)["\x27]' --type-add 'typescript:*.{ts,tsx}' -B 1 -A 1

# Look for status field usage in type definitions and interfaces
ast-grep --pattern 'interface $_ {
  $$$
  status: $_
  $$$
}'

Length of output: 17853

apps/web/app/services/client/api/timer/timer-log.ts (2)

1-3: LGTM: Import statements are well-organized

The new imports are properly structured and align with the added functionality for timesheet status updates.


125-129: Verify consistent endpoint usage

Let's ensure the endpoint is used consistently across the codebase and the HTTP method is appropriate.

✅ Verification successful

Based on the results, I can generate the final response as we have sufficient information about the endpoint usage.

Endpoint usage is consistent and properly implemented

The /timesheet/status endpoint is consistently implemented:

  • Client-side: Uses PUT method via put<UpdateTimesheetStatus[]> in timer-log.ts
  • Server-side: Matches with PUT method configuration in timesheet.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent usage of the timesheet status endpoint and HTTP methods

# Check for all timesheet status endpoint usages
echo "Checking timesheet status endpoint usage:"
rg -A 2 "/timesheet/status"

# Check for PUT method usage patterns
echo "Checking PUT method usage patterns:"
ast-grep --pattern 'put<$_>("/timesheet/status"'

Length of output: 685

apps/web/lib/features/manual-time/manage-member-component.tsx (1)

Line range hint 1-121: Implementation looks good overall!

The changes are well-structured, maintain type safety, and follow React best practices. The addition of the classNameTitle prop enhances the component's flexibility without introducing breaking changes.

apps/web/app/[locale]/timesheet/[memberId]/page.tsx (2)

Line range hint 201-215: Well-structured and maintainable component implementation.

The ViewToggleButton component is well-implemented with:

  • Proper TypeScript typing
  • Conditional styling with dark mode support
  • Internationalization support
  • Clean and reusable structure

Line range hint 1-215: Verify API integration for timesheet status updates.

While the UI improvements are well-implemented, I don't see clear evidence of the API integration for updating timesheet status as mentioned in the PR objectives. Please ensure this functionality is implemented or provide the relevant code for review.

✅ Verification successful

Based on the search results, I can now provide a final response:

API integration for timesheet status updates is properly implemented

The codebase shows complete implementation of timesheet status updates:

  • The useTimesheet hook in apps/web/app/hooks/features/useTimesheet.ts implements updateTimesheetStatus functionality using updateStatusTimesheetFromApi
  • API endpoint /timer/timesheet/status is implemented in apps/web/app/api/timer/timesheet/status/route.ts to handle status updates
  • Server request handler updateStatusTimesheetRequest in apps/web/app/services/server/requests/timesheet.ts makes the actual API call
  • The functionality is properly used in components like table-time-sheet.tsx for updating timesheet statuses
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for API integration code related to timesheet status updates
rg -l "updateTimesheetStatus|timesheet.*status.*update" --type ts --type tsx

Length of output: 106


Script:

#!/bin/bash
# Search for API integration code related to timesheet status updates with correct file extensions
rg -l "updateTimesheetStatus|timesheet.*status.*update" "*.ts" "*.tsx"

# Let's also check the useTimesheet hook implementation
ast-grep --pattern 'const useTimesheet = $_'

# Search for any timesheet-related API calls
rg -A 5 "api.*timesheet|timesheet.*api" "*.ts" "*.tsx"

Length of output: 358


Script:

#!/bin/bash
# First, let's find all TypeScript files in the repository
fd -e ts -e tsx

# Then search for timesheet-related API calls in the found files
rg -A 5 "api.*timesheet|timesheet.*api"

# Look for the useTimesheet hook implementation
rg -A 10 "useTimesheet"

# Search for any status update related code
rg -A 5 "status.*update|updateStatus"

Length of output: 93352

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

Line range hint 190-241: LGTM! Well-implemented date validation

The DatePickerFilter component properly handles date validation with minDate and maxDate constraints. The implementation is clean and follows best practices.

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

470-470: LGTM: Proper integration of StatusTask component

The StatusTask component is correctly integrated into the dropdown menu with the proper timesheet ID being passed.

apps/web/app/hooks/features/useTimesheet.ts (1)

251-251: Verify use of timesheet.flat() when generating statusTimesheet

In the expression getStatusTimesheet(timesheet.flat()), ensure that timesheet is an array of arrays before using flat(). If timesheet is already a flat array, using flat() may not be necessary and could have unintended effects.

apps/web/app/api/timer/timesheet/status/route.ts Outdated Show resolved Hide resolved
apps/web/app/api/timer/timesheet/status/route.ts Outdated Show resolved Hide resolved
apps/web/app/hooks/useScrollListener.ts Show resolved Hide resolved
apps/web/app/hooks/useScrollListener.ts Show resolved Hide resolved
apps/web/app/interfaces/IDailyPlan.ts Show resolved Hide resolved
@Innocent-Akim Innocent-Akim removed the Improvement Improvement label Nov 23, 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: 5

🧹 Outside diff range and nitpick comments (6)
apps/web/app/api/timer/timesheet/status/route.ts (3)

6-15: Add type safety and improve error messaging.

While the authentication implementation is good, consider these remaining improvements:

 export async function PUT(req: Request) {
     const res = new NextResponse();
     const {
         $res,
         user,
         tenantId,
         organizationId,
         access_token
-    } = await authenticatedGuard(req, res);
-    if (!user) return $res('Unauthorized');
+    }: {
+        $res: (data: any) => Response;
+        user: { id: string };
+        tenantId: string;
+        organizationId: string;
+        access_token: string;
+    } = await authenticatedGuard(req, res);
+    if (!user) return $res({
+        success: false,
+        message: 'Authentication required to update timesheet status'
+    });

41-47: Extract validStatuses as a constant.

Consider moving the validStatuses array outside the function to improve maintainability and reusability.

+const VALID_TIMESHEET_STATUSES = ['pending', 'approved', 'rejected'] as const;
+type TimesheetStatus = typeof VALID_TIMESHEET_STATUSES[number];
+
 export async function PUT(req: Request) {
     // ... previous code ...
-    const validStatuses = ['pending', 'approved', 'rejected'];
-    if (!validStatuses.includes(status)) {
+    if (!VALID_TIMESHEET_STATUSES.includes(status as TimesheetStatus)) {
         return $res({
             success: false,
-            message: 'Invalid status value'
+            message: `Status must be one of: ${VALID_TIMESHEET_STATUSES.join(', ')}`
         });
     }

48-68: Enhance error logging and success response.

Consider improving the error handling and success response:

         const { data } = await updateStatusTimesheetRequest(
             {
                 ids,
                 organizationId,
                 status,
                 tenantId
             },
             access_token
         );

         return $res({
             success: true,
-            data
+            data,
+            message: `Successfully updated ${ids.length} timesheet(s) to ${status}`
         });
     } catch (error) {
-        console.error('Error updating timesheet status:', error);
+        console.error('Error updating timesheet status:', {
+            error,
+            ids,
+            status,
+            organizationId,
+            tenantId
+        });
         return $res({
             success: false,
-            message: 'Failed to update timesheet status'
+            message: `Failed to update timesheet status: ${error instanceof Error ? error.message : 'Unknown error'}`
         });
     }
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (3)

Line range hint 65-122: Add form validation for required fields.

The task input and project selection are marked as required (*) but lack proper validation logic. This could lead to invalid form submissions.

Consider implementing form validation:

  1. Add form state management (e.g., using React Hook Form)
  2. Add error states and messages
  3. Disable the save button until all required fields are valid

Example implementation:

+ import { useForm } from 'react-hook-form';
+ 
+ interface FormInputs {
+   task: string;
+   project: string;
+ }
+ 
  export function AddTaskModal({ closeModal, isOpen }: IAddTaskModalProps) {
+   const { register, handleSubmit, formState: { errors } } = useForm<FormInputs>();
+   
    // ... existing code ...
    
    return (
-     <input
-       value={task}
-       onChange={(e) => setTasks(e.target?.value)}
+     <input
+       {...register('task', { required: 'Task is required' })}
+       onChange={(e) => setTasks(e.target?.value)}
      />
+     {errors.task && (
+       <span className="text-red-500 text-sm">{errors.task.message}</span>
+     )}

Line range hint 162-179: Implement form submission handler.

The save button is of type "submit" but lacks a form submission handler to process the data.

Add form submission logic:

+ const handleSubmit = async (e: React.FormEvent) => {
+   e.preventDefault();
+   try {
+     // Validate all required fields
+     if (!task || !selectedValues.Project || shifts.some(s => !s.startTime || !s.endTime)) {
+       return;
+     }
+     // TODO: Add API call to save the time entry
+     closeModal();
+   } catch (error) {
+     console.error('Failed to save time entry:', error);
+   }
+ };

  return (
+   <form onSubmit={handleSubmit}>
      {/* Existing modal content */}
+   </form>
  );

275-319: Add loading states for async operations.

The accordion UI should handle loading states during time calculations and shift updates.

Add loading states:

+ const [isLoading, setIsLoading] = React.useState(false);

  const handleAddShift = () => {
+   setIsLoading(true);
    setShifts([...shifts,
      { startTime: '', endTime: '', totalHours: '00:00h', dateFrom: new Date() },
    ]);
+   setIsLoading(false);
  };

  return (
    <>
      {shifts.map((element, index) => (
        <Accordion key={index} type="single" collapsible 
-         className="w-full p-1">
+         className={clsxm("w-full p-1", 
+           isLoading && "opacity-50 pointer-events-none")}>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 313f891 and cb05f87.

📒 Files selected for processing (2)
  • apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (7 hunks)
  • apps/web/app/api/timer/timesheet/status/route.ts (1 hunks)
🧰 Additional context used
📓 Learnings (1)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3208
File: apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx:30-35
Timestamp: 2024-11-12T14:06:02.202Z
Learning: In the `TimesheetFilter` component, the `Add Time` button does not need to use the `AddManualTimeModal` component, as per the user's decision.
🔇 Additional comments (2)
apps/web/app/api/timer/timesheet/status/route.ts (1)

1-5: LGTM! Dependencies are well-organized.

The imports are properly structured and include all necessary dependencies.

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

1-31: LGTM! Well-structured initialization of time-related state.

The setup properly handles time slots with 15-minute intervals and initializes the date range with the current date.

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

Reviewing files that changed from the base of the PR and between cb05f87 and c4ad2e9.

📒 Files selected for processing (1)
  • apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (7 hunks)
🧰 Additional context used
📓 Learnings (1)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3208
File: apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx:30-35
Timestamp: 2024-11-12T14:06:02.202Z
Learning: In the `TimesheetFilter` component, the `Add Time` button does not need to use the `AddManualTimeModal` component, as per the user's decision.
🔇 Additional comments (2)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (2)

183-218: ⚠️ Potential issue

Add time validation in ShiftTimingSelect.

The component should validate that end time is after start time.

Add time validation:

 interface ShiftTimingSelectProps {
   label: string;
   timeOptions: string[];
   placeholder: string;
   className?: string;
   value?: string;
   onChange?: (value: string) => void;
+  minTime?: string;
 }

 const ShiftTimingSelect = ({ 
   label, 
   timeOptions, 
   placeholder, 
   className, 
   onChange, 
   value,
+  minTime 
 }: ShiftTimingSelectProps) => (
   <div className="flex items-center border border-gray-200 dark:border-gray-700 gap-2 rounded w-full">
     {/* ... */}
     <SelectContent className="z-[10000] max-h-60 overflow-y-auto">
       <SelectGroup>
         {timeOptions
+          .filter(time => !minTime || time > minTime)
           .map((time) => (
           <SelectItem
             key={time}
             value={time}
             className="hover:bg-primary focus:bg-primary hover:text-white px-2 py-1 cursor-pointer"
           >
             {time}
           </SelectItem>
         ))}
       </SelectGroup>
     </SelectContent>
   </div>
 );

Likely invalid or redundant comment.


Line range hint 1-364: Verify implementation against requirements.

Please ensure that:

  1. All time entries are properly synchronized with the API
  2. The timesheet status is updated based on the API response
  3. The UI feedback is provided for all user actions
✅ Verification successful

Let me analyze the API integration and error handling for the timesheet functionality by checking the related files.


Let me check the timesheet implementation and hooks in more detail.


Let me check the implementation of useTimesheet hook and related API calls.


Let me check the timer API and client-side implementations.


Based on the comprehensive code analysis, I can now provide a final response regarding the review comment's concerns.

API integration and error handling are properly implemented

The timesheet functionality is well integrated with the API layer and includes proper error handling:

  1. The AddTaskModal is part of a complete timesheet system that includes:

    • Timer status synchronization via useTimesheet hook
    • API integration through timer-log.ts service
    • Proper status updates through updateTimesheetStatus
    • Error handling in API calls with try-catch blocks
  2. The timesheet status updates are handled through:

    • Status synchronization with backend via updateTimesheetStatus
    • Proper state management using atoms/stores
    • Real-time status updates with proper error boundaries
  3. UI feedback is provided through:

    • Loading states during API operations
    • Form validation with required fields
    • Visual indicators for billable status
    • Time tracking display with proper formatting

The implementation follows best practices for API integration, state management, and error handling. The concerns raised in the review comment have been addressed in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify API integration and status updates

# Check for API integration
rg -l "updateTimesheet|updateStatus" --type ts

# Check for error handling
rg "catch|error|failed" --type ts

Length of output: 80122


Script:

#!/bin/bash
# Check for timesheet API integration in AddTaskModal and related files
ast-grep --pattern 'useTimesheet()' 

# Check for timesheet API calls and status updates
rg -A 5 "updateTimesheet|updateTimesheetStatus" --type ts

# Check for error handling in AddTaskModal
rg -A 5 "catch|error|failed" "apps/web/app/\[locale\]/timesheet/\[memberId\]/components/AddTaskModal.tsx"

Length of output: 2510


Script:

#!/bin/bash
# Check for timesheet hooks and API integration
rg -l "useTimesheet|useTimeLogs|useTimer" --type ts

# Look for timesheet API calls and mutations
ast-grep --pattern 'const { $_ } = useTimesheet($$$)'

# Check AddTaskModal implementation
fd -e tsx -e ts "AddTaskModal" -x cat {}

Length of output: 19272


Script:

#!/bin/bash
# Check useTimesheet hook implementation
cat apps/web/app/hooks/features/useTimesheet.ts

# Check for API endpoints related to timesheet
rg -A 5 "api/timer/timesheet" --type ts

# Check for timesheet mutations and API calls
rg -A 5 "createTimesheet|addTimesheet|saveTimesheet" --type ts

Length of output: 9535


Script:

#!/bin/bash
# Check timer API implementations
rg -A 5 "timer-log" --type ts

# Check for timer/timesheet API routes
fd -e ts -e tsx "route.ts" -x grep -l "timer|timesheet" {}

# Look for timer service implementations
fd -e ts "timer" -x cat {}

Length of output: 62485

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

🧹 Outside diff range and nitpick comments (2)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (2)

265-285: Optimize performance with useCallback

The handleShiftChange function should be memoized to prevent unnecessary re-renders.

-const handleShiftChange = (index: number, field: keyof Shift, value: string) => {
+const handleShiftChange = React.useCallback((index: number, field: keyof Shift, value: string) => {
     const updatedShifts = [...shifts];
     updatedShifts[index][field] = value;

     if (field === 'startTime' || field === 'endTime') {
         // ... existing overlap check code ...
     }
     setShifts(updatedShifts);
-};
+}, [shifts]);

351-358: Improve accessibility and type safety

Add ARIA labels and remove 'any' type casting.

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

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c4ad2e9 and 4028c8b.

📒 Files selected for processing (1)
  • apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (7 hunks)
🧰 Additional context used
📓 Learnings (1)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3208
File: apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx:30-35
Timestamp: 2024-11-12T14:06:02.202Z
Learning: In the `TimesheetFilter` component, the `Add Time` button does not need to use the `AddManualTimeModal` component, as per the user's decision.
🔇 Additional comments (3)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (3)

342-346: 🛠️ Refactor suggestion

Add date validation to prevent past entries

The DatePickerFilter should prevent selection of past dates.

 <DatePickerFilter
     label={value.dateFrom ? value.dateFrom.toLocaleString() : 'Select Date'}
     date={value.dateFrom as Date}
-    setDate={(value) => onChange(index, 'dateFrom', value as any)}
+    setDate={(value) => {
+        const today = new Date();
+        today.setHours(0, 0, 0, 0);
+        if (value && value >= today) {
+            onChange(index, 'dateFrom', value as any);
+        }
+    }}
+    minDate={new Date()}
 />

Likely invalid or redundant comment.


171-177: 🛠️ Refactor suggestion

Add form validation before submission

The save button should be disabled when required fields are empty or invalid.

 <button
     type="submit"
+    disabled={!task || !notes.trim() || shifts.some(s => !s.startTime || !s.endTime)}
     className={clsxm(
         'bg-primary dark:bg-primary-light h-[2.3rem] w-[5.5rem] justify-center font-normal flex items-center text-white px-2 rounded-lg',
+        'disabled:opacity-50 disabled:cursor-not-allowed'
     )}>
     {t('common.SAVE')}
 </button>

Likely invalid or redundant comment.


183-218: 🛠️ Refactor suggestion

Add time validation in ShiftTimingSelect

The component should validate that end time is after start time to prevent invalid time ranges.

 interface ShiftTimingSelectProps {
     label: string;
     timeOptions: string[];
     placeholder: string;
     className?: string;
     value?: string;
     onChange?: (value: string) => void;
+    minTime?: string;
 }

 const ShiftTimingSelect = ({ 
     label, 
     timeOptions, 
     placeholder, 
     className, 
     onChange, 
     value,
+    minTime 
 }: ShiftTimingSelectProps) => (
     // ... existing code ...
     <SelectContent className="z-[10000] max-h-60 overflow-y-auto">
         <SelectGroup>
             {timeOptions
+                .filter(time => !minTime || time > minTime)
                 .map((time) => (
                 <SelectItem
                     key={time}
                     value={time}
                     className="hover:bg-primary focus:bg-primary hover:text-white px-2 py-1 cursor-pointer"
                 >
                     {time}
                 </SelectItem>
             ))}
         </SelectGroup>
     </SelectContent>
 );

Likely invalid or redundant comment.

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 (1)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (1)

26-28: Consider using a more specific type for dateRange

The current type allows null which might lead to runtime errors. Consider using a non-nullable type since you're initializing with new Date().

-const [dateRange, setDateRange] = React.useState<{ from: Date | null }>({
+const [dateRange, setDateRange] = React.useState<{ from: Date }>({
     from: new Date(),
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4028c8b and c586bff.

📒 Files selected for processing (1)
  • apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (7 hunks)
🧰 Additional context used
📓 Learnings (1)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3208
File: apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx:30-35
Timestamp: 2024-11-12T14:06:02.202Z
Learning: In the `TimesheetFilter` component, the `Add Time` button does not need to use the `AddManualTimeModal` component, as per the user's decision.
🔇 Additional comments (2)
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (2)

171-177: ⚠️ Potential issue

Add form validation before submission

The save button should be disabled when required fields are empty or invalid.

 <button
     type="submit"
+    disabled={!task || !notes.trim() || shifts.some(s => !s.startTime || !s.endTime)}
     className={clsxm(
         'bg-primary dark:bg-primary-light h-[2.3rem] w-[5.5rem] justify-center font-normal flex items-center text-white px-2 rounded-lg',
+        'disabled:opacity-50 disabled:cursor-not-allowed'
     )}>
     {t('common.SAVE')}
 </button>

Likely invalid or redundant comment.


343-347: ⚠️ Potential issue

Prevent selection of past dates

The DatePickerFilter should prevent selection of past dates to ensure valid time entries.

 <DatePickerFilter
     label={value.dateFrom ? value.dateFrom.toLocaleString() : 'Select Date'}
     date={value.dateFrom as Date}
-    setDate={(value) => onChange(index, 'dateFrom', value as any)}
+    setDate={(value) => {
+        const today = new Date();
+        today.setHours(0, 0, 0, 0);
+        if (value && value >= today) {
+            onChange(index, 'dateFrom', value as any);
+        }
+    }}
+    minDate={new Date()}
 />

Likely invalid or redundant comment.

@Innocent-Akim Innocent-Akim removed the Don't Merge Do not merge this PR until label not removed label Nov 23, 2024
@Innocent-Akim Innocent-Akim added this to the v0.3.0 milestone Nov 23, 2024
@evereq evereq merged commit 528362c into develop Nov 24, 2024
13 checks passed
@evereq evereq deleted the feat/add-time-entry-modal branch November 24, 2024 16:32
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.

2 participants