"use client" import { useMemo, useState } from "react" import { Pencil, X } from "lucide-react" import { Input } from "@/components/ui/input" import { FIELD_LABELS } from "@/lib/contacts/discovery-utils" import { CONTACTS_DISCOVERY_CHIP_CLASS, CONTACTS_DISCOVERY_GRID_CELL_CLASS, CONTACTS_MUTED_TEXT, } from "@/lib/contacts-chrome-classes" import { cn } from "@/lib/utils" export interface ChipFieldItem { id: string fieldKey: string value: string removed?: boolean } const FIELD_GROUP_ORDER = [ "first_name", "last_name", "full_name", "company", "department", "job_title", "emails", "phones", "addresses", "website", "social_profiles", "notes", ] as const function fieldSortIndex(fieldKey: string): number { const i = FIELD_GROUP_ORDER.indexOf(fieldKey as (typeof FIELD_GROUP_ORDER)[number]) return i === -1 ? 999 : i } function sortFieldKeys(keys: string[]): string[] { return [...keys].sort( (a, b) => fieldSortIndex(a) - fieldSortIndex(b) || a.localeCompare(b, "fr"), ) } function chipAccessibleLabel(fieldLabel: string, value: string): string { const v = value.trim() return v ? `${fieldLabel} : ${v}` : fieldLabel } function chipValueDedupeKey(fieldKey: string, value: string): string { const v = value.trim() if (fieldKey === "emails") return `emails:${v.toLowerCase()}` if (fieldKey === "phones") { const digits = v.replace(/\D/g, "") return digits.length >= 6 ? `phones:${digits}` : `phones:${v.toLowerCase()}` } if (fieldKey === "addresses") return `addresses:${v.toLowerCase()}` return `${fieldKey}:${v.toLowerCase()}` } export function groupChipFields(items: ChipFieldItem[], denseGrid = false) { const map = new Map() const seenValues = new Map>() for (const item of items) { if (item.removed) continue const perField = seenValues.get(item.fieldKey) ?? new Set() const dedupeKey = chipValueDedupeKey(item.fieldKey, item.value) if (perField.has(dedupeKey)) continue perField.add(dedupeKey) seenValues.set(item.fieldKey, perField) const list = map.get(item.fieldKey) ?? [] list.push(item) map.set(item.fieldKey, list) } const toGroup = (fieldKey: string) => ({ fieldKey, label: FIELD_LABELS[fieldKey] ?? fieldKey, items: map.get(fieldKey) ?? [], }) const keys = sortFieldKeys([...map.keys()]) if (!denseGrid) { return keys.map(toGroup) } const sparse: ReturnType[] = [] const dense: ReturnType[] = [] for (const fieldKey of keys) { const group = toGroup(fieldKey) if (group.items.length > 2) { dense.push(group) } else { sparse.push(group) } } return [...sparse, ...dense] } interface DiscoveryFieldChipsProps { items: ChipFieldItem[] /** Compact grid: 1 col < md, 2 cols md–lg, 3 cols xl+; dense fields span full row */ denseGrid?: boolean /** Pencil edit + remove */ editable?: boolean /** X only (e.g. reject suggestion) */ dismissible?: boolean onRemove?: (id: string) => void onValueChange?: (id: string, value: string) => void className?: string } export function DiscoveryFieldChips({ items, denseGrid = false, editable = false, dismissible = false, onRemove, onValueChange, className, }: DiscoveryFieldChipsProps) { const [editingId, setEditingId] = useState(null) const [editValue, setEditValue] = useState("") const groups = useMemo(() => groupChipFields(items, denseGrid), [items, denseGrid]) if (groups.length === 0) return null function startEdit(item: ChipFieldItem) { setEditingId(item.id) setEditValue(item.value) } function commitEdit(id: string) { const v = editValue.trim() if (!v) { onRemove?.(id) } else { onValueChange?.(id, v) } setEditingId(null) } return (
{groups.map((group) => (
2 && "md:col-span-2 xl:col-span-3", )} >

{group.label}

{group.items.map((item) => { const accessibleLabel = chipAccessibleLabel(group.label, item.value) return editingId === item.id ? ( setEditValue(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") commitEdit(item.id) if (e.key === "Escape") setEditingId(null) }} onBlur={() => commitEdit(item.id)} className="h-7 min-w-40 max-w-full flex-1 rounded-full px-3 text-xs" aria-label={`Modifier ${accessibleLabel}`} autoFocus /> ) : ( {item.value} {editable && ( )} {(editable || dismissible) && ( )} ) })}
))}
) }