"use client"; import Link from "next/link"; import { useTransition } from "react"; import { AnimatePresence, motion } from "framer-motion"; import { AlarmClockIcon, CheckIcon, ClockIcon } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { STAGE_LABEL, STAGE_TONE } from "@/lib/stages"; import type { Stage } from "@prisma/client"; import { logContactFollowUpAction, logFollowUpAction, snoozeContactFollowUpAction, snoozeFollowUpAction, } from "@/server/actions"; import { cn } from "@/lib/utils"; type Item = { id: string; company: string; roleTitle: string; /** Null for a person — contacts have no pipeline stage. */ stage: Stage | null; due: string; overdue: boolean; /** * Where the row goes and which snooze applies. An offer is an application's * respond-by date: a link and nothing else, because it cannot be snoozed and * answering it is not "logging a chase". */ kind: "application" | "contact" | "offer"; }; export function FollowUpList({ items, started = true, }: { items: Item[]; /** * Whether there is anything that COULD be chased. An empty list means two * different things and the card was only ever saying one of them: a brand-new * account got a green tick and "Every follow-up is scheduled for later", * which is a congratulation for work nobody has done, on the same screen as * a setup strip saying they have not started. */ started?: boolean; }) { const [pending, startTransition] = useTransition(); const snooze = (item: Item, days: number) => { startTransition(async () => { if (item.kind === "contact") await snoozeContactFollowUpAction(item.id, days); else await snoozeFollowUpAction(item.id, days); toast.success(days === 1 ? "Snoozed to tomorrow" : `Snoozed ${days} days`); }); }; // The other half, and the honest one: snoozing records nothing, so a list // cleared by snoozing looks exactly like one that was worked. const logged = (item: Item) => { startTransition(async () => { try { if (item.kind === "contact") await logContactFollowUpAction(item.id); else await logFollowUpAction(item.id); toast.success("Logged, and back in a week"); } catch (error) { toast.error(error instanceof Error ? error.message : "Could not log that."); } }); }; if (items.length === 0) { return (

{started ? "Nothing to chase" : "Nothing to chase yet"}

{started ? "Every follow-up is scheduled for later." : "Move a job along on the board and its next follow-up date sets itself."}

); } return ( ); }