Skip to content

Commit a3f0679

Browse files
committed
refactor: streamline comments handling across various components
- Consolidated comment fetching logic by removing direct calls to getComments in multiple pages and replacing them with a reusable Comments component. - Updated the Comments component to handle data fetching, loading states, and error handling, enhancing reusability and maintainability. - Removed the CreateCommentForm component as its functionality is now integrated into the Comments component. - This refactor simplifies the codebase and improves the user experience by providing a consistent comments interface.
1 parent b944f48 commit a3f0679

File tree

7 files changed

+99
-285
lines changed

7 files changed

+99
-285
lines changed

apps/app/src/app/(app)/[orgId]/policies/[policyId]/components/PolicyPage.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Control, Member, Policy, User } from '@db';
22
import type { JSONContent } from '@tiptap/react';
3-
import { Comments, CommentWithAuthor } from '../../../../../../components/comments/Comments';
3+
import { Comments } from '../../../../../../components/comments/Comments';
44
import { AuditLogWithRelations } from '../data';
55
import { PolicyPageEditor } from '../editor/components/PolicyDetails';
66
import { PolicyOverview } from './PolicyOverview';
@@ -14,7 +14,6 @@ export default function PolicyPage({
1414
isPendingApproval,
1515
policyId,
1616
logs,
17-
comments,
1817
}: {
1918
policy: (Policy & { approver: (Member & { user: User }) | null }) | null;
2019
assignees: (Member & { user: User })[];
@@ -23,7 +22,6 @@ export default function PolicyPage({
2322
isPendingApproval: boolean;
2423
policyId: string;
2524
logs: AuditLogWithRelations[];
26-
comments: CommentWithAuthor[];
2725
}) {
2826
return (
2927
<>
@@ -42,7 +40,7 @@ export default function PolicyPage({
4240

4341
<RecentAuditLogs logs={logs} />
4442

45-
<Comments entityId={policyId} comments={comments} entityType="policy" />
43+
<Comments entityId={policyId} entityType="policy" />
4644
</>
4745
);
4846
}

apps/app/src/app/(app)/[orgId]/policies/[policyId]/page.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
import PageWithBreadcrumb from '@/components/pages/PageWithBreadcrumb';
22
import type { Metadata } from 'next';
33
import PolicyPage from './components/PolicyPage';
4-
import {
5-
getAssignees,
6-
getComments,
7-
getLogsForPolicy,
8-
getPolicy,
9-
getPolicyControlMappingInfo,
10-
} from './data';
4+
import { getAssignees, getLogsForPolicy, getPolicy, getPolicyControlMappingInfo } from './data';
115

126
export default async function PolicyDetails({
137
params,
@@ -18,7 +12,6 @@ export default async function PolicyDetails({
1812

1913
const policy = await getPolicy(policyId);
2014
const assignees = await getAssignees();
21-
const comments = await getComments(policyId);
2215
const { mappedControls, allControls } = await getPolicyControlMappingInfo(policyId);
2316
const logs = await getLogsForPolicy(policyId);
2417

@@ -39,7 +32,6 @@ export default async function PolicyDetails({
3932
allControls={allControls}
4033
isPendingApproval={isPendingApproval}
4134
logs={logs}
42-
comments={comments}
4335
/>
4436
</PageWithBreadcrumb>
4537
);

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

Lines changed: 3 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import { InherentRiskChart } from '@/components/risks/charts/InherentRiskChart';
33
import { ResidualRiskChart } from '@/components/risks/charts/ResidualRiskChart';
44
import { RiskOverview } from '@/components/risks/risk-overview';
55
import { auth } from '@/utils/auth';
6-
import { AttachmentEntityType, CommentEntityType, db } from '@db';
6+
import { CommentEntityType, db } from '@db';
77
import type { Metadata } from 'next';
88
import { headers } from 'next/headers';
99
import { redirect } from 'next/navigation';
1010
import { cache } from 'react';
11-
import { Comments, CommentWithAuthor } from '../../../../../components/comments/Comments';
11+
import { Comments } from '../../../../../components/comments/Comments';
1212

1313
interface PageProps {
1414
searchParams: Promise<{
@@ -24,7 +24,6 @@ interface PageProps {
2424
export default async function RiskPage({ searchParams, params }: PageProps) {
2525
const { riskId, orgId } = await params;
2626
const risk = await getRisk(riskId);
27-
const comments = await getComments(riskId);
2827
const assignees = await getAssignees();
2928
if (!risk) {
3029
redirect('/');
@@ -43,7 +42,7 @@ export default async function RiskPage({ searchParams, params }: PageProps) {
4342
<InherentRiskChart risk={risk} />
4443
<ResidualRiskChart risk={risk} />
4544
</div>
46-
<Comments entityId={riskId} entityType={CommentEntityType.risk} comments={comments} />
45+
<Comments entityId={riskId} entityType={CommentEntityType.risk} />
4746
</div>
4847
</PageWithBreadcrumb>
4948
);
@@ -75,67 +74,7 @@ const getRisk = cache(async (riskId: string) => {
7574
return risk;
7675
});
7776

78-
const getComments = async (riskId: string): Promise<CommentWithAuthor[]> => {
79-
const session = await auth.api.getSession({
80-
headers: await headers(),
81-
});
82-
83-
const activeOrgId = session?.session.activeOrganizationId;
84-
85-
if (!activeOrgId) {
86-
console.warn('Could not determine active organization ID in getComments');
87-
return [];
88-
}
89-
90-
const comments = await db.comment.findMany({
91-
where: {
92-
organizationId: activeOrgId,
93-
entityId: riskId,
94-
entityType: CommentEntityType.risk,
95-
},
96-
include: {
97-
author: {
98-
include: {
99-
user: true,
100-
},
101-
},
102-
},
103-
orderBy: {
104-
createdAt: 'desc',
105-
},
106-
});
107-
108-
const commentsWithAttachments = await Promise.all(
109-
comments.map(async (comment) => {
110-
const attachments = await db.attachment.findMany({
111-
where: {
112-
organizationId: activeOrgId,
113-
entityId: comment.id,
114-
entityType: AttachmentEntityType.comment,
115-
},
116-
});
117-
return {
118-
id: comment.id,
119-
content: comment.content,
120-
author: {
121-
id: comment.author.user.id,
122-
name: comment.author.user.name,
123-
email: comment.author.user.email,
124-
},
125-
attachments: attachments.map((att) => ({
126-
id: att.id,
127-
name: att.name,
128-
type: att.type,
129-
downloadUrl: att.url || '', // assuming url maps to downloadUrl
130-
createdAt: att.createdAt.toISOString(),
131-
})),
132-
createdAt: comment.createdAt.toISOString(),
133-
};
134-
}),
135-
);
13677

137-
return commentsWithAttachments;
138-
};
13978

14079
const getAssignees = cache(async () => {
14180
const session = await auth.api.getSession({

apps/app/src/app/(app)/[orgId]/tasks/[taskId]/components/TaskMainContent.tsx

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
'use client';
22

3-
import { useTaskComments } from '@/hooks/use-comments-api';
43
import { Separator } from '@comp/ui/separator';
54
import { CommentEntityType, type Task } from '@db';
65
import { useEffect, useState } from 'react';
76
import { useDebouncedCallback } from 'use-debounce';
8-
import { CommentForm } from '../../../../../../components/comments/CommentForm';
9-
import { CommentList } from '../../../../../../components/comments/CommentList';
7+
import { Comments } from '../../../../../../components/comments/Comments';
108
import { updateTask } from '../../actions/updateTask';
119
import { TaskBody } from './TaskBody';
1210

@@ -18,17 +16,6 @@ export function TaskMainContent({ task }: TaskMainContentProps) {
1816
const [title, setTitle] = useState(task.title);
1917
const [description, setDescription] = useState(task.description ?? '');
2018

21-
// Use SWR to fetch comments with real-time updates
22-
const {
23-
data: commentsData,
24-
error: commentsError,
25-
isLoading: commentsLoading,
26-
mutate: refreshComments,
27-
} = useTaskComments(task.id);
28-
29-
// Extract comments from SWR response
30-
const comments = commentsData?.data || [];
31-
3219
const debouncedUpdateTask = useDebouncedCallback(
3320
(field: 'title' | 'description', value: string) => {
3421
updateTask({ id: task.id, [field]: value });
@@ -68,27 +55,7 @@ export function TaskMainContent({ task }: TaskMainContentProps) {
6855
</div>
6956

7057
{/* Comment Section */}
71-
<div className="space-y-4">
72-
<h3 className="text-lg font-medium">Comments</h3>
73-
<CommentForm entityId={task.id} entityType={CommentEntityType.task} />
74-
75-
{commentsLoading && (
76-
<div className="space-y-3">
77-
{/* Simple comment skeletons */}
78-
{[1, 2].map((i) => (
79-
<div key={i} className="bg-muted/20 rounded-lg h-16 animate-pulse"></div>
80-
))}
81-
</div>
82-
)}
83-
84-
{commentsError && (
85-
<div className="text-destructive text-sm">Failed to load comments. Please try again.</div>
86-
)}
87-
88-
{!commentsLoading && !commentsError && (
89-
<CommentList comments={comments} refreshComments={refreshComments} />
90-
)}
91-
</div>
58+
<Comments entityId={task.id} entityType={CommentEntityType.task} variant="inline" />
9259
</div>
9360
);
9461
}

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

Lines changed: 3 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
import PageWithBreadcrumb from '@/components/pages/PageWithBreadcrumb';
44
import { auth } from '@/utils/auth';
5-
import { AttachmentEntityType, CommentEntityType, db } from '@db';
5+
import { CommentEntityType, db } from '@db';
66
import type { Metadata } from 'next';
77
import { headers } from 'next/headers';
88
import { redirect } from 'next/navigation';
99
import { cache } from 'react';
10-
import { Comments, CommentWithAuthor } from '../../../../../components/comments/Comments';
10+
import { Comments } from '../../../../../components/comments/Comments';
1111
import { VendorInherentRiskChart } from './components/VendorInherentRiskChart';
1212
import { VendorResidualRiskChart } from './components/VendorResidualRiskChart';
1313
import { SecondaryFields } from './components/secondary-fields/secondary-fields';
@@ -20,7 +20,6 @@ export default async function VendorPage({ params }: PageProps) {
2020
const { vendorId, orgId } = await params;
2121
const vendor = await getVendor(vendorId);
2222
const assignees = await getAssignees();
23-
const comments = await getComments(vendorId);
2423

2524
if (!vendor || !vendor.vendor) {
2625
redirect('/');
@@ -43,7 +42,7 @@ export default async function VendorPage({ params }: PageProps) {
4342
<VendorInherentRiskChart vendor={vendor.vendor} />
4443
<VendorResidualRiskChart vendor={vendor.vendor} />
4544
</div>
46-
<Comments entityId={vendorId} comments={comments} entityType={CommentEntityType.vendor} />
45+
<Comments entityId={vendorId} entityType={CommentEntityType.vendor} />
4746
</div>
4847
</PageWithBreadcrumb>
4948
);
@@ -91,68 +90,6 @@ const getVendor = cache(async (vendorId: string) => {
9190
};
9291
});
9392

94-
const getComments = async (vendorId: string): Promise<CommentWithAuthor[]> => {
95-
const session = await auth.api.getSession({
96-
headers: await headers(),
97-
});
98-
99-
const activeOrgId = session?.session.activeOrganizationId;
100-
101-
if (!activeOrgId) {
102-
console.warn('Could not determine active organization ID in getComments');
103-
return [];
104-
}
105-
106-
const comments = await db.comment.findMany({
107-
where: {
108-
organizationId: activeOrgId,
109-
entityId: vendorId,
110-
entityType: CommentEntityType.vendor,
111-
},
112-
include: {
113-
author: {
114-
include: {
115-
user: true,
116-
},
117-
},
118-
},
119-
orderBy: {
120-
createdAt: 'desc',
121-
},
122-
});
123-
124-
const commentsWithAttachments = await Promise.all(
125-
comments.map(async (comment) => {
126-
const attachments = await db.attachment.findMany({
127-
where: {
128-
organizationId: activeOrgId,
129-
entityId: comment.id,
130-
entityType: AttachmentEntityType.comment,
131-
},
132-
});
133-
return {
134-
id: comment.id,
135-
content: comment.content,
136-
author: {
137-
id: comment.author.user.id,
138-
name: comment.author.user.name,
139-
email: comment.author.user.email,
140-
},
141-
attachments: attachments.map((att) => ({
142-
id: att.id,
143-
name: att.name,
144-
type: att.type,
145-
downloadUrl: att.url || '', // assuming url maps to downloadUrl
146-
createdAt: att.createdAt.toISOString(),
147-
})),
148-
createdAt: comment.createdAt.toISOString(),
149-
};
150-
}),
151-
);
152-
153-
return commentsWithAttachments;
154-
};
155-
15693
const getAssignees = cache(async () => {
15794
const session = await auth.api.getSession({
15895
headers: await headers(),

0 commit comments

Comments
 (0)