import { formatDistance } from "date-fns"; import { Activity, HeartPulse, Mail, Linkedin } from "lucide-react"; import { useRecordContext, useTranslate, useLocale } from "ra-core"; import { Badge } from "@/components/ds/ui/badge"; import { Progress } from "@/components/ds/ui/progress"; import { AsideSection } from "../misc/AsideSection"; import type { Contact } from "../types"; import { getDateFnsLocale } from "@/i18n/date-fns"; const InternalStatusBadge = ({ status }: { status: string }) => { const translate = useTranslate(); let variant: | "default" | "secondary" | "destructive" | "outline" | "success" | "warning" | "info" | "critical" | "neutral" = "outline"; switch (status) { case "strong": variant = "default"; break; case "active": variant = "success"; break; case "cooling": variant = "warning"; break; case "cold": variant = "warning"; break; case "dormant": variant = "neutral"; break; } return ( {translate(`crm.contact.filter.engagement_status.${status}`, { _: status, })} ); }; const EmailStatusBadge = ({ status }: { status: string }) => { const translate = useTranslate(); let variant: | "default" | "secondary" | "destructive" | "outline" | "success" | "warning" | "info" | "critical" | "neutral" = "outline"; switch (status) { case "valid": variant = "success"; break; case "risky": variant = "warning"; break; case "invalid": variant = "critical"; break; } return ( {translate(`crm.contact.health.status.${status}`, { _: status })} ); }; const LinkedInStatusBadge = ({ status }: { status: string }) => { const translate = useTranslate(); let variant: | "default" | "secondary" | "destructive" | "outline" | "success" | "warning" | "info" | "critical" | "neutral" = "outline"; switch (status) { case "active": variant = "info"; break; case "inactive": variant = "neutral"; break; case "not_found": variant = "critical"; break; } return ( {translate(`crm.contact.health.status.${status}`, { _: status .split("_") .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(" "), })} ); }; export const ContactHealthCard = () => { const record = useRecordContext(); const translate = useTranslate(); const locale = useLocale(); if (!record) return null; const daysSince = record.days_since_last_activity ?? (record.last_seen ? Math.floor( (new Date().getTime() - new Date(record.last_seen).getTime()) / (1000 * 60 * 60 * 24), ) : undefined); const hasInternalHealth = record.internal_heartbeat_score != null || record.internal_heartbeat_status != null || daysSince != null; const hasExternalHealth = record.external_heartbeat_status != null || record.email_validation_status != null || record.linkedin_profile_status != null; return ( {!hasInternalHealth && !hasExternalHealth && (
{translate("crm.contact.health.no_data")}
)} {/* Internal Heartbeat (Relationship Strength) */} {hasInternalHealth && (
{translate("crm.contact.health.relationship_strength")}
{record.internal_heartbeat_score != null && (
{translate("crm.contact.health.engagement_score")} {record.internal_heartbeat_score}/100
)} {record.internal_heartbeat_status && (
)} {daysSince != null && (
{translate("crm.contact.health.last_activity")} {daysSince === 0 ? translate("crm.contact.health.today") : daysSince === 1 ? translate("crm.contact.health.yesterday") : translate("crm.contact.health.days_ago", { days: daysSince, })}
)}
)} {/* External Heartbeat (Contact Validation) */} {hasExternalHealth && (
{translate("crm.contact.health.contact_validation")}
{record.email_validation_status && (
{record.email_last_bounced_at && ( {translate("crm.contact.health.bounced")} )}
)} {record.linkedin_profile_status && (
)} {record.external_heartbeat_checked_at && (
{translate("crm.contact.health.validated")}{" "} {formatDistance( new Date(record.external_heartbeat_checked_at), new Date(), { addSuffix: true, locale: getDateFnsLocale(locale), }, )}
)}
)}
); };