Skip to content

Vendor Page - Partial Implementation - #177

Merged
claudfuen merged 16 commits into
mainfrom
claudio/misc-fixes-2
Mar 25, 2025
Merged

claudfuen merged 16 commits into
mainfrom
claudio/misc-fixes-2

Conversation

@claudfuen

@claudfuen claudfuen commented Mar 24, 2025 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Introduced a new VendorOverview component for displaying vendor details.
    • Added new components for managing vendor comments and tasks, including CreateVendorCommentForm, TaskAttachments, and UpdateTaskForm.
  • UI & Styling

    • Enhanced chart color themes with new CSS variables for better visual representation.
    • Updated localization messages for vendor-related functionalities to improve user experience.
  • Refactor

    • Streamlined vendor forms and user interactions for smoother experiences and clearer visual feedback.
    • Modularized vendor retrieval and task fetching logic in the VendorPage component for improved clarity.

- Enhanced the createVendorAction to return a typed ActionResponse with Vendor data.
- Updated the CreateVendor component to utilize useRouter for navigation upon successful vendor creation, improving user experience.
- Updated the VendorOverview component to utilize server-side rendering and display vendor status and category charts.
- Introduced new chart colors for better visual distinction in the status and category charts.
- Removed unused code and streamlined the layout for enhanced readability and performance.
- Added CSS variables for chart colors to maintain consistency across the application.
… title and description, and add comments section
…omment features, and implement task attachment handling
…pdate task handling, and restructure data table integration
@vercel

vercel Bot commented Mar 24, 2025 •

Copy link
Copy Markdown

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

Name Status Preview Comments Updated (UTC)
app 🛑 Canceled (Inspect) Mar 25, 2025 0:22am
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
comp-portal ⬜️ Skipped (Inspect) Mar 25, 2025 0:22am

@CLAassistant

CLAassistant commented Mar 24, 2025 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Mar 24, 2025 •

Copy link
Copy Markdown

Walkthrough

The update refactors several modules to shift emphasis from risk management to vendor management. Unused tracking and database imports were removed. Multiple vendor schemas, actions, and components have been added or modified. Components and pages now use new naming conventions, control flows, and localized text for vendor tasks, comments, and details. Some risk-related components and forms have been removed altogether. Additionally, CSS variables and Tailwind configuration have been enhanced, and the seeding process in the database package has been restructured.

Changes

File(s) Change Summary
apps/app/src/actions/safe-action.ts Removed unused imports for database and analytics tracking.
apps/app/src/actions/schema.ts Deleted vendor management schemas (e.g., vendorContactSchema, createVendorSchema, etc.).
apps/app/src/app/[...]/risk/[riskId]/page.tsx Removed caching wrappers from getRisk and getTasks functions.
apps/app/src/app/[...]/vendors/(overview)/components/charts/status-chart.tsx
apps/app/src/app/[...]/vendors/(overview)/components/charts/vendors-by-category.tsx
Modified status colors and name formatting; introduced CHART_COLORS for vendor overview charts.
apps/app/src/app/[...]/vendors/(overview)/components/charts/vendor-overview.tsx
apps/app/src/app/[...]/vendors/(overview)/page.tsx
Added new VendorOverview component and replaced placeholders with functional vendor management UI.
apps/app/src/app/[...]/vendors/[vendorId]/actions/*.ts
(create-vendor-comment, create-task-action, create-task-comment, revalidate-upload, update-task-action, update-vendor-action)
apps/app/src/app/[...]/vendors/[vendorId]/actions/schema.ts
Introduced multiple new vendor actions and schemas for comments, tasks, and vendor updates with added revalidation logic.
apps/app/src/app/[...]/vendors/[vendorId]/comments/*.tsx Renamed risk comment forms to vendor; added VendorCommentSheet and VendorComments components; enabled comments in page rendering.
apps/app/src/app/[...]/vendors/[vendorId]/components/secondary-fields/*.tsx Added SecondaryFields and refactored update form (UpdateSecondaryFieldsForm) to handle vendor information.
apps/app/src/app/[...]/vendors/[vendorId]/components/tasks/*.tsx Renamed CreateTaskForm to CreateVendorTaskForm; added CreateVendorTaskSheet, DataTable, empty-states, and updated client column headers for vendor tasks.
apps/app/src/app/[...]/vendors/[vendorId]/components/title-and-description/*.tsx Introduced TitleAndDescription, UpdateTitleAndDescriptionForm, and UpdateTitleAndDescriptionSheet components for vendor details editing.
apps/app/src/app/[...]/vendors/[vendorId]/layout.tsx
apps/app/src/app/[...]/vendors/[vendorId]/page.tsx
Refactored vendor page layout with new data-fetching functions (getVendor, getUsers, getTasks) and back button functionality.
apps/app/src/app/[...]/vendors/[vendorId]/tasks/[taskId]/*.tsx Updated import paths and added new task components: TaskAttachments, TaskComment, TaskOverview, UpdateTaskForm, and TaskPage.
apps/app/src/app/[...]/vendors/actions/create-vendor-action.ts Updated return type to include Vendor type for increased type safety.
apps/app/src/app/[...]/vendors/components/create-vendor-form.tsx
apps/app/src/app/[...]/vendors/components/create-vendor-sheet.tsx
Renamed CreateVendor to CreateVendorForm and updated navigation logic post vendor creation.
Deleted files:
inherent-risk-form.tsx, residual-risk-form.tsx, update-task-form.tsx (vendor tasks), update-risk-form.tsx,
components/tables/vendor-tasks/empty-states.tsx, vendors-overview.tsx, vendor-overview.tsx
Removed obsolete risk-related components and views.
apps/app/src/locales/features/vendors.ts Added new localization keys for vendor overview, forms, task sheets, and update messages.
apps/app/src/styles/globals.css Added new CSS variables for chart state colors.
packages/db/prisma/seed.js Introduced new functions (seedEvidenceRecords, updateEvidenceLinks, updatePolicyLinks) to restructure database seeding.
packages/ui/tailwind.config.ts Added new chart color definitions to the Tailwind theme.
Minor changes:
create-task-form.tsx, loading.tsx, vendor register components
Consolidated imports and updated relative import paths for consistency.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant VP as VendorPage
    participant API as Server/API
    participant DB as Database

    C->>VP: Request vendor page
    VP->>API: getVendor(vendorId)
    API->>DB: Query vendor details
    DB-->>API: Vendor details
    VP->>API: getUsers()
    API->>DB: Query users list
    DB-->>API: List of users
    VP->>API: getTasks(vendorId, filters)
    API->>DB: Query vendor tasks
    DB-->>API: Task data
    VP-->>C: Render TitleAndDescription,\nSecondaryFields,\nDataTable, VendorComments
Loading
sequenceDiagram
    participant U as User (Client)
    participant VCS as VendorCommentSheet
    participant ACT as createVendorCommentAction
    participant DB as Database

    U->>VCS: Submit new vendor comment
    VCS->>ACT: Trigger comment action with input data
    ACT->>DB: Insert vendor comment record
    DB-->>ACT: Acknowledgement/ID
    ACT->>VCS: Return success response
    VCS-->>U: Update comments display
Loading

Poem

I'm a bunny coding away,
Hopping through changes in a brand new way.
Vendor tasks and comments now shine bright,
With each refactor, my heart feels light.
Fresh code paths make my days so gay!
🐰💻 Hop on, let’s play!

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🔭 Outside diff range comments (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/create-vendor-task-form.tsx (1)

121-123: 🛠️ Refactor suggestion

Additional translation keys to update

There are more translation keys that need to be updated to maintain consistency.

                              placeholder={t(
-                                "risk.tasks.form.task_title_description",
+                                "vendors.tasks.form.task_title_description",
                              )}

                              placeholder={t(
-                                "risk.tasks.form.description_description",
+                                "vendors.tasks.form.description_description",
                              )}

-                          <FormLabel>{t("risk.tasks.form.due_date")}</FormLabel>
+                          <FormLabel>{t("vendors.tasks.form.due_date")}</FormLabel>

Also applies to: 144-146, 159-159

🧹 Nitpick comments (49)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/data-table.tsx (1)

103-107: Consider uncommenting the pagination component

The pagination component is commented out but its props are already being passed to the DataTable component. Consider either uncommenting this section to enable pagination or removing the unused props if pagination is handled elsewhere.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/update-task-overview-form.tsx (1)

95-95: Hard-coded form label instead of using translation

The form label for the description field is now a static string "Description" instead of using the translation function. Consider using i18n for consistency with other labels.

-                <FormLabel>Description</FormLabel>
+                <FormLabel>{t("risk.tasks.form.description")}</FormLabel>

Or if updating to the new pattern:

-                <FormLabel>Description</FormLabel>
+                <FormLabel>{t("common.fields.description")}</FormLabel>
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/create-task-action.ts (1)

45-49: Improve error handling with detailed error messages

The current error handling doesn't provide any specific error message back to the client, which makes debugging difficult. Consider returning more detailed error information to help diagnose issues.

Apply this diff to improve error handling:

    } catch (error) {
      return {
        success: false,
+       error: error instanceof Error ? error.message : "An unknown error occurred",
      };
    }
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-attachments.tsx (2)

26-28: Improve error handling

The error state simply displays "Error" without providing any details about what went wrong. This could be improved to be more informative for users.

-  if (error) {
-    return <div>Error</div>;
-  }
+  if (error) {
+    return (
+      <div className="text-destructive text-sm">
+        {t("common.errors.loading_failed")}: {error.message || t("common.errors.unknown")}
+      </div>
+    );
+  }

36-36: Redundant variable assignment

Assigning data to attachments adds unnecessary complexity without providing value. Consider using data directly.

-  const attachments = data;
-
-  return (
-    <Card>
-      ...
-        <FileSection
-          uploadType={UPLOAD_TYPE.riskTask}
-          taskId={taskId}
-          fileUrls={attachments.map((attachment) => attachment.fileUrl)}
+  return (
+    <Card>
+      ...
+        <FileSection
+          uploadType={UPLOAD_TYPE.riskTask}
+          taskId={taskId}
+          fileUrls={data.map((attachment) => attachment.fileUrl)}
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/create-task-comment.ts (1)

1-1: Remove redundant file header comment

The comment is redundant as it duplicates the filename.

-// create-task-comment.ts
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/create-vendor-comment.ts (2)

1-1: Incorrect file header comment

The file header comment incorrectly refers to "create-risk-comment.ts" but this file is for vendor comments.

-// create-risk-comment.ts
+// create-vendor-comment.ts

42-46: Add error details to failure response

The error handler logs the error but doesn't provide any error information to the client. Consider adding error details to help with debugging and user feedback.

      return { success: true };
    } catch (error) {
      console.error("Error creating vendor comment:", error);

-      return { success: false };
+      return { 
+        success: false,
+        error: error instanceof Error ? error.message : "Unknown error occurred"
+      };
    }
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/layout.tsx (1)

7-10: Improve params interface definition

The params is defined as a Promise in the interface, but it's awaited in the function body. It would be clearer to define it as a non-Promise type.

interface LayoutProps {
  children: React.ReactNode;
-  params: Promise<{ vendorId: string }>;
+  params: { vendorId: string } | Promise<{ vendorId: string }>;
}
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/page.tsx (1)

88-88: Update metadata title to match current functionality.

The metadata title still references "sidebar.risk" but this page is now about vendor management. Consider updating the title to match the current functionality.

- title: t("sidebar.risk"),
+ title: t("sidebar.vendors"),
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/update-vendor-action.ts (5)

1-2: Update file comment to match actual functionality.

The comment at the top of the file refers to "update-risk-action.ts" but this file is for vendor actions.

-// update-risk-action.ts
+// update-vendor-action.ts

19-22: Missing return type annotation.

Unlike the createVendorAction which now specifies Promise<ActionResponse<Vendor>> as its return type, this action lacks a return type annotation. Consider adding it for consistency and improved type safety.

-  .action(async ({ parsedInput, ctx }) => {
+  .action(async ({ parsedInput, ctx }): Promise<ActionResponse<Vendor>> => {

34-40: Simplify object property assignments.

Since the property names match the variable names, you can use object shorthand notation.

        data: {
-          name: name,
-          description: description,
-          ownerId: ownerId,
-          category: category,
-          status: status,
+          name,
+          description,
+          ownerId,
+          category,
+          status,
        },

48-50: Return the updated vendor data.

The success response doesn't include the updated vendor data, unlike createVendorAction which returns the vendor in the response. For consistency, consider returning the updated vendor data.

      return {
        success: true,
+       data: updatedVendor,
      };

To implement this, you'll need to capture the return value from the update operation:

-      await db.vendor.update({
+      const updatedVendor = await db.vendor.update({

54-56: Add error message to the error response.

The error response doesn't include an error message, unlike createVendorAction. Consider adding the error message to the response for better error handling.

      return {
        success: false,
+       error: error instanceof Error ? error.message : "Failed to update vendor",
      };
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-overview.tsx (3)

30-38: Consider improving edit button visibility

The pencil icon button in the alert title is quite small (h-3 w-3) and might be hard to notice. Consider making it slightly larger or adding a tooltip to improve discoverability.

-              <PencilIcon className="h-3 w-3" />
+              <PencilIcon className="h-4 w-4" />

52-54: Add error handling for the UpdateTaskForm

When reusing the form component, it would be beneficial to handle potential form submission errors at this level as well, especially since the task is being displayed in a different context than its original form.


44-55: Consider adding a loading state

The card content doesn't show any loading state while the task data might be updating. Consider adding a loading indicator to improve user experience.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comments.tsx (2)

40-69: Add fallback handling for missing user data

When displaying comments, there's no fallback handling if a user is not found. This could lead to potential errors if the user data is incomplete.

-              const commentUser = users.find(
-                (user) => user.id === comment.ownerId,
-              );
+              const commentUser = users.find(
+                (user) => user.id === comment.ownerId,
+              ) || { name: t("common.unknown_user"), image: null };

59-65: Use localized date format

The date format is hardcoded, which could lead to localization issues. Consider using a localized date format that respects the user's locale.

-                      date={format(comment.createdAt, "MMM d yyyy, h:mm a")}
+                      date={t("common.date_format", { date: comment.createdAt })}

Make sure to add the appropriate translation key in your localization files.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/update-task-action.ts (1)

28-41: Incorrect error message for risk ID validation.

The error message when a risk ID is not found doesn't match what's being checked.

- throw new Error("Risk not found");
+ throw new Error("Task not found");
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/title-and-description.tsx (1)

23-23: Inconsistent icon usage

The component is using <Icons.Risk className="h-4 w-4" /> which seems inconsistent with the vendor management context. Consider using a more appropriate icon that represents vendor information.

-        <Icons.Risk className="h-4 w-4" />
+        <Icons.Vendor className="h-4 w-4" />
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/empty-states.tsx (2)

23-23: Inconsistent icon usage

Using <Icons.Transactions2 className="mb-4" /> for a "no results" state seems semantically inappropriate. Consider using an icon that better represents empty results or tasks, such as an empty box or document.

-        <Icons.Transactions2 className="mb-4" />
+        <Icons.EmptyBox className="mb-4" />

48-70: Unused prop and potential layout issues

The isEmpty prop is declared but never used in the component. Also, the absolute positioning (absolute w-full top-0 left-0) could cause layout issues if not carefully managed.

-export function NoTasks({ isEmpty }: { isEmpty: boolean }) {
+export function NoTasks() {
   const t = useI18n();
   const [_, setOpen] = useQueryState("create-vendor-task-sheet");

   return (
-    <div className="absolute w-full top-0 left-0 flex items-center justify-center z-20">
+    <div className="relative w-full flex items-center justify-center py-8">
       <div className="text-center max-w-sm mx-auto flex flex-col items-center justify-center">
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/update-title-and-description-sheet.tsx (2)

51-51: Remove unnecessary space element

There's an unnecessary {" "} which is likely a leftover from editing.

-            </div>{" "}
+            </div>

65-72: Inconsistent UI between desktop and mobile views

The desktop version includes a title and description in the header, while the mobile version only has a hidden title. Consider adding the description to the mobile view for consistency.

  return (
    <Drawer open={isOpen} onOpenChange={handleOpenChange}>
-      <DrawerTitle hidden>{t("vendors.form.update_vendor")}</DrawerTitle>
+      <DrawerTitle>{t("vendors.form.update_vendor")}</DrawerTitle>
      <DrawerContent className="p-6">
+        <p className="text-sm text-muted-foreground mb-4">
+          {t("vendors.form.update_vendor_description")}
+        </p>
        <UpdateTitleAndDescriptionForm vendor={vendor} />
      </DrawerContent>
    </Drawer>
  );
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comment-sheet.tsx (1)

51-51: Remove unnecessary string literal.

There's an unnecessary {" "} string literal after the closing div tag which doesn't serve any purpose in the JSX structure.

-            </div>{" "}
+            </div>
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/update-title-and-description-form.tsx (2)

58-58: Remove console.log statement.

Production code should not contain console.log statements. This debugging statement should be removed before deployment.

-    console.log("Form submitted with data:", data);

57-67: Simplify form submission.

The current implementation unnecessarily unpacks and repacks the form data without any transformation. You can simply pass the data object directly to the execute method.

 const onSubmit = (data: z.infer<typeof updateVendorSchema>) => {
-    console.log("Form submitted with data:", data);
-    updateVendor.execute({
-      id: data.id,
-      name: data.name,
-      description: data.description,
-      category: data.category,
-      status: data.status,
-      ownerId: data.ownerId,
-    });
+    updateVendor.execute(data);
 };
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/data-table.tsx (2)

104-108: Decide on pagination implementation.

There's a commented-out DataTablePagination component. Either implement the pagination functionality or remove the commented code to keep the codebase clean. If pagination is planned for a future iteration, consider adding a TODO comment with more details.


91-100: Improve empty state messaging.

The current "No results" message is generic. Consider enhancing the empty state to provide more context and potentially actionable guidance for the user.

 <TableRow>
   <TableCell
     colSpan={columnHeaders.length}
     className="h-24 text-center"
   >
-    No results.
+    No tasks found. Create a new task to get started.
   </TableCell>
 </TableRow>
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-comments.tsx (1)

48-56: Optimize user lookup.

The code calls users.find() twice for each comment, which is inefficient. Find the user once and store the result to improve performance, especially if the users array is large.

 <div className="flex items-center gap-2">
   <div className="flex items-center gap-2">
+    {(() => {
+      const user = users.find((user) => user.id === comment.ownerId);
+      return (
       <AssignedUser
-        fullName={
-          users.find((user) => user.id === comment.ownerId)?.name
-        }
-        avatarUrl={
-          users.find((user) => user.id === comment.ownerId)?.image
-        }
+        fullName={user?.name}
+        avatarUrl={user?.image}
       />
+      );
+    })()}
     <span className="text-sm text-muted-foreground">
       ({format(comment.createdAt, "MMM d, yyyy")})
     </span>
   </div>
 </div>
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/page.tsx (1)

128-224: Consider adding input validation for pagination
While the pagination logic is correct in most cases, an invalid or negative page number could produce unexpected skip values. It may be beneficial to clamp or sanitize page and per_page inputs to prevent potential edge cases.

Here's a possible approach:

 async function getTasks({
   riskId,
   search,
   status,
   column,
   order,
-  page = 1,
-  per_page = 10,
+  page: rawPage = 1,
+  per_page: rawPerPage = 10,
 }: {
   ...
 }) {
   const session = await auth();
   if (!session || !session.user.organizationId) {
     return { tasks: [], total: 0 };
   }

+  const page = Math.max(1, rawPage);
+  const per_page = Math.max(1, rawPerPage);

   const skip = (page - 1) * per_page;
   ...
 }
packages/db/prisma/seed.js (2)

357-399: Evidence link updates for control requirements (lines 357–399).

Everything logically fits. Consider grouping database updates in a transaction if atomicity is crucial, but this is a good approach for a phased seed.

🧰 Tools
🪛 Biome (1.9.4)

[error] 357-357: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


427-469: Policy link updates for control requirements (lines 427–469).

As with evidence links, consider wrapping multiple updates in a transaction for reliability. Implementation is consistent with the rest of your seeding logic.

🧰 Tools
🪛 Biome (1.9.4)

[error] 427-427: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/page.tsx (8)

1-2: Consider including a comment explaining server-side usage.

You have added "use server"; at line 1, which indicates this file executes on the server. A brief comment or docstring can clarify the server-side context or rationale for new contributors.


20-21: Ensure consistent naming for vendor-related components.

Using TitleAndDescription and SecondaryFields clarifies your new architecture, but confirm if naming aligns with other vendor or task components for coherence across the codebase.


36-38: Validate vendor existence early.

You are retrieving the vendor at lines 36-38, but consider a quick null check or redirect if the vendor is not found earlier. This can optimize code paths by avoiding unnecessary user or task lookups when the vendor is invalid.


62-62: Redirect to a relevant page.

Redirecting to "/" might be abrupt for users. Consider redirecting to a safer fallback page (like a vendors listing page or an error page) for better user experience if vendor is null.


103-121: Add error handling for vendor retrieval.

Your getVendor function returns null if the session or organization ID is missing. Consider logging or throwing a more descriptive error in scenarios where a vendor fails to load, to facilitate easier debugging.


123-133: Consider caching or partial memoization.

getUsers retrieves the same organization users repeatedly if multiple calls are made. Depending on usage, you could cache or memoize results to reduce DB queries and improve performance.


135-151: Review pagination logic.

Setting defaults of page = 1 and per_page = 10 is good, but ensure consistency with the default values set in your searchParams destructuring (which is 5 for per_page). Align these defaults so the user experience is uniform.


152-229: Recommend retrieving only needed fields from vendor tasks.

You are selecting multiple columns from db.vendorTask. If performance becomes a concern, consider projecting only the columns needed by the UI to reduce data over-fetching.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/schema.ts (6)

3-4: Ensure consistent error message localization.

You use plain text error messages for zod validations. If your app is localized, consider retrieving these from a locale-based resource or using a translation function for consistent language coverage.


5-15: Expand comment validation if needed.

createVendorTaskCommentSchema requires a minimum length of 1 for content. If your application allows longer or multi-line content, you might want to set a stricter maximum limit, handle potential spam scenarios, or clarify the maximum length rules.


33-37: Consider additional fields in vendorContactSchema.

Vendor roles often require phone numbers or addresses. Ensure that only name, email, and role are required or if more fields are necessary for your use case.


39-48: Validate website domain thoroughly.

A simple URL check can still pass less conventional URLs (e.g., without a TLD). If your domain usage is strict, consider additional validations like restricting protocols or requiring certain domain names.


59-62: Add more descriptive error message for vendor comment.

createVendorCommentSchema only ensures content is non-empty. You might want a localized or more specific error message (e.g., "comment cannot be empty") for better user feedback.


64-68: Assess the potential usage of advanced risk levels.

Your updateVendorRiskSchema restricts risk to "low", "medium", "high", or "unknown". If you foresee more nuanced risk classification in the future, ensure your schema remains flexible or easily extendable.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5699021 and 5433686.

📒 Files selected for processing (56)
  • apps/app/src/actions/safe-action.ts (0 hunks)
  • apps/app/src/actions/schema.ts (3 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/page.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/components/charts/status-chart.tsx (3 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/components/charts/vendor-overview.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/components/charts/vendors-by-category.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/page.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/create-vendor-comment.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/schema.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/create-task-action.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/create-task-comment.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/revalidate-upload.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/update-task-action.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/update-vendor-action.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/create-vendor-comment-form.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comment-sheet.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comments.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/page.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/secondary-fields/secondary-fields.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/secondary-fields/update-secondary-fields-form.tsx (5 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/create-vendor-task-form.tsx (4 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/create-vendor-task-sheet.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/client-columns.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/data-table.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/empty-states.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/title-and-description.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/update-title-and-description-form.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/update-title-and-description-sheet.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/page.tsx (5 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/data-table.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-attachments.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-comments.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-overview.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/update-task-form.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/update-task-overview-form.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/page.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/actions/create-vendor-action.ts (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/create-vendor-form.tsx (4 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/create-vendor-sheet.tsx (3 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/inherent-risk-form.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/residual-risk-form.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/task/update-task-form.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/update-risk-form.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/register/components/VendorRegisterColumns.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/register/components/VendorRegisterTable.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/register/page.tsx (1 hunks)
  • apps/app/src/components/forms/risks/task/create-task-form.tsx (1 hunks)
  • apps/app/src/components/frameworks/loading.tsx (0 hunks)
  • apps/app/src/components/tables/vendor-tasks/empty-states.tsx (0 hunks)
  • apps/app/src/components/vendors/charts/vendors-overview.tsx (0 hunks)
  • apps/app/src/components/vendors/vendor-overview.tsx (0 hunks)
  • apps/app/src/locales/features/vendors.ts (3 hunks)
  • apps/app/src/styles/globals.css (1 hunks)
  • packages/db/prisma/seed.js (6 hunks)
  • packages/ui/tailwind.config.ts (1 hunks)
💤 Files with no reviewable changes (9)
  • apps/app/src/components/frameworks/loading.tsx
  • apps/app/src/actions/safe-action.ts
  • apps/app/src/components/vendors/charts/vendors-overview.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/update-risk-form.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/residual-risk-form.tsx
  • apps/app/src/components/tables/vendor-tasks/empty-states.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/inherent-risk-form.tsx
  • apps/app/src/components/vendors/vendor-overview.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/task/update-task-form.tsx
🧰 Additional context used
🧬 Code Definitions (21)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/create-vendor-comment.ts (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/schema.ts (1)
  • createVendorCommentSchema (59-62)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/create-task-action.ts (2)
apps/app/src/actions/safe-action.ts (1)
  • authActionClient (40-123)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/schema.ts (1)
  • createVendorTaskSchema (17-31)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/create-vendor-task-form.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/create-task-action.ts (1)
  • createVendorTaskAction (10-50)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comments.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comment-sheet.tsx (1)
  • VendorCommentSheet (21-73)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-overview.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/update-task-form.tsx (1)
  • UpdateTaskForm (38-197)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/update-vendor-action.ts (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/schema.ts (1)
  • updateVendorSchema (50-57)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/update-title-and-description-sheet.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/update-title-and-description-form.tsx (1)
  • UpdateTitleAndDescriptionForm (26-124)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/revalidate-upload.ts (1)
apps/app/src/actions/schema.ts (1)
  • uploadTaskFileSchema (194-201)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/create-task-comment.ts (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/schema.ts (1)
  • createVendorTaskCommentSchema (5-15)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/secondary-fields/secondary-fields.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/secondary-fields/update-secondary-fields-form.tsx (1)
  • UpdateSecondaryFieldsForm (36-197)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/layout.tsx (1)
apps/app/src/locales/auth/auth.ts (1)
  • auth (1-19)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comment-sheet.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/create-vendor-comment-form.tsx (1)
  • CreateVendorCommentForm (29-105)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/create-vendor-form.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/actions/create-vendor-action.ts (1)
  • createVendorAction (20-50)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/create-vendor-sheet.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/create-vendor-form.tsx (1)
  • CreateVendorForm (52-315)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/create-vendor-task-sheet.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/create-vendor-task-form.tsx (1)
  • CreateVendorTaskForm (51-249)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/page.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comments.tsx (1)
  • VendorComments (14-83)
packages/db/prisma/seed.js (1)
packages/db/src/index.js (1)
  • client_1 (4-4)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/title-and-description.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/update-title-and-description-sheet.tsx (1)
  • UpdateTitleAndDescriptionSheet (21-73)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/update-task-action.ts (1)
apps/app/src/actions/schema.ts (1)
  • updateTaskSchema (160-173)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/data-table.tsx (2)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/client-columns.tsx (2)
  • VendorTaskType (8-18)
  • useGetColumnHeaders (20-88)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/columns.tsx (1)
  • VendorTaskType (10-20)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/page.tsx (6)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/title-and-description.tsx (1)
  • TitleAndDescription (12-42)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/secondary-fields/secondary-fields.tsx (1)
  • SecondaryFields (8-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/filter-toolbar.tsx (1)
  • FilterToolbar (22-137)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/data-table.tsx (1)
  • DataTable (27-111)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/client-columns.tsx (1)
  • VendorTaskType (8-18)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/columns.tsx (1)
  • VendorTaskType (10-20)
🪛 Biome (1.9.4)
packages/db/prisma/seed.js

[error] 293-293: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


[error] 294-294: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


[error] 300-300: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


[error] 300-300: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


[error] 357-357: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


[error] 427-427: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)

🔇 Additional comments (87)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/register/components/VendorRegisterColumns.tsx (1)

6-6: Update Import Path for VendorRegisterTableRow
The import for VendorRegisterTableRow has been modified from a parent directory reference to a current directory reference ("./VendorRegisterTable"). This update improves modular clarity and aligns with the new component reorganization. Please ensure that the file at VendorRegisterTable.tsx is correctly updated to reflect these changes.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/register/page.tsx (1)

7-7: Refactor Import Path for VendorRegisterTable
The updated import for VendorRegisterTable from ./components/VendorRegisterTable correctly reflects its new location in the directory structure. This change improves project organization.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/register/components/VendorRegisterTable.tsx (1)

10-11: Adjust Import Paths for Reorganized Components
The import for CreateVendorSheet has been updated to "../../components/create-vendor-sheet", and the import for columns now points to "./VendorRegisterColumns". Both changes are in line with the recent directory restructuring. Please double-check that these paths resolve correctly within the new organizational hierarchy.

packages/ui/tailwind.config.ts (1)

53-58: New chart colors added successfully.

These new color definitions enhance the chart styling options, following the existing pattern in the configuration file. They're aligned with the shift from risk management to vendor management.

apps/app/src/actions/schema.ts (1)

124-124: Added blank lines improve code readability.

The added blank lines enhance the separation between different schema definitions, making the file more readable.

Also applies to: 159-159, 192-193

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/page.tsx (1)

1-7:

Details

❓ Verification inconclusive

This component needs implementation.

The TaskPage component appears to be a placeholder with minimal content. Consider implementing the actual task details display or form functionality.


🏁 Script executed:

#!/bin/bash
# Description: Check if there are any implementations of task detail pages in similar vendor paths

echo "Searching for similar task page implementations..."
rg -i "function TaskPage|export default function" --type tsx apps/app/src/app/\[locale\]/\(app\)/\(dashboard\)/\[orgId\]/vendors/

Length of output: 264


#!/bin/bash
# Re-running search for similar task page implementations using a custom file type for TSX files

echo "Searching for similar task page implementations using updated TSX file detection..."
rg -i --type-add 'tsx:*.tsx' --type tsx 'function TaskPage|export default function' apps/app/src/app/\[locale\]/\(app\)/\(dashboard\)/\[orgId\]/vendors/
apps/app/src/components/forms/risks/task/create-task-form.tsx (1)

36-36: Consolidated import improves readability.

Good refactoring to group related icon imports from the lucide-react library into a single line.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/data-table.tsx (1)

18-18: Import path updated for VendorTaskType

The import path has been updated to point to a more centralized location. This change is consistent with the refactoring mentioned in the PR to shift emphasis from risk management to vendor management.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/components/charts/vendors-by-category.tsx (2)

9-15: Good visual enhancement with consistent chart colors

Adding chart color constants improves visual consistency and uses the CSS variables defined in globals.css. This aligns well with the enhanced Tailwind configuration mentioned in the PR.


26-43: Improved category formatting and color assignment

The changes enhance both the visual presentation and readability:

  1. Adding index parameter enables color assignment
  2. Proper title casing for category names
  3. Special handling for the "Other" category
  4. Color assignment based on index ensures visual consistency

This is a good improvement to the chart's presentation.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/page.tsx (2)

8-8: Added import for VendorComments component

The VendorComments component import is correctly added, which aligns with the PR's focus on enhancing vendor management features.


51-51: Uncommented VendorComments component usage

The VendorComments component is now being used with the correct props (vendor and users). This enables the display of vendor comments which enhances the vendor management functionality.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/update-task-overview-form.tsx (1)

36-36: Updated translation keys for toast messages

The translation keys have been updated from risk.tasks.form.* to risk.form.* patterns. This change is consistent with the PR's focus on refactoring from risk management to vendor management.

Also applies to: 40-40

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/revalidate-upload.ts (1)

18-19:

Details

❓ Verification inconclusive

Verify variable naming alignment with schema

The schema uses riskId but this appears to be in a vendor-related context. Consider whether this should be vendorId instead to maintain consistency with the shift from risk to vendor management.


🏁 Script executed:

#!/bin/bash
# Check usage of vendorId vs riskId in related schemas and actions

echo "Checking for vendorId usage in schema files:"
rg "vendorId" --type ts -A 5 -B 5 "schema.ts"

echo "Checking for riskId usage in schema files:"
rg "riskId" --type ts -A 5 -B 5 "schema.ts"

echo "Checking for usage of revalidateUpload action:"
rg -A 2 -B 2 "revalidateUpload" --type ts

Length of output: 1592


Vendor-Context Variable Name Inconsistency

The vendor-specific revalidation action currently extracts a variable named riskId from the input:

const { riskId, taskId } = parsedInput;

Given that this file lives under a vendor path (i.e. it’s in a directory with [vendorId]), please verify whether the schema (specifically for uploadTaskFileSchema) and the overall vendor workflow expect a vendorId instead. If the schema and callers are meant to operate with vendor-related identifiers, update the destructuring and related usage accordingly.

  • Check if the schema definition (or related validators) for this action should use vendorId rather than riskId.
  • If confirmed, modify line 18 to extract vendorId and adjust downstream usage.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/components/charts/vendor-overview.tsx (1)

1-38: LGTM! Well-structured vendor overview component

The component is well-organized with a clean structure that appropriately uses server-side rendering. The responsive layout will adapt well to different screen sizes, and the component correctly passes the organizationId to its child components.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/create-task-action.ts (1)

10-50: LGTM! Well-implemented server action

The server action follows best practices with proper schema validation, authentication checks, and error handling. The revalidation paths and tags are correctly referenced for the vendor context.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/secondary-fields/secondary-fields.tsx (1)

8-14: LGTM! Clean component structure

The component has a clean structure with appropriate props typing. The integration with the UpdateSecondaryFieldsForm component follows good practices for component composition.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-attachments.tsx (1)

49-49:

Details

❓ Verification inconclusive

Update upload type for vendor context

The code is using UPLOAD_TYPE.riskTask which is specific to risk tasks. For vendor tasks, there should be a corresponding vendor task upload type.

-          uploadType={UPLOAD_TYPE.riskTask}
+          uploadType={UPLOAD_TYPE.vendorTask}

🏁 Script executed:

#!/bin/bash
# Check the UPLOAD_TYPE enum to see if vendorTask is defined
rg -A 10 "export enum UPLOAD_TYPE" --type ts

Length of output: 46


Action Required: Verify Vendor Upload Type

The current code updates the upload type from riskTask to vendorTask for vendor tasks. However, our initial search did not decisively confirm that UPLOAD_TYPE.vendorTask is defined. Please run the above script to manually verify that:

  • The UPLOAD_TYPE enum (which may be declared in either a .ts or .tsx file) includes a vendorTask value.
  • The use of UPLOAD_TYPE.vendorTask is appropriate for vendor tasks.

If the verification confirms that vendorTask exists, then the change is correct:

-          uploadType={UPLOAD_TYPE.riskTask}
+          uploadType={UPLOAD_TYPE.vendorTask}

🏁 Script executed:

#!/bin/bash
# Re-verify the UPLOAD_TYPE enum in both TS and TSX files,
# and search for the vendorTask occurrence.
echo "Searching for UPLOAD_TYPE enum definition (including potential vendorTask values):"
rg -A 10 "export enum UPLOAD_TYPE" --type ts --type tsx

echo "-----"
echo "Searching for 'vendorTask' occurrences:"
rg -n "vendorTask" --type ts --type tsx

Length of output: 564


Verify Vendor Upload Type Presence

The code change updates the upload type from riskTask to vendorTask for vendor tasks. However, our initial search did not conclusively show that the UPLOAD_TYPE enum includes a vendorTask value, likely due to the file type filtering used in the previous command. Please run the above script to manually verify that:

  • The UPLOAD_TYPE enum (in TypeScript files) contains a vendorTask value.
  • The use of UPLOAD_TYPE.vendorTask is appropriate for vendor tasks.

If the verification confirms that vendorTask exists, the diff is valid:

-          uploadType={UPLOAD_TYPE.riskTask}
+          uploadType={UPLOAD_TYPE.vendorTask}

🏁 Script executed:

#!/bin/bash
# Re-run the search for the UPLOAD_TYPE enum definition and the vendorTask key using glob patterns
echo "Searching for UPLOAD_TYPE enum definition in TypeScript files:"
rg -A 10 "export enum UPLOAD_TYPE" -g "*.ts" -g "*.tsx"

echo "-----"
echo "Searching for 'vendorTask' occurrences in TypeScript files:"
rg -n "vendorTask" -g "*.ts" -g "*.tsx"

Length of output: 1649


Vendor Upload Type Verification Needed

The code currently uses a risk-specific upload type:

-          uploadType={UPLOAD_TYPE.riskTask}
+          uploadType={UPLOAD_TYPE.vendorTask}

However, our automated searches only confirm that the term “vendorTask” is used in the vendor-related actions and pages but did not conclusively locate the declaration of the UPLOAD_TYPE enum with a vendorTask member.

• Action: Please manually verify that the UPLOAD_TYPE enum—in the appropriate TypeScript file—includes a vendorTask entry.
• Note: If the vendorTask value is not present, please update the enum definition accordingly.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/layout.tsx (2)

42-44: Review back button destination

The backButtonHref is set to the vendor registration page (/${orgId}/vendors/register), which might be confusing for users who expect to go back to a vendor list. Consider changing to the vendors list page.

      <SecondaryMenu
        showBackButton
-        backButtonHref={`/${orgId}/vendors/register`}
+        backButtonHref={`/${orgId}/vendors`}

Is the intended user flow to go back to the registration page? This seems unusual as a back button typically takes users to a list view rather than a registration form.


39-57: LGTM! Nice layout structure improvements.

The layout has been well-structured with proper spacing, back button functionality, and clear navigation items including the vendor name and comments section. The use of the space-y-4 class improves the vertical spacing between elements.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/actions/create-vendor-action.ts (2)

6-6: Good addition of the Vendor type import.

Adding the Vendor type import improves type safety and explicitly shows what data structure is being returned.


22-22: Improved type safety with generic ActionResponse.

Updating the return type to Promise<ActionResponse<Vendor>> makes the API contract more explicit and provides better type safety, ensuring consumers of this function know they'll receive a Vendor object in the response data.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/page.tsx (2)

57-59: Good implementation of the VendorOverview component.

The code now properly renders the VendorOverview component, passing the organizationId from the session. This aligns with the shift from risk management to vendor management mentioned in the PR summary.


2-4:

Details

❓ Verification inconclusive

Verify unused imports.

You've imported RiskOverview and other components, but I don't see RiskOverview being used in this file. Consider removing unused imports to keep the codebase clean.


🏁 Script executed:

#!/bin/bash
# Check if RiskOverview is used elsewhere in the file
rg "RiskOverview" "apps/app/src/app/\[locale\]/(app)/(dashboard)/\[orgId\]/vendors/(overview)/page.tsx"

Length of output: 227


Review Comment Verification – Please Manually Confirm the File and Usage

The automated check using the original rg command couldn’t locate the file at apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/page.tsx. This might be due to the literal bracket and parenthesis characters in the path. In any case, the intention remains to ensure that unused imports (like RiskOverview) are not present if the component isn’t used.

To gather further information, please run the following script to search for any page.tsx files under the vendors directory:

#!/bin/bash
# Locate all page.tsx files within directories likely to match the vendors overview route.
find . -type f -name "page.tsx" | grep -i "vendors"

If you locate the intended file, please verify whether the RiskOverview import appears in it. If you confirm that RiskOverview isn’t used, then the import should be removed to keep the codebase clean.

• Action Items:

  • File Check: Manually verify that the file exists at the expected path or locate its actual path if different.
  • Usage Check: Confirm that RiskOverview is not used within that file.
  • Cleanup: Remove any unused imports accordingly.
apps/app/src/styles/globals.css (1)

253-265: Well-structured and documented CSS variables for chart states.

The addition of these CSS variables with clear documentation improves maintainability and consistency across the application. The comments for each variable clearly explain their intended use cases.

Some observations:

  • Good use of HSL color format for most variables
  • Clear naming convention with the --chart- prefix
  • Helpful comments that explain each variable's purpose

This change will make it easier to maintain a consistent visual language for different chart states throughout the application.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-overview.tsx (1)

1-61: Good implementation of the TaskOverview component!

The component provides a clean user interface for viewing and managing task details, with proper internationalization support and well-structured layout.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/create-vendor-sheet.tsx (3)

11-11: Appropriate component name change

Changing the import from CreateVendor to CreateVendorForm improves naming consistency by clearly indicating this is a form component.


40-40: Updated component reference correctly

The component usage has been properly updated to match the renamed import.


51-51: Updated component reference correctly

The component usage has been properly updated to match the renamed import in the mobile view as well.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/create-vendor-comment-form.tsx (6)

26-27: Correctly updated imports for vendor-related functionality

The imports have been appropriately updated to use vendor-specific actions and schemas, supporting the shift from risk management to vendor management.


29-33: Properly renamed component and updated related variables

The component has been renamed from CreateRiskCommentForm to CreateVendorCommentForm, and the related variables have been updated to reflect the vendor context.


34-42: Updated action hook for vendor comments

The action hook has been correctly updated to use the vendor-specific action with appropriate success and error handling.


44-50: Updated form schema and default values

The form configuration has been updated to use the vendor-specific schema and vendor ID.


52-54: Updated form submission logic

The form submission has been correctly updated to use the vendor-specific action.


91-95: Updated disabled state for button

The button's disabled state now correctly reflects the vendor comment action status.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comments.tsx (2)

14-23: Good component structure and state management

The component is well-structured with appropriate props typing and state management using useQueryState for the comment sheet.


70-77: Well-handled empty state

Good use of the EmptyCard component to display a meaningful message when there are no comments.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/create-vendor-task-sheet.tsx (4)

1-11: Good use of imports and client directive.

The imports are well-organized and the "use client" directive is correctly placed at the top of the file since this is a client component that uses hooks.


13-23: Well-structured component with proper state management.

The component correctly uses:

  • Internationalization with useI18n
  • Media query detection for responsive design
  • URL-based state management with useQueryState
  • Proper function to handle state changes

This approach makes the component state bookmarkable and shareable via URL.


24-46: Good responsive implementation for desktop view.

The component correctly:

  • Conditionally renders a Sheet for desktop screens
  • Includes proper header with title and close button
  • Wraps the form in a ScrollArea for better UX
  • Uses stack property for proper z-index handling

The implementation follows accessibility best practices with proper labeling.


48-55: Well-implemented mobile fallback.

The component appropriately renders a Drawer component for mobile screens with correctly configured properties. The hidden attribute on DrawerTitle maintains accessibility while controlling visibility.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/components/create-vendor-form.tsx (4)

35-35: LGTM: Added Next.js router import.

The added import is necessary for the new navigation functionality implemented below.


52-52: LGTM: Renamed component to better reflect its purpose.

The rename from CreateVendor to CreateVendorForm makes the component's role clearer and follows naming conventions.


79-80: LGTM: Initialized router for programmatic navigation.

The router initialization is correctly placed outside any conditional blocks.


84-95: Improved UX with automatic navigation after vendor creation.

The implementation now redirects users to the newly created vendor page after successful creation instead of just closing the form. This provides better feedback and workflow continuity.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/update-task-action.ts (3)

1-10: LGTM: Good imports and server declaration.

The server action is correctly marked with "use server" and includes appropriate imports for database access and revalidation.


11-20: Well-structured action with schema validation and metadata.

The update task action is properly configured with:

  • Schema validation using authActionClient
  • Appropriate metadata for tracking and analytics

42-54: LGTM: Proper database update with all required fields.

The update operation correctly includes all necessary fields and proper filtering to ensure organizational data boundaries.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/client-columns.tsx (2)

1-1: LGTM: Changed to client-side internationalization.

Correctly switched from server-side getI18n to client-side useI18n for this client component.


20-22: Improved function name and made it synchronous.

Changed from an async server function to a synchronous hook, which:

  1. Better represents its usage pattern
  2. Eliminates unnecessary Promise handling
  3. Makes it easier to use in React components

The new name useGetColumnHeaders clearly indicates it's a hook.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/title-and-description.tsx (1)

12-42: The component looks well-structured and functional.

The TitleAndDescription component effectively displays vendor information with a clean interface and includes an edit button that integrates with the UpdateTitleAndDescriptionSheet component.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/empty-states.tsx (1)

15-46: Well implemented NoResults component

The NoResults component is well-structured and provides appropriate user feedback and actions based on the context.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/create-vendor-task-form.tsx (1)

51-94: Function refactored correctly for vendor tasks

The component has been correctly refactored from general tasks to vendor-specific tasks with appropriate changes to the action, schema, and prop handling.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/update-title-and-description-sheet.tsx (1)

21-63: Well-implemented responsive component

The desktop implementation of the sheet is well-structured with appropriate headers, description, and responsive behavior.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/comments/components/vendor-comment-sheet.tsx (1)

21-73: LGTM: Well-implemented responsive layout pattern.

This component effectively implements a responsive design pattern by:

  1. Using useMediaQuery to detect device size
  2. Conditionally rendering either a Sheet (desktop) or Drawer (mobile) component
  3. Maintaining state via URL query parameters with useQueryState
  4. Providing appropriate UI elements for each viewport size

This is a clean implementation that follows good React patterns.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/page.tsx (1)

108-126: Looks solid for risk retrieval
The function correctly checks for a valid session and organization ID before querying the database, returning null if no valid session is found. The logic is straightforward and effectively returns the matching risk or null if not found.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/update-task-form.tsx (1)

1-198: Confirm intent behind auto-submission on user selection
The form triggers submission (onOpenChange={() => form.handleSubmit(onSubmit)}) whenever the assignee dropdown is opened or closed. Verify that this automatic submission is intentional. If not, consider removing or binding it strictly to field changes rather than opening/closing, to avoid partial or unintended updates.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/secondary-fields/update-secondary-fields-form.tsx (1)

4-198: Vendor fields update logic looks good
This refactor cleanly adapts the component from risk to vendor management, leveraging the updateVendorAction and updateVendorSchema. The field mappings and default values appear to align well with vendor data.

packages/db/prisma/seed.js (14)

34-36: New console logs for evidence records (phase 1).

No issues found; logging adds clarity to the seeding phases.


43-45: New console logs for policy links (phase 1).

No issues found; logging is consistent with the phased approach.


46-48: New console logs for evidence links (phase 2).

No issues found; consistent logging for the final phase of seeding.


94-94: Added department fallback for policy updates.

Using client_1.Departments.none provides a safe default when policyData.metadata?.department is unavailable. Looks good.


104-104: Added department fallback for policy creation.

Again, using client_1.Departments.none is consistent with the fallback strategy.


186-186: Upsert logic for controls in seedFrameworkCategoryControls.

The upsert block is correctly structured, ensuring we either create or update the control. Implementation is sound.


208-209: Explanatory comment for policy/evidence requirements initialization.

Appreciate the clarity. This ensures we understand that policyId and evidenceId will be linked later.


216-228: Initial null assignments for policyId and evidenceId, plus fallback for name and description.

Your approach of defaulting to empty strings is reasonable. It avoids null insertions for textual fields while the references are updated later.


290-299: Introduction of seedEvidenceRecords (lines 290–299).

The fundamental structure for reading evidence files and logging progress is clear and maintainable. The try/catch approach is suitable for error handling.

🧰 Tools
🪛 Biome (1.9.4)

[error] 293-293: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


[error] 294-294: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


300-319: Upsert logic for evidence records (lines 300–319).

Storing evidence data with controlled fallback values (department → Departments.none, frequency → null) is consistent with other parts of the seeding routine.

🧰 Tools
🪛 Biome (1.9.4)

[error] 300-300: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


[error] 300-300: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


320-329: Completion of seedEvidenceRecords function (lines 320–329).

Graceful handling of errors and final logging is appropriate. Good job wrapping potential issues in the catch block.


330-356: updateEvidenceLinks function scaffolding (lines 330–356).

The function name and logs align with the concept of a second phase for linking. No immediate concerns with the structure so far.


400-426: updatePolicyLinks function scaffolding (lines 400–426).

Similar phased approach, focusing on policy linking. The naming and logs make it clear where policy references are updated.


293-294: False positives from static analysis about the comma operator.

These lines appear to be artifacts of Babel/TypeScript compilation (e.g., (0, node_path_1.join)). They’re safe to ignore as long as no actual comma operator logic is present.

Also applies to: 300-300, 357-357, 427-427

🧰 Tools
🪛 Biome (1.9.4)

[error] 293-293: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)


[error] 294-294: The comma operator is disallowed.

Its use is often confusing and obscures side effects.

(lint/style/noCommaOperator)

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/components/charts/status-chart.tsx (4)

7-10: Updated STATUS_COLORS keys.

Renaming underscores to a more consistent style is fine. The new classes (bg-chart-destructive, etc.) appear aligned with the revised naming convention.


26-29: Splitting status names by underscores and capitalizing words.

This improves readability for display. The logic is straightforward and well-suited to typical status keys.

Also applies to: 32-36


39-41: Ensuring all status names are included.

Pushing placeholder entries with value: 0 helps present a uniform chart. No issues here.


99-99: Normalized naming in getStatusColor.

Replacing spaces with underscores helps map the display name back to the color key. This ensures consistent color resolution.

apps/app/src/locales/features/vendors.ts (5)

3-3: New key overview.

Adding “Overview” aligns with the top-level terminology used elsewhere. No concerns here.


19-19: vendor_name_description additions.

Helpful guidance for users filling out the vendor name. Looks good.


24-24: vendor_description_description additions.

Consistent approach to providing clear placeholder assistance. Well done.


31-34: New strings to support vendor update flow.

The additional keys (update_vendor, update_vendor_description, etc.) properly expand localization for update actions. Nicely integrated.


59-61: New sheet object under tasks, adding a "Create Vendor Task" title.

This is consistent with the established pattern under tasks. Localization keys appear coherent and purposeful.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/page.tsx (3)

5-12: Check for unused imports.

You've introduced multiple imports for the tasks data table, empty states, filter toolbar, and getServerColumnHeaders, yet getServerColumnHeaders appears never to be called. Confirm whether you intend to call it or if you can remove it to streamline the code.


67-68: Confirm the order of TitleAndDescription and SecondaryFields.

Ensure that the design or user flow requires showing the title first and then secondary fields. If needed, you can swap or reorganize these components for better layout.


80-87: Verify integration of FilterToolbar and DataTable.

The FilterToolbar and DataTable are now rendered within the same fragment. Confirm that the filtering logic updates the table accordingly (e.g., ensuring sets of search params re-fetch or re-render the table).

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/schema.ts (3)

1-2: Check for version alignment in vendor status definitions.

You import VendorStatus and VendorCategory from @bubba/db/types. Validate that your newly added fields and statuses reflect the updated definitions in that package, preventing mismatches or missing statuses.


17-31: Double-check date validation logic.

dueDate is validated with z.date(). If users are expected to submit date strings, confirm that the environment properly transforms them into Date objects beforehand. Otherwise, you might need to parse the string in your action if it’s currently failing client-side.


50-57: Enable partial updates for vendor status if appropriate.

updateVendorSchema demands status. If a user only wants to update the vendor’s category, they might be forced to provide a status every time. Reevaluate whether a partial or optional field might be more flexible for subsequent updates.

Comment on lines +25 to +27
revalidatePath(`/${user.organizationId}/risk/${riskId}`);
revalidatePath(`/${user.organizationId}/risk/${riskId}/tasks/${taskId}`);
revalidateTag("risk-cache");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Path references need to be updated to use vendor paths instead of risk paths

The revalidation paths and tags are still referencing "risk" even though this file is in a vendor-related directory. Based on the PR summary about shifting from risk management to vendor management, these should likely be updated to reference vendors instead.

Apply this diff to update the revalidation paths and tags:

-    revalidatePath(`/${user.organizationId}/risk/${riskId}`);
-    revalidatePath(`/${user.organizationId}/risk/${riskId}/tasks/${taskId}`);
-    revalidateTag("risk-cache");
+    revalidatePath(`/${user.organizationId}/vendors/${vendorId}`);
+    revalidatePath(`/${user.organizationId}/vendors/${vendorId}/tasks/${taskId}`);
+    revalidateTag("vendor-cache");
📝 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
revalidatePath(`/${user.organizationId}/risk/${riskId}`);
revalidatePath(`/${user.organizationId}/risk/${riskId}/tasks/${taskId}`);
revalidateTag("risk-cache");
revalidatePath(`/${user.organizationId}/vendors/${vendorId}`);
revalidatePath(`/${user.organizationId}/vendors/${vendorId}/tasks/${taskId}`);
revalidateTag("vendor-cache");

<CardHeader>
<CardTitle>
<div className="flex items-center justify-between gap-2">
{t("risk.dashboard.overview")}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update i18n key to reference vendors instead of risk

The component uses the key "risk.dashboard.overview" for the title text, but this is in a vendor-related context. This should be updated to use a vendor-related i18n key to maintain consistency with the shift from risk to vendor management.

Apply this diff to update the i18n key:

-              {t("risk.dashboard.overview")}
+              {t("vendors.dashboard.overview")}
📝 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
{t("risk.dashboard.overview")}
{t("vendors.dashboard.overview")}

"use client";

import { UPLOAD_TYPE } from "@/actions/types";
import { useTaskAttachments } from "@/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/tasks/[taskId]/data/useTaskAttachment";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Inconsistent path structure detected

The import path is still referencing the risk-related path structure (risk/[riskId]/tasks) while this component is being used in the vendors context. This indicates the hook hasn't been properly updated for vendor tasks.

-import { useTaskAttachments } from "@/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/tasks/[taskId]/data/useTaskAttachment";
+import { useTaskAttachments } from "@/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/data/useTaskAttachment";
📝 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
import { useTaskAttachments } from "@/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/tasks/[taskId]/data/useTaskAttachment";
import { useTaskAttachments } from "@/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/data/useTaskAttachment";

<CardHeader>
<CardTitle>
<div className="flex items-center justify-between gap-2">
{t("risk.tasks.attachments")}

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

Update localization namespace

The text reference still uses the "risk" namespace rather than "vendor", which is inconsistent with the current vendor context.

-            {t("risk.tasks.attachments")}
+            {t("vendor.tasks.attachments")}
📝 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
{t("risk.tasks.attachments")}
{t("vendor.tasks.attachments")}

Comment on lines +37 to +38
revalidatePath(`/${user.organizationId}/vendor/${vendorId}`);
revalidatePath(`/${user.organizationId}/vendor/${vendorId}/tasks/${vendorTaskId}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix inconsistent path structure in revalidation

There are path inconsistencies in the revalidation paths. Line 37 uses vendor while line 38 uses vendor/. Also, according to the layout.tsx file, the correct path should use the plural form vendors.

-    revalidatePath(`/${user.organizationId}/vendor/${vendorId}`);
-    revalidatePath(`/${user.organizationId}/vendor/${vendorId}/tasks/${vendorTaskId}`);
+    revalidatePath(`/${user.organizationId}/vendors/${vendorId}`);
+    revalidatePath(`/${user.organizationId}/vendors/${vendorId}/tasks/${vendorTaskId}`);
📝 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
revalidatePath(`/${user.organizationId}/vendor/${vendorId}`);
revalidatePath(`/${user.organizationId}/vendor/${vendorId}/tasks/${vendorTaskId}`);
revalidatePath(`/${user.organizationId}/vendors/${vendorId}`);
revalidatePath(`/${user.organizationId}/vendors/${vendorId}/tasks/${vendorTaskId}`);

Comment on lines +23 to +42
if (!user.id || !user.organizationId) {
throw new Error("Invalid user input");
}

await db.vendorTaskComment.create({
data: {
vendorId,
taskId: vendorTaskId,
content,
ownerId: user.id,
organizationId: user.organizationId,
},
});

revalidatePath(`/${user.organizationId}/vendor/${vendorId}`);
revalidatePath(`/${user.organizationId}/vendor/${vendorId}/tasks/${vendorTaskId}`);
revalidateTag(`vendor_${user.organizationId}`);

return { success: true };
});

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

Add error handling

Unlike the create-vendor-comment.ts file, this action doesn't include a try/catch block to handle potential database errors. For consistency and robustness, add error handling.

    if (!user.id || !user.organizationId) {
      throw new Error("Invalid user input");
    }

+    try {
      await db.vendorTaskComment.create({
        data: {
          vendorId,
          taskId: vendorTaskId,
          content,
          ownerId: user.id,
          organizationId: user.organizationId,
        },
      });

      revalidatePath(`/${user.organizationId}/vendors/${vendorId}`);
      revalidatePath(`/${user.organizationId}/vendors/${vendorId}/tasks/${vendorTaskId}`);
      revalidateTag(`vendor_${user.organizationId}`);

      return { success: true };
+    } catch (error) {
+      console.error("Error creating task comment:", error);
+      return { success: false };
+    }
📝 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
if (!user.id || !user.organizationId) {
throw new Error("Invalid user input");
}
await db.vendorTaskComment.create({
data: {
vendorId,
taskId: vendorTaskId,
content,
ownerId: user.id,
organizationId: user.organizationId,
},
});
revalidatePath(`/${user.organizationId}/vendor/${vendorId}`);
revalidatePath(`/${user.organizationId}/vendor/${vendorId}/tasks/${vendorTaskId}`);
revalidateTag(`vendor_${user.organizationId}`);
return { success: true };
});
if (!user.id || !user.organizationId) {
throw new Error("Invalid user input");
}
try {
await db.vendorTaskComment.create({
data: {
vendorId,
taskId: vendorTaskId,
content,
ownerId: user.id,
organizationId: user.organizationId,
},
});
revalidatePath(`/${user.organizationId}/vendors/${vendorId}`);
revalidatePath(`/${user.organizationId}/vendors/${vendorId}/tasks/${vendorTaskId}`);
revalidateTag(`vendor_${user.organizationId}`);
return { success: true };
} catch (error) {
console.error("Error creating task comment:", error);
return { success: false };
}

Comment on lines +56 to +62
revalidatePath(`/${user.organizationId}/risk`);
revalidatePath(`/${user.organizationId}/risk/${riskId.riskId}`);
revalidatePath(
`/${user.organizationId}/risk/${riskId.riskId}/tasks/${id}`
);
revalidateTag("risks");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Paths reference "risk" instead of "vendors".

The revalidation paths appear to be using a risk-related path structure while this file is in a vendors directory structure.

Consider updating the revalidation paths to match the vendors structure:

- revalidatePath(`/${user.organizationId}/risk`);
- revalidatePath(`/${user.organizationId}/risk/${riskId.riskId}`);
- revalidatePath(
-   `/${user.organizationId}/risk/${riskId.riskId}/tasks/${id}`
- );
+ revalidatePath(`/${user.organizationId}/vendors`);
+ revalidatePath(`/${user.organizationId}/vendors/${parsedInput.vendorId}`);
+ revalidatePath(
+   `/${user.organizationId}/vendors/${parsedInput.vendorId}/tasks/${id}`
+ );

Additionally, you'll need to add the vendorId to the schema and retrieve it from the database if not provided in the input.

📝 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
revalidatePath(`/${user.organizationId}/risk`);
revalidatePath(`/${user.organizationId}/risk/${riskId.riskId}`);
revalidatePath(
`/${user.organizationId}/risk/${riskId.riskId}/tasks/${id}`
);
revalidateTag("risks");
revalidatePath(`/${user.organizationId}/vendors`);
revalidatePath(`/${user.organizationId}/vendors/${parsedInput.vendorId}`);
revalidatePath(
`/${user.organizationId}/vendors/${parsedInput.vendorId}/tasks/${id}`
);
revalidateTag("risks");

const createTask = useAction(createTaskAction, {
const createTask = useAction(createVendorTaskAction, {
onSuccess: () => {
toast.success(t("risk.tasks.form.success"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Translation keys still reference 'risk' instead of 'vendor'

Multiple translation keys throughout the component still reference "risk" instead of "vendor", which is inconsistent with the vendor management focus of this component.

-      toast.success(t("risk.tasks.form.success"));
+      toast.success(t("vendors.tasks.form.success"));

-      toast.error(t("risk.tasks.form.error"));
+      toast.error(t("vendors.tasks.form.error"));

-                  {t("risk.tasks.form.title")}
+                  {t("vendors.tasks.form.title")}

-                            {t("risk.tasks.form.task_title")}
+                            {t("vendors.tasks.form.task_title")}

-                            {t("risk.tasks.form.description")}
+                            {t("vendors.tasks.form.description")}

Also applies to: 77-77, 104-104, 114-114, 138-138

Comment on lines +49 to +56
<AssignedUser
fullName={
users.find((user) => user.id === comment.ownerId)?.name
}
avatarUrl={
users.find((user) => user.id === comment.ownerId)?.image
}
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Add fallback for missing users.

The component doesn't handle the case when a user corresponding to a comment's ownerId is not found. This could lead to undefined values being passed to the AssignedUser component.


🏁 Script executed:

#!/bin/bash
# Check if the AssignedUser component handles undefined props gracefully

# Look for fallback handling in the AssignedUser component
rg -A 10 "export function AssignedUser" 

Length of output: 863


Missing Fallback for Undefined Comment Owner

The current implementation in apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/task-comments.tsx passes potentially undefined values to the AssignedUser component when no matching user is found. Although the AssignedUser component uses a nullish check for the fullName in the alt attribute (i.e., alt={fullName ?? ""}) and conditionally renders the avatar based on avatarUrl, it does not address the overall case of a missing user. This can result in an unexpected UI state or missing information.

To address this, please consider:

  • Extracting the user lookup into a variable: This avoids duplicate calls to users.find(...) and makes the code more maintainable.
  • Providing a default fallback for fullName (and optionally for avatarUrl): For example, display "Unknown User" when no user is found.

Refactored snippet suggestion:

const commentUser = users.find(user => user.id === comment.ownerId);

<AssignedUser
  fullName={commentUser ? commentUser.name : "Unknown User"}
  avatarUrl={commentUser ? commentUser.image : undefined}
/>

This change will ensure that AssignedUser always receives defined props, thereby improving the robustness of the user interface.

Comment on lines +51 to +58
const { tasks: loadedTasks, total } = await getTasks({
vendorId,
search,
status: status as VendorTaskStatus,
column,
order,
page: Number.parseInt(page),
per_page: Number.parseInt(per_page),

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

Provide fallback for invalid page/per_page inputs.

When parsing page/per_page, consider validating them or defaulting to known safe values to avoid runtime errors. For instance, you can handle negative or non-numeric inputs gracefully.

- page: Number.parseInt(page),
- per_page: Number.parseInt(per_page),
+ page: Number.isNaN(Number.parseInt(page)) || Number.parseInt(page) < 1
+   ? 1
+   : Number.parseInt(page),
+ per_page: Number.isNaN(Number.parseInt(per_page)) || Number.parseInt(per_page) < 1
+   ? 5
+   : Number.parseInt(per_page),
📝 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
const { tasks: loadedTasks, total } = await getTasks({
vendorId,
search,
status: status as VendorTaskStatus,
column,
order,
page: Number.parseInt(page),
per_page: Number.parseInt(per_page),
const { tasks: loadedTasks, total } = await getTasks({
vendorId,
search,
status: status as VendorTaskStatus,
column,
order,
page: Number.isNaN(Number.parseInt(page)) || Number.parseInt(page) < 1
? 1
: Number.parseInt(page),
per_page: Number.isNaN(Number.parseInt(per_page)) || Number.parseInt(per_page) < 1
? 5
: Number.parseInt(per_page),

@vercel
vercel Bot temporarily deployed to Preview – comp-portal March 25, 2025 00:16 Inactive
@vercel
vercel Bot temporarily deployed to Preview – comp-portal March 25, 2025 00:17 Inactive
@vercel
vercel Bot temporarily deployed to Preview – comp-portal March 25, 2025 00:17 Inactive
@claudfuen claudfuen changed the title Claudio/misc fixes 2 Vendor Page - Partial Implementation Mar 25, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/page.tsx (1)

134-228: Well-structured task fetching with proper pagination and filtering.

The getTasks function effectively handles filtering, sorting, and pagination. The parallel fetching of tasks and count is efficient. The transformation of the database results to match the expected VendorTaskType interface is well done.

Consider consolidating the duplicate WHERE conditions in the tasks query and count query to improve maintainability:

+ const baseWhereCondition = {
+   vendorId,
+   AND: [
+     search
+       ? {
+           OR: [
+             { title: { contains: search, mode: "insensitive" } },
+             { description: { contains: search, mode: "insensitive" } },
+           ],
+         }
+       : {},
+     status ? { status } : {},
+   ],
+ };

  const [tasks, total] = await Promise.all([
    db.vendorTask
      .findMany({
-       where: {
-         vendorId,
-         AND: [
-           search
-             ? {
-                 OR: [
-                   { title: { contains: search, mode: "insensitive" } },
-                   {
-                     description: { contains: search, mode: "insensitive" },
-                   },
-                 ],
-               }
-             : {},
-           status ? { status } : {},
-         ],
-       },
+       where: baseWhereCondition,
        // ... rest of the query
      }),
    db.vendorTask.count({
-     where: {
-       vendorId,
-       AND: [
-         search
-           ? {
-               OR: [
-                 { title: { contains: search, mode: "insensitive" } },
-                 { description: { contains: search, mode: "insensitive" } },
-               ],
-             }
-           : {},
-         status ? { status } : {},
-       ],
-     },
+     where: baseWhereCondition,
    }),
  ]);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5433686 and 70ba719.

📒 Files selected for processing (3)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/update-task-action.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/page.tsx (5 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/update-task-form.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/task/update-task-action.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/tasks/[taskId]/components/update-task-form.tsx
🧰 Additional context used
🧬 Code Definitions (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/page.tsx (6)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/title-and-description/title-and-description.tsx (1)
  • TitleAndDescription (12-42)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/secondary-fields/secondary-fields.tsx (1)
  • SecondaryFields (8-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/filter-toolbar.tsx (1)
  • FilterToolbar (22-137)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/data-table.tsx (1)
  • DataTable (27-111)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/client-columns.tsx (1)
  • VendorTaskType (8-18)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/columns.tsx (1)
  • VendorTaskType (10-20)
🔇 Additional comments (7)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/page.tsx (7)

1-20: Well-organized imports and component structure!

The reorganization of imports based on the feature-specific directory structure (including vendorId in paths) improves code organization and maintainability. The introduction of new components like SecondaryFields and TitleAndDescription suggests a more modular approach.


33-62: Good extraction of data fetching logic into separate functions.

Extracting the vendor retrieval, user fetching, and task fetching into dedicated functions (getVendor, getUsers, and getTasks) improves code readability and maintainability. The simplified error handling with a clear redirect is also a good approach.


50-58: Provide fallback for invalid page/per_page inputs.

When parsing page/per_page, consider validating them or defaulting to known safe values to avoid runtime errors. For instance, you can handle negative or non-numeric inputs gracefully.

- page: Number.parseInt(page),
- per_page: Number.parseInt(per_page),
+ page: Number.isNaN(Number.parseInt(page)) || Number.parseInt(page) < 1
+   ? 1
+   : Number.parseInt(page),
+ per_page: Number.isNaN(Number.parseInt(per_page)) || Number.parseInt(per_page) < 1
+   ? 5
+   : Number.parseInt(per_page),

65-98: Clean UI structure with clear component responsibilities.

The refactored UI structure with dedicated components (TitleAndDescription, SecondaryFields) makes the code more maintainable and easier to understand. Each component now has a clear responsibility in the UI hierarchy.


102-120: Well-implemented vendor fetching with proper error handling.

The getVendor function correctly handles session validation and returns null when there's no valid session, which is then properly handled in the main component with a redirect.


122-132: Properly implemented user fetching function.

The getUsers function correctly handles session validation and returns an empty array as a fallback when there's no valid session, providing a safe default.


230-242: Metadata function is correctly implemented.

The generateMetadata function correctly sets the locale and retrieves the internationalized title.

This branch was successfully deployed

1 active and 1 inactive deployments
Preview – app — 70ba719e Deployed Mar 25, 2025 by vercel[bot]
Preview – comp-portal — 70ba719e Deployed Mar 25, 2025 by vercel[bot]
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.

2 participants