From 77f99d8d8a276e513168198637c7c0ef8e28ec84 Mon Sep 17 00:00:00 2001 From: R3D347HR4Y Date: Tue, 19 May 2026 00:48:20 +0200 Subject: [PATCH] hehe --- app/contacts/[[...slug]]/page.tsx | 7 + app/contacts/layout.tsx | 13 + .../contacts-page/add-coordinates-view.tsx | 113 ++++ .../contacts-page/bulk-create-dialog.tsx | 71 +++ .../contacts-page/contact-create-page.tsx | 507 ++++++++++++++++++ .../contacts-page/contact-detail-page.tsx | 248 +++++++++ .../contacts-page/contacts-app-shell.tsx | 124 +++++ .../gmail/contacts-page/contacts-header.tsx | 40 ++ .../gmail/contacts-page/contacts-sidebar.tsx | 233 ++++++++ .../gmail/contacts-page/contacts-table.tsx | 356 ++++++++++++ .../gmail/contacts-page/import-dialog.tsx | 153 ++++++ components/gmail/contacts-page/index.ts | 1 + .../contacts-page/merge-duplicates-view.tsx | 223 ++++++++ components/gmail/contacts-page/trash-view.tsx | 119 ++++ .../gmail/contacts/contacts-list-view.tsx | 5 +- components/gmail/header-account-actions.tsx | 106 ++++ components/gmail/header.tsx | 94 +--- lib/contacts/contacts-store.ts | 193 ++++++- lib/contacts/duplicate-detection.ts | 137 +++++ lib/contacts/export-contacts.ts | 118 ++++ lib/contacts/import-parsers.ts | 314 +++++++++++ lib/contacts/index.ts | 29 +- lib/contacts/mock-data.ts | 28 +- lib/contacts/print-contacts.ts | 69 +++ lib/contacts/types.ts | 2 + next-env.d.ts | 2 +- tsconfig.tsbuildinfo | 2 +- 27 files changed, 3195 insertions(+), 112 deletions(-) create mode 100644 app/contacts/[[...slug]]/page.tsx create mode 100644 app/contacts/layout.tsx create mode 100644 components/gmail/contacts-page/add-coordinates-view.tsx create mode 100644 components/gmail/contacts-page/bulk-create-dialog.tsx create mode 100644 components/gmail/contacts-page/contact-create-page.tsx create mode 100644 components/gmail/contacts-page/contact-detail-page.tsx create mode 100644 components/gmail/contacts-page/contacts-app-shell.tsx create mode 100644 components/gmail/contacts-page/contacts-header.tsx create mode 100644 components/gmail/contacts-page/contacts-sidebar.tsx create mode 100644 components/gmail/contacts-page/contacts-table.tsx create mode 100644 components/gmail/contacts-page/import-dialog.tsx create mode 100644 components/gmail/contacts-page/index.ts create mode 100644 components/gmail/contacts-page/merge-duplicates-view.tsx create mode 100644 components/gmail/contacts-page/trash-view.tsx create mode 100644 components/gmail/header-account-actions.tsx create mode 100644 lib/contacts/duplicate-detection.ts create mode 100644 lib/contacts/export-contacts.ts create mode 100644 lib/contacts/import-parsers.ts create mode 100644 lib/contacts/print-contacts.ts diff --git a/app/contacts/[[...slug]]/page.tsx b/app/contacts/[[...slug]]/page.tsx new file mode 100644 index 0000000..5cbac21 --- /dev/null +++ b/app/contacts/[[...slug]]/page.tsx @@ -0,0 +1,7 @@ +"use client" + +import { ContactsAppShell } from "@/components/gmail/contacts-page/contacts-app-shell" + +export default function ContactsPage() { + return +} diff --git a/app/contacts/layout.tsx b/app/contacts/layout.tsx new file mode 100644 index 0000000..66c05ef --- /dev/null +++ b/app/contacts/layout.tsx @@ -0,0 +1,13 @@ +import type { Metadata } from "next" + +export const metadata: Metadata = { + title: "Contacts - Ultimail", +} + +export default function ContactsLayout({ + children, +}: { + children: React.ReactNode +}) { + return children +} diff --git a/components/gmail/contacts-page/add-coordinates-view.tsx b/components/gmail/contacts-page/add-coordinates-view.tsx new file mode 100644 index 0000000..0141135 --- /dev/null +++ b/components/gmail/contacts-page/add-coordinates-view.tsx @@ -0,0 +1,113 @@ +"use client" + +import { useMemo, useState } from "react" +import { Button } from "@/components/ui/button" +import { useContactsStore } from "@/lib/contacts/contacts-store" +import { fullContactDisplayName } from "@/lib/contacts/types" +import { avatarColor, senderInitial } from "@/lib/sender-display" + +export function AddCoordinatesView() { + const { getCoordinateSuggestions, updateContact } = useContactsStore() + const suggestions = useMemo(() => getCoordinateSuggestions(), [getCoordinateSuggestions]) + const [dismissed, setDismissed] = useState>(new Set()) + + const visible = suggestions.filter((s) => !dismissed.has(s.contact.id)) + + function handleAdd(contactId: string, field: string, value: string) { + updateContact(contactId, { [field]: value }) + setDismissed((s) => new Set(s).add(contactId)) + } + + function handleIgnore(contactId: string) { + setDismissed((s) => new Set(s).add(contactId)) + } + + function handleAddAll() { + for (const s of visible) { + updateContact(s.contact.id, { [s.suggestedField]: s.suggestedValue }) + } + setDismissed(new Set(suggestions.map((s) => s.contact.id))) + } + + return ( +
+
+

+ Ajouter des coordonnées ({visible.length}) +

+ {visible.length > 0 && ( + + )} +
+ + {visible.length === 0 && ( +

+ Aucune suggestion disponible +

+ )} + +
+ {visible.map((suggestion) => { + const { contact, suggestedField, suggestedValue } = suggestion + const displayName = fullContactDisplayName(contact) + const name = displayName || contact.emails[0]?.value || "?" + const color = avatarColor(name) + const initial = senderInitial(name) + + return ( +
+

Contact à modifier

+
+ {contact.avatarUrl ? ( + {name} + ) : ( +
+ {initial} +
+ )} +
+

{name}

+ {contact.emails[0] && ( +

{contact.emails[0].value}

+ )} + {contact.phones[0] && ( +

{contact.phones[0].value} ({contact.phones[0].label})

+ )} +
+
+ +
+

Détails à ajouter

+

{suggestedValue}

+
+ +
+ + +
+
+ ) + })} +
+
+ ) +} diff --git a/components/gmail/contacts-page/bulk-create-dialog.tsx b/components/gmail/contacts-page/bulk-create-dialog.tsx new file mode 100644 index 0000000..92a3b45 --- /dev/null +++ b/components/gmail/contacts-page/bulk-create-dialog.tsx @@ -0,0 +1,71 @@ +"use client" + +import { useState } from "react" +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { Button } from "@/components/ui/button" +import { useContactsStore } from "@/lib/contacts/contacts-store" +import { parseBulkContactText } from "@/lib/contacts/import-parsers" + +interface BulkCreateDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + onOpenImport?: () => void +} + +export function BulkCreateDialog({ open, onOpenChange, onOpenImport }: BulkCreateDialogProps) { + const [input, setInput] = useState("") + const addContacts = useContactsStore((s) => s.addContacts) + + function handleCreate() { + const parsed = parseBulkContactText(input) + if (parsed.length === 0) return + + addContacts(parsed) + setInput("") + onOpenChange(false) + } + + return ( + + + + Créer plusieurs contacts + +
+

+ Ajoutez des noms, des adresses e-mail ou les deux +

+