151 lines
5.1 KiB
TypeScript
151 lines
5.1 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { useMutation, useSuspenseQuery } from '@tanstack/react-query';
|
|
import { toast } from 'sonner';
|
|
import { AlertModal } from '@/components/modal/alert-modal';
|
|
import { Icons } from '@/components/icons';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { deleteEnquiryFollowupMutation } from '../api/mutations';
|
|
import { enquiryFollowupsOptions } from '../api/queries';
|
|
import type { EnquiryReferenceData } from '../api/types';
|
|
import { FollowupFormSheet } from './followup-form-sheet';
|
|
|
|
export function EnquiryFollowupsTab({
|
|
enquiryId,
|
|
customerId,
|
|
referenceData,
|
|
canCreate,
|
|
canUpdate,
|
|
canDelete
|
|
}: {
|
|
enquiryId: string;
|
|
customerId: string;
|
|
referenceData: EnquiryReferenceData;
|
|
canCreate: boolean;
|
|
canUpdate: boolean;
|
|
canDelete: boolean;
|
|
}) {
|
|
const { data } = useSuspenseQuery(enquiryFollowupsOptions(enquiryId));
|
|
const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
const [open, setOpen] = useState(false);
|
|
const [deleteOpen, setDeleteOpen] = useState(false);
|
|
const selected = data.items.find((item) => item.id === selectedId);
|
|
const followupTypeMap = new Map(referenceData.followupTypes.map((item) => [item.id, item.label]));
|
|
|
|
const deleteMutation = useMutation({
|
|
...deleteEnquiryFollowupMutation,
|
|
onSuccess: () => {
|
|
toast.success('Follow-up deleted successfully');
|
|
setDeleteOpen(false);
|
|
setSelectedId(null);
|
|
},
|
|
onError: (error) =>
|
|
toast.error(error instanceof Error ? error.message : 'Failed to delete follow-up')
|
|
});
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader className='flex flex-row items-start justify-between gap-4'>
|
|
<div>
|
|
<CardTitle>Follow-ups</CardTitle>
|
|
<CardDescription>
|
|
Track the latest contact moments, outcomes, and next steps for this enquiry.
|
|
</CardDescription>
|
|
</div>
|
|
{canCreate ? (
|
|
<Button
|
|
size='sm'
|
|
onClick={() => {
|
|
setSelectedId(null);
|
|
setOpen(true);
|
|
}}
|
|
>
|
|
<Icons.add className='mr-2 h-4 w-4' /> Add Follow-up
|
|
</Button>
|
|
) : null}
|
|
</CardHeader>
|
|
<CardContent className='space-y-4'>
|
|
{!data.items.length ? (
|
|
<div className='text-muted-foreground rounded-lg border border-dashed p-8 text-center text-sm'>
|
|
No follow-ups recorded yet.
|
|
</div>
|
|
) : (
|
|
data.items.map((item) => (
|
|
<div
|
|
key={item.id}
|
|
className='flex flex-col gap-3 rounded-lg border p-4 md:flex-row md:items-start md:justify-between'
|
|
>
|
|
<div className='space-y-2'>
|
|
<div className='flex flex-wrap items-center gap-2'>
|
|
<Badge variant='outline'>
|
|
{followupTypeMap.get(item.followupType) ?? 'Unknown type'}
|
|
</Badge>
|
|
<span className='text-sm font-medium'>
|
|
{new Date(item.followupDate).toLocaleDateString()}
|
|
</span>
|
|
</div>
|
|
{item.outcome ? <p className='text-sm'>{item.outcome}</p> : null}
|
|
{item.nextAction ? (
|
|
<p className='text-muted-foreground text-sm'>Next action: {item.nextAction}</p>
|
|
) : null}
|
|
{item.nextFollowupDate ? (
|
|
<p className='text-muted-foreground text-sm'>
|
|
Next follow-up: {new Date(item.nextFollowupDate).toLocaleDateString()}
|
|
</p>
|
|
) : null}
|
|
{item.notes ? <p className='text-muted-foreground text-sm'>{item.notes}</p> : null}
|
|
</div>
|
|
<div className='flex gap-2'>
|
|
<Button
|
|
variant='outline'
|
|
size='sm'
|
|
disabled={!canUpdate}
|
|
onClick={() => {
|
|
setSelectedId(item.id);
|
|
setOpen(true);
|
|
}}
|
|
>
|
|
<Icons.edit className='mr-2 h-4 w-4' /> Edit
|
|
</Button>
|
|
<Button
|
|
variant='outline'
|
|
size='sm'
|
|
disabled={!canDelete}
|
|
onClick={() => {
|
|
setSelectedId(item.id);
|
|
setDeleteOpen(true);
|
|
}}
|
|
>
|
|
<Icons.trash className='mr-2 h-4 w-4' /> Delete
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
))
|
|
)}
|
|
</CardContent>
|
|
|
|
<FollowupFormSheet
|
|
enquiryId={enquiryId}
|
|
followup={selected}
|
|
open={open}
|
|
onOpenChange={setOpen}
|
|
referenceData={referenceData}
|
|
customerId={customerId}
|
|
/>
|
|
<AlertModal
|
|
isOpen={deleteOpen}
|
|
onClose={() => setDeleteOpen(false)}
|
|
onConfirm={() => {
|
|
if (selectedId) {
|
|
deleteMutation.mutate({ enquiryId, followupId: selectedId });
|
|
}
|
|
}}
|
|
loading={deleteMutation.isPending}
|
|
/>
|
|
</Card>
|
|
);
|
|
}
|