initial commit after split
This commit is contained in:
97
webui/src/features/addressbook/AddressBookPage.tsx
Normal file
97
webui/src/features/addressbook/AddressBookPage.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import Button from "../../components/Button";
|
||||
import Card from "../../components/Card";
|
||||
import PageTitle from "../../components/PageTitle";
|
||||
import StatusBadge from "../../components/StatusBadge";
|
||||
import DataGrid, { type DataGridColumn } from "../../components/table/DataGrid";
|
||||
|
||||
const personalContacts = [
|
||||
{ name: "Ada Lovelace", email: "ada@example.local", source: "Personal", tags: "Used recently" },
|
||||
{ name: "Grace Hopper", email: "grace@example.local", source: "Personal", tags: "Favorite" }
|
||||
];
|
||||
|
||||
const groupContacts = [
|
||||
{ name: "Project Office", email: "project-office@example.local", source: "Group", tags: "Shared" },
|
||||
{ name: "Finance Team", email: "finance@example.local", source: "Group", tags: "Shared list" }
|
||||
];
|
||||
|
||||
const tenantContacts = [
|
||||
{ name: "Helpdesk", email: "helpdesk@example.local", source: "Tenant", tags: "Directory" },
|
||||
{ name: "Data Protection", email: "privacy@example.local", source: "Tenant", tags: "Directory" }
|
||||
];
|
||||
|
||||
function contactColumns(): DataGridColumn<{ name: string; email: string; source: string; tags: string }>[] {
|
||||
return [
|
||||
{ id: "name", header: "Name", width: "minmax(180px, 1fr)", sortable: true, filterable: true, sticky: "start", render: (contact) => <strong>{contact.name}</strong>, value: (contact) => contact.name },
|
||||
{ id: "email", header: "Email", width: 240, sortable: true, filterable: true, value: (contact) => contact.email },
|
||||
{ id: "scope", header: "Scope", width: 140, sortable: true, filterable: true, columnType: "from-list", list: { options: [{ value: "Personal", label: "Personal" }, { value: "Group", label: "Group" }, { value: "Tenant", label: "Tenant" }] }, value: (contact) => contact.source },
|
||||
{ id: "tags", header: "Tags", width: 180, sortable: true, filterable: true, value: (contact) => contact.tags },
|
||||
{ id: "status", header: "Status", width: 130, sortable: true, filterable: true, columnType: "from-list", list: { options: [{ value: "mock", label: "Mock" }], display: "pill" }, render: () => <StatusBadge status="mock" />, value: () => "mock" }
|
||||
];
|
||||
}
|
||||
|
||||
export default function AddressBookPage() {
|
||||
const allContacts = [...personalContacts, ...groupContacts, ...tenantContacts];
|
||||
|
||||
return (
|
||||
<div className="content-pad workspace-data-page module-entry-page address-book-page">
|
||||
<div className="page-heading split workspace-heading">
|
||||
<div>
|
||||
<PageTitle>Address Book</PageTitle>
|
||||
<p>Mock workspace for personal, group and tenant address books. These contacts can later feed recipient autocomplete and reusable address selections.</p>
|
||||
</div>
|
||||
<div className="button-row compact-actions">
|
||||
<Button disabled>Import</Button>
|
||||
<Button variant="primary" disabled>Add contact</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="metric-grid">
|
||||
<Card title="Personal"><strong className="module-big-number">{personalContacts.length}</strong><p className="muted">Private contacts and remembered addresses.</p></Card>
|
||||
<Card title="Group"><strong className="module-big-number">{groupContacts.length}</strong><p className="muted">Shared group address books and lists.</p></Card>
|
||||
<Card title="Tenant"><strong className="module-big-number">{tenantContacts.length}</strong><p className="muted">Tenant directory and approved shared contacts.</p></Card>
|
||||
<Card title="Sync"><strong className="module-big-number">Mock</strong><p className="muted">CardDAV/LDAP/import connectors can be added later.</p></Card>
|
||||
</div>
|
||||
|
||||
<div className="dashboard-grid settings-dashboard-grid">
|
||||
<Card title="Address book scopes">
|
||||
<div className="address-book-scope-list">
|
||||
<AddressBookScope title="Personal address book" description="Private contacts, remembered recipients and personal aliases." status="Local" />
|
||||
<AddressBookScope title="Group address books" description="Shared contact sets for teams, departments or campaign groups." status="Shared" />
|
||||
<AddressBookScope title="Tenant directory" description="Tenant-wide contacts, functional mailboxes and approved lists." status="Directory" />
|
||||
</div>
|
||||
</Card>
|
||||
<Card title="Planned address actions">
|
||||
<div className="placeholder-stack">
|
||||
<span>Choose addresses from personal, group or tenant source</span>
|
||||
<span>Remember addresses used in campaigns after opt-in</span>
|
||||
<span>Share selected contacts with a group</span>
|
||||
<span>Use contacts in To, CC, BCC, sender and Reply-To fields</span>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card title="Contacts" actions={<Button disabled>Manage sources</Button>}>
|
||||
<DataGrid
|
||||
id="address-book-contacts"
|
||||
rows={allContacts}
|
||||
columns={contactColumns()}
|
||||
getRowKey={(contact) => contact.source + "-" + contact.email}
|
||||
emptyText="No contacts found."
|
||||
className="compact-table-wrap module-table"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AddressBookScope({ title, description, status }: { title: string; description: string; status: string }) {
|
||||
return (
|
||||
<div className="address-book-scope-card">
|
||||
<div>
|
||||
<strong>{title}</strong>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
<StatusBadge status={status} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user