Skip to content

Conversation

@vibhor121
Copy link

@vibhor121 vibhor121 commented Sep 10, 2025

  • Create TaskDetailsModal component for viewing complete task information
  • Add View Details button (eye icon) to task tables in dashboard and team pages
  • Display task title, description, status, priority, assignee, created by, due date, labels, tags, and watchlist status
  • Use large textarea for easy reading of task descriptions
  • Remove edit functionality to keep it as view-only feature
  • Integrate modal into both main task list and team task list components

Date: 10 septem 2025

Developer Name:


Issue Ticket Number

Description

Documentation Updated?

  • Yes
  • No

Under Feature Flag

  • No

Database Changes

No

Breaking Changes

  • Yes
  • No

Development Tested?

  • Yes

Screenshots

image Screenshot from 2025-09-10 11-16-56

Test Coverage

Screenshot 1

Additional Notes

Description by Korbit AI

What change is being made?

Add a new TaskDetailsModal component for viewing task details in a read-only modal, and integrate it into the Todo list and team tasks UIs with an eye-button trigger.

Why are these changes being made?

Provide an accessible, view-only details dialog to quickly inspect task information from lists without editing. (If any broader UX decisions or limitations exist, they are not reflected in the code; this PR focuses on read-only detail viewing via a modal.)

Is this description stale? Ask me to generate a new description by commenting /korbit-generate-pr-description

- Create TaskDetailsModal component for viewing complete task information
- Add View Details button (eye icon) to task tables in dashboard and team pages
- Display task title, description, status, priority, assignee, created by, due date, labels, tags, and watchlist status
- Use large textarea for easy reading of task descriptions
- Remove edit functionality to keep it as view-only feature
- Integrate modal into both main task list and team task list components
@coderabbitai
Copy link

coderabbitai bot commented Sep 10, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Summary by CodeRabbit

  • New Features
    • View full task details in a modal: title, description, status, priority, assignee, creator, due date, labels, tags, watchlist, deferred-until, and task ID.
    • Added “View details” (eye) button to task rows for quick access to the modal.
    • Team Tasks header now includes a switch to show/hide completed tasks.
    • Consistent date formatting with clear fallbacks for missing information.

Walkthrough

Adds a new TaskDetailsModal component and integrates it with an Eye-button in task rows to view detailed task info. Updates team tasks view to use TASK_STATUS_ENUM for including done tasks and adds an IncludeDoneSwitch in the header. Minor import reorganizations; no API signature changes.

Changes

Cohort / File(s) Summary of changes
New details modal component
components/task-details-modal.tsx
Introduces TaskDetailsModal React component to display task details in a modal (title, description, status, priority, assignee, creator, due date, ID, labels, tags, watchlist, deferred info). Manages open state; uses existing UI primitives and date formatting.
Integrate modal in todo list table
components/todo-list-table.tsx
Adds Eye-button wrapped with TaskDetailsModal in row actions to view task details; imports EyeIcon, TaskDetailsModal, Button. No data/table structure changes.
Team tasks enhancements
modules/teams/team-tasks.tsx
Uses TASK_STATUS_ENUM.DONE to derive include-done filtering; adds IncludeDoneSwitch to header; integrates Eye-button with TaskDetailsModal per row; adjusts imports and order.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant T as TodoListTableRow
  participant M as TaskDetailsModal
  participant UI as UI Primitives

  U->>T: Click "View details" (Eye)
  T->>M: Open modal with task props
  activate M
  M->>UI: Render dialog, text, grid, badges, avatars
  note right of M: Fields shown with fallbacks<br/>Dates formatted via DateUtil
  U-->>M: Close
  M->>UI: Dismiss dialog
  deactivate M
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • iamitprakash
  • AnujChhikara
  • Achintya-Chatterjee

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title “feat: Add task details modal with view-only functionality” succinctly captures the primary change by highlighting the introduction of a task details modal and its read-only nature, making it clear and specific enough for reviewers to understand the core purpose of the pull request at a glance.
Description Check ✅ Passed The description thoroughly outlines the new TaskDetailsModal component, the “View Details” button integration in relevant tables, the fields displayed within the modal, and related UI adjustments, directly corresponding to the changes in the codebase.

Poem

A click, an Eye, the details gleam,
Tasks unfold like a tidy dream.
Switch to see the “done” parade,
Labels, tags in neat arrayed.
I thump my paw—review’s a breeze,
Modal pops, and all’s at ease. 🐇👁️✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "feat: Add task details modal with view-only functionality" succinctly describes the primary change—adding a task details modal and making it view-only—and aligns with the modified files (task-details-modal, todo-list-table, team-tasks). It is concise, uses a conventional "feat:" prefix, and communicates the main intent for reviewers scanning history. The title is specific and not misleading.
Description Check ✅ Passed The PR description clearly summarizes the addition of TaskDetailsModal, where it is integrated (dashboard and team pages), the fields displayed, view-only behavior, and includes testing/screenshots metadata, which matches the changes in the diff and raw summary. It is specific and directly related to the changeset, so it meets the lenient description requirement. There is no indication the description is off-topic or unrelated.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

{task.assignee ? (
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center text-white text-xs font-medium">
{task.assignee.assignee_name?.charAt(0).toUpperCase() || 'U'}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The optional chaining operator is applied too late in the expression. If assignee_name is null or undefined, the code will still attempt to access it through task.assignee.assignee_name, which could cause a runtime error if assignee exists but assignee_name doesn't. Consider using optional chaining earlier in the chain:

{task.assignee?.assignee_name?.charAt(0).toUpperCase() || 'U'}

This ensures safe property access throughout the entire expression.

Suggested change
{task.assignee.assignee_name?.charAt(0).toUpperCase() || 'U'}
{task.assignee?.assignee_name?.charAt(0).toUpperCase() || 'U'}

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Deferred Until
</Label>
<div className="text-gray-900">
{new DateUtil(task.deferredDetails.deferredTill).format(DateFormats.D_MMM_YYYY)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a potential null reference issue in this line. While the condition correctly uses optional chaining with task.deferredDetails?.deferredTill, the actual usage below doesn't maintain this pattern. To prevent runtime errors, please use optional chaining consistently:

new DateUtil(task.deferredDetails?.deferredTill).format(DateFormats.D_MMM_YYYY)

This ensures the code handles cases where deferredDetails might be null or undefined.

Suggested change
{new DateUtil(task.deferredDetails.deferredTill).format(DateFormats.D_MMM_YYYY)}
{new DateUtil(task.deferredDetails?.deferredTill).format(DateFormats.D_MMM_YYYY)}

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Copy link

@korbit-ai korbit-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by Korbit AI

Korbit automatically attempts to detect when you fix issues in new commits.
Category Issue Status
Readability Repeated Complex User Initial Logic ▹ view
Security Unsanitized Task Description Rendering ▹ view
Design Modal State Control Limitation ▹ view
Performance Redundant String Operations ▹ view
Performance Inefficient Date Formatting ▹ view
Performance Inefficient Array Key Usage ▹ view
Design Duplicated User Avatar Logic ▹ view
Files scanned
File Path Reviewed
modules/teams/team-tasks.tsx
components/todo-list-table.tsx
components/task-details-modal.tsx

Explore our documentation to understand the languages and file types we support and the files we ignore.

Check out our docs on how you can make Korbit work best for you and your team.

Loving Korbit!? Share us on LinkedIn Reddit and X

Comment on lines +60 to +62
value={task.description || 'No description provided'}
readOnly
className="min-h-[100px] resize-none border-none bg-transparent p-0 focus:ring-0"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsanitized Task Description Rendering category Security

Tell me more
What is the issue?

Task description is rendered directly in a textarea without sanitization, potentially allowing XSS attacks if the description contains malicious content.

Why this matters

If the task description contains JavaScript code or HTML tags, it could execute in the user's browser when rendered, leading to cross-site scripting (XSS) vulnerabilities.

Suggested change ∙ Feature Preview
// Option 1: Use a sanitization library
import DOMPurify from 'dompurify';

<Textarea
  value={DOMPurify.sanitize(task.description) || 'No description provided'}
  readOnly
  className="min-h-[100px] resize-none border-none bg-transparent p-0 focus:ring-0"
/>

// Option 2: If HTML is not needed, escape special characters
<Textarea
  value={task.description?.replace(/[<>"'&]/g, (char) => ({
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
    '&': '&amp;'
  }[char])) || 'No description provided'}
  readOnly
  className="min-h-[100px] resize-none border-none bg-transparent p-0 focus:ring-0"
/>
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

}

export function TaskDetailsModal({ task, children }: TaskDetailsModalProps) {
const [isOpen, setIsOpen] = useState(false)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modal State Control Limitation category Design

Tell me more
What is the issue?

The modal's open state is managed internally, which prevents parent components from controlling the modal's visibility or reacting to its state changes.

Why this matters

Parent components may need to programmatically open/close the modal or synchronize its state with other UI elements. The current implementation prevents this flexibility.

Suggested change ∙ Feature Preview

Add isOpen and onOpenChange props to allow parent components to control the modal's state:

type TaskDetailsModalProps = {
  task: TTask
  children: React.ReactNode
  isOpen?: boolean
  onOpenChange?: (open: boolean) => void
}

export function TaskDetailsModal({ 
  task, 
  children, 
  isOpen: controlledIsOpen,
  onOpenChange 
}: TaskDetailsModalProps) {
  const [uncontrolledIsOpen, setUncontrolledIsOpen] = useState(false)
  const isOpen = controlledIsOpen ?? uncontrolledIsOpen
  const handleOpenChange = (open: boolean) => {
    setUncontrolledIsOpen(open)
    onOpenChange?.(open)
  }

  return (
    <Dialog open={isOpen} onOpenChange={handleOpenChange}>
      {/* rest of the code... */}
    </Dialog>
  )
}
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

{task.createdBy ? (
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-green-500 rounded-full flex items-center justify-center text-white text-xs font-medium">
{task.createdBy.name?.charAt(0).toUpperCase() || 'U'}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant String Operations category Performance

Tell me more
What is the issue?

Multiple unnecessary string operations are being performed on every render for both assignee and creator initials.

Why this matters

Each render triggers charAt(), toUpperCase(), and optional chaining operations. For a list of tasks, this can impact performance, especially during scrolling or frequent re-renders.

Suggested change ∙ Feature Preview

Memoize the initials or compute them when the task data changes:

const getInitials = useCallback((name?: string) => {
  return name?.charAt(0).toUpperCase() || 'U'
}, [])

// Then use:
{getInitials(task.createdBy.name)}
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

</Label>
<div className="text-gray-900">
{task.dueAt ? (
new DateUtil(task.dueAt).format(DateFormats.D_MMM_YYYY)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inefficient Date Formatting category Performance

Tell me more
What is the issue?

Date formatting operations are being created and executed on every render.

Why this matters

Creating new DateUtil instances and formatting dates on each render is computationally expensive, especially when dealing with lists of tasks.

Suggested change ∙ Feature Preview

Memoize the formatted date or move the formatting logic outside the render cycle:

const formattedDate = useMemo(() => {
  return task.dueAt ? new DateUtil(task.dueAt).format(DateFormats.D_MMM_YYYY) : 'No due date'
}, [task.dueAt])

// Then use:
{formattedDate}
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +182 to +186
{task.tags.map((tag, index) => (
<span
key={index}
className="px-2 py-1 bg-gray-200 text-gray-700 text-xs rounded-full"
>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inefficient Array Key Usage category Performance

Tell me more
What is the issue?

Using array index as key in the tags mapping can lead to unnecessary re-renders when the array changes.

Why this matters

When tags are added, removed, or reordered, React may unnecessarily re-render components because index-based keys don't provide stable identification.

Suggested change ∙ Feature Preview

Use the tag value as the key if tags are unique, or generate stable IDs:

task.tags.map((tag) => (
  <span
    key={tag} // Assuming tags are unique strings
    className="px-2 py-1 bg-gray-200 text-gray-700 text-xs rounded-full"
  >
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

{task.assignee ? (
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center text-white text-xs font-medium">
{task.assignee.assignee_name?.charAt(0).toUpperCase() || 'U'}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repeated Complex User Initial Logic category Readability

Tell me more
What is the issue?

The complex fallback logic for user initials appears multiple times with slight variations.

Why this matters

Duplicated complex logic makes the code harder to maintain and increases the chance of inconsistencies.

Suggested change ∙ Feature Preview
const getUserInitial = (name?: string) => name?.charAt(0).toUpperCase() || 'U';

// Then use it like:
{getUserInitial(task.assignee.assignee_name)}
{getUserInitial(task.createdBy.name)}
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +95 to +113
{/* Assignee */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
<UserIcon className="inline w-4 h-4 mr-1" />
Assignee
</Label>
<div className="text-gray-900">
{task.assignee ? (
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center text-white text-xs font-medium">
{task.assignee.assignee_name?.charAt(0).toUpperCase() || 'U'}
</div>
<span>{task.assignee.assignee_name || 'Unknown User'}</span>
</div>
) : (
'Unassigned'
)}
</div>
</div>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated User Avatar Logic category Design

Tell me more
What is the issue?

The user avatar display logic is duplicated between Assignee and Created By sections with nearly identical markup and styling.

Why this matters

Violates the DRY principle and makes maintenance harder as changes to the avatar display need to be made in multiple places.

Suggested change ∙ Feature Preview

Extract the avatar display into a reusable component:

const UserAvatar = ({ name, bgColor }: { name: string; bgColor: string }) => (
  <div className="flex items-center space-x-2">
    <div className={`w-6 h-6 ${bgColor} rounded-full flex items-center justify-center text-white text-xs font-medium`}>
      {name?.charAt(0).toUpperCase() || 'U'}
    </div>
    <span>{name || 'Unknown User'}</span>
  </div>
);
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
components/todo-list-table.tsx (1)

150-151: Fix colSpan mismatch when Deferred column is shown.

Empty and shimmer rows don’t account for showDeferredColumn, causing misaligned table cells.

- <TableCell colSpan={showActions ? 7 : 6}>
+ <TableCell colSpan={(showActions ? 8 : 7) + (showDeferredColumn ? 1 : 0) - 1}>

And similarly in TodoListTableRowShimmer:

- <TableCell colSpan={showActions ? 7 : 6}>
+ <TableCell colSpan={(showActions ? 8 : 7) + (showDeferredColumn ? 1 : 0) - 1}>

If showDeferredColumn isn’t available in shimmer’s props, extend its props to accept it.

Also applies to: 176-177

modules/teams/team-tasks.tsx (2)

105-107: Correct colSpan for team tasks table.

Header shows 7 base columns + Actions => 8. Current colSpan={showActions ? 7 : 6} is off by one.

- <TableCell colSpan={showActions ? 7 : 6}>
+ <TableCell colSpan={showActions ? 8 : 7}>

38-41: Rename typo: isRessignTodoCtaVisible → isReassignTodoCtaVisible.

Improves readability and consistency.

- const isRessignTodoCtaVisible =
+ const isReassignTodoCtaVisible =
   todo.assignee?.user_type === USER_TYPE_ENUM.TEAM && team?.poc_id === user.id
...
- {isRessignTodoCtaVisible && <ReassignUser taskId={todo.id} teamId={team.id} />}
+ {isReassignTodoCtaVisible && <ReassignUser taskId={todo.id} teamId={team.id} />}
...
- {!isRessignTodoCtaVisible && (
+ {!isReassignTodoCtaVisible && (

Also applies to: 73-77

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c75372 and 0c3287a.

📒 Files selected for processing (3)
  • components/task-details-modal.tsx (1 hunks)
  • components/todo-list-table.tsx (2 hunks)
  • modules/teams/team-tasks.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-29T11:21:22.274Z
Learnt from: Hariom01010
PR: Real-Dev-Squad/todo-frontend#192
File: api/teams/teams.type.ts:56-58
Timestamp: 2025-08-29T11:21:22.274Z
Learning: In the todo-frontend repository, UI mappings for TeamActivityActions are handled in lib/team-utils.ts in the getActivityUIData function using a switch statement that maps each action to an icon, title, and description for rendering audit logs.

Applied to files:

  • modules/teams/team-tasks.tsx
🧬 Code graph analysis (3)
components/todo-list-table.tsx (1)
components/task-details-modal.tsx (1)
  • TaskDetailsModal (27-232)
components/task-details-modal.tsx (5)
api/tasks/tasks.types.ts (1)
  • TTask (11-24)
components/todo-status-table.tsx (1)
  • TodoStatusTable (15-32)
components/task-priority-label.tsx (1)
  • TaskPriorityLabel (14-29)
lib/date-util.ts (1)
  • DateUtil (11-21)
components/todo-labels-list.tsx (1)
  • TodoLabelsList (92-109)
modules/teams/team-tasks.tsx (2)
components/task-details-modal.tsx (1)
  • TaskDetailsModal (27-232)
components/ui/button.tsx (1)
  • Button (59-59)
🔇 Additional comments (5)
components/todo-list-table.tsx (2)

8-8: Imports for modal trigger look good.

No issues with added imports.

Also applies to: 14-14, 18-18


160-168: Confirm UX: details hidden for TEAM-assigned tasks.

showActions={showActions && task.assignee?.user_type !== USER_TYPE_ENUM.TEAM} will also hide the View Details button. If details should be available to everyone, gate edit/watchlist only.

modules/teams/team-tasks.tsx (2)

10-11: Imports and integration look consistent.

All new imports align with usage.

Also applies to: 13-13, 18-18, 24-24


131-135: Verify “Include done” behavior — this filters to only DONE tasks.

includeDoneTasks is true only when status === TASK_STATUS_ENUM.DONE, and then queryParams sets status: DONE. That shows only DONE, not “include” in results. Confirm intended copy/behavior.

components/task-details-modal.tsx (1)

30-41: LGTM – controlled Dialog with trigger-as-child is correct.

State handling and modal structure are sound.

Comment on lines +22 to +25
type TaskDetailsModalProps = {
task: TTask
children: React.ReactNode
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix React type reference for children.

Using React.ReactNode without importing the React namespace can fail TS checks. Prefer ReactNode type import.

-import { useState } from 'react'
+import { useState } from 'react'
+import type { ReactNode } from 'react'
...
-type TaskDetailsModalProps = {
+type TaskDetailsModalProps = {
   task: TTask
-  children: React.ReactNode
+  children: ReactNode
 }

Also applies to: 17-17

🤖 Prompt for AI Agents
In components/task-details-modal.tsx around lines 17 and 22-25, replace the use
of the namespaced type React.ReactNode with the directly imported ReactNode and
add the import: import { ReactNode } from 'react'; update the
TaskDetailsModalProps children type to use ReactNode and update any other
occurrences in the file to use the imported ReactNode to satisfy TypeScript
checks.

Comment on lines +59 to +64
<Textarea
value={task.description || 'No description provided'}
readOnly
className="min-h-[100px] resize-none border-none bg-transparent p-0 focus:ring-0"
/>
</div>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Associate description with an accessible name.

Add aria-label to the read-only textarea.

  <Textarea
    value={task.description || 'No description provided'}
    readOnly
+   aria-label="Task description"
    className="min-h-[100px] resize-none border-none bg-transparent p-0 focus:ring-0"
  />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Textarea
value={task.description || 'No description provided'}
readOnly
className="min-h-[100px] resize-none border-none bg-transparent p-0 focus:ring-0"
/>
</div>
<Textarea
value={task.description || 'No description provided'}
readOnly
aria-label="Task description"
className="min-h-[100px] resize-none border-none bg-transparent p-0 focus:ring-0"
/>
🤖 Prompt for AI Agents
In components/task-details-modal.tsx around lines 59 to 64, the read-only
Textarea lacks an accessible name; add an aria-label prop to the Textarea (for
example "Task description" or a dynamic value like `Description for ${task.title
|| 'task'}`) so screen readers can identify the field; ensure the aria-label
conveys that this is the task description and keep the Textarea readOnly
behavior unchanged.

Comment on lines +176 to +189
{task.tags && task.tags.length > 0 && (
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
Tags
</Label>
<div className="flex flex-wrap gap-2">
{task.tags.map((tag, index) => (
<span
key={index}
className="px-2 py-1 bg-gray-200 text-gray-700 text-xs rounded-full"
>
{tag}
</span>
))}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Consider stable keys for tags if unique.

If tag strings are unique, prefer key={tag} over index to avoid reconciliation issues on reordering.

🤖 Prompt for AI Agents
In components/task-details-modal.tsx around lines 176 to 189, the tag list uses
the array index as the React key which can cause reconciliation bugs on reorder;
if tag strings are guaranteed unique, change the key to the tag value
(key={tag}); if they may not be unique, use a stable key such as a unique id on
each tag or a composite key like `${tag}-${index}` to ensure stability.

Comment on lines +102 to +107
<TaskDetailsModal task={todo}>
<Button variant="ghost" size="sm" className="h-8 w-8 p-0">
<EyeIcon className="h-4 w-4" />
<span className="sr-only">View details</span>
</Button>
</TaskDetailsModal>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Good addition of view-only TaskDetails trigger; add explicit aria-label for better SR output.

Current sr-only text works; an aria-label with task context improves accessibility.

-  <Button variant="ghost" size="sm" className="h-8 w-8 p-0">
+  <Button
+    variant="ghost"
+    size="sm"
+    className="h-8 w-8 p-0"
+    aria-label={`View details: ${todo.title}`}
+    title="View details"
+  >
     <EyeIcon className="h-4 w-4" />
-    <span className="sr-only">View details</span>
+    <span className="sr-only">View details</span>
   </Button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<TaskDetailsModal task={todo}>
<Button variant="ghost" size="sm" className="h-8 w-8 p-0">
<EyeIcon className="h-4 w-4" />
<span className="sr-only">View details</span>
</Button>
</TaskDetailsModal>
<TaskDetailsModal task={todo}>
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0"
aria-label={`View details: ${todo.title}`}
title="View details"
>
<EyeIcon className="h-4 w-4" />
<span className="sr-only">View details</span>
</Button>
</TaskDetailsModal>
🤖 Prompt for AI Agents
In components/todo-list-table.tsx around lines 102 to 107, the view-only
TaskDetails trigger uses an sr-only span but lacks an explicit aria-label; add
an aria-label attribute to the Button (e.g., `aria-label={`View details for
${todo.title}`}` or similar using the task context) so screen readers receive a
concise, contextual label, keeping the existing sr-only span if desired for
redundancy.

Comment on lines +67 to +72
<TaskDetailsModal task={todo}>
<Button variant="ghost" size="sm" className="h-8 w-8 p-0">
<EyeIcon className="h-4 w-4" />
<span className="sr-only">View details</span>
</Button>
</TaskDetailsModal>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Nice modal trigger; add aria-label with task title.

Matches pattern in dashboard table; include contextual label.

- <Button variant="ghost" size="sm" className="h-8 w-8 p-0">
+ <Button
+   variant="ghost"
+   size="sm"
+   className="h-8 w-8 p-0"
+   aria-label={`View details: ${todo.title}`}
+   title="View details"
+ >
    <EyeIcon className="h-4 w-4" />
    <span className="sr-only">View details</span>
  </Button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<TaskDetailsModal task={todo}>
<Button variant="ghost" size="sm" className="h-8 w-8 p-0">
<EyeIcon className="h-4 w-4" />
<span className="sr-only">View details</span>
</Button>
</TaskDetailsModal>
<TaskDetailsModal task={todo}>
<Button
variant="ghost"
size="sm"
className="h-8 w-8 p-0"
aria-label={`View details: ${todo.title}`}
title="View details"
>
<EyeIcon className="h-4 w-4" />
<span className="sr-only">View details</span>
</Button>
</TaskDetailsModal>
🤖 Prompt for AI Agents
In modules/teams/team-tasks.tsx around lines 67 to 72, the modal trigger Button
lacks an accessible aria-label that includes the task title; add an aria-label
prop to the Button that contains contextual text including the todo.title (for
example "View details for {todo.title}") so screen readers get the task-specific
label, keeping the existing visually-hidden span as needed.

@vibhor121 vibhor121 marked this pull request as draft September 10, 2025 09:00
@vibhor121 vibhor121 marked this pull request as ready for review September 24, 2025 11:23
Copy link

@korbit-ai korbit-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by Korbit AI

Korbit automatically attempts to detect when you fix issues in new commits.
Category Issue Status
Design Incorrect icon for Task ID field ▹ view
Documentation Missing Component Documentation ▹ view
Functionality Unstable React keys using array index ▹ view
Documentation Missing Props Documentation ▹ view
Design Component with Multiple Responsibilities ▹ view
Files scanned
File Path Reviewed
modules/teams/team-tasks.tsx
components/todo-list-table.tsx
components/task-details-modal.tsx

Explore our documentation to understand the languages and file types we support and the files we ignore.

Check out our docs on how you can make Korbit work best for you and your team.

Loving Korbit!? Share us on LinkedIn Reddit and X

Comment on lines +153 to +154
<ClockIcon className="inline w-4 h-4 mr-1" />
Task ID
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect icon for Task ID field category Design

Tell me more
What is the issue?

Clock icon is semantically incorrect for representing a Task ID field.

Why this matters

Users may be confused by the visual representation as clock icons typically represent time-related information, not identifiers, reducing the UI's intuitiveness.

Suggested change ∙ Feature Preview

Use a more appropriate icon like HashIcon or remove the icon entirely:

<Label className="text-sm font-medium text-gray-700 mb-2 block">
  Task ID
</Label>

Or import and use HashIcon:

import { HashIcon } from 'lucide-react'

<Label className="text-sm font-medium text-gray-700 mb-2 block">
  <HashIcon className="inline w-4 h-4 mr-1" />
  Task ID
</Label>
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +22 to +25
type TaskDetailsModalProps = {
task: TTask
children: React.ReactNode
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Props Documentation category Documentation

Tell me more
What is the issue?

The TaskDetailsModalProps type lacks documentation explaining the purpose of each prop and their expected values.

Why this matters

Without clear prop documentation, other developers may misuse the component or spend unnecessary time investigating the expected prop values.

Suggested change ∙ Feature Preview
/** Props for the TaskDetailsModal component */
type TaskDetailsModalProps = {
  /** The task object containing all task details to be displayed */
  task: TTask
  /** The trigger element that opens the modal when clicked */
  children: React.ReactNode
}
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

children: React.ReactNode
}

export function TaskDetailsModal({ task, children }: TaskDetailsModalProps) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Component Documentation category Documentation

Tell me more
What is the issue?

The TaskDetailsModal component lacks a component-level JSDoc comment explaining its purpose and usage.

Why this matters

Without component documentation, developers need to read through the implementation to understand the component's purpose and how to use it correctly.

Suggested change ∙ Feature Preview
/**
 * A modal component that displays detailed information about a task,
 * including its title, description, status, priority, assignee, and other metadata.
 */
export function TaskDetailsModal({ task, children }: TaskDetailsModalProps) {
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +182 to +189
{task.tags.map((tag, index) => (
<span
key={index}
className="px-2 py-1 bg-gray-200 text-gray-700 text-xs rounded-full"
>
{tag}
</span>
))}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unstable React keys using array index category Functionality

Tell me more
What is the issue?

Using array index as React key when rendering tags list creates unstable keys that can cause rendering issues.

Why this matters

React may incorrectly reconcile components when tags are reordered, added, or removed, leading to potential state corruption or performance issues in the UI.

Suggested change ∙ Feature Preview

Use the tag value itself as the key since tags should be unique strings:

{task.tags.map((tag) => (
  <span
    key={tag}
    className="px-2 py-1 bg-gray-200 text-gray-700 text-xs rounded-full"
  >
    {tag}
  </span>
))}
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +27 to +231
export function TaskDetailsModal({ task, children }: TaskDetailsModalProps) {
const [isOpen, setIsOpen] = useState(false)

return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
{children}
</DialogTrigger>
<DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="text-xl font-semibold text-gray-900">
Task Details
</DialogTitle>
</DialogHeader>

<div className="space-y-6">
{/* Task Title */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
Task Title
</Label>
<div className="text-lg font-medium text-gray-900">
{task.title}
</div>
</div>

{/* Description */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
Description
</Label>
<div className="min-h-[120px] p-3 bg-gray-50 rounded-md border">
<Textarea
value={task.description || 'No description provided'}
readOnly
className="min-h-[100px] resize-none border-none bg-transparent p-0 focus:ring-0"
/>
</div>
</div>

<Separator />

{/* Task Information Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Status */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
Status
</Label>
<div className="flex items-center">
<TodoStatusTable status={task.status} />
</div>
</div>

{/* Priority */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
Priority
</Label>
<div className="flex items-center">
{task.priority ? (
<TaskPriorityLabel priority={task.priority} />
) : (
<span className="text-gray-500">No priority set</span>
)}
</div>
</div>

{/* Assignee */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
<UserIcon className="inline w-4 h-4 mr-1" />
Assignee
</Label>
<div className="text-gray-900">
{task.assignee ? (
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center text-white text-xs font-medium">
{task.assignee.assignee_name?.charAt(0).toUpperCase() || 'U'}
</div>
<span>{task.assignee.assignee_name || 'Unknown User'}</span>
</div>
) : (
'Unassigned'
)}
</div>
</div>

{/* Created By */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
<UserPlusIcon className="inline w-4 h-4 mr-1" />
Created By
</Label>
<div className="text-gray-900">
{task.createdBy ? (
<div className="flex items-center space-x-2">
<div className="w-6 h-6 bg-green-500 rounded-full flex items-center justify-center text-white text-xs font-medium">
{task.createdBy.name?.charAt(0).toUpperCase() || 'U'}
</div>
<span>{task.createdBy.name || 'Unknown User'}</span>
</div>
) : (
'Unknown'
)}
</div>
</div>

{/* Due Date */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
<CalendarIcon className="inline w-4 h-4 mr-1" />
Due Date
</Label>
<div className="text-gray-900">
{task.dueAt ? (
new DateUtil(task.dueAt).format(DateFormats.D_MMM_YYYY)
) : (
'No due date'
)}
</div>
</div>

{/* Task ID */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
<ClockIcon className="inline w-4 h-4 mr-1" />
Task ID
</Label>
<div className="text-gray-900 font-mono text-sm">
{task.id}
</div>
</div>
</div>

{/* Labels */}
{task.labels && task.labels.length > 0 && (
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
<TagIcon className="inline w-4 h-4 mr-1" />
Labels
</Label>
<div className="flex flex-wrap gap-2">
<TodoLabelsList labels={task.labels} />
</div>
</div>
)}

{/* Tags */}
{task.tags && task.tags.length > 0 && (
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
Tags
</Label>
<div className="flex flex-wrap gap-2">
{task.tags.map((tag, index) => (
<span
key={index}
className="px-2 py-1 bg-gray-200 text-gray-700 text-xs rounded-full"
>
{tag}
</span>
))}
</div>
</div>
)}

{/* Watchlist Status */}
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
Watchlist
</Label>
<div className="text-gray-900">
{task.in_watchlist ? (
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
⭐ In Watchlist
</span>
) : (
<span className="text-gray-500">Not in watchlist</span>
)}
</div>
</div>

{/* Deferred Details */}
{task.deferredDetails?.deferredTill && (
<div>
<Label className="text-sm font-medium text-gray-700 mb-2 block">
Deferred Until
</Label>
<div className="text-gray-900">
{new DateUtil(task.deferredDetails.deferredTill).format(DateFormats.D_MMM_YYYY)}
</div>
</div>
)}
</div>

{/* Action Buttons */}
<div className="flex justify-end space-x-2 pt-4 border-t">
<Button variant="outline" onClick={() => setIsOpen(false)}>
Close
</Button>
</div>
</DialogContent>
</Dialog>
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Component with Multiple Responsibilities category Design

Tell me more
What is the issue?

The TaskDetailsModal component has too many responsibilities, handling both the modal dialog logic and the rendering of multiple different types of task information.

Why this matters

This violates the Single Responsibility Principle and makes the component harder to maintain, test, and reuse. Future changes to either the modal behavior or task display logic will require modifying this large component.

Suggested change ∙ Feature Preview

Split the component into smaller, focused components:

function TaskDetails({ task }: { task: TTask }) {
  return (
    <div className="space-y-6">
      <TaskHeader task={task} />
      <TaskDescription description={task.description} />
      <TaskMetadata task={task} />
      <TaskLabelsSection labels={task.labels} />
      <TaskTagsSection tags={task.tags} />
      <TaskWatchlistStatus inWatchlist={task.in_watchlist} />
      <TaskDeferredDetails deferredDetails={task.deferredDetails} />
    </div>
  )
}

export function TaskDetailsModal({ task, children }: TaskDetailsModalProps) {
  const [isOpen, setIsOpen] = useState(false)
  return (
    <Dialog open={isOpen} onOpenChange={setIsOpen}>
      <DialogContent>
        <TaskDetails task={task} />
      </DialogContent>
    </Dialog>
  )
}
Provide feedback to improve future suggestions

Nice Catch Incorrect Not in Scope Not in coding standard Other

💬 Looking for more details? Reply to this comment to chat with Korbit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant