feat(uat-batch): Groups F + G + H — DocsHub/signing + admin consolidation + email
F27–F29, G30, G31, H32, H33 from the 2026-05-21 plan.
Shipped now:
F28 Past-milestones expandable history. The Past strip on the
Interest overview becomes an <Accordion> — each row collapses
to the same one-line summary as before, expands to render the
full <MilestoneSection> (steps list, sub-status, inline doc
actions). Reuses the existing MilestoneSection so no new
per-milestone rendering needs to be maintained.
F29 Watchers configurable at document creation time. The unified
create-document wizard gets a Watchers section with a
multi-select checkbox list backed by /api/v1/admin/users/picker.
Selected user ids are sent in the `watchers` array on the POST
(replacing the prior hardcoded `[]`). UI matches the
post-creation WatchersCard so reps see the same identity rows
regardless of entry point.
G30 /admin/invitations merged into /admin/users. The Users page
now wraps the existing UserList + InvitationsManager in a
Tabs control (Active users / Invitations). The standalone
/admin/invitations route returns a redirect to the merged page
for bookmark back-compat. Removed nav catalog entry +
admin-sections-browser tile; extended the Users catalog
keywords with "invitations / pending invites / onboarding"
so command-K search still lands on the right surface.
G31 /admin/ai picks up the berth-PDF-parser section + a "planned
AI surfaces" placeholder. Berth PDF parser remains
env-configured today; the page now documents it so admins
don't hunt for the controls. Closes the "where do I configure
AI?" loop.
H32 Email settings explainer panel above the SMTP cards. Spells
out why noreply + sales have separate credentials and which
workflows ship from each mailbox. Existing field titles
gained the "(noreply)" suffix so the model maps cleanly.
H33 Supplemental-info-request email rebuilt to use the shared
branded shell (logo + blurred overhead background + max-
width 600 table layout) instead of the prior plain-HTML
page. Per-port branding (logo / primary color / background /
header / footer) flows from getPortBrandingConfig. CTA
button picks up the port's primary color.
Already shipped (verified pre-shipped):
F27 DocumentsHub root view already hides the breadcrumb via
`selectedFolderId !== undefined` conditional.
Verified: tsc clean, vitest 1454/1454.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { Info } from 'lucide-react';
|
||||
|
||||
import { PageHeader } from '@/components/shared/page-header';
|
||||
import { RegistryDrivenForm } from '@/components/admin/shared/registry-driven-form';
|
||||
import { SalesEmailConfigCard } from '@/components/admin/sales-email-config-card';
|
||||
@@ -11,18 +13,43 @@ export default function EmailSettingsPage() {
|
||||
title="Email Settings"
|
||||
description="Per-port outgoing email configuration. SMTP credentials and the From address default to environment variables when these fields are blank. Header/footer HTML lives under Branding."
|
||||
/>
|
||||
|
||||
{/* Explainer for the "two accounts" model — addresses the recurring
|
||||
UAT question "why are there separate SMTP credentials for sales
|
||||
and noreply?". Keeps the answer in front of the admin before
|
||||
they reach the per-card form below. */}
|
||||
<div className="rounded-md border border-border bg-muted/40 px-4 py-3 text-sm">
|
||||
<div className="flex items-start gap-2">
|
||||
<Info className="mt-0.5 size-4 shrink-0 text-muted-foreground" aria-hidden />
|
||||
<div className="space-y-1 text-muted-foreground">
|
||||
<p>
|
||||
<strong className="text-foreground">Why two accounts?</strong> Transactional emails
|
||||
(signing invites, notifications, password resets) ship from your noreply mailbox over
|
||||
the SMTP credentials below. Rep-authored sales emails (one-off messages, proposal
|
||||
sends) ship from the sales mailbox with separate credentials so replies land in a
|
||||
human-monitored inbox.
|
||||
</p>
|
||||
<p>
|
||||
The noreply credentials are also used by the supplemental-info workflow + portal
|
||||
activation, i.e. anywhere the platform sends on its own initiative. The sales
|
||||
credentials are only used when a rep clicks Send in the compose UI.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Registry-driven so each field shows the "Using env fallback /
|
||||
port / global / default" badge inline — admins can tell at a
|
||||
glance which fields are coming from .env vs. UI overrides. */}
|
||||
<RegistryDrivenForm
|
||||
sections={['email.from']}
|
||||
title="From address"
|
||||
description="Identity headers used by system-generated emails."
|
||||
title="From address (noreply)"
|
||||
description="Identity headers used by system-generated emails. Set the From + Reply-To here; the matching SMTP credentials live in the next card."
|
||||
/>
|
||||
<RegistryDrivenForm
|
||||
sections={['email.smtp']}
|
||||
title="SMTP transport overrides"
|
||||
description="Optional per-port SMTP credentials. Leave blank to use the global env defaults. Each field shows its current source (env / port / default) so you can tell what's active without checking the deploy."
|
||||
title="SMTP transport overrides (noreply)"
|
||||
description="Optional per-port SMTP credentials for the noreply mailbox. Leave blank to use the global env defaults. Each field shows its current source (env / port / default) so you can tell what's active without checking the deploy."
|
||||
/>
|
||||
<SmtpTestSendCard />
|
||||
<SalesEmailConfigCard />
|
||||
|
||||
Reference in New Issue
Block a user