"use client"; import Link from "next/link"; import { BellIcon, CalendarClockIcon, CircleUserRoundIcon, HandshakeIcon, ListChecksIcon, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { cn } from "@/lib/utils"; /** * Everything that has come round, in the chrome. * * This used to be a card on the dashboard called "Needs you now", which meant * you only saw what was owed if you happened to be on that page. A bell in the * top bar is on every page, which is the whole point of a thing that is trying * to interrupt you. * * One count, four groups. The count is a single number because two numbers in * the chrome make you do arithmetic; the groups stay apart inside because * chasing a company, pinging a person, ticking a task and answering an offer * are four different actions and a flat list of look-alike rows hides which is * which. * * An offer deadline sits at the top of the list. It is the only date here that * cannot be caught up on tomorrow. * * Nothing here is dismissable, and that is deliberate: an item leaves this list * by being dealt with — logging the follow-up, moving the ping, ticking the * task — not by being swiped away. A dismissable notification would let the * bell go quiet while the work stayed undone. */ export type Notice = { kind: "APPLICATION" | "CONTACT" | "TASK" | "OFFER"; id: string; title: string; detail: string; due: string; overdue: boolean; }; const GROUPS = [ { key: "OFFER" as const, label: "Answer by", icon: HandshakeIcon, href: (id: string) => `/applications/${id}`, }, { key: "APPLICATION" as const, label: "Follow up", icon: CalendarClockIcon, href: (id: string) => `/applications/${id}`, }, { key: "CONTACT" as const, label: "Ping", icon: CircleUserRoundIcon, href: (id: string) => `/crm/contacts/${id}`, }, { key: "TASK" as const, label: "Due", icon: ListChecksIcon, href: () => "/" }, ]; export function Notifications({ items }: { items: Notice[] }) { const overdue = items.filter((item) => item.overdue).length; return (
Needs you now {overdue > 0 && ( {overdue} overdue )}
{items.length === 0 ? (

Nothing has come round. Dates you set on applications, people and tasks show up here when they arrive.

) : (
{GROUPS.map((group) => { const rows = items.filter((item) => item.kind === group.key); if (rows.length === 0) return null; return (
{group.label} {rows.length}
{rows.map((row) => ( {row.title} {row.detail && ( {row.detail} )} {row.due} ))}
); })}
)}
); }