-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
3108 feature/ task list view all tasks in a team #3234
3108 feature/ task list view all tasks in a team #3234
Conversation
Warning Rate limit exceeded@NdekoCode has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 5 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. WalkthroughThe pull request includes multiple changes across various files, focusing on code formatting, structural adjustments, and the introduction of new components. Key modifications include disabling the automatic removal of unused imports in the Changes
Possibly related PRs
Suggested labels
Suggested reviewers
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 (
|
🚨 Potential security issues detected. Learn more about Socket for GitHub ↗︎ To accept the risk, merge this PR and you will not be notified again.
Next stepsWhat is a critical CVE?Contains a Critical Common Vulnerability and Exposure (CVE). Remove or replace dependencies that include known critical CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies. Take a deeper look at the dependencyTake a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support [AT] socket [DOT] dev. Remove the packageIf you happen to install a dependency that Socket reports as Known Malware you should immediately remove it and select a different dependency. For other alert types, you may may wish to investigate alternative packages or consider if there are other ways to mitigate the specific risk posed by the dependency. Mark a package as acceptable riskTo ignore an alert, reply with a comment starting with
|
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: 19
🧹 Outside diff range and nitpick comments (44)
apps/web/app/stores/menu.ts (1)
4-4
: Consider enhancing type safety and storage key management.While the implementation is functional, there are opportunities for improvement:
- The type
{ [key: string]: boolean }
could be more specific to prevent potential errors.- The storage key should be namespaced to avoid conflicts.
Consider these improvements:
+// Define specific menu keys to enhance type safety +type MenuKey = 'main' | 'tasks' | 'settings' | 'profile'; +type MenuState = { [K in MenuKey]?: boolean }; + -export const openMenusState = atom<{ [key: string]: boolean }>({}); +export const openMenusState = atom<MenuState>({}); + +// Use a namespaced storage key -export const openMenusStateStorage = atomWithStorage<{ [key: string]: boolean }>('sidebar-open-menus', {}); +export const openMenusStateStorage = atomWithStorage<MenuState>('ever-teams:sidebar-open-menus', {});Also applies to: 6-8
apps/web/components/pages/team/tasks/StatusBadge.tsx (3)
1-2
: Remove unnecessary React importSince React 17+, the React import is not required for JSX usage due to the new JSX transform.
import { cn } from '@/lib/utils'; -import React from 'react';
4-8
: Enhance type safety and documentationConsider the following improvements:
- Add JSDoc documentation to describe the component's purpose and props
- Make the
color
prop type-safe by using a union type of allowed colors+/** + * A badge component that displays a status label with a count + */ interface StatusBadgeProps { + /** The text label to display */ label: string; + /** The count to display in parentheses */ count: number; - color: string; + /** The background color class for the badge */ + color: 'bg-gray-100' | 'bg-yellow-100' | 'bg-green-100' | 'bg-red-100'; }
10-21
: Enhance accessibility and performanceConsider the following improvements:
- Add proper ARIA attributes for better accessibility
- Memoize the component if it's used in lists
- Extract the base classes for reusability
-const StatusBadge: React.FC<StatusBadgeProps> = ({ label, count, color }) => { +const baseClasses = 'gap-0.5 self-stretch py-1.5 justify-center md:px-3 px-2 flex items-center capitalize text-sm relative min-h-[26px] rounded-[40px]'; + +const StatusBadge = React.memo(({ label, count, color }: StatusBadgeProps) => { return ( <div + role="status" + aria-label={`${label} status with count ${count}`} className={cn( - 'gap-0.5 self-stretch py-1.5 justify-center md:px-3 px-2 flex items-center capitalize text-sm relative min-h-[26px] rounded-[40px]', + baseClasses, color )} > {label} ({count}) </div> ); -}; +}); + +StatusBadge.displayName = 'StatusBadge';apps/web/components/pages/team/tasks/AssigneeUser.tsx (1)
5-6
: Consider handling multiple assignees and simplify array access.The component currently only displays the first assignee, which might be limiting. Also,
users.at(0)
could be simplified tousers[0]
for better readability.-const employee = users && users.length > 0 ? users.at(0) : null; +const employee = users?.[0] ?? null;Consider adding support for multiple assignees if that's a requirement:
const AssigneeUser: FC<{ users: IEmployee[]; showAll?: boolean }> = ({ users, showAll }) => { if (!users?.length) { return <span className="text-xs font-medium text-indigo-950 dark:text-gray-200">No user assigned</span>; } return ( <div className="flex items-center gap-1.5 h-full"> {(showAll ? users : [users[0]]).map((employee) => ( <div key={employee.id} className="flex items-center gap-2.5"> {/* ... existing avatar and name rendering ... */} </div> ))} {!showAll && users.length > 1 && ( <span className="text-xs text-gray-500">+{users.length - 1} more</span> )} </div> ); };apps/web/components/pages/team/tasks/TaskTable.tsx (3)
1-8
: Consider standardizing import paths for better maintainability.The mix of relative (
./columns
) and absolute (@/app/hooks
) imports could be standardized. Consider using absolute imports consistently throughout the file for better maintainability and easier refactoring.-import { columns } from './columns'; -import { TasksDataTable } from './tasks-data-table'; +import { columns } from '@/app/components/pages/team/tasks/columns'; +import { TasksDataTable } from '@/app/components/pages/team/tasks/tasks-data-table';
14-29
: Enhance component performance and accessibility.A few suggestions to improve the implementation:
- Memoize the columns prop since it's likely static
- Add appropriate ARIA labels for accessibility
- Consider adding empty state handling when there are no tasks
+import { useMemo } from 'react'; + export function TaskTable() { const { tasks } = useTeamTasks(); + const memoizedColumns = useMemo(() => columns, []); const { total, onPageChange, itemsPerPage, itemOffset, endOffset, setItemsPerPage, currentItems } = usePagination<ITeamTask>(tasks); + + if (currentItems.length === 0) { + return <div className="w-full text-center py-4">No tasks found</div>; + } + return ( - <div className="w-full flex flex-col min-h-full"> - <TasksDataTable columns={columns} className="border-none" data={currentItems} /> + <div className="w-full flex flex-col min-h-full" role="region" aria-label="Team Tasks"> + <TasksDataTable + columns={memoizedColumns} + className="border-none" + data={currentItems} + /> <Paginate total={total}
1-30
: Add JSDoc documentation for the component.Since this is a new feature for task list view, adding comprehensive documentation would help other developers understand the component's purpose and usage.
+/** + * TaskTable Component + * + * Displays a paginated table of team tasks with sorting and filtering capabilities. + * Integrates with the team's task management system and provides pagination controls. + * + * @example + * ```tsx + * <TaskTable /> + * ``` + */ export function TaskTable() {apps/web/app/hooks/features/useAuthTeamTasks.ts (3)
16-28
: Consider optimizing task filtering performanceThe current implementation performs two separate iterations over the tasks array. Consider combining both filters into a single pass for better performance, especially with large task lists.
-const assignedTasks = useMemo(() => { - if (!user) return []; - return tasks.filter((task) => { - return task?.members.some((m) => m.userId === user.id); - }); -}, [tasks, user]); - -const unassignedTasks = useMemo(() => { - if (!user) return []; - return tasks.filter((task) => { - return !task?.members.some((m) => m.userId === user.id); - }); -}, [tasks, user]); +const { assignedTasks, unassignedTasks } = useMemo(() => { + if (!user) return { assignedTasks: [], unassignedTasks: [] }; + return tasks.reduce( + (acc, task) => { + const isAssigned = task?.members.some((m) => m.userId === user.id); + if (isAssigned) { + acc.assignedTasks.push(task); + } else { + acc.unassignedTasks.push(task); + } + return acc; + }, + { assignedTasks: [], unassignedTasks: [] } + ); +}, [tasks, user]);
31-33
: Simplify nested array mappingThe nested map operations can be flattened for better readability.
-const outStandingTasksCount = estimatedTotalTime( - outstandingPlans?.map((plan) => plan.tasks?.map((task) => task)) -).totalTasks; +const outStandingTasksCount = estimatedTotalTime( + outstandingPlans?.flatMap((plan) => plan.tasks || []) +).totalTasks;
35-35
: Fix typo in variable nameThe variable name contains an inconsistent capitalization.
-const todayTasksCOunt = getTotalTasks(todayPlan); +const todayTasksCount = getTotalTasks(todayPlan);apps/web/lib/features/activity/components/screenshot-details.tsx (1)
25-25
: Improved scrolling behavior withoverflow-x-auto
The change from
overflow-x-scroll
tooverflow-x-auto
is a good improvement as it:
- Shows scrollbars only when necessary, reducing visual clutter
- Follows web accessibility best practices by not forcing scrollbars
- Maintains consistent behavior across different screen sizes and content lengths
Consider also adding
scrollbar-gutter: stable
to prevent layout shifts when the scrollbar appears:-<div className="w-full p-4 overflow-x-auto"> +<div className="w-full p-4 overflow-x-auto scrollbar-gutter-stable">apps/web/components/pages/team/tasks/FilterButton.tsx (2)
19-75
: Consider extracting and standardizing the SVG icon.The SVG implementation has inconsistent stroke colors (
#282048
and#292D32
) and could benefit from being extracted into a separate component.Consider:
- Creating a separate
FilterIcon
component- Standardizing the stroke color
- Making the color configurable via props
+// components/icons/FilterIcon.tsx +interface FilterIconProps { + className?: string; + color?: string; +} + +export const FilterIcon = ({ className, color = 'currentColor' }: FilterIconProps) => ( + <svg + className={className} + width={14} + height={14} + viewBox="0 0 14 14" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + {/* SVG paths with standardized stroke={color} */} + </svg> +); // In FilterButton.tsx -<svg className="w-4 h-4" ...> +<FilterIcon className="w-4 h-4" />
14-97
: Consider enhancing the filter functionality.While the current implementation handles basic column visibility, consider adding these common table filter features:
- Persistence of filter state (e.g., using localStorage or URL params)
- Reset to default visibility
- Select/deselect all columns option
Example implementation of these features:
// Add these props to FilterButtonProps interface FilterButtonProps<TData> { table: Table<TData>; persistKey?: string; // Optional key for storing state defaultVisible?: string[]; // Default visible columns } // Inside the component, add these features const persistedState = persistKey ? localStorage.getItem(persistKey) : null; useEffect(() => { if (persistedState) { const visibleColumns = JSON.parse(persistedState); table.getAllColumns().forEach(column => { column.toggleVisibility(visibleColumns.includes(column.id)); }); } }, []); // Add these actions to DropdownMenuContent <DropdownMenuContent> <DropdownMenuItem onSelect={() => { table.getAllColumns().forEach(column => { column.toggleVisibility(true); }); }}> Show All </DropdownMenuItem> <DropdownMenuItem onSelect={() => { table.getAllColumns().forEach(column => { column.toggleVisibility(false); }); }}> Hide All </DropdownMenuItem> <DropdownMenuSeparator /> {/* Existing column checkboxes */} </DropdownMenuContent>apps/web/lib/components/pagination.tsx (1)
30-30
: Consider documenting className usage and potential responsive conflictsWhile the className implementation is correct, consider:
- Adding JSDoc comments to document the expected className format and usage
- Being cautious about potential conflicts between custom classes and the built-in responsive utilities (
flex-col md:flex-row
)Add documentation above the Props type:
/** * Props for the Paginate component * @property {string} className - Optional CSS classes to override or extend the default styling. * Note: Be cautious with flex/responsive utilities as they might conflict with built-in styles. */ type Props = {apps/web/components/pages/team/tasks/DropdownMenuTask.tsx (2)
16-25
: Consider optimizing member lookup for better performance.The current member lookup using
array.find()
has O(n) complexity. For better performance with large teams, consider using a Map or maintaining a lookup object.const DropdownMenuTask: FC<{ task: ITeamTask }> = ({ task }) => { const { activeTeam } = useOrganizationTeams(); const router = useRouter(); const { user } = useAuthenticateUser(); - const member = activeTeam?.members.find((m) => m?.employee?.user?.id === user?.id); + // Create a lookup map when team data changes + const memberMap = useMemo(() => { + const map = new Map(); + activeTeam?.members.forEach((m) => { + if (m?.employee?.user?.id) { + map.set(m.employee.user.id, m); + } + }); + return map; + }, [activeTeam?.members]); + const member = user?.id ? memberMap.get(user.id) : undefined;
38-64
: Enhance button accessibility.While the button includes a screen reader text, it could benefit from additional ARIA attributes for better accessibility.
<Button variant="ghost" className="h-8 w-8 p-0 dark:text-gray-200 text-[#292D32]" + aria-haspopup="true" + aria-expanded="false" + aria-label="Task options menu" >apps/web/lib/components/combobox/index.tsx (4)
36-39
: Consider more descriptive state variable names.The
popoverWidth
state could be renamed totriggerWidth
orbuttonWidth
since it specifically stores the width of the trigger button.-const [popoverWidth, setPopoverWidth] = React.useState<number | null>(null); +const [triggerWidth, setTriggerWidth] = React.useState<number | null>(null);
41-48
: Consider adding type safety to handleSelect function.The currentValue parameter could be more strictly typed to match the return type of itemToValue.
-const handleSelect = (currentValue: string) => { +const handleSelect = (currentValue: ReturnType<typeof itemToValue>) => {
50-54
: Consider optimizing the width calculation effect.The effect could be simplified by using a ResizeObserver for more efficient width tracking, especially useful if the button width changes dynamically.
React.useEffect(() => { + const observer = new ResizeObserver((entries) => { + const [entry] = entries; + setPopoverWidth(entry.contentRect.width); + }); + if (triggerRef.current) { - setPopoverWidth(triggerRef.current.offsetWidth); + observer.observe(triggerRef.current); } + + return () => observer.disconnect(); }, [triggerRef.current]);
90-105
: Consider enhancing keyboard navigation feedback.While the component has good accessibility features, the CommandItem could benefit from more visible focus states for keyboard navigation.
<CommandItem className={cn( 'w-full dark:bg-dark--theme-light', + 'focus:ring-2 focus:ring-offset-2 focus:ring-primary focus:outline-none', className )} key={itemToValue(item)} value={itemToValue(item)} onSelect={() => handleSelect(itemToValue(item))} >
apps/web/app/interfaces/ITask.ts (1)
Line range hint
119-124
: Redundant type definitions for issue types.There are two similar type definitions for issue types:
ITaskIssue
typeIssueType
enumConsider consolidating these to avoid potential maintenance issues.
Consider using the enum as the type:
-export type ITaskIssue = 'Bug' | 'Task' | 'Story' | 'Epic'; +export type ITaskIssue = IssueType;Also applies to: 126-131
apps/web/components/pages/team/tasks/columns.tsx (3)
102-109
: Consider adding text truncation for long titles.The title might overflow its container with long text. Consider adding text truncation.
cell: ({ row }) => ( - <div className="text-sm font-semibold text-indigo-950 dark:text-gray-200">{row.original.title}</div> + <div className="text-sm font-semibold text-indigo-950 dark:text-gray-200 truncate max-w-[300px]" title={row.original.title}> + {row.original.title} + </div> )
115-127
: Consider extracting className configurations.The hardcoded className values could be moved to a configuration object or CSS module for better maintainability.
const statusDropdownStyles = { wrapper: 'lg:max-w-[190px] w-full', status: 'text-xs py-1.5 w-full' } as const; // Then in the cell renderer cell: ({ row }) => ( <ActiveTaskStatusDropdown task={row.original} defaultValue={row.original.status} className={statusDropdownStyles.wrapper} taskStatusClassName={statusDropdownStyles.status} /> )
128-134
: Consider adding error boundary for the action menu.The DropdownMenuTask component might fail if the task data is malformed. Consider wrapping it in an error boundary.
import { ErrorBoundary } from '@/components/common/ErrorBoundary'; // In the cell renderer cell: ({ row }) => ( <ErrorBoundary fallback={<div>Failed to load actions</div>}> <DropdownMenuTask task={row.original} /> </ErrorBoundary> )apps/web/lib/features/task/daily-plan/outstanding-date.tsx (2)
15-17
: Consider adding proper typing for the profile prop.Using
any
type reduces type safety. Consider defining a proper interface or type for the profile prop to improve type checking and code maintainability.interface IOutstandingFilterDate { - profile: any; + profile: { + id: string; + // Add other required profile properties + }; }
110-112
: Remove commented code.The commented placeholder and "Plan tasks list" comment appear to be unnecessary. Consider removing them to maintain code cleanliness.
- {/* <>{provided.placeholder}</> */} - {/* Plan tasks list */}apps/web/lib/features/team-members.tsx (3)
96-96
: Consider extracting repeated className into a constant.The same className string
"!overflow-x-auto !mx-0 px-1"
is duplicated across multiple Container components. This could lead to maintenance issues if the styling needs to change.Consider applying this refactor:
+ const CONTAINER_CLASSES = "!overflow-x-auto !mx-0 px-1"; // Then use it in all Container components like: - <Container fullWidth={fullWidth} className="!overflow-x-auto !mx-0 px-1"> + <Container fullWidth={fullWidth} className={CONTAINER_CLASSES}>Also applies to: 113-113, 126-126, 149-149, 161-161
Line range hint
161-169
: Consider removing redundant default case.The default case duplicates the exact same logic as the
IssuesView.CARDS
case. This violates the DRY principle and could lead to maintenance issues.Consider removing the default case and letting the CARDS case handle both scenarios:
- default: - teamMembersView = ( - <Container fullWidth={fullWidth} className="!overflow-x-auto !mx-0 px-1"> - <TeamMembersCardView - teamMembers={$members} - currentUser={currentUser} - publicTeam={publicTeam} - teamsFetching={teamsFetching} - /> - </Container> - );
Line range hint
176-185
: Consider improving the readability of sortByWorkStatus function.The current implementation uses a long chain of conditions that's hard to read and maintain. Consider breaking it down into more readable parts.
Here's a suggested refactor:
const sortByWorkStatus = (user_a: OT_Member, user_b: OT_Member) => { - return user_a.timerStatus == 'running' || - (user_a.timerStatus == 'online' && user_b.timerStatus != 'running') || - (user_a.timerStatus == 'pause' && user_b.timerStatus !== 'running' && user_b.timerStatus !== 'online') || - (user_a.timerStatus == 'idle' && user_b.timerStatus == 'suspended') || - (user_a.timerStatus === undefined && user_b.timerStatus == 'suspended') - ? true - : false; + const statusPriority = { + 'running': 1, + 'online': 2, + 'pause': 3, + 'idle': 4, + 'suspended': 5, + undefined: 4 + }; + return statusPriority[user_a.timerStatus] < statusPriority[user_b.timerStatus]; };This approach:
- Makes the priority order explicit and easy to modify
- Reduces cognitive complexity
- Is more maintainable
apps/web/lib/features/task/daily-plan/past-tasks.tsx (3)
17-26
: Consider adding proper typing for the profile prop.The
profile
prop is currently typed asany
. Consider defining a proper interface or type for better type safety and code maintainability.-export function PastTasks({ profile, currentTab = 'Past Tasks' }: { profile: any; currentTab?: FilterTabs }) { +interface ProfileProps { + // Add relevant profile properties here + id: string; + // ... other properties +} + +export function PastTasks({ profile, currentTab = 'Past Tasks' }: { profile: ProfileProps; currentTab?: FilterTabs }) {
28-71
: Consider enhancing drag-and-drop accessibility.The drag-and-drop functionality should include ARIA attributes and keyboard navigation support for better accessibility.
Consider adding aria labels and role attributes:
<ul ref={provided.innerRef} {...provided.droppableProps} + role="list" + aria-label="Draggable task list" className={clsxm( // ... existing classes )} >
72-123
: Consider extracting task rendering logic into separate components.The task rendering logic contains complex conditional rendering with duplicate code between CARDS and TABLE views. Consider extracting this into separate components to improve maintainability and reduce code duplication.
Example refactor:
// TaskItem.tsx interface TaskItemProps { task: Task; index: number; view: 'CARDS' | 'TABLE'; plan: Plan; profile: ProfileProps; currentTab: FilterTabs; } const TaskItem = ({ task, index, view, plan, profile, currentTab }: TaskItemProps) => { 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 // ... TaskCard props /> ) : ( <TaskBlockCard task={task} /> )} </div> )} </Draggable> ); };apps/web/components/nav-main.tsx (2)
41-64
: Consider refactoring handleMenuToggle for better maintainabilityWhile the implementation works, the
handleMenuToggle
function could be simplified and split for better maintainability and performance.Consider this refactoring:
-const handleMenuToggle = (label: string, index: number) => { - setOpenMenus((prev) => ({ - ...prev, - [label]: !prev[label] - })); - - // Close all other sub-menus - setOpenMenus((prev) => { - const newState = { ...prev }; - Object.keys(prev).forEach((key) => { - if (key !== label) { - newState[key] = false; - } - }); - return newState; - }); - - setActiveMenuIndex(index); - setActiveSubMenuIndex(null); -}; +const handleMenuToggle = (label: string, index: number) => { + setOpenMenus((prev) => { + const newState = Object.keys(prev).reduce((acc, key) => ({ + ...acc, + [key]: key === label ? !prev[key] : false + }), {}); + return newState; + }); + + setActiveMenuIndex(index); + setActiveSubMenuIndex(null); +};This refactoring:
- Combines the two state updates into one
- Uses reduce for better readability
- Maintains the same functionality with less code
89-95
: Simplify collapsed state rendering using component compositionThe current implementation duplicates the collapsed state rendering logic. This can be simplified using component composition.
Consider extracting the icon rendering logic:
const MenuIcon = ({ icon: Icon, collapsed }: { icon: LucideIcon; collapsed: boolean }) => { if (collapsed) { return ( <SidebarTriggerButton className="!p-0 !bg-inherit !text-inherit"> <Icon /> </SidebarTriggerButton> ); } return <Icon />; };Then use it in both places:
-{state === 'collapsed' ? ( - <SidebarTriggerButton className="!p-0 !bg-inherit !text-inherit"> - <item.icon /> - </SidebarTriggerButton> -) : ( - <item.icon /> -)} +<MenuIcon icon={item.icon} collapsed={state === 'collapsed'} />Also applies to: 119-125
apps/web/components/app-sidebar.tsx (3)
68-69
: Consider memoizing the sorted tasks list.The sort operation is performed on every render. Consider memoizing this operation using
useMemo
to optimize performance.+ const sortedFavoriteTasks = useMemo(() => + favoriteTasks.sort((a, b) => + a.title.toLowerCase().localeCompare(b.title.toLowerCase()) + ), + [favoriteTasks] + );
98-104
: Add tooltip for truncated task titles.The task title is truncated but users can't see the full text. Consider adding a tooltip.
<span className={cn( '!font-light text-nowrap text-sm max-w-[100px] whitespace-nowrap text-ellipsis overflow-hidden' )} + title={task?.title} > {task?.title} </span>
155-162
: Add tooltip for disabled create project button.Users should understand why the create project button is disabled.
<Button className="w-full text-xs mt-3 dark:text-white rounded-xl border-[0.0938rem]" variant="outline" disabled={!user?.isEmailVerified} + title={!user?.isEmailVerified ? t('common.VERIFY_EMAIL_TO_CREATE_PROJECT') : ''} > <PlusIcon className="w-4 h-4" /> {t('common.CREATE_PROJECT')} </Button>
apps/web/lib/features/user-profile-plans.tsx (1)
447-449
: Simplify the className template string.The multi-line template string could be simplified for better readability.
- className={`mb-6 flex ${ - planMode === 'Future Tasks' ? 'justify-start' : 'justify-around' - } items-center gap-5`} + className={`mb-6 flex items-center ${planMode === 'Future Tasks' ? 'justify-start gap-5' : 'justify-around gap-5'}`}apps/web/components/ui/sidebar.tsx (2)
260-279
: LGTM! Clean implementation of the new generic trigger button.The new
SidebarTriggerButton
component follows the established patterns and provides a more flexible interface by accepting children for custom content.Consider consolidating
SidebarTrigger
andSidebarTriggerButton
into a single component since they share similar functionality. The existingSidebarTrigger
could be implemented as a specialized version ofSidebarTriggerButton
.
280-281
: Move the display name assignment.The display name for
SidebarTrigger
should be moved before theSidebarTriggerButton
definition to maintain a consistent code organization pattern.apps/web/components/pages/team/tasks/tasks-data-table.tsx (3)
36-36
: Use stable keys instead of indexUsing indices as keys can lead to rendering issues in React. It's better to use a stable identifier like the
status
value.Apply this change:
- key={index} + key={status}
47-54
: Debounce search input to enhance performanceConsider debouncing the search input to prevent excessive re-renders and improve performance when filtering tasks.
You can implement debouncing like this:
+ import { useEffect, useState } from 'react'; + import { debounce } from 'lodash'; const [searchValue, setSearchValue] = useState(''); + const debouncedSetFilter = useMemo( + () => debounce((value) => table.getColumn('title')?.setFilterValue(value), 300), + [table] + ); + useEffect(() => { + debouncedSetFilter(searchValue); + return () => { + debouncedSetFilter.cancel(); + }; + }, [searchValue, debouncedSetFilter]); <Input placeholder="Search tasks..." - value={(table.getColumn('title')?.getFilterValue() as string) ?? ''} - onChange={(event) => table.getColumn('title')?.setFilterValue(event.target.value)} + value={searchValue} + onChange={(event) => setSearchValue(event.target.value)} className="max-w-sm pl-10 bg-transparent border-none placeholder:font-normal" />
147-170
: Simplify getStatusColor function for maintainabilityRefactor the
getStatusColor
function to use an object mapping. This improves readability and makes it easier to add or modify statuses in the future.Apply this refactor:
- function getStatusColor(status: ITaskStatus) { - switch (status) { - case 'in-review': - return 'bg-[#f3d8b0]'; - case 'backlog': - return 'bg-[#ffcc00]'; - case 'open': - return 'bg-[#d6e4f9]'; - case 'in-progress': - return 'bg-[#ece8fc]'; - case 'ready-for-review': - return 'bg-[#f5f1cb]'; - case 'blocked': - return 'bg-[#f5b8b8]'; - case 'done': - return 'bg-[#4caf50] text-gray-100'; - case 'completed': - return 'bg-[#d4efdf]'; - case 'custom': - return 'bg-[#d4efdf]'; - default: - return 'bg-gray-100 text-gray-800'; - } - } + const statusColors: Record<ITaskStatus, string> = { + 'in-review': 'bg-[#f3d8b0]', + 'backlog': 'bg-[#ffcc00]', + 'open': 'bg-[#d6e4f9]', + 'in-progress': 'bg-[#ece8fc]', + 'ready-for-review': 'bg-[#f5f1cb]', + 'blocked': 'bg-[#f5b8b8]', + 'done': 'bg-[#4caf50] text-gray-100', + 'completed': 'bg-[#d4efdf]', + 'custom': 'bg-[#d4efdf]', + }; + + function getStatusColor(status: ITaskStatus) { + return statusColors[status] || 'bg-gray-100 text-gray-800'; + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (2)
apps/web/public/assets/user-teams.png
is excluded by!**/*.png
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (39)
.vscode/settings.json
(1 hunks)apps/web/app/[locale]/layout.tsx
(3 hunks)apps/web/app/[locale]/page-component.tsx
(2 hunks)apps/web/app/[locale]/permissions/component.tsx
(2 hunks)apps/web/app/[locale]/profile/[memberId]/page.tsx
(1 hunks)apps/web/app/[locale]/team/tasks/page.tsx
(1 hunks)apps/web/app/hooks/features/useAuthTeamTasks.ts
(1 hunks)apps/web/app/interfaces/ITask.ts
(1 hunks)apps/web/app/layout.tsx
(1 hunks)apps/web/app/stores/menu.ts
(1 hunks)apps/web/components/app-sidebar.tsx
(3 hunks)apps/web/components/nav-main.tsx
(4 hunks)apps/web/components/pages/task/description-block/task-description-editor.tsx
(2 hunks)apps/web/components/pages/task/details-section/blocks/task-main-info.tsx
(2 hunks)apps/web/components/pages/team/tasks/AssigneeUser.tsx
(1 hunks)apps/web/components/pages/team/tasks/DropdownMenuTask.tsx
(1 hunks)apps/web/components/pages/team/tasks/FilterButton.tsx
(1 hunks)apps/web/components/pages/team/tasks/StatusBadge.tsx
(1 hunks)apps/web/components/pages/team/tasks/TaskTable.tsx
(1 hunks)apps/web/components/pages/team/tasks/columns.tsx
(1 hunks)apps/web/components/pages/team/tasks/tasks-data-table.tsx
(1 hunks)apps/web/components/ui/sidebar.tsx
(2 hunks)apps/web/components/ui/table.tsx
(4 hunks)apps/web/lib/components/combobox/index.tsx
(1 hunks)apps/web/lib/components/pagination.tsx
(1 hunks)apps/web/lib/components/svgs/app-logo.tsx
(1 hunks)apps/web/lib/components/time-picker/index.tsx
(1 hunks)apps/web/lib/features/activity/components/screenshot-details.tsx
(1 hunks)apps/web/lib/features/integrations/calendar/calendar-component.tsx
(1 hunks)apps/web/lib/features/task/daily-plan/future-tasks.tsx
(2 hunks)apps/web/lib/features/task/daily-plan/outstanding-all.tsx
(1 hunks)apps/web/lib/features/task/daily-plan/outstanding-date.tsx
(2 hunks)apps/web/lib/features/task/daily-plan/past-tasks.tsx
(2 hunks)apps/web/lib/features/task/task-status.tsx
(2 hunks)apps/web/lib/features/team-members.tsx
(6 hunks)apps/web/lib/features/user-profile-plans.tsx
(2 hunks)apps/web/lib/layout/main-layout.tsx
(1 hunks)apps/web/locales/en.json
(1 hunks)apps/web/package.json
(1 hunks)
✅ Files skipped from review due to trivial changes (8)
- .vscode/settings.json
- apps/web/app/[locale]/layout.tsx
- apps/web/app/[locale]/profile/[memberId]/page.tsx
- apps/web/components/pages/task/details-section/blocks/task-main-info.tsx
- apps/web/lib/features/integrations/calendar/calendar-component.tsx
- apps/web/lib/features/task/daily-plan/outstanding-all.tsx
- apps/web/lib/features/task/task-status.tsx
- apps/web/locales/en.json
🧰 Additional context used
🪛 Biome
apps/web/app/[locale]/page-component.tsx
[error] 123-123: 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/app/[locale]/permissions/component.tsx
[error] 29-29: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 45-45: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 51-51: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
apps/web/app/hooks/features/useAuthTeamTasks.ts
[error] 44-44: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
apps/web/components/pages/task/description-block/task-description-editor.tsx
[error] 41-41: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
apps/web/lib/components/time-picker/index.tsx
[error] 30-30: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
apps/web/lib/features/task/daily-plan/future-tasks.tsx
[error] 120-120: 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 (39)
apps/web/app/layout.tsx (1)
12-12
:
Critical: Restore HTML and body tags in root layout
The root layout must include html
and body
tags as per Next.js requirements. Removing these tags can break the application's HTML structure, affecting SEO, accessibility, and proper document rendering.
Apply this diff to restore the proper structure:
-return <>{children}</>;
+return (
+ <html lang="en">
+ <body>{children}</body>
+ </html>
+);
Let's verify if there are any other layout files that might be providing these tags:
apps/web/app/stores/menu.ts (2)
1-2
: LGTM! Clean and well-organized imports.
The imports are correctly structured, following the pattern of importing core modules before utility modules.
7-8
: LGTM! Well-structured active state management.
The use of nullable number types for menu indices is appropriate and provides clear inactive states.
apps/web/components/pages/team/tasks/AssigneeUser.tsx (2)
1-3
: LGTM! Clean and well-organized imports.
The imports are properly structured and all are being utilized in the component.
28-28
: LGTM! Clean export statement.
apps/web/app/[locale]/team/tasks/page.tsx (3)
1-13
: LGTM! Well-organized imports.
The imports are properly organized and all dependencies are being used effectively in the component.
39-39
: LGTM! Proper authentication implementation.
The component is correctly wrapped with authentication and includes a display name for better debugging.
29-37
: Verify TaskTable configuration requirements.
The TaskTable component is rendered without any props. Please verify if it needs any configuration props for customization or pagination settings.
✅ Verification successful
Let me search for the TaskTable component definition to better understand its implementation.
Let me check the implementation of TaskTable component to understand its props requirements.
TaskTable component is correctly implemented without requiring props
The TaskTable component is self-contained and manages its own state through hooks:
- Uses
useTeamTasks
hook to fetch and manage tasks data - Implements pagination using
usePagination
hook - Renders TasksDataTable with required props derived from internal state
- Includes Paginate component with proper configuration
No additional configuration props are needed as the component handles all functionality internally.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for TaskTable component definition to check its props interface
ast-grep --pattern 'interface $TaskTableProps {
$$$
}'
# Search for other TaskTable usages to see how it's configured elsewhere
rg -A 3 '<TaskTable'
Length of output: 303
Script:
#!/bin/bash
# Search for TaskTable component definition
ast-grep --pattern 'const TaskTable = $$$'
# Search for TaskTable component file
fd TaskTable
Length of output: 110
Script:
#!/bin/bash
# Check the TaskTable component implementation
cat apps/web/components/pages/team/tasks/TaskTable.tsx
Length of output: 1040
apps/web/app/hooks/features/useAuthTeamTasks.ts (2)
7-13
: LGTM: Clean hook setup with proper state management
The hook initialization is well-structured with appropriate use of Jotai's state management.
56-62
: LGTM: Clean return structure with new tasks property
The return object is well-organized and the addition of the tasks
property is properly implemented.
apps/web/components/ui/table.tsx (8)
3-3
: LGTM: Utility function import change is appropriate
The change to use cn
from a centralized utils module is a good practice for maintaining consistent class name management across the application.
7-8
: Improved table structure with responsive wrapper
The addition of a relative wrapper div with full width provides better control over table layout and responsiveness. The class merging is properly implemented using the new cn
utility.
15-15
: LGTM: Clear and explicit border styling
The border styling is now more explicitly defined using modern CSS selector syntax.
28-32
: Enhanced footer styling with better visual hierarchy
The footer styling has been improved with:
- Proper border handling
- Subtle background color using opacity
- Consistent font weight
- Prevention of double borders
41-41
: LGTM: Improved row interaction states
The row styling now includes proper state management for hover and selection, with smooth transitions.
52-55
: LGTM: Well-structured heading cell styling
The heading cell styling provides good visual hierarchy with:
- Consistent padding and alignment
- Proper text styling for headers
- Special handling for checkbox columns
64-64
: LGTM: Clean and consistent cell styling
The cell styling maintains consistency with the table's design system.
71-71
: LGTM: Appropriate caption styling
The caption styling properly integrates with the table's visual hierarchy.
apps/web/lib/layout/main-layout.tsx (1)
36-36
: Verify overflow behavior with wide content.
The addition of overflow-x-hidden
and min-w-fit
improves layout stability, but please verify that no critical content gets clipped in various viewport sizes.
Let's check for potential overflow issues in the codebase:
✅ Verification successful
Based on the search results, I can now make a determination about the overflow behavior in the codebase:
No overflow issues with the updated layout class
The addition of overflow-x-hidden min-w-fit
to the main layout's outer div is safe and consistent with the codebase's patterns:
- The codebase already uses
overflow-x-hidden
in several container components to prevent unwanted horizontal scrolling - The
min-w-fit
ensures content won't be squeezed too narrow, working in tandem with the overflow control - Key scrollable areas like tables, grids and content sections have explicit
overflow-x-auto
where horizontal scrolling is needed - The layout change won't affect these intentionally scrollable areas since they have their own overflow controls
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Look for components or elements that might be affected by horizontal overflow
# Test 1: Search for wide elements or explicit width settings
rg -g '*.tsx' -g '*.jsx' -A 2 'w-\[.*px\]|width:|min-w-\[|max-w-\[|overflow-x-|scroll-x'
# Test 2: Search for horizontal scrolling containers that might be affected
rg -g '*.tsx' -g '*.jsx' -A 2 'overflow-x-scroll|overflow-x-auto'
# Test 3: Search for tables or grid layouts that might extend beyond viewport
rg -g '*.tsx' -g '*.jsx' -A 2 'table-|grid-cols-'
Length of output: 356998
apps/web/components/pages/team/tasks/FilterButton.tsx (1)
1-12
: LGTM! Well-structured imports and type definitions.
The imports are properly organized and the generic type definition for FilterButtonProps
follows TypeScript best practices.
apps/web/lib/components/pagination.tsx (3)
5-5
: LGTM: Clean import of className utility
The addition of the cn
utility import is appropriate for handling className merging.
13-13
: LGTM: Well-typed className prop addition
The optional className prop is properly typed and integrates well with the existing Props type.
16-24
: LGTM: Clean component signature update
The className prop is correctly added to the component's parameter destructuring.
apps/web/components/pages/team/tasks/DropdownMenuTask.tsx (2)
1-15
: LGTM! Well-organized imports.
The imports are logically grouped and all dependencies are being used within the component.
92-92
: LGTM! Proper component export.
The default export follows React component conventions.
apps/web/lib/components/combobox/index.tsx (2)
1-20
: LGTM! Well-structured interface with comprehensive type definitions.
The interface is well-designed with clear property names and appropriate types. Good use of generics for type safety.
24-35
: LGTM! Good use of Readonly type.
The addition of Readonly<ComboboxProps<T>>
helps enforce immutability and prevents accidental prop mutations.
apps/web/app/interfaces/ITask.ts (1)
37-37
: Type safety improvement for issueType property.
The change from string
to ITaskIssue
improves type safety by restricting values to predefined issue types.
Let's verify the impact of this type change:
✅ Verification successful
Let me verify the usage of issueType
in the codebase to ensure there are no breaking changes.
Let me check the actual type definitions and usage to fully understand the change.
Type change is safe and consistent with codebase usage
The change from string
to ITaskIssue
in ITeamTask
interface is safe because:
- All string literals used in the codebase for
issueType
match theITaskIssue
type values: 'Bug', 'Task', 'Story', 'Epic' - The
ICreateTask
interface retainsstring
type forissueType
which is appropriate for input/creation scenarios - The enum
IssueType
aligns with theITaskIssue
type values, providing type safety at runtime
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for potential breaking changes in issue type usage
# Look for direct string assignments to issueType that might break with the new type
rg -A 2 "issueType.*=.*['\"](Bug|Task|Story|Epic)['\"]"
Length of output: 20959
Script:
#!/bin/bash
# Check for any direct string assignments to issueType that might break with the new type
rg "issueType\s*=\s*[^=]" --type ts
# Check the interface definition to understand the type change
rg "interface.*ITeamTask" -A 10
Length of output: 1512
Script:
#!/bin/bash
# Check the ITaskIssue type definition and related types
rg "type.*ITaskIssue|enum.*IssueType" -A 5
# Check the ICreateTask interface to understand the inconsistency mentioned
rg "interface.*ICreateTask" -A 15
Length of output: 4044
apps/web/components/pages/team/tasks/columns.tsx (1)
1-7
: LGTM! Imports are clean and well-organized.
apps/web/lib/features/task/daily-plan/outstanding-date.tsx (2)
18-21
: LGTM! Clean state management implementation.
The component properly initializes state using appropriate React hooks and follows best practices for state management.
25-27
: Consider adding error handling for drag and drop operations.
The onDragEnd
callback should include error handling to gracefully handle failed drag operations and provide user feedback.
<DragDropContext
onDragEnd={(result) => {
+ try {
handleDragAndDrop(result, outstandingTasks, setOutstandingTasks)
+ } catch (error) {
+ console.error('Failed to reorder task:', error);
+ // Consider adding a toast notification here
+ }
}}
>
apps/web/package.json (1)
70-70
: LGTM! Please verify testing with new components.
The update to @tanstack/react-table
from ^8.10.7
to ^8.20.5
maintains major version compatibility while providing access to new features needed for the task list view components.
Please ensure the new version has been tested with the introduced components. Run the following to check for any potential breaking changes in the minor versions:
✅ Verification successful
Let me analyze the results and generate additional verification scripts to check the usage of @tanstack/react-table
in the components.
Let me check the actual implementation details of these components to verify the usage of the updated library version.
Version update is safe to proceed
The update to @tanstack/react-table
from ^8.10.7
to ^8.20.5
is verified to be compatible with the current implementation. The components are using standard table features (useReactTable
, getCoreRowModel
, getFilteredRowModel
) that are stable across minor versions of v8.x.x.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for breaking changes in @tanstack/react-table between versions
# Test: Search for any migration guides or breaking changes in the repository
rg -i "breaking.*changes|migration.*guide" $(fd -t f . -E "node_modules" -E "dist" -E "build")
# Test: Check if the new components are importing any potentially renamed or moved exports
rg "@tanstack/react-table" $(fd "TaskTable|FilterButton" -t f)
Length of output: 92163
Script:
#!/bin/bash
# Check how @tanstack/react-table is being used in the components
ast-grep --pattern 'import { $_ } from "@tanstack/react-table"' apps/web/components/pages/team/tasks/TaskTable.tsx apps/web/components/pages/team/tasks/FilterButton.tsx
# Check for any table-related components that might be using the library
rg -l "Table|useReactTable|ColumnDef" apps/web/components/pages/team/tasks/
Length of output: 460
Script:
#!/bin/bash
# Check the implementation details of table components
rg -A 5 "@tanstack/react-table" apps/web/components/pages/team/tasks/tasks-data-table.tsx apps/web/components/pages/team/tasks/columns.tsx apps/web/components/pages/team/tasks/TaskTable.tsx
# Check for any specific features or APIs being used
rg "useReactTable|getCoreRowModel|getSortedRowModel|getFilteredRowModel" apps/web/components/pages/team/tasks/*.tsx
Length of output: 2596
apps/web/lib/features/team-members.tsx (1)
22-22
: LGTM! Good type safety improvement.
The change to Readonly<TeamMembersProps>
enforces immutability of props, which is a React best practice and helps prevent accidental mutations.
apps/web/lib/features/task/daily-plan/past-tasks.tsx (1)
Line range hint 1-14
: LGTM! Import statements are well-organized.
The imports are logically grouped and include all necessary dependencies for the component's functionality.
apps/web/app/[locale]/page-component.tsx (1)
65-65
: LGTM! Height class modification improves layout flexibility.
The change from h-screen
to h-full min-h-screen
is a good improvement that allows the container to grow with content while maintaining a minimum viewport height.
apps/web/lib/components/svgs/app-logo.tsx (1)
4-4
: LGTM! Good use of Next.js Image component
Using next/image
instead of the standard HTML img
tag is a good practice as it provides automatic image optimization, lazy loading, and prevents layout shifts.
apps/web/components/nav-main.tsx (1)
2-2
: LGTM: Clean state management implementation
The implementation of state management using Jotai atoms is well-structured and follows React best practices. The state variables are appropriately named and their purposes are clear.
Also applies to: 19-19, 37-39
apps/web/lib/features/user-profile-plans.tsx (1)
285-285
: LGTM! Improved scrolling behavior.
The change from overflow-x-scroll
to overflow-x-auto
is a good improvement as it provides better UX by only showing scrollbars when necessary.
apps/web/components/ui/sidebar.tsx (1)
678-678
: LGTM! Proper export of the new component.
The new component is correctly exported alongside other sidebar components.
Report too large to display inline |
Description
Please include a summary of the changes and the related issue.
Type of Change
Checklist
Previous screenshots
Please add here videos or images of previous status
Current screenshots
Please add here videos or images of previous status
ndekocode-ever0teams-2024_11_06-18_12_27.webm
Summary by CodeRabbit
Release Notes
New Features
TeamTask
,AssigneeUser
,DropdownMenuTask
,FilterButton
,StatusBadge
, andTaskTable
for enhanced task management and display.Improvements
MainLayout
,AppSidebar
, and dropdown menus for better user experience.Bug Fixes
Localization
Dependency Updates
@tanstack/react-table
to version^8.20.5
for improved functionality.