share parseMeasures helper, accept ; and , separators

This commit is contained in:
Khalim Conn-Kowlessar 2026-05-05 11:25:54 +00:00
parent dc3bfa73d3
commit 35d0af4474
3 changed files with 22 additions and 10 deletions

View file

@ -0,0 +1,20 @@
/**
* Parses a measure-list string from the HubSpot pull pipeline.
*
* HubSpot's `proposed_measures` field is delivered as a semicolon-separated
* list (its native multi-select format). Earlier records were sometimes stored
* as comma-separated strings, and freeform text from contractors may use either
* separator. To keep the UI tolerant we accept both `;` and `,` as delimiters.
*
* Empty / whitespace-only inputs return `[]`. Individual entries are trimmed
* and any blank entries (e.g. from a trailing separator) are dropped.
*/
export function parseMeasures(raw: string | null | undefined): string[] {
if (!raw) return [];
// Tolerant strategy: split on either `;` or `,`. HubSpot's multi-select
// exports use `;` natively; legacy values and ad-hoc text may use `,`.
return raw
.split(/[;,]/)
.map((m) => m.trim())
.filter(Boolean);
}

View file

@ -23,6 +23,7 @@ import { CheckCircle2, XCircle, Upload, Loader2, Clock, ChevronDown, ChevronRigh
import { uploadFileToS3 } from "@/app/utils/s3";
import type { ClassifiedDeal, DocStatusMap } from "./types";
import { getRequiredDocs } from "@/app/lib/measureDocumentRequirements";
import { parseMeasures } from "@/app/lib/parseMeasures";
// ── Types ─────────────────────────────────────────────────────────────────
@ -164,11 +165,6 @@ function contentTypeFor(ext: string): string {
return "application/octet-stream";
}
function parseMeasures(raw: string | null | undefined): string[] {
if (!raw) return [];
return raw.split(",").map((m) => m.trim()).filter(Boolean);
}
function s3KeyBasename(key: string): string {
return key.split("/").pop() ?? key;
}

View file

@ -18,6 +18,7 @@ import { Search, Save, ChevronDown, ChevronRight } from "lucide-react";
import { STAGE_COLORS } from "./types";
import type { ClassifiedDeal, PortfolioCapabilityType, ApprovalsByDeal } from "./types";
import { ApprovalConfirmDialog, type PendingDiff } from "./ApprovalConfirmDialog";
import { parseMeasures } from "@/app/lib/parseMeasures";
type AuditEvent = {
id: string;
@ -36,11 +37,6 @@ type Props = {
portfolioId: string;
};
function parseMeasures(raw: string | null | undefined): string[] {
if (!raw) return [];
return raw.split(",").map((m) => m.trim()).filter(Boolean);
}
function ApprovalStatus({
proposed,
approved,