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]: Manage Permissions and Improve Time entries view #3403

Merged
merged 7 commits into from
Dec 8, 2024

Conversation

Innocent-Akim
Copy link
Contributor

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

Description

#3047
#3046
#3219

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 user permissions management in the Timesheet components, allowing for conditional rendering based on user roles.
    • Added support for displaying different log types in the task display with corresponding icons.
    • Introduced user context in multiple components for improved access control and functionality.
    • New components for shift timing selection and management in the Add Task modal.
  • Bug Fixes

    • Improved date handling logic to default to the current week in the Timesheet component.
  • Style

    • Updated button styles for better interactivity and visual representation in the Timesheet filter.
    • Enhanced visual elements in the Timesheet filter date component for improved user experience.
    • Adjusted styling for the Task Status component in the Add Task modal.
  • Chores

    • Minor formatting adjustments across various components for consistency.

Copy link
Contributor

coderabbitai bot commented Dec 7, 2024

Caution

Review failed

The pull request is closed.

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]/kanban/page.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 enhancements across several components related to timesheet management. Key modifications include the addition of an optional user property to various components such as CalendarView, TimesheetFilter, and TimesheetView. The TimesheetFilter component now conditionally renders UI elements based on user permissions. The date handling in the page.tsx file is updated to reflect the current week, and a new function in the useTimelogFilterOptions hook checks user access rights. Overall, these changes improve user context management and UI interactions based on permissions.

Changes

File Change Summary
apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx Added optional user property to BaseCalendarDataViewProps interface and CalendarView function signature.
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx Added optional user property to ITimesheetFilter interface and modified rendering logic based on user permissions.
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx Added import for ChevronDown and updated button styles for improved interactivity.
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx Updated TimesheetView to include user prop, passed to DataTableTimeSheet.
apps/web/app/[locale]/timesheet/[memberId]/page.tsx Changed date handling to use the current week, updated useTimesheet hook to include user context, and passed user prop to relevant components.
apps/web/app/hooks/features/useTimelogFilterOptions.ts Introduced isUserAllowedToAccess function to check user permissions based on roles.
apps/web/app/hooks/features/useTimesheet.ts Added isManage variable to determine user access rights for managing timesheets.
apps/web/lib/features/integrations/calendar/table-time-sheet.tsx Updated DataTableTimeSheet and TaskActionMenu to accept user and isManage props for conditional rendering based on permissions.
apps/web/lib/features/task/task-displays.tsx Enhanced DisplayTimeForTimesheet to include optional logType parameter for dynamic icon rendering.
apps/web/lib/settings/member-table.tsx Minor formatting adjustments with no impact on functionality.
apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx Modified TaskStatus styling, added ShiftTimingSelect, OptimizedAccordion, and ShiftManagement components for enhanced time entry management.

Possibly related PRs

Suggested labels

WEB

Suggested reviewers

  • evereq
  • Cedric921

🐇 "In the meadow where we play,
A new user prop leads the way.
With filters fine and dates so neat,
Our timesheets now are quite a treat!
Permissions checked, the view is bright,
Hop along, all feels just right!" 🐇


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3c53830 and 3dd3562.

📒 Files selected for processing (13)
  • apps/web/app/[locale]/kanban/page.tsx (3 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/AddTaskModal.tsx (1 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx (1 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx (3 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx (4 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx (2 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/page.tsx (7 hunks)
  • apps/web/app/hooks/features/useTimelogFilterOptions.ts (3 hunks)
  • apps/web/app/hooks/features/useTimesheet.ts (2 hunks)
  • apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (7 hunks)
  • apps/web/lib/features/task/task-displays.tsx (2 hunks)
  • apps/web/lib/features/team-members-kanban-view.tsx (2 hunks)
  • apps/web/lib/settings/member-table.tsx (1 hunks)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

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

Copy link
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: 3

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

19-19: Simplify the optional type notation

The current type definition has redundant optional notation. Using either ? or | undefined is sufficient, but not both.

-    user?: IUser | undefined
+    user?: IUser

14-22: Implementation appears incomplete

The changes add user context to support permission management, but the actual permission checks aren't implemented. Consider:

  1. Adding permission checks where needed (e.g., for sensitive actions or data)
  2. Documenting the intended permission requirements
  3. Passing the user prop to child components if they need to handle permissions

Would you like assistance in implementing the permission checks or documenting the requirements?

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

118-120: Consider safer employee ID filtering

While the functional approach is good, consider adding explicit null checks for employee objects to prevent potential runtime errors.

-employeeIds: isManage
-    ? employee?.map(({ employee: { id } }) => id).filter(Boolean)
-    : [user.employee.id],
+employeeIds: isManage
+    ? employee?.map(({ employee }) => employee?.id)
+        .filter((id): id is string => id !== undefined && id !== null)
+    : [user.employee?.id].filter((id): id is string => id !== undefined && id !== null),
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 88fc30c and 50a1e98.

📒 Files selected for processing (10)
  • apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx (1 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx (3 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx (4 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx (2 hunks)
  • apps/web/app/[locale]/timesheet/[memberId]/page.tsx (6 hunks)
  • apps/web/app/hooks/features/useTimelogFilterOptions.ts (3 hunks)
  • apps/web/app/hooks/features/useTimesheet.ts (2 hunks)
  • apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (6 hunks)
  • apps/web/lib/features/task/task-displays.tsx (2 hunks)
  • apps/web/lib/settings/member-table.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/lib/settings/member-table.tsx
🔇 Additional comments (25)
apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx (2)

14-14: LGTM!

The IUser interface import is correctly added and necessary for the type definitions.


15-20: Verify the necessity of the user prop in BaseCalendarDataViewProps

The user prop is added to the interface but isn't utilized in the BaseCalendarDataView component. If this prop is intended for future use, consider adding a TODO comment. Otherwise, consider removing it to avoid unused props.

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

157-161: Enhancement: Add user context for permission checks

The addition of the user parameter and the computation of isManage using isUserAllowedToAccess(user) enhances the component by enabling conditional rendering based on user permissions.


302-302: Conditional rendering of timesheet buttons based on permissions

Using isManage to conditionally render timesheet action buttons ensures that only authorized users can perform management actions.


364-369: Pass logType and user permissions to child components

Passing logType to DisplayTimeForTimesheet and isManage, user to TaskActionMenu allows these components to render content appropriately based on the log type and user permissions.


472-476: Correctly determine edit permissions

The canEdit logic correctly allows a user to edit if they have management permissions (isManage) or if they are the owner of the timesheet entry.


493-508: Conditional rendering of menu items based on user permissions

  • The edit option is displayed when the user can edit (canEdit), ensuring users without proper permissions cannot access this action.
  • Management actions are only available to users with isManage permissions.
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx (3)

2-2: Import IUser for user context

Importing IUser allows the component to utilize user information for permission checks and conditional rendering.


7-7: Update TimesheetView to accept user prop

Adding the user prop to TimesheetView enables the component to pass user context to child components for permission-based rendering.


30-30: Pass user context to DataTableTimeSheet

By passing the user prop to DataTableTimeSheet, you ensure that user permissions are considered when rendering the timesheet data.

apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx (4)

6-7: Import user interfaces and hooks

Importing IUser, TimesheetLog, TimesheetStatus, and useTimelogFilterOptions ensures the component has the necessary types and functions for handling user permissions.


18-18: Extend ITimesheetFilter interface with user prop

Adding the optional user prop to the ITimesheetFilter interface allows the filter component to access user information for permission checks.


22-24: Determine manage permissions in TimesheetFilter

Using isUserAllowedToAccess(user) to set isManage enables the component to conditionally render filters and actions based on user permissions.


42-55: Conditional rendering of filter options based on permissions

Wrapping the filter options and add time button inside {isManage && (...)} ensures that only users with manage permissions can access these features.

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

1-1: Import user types for permission checks

Importing IUser and RoleNameEnum allows the hook to define and check user roles accurately.


21-28: Implement isUserAllowedToAccess function

The isUserAllowedToAccess function correctly checks if the user's role is within the allowed roles for managing timesheets.


79-79: Expose isUserAllowedToAccess from the hook

By returning isUserAllowedToAccess, you enable other components to utilize this permission check function.

apps/web/lib/features/task/task-displays.tsx (3)

8-8: Import additional icons for log types

Importing CalendarArrowDown, CalendarClock, and UserPlusIcon provides the necessary icons to represent different log types.


77-90: Enhance DisplayTimeForTimesheet with log type icons

  • Adding the logType prop allows the component to display different icons based on the type of log entry (TRACKED, MANUAL, IDLE).
  • The icons mapping and resolvedLogType ensure that the correct icon is displayed, enhancing the UI for users.

92-98: Display time with appropriate icon

The updated component correctly displays the time alongside the icon corresponding to the logType, improving visual clarity.

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

24-24: LGTM: Improved date range handling

The change to use startOfWeek and endOfWeek with Monday as the start day is a good improvement for timesheet management, following common business practices.

Also applies to: 49-50


218-218: LGTM: Consistent user context propagation

The addition of the user prop to both view components ensures consistent permission handling throughout the timesheet interface.

Also applies to: 224-224

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

177-187: LGTM: Enhanced button UI and accessibility

The button improvements provide better visual feedback with hover states and clearer hierarchy with the ChevronDown icon. The increased height and font size enhance clickability.

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

98-98: LGTM: Clean permission handling implementation

Good separation of concerns by using isUserAllowedToAccess from the filter options hook to determine management permissions.

Also applies to: 104-104


303-304: LGTM: Well-structured hook return value

Good addition of the groupByDate utility and isManage flag to the hook's return value, maintaining a clean interface for consumers.

@Innocent-Akim Innocent-Akim self-assigned this Dec 7, 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: 0

🧹 Outside diff range and nitpick comments (1)
apps/web/lib/features/task/task-displays.tsx (1)

77-98: Add aria-labels to icons for accessibility

The implementation looks good overall! Consider adding aria-labels to the icons for better accessibility.

 const icons = {
-    MANUAL: <UserPlusIcon className={`text-red-500 ${iconClasses}`} />,
-    TRACKED: <ClockIcon className={`text-green-400 ${iconClasses}`} />,
-    IDLE: <CalendarArrowDown className={`text-yellow-400 ${iconClasses}`} />,
+    MANUAL: <UserPlusIcon className={`text-red-500 ${iconClasses}`} aria-label="Manual time entry" />,
+    TRACKED: <ClockIcon className={`text-green-400 ${iconClasses}`} aria-label="Tracked time" />,
+    IDLE: <CalendarArrowDown className={`text-yellow-400 ${iconClasses}`} aria-label="Idle time" />,
 };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 50a1e98 and 281e965.

📒 Files selected for processing (2)
  • apps/web/app/[locale]/timesheet/[memberId]/page.tsx (6 hunks)
  • apps/web/lib/features/task/task-displays.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/[locale]/timesheet/[memberId]/page.tsx
🔇 Additional comments (2)
apps/web/lib/features/task/task-displays.tsx (2)

8-8: LGTM: New icon imports

The new imports are correctly placed and necessary for the enhanced log type visualization.


77-77: Verify the usage of different log types

Let's verify how the different log types are being used across the codebase to ensure consistent implementation.

Also applies to: 90-90

✅ Verification successful

Log types are consistently implemented across the codebase

The verification shows that:

  • The log types ('TRACKED', 'MANUAL', 'IDLE') are properly defined as an enum in apps/web/app/interfaces/ITimer.ts
  • 'TRACKED' is the default log type used consistently across timer-related operations
  • DisplayTimeForTimesheet component is used in multiple timesheet-related views with proper type checking
  • The implementation defaults to 'TRACKED' when no log type is provided (logType ?? 'TRACKED')
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of DisplayTimeForTimesheet component with different log types
rg -A 2 "DisplayTimeForTimesheet.*logType=" 

# Search for string literals that might define these log types
rg "'(TRACKED|MANUAL|IDLE)'" --type typescript

Length of output: 135


Script:

#!/bin/bash
# Search for usage of DisplayTimeForTimesheet component
rg "DisplayTimeForTimesheet" -A 2

# Search for these log type strings without typescript extension
rg "'(TRACKED|MANUAL|IDLE)'"

# Search for type definitions or enums related to log types
rg -g "*.ts*" "type.*=.*('TRACKED'|'MANUAL'|'IDLE')"

Length of output: 5739

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

157-167: Consider memoizing the member count calculation

While the unique member count calculation is correct, it could be optimized by moving it to a useMemo hook to prevent unnecessary recalculations on each render.

Consider applying this optimization:

+const uniqueMemberCount = useMemo(() => 
+  Object.values(statusTimesheet)
+    .flat()
+    .map(entry => entry.employee.id)
+    .filter((id, index, array) => array.indexOf(id) === index)
+    .length,
+  [statusTimesheet]
+);

{isManage && (
  <TimesheetCard
-    count={Object.values(statusTimesheet)
-      .flat()
-      .map(entry => entry.employee.id)
-      .filter((id, index, array) => array.indexOf(id) === index)
-      .length}
+    count={uniqueMemberCount}
    title="Members Worked"
    description="People worked since last time"
    icon={<User2 className="font-bold" />}
    classNameIcon="bg-[#30B366] shadow-[#30b3678f]"
  />
)}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 281e965 and e262292.

📒 Files selected for processing (1)
  • apps/web/app/[locale]/timesheet/[memberId]/page.tsx (7 hunks)
🔇 Additional comments (4)
apps/web/app/[locale]/timesheet/[memberId]/page.tsx (4)

49-50: LGTM: Improved date range initialization

The change to use startOfWeek and endOfWeek with Monday as the start day is a good improvement for business timesheet views.


92-96: LGTM: Well-implemented duration calculation

The total duration calculation correctly aggregates timesheet durations with proper error handling.


52-54: ⚠️ Potential issue

Consider safer null handling for date parameters

The non-null assertions (!) on dateRange.from and dateRange.to could lead to runtime errors if the dates are null.

Apply this diff for safer null handling:

-startDate: dateRange.from!,
-endDate: dateRange.to!,
+startDate: dateRange.from ?? startOfWeek(new Date(), { weekStartsOn: 1 }),
+endDate: dateRange.to ?? endOfWeek(new Date(), { weekStartsOn: 1 }),

201-201: Verify user prop usage in child components

The user prop is consistently passed to TimesheetFilter, TimesheetView, and CalendarView components. Let's verify its implementation in these components.

Also applies to: 226-226, 232-232

✅ Verification successful

Based on the search results, I can now provide a final response as we have found the necessary information about how the user prop is implemented in all three components:

User prop is properly implemented across components

The verification shows that:

  • TimesheetFilter component properly defines and uses the user prop in its interface ITimesheetFilter
  • TimesheetView component properly defines and uses the user prop in its props interface
  • CalendarView component properly defines and uses the user prop in its props interface

All components consistently implement the user prop as an optional IUser type, which aligns with how it's being passed from the parent component.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how the user prop is used in the child components

# Check TimesheetFilter implementation
ast-grep --pattern 'interface TimesheetFilterProps {
  $$$
  user: $_
  $$$
}'

# Check TimesheetView implementation
ast-grep --pattern 'interface TimesheetViewProps {
  $$$
  user: $_
  $$$
}'

# Check CalendarView implementation
ast-grep --pattern 'interface CalendarViewProps {
  $$$
  user: $_
  $$$
}'

Length of output: 237


Script:

#!/bin/bash
# Let's try a different approach to find these components and their props

# Search for TimesheetFilter component definition and usage
rg "TimesheetFilter" -A 5 -B 5

# Search for TimesheetView component definition and usage
rg "TimesheetView" -A 5 -B 5

# Search for CalendarView component definition and usage
rg "CalendarView" -A 5 -B 5

Length of output: 32191

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

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

97-97: LGTM! Consider using design tokens for consistency.

The styling changes are valid, but the highly specific padding values (0.3312rem, 0.2875rem) might be better represented using design tokens for maintainability.

Consider using design system variables:

-className={clsxm('rounded-sm h-auto !px-[0.3312rem] py-[0.2875rem] text-white bg-primary')}
+className={clsxm('rounded-sm h-auto !px-2 py-1 text-white bg-primary')}

Line range hint 249-259: Add input validation and handle edge cases in time conversion.

The time conversion logic has potential issues with edge cases:

  1. No validation for malformed time inputs
  2. Midnight (12 AM) is not handled correctly
  3. No error handling for invalid time formats

Consider this safer implementation:

 const convertToMinutesHour = (time: string): number => {
+    if (!time || !/^\d{1,2}:\d{2} [AP]M$/.test(time)) {
+        throw new Error('Invalid time format. Expected "HH:MM AM/PM"');
+    }
     const [hourMinute, period] = time.split(' ');
     const [hours, minutes] = hourMinute.split(':').map(Number);
+    
+    if (hours < 1 || hours > 12 || minutes < 0 || minutes > 59) {
+        throw new Error('Invalid hours or minutes');
+    }
 
-    let totalMinutes = (hours % 12) * 60 + minutes;
+    let totalMinutes = (hours === 12 ? 0 : hours) * 60 + minutes;
     if (period === 'PM') totalMinutes += 720;
 
     return totalMinutes;
 }

Line range hint 28-53: Implement comprehensive form validation and error handling.

The form lacks proper validation feedback:

  1. No error messages for required fields
  2. No validation before form submission
  3. Missing error states for invalid inputs

Consider implementing form validation:

interface FormErrors {
  task?: string;
  notes?: string;
  shifts?: { startTime?: string; endTime?: string }[];
}

// Add to component state
const [errors, setErrors] = React.useState<FormErrors>({});

// Add validation function
const validateForm = (): boolean => {
  const newErrors: FormErrors = {};
  
  if (!task.trim()) {
    newErrors.task = t('errors.TASK_REQUIRED');
  }
  
  if (!notes.trim()) {
    newErrors.notes = t('errors.NOTES_REQUIRED');
  }
  
  // Validate shifts
  const shiftErrors = shifts.map(shift => ({
    startTime: !shift.startTime ? t('errors.START_TIME_REQUIRED') : undefined,
    endTime: !shift.endTime ? t('errors.END_TIME_REQUIRED') : undefined
  }));
  
  if (shiftErrors.some(err => err.startTime || err.endTime)) {
    newErrors.shifts = shiftErrors;
  }
  
  setErrors(newErrors);
  return Object.keys(newErrors).length === 0;
};

// Update submit handler
const handleSubmit = () => {
  if (!validateForm()) {
    return;
  }
  // Proceed with submission
};

Line range hint 307-393: Optimize component structure and state management.

The current implementation has several architectural concerns:

  1. Complex prop drilling through multiple levels
  2. Scattered state management
  3. Tightly coupled components

Consider these improvements:

  1. Use React Context for sharing state and callbacks
  2. Extract shift validation logic into a custom hook
  3. Implement proper component composition

Example implementation:

// Create ShiftContext
const ShiftContext = React.createContext<{
  timeOptions: string[];
  onShiftChange: (index: number, field: keyof Shift, value: string) => void;
  t: TranslationHooks;
} | null>(null);

// Create custom hook for shift validation
const useShiftValidation = () => {
  const validateShift = (start: string, end: string): boolean => {
    // Move validation logic here
  };
  
  return { validateShift };
};

// Simplify ShiftManagement component
const ShiftManagement = ({ index, value }: { index: number; value: Shift }) => {
  const context = React.useContext(ShiftContext);
  if (!context) throw new Error('ShiftManagement must be used within ShiftContext');
  
  const { timeOptions, onShiftChange, t } = context;
  
  return (
    // Simplified JSX
  );
};
apps/web/lib/features/integrations/calendar/table-time-sheet.tsx (1)

Line range hint 472-508: Consider refactoring permission-based rendering.

The component could be improved by:

  1. Consolidating permission checks
  2. Adding error handling for the edit modal
  3. Extracting menu items into separate components

Consider this refactor:

 const TaskActionMenu = ({ dataTimesheet, isManage, user }: { dataTimesheet: TimesheetLog, isManage?: boolean, user?: IUser | undefined }) => {
   const { isOpen: isEditTask, openModal: isOpenModalEditTask, closeModal: isCloseModalEditTask } = useModal();
+  const [error, setError] = useState<Error | null>(null);
   const t = useTranslations();
   const canEdit = isManage || user?.id === dataTimesheet.employee.user.id;

+  const handleEdit = () => {
+    try {
+      isOpenModalEditTask();
+    } catch (error) {
+      setError(error as Error);
+      // Handle error appropriately
+    }
+  };

+  const renderMenuItems = () => {
+    const items = [];
+    if (canEdit) {
+      items.push(
+        <DropdownMenuItem key="edit" className="cursor-pointer" onClick={handleEdit}>
+          {t('common.EDIT')}
+        </DropdownMenuItem>
+      );
+    }
+    if (isManage) {
+      items.push(
+        <StatusTask key="status" timesheet={dataTimesheet} />,
+        <DropdownMenuItem key="delete" className="text-red-600 hover:!text-red-600 cursor-pointer">
+          {t('common.DELETE')}
+        </DropdownMenuItem>
+      );
+    }
+    return items;
+  };

   return (
     <>
       {<EditTaskModal
         closeModal={isCloseModalEditTask}
         isOpen={isEditTask}
         dataTimesheet={dataTimesheet}
       />}
       <DropdownMenu>
         <DropdownMenuTrigger asChild>
           <Button variant="ghost" className="w-8 h-8 p-0 text-sm sm:text-base">
             <span className="sr-only">Open menu</span>
             <MoreHorizontal className="w-4 h-4" />
           </Button>
         </DropdownMenuTrigger>
         <DropdownMenuContent align="end">
-          {canEdit && (
-            <DropdownMenuItem className="cursor-pointer" onClick={isOpenModalEditTask}>
-              {t('common.EDIT')}
-            </DropdownMenuItem>
-          )}
-          <DropdownMenuSeparator />
-          {isManage && (
-            <>
-              <StatusTask timesheet={dataTimesheet} />
-              <DropdownMenuItem className="text-red-600 hover:!text-red-600 cursor-pointer">
-                {t('common.DELETE')}
-              </DropdownMenuItem>
-            </>
-          )}
+          {renderMenuItems()}
         </DropdownMenuContent>
       </DropdownMenu>
     </>
   );
 };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e869b45 and 3c53830.

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

157-161: LGTM! Clean implementation of user-based permissions.

The changes properly implement permission checks using optional parameters and follow React best practices.


302-302: LGTM! Proper implementation of permission-based UI rendering.

The changes correctly implement conditional rendering based on user permissions and maintain good component composition.

Also applies to: 366-369


472-476: LGTM! Clean implementation of permission checks.

The permission check logic is well-implemented using the combination of isManage and user ID comparison.

@Innocent-Akim Innocent-Akim requested a review from evereq December 8, 2024 10:23
@Innocent-Akim Innocent-Akim force-pushed the feat/manage-permissions-and-time-entries-view branch from 3c53830 to 3dd3562 Compare December 8, 2024 17:58
@evereq evereq merged commit ca52c4d into develop Dec 8, 2024
11 of 13 checks passed
@evereq evereq deleted the feat/manage-permissions-and-time-entries-view branch December 8, 2024 18:00
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