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,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { ArrowLeft, Plus, Trash2 } from 'lucide-react';
|
||||
import { ArrowLeft, Eye, Plus, Trash2 } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -78,6 +78,23 @@ export function CreateDocumentWizard({ portSlug }: CreateDocumentWizardProps) {
|
||||
const [subjectType, setSubjectType] = useState<(typeof SUBJECT_TYPES)[number]['key']>('interest');
|
||||
const [subjectId, setSubjectId] = useState('');
|
||||
|
||||
// Watchers picked at create-time. Each selected user gets an in-app
|
||||
// notification on every signing event (opened, signed, declined,
|
||||
// completed) once the document is created. Same surface the
|
||||
// post-creation WatchersCard exposes, but lets the rep wire it
|
||||
// upfront instead of digging into the detail page afterwards.
|
||||
const [watcherUserIds, setWatcherUserIds] = useState<string[]>([]);
|
||||
const [watcherUsers, setWatcherUsers] = useState<
|
||||
Array<{ id: string; name: string | null; email: string | null }>
|
||||
>([]);
|
||||
useEffect(() => {
|
||||
void apiFetch<{
|
||||
data: Array<{ id: string; name: string | null; email: string | null }>;
|
||||
}>('/api/v1/admin/users/picker')
|
||||
.then((res) => setWatcherUsers(res.data ?? []))
|
||||
.catch(() => setWatcherUsers([]));
|
||||
}, []);
|
||||
|
||||
const [signers, setSigners] = useState<SignerRow[]>([
|
||||
{ signerName: '', signerEmail: '', signerRole: 'client', signingOrder: 1 },
|
||||
]);
|
||||
@@ -154,7 +171,7 @@ export function CreateDocumentWizard({ portSlug }: CreateDocumentWizardProps) {
|
||||
notes: notes.trim() || undefined,
|
||||
[subjectField]: subjectId.trim(),
|
||||
signingMode,
|
||||
watchers: [],
|
||||
watchers: watcherUserIds,
|
||||
autoPlaceFields: true,
|
||||
sendImmediately: false,
|
||||
remindersDisabled: reminderMode === 'disabled',
|
||||
@@ -427,6 +444,45 @@ export function CreateDocumentWizard({ portSlug }: CreateDocumentWizardProps) {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="rounded-md border bg-white p-4 lg:col-span-2">
|
||||
<h2 className="mb-3 flex items-center gap-1.5 text-sm font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
<Eye className="size-3.5" aria-hidden />
|
||||
Watchers
|
||||
</h2>
|
||||
<p className="mb-2 text-xs text-muted-foreground">
|
||||
Selected users receive an in-app notification on every signing event (opened, signed,
|
||||
declined, completed). Can be edited from the document detail page after creation.
|
||||
</p>
|
||||
{watcherUsers.length === 0 ? (
|
||||
<p className="text-xs italic text-muted-foreground">No users available to add.</p>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 gap-1 sm:grid-cols-2">
|
||||
{watcherUsers.map((u) => {
|
||||
const checked = watcherUserIds.includes(u.id);
|
||||
return (
|
||||
<label
|
||||
key={u.id}
|
||||
className="flex cursor-pointer items-center gap-2 rounded-sm px-1 py-0.5 text-sm hover:bg-muted/50"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
onChange={() =>
|
||||
setWatcherUserIds((prev) =>
|
||||
checked ? prev.filter((id) => id !== u.id) : [...prev, u.id],
|
||||
)
|
||||
}
|
||||
/>
|
||||
<span className="truncate">
|
||||
{u.name ?? u.email ?? `User ${u.id.slice(0, 8)}…`}
|
||||
</span>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
<section className="rounded-md border bg-white p-4 lg:col-span-2">
|
||||
<h2 className="mb-3 text-sm font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
Reminders
|
||||
|
||||
Reference in New Issue
Block a user