-
Notifications
You must be signed in to change notification settings - Fork 74
feat: add table view for daily plan tasks #3335
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 table view for daily plan tasks #3335
Conversation
WalkthroughThe 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, Changes
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
Assessment against linked issues
Possibly related PRs
Suggested reviewers
Poem
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
apps/web/components/ui/data-table.tsxOops! 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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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 sizeConsider 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 parametersThe
unknown
type for the second generic parameter ofCellContext
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 statesThe 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:
- Wrapping the component in an error boundary
- Adding loading states while data is being fetched
- 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:
- Add ARIA labels for better accessibility
- Move hardcoded width values to theme constants
- 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 interfaceConsider 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 paramThe 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 dataConsider 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 stateWhile 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 colorsReplace 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 componentThere'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 handlingThe table view integration looks good, but consider these improvements:
- The
data
prop seems redundant since it's justplan.tasks
. Consider passingplan.tasks
directly.- 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 logicThe 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 componentThe 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 logicThe 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 readabilityIn the
TaskInfo
component, you check for the existence oftask
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 propsWhile you have provided types for the
TaskInfo
component props, the intersection ofIClassName
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-rendersIn the
TaskCardMenu
component, thehandleAssignment
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 ifmemberInfo.assignTask
andmemberInfo.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 occurrencesThe computation of
isTaskPlannedMultipleTimes
uses areduce
function, which can be made more concise and efficient.Consider using
flatMap
andfilter
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 logicIn the
taskPlannedTomorrow
calculation, the use ofmoment
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
📒 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:
- The daily plan view represents tasks that are already assigned to the authenticated user
- The TaskEstimateInfo component uses this prop to show task progress and estimation information
- 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 whenview === '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.
apps/web/lib/features/task/daily-plan/table-view/cells/task-times-cell.tsx
Show resolved
Hide resolved
apps/web/lib/features/task/daily-plan/table-view/cells/task-times-cell.tsx
Show resolved
Hide resolved
apps/web/lib/features/task/daily-plan/table-view/cells/task-estimation-cell.tsx
Show resolved
Hide resolved
apps/web/lib/features/task/daily-plan/table-view/cells/task-estimation-cell.tsx
Show resolved
Hide resolved
apps/web/lib/features/task/daily-plan/table-view/cells/task-action-menu-cell.tsx
Show resolved
Hide resolved
@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 |
ff8bf77
to
09d6d15
Compare
There was a problem hiding this 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 propThe table view integration looks good, but there are opportunities to improve type safety:
- Define an enum or union type for view modes:
type ViewMode = 'TABLE' | 'CARDS' | 'BLOCKS';
- 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 stylesThe 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 renderingThe 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 logicThe 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 logicThe 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 TimerButtonCallThe timer start logic has potential issues that need to be addressed:
- Task status check should be done before state updates
- Potential race condition between setActiveTask and timer start
- 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 componentThe 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 implementationThe component has several areas for improvement:
- Simplify boolean checks:
-if (viewType == 'default' || - (viewType === 'dailyplan' && planMode === 'Outstanding')) { +const shouldShowPlanOptions = viewType === 'default' || + (viewType === 'dailyplan' && planMode === 'Outstanding'); +if (shouldShowPlanOptions) {
- 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} >
- 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 componentsThe 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
📒 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)
Description
Fix #3128
Type of Change
Checklist
Previous screenshots
Current screenshots
Summary by CodeRabbit
Release Notes
New Features
DailyPlanTasksTableView
component.Invite
component for user invitations within theTeamMembersTableView
.FutureTasks
component.Bug Fixes
TaskCard
component to prevent starting timers on closed tasks.Improvements