Files
alla-allaos-fullstack/src/features/crm/enquiries/components/enquiry-followups-tab.tsx
2026-06-15 13:46:33 +07:00

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>
);
}