Vendor Page - Partial Implementation - #177
Conversation
- 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.
…w task creation and update actions
…or registration components
… title and description, and add comments section
…omment features, and implement task attachment handling
…structure title and description handling
…pdate task handling, and restructure data table integration
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
1 Skipped Deployment
|
WalkthroughThe 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
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
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
Poem
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
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 suggestionAdditional 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 componentThe 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 translationThe 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 messagesThe 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 handlingThe 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 assignmentAssigning
datatoattachmentsadds unnecessary complexity without providing value. Consider usingdatadirectly.- 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 commentThe comment is redundant as it duplicates the filename.
-// create-task-comment.tsapps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/actions/create-vendor-comment.ts (2)
1-1: Incorrect file header commentThe 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 responseThe 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: Improveparamsinterface definitionThe
paramsis 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
createVendorActionwhich now specifiesPromise<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
createVendorActionwhich 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 visibilityThe 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 UpdateTaskFormWhen 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 stateThe 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 dataWhen 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 formatThe 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 usageThe 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 usageUsing
<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 issuesThe
isEmptyprop 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 elementThere's an unnecessary
{" "}which is likely a leftover from editing.- </div>{" "} + </div>
65-72: Inconsistent UI between desktop and mobile viewsThe 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
DataTablePaginationcomponent. 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 unexpectedskipvalues. It may be beneficial to clamp or sanitizepageandper_pageinputs 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
TitleAndDescriptionandSecondaryFieldsclarifies 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 ifvendoris null.
103-121: Add error handling for vendor retrieval.Your
getVendorfunction returnsnullif 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.
getUsersretrieves 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 = 1andper_page = 10is good, but ensure consistency with the default values set in your searchParams destructuring (which is 5 forper_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
zodvalidations. 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.
createVendorTaskCommentSchemarequires a minimum length of 1 forcontent. 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.
createVendorCommentSchemaonly ensurescontentis 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
updateVendorRiskSchemarestricts 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
📒 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 forVendorRegisterTableRowhas 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 atVendorRegisterTable.tsxis 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 forVendorRegisterTablefrom./components/VendorRegisterTablecorrectly 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 forCreateVendorSheethas been updated to"../../components/create-vendor-sheet", and the import forcolumnsnow 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
TaskPagecomponent 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-reactlibrary 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 VendorTaskTypeThe 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 colorsAdding 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 assignmentThe changes enhance both the visual presentation and readability:
- Adding index parameter enables color assignment
- Proper title casing for category names
- Special handling for the "Other" category
- 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 componentThe VendorComments component import is correctly added, which aligns with the PR's focus on enhancing vendor management features.
51-51: Uncommented VendorComments component usageThe 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 messagesThe 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
riskIdbut this appears to be in a vendor-related context. Consider whether this should bevendorIdinstead 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 tsLength of output: 1592
Vendor-Context Variable Name Inconsistency
The vendor-specific revalidation action currently extracts a variable named
riskIdfrom 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 foruploadTaskFileSchema) and the overall vendor workflow expect avendorIdinstead. 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
vendorIdrather thanriskId.- If confirmed, modify line 18 to extract
vendorIdand 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 componentThe 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 actionThe 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 structureThe component has a clean structure with appropriate props typing. The integration with the
UpdateSecondaryFieldsFormcomponent 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.riskTaskwhich 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 tsLength of output: 46
Action Required: Verify Vendor Upload Type
The current code updates the upload type from
riskTasktovendorTaskfor vendor tasks. However, our initial search did not decisively confirm thatUPLOAD_TYPE.vendorTaskis defined. Please run the above script to manually verify that:
- The
UPLOAD_TYPEenum (which may be declared in either a.tsor.tsxfile) includes avendorTaskvalue.- The use of
UPLOAD_TYPE.vendorTaskis appropriate for vendor tasks.If the verification confirms that
vendorTaskexists, 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 tsxLength of output: 564
Verify Vendor Upload Type Presence
The code change updates the upload type from
riskTasktovendorTaskfor vendor tasks. However, our initial search did not conclusively show that theUPLOAD_TYPEenum includes avendorTaskvalue, likely due to the file type filtering used in the previous command. Please run the above script to manually verify that:
- The
UPLOAD_TYPEenum (in TypeScript files) contains avendorTaskvalue.- The use of
UPLOAD_TYPE.vendorTaskis appropriate for vendor tasks.If the verification confirms that
vendorTaskexists, 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_TYPEenum with avendorTaskmember.• Action: Please manually verify that the
UPLOAD_TYPEenum—in the appropriate TypeScript file—includes avendorTaskentry.
• Note: If thevendorTaskvalue 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 destinationThe
backButtonHrefis 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-4class 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
RiskOverviewand other components, but I don't seeRiskOverviewbeing 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
rgcommand couldn’t locate the file atapps/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 (likeRiskOverview) are not present if the component isn’t used.To gather further information, please run the following script to search for any
page.tsxfiles 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
RiskOverviewimport appears in it. If you confirm thatRiskOverviewisn’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
RiskOverviewis 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 changeChanging the import from
CreateVendortoCreateVendorFormimproves naming consistency by clearly indicating this is a form component.
40-40: Updated component reference correctlyThe component usage has been properly updated to match the renamed import.
51-51: Updated component reference correctlyThe 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 functionalityThe 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 variablesThe component has been renamed from
CreateRiskCommentFormtoCreateVendorCommentForm, and the related variables have been updated to reflect the vendor context.
34-42: Updated action hook for vendor commentsThe 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 valuesThe form configuration has been updated to use the vendor-specific schema and vendor ID.
52-54: Updated form submission logicThe form submission has been correctly updated to use the vendor-specific action.
91-95: Updated disabled state for buttonThe 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 managementThe component is well-structured with appropriate props typing and state management using
useQueryStatefor the comment sheet.
70-77: Well-handled empty stateGood use of the
EmptyCardcomponent 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
CreateVendortoCreateVendorFormmakes 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:
- Better represents its usage pattern
- Eliminates unnecessary Promise handling
- Makes it easier to use in React components
The new name
useGetColumnHeadersclearly 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
TitleAndDescriptioncomponent effectively displays vendor information with a clean interface and includes an edit button that integrates with theUpdateTitleAndDescriptionSheetcomponent.apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/[vendorId]/components/tasks/data-table/empty-states.tsx (1)
15-46: Well implemented NoResults componentThe
NoResultscomponent 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 tasksThe 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 componentThe 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:
- Using
useMediaQueryto detect device size- Conditionally rendering either a
Sheet(desktop) orDrawer(mobile) component- Maintaining state via URL query parameters with
useQueryState- 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, returningnullif no valid session is found. The logic is straightforward and effectively returns the matching risk ornullif 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 theupdateVendorActionandupdateVendorSchema. 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.noneprovides a safe default whenpolicyData.metadata?.departmentis unavailable. Looks good.
104-104: Added department fallback for policy creation.Again, using
client_1.Departments.noneis consistent with the fallback strategy.
186-186: Upsert logic for controls inseedFrameworkCategoryControls.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
policyIdandevidenceIdwill be linked later.
216-228: Initial null assignments forpolicyIdandevidenceId, plus fallback fornameanddescription.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 ofseedEvidenceRecords(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 ofseedEvidenceRecordsfunction (lines 320–329).Graceful handling of errors and final logging is appropriate. Good job wrapping potential issues in the catch block.
330-356:updateEvidenceLinksfunction 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:updatePolicyLinksfunction 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: UpdatedSTATUS_COLORSkeys.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: 0helps present a uniform chart. No issues here.
99-99: Normalized naming ingetStatusColor.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 keyoverview.Adding “Overview” aligns with the top-level terminology used elsewhere. No concerns here.
19-19:vendor_name_descriptionadditions.Helpful guidance for users filling out the vendor name. Looks good.
24-24:vendor_description_descriptionadditions.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: Newsheetobject 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, yetgetServerColumnHeadersappears 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
FilterToolbarandDataTableare 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
VendorStatusandVendorCategoryfrom@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.
dueDateis validated withz.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.
updateVendorSchemademandsstatus. 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.
| revalidatePath(`/${user.organizationId}/risk/${riskId}`); | ||
| revalidatePath(`/${user.organizationId}/risk/${riskId}/tasks/${taskId}`); | ||
| revalidateTag("risk-cache"); |
There was a problem hiding this comment.
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.
| 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")} |
There was a problem hiding this comment.
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.
| {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"; |
There was a problem hiding this comment.
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.
| 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")} |
There was a problem hiding this comment.
🛠️ 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.
| {t("risk.tasks.attachments")} | |
| {t("vendor.tasks.attachments")} |
| revalidatePath(`/${user.organizationId}/vendor/${vendorId}`); | ||
| revalidatePath(`/${user.organizationId}/vendor/${vendorId}/tasks/${vendorTaskId}`); |
There was a problem hiding this comment.
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.
| revalidatePath(`/${user.organizationId}/vendor/${vendorId}`); | |
| revalidatePath(`/${user.organizationId}/vendor/${vendorId}/tasks/${vendorTaskId}`); | |
| revalidatePath(`/${user.organizationId}/vendors/${vendorId}`); | |
| revalidatePath(`/${user.organizationId}/vendors/${vendorId}/tasks/${vendorTaskId}`); |
| 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 }; | ||
| }); |
There was a problem hiding this comment.
🛠️ 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.
| 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 }; | |
| } |
| revalidatePath(`/${user.organizationId}/risk`); | ||
| revalidatePath(`/${user.organizationId}/risk/${riskId.riskId}`); | ||
| revalidatePath( | ||
| `/${user.organizationId}/risk/${riskId.riskId}/tasks/${id}` | ||
| ); | ||
| revalidateTag("risks"); | ||
|
|
There was a problem hiding this comment.
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.
| 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")); |
There was a problem hiding this comment.
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
| <AssignedUser | ||
| fullName={ | ||
| users.find((user) => user.id === comment.ownerId)?.name | ||
| } | ||
| avatarUrl={ | ||
| users.find((user) => user.id === comment.ownerId)?.image | ||
| } | ||
| /> |
There was a problem hiding this comment.
💡 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 foravatarUrl): 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.
| const { tasks: loadedTasks, total } = await getTasks({ | ||
| vendorId, | ||
| search, | ||
| status: status as VendorTaskStatus, | ||
| column, | ||
| order, | ||
| page: Number.parseInt(page), | ||
| per_page: Number.parseInt(per_page), |
There was a problem hiding this comment.
🛠️ 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.
| 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), |
There was a problem hiding this comment.
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
getTasksfunction effectively handles filtering, sorting, and pagination. The parallel fetching of tasks and count is efficient. The transformation of the database results to match the expectedVendorTaskTypeinterface 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
📒 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
SecondaryFieldsandTitleAndDescriptionsuggests 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, andgetTasks) 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
getVendorfunction 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
getUsersfunction 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
generateMetadatafunction correctly sets the locale and retrieves the internationalized title.
Summary by CodeRabbit
New Features
VendorOverviewcomponent for displaying vendor details.CreateVendorCommentForm,TaskAttachments, andUpdateTaskForm.UI & Styling
Refactor
VendorPagecomponent for improved clarity.