'use client'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useParams } from 'next/navigation'; import { CheckCircle2, ChevronRight } from 'lucide-react'; import { Checkbox } from '@/components/ui/checkbox'; import { Button } from '@/components/ui/button'; import { apiFetch } from '@/lib/api/client'; import { toastError } from '@/lib/api/toast-error'; import { cn } from '@/lib/utils'; interface QualificationRow { key: string; label: string; description: string | null; enabled: boolean; displayOrder: number; confirmed: boolean; confirmedAt: string | null; confirmedBy: string | null; notes: string | null; } interface QualificationResponse { data: { criteria: QualificationRow[]; fullyQualified: boolean; }; } /** * Per-interest qualification checklist. Hidden when the port has no * enabled criteria. When the rep has confirmed every enabled criterion AND * the deal is still in 'enquiry', a soft hint surfaces a Promote button * that advances the stage to 'qualified' through the standard transition * endpoint (no override; this is the canonical adjacent move). */ export function QualificationChecklist({ interestId, currentStage, }: { interestId: string; currentStage: string; }) { const params = useParams<{ portSlug: string }>(); const queryClient = useQueryClient(); const { data, isLoading } = useQuery({ queryKey: ['interest-qualifications', interestId], queryFn: () => apiFetch(`/api/v1/interests/${interestId}/qualifications`), }); const toggleMutation = useMutation({ mutationFn: async (vars: { criterionKey: string; confirmed: boolean }) => apiFetch(`/api/v1/interests/${interestId}/qualifications`, { method: 'PUT', body: { criterionKey: vars.criterionKey, confirmed: vars.confirmed }, }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['interest-qualifications', interestId] }); }, onError: (err) => toastError(err), }); const promoteMutation = useMutation({ mutationFn: async () => apiFetch(`/api/v1/interests/${interestId}/stage`, { method: 'POST', body: { pipelineStage: 'qualified' }, }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['interests', interestId] }); queryClient.invalidateQueries({ queryKey: ['interests'] }); }, onError: (err) => toastError(err), }); if (isLoading) return null; if (!data) return null; const criteria = data.data.criteria; if (criteria.length === 0) return null; const fullyQualified = data.data.fullyQualified; const showPromoteHint = fullyQualified && currentStage === 'enquiry'; // Avoid referencing `params` in the JSX so the unused destructure passes // strict noUnused checks; it stays available for future deep-link hooks. void params; return (

Qualification

{fullyQualified ? ( All confirmed ) : ( {criteria.filter((c) => c.confirmed).length} of {criteria.length} confirmed )}
{showPromoteHint ? (

All criteria confirmed — this lead is ready to qualify.

) : null}
); }