Skip to content

feat(evidence): Add department and assignee filtering to evidence tasks#81

Merged
Marfuen merged 4 commits into
mainfrom
mariano/stuff
Feb 25, 2025
Merged

feat(evidence): Add department and assignee filtering to evidence tasks#81
Marfuen merged 4 commits into
mainfrom
mariano/stuff

Conversation

@Marfuen
Copy link
Copy Markdown
Contributor

@Marfuen Marfuen commented Feb 25, 2025

  • Enhance evidence tasks list with department and assignee filtering
  • Update Prisma schema to support assignee and department for organization evidence
  • Implement new filter options in EvidenceList and data table columns
  • Add assignee and department columns to evidence tasks view
  • Improve file preview and section components with better loading and preview handling
  • Update hooks and server actions to support new filtering parameters

Summary by CodeRabbit

  • New Features
    • Enhanced the evidence dashboard with new, intuitive filters for department and assignee.
    • Redesigned the evidence review interface to streamline updates for review frequency, department, and assignment.
    • Improved file preview functionality for faster, integrated previews and visual feedback.
    • Introduced new components for managing evidence assignments, department selections, and review details.
    • Added pagination, search functionalities, and active filter badges to enhance user navigation and data retrieval.
    • Implemented a statistics overview for evidence tasks, providing insights into task categories.

- Enhance evidence tasks list with department and assignee filtering
- Update Prisma schema to support assignee and department for organization evidence
- Implement new filter options in EvidenceList and data table columns
- Add assignee and department columns to evidence tasks view
- Improve file preview and section components with better loading and preview handling
- Update hooks and server actions to support new filtering parameters
@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 25, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
app ✅ Ready (Inspect) Visit Preview 💬 Add feedback Feb 25, 2025 11:00pm
2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
comp-portal ⬜️ Skipped (Inspect) Feb 25, 2025 11:00pm
web ⬜️ Skipped (Inspect) Feb 25, 2025 11:00pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 25, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This pull request introduces several new actions, components, hooks, and database migrations to enhance organization evidence management. New server-side functions retrieve organization administrators and update evidence details such as department and frequency. UI components are expanded with filters for department and assignee, along with dedicated sections for assignment and review management. Additionally, hooks are introduced to fetch organization admin data, and the database schema is updated with new columns, indices, and foreign key constraints to support evidence assignments and departmental categorization.

Changes

File(s) Change Summary
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationAdmins.ts
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEmployees.ts
Introduced new getOrganizationAdmins functions using authActionClient to retrieve organization admins (admin/owner roles) with proper authentication and error handling.
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEvidence.ts
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEvidenceTasks.ts
.../evidence/[id]/Actions/{assignEvidence,updateEvidenceDepartment,updateEvidenceFrequency}.ts
Enhanced evidence actions by updating queries to include assignee details, extending input schemas with department and assigneeId, and adding new actions for assigning evidence as well as updating its department and frequency.
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/{EvidenceList.tsx,data-table/columns.tsx,data-table/types.ts}
.../evidence/[id]/Components/{AssigneeSection,DepartmentSection,EvidenceDetails,FileCard,FileSection,FrequencySection,ReviewSection}.tsx
Expanded UI components with new filters (department, assignee), integrated file preview enhancements, replaced the review date card with a comprehensive review section, and introduced components to manage assignment, department, and frequency updates.
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/hooks/useOrganizationAdmins.ts
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/hooks/useEvidenceTasks.ts
Added a custom hook for fetching organization administrators and extended the evidence tasks hook to support filtering by department and assignee.
packages/db/prisma/migrations/*
packages/db/prisma/schema.prisma
Modified the database schema with migrations that add new columns (assigneeId and department), create indices, and update foreign key constraints. The Prisma models now include relationships for evidence assignments and departmental categorization.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant A as AssigneeSection
    participant S as assignEvidence Action
    participant DB as Database
    U->>A: Select new assignee
    A->>S: Invoke assignEvidence(evidenceId, assigneeId)
    S->>DB: Verify user organization and fetch evidence
    DB-->>S: Return evidence record
    S->>DB: Validate assignee’s admin privileges
    DB-->>S: Return admin details
    S->>DB: Update evidence with new assigneeId
    DB-->>S: Return updated evidence
    S-->>A: Send success response
    A-->>U: Update UI with new assignment
Loading
sequenceDiagram
    participant U as User
    participant G as getOrganizationAdmins
    participant DB as Database
    U->>G: Request organization admins
    G->>DB: Query for admin/owner members
    DB-->>G: Return user details
    G-->>U: Provide formatted admin list
Loading

Poem

I'm a spirited rabbit with a code-filled day,
Hopping through functions in a merry ballet.
New actions, hooks, and components abound,
Like carrots and clover freshly found.
I nibble on code with a joyful heart,
Celebrating changes as I hop and dart!
🐰💻 Hop on, let the updates start!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c2292d and ebe9479.

📒 Files selected for processing (6)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getEvidenceTasksStats.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEvidenceTasks.ts (5 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceList.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceSummaryCards.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/hooks/useEvidenceTasks.ts (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/hooks/useEvidenceTasksStats.ts (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (10)
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/FileSection.tsx (1)

79-94: Automatic preview loading is a nice UX improvement

This useEffect hook automatically loads file previews when the component mounts or when fileUrls change, which improves the user experience by making content immediately available.

One potential enhancement:

- const loadPreviews = async () => {
-   for (const url of filesToLoad) {
-     await handlePreviewClick(url);
-   }
- };
+ const loadPreviews = async () => {
+   // Load first 3 previews immediately, then load others in background
+   const initialBatch = filesToLoad.slice(0, 3);
+   const remainingFiles = filesToLoad.slice(3);
+   
+   // Load initial batch sequentially
+   for (const url of initialBatch) {
+     await handlePreviewClick(url);
+   }
+   
+   // Load remaining files in background
+   if (remainingFiles.length > 0) {
+     setTimeout(() => {
+       remainingFiles.forEach(url => handlePreviewClick(url));
+     }, 100);
+   }
+ };

This would provide a more responsive experience when there are many files by showing some previews immediately while loading others in the background.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Actions/updateEvidenceFrequency.ts (1)

49-62: Consider adding an optimistic check before updating

The function currently updates the frequency even if it's the same as the existing value. Consider adding a check to avoid unnecessary database operations.

+ // Skip update if frequency hasn't changed
+ if (evidence.frequency === frequency) {
+   return {
+     success: true,
+     data: evidence,
+   };
+ }

// Update the evidence frequency
const updatedEvidence = await db.organizationEvidence.update({
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/AssigneeSection.tsx (1)

58-70: Consider refactoring to reduce duplicated logic.

The handleAssigneeChange function duplicates some of the same logic that exists in the useEffect hook on lines 49-56. Consider extracting the common functionality into a separate function.

+ const updateSelectedAdmin = (newAssigneeId: string | null) => {
+   if (newAssigneeId && admins) {
+     const admin = admins.find((a) => a.id === newAssigneeId);
+     setSelectedAdmin(admin || null);
+   } else {
+     setSelectedAdmin(null);
+   }
+ };

  useEffect(() => {
    if (admins && assigneeId) {
-     const admin = admins.find((a) => a.id === assigneeId);
-     setSelectedAdmin(admin || null);
+     updateSelectedAdmin(assigneeId);
    } else {
      setSelectedAdmin(null);
    }
  }, [admins, assigneeId]);

  const handleAssigneeChange = (value: string) => {
    const newAssigneeId = value === "none" ? null : value;
    setAssigneeId(newAssigneeId);

-   if (newAssigneeId && admins) {
-     const admin = admins.find((a) => a.id === newAssigneeId);
-     setSelectedAdmin(admin || null);
-   } else {
-     setSelectedAdmin(null);
-   }
+   updateSelectedAdmin(newAssigneeId);

    updateAssignee({ id: evidenceId, assigneeId: newAssigneeId });
  };
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/ReviewSection.tsx (2)

11-11: Remove unused Pencil icon import.

The Pencil icon from lucide-react is imported but never used in the component.

-import { CalendarClock, Pencil, RefreshCw, Building } from "lucide-react";
+import { CalendarClock, RefreshCw, Building } from "lucide-react";

35-35: Consider memoizing the calculateNextReview result.

If the calculateNextReview function becomes computationally expensive in the future, consider memoizing the result with useMemo to prevent unnecessary recalculations.

-  const reviewInfo = calculateNextReview(lastPublishedAt, frequency);
+  const reviewInfo = useMemo(
+    () => calculateNextReview(lastPublishedAt, frequency),
+    [lastPublishedAt, frequency]
+  );

// Don't forget to add the import
// import { useMemo } from "react";
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceList.tsx (2)

41-53: Consider fetching enum values instead of hardcoding.

While hardcoding enum values works, consider fetching these values from an API or a shared constants file to ensure the UI stays in sync with backend changes.


93-93: Remove console.log statement before production.

There's a console.log statement that should be removed before deploying to production.

-console.log({ evidenceTasks, error });
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/DepartmentSection.tsx (1)

31-43: Enhance error handling for better debugging.

While the error handling works, consider providing more specific error messages based on the error type.

      onError: (error) => {
        console.error("Error updating department:", error);
-       toast.error("Failed to update department");
+       toast.error(`Failed to update department: ${error.message || "Unknown error"}`);
      },
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/hooks/useOrganizationAdmins.ts (2)

6-12: Consider using a more specific type for the role field.

The role field is currently typed as string, but if there are specific roles like "admin" or "owner", consider using a union type or enum for better type safety.

-  role: string;
+  role: "admin" | "owner" | "member";

33-38: Consider adding cache time configuration.

Since the list of organization admins likely doesn't change frequently, you might want to add a dedupingInterval or other cache configuration to optimize performance.

export function useOrganizationAdmins() {
  return useSWR<Admin[]>("organization-admins", fetchOrganizationAdmins, {
    revalidateOnFocus: false,
    revalidateOnReconnect: false,
+   dedupingInterval: 60000, // Cache for 1 minute
  });
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dda8060 and 4b798bc.

📒 Files selected for processing (23)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationAdmins.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEmployees.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEvidence.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEvidenceTasks.ts (5 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceList.tsx (11 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/data-table/columns.tsx (3 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/data-table/types.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Actions/assignEvidence.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Actions/updateEvidenceDepartment.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Actions/updateEvidenceFrequency.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/AssigneeSection.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/DepartmentSection.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/EvidenceDetails.tsx (4 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/FileCard.tsx (4 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/FileSection.tsx (3 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/FrequencySection.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/ReviewSection.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/hooks/useOrganizationAdmins.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/hooks/useEvidenceTasks.ts (2 hunks)
  • packages/db/prisma/migrations/20250225193214_add_evidence_assignee/migration.sql (1 hunks)
  • packages/db/prisma/migrations/20250225193719_update_evidence_assignee_to_user/migration.sql (1 hunks)
  • packages/db/prisma/migrations/20250225204820_add_department_to_evidence/migration.sql (1 hunks)
  • packages/db/prisma/schema.prisma (3 hunks)
🔇 Additional comments (75)
packages/db/prisma/migrations/20250225193719_update_evidence_assignee_to_user/migration.sql (1)

1-5: Good database constraint handling for assignee relationships.

The migration appropriately updates the foreign key constraint for the assigneeId column. Setting ON DELETE SET NULL is a good choice as it ensures evidence tasks remain in the system even if an assigned user is deleted. The ON UPDATE CASCADE maintains referential integrity if user IDs change.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationAdmins.ts (1)

1-71: Well-structured server action for retrieving organization admins

The implementation follows good practices with proper error handling, appropriate database querying, and clean data transformation. The action correctly verifies the user's organization context before executing the query.

A few suggestions for future enhancements:

  1. Consider adding pagination support if organizations might have many admins
  2. You might want to add caching for this data since admin lists don't change frequently
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/FileSection.tsx (1)

49-76: Good optimization to prevent redundant preview loading

The added check prevents duplicate preview loading operations when a preview is already loading or has been loaded.

packages/db/prisma/migrations/20250225193214_add_evidence_assignee/migration.sql (1)

1-9:

Details

✅ Verification successful

Foreign key references Employee table rather than User

The migration adds the assigneeId column with a foreign key constraint to the Employee table. However, based on the PR objective and the getOrganizationAdmins.ts file which returns User records, this should likely reference the User table instead.


🏁 Script executed:

#!/bin/bash
# Check if there are any subsequent migrations that might correct this
fd --type f ".*migration.sql$" packages/db/prisma/migrations | grep -A 5 "20250225193214" | sort

# Check the Prisma schema to see the current relationship
grep -A 5 "assigneeId" packages/db/prisma/schema.prisma

Length of output: 634


Action Required: Confirm Migration Order and Final Schema Consistency

The initial migration (20250225193214_add_evidence_assignee/migration.sql) adds the assigneeId column with a foreign key referencing the Employee table. However, as intended by the PR objective, the subsequent migration (20250225193719_update_evidence_assignee_to_user/migration.sql) updates the foreign key to reference the User table. This is verified by the Prisma schema that now shows the relationship as:

  • assigneeId String?
  • assignee User? @relation(fields: [assigneeId], references: [id], onDelete: SetNull)

Please ensure that the intended migration ordering is maintained in all deployment environments to avoid any inconsistency during rollouts. If the historical migration cannot be changed, consider adding a comment to the update migration for clarity to future maintainers.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Actions/updateEvidenceFrequency.ts (2)

8-11: Good schema validation using zod

The schema correctly validates that the id is a string and that frequency is a valid enum value or null.


26-47: Proper authorization and data validation

The action correctly verifies the user's organization context and ensures the evidence exists and belongs to the user's organization before proceeding with the update.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/EvidenceDetails.tsx (4)

12-12: Component replacement looks good

The ReviewSection component import replaces the previous ReviewDateCard, which aligns with the PR objective to enhance evidence tasks with department and assignee filtering capabilities.


45-53: Enhanced loading state UI

The loading state UI has been improved with a better structured skeleton layout that properly aligns with the actual rendered component.


84-107: Improved layout for publish status and button

The restructuring of the publish status and button improves the UI organization and maintains the conditional rendering functionality.


109-116: Review section implementation

The ReviewSection component properly receives all necessary props to handle evidence review information including the new department and assignee capabilities.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Actions/assignEvidence.ts (6)

8-21: Well-structured server action setup

The server action is well-defined with proper schema validation and metadata for tracking purposes.


26-31: Organization validation

Good security check to ensure the user has an associated organization before proceeding.


33-47: Evidence validation

Proper validation to ensure the evidence exists and belongs to the user's organization.


49-67: Assignee validation

Good security check to verify that the assignee exists and has the appropriate admin privileges.


69-78: Evidence update implementation

The code properly updates the evidence with the new assignee and sets the updated timestamp.


84-90: Error handling

Comprehensive error handling with appropriate logging and user-friendly error messages.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEvidenceTasks.ts (5)

4-4: Added department type import

The import of Departments aligns with the PR objective to add department filtering capability.


29-30: New filter parameters

The schema has been properly extended with new optional filters for department and assigneeId.


44-52: Enhanced input destructuring

The destructuring of parsedInput has been reorganized to include the new filter parameters.


70-74: Filter implementation

The whereClause construction has been properly extended to include filtering by department and assigneeId.


117-125: Assignee data inclusion

The query now includes the assignee data with appropriate field selection, which aligns with the PR objective to support assignee filtering.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEmployees.ts (5)

7-14: Well-structured server action setup

The server action is well-defined with proper metadata for tracking purposes.


18-23: Organization validation

Good security check to ensure the user has an associated organization before proceeding.


26-48: Query implementation

The database query is well-structured to retrieve organization members with admin or owner roles, including appropriate field selection and sorting.


51-56: Data transformation

Good transformation of the database results into a simpler format for the frontend.


62-68: Error handling

Comprehensive error handling with appropriate logging and user-friendly error messages.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Actions/updateEvidenceDepartment.ts (1)

1-71: Well-structured server action implementation with proper validation and security checks.

The action correctly validates input, performs proper authorization checks, and includes comprehensive error handling. It ensures the user has access to the organization's evidence before allowing the update.

Good practices observed:

  • Using zod for input validation
  • Checking organization membership
  • Verifying evidence ownership
  • Proper error handling with specific error messages
  • Appropriate logging
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/hooks/useEvidenceTasks.ts (4)

13-14: LGTM: New filter properties added correctly.

The department and assigneeId properties are correctly typed and properly added to the interface.


51-59: LGTM: Updated destructuring to include new properties.

The destructuring properly includes the new department and assigneeId properties with the existing ones.


62-71: LGTM: Updated SWR cache key with new filter parameters.

The SWR cache key array has been correctly updated to include the new filter parameters, ensuring proper cache invalidation when these values change.


73-81: LGTM: Updated fetchEvidenceTasks call with new parameters.

The fetchEvidenceTasks function call correctly passes the new department and assigneeId parameters.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/AssigneeSection.tsx (5)

18-22: LGTM: Clear and well-typed props interface.

The props interface is well-defined with appropriate types for each property.


29-33: LGTM: Proper state initialization.

The state is properly initialized with the current assignee ID, falling back to null if not provided.


35-43: LGTM: Well-structured action hook with success and error handling.

The useAction hook implementation includes proper success and error feedback through toast notifications.


72-89: LGTM: Good UX with loading and error states.

The component properly handles loading and error states, providing appropriate feedback to the user.


96-151: LGTM: Well-designed select component with avatar integration.

The select implementation is well-designed, providing both a visual representation (avatar) and the name of each assignee. The placeholder for unassigned status is also a nice touch.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/ReviewSection.tsx (2)

37-106: LGTM: Well-organized layout with clear sections.

The component has a well-structured layout with clear sections for different types of information (department, frequency, next review). The responsive design (using flex-col/flex-row) ensures good display across different device sizes.


92-101: LGTM: Clear conditional rendering for next review date.

The conditional rendering for the next review date is implemented well, showing "ASAP" in red when no review information is available and the days until review with the formatted date otherwise.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/FrequencySection.tsx (1)

1-79: Clean and functional frequency selection component with proper state management.

This component is well-structured and follows React best practices. It correctly manages state, handles side effects with useEffect, and provides appropriate feedback to users through toast notifications. The component is also properly typed with a clear interface.

I particularly like how the component:

  1. Synchronizes its local state with the incoming prop using useEffect
  2. Uses the next-safe-action pattern for handling server actions
  3. Provides visual feedback during execution with the disabled state
  4. Has clean error handling with user-friendly messages
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/data-table/columns.tsx (2)

66-88: Well-implemented department column with proper null handling.

The department column implementation is clean with good formatting logic. It properly handles cases where the department is null or "none" by displaying a fallback message. The visual formatting with the Building icon and text transformation enhances readability.


134-164: Robust assignee column with proper fallback handling.

The assignee column implementation is well-executed. It handles the unassigned state appropriately and includes a nicely formatted display with an avatar. The avatar component has proper fallback handling for when an image is not available. The text truncation is also a good detail for handling long names in a limited space.

packages/db/prisma/schema.prisma (2)

1057-1058: Good default value for department field.

Setting a default value of "none" for the department field ensures there won't be null values to handle in the UI. This is consistent with how the department is handled in the UI components.


1070-1075: Well-structured relationship for assignee with appropriate cascade behavior.

The assignee relationship is properly implemented with an index for query optimization. Using onDelete: SetNull is a good choice here as it ensures that if a user is deleted, the evidence won't be deleted with it, but the assignee reference will be cleared.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/FileCard.tsx (7)

3-3: Ensure all imports are necessary.

The import statement now includes useState which is properly utilized for the newly added preview loading state.


6-11: LGTM - Dialog components properly imported.

The DialogTitle component is now correctly imported and used in the file preview dialog.


29-32: LGTM - Icons and accessibility components added.

Added Loader2 and Maximize2 icons for visual indicators, and VisuallyHidden for accessibility.


60-74: Great user experience improvement with automatic preview loading.

The automatic preview loading functionality enhances user experience by loading the preview as soon as the component mounts, rather than requiring a user action.


78-150: Well-structured preview rendering with improved UX.

The preview rendering has been significantly improved with:

  • Clear loading states
  • Better handling of different file types
  • Direct preview in card
  • Maximize buttons for expandability
  • Proper tooltips for file names

This implementation provides better immediate feedback to users and a more intuitive interface.


152-154: LGTM - Added file name in dialog title.

Adding the file name in the DialogTitle improves context awareness when viewing the expanded preview.


233-233: Minor icon size adjustment for consistency.

Size adjustment for the Trash icon ensures visual consistency in the UI.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceList.tsx (14)

17-19: LGTM - Icons imported for new filter UI elements.

The Building and User icons are appropriately imported for use in the department and assignee filter UI.


30-31: LGTM - Type imports properly updated.

The Departments type is now imported from @bubba/db for proper type checking of the department filter.


39-40: LGTM - Avatar components imported for assignee display.

Avatar components are imported for better visual representation of assignees in the filter dropdown.


59-60: LGTM - New query state variables for filtering.

New query state variables for department and assignee filtering are correctly implemented.


78-79: LGTM - Updated API parameters for filtering.

The useOrganizationEvidenceTasks hook is properly updated to include the new filter parameters.


95-103: LGTM - Improved memo handling for filter options.

Using predefined constants for frequencies and departments improves performance by avoiding recalculations on each render.


105-129: Well-structured assignee data handling.

The approach to building a map of unique assignees is clean and efficient. Using Map and providing proper sorting ensures a consistent UI experience.


135-136: LGTM - Updated clearFilters to include new filters.

The clearFilters function correctly resets the new department and assignee filters.


154-158: LGTM - Updated filter check logic.

The hasActiveFilters check is properly updated to include the new filter states.


172-176: LGTM - Helper for selected assignee display.

Finding the selected assignee name for display is well implemented.


197-200: LGTM - Updated badge count logic.

The active filter badge count is correctly updated to include the new filters.


248-295: Well-structured department and assignee filter UI.

The new filter UI components are well-organized and maintain consistency with the existing filtering pattern:

  • Clear visual indicators with icons
  • Consistent interaction patterns
  • Proper state handling
  • Reset to first page when filters change

The Avatar implementation for assignees adds a nice visual touch.


341-367: LGTM - Filter badges for new filters.

New filter badges for department and assignee match the existing pattern and provide clear visual feedback about active filters.


402-416: LGTM - Pagination button adjustments.

Minor adjustments to pagination button styling maintain UI consistency.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/Components/DepartmentSection.tsx (7)

1-15: LGTM - Well-structured imports and client directive.

The component correctly uses the client directive and imports all necessary dependencies.


16-20: LGTM - Clear interface definition.

The DepartmentSectionProps interface is well-defined with appropriate types.


22-29: LGTM - Proper state initialization.

State is correctly initialized from props with appropriate fallback.


45-48: LGTM - Sync state with prop changes.

The useEffect correctly syncs the internal state when the currentDepartment prop changes.


49-53: LGTM - Clean value handling.

The department change handler properly manages the "none" value case and updates both local state and remote data.


55-57: LGTM - Good filter implementation.

Filtering out the "none" option from the dropdown and handling it separately improves the UX.


59-77: LGTM - Well-structured and accessible UI.

The Select component implementation is clean with:

  • Proper disabled state during execution
  • Clear placeholder
  • Consistent formatting of department names
  • Proper "None" option handling

The UI provides a good user experience for department selection.

packages/db/prisma/migrations/20250225204820_add_department_to_evidence/migration.sql (1)

1-2: SQL migration looks good.

The migration correctly adds a department column to the OrganizationEvidence table with a default value of 'none'. This aligns with the PR objective to support department filtering.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Actions/getOrganizationEvidence.ts (1)

37-40: Approved: Added assignee inclusion to query.

Including the assignee data is necessary for the new filtering functionality and properly extends the query result shape.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/data-table/types.ts (1)

7-12: Type extension looks good.

The assignee property is properly defined with all necessary fields and correctly marked as optional. This supports the assignee filtering functionality required by the PR.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/hooks/useOrganizationAdmins.ts (1)

14-31: Robust error handling in the fetcher function.

The fetchOrganizationAdmins function has comprehensive error handling and appropriate fallbacks. Good job!

…ilter components

- Extract filter-related components into separate files for better organization
- Create EvidenceTableProvider to centralize state management for evidence tasks
- Implement modular components for search, filtering, and pagination
- Move constants to a dedicated file
- Simplify EvidenceList component by delegating responsibilities to new components
- Improve code readability and maintainability
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (10)
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/constants.ts (2)

4-11: Consider future-proofing department definitions.

While the current implementation is clean and appropriate, consider implementing a mechanism to ensure these constants stay in sync with the actual enum definitions in the database schema. If the Departments enum in @bubba/db changes, this array would need manual updates.


14-14: Consistent formatting for arrays.

For consistency with the ALL_DEPARTMENTS array, consider formatting the ALL_FREQUENCIES array with each value on a separate line, especially if more frequencies might be added in the future.

-export const ALL_FREQUENCIES: Frequency[] = ["monthly", "quarterly", "yearly"];
+export const ALL_FREQUENCIES: Frequency[] = [
+  "monthly",
+  "quarterly",
+  "yearly",
+];
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/ActiveFilterBadges.tsx (2)

57-68: Consider extracting department name formatting to a utility function

The department name formatting logic (replacing underscores with spaces and converting to uppercase) might be needed elsewhere in the application. Consider extracting this to a utility function for reusability.

- Department: {department.replace(/_/g, " ").toUpperCase()}
+ Department: {formatDepartmentName(department)}

And then create a utility function:

// utils/formatting.ts
export function formatDepartmentName(department: string): string {
  return department.replace(/_/g, " ").toUpperCase();
}

69-80: Simplify assignee badge condition

The condition check for both assigneeId and assigneeName is redundant since you're already handling the "Unknown" case when finding the assignee name.

- {assigneeId && assigneeName && (
+ {assigneeId && (
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/PaginationControls.tsx (1)

41-46: Consider making page size options configurable

The page size options are currently hardcoded. Consider making these configurable through props or a constant to improve flexibility and maintainability.

- {[5, 10, 20, 50, 100].map((size) => (
+ {PAGE_SIZE_OPTIONS.map((size) => (

And define the constant:

// Either as a constant in the same file or in a constants file
const PAGE_SIZE_OPTIONS = [5, 10, 20, 50, 100];

// Or through props
interface PaginationControlsProps {
  pageSizeOptions?: number[];
}

export function PaginationControls({ 
  pageSizeOptions = [5, 10, 20, 50, 100] 
}: PaginationControlsProps) {
  // ...
}
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/SearchInput.tsx (1)

21-28: Consider optimizing the pagination reset

The component always resets the page to "1" on every debounce update, even when clearing the search input. This might cause unnecessary rerenders if a user frequently clears the input without typing new content.

useEffect(() => {
  if (debouncedValue === "") {
    setSearch(null);
+   if (search !== null) {
+     setPage("1"); // Only reset page when actually clearing a search
+   }
  } else {
    setSearch(debouncedValue);
+   setPage("1"); // Reset to first page when searching
  }
- setPage("1"); // Reset to first page when searching
}, [debouncedValue, setSearch, setPage, search]);
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/FilterDropdown.tsx (1)

107-109: Consider parameterizing the department format transformation.

The code assumes departments are stored with underscores that should be displayed as spaces and in uppercase. If the formatting requirements change, you'd need to update this in multiple places.

Consider extracting this to a utility function:

-<span>{dept.replace(/_/g, " ").toUpperCase()}</span>
+<span>{formatDepartmentName(dept)}</span>

And define the function elsewhere to be reused across the application.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceList.tsx (1)

19-19: Consider adding an empty state message instead of returning null.

When there are no evidence tasks and the component is not loading, it returns null. This might be confusing for users.

Consider adding an empty state message to guide users:

-if (!evidenceTasks.length && !isLoading) return null;
+if (!evidenceTasks.length && !isLoading) {
+  return (
+    <div className="w-full py-10 text-center">
+      <p className="text-muted-foreground">No evidence tasks found. Try adjusting your filters.</p>
+    </div>
+  );
+}
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/hooks/useEvidenceTableContext.tsx (2)

94-101: Simplify data transformation if possible.

The transformation from rawEvidenceTasks to evidenceTasks only adds an evidence object with a name property that duplicates the existing name property.

If this transformation isn't required by the DataTable component, consider simplifying:

-  const evidenceTasks = useMemo(() => {
-    return rawEvidenceTasks?.map((task) => ({
-      ...task,
-      evidence: {
-        name: task.name,
-      },
-    })) as EvidenceTaskRow[] | undefined;
-  }, [rawEvidenceTasks]);
+  const evidenceTasks = rawEvidenceTasks as EvidenceTaskRow[] | undefined;

If it is required, consider adding a comment explaining why this transformation is needed.


108-129: Consider fetching all assignees separately.

The current implementation only shows assignees who are assigned to tasks in the current filtered view, which might limit filtering options.

Consider fetching all possible assignees from a separate API call to ensure users can filter by any assignee regardless of current view state.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b798bc and 8c2292d.

📒 Files selected for processing (11)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/ActiveFilterBadges.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/FilterDropdown.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/PaginationControls.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/SearchInput.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/index.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceList.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/data-table/index.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/index.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/constants.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/hooks/useEvidenceTableContext.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/page.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/index.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/data-table/index.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/index.ts
🔇 Additional comments (11)
apps/app/src/app/[locale]/(app)/(dashboard)/evidence/constants.ts (1)

1-14: Constants align with the new filtering requirements and follow good practices.

The file properly defines type-safe constants for departments and frequencies that will be used for filtering evidence tasks, which aligns with the PR objective of adding department filtering functionality. The constants are well-organized with descriptive comments.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/page.tsx (1)

2-2: Proper implementation of context provider pattern

The addition of the EvidenceTableProvider wrapper is a clean implementation of the context provider pattern. This is a good architectural decision that centralizes state management for evidence filtering functionality.

Also applies to: 5-9

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/ActiveFilterBadges.tsx (1)

7-30: Well-structured filter badge implementation

The component correctly handles displaying active filters with a clean implementation for finding the assignee name and returning null when no filters are active.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/PaginationControls.tsx (1)

14-22: Good pagination implementation with proper error handling

The component properly handles missing pagination data by returning null and correctly parses the current page.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/SearchInput.tsx (1)

13-29: Efficient implementation of debounced search

Good use of debounce to optimize performance while typing. The effect correctly handles both setting and clearing the search, and resets pagination when search changes.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceFilters/FilterDropdown.tsx (3)

85-88: Good use of pagination reset during filtering.

Resetting to the first page when a filter changes is good UX practice - this prevents confusion that might occur if the user is on a page that no longer exists after filtering.


126-136: Graceful handling of missing assignee images.

Good implementation of the Avatar component with proper fallbacks for when images are missing or null.


140-152: Clean implementation of "Clear all filters" button.

The conditional rendering of the clear filters button only when filters are active is a good UX pattern. The ghost variant is appropriate for this type of secondary action.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/Components/EvidenceList.tsx (2)

25-36: Well-organized filter UI components.

The separation of filter components into distinct, reusable parts (SearchInput, FilterDropdown, ActiveFilterBadges) improves code organization and maintainability.


43-43: Simplified data table implementation.

The DataTable now directly receives the evidenceTasks array without additional transformation, suggesting good standardization of the data structure.

apps/app/src/app/[locale]/(app)/(dashboard)/evidence/hooks/useEvidenceTableContext.tsx (1)

196-200: Good context validation.

Throwing an error when the hook is used outside of its provider prevents subtle bugs and makes the dependency clear to developers.

Comment on lines +85 to +91
status: status as "published" | "draft" | null,
frequency: frequency as any,
department: department as any,
assigneeId,
page: currentPage,
pageSize: currentPageSize,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using 'any' type assertions.

Type assertions to 'any' bypass TypeScript's type checking, potentially leading to runtime errors. This is especially concerning when passing these values to API calls.

Replace the 'any' type assertions with proper types:

-  frequency: frequency as any,
-  department: department as any,
+  frequency: frequency as Frequency | null,
+  department: department as Departments | null,
📝 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
status: status as "published" | "draft" | null,
frequency: frequency as any,
department: department as any,
assigneeId,
page: currentPage,
pageSize: currentPageSize,
});
status: status as "published" | "draft" | null,
frequency: frequency as Frequency | null,
department: department as Departments | null,
assigneeId,
page: currentPage,
pageSize: currentPageSize,
});

- Implement server action `getEvidenceTasksStats` to calculate evidence task statuses
- Create `useEvidenceTasksStats` hook for fetching and managing task statistics
- Add `EvidenceSummaryCards` component to display task status overview
- Enhance `EvidenceList` with summary cards and improved empty state handling
- Improve error logging and handling in evidence tasks data fetching
- Add detailed logging for debugging evidence tasks data
@vercel vercel Bot temporarily deployed to Preview – comp-portal February 25, 2025 22:57 Inactive
@vercel vercel Bot temporarily deployed to Preview – web February 25, 2025 22:57 Inactive
@vercel vercel Bot temporarily deployed to Preview – app February 25, 2025 22:58 Inactive
@vercel vercel Bot temporarily deployed to Preview – web February 25, 2025 22:58 Inactive
@vercel vercel Bot temporarily deployed to Preview – comp-portal February 25, 2025 22:58 Inactive
@Marfuen Marfuen merged commit 1794850 into main Feb 25, 2025
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