chore(autonomous-session): consolidate uncommitted work from prior session
Bundles the prior autonomous-session output that was sitting unstaged: - Em-dash sweep across src/ + tests/ (en-dash/em-dash to hyphen, ~2280 instances) - country-flag-icons rollout (CountryFlag component, replaces emoji glyphs that never rendered on Windows; lazy-loads the 3x2 SVG index as a single chunk after the per-subpath dynamic-import approach silently failed in webpack) - Admin IA Phase 1+2: 7-domain regroup, 41 to 38 pages, /admin/berths index, redirects (ocr to ai, reports to dashboard, invitations to users), docs/admin-ia-proposal.md - Per-template email tester (registry + endpoint + UI on Email admin page) - Cancel-document mode picker (delete-from-Documenso vs keep-for-audit) - Dashboard PDF report: 25 widgets, SVG charts, date-range picker, 11 resolvers - Customize-widgets per-region sortables at xl+ (charts/rails/feed); single flat sortable below xl when the layout stacks; per-viewport saved orders - Audit doc updates capturing each shipped item - Lint fixes: react-compiler immutability in DonutChart (reduce instead of let-reassign), set-state-in-effect disables in CountryFlag and UploadForSigning preview-bytes effect, unused 'confirm' destructures in interest contract + reservation tabs, unescaped apostrophe in test-template card copy
This commit is contained in:
@@ -23,7 +23,7 @@ import { FieldHistoryProvider, FieldHistoryIcon } from '@/components/shared/fiel
|
||||
import { ClientChannelEditor } from '@/components/clients/client-channel-editor';
|
||||
import { InlineTagEditor } from '@/components/shared/inline-tag-editor';
|
||||
import { RemindersInline } from '@/components/reminders/reminders-inline';
|
||||
// Legacy `RecommendationList` removed 2026-05-15 — replaced by the same
|
||||
// Legacy `RecommendationList` removed 2026-05-15 - replaced by the same
|
||||
// rule-based `BerthRecommenderPanel` (already imported above) used on the
|
||||
// Overview tab so the scoring + UI stay consistent. The old component
|
||||
// pulled stale "AI"-style rows that all scored 50% because the underlying
|
||||
@@ -111,7 +111,7 @@ interface InterestTabsOptions {
|
||||
desiredLengthM?: string | null;
|
||||
desiredWidthM?: string | null;
|
||||
desiredDraftM?: string | null;
|
||||
/** Unit the rep originally entered the dims in — drives the
|
||||
/** Unit the rep originally entered the dims in - drives the
|
||||
* recommender header's display so a metric-entered deal doesn't
|
||||
* render as ft. The three columns share an entry unit in practice. */
|
||||
desiredLengthUnit?: string | null;
|
||||
@@ -125,25 +125,25 @@ interface InterestTabsOptions {
|
||||
* auto-advance once payment totals catch up. */
|
||||
depositExpectedAmount?: string | null;
|
||||
depositExpectedCurrency?: string | null;
|
||||
/** Doc-bearing stage sub-status badges — drive the milestone past/current
|
||||
/** Doc-bearing stage sub-status badges - drive the milestone past/current
|
||||
* classification independently of the pipeline stage. NULL until the
|
||||
* matching stage is reached. */
|
||||
eoiDocStatus?: string | null;
|
||||
reservationDocStatus?: string | null;
|
||||
contractDocStatus?: string | null;
|
||||
/** Final outcome — 'won' surfaces the wrap-up checklist panel. */
|
||||
/** Final outcome - 'won' surfaces the wrap-up checklist panel. */
|
||||
outcome?: string | null;
|
||||
/** Interest id — needed for the queryClient.invalidateQueries calls
|
||||
/** Interest id - needed for the queryClient.invalidateQueries calls
|
||||
* that fire after an inline contact edit. The parent passes this
|
||||
* through `interestId` already, but the inline-edit handlers below
|
||||
* use the structured object form. */
|
||||
id: string;
|
||||
/** Linked client id — required for the PATCH /api/v1/clients/[id]/
|
||||
/** Linked client id - required for the PATCH /api/v1/clients/[id]/
|
||||
* contacts/[contactId] flow that the inline Email + Phone editors
|
||||
* use. Null on an unlinked interest (rare but possible). */
|
||||
clientId: string | null;
|
||||
/** Primary contact channels resolved from the linked client record by
|
||||
* getInterestById — both editable inline. The contact row's id is
|
||||
* getInterestById - both editable inline. The contact row's id is
|
||||
* exposed alongside so the inline editor can PATCH the right row
|
||||
* without an extra fetch. */
|
||||
clientPrimaryEmail?: string | null;
|
||||
@@ -163,7 +163,7 @@ interface InterestTabsOptions {
|
||||
reminderEnabled: boolean;
|
||||
reminderDays: number | null;
|
||||
reminderLastFired: string | null;
|
||||
/** Count of berths linked via the interest_berths junction —
|
||||
/** Count of berths linked via the interest_berths junction -
|
||||
* drives the "Berth Interest" milestone on the Overview tab. */
|
||||
linkedBerthCount?: number;
|
||||
notes: string | null;
|
||||
@@ -391,7 +391,7 @@ function MilestoneAdvanceButton({
|
||||
* Skip-ahead backfill control: shown next to past milestones whose
|
||||
* date column is null. Opens the same date popover as
|
||||
* MilestoneAdvanceButton but PATCHes the date column directly without
|
||||
* triggering a stage transition — the stage was already advanced
|
||||
* triggering a stage transition - the stage was already advanced
|
||||
* manually upstream.
|
||||
*/
|
||||
function MilestoneBackfillButton({
|
||||
@@ -640,7 +640,7 @@ function OverviewTab({
|
||||
const portSlug = params?.portSlug ?? '';
|
||||
// QueryClient lifted to the top of the tab so the inline-edit email +
|
||||
// Lift the EOI generate dialog into the Overview so the milestone card
|
||||
// can launch it inline — same dialog the dedicated EOI tab uses, so the
|
||||
// can launch it inline - same dialog the dedicated EOI tab uses, so the
|
||||
// editing/confirmation flow is identical regardless of entry point.
|
||||
const [eoiGenerateOpen, setEoiGenerateOpen] = useState(false);
|
||||
const mutation = useInterestPatch(interestId);
|
||||
@@ -681,14 +681,14 @@ function OverviewTab({
|
||||
};
|
||||
|
||||
// Determine each milestone's phase relative to the current pipeline
|
||||
// stage. The overview hides future-phase milestones by default — it
|
||||
// stage. The overview hides future-phase milestones by default - it
|
||||
// was visually noisy to see Deposit + Contract cards on a deal still
|
||||
// at the EOI stage, and the empty cards invited mis-clicks.
|
||||
//
|
||||
// Past milestones still render (collapsed history) so reps can see
|
||||
// what's been completed. Future milestones are gated behind a "Show
|
||||
// upcoming milestones" toggle so the rep CAN reach them when a deal
|
||||
// genuinely skips stages — the click then routes through the same
|
||||
// genuinely skips stages - the click then routes through the same
|
||||
// override-confirm flow as the inline stage picker.
|
||||
const stageIdx = PIPELINE_STAGES.indexOf(interest.pipelineStage as PipelineStage);
|
||||
const reservationIdx = PIPELINE_STAGES.indexOf('reservation');
|
||||
@@ -707,7 +707,7 @@ function OverviewTab({
|
||||
// pipeline-stage column happens to sit. The previous "phase === current
|
||||
// only when stageIdx exactly matches" rule produced an empty Overview
|
||||
// for the qualified + nurturing stages (no milestone marked current, EOI
|
||||
// hidden under "show upcoming") — exactly the gap the rep complained
|
||||
// hidden under "show upcoming") - exactly the gap the rep complained
|
||||
// about. New model: the FIRST not-yet-complete milestone in the fixed
|
||||
// berth_interest → eoi → reservation → deposit → contract order is
|
||||
// 'current'. Everything before is 'past'; everything after is 'future'.
|
||||
@@ -727,7 +727,7 @@ function OverviewTab({
|
||||
// the deal's current pipelineStage column. When the rep manually
|
||||
// jumps the stage forward (Reservation+) but earlier sub-statuses
|
||||
// are still un-signed, we need the current-stage milestone to stay
|
||||
// marked `'current'` regardless of completion — otherwise EOI gets
|
||||
// marked `'current'` regardless of completion - otherwise EOI gets
|
||||
// flagged as NEXT STEP and the actual current stage hides under
|
||||
// "Upcoming milestones". Earlier-than-stage milestones go to
|
||||
// `'past'` so the rep can render backfill controls against them.
|
||||
@@ -749,7 +749,7 @@ function OverviewTab({
|
||||
if (k === firstIncompleteKey) return 'current';
|
||||
return 'future';
|
||||
}
|
||||
// A stage DOES own a different milestone — bucket by position
|
||||
// A stage DOES own a different milestone - bucket by position
|
||||
// relative to it. Earlier slots go to `past` even if incomplete
|
||||
// (the backfill controls live there); later slots go to `future`.
|
||||
const idx = order.indexOf(k);
|
||||
@@ -797,12 +797,12 @@ function OverviewTab({
|
||||
phase: berthInterestPhase,
|
||||
title: 'Berth Interest',
|
||||
icon: Anchor,
|
||||
// No status badge — the count IS the status. Showing "0 berths"
|
||||
// No status badge - the count IS the status. Showing "0 berths"
|
||||
// would just duplicate the empty-state copy below.
|
||||
status: hasLinkedBerth
|
||||
? `${interest.linkedBerthCount} berth${(interest.linkedBerthCount ?? 0) === 1 ? '' : 's'}`
|
||||
: null,
|
||||
// No advanceStage step — the milestone tracks a state (berths
|
||||
// No advanceStage step - the milestone tracks a state (berths
|
||||
// linked) rather than a stage transition. Hide the row chrome by
|
||||
// passing an empty steps array; the footer renders the action.
|
||||
steps: [],
|
||||
@@ -846,8 +846,8 @@ function OverviewTab({
|
||||
// When the EOI milestone is the active next step but nothing's been
|
||||
// sent yet, surface the actual generation entry points instead of
|
||||
// making the rep navigate to the EOI tab first. Mirrors the EOI
|
||||
// tab's Generate flow exactly — same dialog component, same
|
||||
// confirmation step — so behaviour stays consistent.
|
||||
// tab's Generate flow exactly - same dialog component, same
|
||||
// confirmation step - so behaviour stays consistent.
|
||||
footer:
|
||||
eoiPhase === 'current' && !interest.dateEoiSent ? (
|
||||
<div className="flex flex-wrap items-center gap-2 pt-1">
|
||||
@@ -1062,7 +1062,7 @@ function OverviewTab({
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
{/* Reuse the same MilestoneSection layout used for the
|
||||
current milestone — the steps list, sub-status badge,
|
||||
current milestone - the steps list, sub-status badge,
|
||||
and any inline doc actions all render the same way.
|
||||
`isActive={false}` keeps the NEXT-STEP pill off. */}
|
||||
<MilestoneSection
|
||||
@@ -1329,7 +1329,7 @@ function OverviewTab({
|
||||
stands today; reading it on Overview, "current stage"
|
||||
answers the implicit "where in the deal is this?". A
|
||||
historical "stage-at-note-time" lookup would need an
|
||||
audit_logs read per teaser render — over-engineered for
|
||||
audit_logs read per teaser render - over-engineered for
|
||||
a context hint. */}
|
||||
<span
|
||||
className={cn(
|
||||
@@ -1424,7 +1424,7 @@ export function getInterestTabs({
|
||||
clientId = null,
|
||||
interest,
|
||||
}: InterestTabsOptions): DetailTab[] {
|
||||
// The EOI / Contract / Reservation tabs are stage-conditional —
|
||||
// The EOI / Contract / Reservation tabs are stage-conditional -
|
||||
// each appears only at the stages where the rep is likely to act
|
||||
// on it. Hides clutter from later-stage deals where earlier docs
|
||||
// are ancient history. Each tab still queries for its own past
|
||||
@@ -1437,7 +1437,7 @@ export function getInterestTabs({
|
||||
const contractIdx = PIPELINE_STAGES.indexOf('contract');
|
||||
// EOI: from qualified through contract (the deal's whole life past lead-only).
|
||||
const showEoiTab = stageIdx >= qualifiedIdx;
|
||||
// Reservation: once the EOI is signed onward — the reservation agreement
|
||||
// Reservation: once the EOI is signed onward - the reservation agreement
|
||||
// is the v1 step between EOI and deposit. Stays visible through contract
|
||||
// so the rep can re-open the signed reservation later.
|
||||
const showReservationTab = stageIdx >= reservationIdx;
|
||||
|
||||
Reference in New Issue
Block a user