import { ShowBase, useListContext, useRecordContext, useShowContext, useTranslate, useNotify, useRedirect, } from "ra-core"; import { useEffect } from "react"; import { Link as RouterLink } from "react-router-dom"; import { Receipt } from "lucide-react"; import { Button } from "@/components/ds/ui/button"; import { ReferenceField } from "@/components/ds/admin/reference-field"; import { ReferenceManyField } from "@/components/ds/admin/reference-many-field"; import { TextField } from "@/components/ds/admin/text-field"; import { Card, CardContent } from "@/components/ds/ui/card"; import { CompanyAvatar } from "../companies/CompanyAvatar"; import { NoteCreate, NotesIterator } from "../notes"; import { Avatar } from "./Avatar"; import { ContactAside } from "./ContactAside"; import { ActivityFeed } from "../activities/ActivityFeed"; import { InvoiceCard } from "../invoices"; import type { Contact, Invoice } from "../types"; const isCanceledRequestError = (value: unknown) => { if (!value) return false; const pending: unknown[] = [value]; const seen = new Set(); while (pending.length > 0) { const current = pending.pop(); if (!current || seen.has(current)) continue; seen.add(current); if (typeof current === "string") { const text = current.toLowerCase(); if ( text.includes("abort") || text.includes("canceled") || text.includes("cancelled") || text.includes("err_canceled") ) { return true; } continue; } if (typeof current !== "object") continue; const maybeError = current as { name?: unknown; message?: unknown; code?: unknown; details?: unknown; cause?: unknown; error?: unknown; reason?: unknown; }; const text = [ maybeError.name, maybeError.message, maybeError.code, maybeError.details, ] .filter((token): token is string => typeof token === "string") .map((token) => token.toLowerCase()) .join(" "); if ( text.includes("abort") || text.includes("canceled") || text.includes("cancelled") || text.includes("err_canceled") ) { return true; } if (maybeError.cause) pending.push(maybeError.cause); if (maybeError.error) pending.push(maybeError.error); if (maybeError.reason) pending.push(maybeError.reason); } return false; }; export const ContactShow = () => ( undefined }} > ); const ContactShowContent = () => { const { record, isPending, error } = useShowContext(); const translate = useTranslate(); const notify = useNotify(); const redirect = useRedirect(); // Handle error (contact not found) useEffect(() => { if (isPending || record || !error || isCanceledRequestError(error)) return; notify("Contact not found or has been deleted", { type: "error" }); redirect("/contacts"); }, [error, isPending, notify, record, redirect]); if (isPending || !record) return null; return (
{record.first_name} {record.last_name}
{record.title} {record.title && record.company_id != null && ` ${translate("crm.contact.field.at")} `} {record.company_id != null && (   )}
{/* Activity Timeline - Shows processing status (temporary) */}

{translate("crm.contact.section.activity_timeline")}

{translate("crm.contact.section.activity_timeline_description")}

{/* Notes - Permanent record of outcomes */}

{translate("crm.contact.section.notes")}

{translate("crm.contact.section.notes_description")}

} >
{/* Invoices Section */}

{translate("resources.invoices.name", { smart_count: 2 })}

); }; const InvoicesIterator = () => { const { data: invoices, error, isPending } = useListContext(); if (isPending || error) return null; return (
{invoices.map((invoice) => ( ))}
); }; const CreateRelatedInvoiceButton = () => { const contact = useRecordContext(); const translate = useTranslate(); return ( ); };