fix(uat): batch — timeline overshoot, name-sync, reset-password, dashboard cleanup, queue/seed hygiene + alpha UAT findings doc
UAT findings landed across the last few Playwright + React Grab passes; single grouped commit so the index doesn't fragment into 30 one-liners. User & auth: - `user-settings`: name now updates the avatar + topbar menu after save (was reading stale session). - `me/password-reset`: 3 bugs (token validation, error response shape, redirect chain). - Admin user permission-overrides route honours the same envelope as the rest of the admin surface. Dashboard: - Removed obsolete `revenue-breakdown-chart` + `dashboard-widgets-card` (replaced by the customisable widget grid). - Strip `revenue_breakdown` from analytics route + use-analytics + service + integration test so nothing renders an empty card. - Activity log timeline overshoot fix (`interest-timeline` + `entity-activity-feed`). - Tightened tiles: active-deals, berth-heat-widget, pipeline-value, kpi-tile. - `dev-mode-banner`: derive dismissed state synchronously instead of via an effect (set-state-in-effect lint rule). Forms & lists (assorted polish): - client / company / yacht / interest / reminder forms — validation + empty-state copy + tab transitions. - companies/yachts list tweaks; berth recommender panel; qualification checklist; supplemental info request button. Infra & misc: - Queue workers (ai / email / notifications) — log shape + per-job timeout consistency. - Auth / brochures / users schema small adjustments; seeds reflect permissions matrix changes. - Scan shell + scanner manifest + AI admin page small fixes. - `next.config.transpilePackages` adds `echarts`/`zrender`/`echarts-for-react` (recommended config from echarts-for-react inside Next). Docs: - `docs/superpowers/audits/alpha-uat-master.md` — single rolling cross-cutting UAT findings doc (per CLAUDE.md convention). - `docs/BACKLOG.md`: dashboard stats cards (§I) + activity-log normalization (§J). - 2026-05-18 audit log updated with this batch. - `CLAUDE.md` — small manual UAT scaffold notes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -165,8 +165,15 @@ export async function getRevenueForecast(portId: string) {
|
||||
.innerJoin(berths, eq(interestBerths.berthId, berths.id))
|
||||
.where(activeInterestsWhere(portId));
|
||||
|
||||
// Build stageBreakdown
|
||||
const stageMap: Record<string, { count: number; weightedValue: number }> = {};
|
||||
// Build stageBreakdown — gross value, weighted value, per-stage weight,
|
||||
// and `dealsMissingPrice` (deals whose primary berth has no/zero price)
|
||||
// all surface to callers. The dashboard tile shows a warning chip when
|
||||
// any deals in a stage are missing a berth price so the $0 line item
|
||||
// doesn't read as legitimate.
|
||||
const stageMap: Record<
|
||||
string,
|
||||
{ count: number; grossValue: number; weightedValue: number; dealsMissingPrice: number }
|
||||
> = {};
|
||||
|
||||
for (const row of interestRows) {
|
||||
const stage = row.pipelineStage ?? 'open';
|
||||
@@ -175,21 +182,28 @@ export async function getRevenueForecast(portId: string) {
|
||||
const weighted = price * weight;
|
||||
|
||||
if (!stageMap[stage]) {
|
||||
stageMap[stage] = { count: 0, weightedValue: 0 };
|
||||
stageMap[stage] = { count: 0, grossValue: 0, weightedValue: 0, dealsMissingPrice: 0 };
|
||||
}
|
||||
stageMap[stage]!.count += 1;
|
||||
stageMap[stage]!.grossValue += price;
|
||||
stageMap[stage]!.weightedValue += weighted;
|
||||
if (!(price > 0)) stageMap[stage]!.dealsMissingPrice += 1;
|
||||
}
|
||||
|
||||
const stageBreakdown = PIPELINE_STAGES.map((stage) => ({
|
||||
stage,
|
||||
count: stageMap[stage]?.count ?? 0,
|
||||
grossValue: stageMap[stage]?.grossValue ?? 0,
|
||||
weightedValue: stageMap[stage]?.weightedValue ?? 0,
|
||||
weight: weights[stage] ?? 0,
|
||||
dealsMissingPrice: stageMap[stage]?.dealsMissingPrice ?? 0,
|
||||
}));
|
||||
|
||||
const totalGrossValue = stageBreakdown.reduce((acc, s) => acc + s.grossValue, 0);
|
||||
const totalWeightedValue = stageBreakdown.reduce((acc, s) => acc + s.weightedValue, 0);
|
||||
|
||||
return {
|
||||
totalGrossValue,
|
||||
totalWeightedValue,
|
||||
stageBreakdown,
|
||||
weightsSource,
|
||||
|
||||
Reference in New Issue
Block a user