Skip to content

Conversation

CREDO23
Copy link
Contributor

@CREDO23 CREDO23 commented Nov 13, 2024

Description

Fix #3128

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

Screenshot from 2024-11-13 19-02-26

Current screenshots

Screenshot from 2024-11-13 18-49-30

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new table view for displaying daily plan tasks via the DailyPlanTasksTableView component.
    • Added the Invite component for user invitations within the TeamMembersTableView.
    • Streamlined task deletion with a direct button action in the FutureTasks component.
    • Added new components for task action menus, estimations, info, and times in the table view.
  • Bug Fixes

    • Enhanced logic for the timer functionality in the TaskCard component to prevent starting timers on closed tasks.
  • Improvements

    • Improved rendering logic for task views, allowing for both table and card formats.
    • Enhanced user experience with updated loading states and streamlined component structures.

Copy link
Contributor

coderabbitai bot commented Nov 13, 2024

Walkthrough

The changes introduce a new table view for displaying planned tasks in the Daily Plan feature, replacing the previous card and block views. A new component, DailyPlanTasksTableView, is created and integrated into various components, allowing for conditional rendering based on the selected view. Additionally, several new components are added to manage task actions, estimations, and information within the table. The modifications streamline the delete functionality and enhance the overall structure of the task management system without altering existing functionalities.

Changes

File Path Change Summary
apps/web/components/ui/data-table.tsx Minor modification in rendering logic for header content in DataTable.
apps/web/lib/features/task/daily-plan/future-tasks.tsx Introduced DailyPlanTasksTableView, replacing Droppable for 'TABLE' view. Simplified delete functionality.
apps/web/lib/features/task/daily-plan/past-tasks.tsx Added DailyPlanTasksTableView for 'TABLE' view, maintaining original Droppable logic for other views.
apps/web/lib/features/task/daily-plan/table-view/cells/task-action-menu-cell.tsx New component TaskActionMenuCell for rendering task actions in table cells.
apps/web/lib/features/task/daily-plan/table-view/cells/task-estimation-cell.tsx New component DailyPlanTaskEstimationCell for displaying task estimation in table cells.
apps/web/lib/features/task/daily-plan/table-view/cells/task-info-cell.tsx New component DailyPlanTaskInfoCell for rendering task information in table cells.
apps/web/lib/features/task/daily-plan/table-view/cells/task-times-cell.tsx New component DailyPlanTaskTimesCell for displaying task times in table cells.
apps/web/lib/features/task/daily-plan/table-view/index.tsx Introduced DailyPlanTasksTableView component, defining table columns and rendering tasks.
apps/web/lib/features/task/task-card.tsx Exported TaskInfo and TaskCardMenu functions; improved timer handling logic.
apps/web/lib/features/team-members-table-view.tsx Added Invite component for user invitations within TeamMembersTableView.
apps/web/lib/features/user-profile-plans.tsx Integrated DailyPlanTasksTableView into AllPlans function, modifying task rendering logic.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant FutureTasks
    participant PastTasks
    participant DailyPlanTasksTableView
    participant DataTable

    User->>FutureTasks: Selects 'TABLE' view
    FutureTasks->>DailyPlanTasksTableView: Render table view
    DailyPlanTasksTableView->>DataTable: Passes tasks data
    DataTable-->>User: Displays tasks in table format

    User->>PastTasks: Selects 'TABLE' view
    PastTasks->>DailyPlanTasksTableView: Render table view
    DailyPlanTasksTableView->>DataTable: Passes tasks data
    DataTable-->>User: Displays tasks in table format
Loading

Assessment against linked issues

Objective Addressed Explanation
Implement table view for planned tasks page (#[3128])

Possibly related PRs

Suggested reviewers

  • evereq
  • Cedric921

Poem

Hop, hop, hooray, what a sight to see,
A table of tasks, as fine as can be!
With actions and times, all neatly in rows,
Our daily plans flourish, as progress just flows!
So gather 'round, friends, let’s cheer and delight,
For the table view's here, making work feel just right! 🐇✨

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/components/ui/data-table.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.

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

🧹 Outside diff range and nitpick comments (22)
apps/web/lib/features/task/daily-plan/table-view/cells/task-info-cell.tsx (1)

5-7: Consider destructuring props for better readability.

While the current implementation works well, we could improve readability by destructuring the props.

-export default function DailyPlanTaskInfoCell(props: CellContext<ITeamTask, unknown>) {
-	return <TaskInfo task={props.row.original} className="w-full px-4" tab={'default'} />;
+export default function DailyPlanTaskInfoCell({
+	row: { original: task },
+}: CellContext<ITeamTask, unknown>) {
+	return <TaskInfo task={task} className="w-full px-4" tab="default" />;
}
apps/web/lib/features/task/daily-plan/table-view/cells/task-times-cell.tsx (3)

1-7: Optimize lodash import for better bundle size

Consider using the modular import from lodash-es to reduce bundle size.

-import get from 'lodash/get';
+import { get } from 'lodash-es';

8-8: Improve type safety in CellContext generic parameters

The unknown type for the second generic parameter of CellContext could be more specific. Consider using the actual value type that this cell handles.

-export default function DailyPlanTaskTimesCell(props: CellContext<ITeamTask, unknown>) {
+export default function DailyPlanTaskTimesCell(props: CellContext<ITeamTask, any>) {

8-31: Consider adding error boundaries and loading states

The component handles multiple async operations and external data but lacks error boundaries and loading states. This could lead to poor user experience if data fetching fails or is slow.

Consider:

  1. Wrapping the component in an error boundary
  2. Adding loading states while data is being fetched
  3. Handling edge cases when team or member data is unavailable
apps/web/lib/features/task/daily-plan/table-view/cells/task-estimation-cell.tsx (1)

1-6: LGTM! Consider improving type imports.

The imports are well-organized and appropriate for the component's functionality. However, consider using a more specific type import from '@tanstack/react-table' to improve type safety and bundle size.

-import { CellContext } from '@tanstack/react-table';
+import type { CellContext } from '@tanstack/react-table';
apps/web/lib/features/task/daily-plan/table-view/cells/task-action-menu-cell.tsx (2)

13-15: Add type safety for column metadata access.

Using lodash get with type casting could mask potential type errors. Consider adding type definitions for column metadata.

interface TaskColumnMeta {
  profile: I_UserProfilePage;
  plan: unknown; // Replace with actual type
  planMode: unknown; // Replace with actual type
}

// Then use it in the component:
const meta = props.column.columnDef.meta as TaskColumnMeta;
const { profile, plan, planMode } = meta;

25-49: Enhance accessibility and maintainability of the component.

Consider the following improvements:

  1. Add ARIA labels for better accessibility
  2. Move hardcoded width values to theme constants
  3. Use JSDoc style comments for better documentation
-<div className="flex items-center justify-center w-1/5 h-full xl:justify-between lg:px-3 2xl:w-52 3xl:w-80">
+<div 
+  role="cell"
+  aria-label="Task Actions"
+  className={clsx(
+    'flex items-center justify-center h-full xl:justify-between lg:px-3',
+    styles.taskActionCell // Move width values to CSS module
+  )}
+>

Also, replace the inline comment with JSDoc:

/** 
 * Renders a dropdown that allows users to change the task status.
 * The dropdown is disabled when the task is in a loading state.
 */
apps/web/lib/features/task/daily-plan/table-view/index.tsx (3)

11-16: Add JSDoc documentation for the interface

Consider adding JSDoc documentation to the interface to improve code maintainability and developer experience.

+/**
+ * Props for the DailyPlanTasksTableView component
+ * @interface IDailyPlanTasksTableViewProps
+ */
interface IDailyPlanTasksTableViewProps {
+  /** Array of team tasks to display in the table */
  data: ITeamTask[];
+  /** Daily plan object containing plan details */
  plan: IDailyPlan;
+  /** User profile information */
  profile: I_UserProfilePage;
+  /** Optional filter mode for the plan view */
  planMode?: FilterTabs;
}

18-27: Fix documentation typos and add missing param

The JSDoc has a typo and is missing documentation for the 'plan' parameter.

/**
 * Table view of daily plan tasks
 *
-* @param {Object} props - THe props object
+* @param {Object} props - The props object
 * @param {ITeamTask[]} props.data - The tasks
+* @param {IDailyPlan} props.plan - The daily plan object
 * @param {I_UserProfilePage} props.profile - The user profile page
 * @param {FilterTabs} props.planMode - The plan mode to display
 *
 * @returns {JSX.Element} - The table view of daily plan tasks
 */

74-74: Add error handling for empty data

Consider adding error handling or empty state rendering when the data array is empty or invalid.

-return <DataTable isHeader={false} columns={columns} data={data} />;
+return (
+  <>
+    {!data?.length ? (
+      <div className="text-center py-4">No tasks available</div>
+    ) : (
+      <DataTable isHeader={false} columns={columns} data={data} />
+    )}
+  </>
+);
apps/web/lib/features/task/daily-plan/past-tasks.tsx (3)

55-61: Consider adding type safety for view state

While the view switching logic is clean, consider adding type safety for the view state to prevent potential runtime errors.

+ type ViewType = 'TABLE' | 'CARDS' | 'BLOCKS';
+ const view = useAtomValue<ViewType>(dailyPlanViewHeaderTabs);

76-76: Use design tokens for colors

Replace hardcoded color values with design system tokens for better maintainability and consistency.

- snapshot.isDraggingOver ? 'lightblue' : '#F7F7F8'
+ snapshot.isDraggingOver ? 'bg-blue-100' : 'bg-gray-50'

83-91: Consider extracting draggable wrapper component

There's duplicate code for the draggable wrapper in both view modes. Consider extracting this into a reusable component to reduce duplication.

interface DraggableWrapperProps {
  provided: DraggableProvided;
  children: React.ReactNode;
  marginBottom?: number;
}

const DraggableWrapper: React.FC<DraggableWrapperProps> = ({
  provided,
  children,
  marginBottom = 4
}) => (
  <div
    ref={provided.innerRef}
    {...provided.draggableProps}
    {...provided.dragHandleProps}
    style={{
      ...provided.draggableProps.style,
      marginBottom
    }}
  >
    {children}
  </div>
);

Also applies to: 120-128

apps/web/lib/features/task/daily-plan/future-tasks.tsx (2)

61-66: Consider optimizing props and adding error handling

The table view integration looks good, but consider these improvements:

  1. The data prop seems redundant since it's just plan.tasks. Consider passing plan.tasks directly.
  2. Consider adding error boundaries and loading states for better user experience.
 <DailyPlanTasksTableView
   profile={profile}
   plan={plan}
-  data={plan.tasks ?? []}
+  tasks={plan.tasks ?? []}
 />

79-134: Consider extracting drag and drop task rendering logic

The nested conditional rendering with Draggable components is becoming complex and harder to maintain. Consider extracting this logic into a separate component to improve readability and maintainability.

Example structure:

interface DraggableTaskProps {
  task: Task;
  index: number;
  view: 'CARDS' | 'BLOCKS';
  plan: Plan;
  profile: Profile;
}

const DraggableTask: React.FC<DraggableTaskProps> = ({ task, index, view, plan, profile }) => {
  return (
    <Draggable key={task.id} draggableId={task.id} index={index}>
      {(provided) => (
        <div
          ref={provided.innerRef}
          {...provided.draggableProps}
          {...provided.dragHandleProps}
          style={{
            ...provided.draggableProps.style,
            marginBottom: view === 'CARDS' ? 4 : 8
          }}
        >
          {view === 'CARDS' ? (
            <TaskCard
              key={`${task.id}${plan.id}`}
              // ... other props
            />
          ) : (
            <TaskBlockCard task={task} />
          )}
        </div>
      )}
    </Draggable>
  );
};
apps/web/lib/features/user-profile-plans.tsx (2)

280-357: Consider extracting the Droppable view logic into a separate component

The current implementation mixes view logic for cards and blocks within the same component, making it harder to maintain. Consider extracting this into a separate component to improve code organization and reusability.

+ // Create a new file: DailyPlanDraggableView.tsx
+ interface DailyPlanDraggableViewProps {
+   plan: IDailyPlan;
+   view: string;
+   profile: any;
+   currentTab?: FilterTabs;
+ }
+ 
+ export function DailyPlanDraggableView({ plan, view, profile, currentTab }: DailyPlanDraggableViewProps) {
+   return (
+     <Droppable
+       droppableId={plan.id as string}
+       key={plan.id}
+       type="task"
+       direction={view === 'CARDS' ? 'vertical' : 'horizontal'}
+     >
+       {/* ... existing implementation ... */}
+     </Droppable>
+   );
+ }

- {view === 'TABLE' ? (
-   <DailyPlanTasksTableView
-     profile={profile}
-     plan={plan}
-     data={plan.tasks ?? []}
-   />
- ) : (
-   <Droppable>
-     {/* ... existing implementation ... */}
-   </Droppable>
- )}
+ {view === 'TABLE' ? (
+   <DailyPlanTasksTableView
+     profile={profile}
+     plan={plan}
+     data={plan.tasks ?? []}
+   />
+ ) : (
+   <DailyPlanDraggableView
+     plan={plan}
+     view={view}
+     profile={profile}
+     currentTab={currentTab}
+   />
+ )}
🧰 Tools
🪛 Biome

[error] 356-356: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


290-295: Improve className conditional logic

The className conditional logic could be simplified using a more maintainable approach with a dedicated styles object.

- className={clsxm(
-   view === 'CARDS' && 'flex-col',
-   'flex gap-2 pb-[1.5rem]',
-   view === 'BLOCKS' && 'overflow-x-auto',
-   snapshot.isDraggingOver ? 'lightblue' : '#F7F7F8'
- )}
+ const styles = {
+   base: 'flex gap-2 pb-[1.5rem]',
+   cards: view === 'CARDS' ? 'flex-col' : '',
+   blocks: view === 'BLOCKS' ? 'overflow-x-auto' : '',
+   dragging: snapshot.isDraggingOver ? 'lightblue' : '#F7F7F8'
+ };
+ className={clsxm(styles.base, styles.cards, styles.blocks, styles.dragging)}
apps/web/lib/features/task/task-card.tsx (5)

Line range hint 483-502: Simplify conditional rendering for better readability

In the TaskInfo component, you check for the existence of task multiple times, which can be streamlined to enhance readability.

Consider refactoring the component to reduce redundant checks:

export function TaskInfo({ /* props */ }) {
  const router = useRouter();

+ if (!task) {
+   return <div className="self-center py-1 text-center">--</div>;
+ }

  return (
    <div className={clsxm('h-full flex flex-col items-start justify-between gap-[1.0625rem]', className)}>
      {/* Task */}
-     {!task && <div className="self-center py-1 text-center">--</div>}
      <div className="w-full h-10 overflow-hidden">
        <div className={clsxm('h-full flex flex-col items-start justify-start')}>
          <div
            className={clsxm('text-sm text-ellipsis overflow-hidden w-full cursor-pointer')}
            onClick={() => router.push(`/task/${task.id}`)}
          >
            <TaskNameInfoDisplay
              task={task}
              className={clsxm(taskBadgeClassName)}
              taskTitleClassName={clsxm(taskTitleClassName)}
            />
          </div>
        </div>
      </div>

      {/* Task status */}
      <TaskAllStatusTypes task={task} tab={tab} dayPlanTab={dayPlanTab} />
    </div>
  );
}

Line range hint 483-502: Ensure proper typing of component props

While you have provided types for the TaskInfo component props, the intersection of IClassName and the custom type may lead to cluttered or complex typings.

Consider defining a single interface for the props to enhance clarity:

interface TaskInfoProps extends IClassName {
  tab: 'default' | 'unassign' | 'dailyplan';
  dayPlanTab?: FilterTabs;
  task?: Nullable<ITeamTask>;
  taskBadgeClassName?: string;
  taskTitleClassName?: string;
}

And then use it in your component:

export function TaskInfo(props: TaskInfoProps) {
  // component logic
}

Line range hint 529-619: Optimize useCallback dependencies to prevent unnecessary re-renders

In the TaskCardMenu component, the handleAssignment function's dependencies may be incomplete, potentially leading to stale closures or unexpected behavior.

Ensure that all variables used within useCallback are included in the dependency array. Specifically, verify if memberInfo.assignTask and memberInfo.unassignTask are stable references.

If memberInfo changes frequently, consider memoizing it or adjusting the dependencies:

const handleAssignment = useCallback(() => {
  if (viewType === 'unassign') {
    memberInfo?.assignTask(task);
  } else {
    memberInfo?.unassignTask(task);
  }
- }, [memberInfo, task, viewType]);
+ }, [memberInfo?.assignTask, memberInfo?.unassignTask, task, viewType]);

Line range hint 538-544: Improve performance when calculating task occurrences

The computation of isTaskPlannedMultipleTimes uses a reduce function, which can be made more concise and efficient.

Consider using flatMap and filter to simplify the calculation:

- const isTaskPlannedMultipleTimes =
-   allPlans.reduce((count, plan) => {
-     if (plan?.tasks) {
-       const taskCount = plan.tasks.filter((_task) => _task.id === task.id).length;
-       return count + taskCount;
-     }
-     return count;
-   }, 0) > 1;
+ const taskOccurrences = allPlans
+   .flatMap((plan) => plan.tasks || [])
+   .filter((_task) => _task.id === task.id).length;
+ const isTaskPlannedMultipleTimes = taskOccurrences > 1;

Line range hint 552-562: Simplify date comparison logic

In the taskPlannedTomorrow calculation, the use of moment could be streamlined for better readability and performance.

Consider simplifying the date comparison:

const taskPlannedTomorrow = useMemo(
  () =>
    futurePlans
-     .filter((_plan) =>
-       moment(_plan.date)
-         .format('YYYY-MM-DD')
-         ?.toString()
-         ?.startsWith(moment()?.add(1, 'day').format('YYYY-MM-DD'))
-     )[0]
+     .find((_plan) => moment(_plan.date).isSame(moment().add(1, 'day'), 'day'))
      ?.tasks?.find((_task) => _task.id === task.id),
  [futurePlans, task.id]
);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1a1d0c6 and ff8bf77.

📒 Files selected for processing (11)
  • apps/web/components/ui/data-table.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/future-tasks.tsx (2 hunks)
  • apps/web/lib/features/task/daily-plan/past-tasks.tsx (2 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-action-menu-cell.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-estimation-cell.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-info-cell.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-times-cell.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/index.tsx (1 hunks)
  • apps/web/lib/features/task/task-card.tsx (2 hunks)
  • apps/web/lib/features/team-members-table-view.tsx (0 hunks)
  • apps/web/lib/features/user-profile-plans.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/lib/features/team-members-table-view.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/web/components/ui/data-table.tsx
🧰 Additional context used
🪛 Biome
apps/web/lib/features/task/daily-plan/future-tasks.tsx

[error] 135-135: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

apps/web/lib/features/user-profile-plans.tsx

[error] 356-356: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


[error] 358-409: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

🔇 Additional comments (12)
apps/web/lib/features/task/daily-plan/table-view/cells/task-info-cell.tsx (2)

5-7: LGTM! Clean and type-safe implementation.

The component correctly implements the table cell rendering with proper TypeScript types and integrates well with the existing TaskInfo component.


6-6: Verify the default tab behavior.

The component uses a hardcoded 'default' tab value. Let's verify if this is the intended behavior across all contexts where this cell might be used.

✅ Verification successful

Based on the search results, I can now generate the final response as we have sufficient information about the tab prop usage across the codebase.

The 'default' tab value is consistent with the codebase's type definitions and usage patterns

The hardcoded 'default' tab value is correct as:

  • The type definition in multiple files shows tab is an enum with exactly three possible values: 'default' | 'unassign' | 'dailyplan'
  • Other components consistently use 'default' as the standard tab value for TaskInfo
  • The daily plan table view context aligns with the standard task display scenario where 'default' is appropriate
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other usages of TaskInfo to verify tab prop patterns
ast-grep --pattern 'TaskInfo $$$tab={$_}$$$'

# Search for any configuration or constants defining tab values
rg -g '!*.{lock,json,md}' -i 'tab.*default' 

Length of output: 2068

apps/web/lib/features/task/daily-plan/table-view/cells/task-estimation-cell.tsx (1)

23-24: 🛠️ Refactor suggestion

Verify hardcoded activeAuthTask and add loading states.

The component has a hardcoded activeAuthTask={true} which might not be appropriate for all cases. Additionally, loading and error states should be handled explicitly.

Let's verify the usage of activeAuthTask in the TaskEstimateInfo component:

Consider these improvements:

+  if (!memberInfo || !taskEdition) {
+    return <div>Loading...</div>;
+  }
+
-  return <TaskEstimateInfo plan={plan} memberInfo={memberInfo} edition={taskEdition} activeAuthTask={true} />;
+  return (
+    <TaskEstimateInfo
+      plan={plan}
+      memberInfo={memberInfo}
+      edition={taskEdition}
+      activeAuthTask={taskEdition.canEdit} // or appropriate condition
+    />
+  );
✅ Verification successful

Let me analyze the search results to verify the usage of activeAuthTask prop in the TaskEstimateInfo component.

I want to verify how the activeAuthTask prop is used within the TaskEstimateInfo component to determine if hardcoding it to true is appropriate or if it should be derived from some condition.


Let me search for the usage of canEdit property in the taskEdition object to verify if it would be an appropriate condition for activeAuthTask.

I want to verify if taskEdition.canEdit exists and understand its usage before making a final recommendation about the activeAuthTask prop.


Let me try a different approach to understand the task edition and authorization context.

I want to understand the authorization patterns and task editing permissions before making a final recommendation about the activeAuthTask prop.


Based on the analysis of the codebase, I can now generate the final response regarding the hardcoded activeAuthTask prop.

The hardcoded activeAuthTask={true} is correct in this context

The activeAuthTask prop is used in conjunction with isAuthUser throughout the codebase to control task progress tracking and timer functionality. In the daily plan table view context (task-estimation-cell.tsx), this is the correct behavior because:

  1. The daily plan view represents tasks that are already assigned to the authenticated user
  2. The TaskEstimateInfo component uses this prop to show task progress and estimation information
  3. The prop is consistently set to true in similar daily plan contexts across the codebase

Regarding the loading states:

+ if (!memberInfo || !taskEdition) {
+   return <Spinner />;  // or your preferred loading component
+ }

  return <TaskEstimateInfo plan={plan} memberInfo={memberInfo} edition={taskEdition} activeAuthTask={true} />;
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for TaskEstimateInfo component definition and usages
ast-grep --pattern 'const TaskEstimateInfo = $_' -A 10
rg "activeAuthTask" -A 5

Length of output: 29270


Script:

#!/bin/bash
# Search for TaskEstimateInfo component definition and its usage of activeAuthTask
ast-grep --pattern 'function TaskEstimateInfo({ $$$, activeAuthTask, $$$}) {
  $$$
}'

# Search for any conditional logic related to activeAuthTask in TaskEstimateInfo
rg -A 10 "TaskEstimateInfo.*activeAuthTask" apps/web/lib/features/team/user-team-card/task-estimate.tsx

Length of output: 4700


Script:

#!/bin/bash
# Search for taskEdition.canEdit usage
rg "taskEdition.*canEdit" -A 5

# Search for the type definition of taskEdition
ast-grep --pattern 'type $_Edition = {
  $$$
}'

Length of output: 82


Script:

#!/bin/bash
# Search for task edition type or interface definitions
ast-grep --pattern 'interface $_Edition {
  $$$
}'

# Search for any canEdit related properties in the codebase
rg "canEdit" -A 5

# Look for task authorization patterns
rg "isAuthUser|isAuthTeamManager" -A 5

Length of output: 80873

apps/web/lib/features/task/daily-plan/table-view/cells/task-action-menu-cell.tsx (3)

1-8: LGTM! Imports are well-organized and necessary.

All imports are being utilized appropriately within the component.


1-51: Verify integration with the table view system.

Let's ensure this component is properly integrated with the table configuration.

✅ Verification successful

Component is properly integrated with table configuration

The verification shows that TaskActionMenuCell is correctly integrated:

  • It's properly imported and used in the table configuration at apps/web/lib/features/task/daily-plan/table-view/index.tsx
  • The column definition includes all required meta properties (plan, profile, planMode) that match the component's expectations
  • It's configured as an action column with appropriate header and ID
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for table configuration files that use this component
rg -l "TaskActionMenuCell" --type typescript

# Check for consistent column definitions across the table view
ast-grep --pattern 'columns = [
  $$$
  {
    $$$
    cell: TaskActionMenuCell
    $$$
  }
  $$$
]'

Length of output: 181


Script:

#!/bin/bash
# Search for files containing TaskActionMenuCell
rg "TaskActionMenuCell"

# Search for table configurations using this component
rg "cell.*TaskActionMenuCell" -A 5 -B 5

Length of output: 1247


9-9: 🛠️ Refactor suggestion

Improve type safety for the component props.

The unknown type for the cell value is too permissive and could lead to runtime errors.

-export default function TaskActionMenuCell(props: CellContext<ITeamTask, unknown>) {
+export default function TaskActionMenuCell(props: CellContext<ITeamTask, any>) {
+  // TODO: Replace 'any' with the actual type of the cell value

Likely invalid or redundant comment.

apps/web/lib/features/task/daily-plan/table-view/index.tsx (1)

1-75: Verify view toggle integration

Since this table view is meant to be toggled alongside the existing blocks view (as mentioned in the PR objectives), ensure that the parent component properly handles the view toggle state and passes the correct data props.

✅ Verification successful

View toggle integration is properly implemented

The table view is correctly integrated with the view toggle functionality:

  • The view state is managed through dailyPlanViewHeaderTabs atom and consistently used across components
  • Parent components (past-tasks.tsx, future-tasks.tsx, outstanding-date.tsx, outstanding-all.tsx) properly handle the view toggle and render the table view when view === 'TABLE'
  • The view toggle UI is implemented in views-header-tabs.tsx with all three view options (CARDS, TABLE, BLOCKS)
  • The table view component receives all necessary props (profile, plan, planMode) from parent components
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for view toggle implementation in parent components
rg -t tsx -t jsx "view.*[\"']TABLE[\"']|[\"']BLOCKS?[\"']" ./apps/web/lib/features/task/daily-plan/

Length of output: 137


Script:

#!/bin/bash
# Search for view toggle implementation in parent components with correct file extensions
rg --type-add 'tsx:*.tsx' --type-add 'jsx:*.jsx' -t tsx -t jsx "view.*[\"']TABLE[\"']|[\"']BLOCKS?[\"']" ./apps/web/lib/features/task/daily-plan/

# Also search for any view-related state or props
rg --type-add 'tsx:*.tsx' --type-add 'jsx:*.jsx' -t tsx -t jsx -A 3 "(viewType|viewMode|view)\s*[=:]" ./apps/web/lib/features/task/daily-plan/

# Look for files that might contain the view toggle implementation
fd -e tsx -e jsx . ./apps/web/lib/features/task/daily-plan/ --exec head -n 20 {}

Length of output: 22229

apps/web/lib/features/task/daily-plan/past-tasks.tsx (1)

16-16: LGTM: Clean import addition

The new table view component import follows the established naming and import conventions.

apps/web/lib/features/task/daily-plan/future-tasks.tsx (2)

19-19: LGTM: Clean import of new table view component

The import of DailyPlanTasksTableView aligns with the PR objectives of implementing a table view for planned tasks.


61-67: Verify table view consistency with Teams page

Let's ensure the table view implementation matches the Teams page layout and functionality.

apps/web/lib/features/user-profile-plans.tsx (2)

272-279: LGTM: Clean implementation of table view integration

The conditional rendering of the table view is well-implemented, with proper prop passing for profile, plan, and task data.


361-404: Verify the impact of deleting a plan with tasks

The delete plan functionality should handle cleanup of associated tasks. Consider adding a warning message if the plan contains tasks.

@evereq
Copy link
Member

evereq commented Nov 14, 2024

@CREDO23 it's hard for me to merge this one as complex merge conflict. Please try to rebase on top of develop and try to see if you can CAREFULLY fix merge conflicts

@CREDO23 CREDO23 requested review from evereq and Cedric921 November 15, 2024 04:16
@CREDO23 CREDO23 force-pushed the 3128-improvement-daily-plan--implement-table-view-for-planned-tasks-page branch from ff8bf77 to 09d6d15 Compare November 15, 2024 05:45
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 (9)
apps/web/lib/features/task/daily-plan/future-tasks.tsx (3)

19-19: Add type safety for view modes and profile prop

The table view integration looks good, but there are opportunities to improve type safety:

  1. Define an enum or union type for view modes:
type ViewMode = 'TABLE' | 'CARDS' | 'BLOCKS';
  1. Add proper typing for the profile prop instead of using 'any':
interface Profile {
  // Add relevant profile properties
}

export function FutureTasks({ profile }: { profile: Profile })

Also applies to: 61-67


91-94: Extract common drag and drop styles

The margin styles are duplicated between card and block view draggable components. Consider extracting these into a reusable style object:

const draggableStyles = (provided: DraggableProvided) => ({
  ...provided.draggableProps.style,
  marginBottom: view === 'CARDS' ? 4 : 8
});

// Then use it in both places:
style={draggableStyles(provided)}

Also applies to: 124-127


178-180: Simplify conditional rendering

The empty fragment fallback can be simplified by removing the explicit condition:

-{canSeeActivity ? (
  <div className="flex shrink-0 justify-end">
    <AlertPopup>
      {/* ... */}
    </AlertPopup>
  </div>
-) : (
-  <></>
-)}
+{canSeeActivity && (
+  <div className="flex shrink-0 justify-end">
+    <AlertPopup>
+      {/* ... */}
+    </AlertPopup>
+  </div>
+)}
apps/web/lib/features/user-profile-plans.tsx (2)

345-425: Consider extracting Droppable component logic

The Droppable component implementation contains complex nested conditional rendering with multiple levels of component nesting. This could be extracted into a separate component to improve readability and maintainability.

Consider extracting the Droppable logic into a separate component like this:

+ const TaskList = ({ view, plan, profile, currentTab }) => {
+   return (
+     <Droppable
+       droppableId={plan.id}
+       key={plan.id}
+       type="task"
+       direction={view === 'CARDS' ? 'vertical' : 'horizontal'}
+     >
+       {(provided, snapshot) => (
+         // ... existing Droppable content
+       )}
+     </Droppable>
+   );
+ };

  {view === 'TABLE' ? (
    <DailyPlanTasksTableView
      profile={profile}
      plan={plan}
      data={plan.tasks ?? []}
    />
  ) : (
-   <Droppable...>
+   <TaskList view={view} plan={plan} profile={profile} currentTab={currentTab} />
  )}
🧰 Tools
🪛 Biome

[error] 421-421: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


362-420: Consider memoizing task rendering logic

The task rendering logic inside the map function is complex and could benefit from memoization to prevent unnecessary re-renders, especially for large task lists.

Consider extracting the task rendering logic into a memoized component:

const MemoizedTaskItem = React.memo(({ task, view, provided, plan, profile, currentTab }) => {
  if (view === 'CARDS') {
    return (
      <div
        ref={provided.innerRef}
        {...provided.draggableProps}
        {...provided.dragHandleProps}
        style={{
          ...provided.draggableProps.style,
          marginBottom: 6
        }}
      >
        <TaskCard
          isAuthUser={true}
          activeAuthTask={true}
          viewType={'dailyplan'}
          task={task}
          profile={profile}
          type="HORIZONTAL"
          taskBadgeClassName={`rounded-sm`}
          taskTitleClassName="mt-[0.0625rem]"
          planMode={currentTab === 'Today Tasks' ? 'Today Tasks' : undefined}
          plan={plan}
          className="shadow-[0px_0px_15px_0px_#e2e8f0]"
        />
      </div>
    );
  }
  return <TaskBlockCard task={task} />;
});
apps/web/lib/features/task/task-card.tsx (4)

Line range hint 483-528: Critical: Improve error handling and state management in TimerButtonCall

The timer start logic has potential issues that need to be addressed:

  1. Task status check should be done before state updates
  2. Potential race condition between setActiveTask and timer start
  3. Missing error handling for updateOrganizationTeamEmployee

Consider this improved implementation:

 const startTimerWithTask = useCallback(async () => {
+    if (!task || task.status === 'closed') {
+        return;
+    }
     setLoading(true);
-    if (task.status === 'closed') return;
     try {
         if (timerStatus?.running) {
             await stopTimer();
         }
         
         setActiveTask(task);
         
         // Update Current user's active task
-        const currentEmployeeDetails = activeTeam?.members.find((member) => member.id === currentMember?.id);
-        if (currentEmployeeDetails && currentEmployeeDetails.id) {
-            updateOrganizationTeamEmployee(currentEmployeeDetails.id, {
+        const currentEmployeeDetails = activeTeam?.members.find(
+            (member) => member.id === currentMember?.id
+        );
+        if (currentEmployeeDetails?.id) {
+            await updateOrganizationTeamEmployee(currentEmployeeDetails.id, {
                 organizationId: task.organizationId,
                 activeTaskId: task.id,
                 organizationTeamId: activeTeam?.id,
                 tenantId: activeTeam?.tenantId
             });
         }
-        window.setTimeout(startTimer, 100);
+        await startTimer();
+    } catch (error) {
+        console.error('Failed to start timer:', error);
+        // Handle error appropriately
+    } finally {
+        setLoading(false);
     }
 }, [/* ... existing dependencies ... */]);

Line range hint 483-528: Enhance accessibility in TaskInfo component

The component needs accessibility improvements for better usability:

 <div
     className={clsxm('text-sm text-ellipsis overflow-hidden w-full cursor-pointer')}
     onClick={() => task && router.push(`/task/${task?.id}`)}
+    role="button"
+    tabIndex={0}
+    onKeyDown={(e) => {
+        if (e.key === 'Enter' || e.key === ' ') {
+            task && router.push(`/task/${task?.id}`);
+        }
+    }}
+    aria-label={`View details for task ${task?.taskNumber}`}
 >

Line range hint 529-728: Optimize TaskCardMenu implementation

The component has several areas for improvement:

  1. Simplify boolean checks:
-if (viewType == 'default' ||
-    (viewType === 'dailyplan' && planMode === 'Outstanding')) {
+const shouldShowPlanOptions = viewType === 'default' || 
+    (viewType === 'dailyplan' && planMode === 'Outstanding');
+if (shouldShowPlanOptions) {
  1. Add loading states for task actions:
 <span
     onClick={() => toggleFavorite(task)}
+    className={clsxm(
+        'font-normal whitespace-nowrap transition-all',
+        'hover:font-semibold hover:transition-all',
+        loading && 'opacity-50 cursor-not-allowed'
+    )}
+    aria-disabled={loading}
 >
  1. Optimize useMemo dependencies:
 const taskPlannedToday = useMemo(
     () => todayPlan[todayPlan.length - 1]?.tasks?.find(
         (_task) => _task.id === task.id
     ),
-    [task.id, todayPlan]
+    [task?.id, todayPlan[todayPlan.length - 1]?.tasks]
 );

Line range hint 729-900: Improve type safety in helper components

The helper components need better TypeScript type definitions and error handling:

+interface PlanTaskProps {
+    taskId: string;
+    planMode: IDailyPlanMode;
+    employeeId?: string;
+    chooseMember?: boolean;
+    taskPlannedToday?: ITeamTask;
+    taskPlannedForTomorrow?: ITeamTask;
+}

-export function PlanTask({
+export function PlanTask({
     planMode,
     taskId,
     employeeId,
     chooseMember,
     taskPlannedToday,
     taskPlannedForTomorrow
-}: {
-    taskId: string;
-    planMode: IDailyPlanMode;
-    employeeId?: string;
-    chooseMember?: boolean;
-    taskPlannedToday?: ITeamTask;
-    taskPlannedForTomorrow?: ITeamTask;
-})
+}: PlanTaskProps)

Also add error boundaries for the components:

import { ErrorBoundary } from 'react-error-boundary';

export function PlanTask(props: PlanTaskProps) {
    return (
        <ErrorBoundary fallback={<div>Something went wrong</div>}>
            {/* Existing component code */}
        </ErrorBoundary>
    );
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ff8bf77 and 09d6d15.

📒 Files selected for processing (11)
  • apps/web/components/ui/data-table.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/future-tasks.tsx (2 hunks)
  • apps/web/lib/features/task/daily-plan/past-tasks.tsx (2 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-action-menu-cell.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-estimation-cell.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-info-cell.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-times-cell.tsx (1 hunks)
  • apps/web/lib/features/task/daily-plan/table-view/index.tsx (1 hunks)
  • apps/web/lib/features/task/task-card.tsx (2 hunks)
  • apps/web/lib/features/team-members-table-view.tsx (0 hunks)
  • apps/web/lib/features/user-profile-plans.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/lib/features/team-members-table-view.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/web/components/ui/data-table.tsx
  • apps/web/lib/features/task/daily-plan/past-tasks.tsx
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-action-menu-cell.tsx
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-estimation-cell.tsx
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-info-cell.tsx
  • apps/web/lib/features/task/daily-plan/table-view/cells/task-times-cell.tsx
  • apps/web/lib/features/task/daily-plan/table-view/index.tsx
🧰 Additional context used
🪛 Biome
apps/web/lib/features/task/daily-plan/future-tasks.tsx

[error] 135-135: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

apps/web/lib/features/user-profile-plans.tsx

[error] 421-421: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

🔇 Additional comments (3)
apps/web/lib/features/user-profile-plans.tsx (3)

53-53: LGTM: Clean import statement

The import of the new DailyPlanTasksTableView component follows the project's import conventions.


338-344: LGTM: Clean conditional rendering implementation

The table view implementation correctly uses conditional rendering based on the view state, passing the necessary props to the DailyPlanTasksTableView component.


421-421: 🛠️ Refactor suggestion

Remove unnecessary Fragment wrapper

The Fragment wrapper around provided.placeholder is unnecessary as it's the only child element.

Apply this change:

- <>{provided.placeholder}</>
+ {provided.placeholder}

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome

[error] 421-421: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

@evereq evereq merged commit ae9cb25 into develop Nov 18, 2024
13 checks passed
@evereq evereq deleted the 3128-improvement-daily-plan--implement-table-view-for-planned-tasks-page branch November 18, 2024 19:21
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.

[Improvement] Daily Plan | Implement Table view for Planned Tasks page
2 participants