This commit is contained in:
phaichayon
2026-07-01 08:44:35 +07:00
parent 0c39472dca
commit 6d6cd3a6df
32 changed files with 1284 additions and 333 deletions

View File

@@ -257,15 +257,7 @@ export interface QuotationAttachmentRecord {
deletedAt: string | null;
}
export interface QuotationActivityRecord {
id: string;
action: string;
entityType: string;
entityId: string;
createdAt: string;
userId: string;
actorName: string | null;
}
export type QuotationActivityRecord = CrmAuditLogRecord;
export interface QuotationRelationItem {
id: string;
@@ -481,3 +473,4 @@ export interface QuotationCustomerPackageGenerateResponse {
pageCount: number;
} | null;
}
import type { CrmAuditLogRecord } from '@/features/crm/audit-log/types';

View File

@@ -27,6 +27,7 @@ import {
SelectValue
} from '@/components/ui/select';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { AuditLogTab } from '@/features/crm/components/audit-log-tab';
import { formatDate, formatDateTime } from '@/lib/date-format';
import { formatNumber } from '@/lib/number-format';
import {
@@ -1231,7 +1232,7 @@ const canReviseByStatus = ['accepted', 'rejected', 'sent', 'approved'].includes(
<TabsTrigger value='topics'>Topics</TabsTrigger>
<TabsTrigger value='followups'>Follow-ups</TabsTrigger>
<TabsTrigger value='attachments'>Attachments</TabsTrigger>
<TabsTrigger value='activity'>Activity</TabsTrigger>
<TabsTrigger value='activity'>Audit Log</TabsTrigger>
<TabsTrigger value='approval'>Approval</TabsTrigger>
</TabsList>
@@ -1657,45 +1658,12 @@ const canReviseByStatus = ['accepted', 'rejected', 'sent', 'approved'].includes(
</Card>
</TabsContent>
<TabsContent value='activity'>
<Card>
<CardHeader>
<CardTitle>Activity</CardTitle>
<CardDescription>
Audit events for quotation mutations and child records.
</CardDescription>
</CardHeader>
<CardContent className='space-y-4'>
{!data.activity.length ? (
<EmptyState message='No activity recorded yet.' />
) : (
data.activity.map((item, index) => (
<div key={item.id} className='space-y-4'>
<div className='flex items-start gap-3'>
<div className='bg-primary mt-2 h-2 w-2 rounded-full' />
<div className='space-y-1'>
<div className='flex items-center gap-2'>
<Badge variant='outline' className='capitalize'>
{item.action}
</Badge>
<Badge variant='secondary'>
{item.entityType.replaceAll('_', ' ')}
</Badge>
<span className='text-sm font-medium'>
{item.actorName ?? item.userId}
</span>
</div>
<div className='text-muted-foreground text-xs'>
{formatDateTime(item.createdAt)}
</div>
</div>
</div>
{index < data.activity.length - 1 ? <Separator /> : null}
</div>
))
)}
</CardContent>
</Card>
<TabsContent value='activity'>
<AuditLogTab
items={data.activity}
emptyMessage='No audit log recorded yet.'
description='System-generated immutable history for this quotation and its child records.'
/>
</TabsContent>
<TabsContent value='approval'>

View File

@@ -1444,7 +1444,10 @@ export async function getQuotationActivity(
entityId: log.entityId,
createdAt: log.createdAt,
userId: log.userId,
actorName: actorMap.get(log.userId) ?? null
actorName: actorMap.get(log.userId) ?? null,
beforeData: log.beforeData,
afterData: log.afterData,
requestId: log.requestId
}));
}