From 28fe7093f4c02bfd68da1e0153f3876e3b536f8a Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Fri, 17 Apr 2026 12:31:51 +0200 Subject: [PATCH] ui: Enhance contact details page with improved layout and loading indicators --- apps/web/src/pages/contacts/[id].tsx | 671 +++++++++++++-------------- 1 file changed, 322 insertions(+), 349 deletions(-) diff --git a/apps/web/src/pages/contacts/[id].tsx b/apps/web/src/pages/contacts/[id].tsx index 4b21314..7ae72a6 100644 --- a/apps/web/src/pages/contacts/[id].tsx +++ b/apps/web/src/pages/contacts/[id].tsx @@ -2,17 +2,18 @@ import { Button, Card, CardContent, - CardDescription, CardHeader, CardTitle, ConfirmDialog, Input, Label, + Switch, } from '@plunk/ui'; import type {Contact} from '@plunk/db'; import {AnimatePresence, motion} from 'framer-motion'; -import {ArrowLeft, Check, Copy, Database, ExternalLink, Mail, Save, Settings, Trash2} from 'lucide-react'; +import {ArrowLeft, Check, Copy, Database, ExternalLink, Loader2, Save, Settings, Trash2} from 'lucide-react'; import Link from 'next/link'; +import {NextSeo} from 'next-seo'; import {useRouter} from 'next/router'; import {useEffect, useState} from 'react'; import {DashboardLayout} from '../../components/DashboardLayout'; @@ -36,7 +37,6 @@ export default function ContactDetailPage() { const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [copiedId, setCopiedId] = useState(null); - // Initialize form when contact loads useEffect(() => { if (contact) { setEmail(contact.email); @@ -75,14 +75,14 @@ export default function ContactDetailPage() { } }; - const copyToClipboard = async (url: string, label: string, id: string) => { + const copyToClipboard = async (text: string, label: string, copyId: string) => { try { - await navigator.clipboard.writeText(url); - setCopiedId(id); + await navigator.clipboard.writeText(text); + setCopiedId(copyId); setTimeout(() => setCopiedId(null), 2000); - toast.success(`${label} link copied to clipboard`); + toast.success(`${label} copied to clipboard`); } catch { - toast.error('Failed to copy link'); + toast.error('Failed to copy'); } }; @@ -90,22 +90,7 @@ export default function ContactDetailPage() { return (
-
- - - - -

Loading contact...

-
+
); @@ -131,354 +116,342 @@ export default function ContactDetailPage() { } return ( - -
- {/* Header */} -
-
- - - -
-

{contact.email}

-

- - {contact.subscribed ? 'Subscribed' : 'Unsubscribed'} - -

+ <> + + +
+ {/* Header */} +
+
+ + + +
+

{contact.email}

+

+ + {contact.subscribed ? 'Subscribed' : 'Unsubscribed'} + +

+
-
-
-
-
-
- {/* Edit Form */} -
- - - Contact Information - Update contact details and subscription status - - -
-
- - setEmail(e.target.value)} - required - placeholder="contact@example.com" - /> -
- -
-
- -

- {subscribed ? 'Contact will receive emails' : 'Contact will not receive emails'} -

-
- +
+ +
+
+ +

+ {subscribed ? 'Receives emails from campaigns and workflows' : 'Will not receive emails'} +

+
+ +
+ +
+ {contact && ( + | null} + onChange={setCustomData} + /> + )} +
+ + +
+
+
+ + {/* Activity Feed */} + + + Activity + + + + + +
+ + {/* Metadata Sidebar */} +
+ + + Details + + +
+ +
+

Contact ID

+
+

{contact.id}

+ +
+
- {contact && ( - | null} - onChange={setCustomData} - /> - )} -
- - - -
-
- - {/* Activity Feed */} - - - Activity Feed - Recent activity for this contact - - - - - -
- - {/* Metadata Sidebar */} -
- - - Metadata - - -
- -
-

Email

-

{contact.email}

-
-
- -
- -
-

Contact ID

-

{contact.id}

-
-
- -
-

Created

-
-

{dayjs(contact.createdAt).fromNow()}

-
- {dayjs(contact.createdAt).format('DD MMMM YYYY, hh:mm')} +

Created

+
+

{dayjs(contact.createdAt).fromNow()}

+
+ {dayjs(contact.createdAt).format('DD MMMM YYYY, hh:mm')} +
-
-
-

Last Updated

-
-

{dayjs(contact.updatedAt).fromNow()}

-
- {dayjs(contact.updatedAt).format('DD MMMM YYYY, hh:mm')} +
+

Last Updated

+
+

{dayjs(contact.updatedAt).fromNow()}

+
+ {dayjs(contact.updatedAt).format('DD MMMM YYYY, hh:mm')} +
-
- - + + - {/* Stats Card */} - - - Activity - Email engagement statistics - - -
- Emails Sent - 0 -
-
- Emails Opened - 0 -
-
- Links Clicked - 0 -
-
-
- - {/* Public Links Card */} - - - Public Links - Share these links with the contact - - -
-

Subscribe Page

-
- - + {/* Public Links Card */} + + + Public Links + + +
+

Subscribe Page

+
+ + +
-
-
-

Unsubscribe Page

-
- - +
+

Unsubscribe Page

+
+ + +
-
-
-

Manage Preferences

-
- - +
+

Manage Preferences

+
+ + +
-
- -
-

- These public links allow the contact to manage their subscription without logging in. -

-
- - + + +
-
- - + + + ); }