mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 11:39:00 +00:00
fix(work-orders): keep completion freeze on live registry edits
This commit is contained in:
parent
1809694973
commit
c7aec49f05
20 changed files with 208 additions and 59 deletions
|
|
@ -46,7 +46,7 @@ export function CompDocDetailsSection({
|
||||||
<CompDocDetailRow
|
<CompDocDetailRow
|
||||||
icon={MapPin}
|
icon={MapPin}
|
||||||
label="Site Code"
|
label="Site Code"
|
||||||
value={`${row.site} · Amazon.com Services LLC`}
|
value={`${site.code} · Amazon.com Services LLC`}
|
||||||
/>
|
/>
|
||||||
<CompDocEditableRow
|
<CompDocEditableRow
|
||||||
label="Address"
|
label="Address"
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ export function CompDocPreviewDocument({
|
||||||
isGenerated={isGenerated}
|
isGenerated={isGenerated}
|
||||||
generatedAt={generatedAt}
|
generatedAt={generatedAt}
|
||||||
/>
|
/>
|
||||||
<CompDocPreviewVendorSafety row={row} />
|
<CompDocPreviewVendorSafety site={site} />
|
||||||
<CompDocPreviewProcedureNotes pm={row.pm} notes={notes} />
|
<CompDocPreviewProcedureNotes pm={row.pm} notes={notes} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,10 @@ export function CompDocPreviewServiceInfo({
|
||||||
margin: "2px 0",
|
margin: "2px 0",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Site ID — {row.site}
|
Site ID — {site.code}
|
||||||
</Text>
|
</Text>
|
||||||
<Text as="p" style={{ fontSize: 13, color: "#161E38", margin: "2px 0" }}>
|
<Text as="p" style={{ fontSize: 13, color: "#161E38", margin: "2px 0" }}>
|
||||||
Amazon.com Services LLC {row.site}
|
Amazon.com Services LLC {site.code}
|
||||||
</Text>
|
</Text>
|
||||||
<Text as="p" style={{ fontSize: 13, color: "#58595B", margin: "2px 0" }}>
|
<Text as="p" style={{ fontSize: 13, color: "#58595B", margin: "2px 0" }}>
|
||||||
{site.street},
|
{site.street},
|
||||||
|
|
|
||||||
|
|
@ -73,10 +73,10 @@ export function CompDocPreviewSummary({
|
||||||
margin: "2px 0",
|
margin: "2px 0",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Site ID — {row.site}
|
Site ID — {site.code}
|
||||||
</Text>
|
</Text>
|
||||||
<Text variant="body" sx={{ fontSize: 13, color: "#161E38", margin: "2px 0" }}>
|
<Text variant="body" sx={{ fontSize: 13, color: "#161E38", margin: "2px 0" }}>
|
||||||
Amazon.com Services LLC {row.site}
|
Amazon.com Services LLC {site.code}
|
||||||
</Text>
|
</Text>
|
||||||
<Text variant="body" sx={{ fontSize: 13, color: "#58595B", margin: "2px 0" }}>
|
<Text variant="body" sx={{ fontSize: 13, color: "#58595B", margin: "2px 0" }}>
|
||||||
{site.street},
|
{site.street},
|
||||||
|
|
@ -88,8 +88,8 @@ export function CompDocPreviewSummary({
|
||||||
|
|
||||||
<Text variant="body" sx={{ fontSize: 13, color: "#161E38", margin: "14px 0 6px" }}>
|
<Text variant="body" sx={{ fontSize: 13, color: "#161E38", margin: "14px 0 6px" }}>
|
||||||
<span style={{ fontWeight: 700 }}>Vendor / Technician: </span>
|
<span style={{ fontWeight: 700 }}>Vendor / Technician: </span>
|
||||||
{row.tech || "—"}
|
{site.tech || "—"}
|
||||||
{row.company ? ` · ${row.company}` : ""}
|
{site.company ? ` · ${site.company}` : ""}
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
import { Text } from "@/components/ui/text";
|
import { Text } from "@/components/ui/text";
|
||||||
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
|
import type { CompDocSiteInfo } from "@/domain/work-orders/types/completion-doc";
|
||||||
import { SAFETY_BULLETS } from "@/domain/work-orders/utils/completion-doc-procedures";
|
import { SAFETY_BULLETS } from "@/domain/work-orders/utils/completion-doc-procedures";
|
||||||
|
|
||||||
type CompDocPreviewVendorSafetyProps = {
|
type CompDocPreviewVendorSafetyProps = {
|
||||||
row: WorkOrderTableRow;
|
site: CompDocSiteInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function CompDocPreviewVendorSafety({ row }: CompDocPreviewVendorSafetyProps) {
|
export function CompDocPreviewVendorSafety({ site }: CompDocPreviewVendorSafetyProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Text as="p" style={{ fontSize: 13, color: "#161E38", margin: "14px 0 6px" }}>
|
<Text as="p" style={{ fontSize: 13, color: "#161E38", margin: "14px 0 6px" }}>
|
||||||
<span style={{ fontWeight: 700 }}>Vendor / Technician: </span>
|
<span style={{ fontWeight: 700 }}>Vendor / Technician: </span>
|
||||||
{row.tech || "—"}
|
{site.tech || "—"}
|
||||||
{row.company ? ` · ${row.company}` : ""}
|
{site.company ? ` · ${site.company}` : ""}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<ul style={{ listStyle: "disc", paddingLeft: 18, margin: "8px 0 0" }}>
|
<ul style={{ listStyle: "disc", paddingLeft: 18, margin: "8px 0 0" }}>
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,9 @@ export function useCompDocDialog({
|
||||||
setEditDateCompleted,
|
setEditDateCompleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const company = effectiveCompany(info);
|
||||||
const amazonRep = effectivePoc(info).contacts[0]?.name || "";
|
const amazonRep = effectivePoc(info).contacts[0]?.name || "";
|
||||||
const seaRep = effectiveCompany(info).contactName || "";
|
const seaRep = company.contactName || "";
|
||||||
const cfg = DOC_STATE_CFG[docState];
|
const cfg = DOC_STATE_CFG[docState];
|
||||||
const isNotRequired = docState === "not-required";
|
const isNotRequired = docState === "not-required";
|
||||||
const isGenerated = docState === "generated" || Boolean(signOffAttachment);
|
const isGenerated = docState === "generated" || Boolean(signOffAttachment);
|
||||||
|
|
@ -114,6 +115,9 @@ export function useCompDocDialog({
|
||||||
dateCompleted: editDateCompleted,
|
dateCompleted: editDateCompleted,
|
||||||
amazonRep,
|
amazonRep,
|
||||||
seaRep,
|
seaRep,
|
||||||
|
siteCode: site.code,
|
||||||
|
tech: company.contactName || "",
|
||||||
|
company: company.name || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
const { persist, syncDateIfChanged, refreshAuthoritativeState, handleSaveDraft, handleGenerate } =
|
const { persist, syncDateIfChanged, refreshAuthoritativeState, handleSaveDraft, handleGenerate } =
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { formatApptRange, parseApptTime } from "@/domain/work-orders/utils/wizar
|
||||||
import {
|
import {
|
||||||
effectiveCompany,
|
effectiveCompany,
|
||||||
effectivePoc,
|
effectivePoc,
|
||||||
|
effectiveSite,
|
||||||
} from "@/domain/work-orders/utils/effective-completion-snapshot";
|
} from "@/domain/work-orders/utils/effective-completion-snapshot";
|
||||||
import { DocBadge } from "./slide-over-doc-badge";
|
import { DocBadge } from "./slide-over-doc-badge";
|
||||||
import { SlideOverInfoTabAssignedField } from "./slide-over-info-tab-assigned-field";
|
import { SlideOverInfoTabAssignedField } from "./slide-over-info-tab-assigned-field";
|
||||||
|
|
@ -71,10 +72,11 @@ function SlideOverCompletedSite({
|
||||||
sites: LocationOption[];
|
sites: LocationOption[];
|
||||||
}) {
|
}) {
|
||||||
const primaryPoc = poc.contacts[0];
|
const primaryPoc = poc.contacts[0];
|
||||||
|
const frozenSite = effectiveSite(source);
|
||||||
return (
|
return (
|
||||||
<SiteCell
|
<SiteCell
|
||||||
value={source.site}
|
value={frozenSite?.code ?? source.site}
|
||||||
location={source.location}
|
location={frozenSite?.label ?? source.location}
|
||||||
locationId={source.locationId}
|
locationId={source.locationId}
|
||||||
pocName={primaryPoc?.name ?? ""}
|
pocName={primaryPoc?.name ?? ""}
|
||||||
pocPhone={primaryPoc?.phone ?? ""}
|
pocPhone={primaryPoc?.phone ?? ""}
|
||||||
|
|
@ -82,10 +84,11 @@ function SlideOverCompletedSite({
|
||||||
additionalContacts={poc.contacts.slice(1).map((contact) => ({
|
additionalContacts={poc.contacts.slice(1).map((contact) => ({
|
||||||
name: contact.name ?? "",
|
name: contact.name ?? "",
|
||||||
phone: contact.phone ?? "",
|
phone: contact.phone ?? "",
|
||||||
|
notes: contact.notes ?? "",
|
||||||
}))}
|
}))}
|
||||||
sites={sites}
|
sites={sites}
|
||||||
viewOnly
|
viewOnly
|
||||||
frozenSite={source.frozenSite}
|
frozenSite={frozenSite}
|
||||||
onSave={() => undefined}
|
onSave={() => undefined}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -98,21 +98,31 @@ export function VendorDialogBody({
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<FieldLabel>Technician (optional)</FieldLabel>
|
<FieldLabel>Technician (optional)</FieldLabel>
|
||||||
<WizardFieldSelect
|
{frozenCompany != null ? (
|
||||||
value={selectedKey}
|
<div className={DLG_INPUT_CLS} style={DLG_INPUT_STYLE}>
|
||||||
placeholder={selectedCompany ? "Select technician …" : "Pick a company first"}
|
{frozenCompany.contactName?.trim() || tech || "—"}
|
||||||
disabled={!selectedCompany}
|
</div>
|
||||||
icon={
|
) : (
|
||||||
<Wrench size={14} className="shrink-0" style={{ color: "var(--color-text-muted)" }} />
|
<WizardFieldSelect
|
||||||
}
|
value={selectedKey}
|
||||||
searchPlaceholder="Search technician…"
|
placeholder={selectedCompany ? "Select technician …" : "Pick a company first"}
|
||||||
options={technicianOptions.map((option) => ({
|
disabled={!selectedCompany}
|
||||||
key: option.key,
|
icon={
|
||||||
label: option.name,
|
<Wrench
|
||||||
}))}
|
size={14}
|
||||||
onPick={onPick}
|
className="shrink-0"
|
||||||
/>
|
style={{ color: "var(--color-text-muted)" }}
|
||||||
{companyVendorForAdd != null && (
|
/>
|
||||||
|
}
|
||||||
|
searchPlaceholder="Search technician…"
|
||||||
|
options={technicianOptions.map((option) => ({
|
||||||
|
key: option.key,
|
||||||
|
label: option.name,
|
||||||
|
}))}
|
||||||
|
onPick={onPick}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{frozenCompany == null && companyVendorForAdd != null && (
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<VendorDialogAddTechnician
|
<VendorDialogAddTechnician
|
||||||
companyName={anchorCompanyName}
|
companyName={anchorCompanyName}
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,8 @@ export function VendorDialog({
|
||||||
technicianOptions={form.technicianOptions}
|
technicianOptions={form.technicianOptions}
|
||||||
anchorCompanyName={form.anchorCompanyName}
|
anchorCompanyName={form.anchorCompanyName}
|
||||||
companyVendorForAdd={viewOnly ? undefined : (form.companyVendor ?? undefined)}
|
companyVendorForAdd={viewOnly ? undefined : (form.companyVendor ?? undefined)}
|
||||||
tech={form.selected?.name ?? form.t}
|
tech={frozenCompany?.contactName ?? form.selected?.name ?? form.t}
|
||||||
phone={form.phone}
|
phone={frozenCompany?.phone ?? form.phone}
|
||||||
notes={form.notes}
|
notes={form.notes}
|
||||||
resolvedCompany={form.resolvedCompany}
|
resolvedCompany={form.resolvedCompany}
|
||||||
selectedVendor={form.selectedVendor}
|
selectedVendor={form.selectedVendor}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-ta
|
||||||
import { applyAssignedToTableSave } from "@/domain/work-orders/utils/work-order-feedback-toasts";
|
import { applyAssignedToTableSave } from "@/domain/work-orders/utils/work-order-feedback-toasts";
|
||||||
import { isWorkOrderCompletionSurfaceReadOnly } from "@/domain/work-orders/utils/work-order-lock";
|
import { isWorkOrderCompletionSurfaceReadOnly } from "@/domain/work-orders/utils/work-order-lock";
|
||||||
import {
|
import {
|
||||||
|
effectiveAdditionalContacts,
|
||||||
effectivePoc,
|
effectivePoc,
|
||||||
effectiveSite,
|
effectiveSite,
|
||||||
} from "@/domain/work-orders/utils/effective-completion-snapshot";
|
} from "@/domain/work-orders/utils/effective-completion-snapshot";
|
||||||
|
|
@ -69,10 +70,7 @@ export function WoTableRowCells({
|
||||||
pocName={primaryPoc?.name ?? ""}
|
pocName={primaryPoc?.name ?? ""}
|
||||||
pocPhone={primaryPoc?.phone ?? ""}
|
pocPhone={primaryPoc?.phone ?? ""}
|
||||||
pocNotes={poc.notes ?? ""}
|
pocNotes={poc.notes ?? ""}
|
||||||
additionalContacts={poc.contacts.slice(1).map((contact) => ({
|
additionalContacts={effectiveAdditionalContacts(row)}
|
||||||
name: contact.name ?? "",
|
|
||||||
phone: contact.phone ?? "",
|
|
||||||
}))}
|
|
||||||
sites={sites}
|
sites={sites}
|
||||||
q={search}
|
q={search}
|
||||||
viewOnly={viewOnly}
|
viewOnly={viewOnly}
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,9 @@ export function useCompDocDialog({
|
||||||
setEditAddress(value);
|
setEditAddress(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const company = effectiveCompany(row);
|
||||||
const amazonRep = effectivePoc(row).contacts[0]?.name || "";
|
const amazonRep = effectivePoc(row).contacts[0]?.name || "";
|
||||||
const seaRep = effectiveCompany(row).contactName || "";
|
const seaRep = company.contactName || "";
|
||||||
const cfg = DOC_STATE_CFG[docState];
|
const cfg = DOC_STATE_CFG[docState];
|
||||||
const isNotRequired = docState === "not-required";
|
const isNotRequired = docState === "not-required";
|
||||||
const isGenerated = docState === "generated";
|
const isGenerated = docState === "generated";
|
||||||
|
|
@ -120,6 +121,9 @@ export function useCompDocDialog({
|
||||||
dateCompleted: editDateCompleted,
|
dateCompleted: editDateCompleted,
|
||||||
amazonRep,
|
amazonRep,
|
||||||
seaRep,
|
seaRep,
|
||||||
|
siteCode: site.code,
|
||||||
|
tech: company.contactName || "",
|
||||||
|
company: company.name || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
const previewSite = useMemo(
|
const previewSite = useMemo(
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,7 @@ function readFrozenPoc(item: Record<string, unknown>): WorkOrderFrozenPoc | unde
|
||||||
? rawContacts.map(asRecord).map((contact) => ({
|
? rawContacts.map(asRecord).map((contact) => ({
|
||||||
name: readString(contact, "name", "Name"),
|
name: readString(contact, "name", "Name"),
|
||||||
phone: readString(contact, "phone", "Phone"),
|
phone: readString(contact, "phone", "Phone"),
|
||||||
|
notes: readString(contact, "notes", "Notes"),
|
||||||
}))
|
}))
|
||||||
: [];
|
: [];
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ export interface DocFields {
|
||||||
dateCompleted: string;
|
dateCompleted: string;
|
||||||
amazonRep: string;
|
amazonRep: string;
|
||||||
seaRep: string;
|
seaRep: string;
|
||||||
|
siteCode: string;
|
||||||
|
tech: string;
|
||||||
|
company: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DocState = "draft" | "generated" | "not-required";
|
export type DocState = "draft" | "generated" | "not-required";
|
||||||
|
|
@ -31,12 +34,15 @@ export interface CompletionDocStateConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CompDocSiteInfo {
|
export interface CompDocSiteInfo {
|
||||||
|
code: string;
|
||||||
street: string;
|
street: string;
|
||||||
city: string;
|
city: string;
|
||||||
state: string;
|
state: string;
|
||||||
zip: string;
|
zip: string;
|
||||||
label: string;
|
label: string;
|
||||||
fullAddress: string;
|
fullAddress: string;
|
||||||
|
tech: string;
|
||||||
|
company: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CompDocSaveStatus = Exclude<CompletionDocStatus, "">;
|
export type CompDocSaveStatus = Exclude<CompletionDocStatus, "">;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export type WorkOrderFrozenCompany = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type WorkOrderFrozenPoc = {
|
export type WorkOrderFrozenPoc = {
|
||||||
contacts: { name?: string; phone?: string }[];
|
contacts: { name?: string; phone?: string; notes?: string }[];
|
||||||
notes?: string;
|
notes?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,11 +75,11 @@ export function buildDocHtml(
|
||||||
<div class="rule"></div>
|
<div class="rule"></div>
|
||||||
<h1>${esc(serviceTitle(row).toUpperCase())}</h1>
|
<h1>${esc(serviceTitle(row).toUpperCase())}</h1>
|
||||||
<p style="margin:2px 0;" class="wo">WO# ${esc(row.woNumber)}</p>
|
<p style="margin:2px 0;" class="wo">WO# ${esc(row.woNumber)}</p>
|
||||||
<p style="margin:14px 0 0;">Site ID — ${esc(row.site)}</p>
|
<p style="margin:14px 0 0;">Site ID — ${esc(fields.siteCode)}</p>
|
||||||
<p style="margin:2px 0;">Amazon.com Services LLC ${esc(row.site)}</p>
|
<p style="margin:2px 0;">Amazon.com Services LLC ${esc(fields.siteCode)}</p>
|
||||||
<p style="margin:2px 0;" class="muted">${esc(fields.street)},</p>
|
<p style="margin:2px 0;" class="muted">${esc(fields.street)},</p>
|
||||||
<p style="margin:2px 0;" class="muted">${esc(cityStateZip)}</p>
|
<p style="margin:2px 0;" class="muted">${esc(cityStateZip)}</p>
|
||||||
<p style="margin:14px 0 4px;"><b>Vendor / Technician:</b> ${esc(row.tech || "—")}${row.company ? ` · ${esc(row.company)}` : ""}</p>
|
<p style="margin:14px 0 4px;"><b>Vendor / Technician:</b> ${esc(fields.tech || "—")}${fields.company ? ` · ${esc(fields.company)}` : ""}</p>
|
||||||
<ul style="padding-left:20px;">${safety}</ul>
|
<ul style="padding-left:20px;">${safety}</ul>
|
||||||
${completedBlock}
|
${completedBlock}
|
||||||
<h3 style="margin:16px 0 4px;">${esc(proc.heading)}:</h3>
|
<h3 style="margin:16px 0 4px;">${esc(proc.heading)}:</h3>
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,53 @@
|
||||||
import type { Location } from "@/domain/locations/types/location";
|
import type { Location } from "@/domain/locations/types/location";
|
||||||
import type { CompDocSiteInfo } from "@/domain/work-orders/types/completion-doc";
|
import type { CompDocSiteInfo } from "@/domain/work-orders/types/completion-doc";
|
||||||
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
|
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
|
||||||
import { effectiveSite } from "@/domain/work-orders/utils/effective-completion-snapshot";
|
import {
|
||||||
|
effectiveCompany,
|
||||||
|
effectiveSite,
|
||||||
|
} from "@/domain/work-orders/utils/effective-completion-snapshot";
|
||||||
|
|
||||||
|
type CompDocAddress = Pick<
|
||||||
|
CompDocSiteInfo,
|
||||||
|
"street" | "city" | "state" | "zip" | "label" | "fullAddress"
|
||||||
|
>;
|
||||||
|
|
||||||
|
type CompDocIdentityRow = Pick<WorkOrderTableRow, "site" | "location" | "status" | "frozenSite"> &
|
||||||
|
Partial<Pick<WorkOrderTableRow, "company" | "tech" | "techPhone" | "frozenCompany">>;
|
||||||
|
|
||||||
function buildLabel(city?: string, state?: string): string {
|
function buildLabel(city?: string, state?: string): string {
|
||||||
return [city, state].filter(Boolean).join(", ");
|
return [city, state].filter(Boolean).join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
function toCompDocSite(street: string, city: string, state: string, zip: string): CompDocSiteInfo {
|
function toCompDocAddress(
|
||||||
|
street: string,
|
||||||
|
city: string,
|
||||||
|
state: string,
|
||||||
|
zip: string,
|
||||||
|
): CompDocAddress {
|
||||||
const label = buildLabel(city, state);
|
const label = buildLabel(city, state);
|
||||||
const fullAddress = [street, label, zip].filter(Boolean).join(", ") || "—";
|
const fullAddress = [street, label, zip].filter(Boolean).join(", ") || "—";
|
||||||
return { street, city, state, zip, label, fullAddress };
|
return { street, city, state, zip, label, fullAddress };
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveLiveLocationSite(location: Location): CompDocSiteInfo {
|
function withCompDocIdentity(address: CompDocAddress, row: CompDocIdentityRow): CompDocSiteInfo {
|
||||||
return toCompDocSite(
|
const frozen = effectiveSite(row);
|
||||||
|
const company = effectiveCompany({
|
||||||
|
status: row.status,
|
||||||
|
company: row.company ?? "",
|
||||||
|
tech: row.tech ?? "",
|
||||||
|
techPhone: row.techPhone ?? "",
|
||||||
|
frozenCompany: row.frozenCompany,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...address,
|
||||||
|
code: frozen?.code ?? row.site,
|
||||||
|
tech: company.contactName ?? "",
|
||||||
|
company: company.name ?? "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveLiveLocationSite(location: Location): CompDocAddress {
|
||||||
|
return toCompDocAddress(
|
||||||
location.address ?? "",
|
location.address ?? "",
|
||||||
location.city ?? "",
|
location.city ?? "",
|
||||||
location.state ?? "",
|
location.state ?? "",
|
||||||
|
|
@ -22,30 +55,33 @@ function resolveLiveLocationSite(location: Location): CompDocSiteInfo {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveRowLocationSite(row: Pick<WorkOrderTableRow, "location">): CompDocSiteInfo {
|
function resolveRowLocationSite(row: Pick<WorkOrderTableRow, "location">): CompDocAddress {
|
||||||
const locationParts = row.location.split(",").map((part) => part.trim());
|
const locationParts = row.location.split(",").map((part) => part.trim());
|
||||||
const city = locationParts[0] ?? "";
|
const city = locationParts[0] ?? "";
|
||||||
const state = locationParts[1] ?? "";
|
const state = locationParts[1] ?? "";
|
||||||
const label = buildLabel(city, state);
|
const label = buildLabel(city, state);
|
||||||
const street = row.location && !label ? row.location : "";
|
const street = row.location && !label ? row.location : "";
|
||||||
return toCompDocSite(street, city, state, "");
|
return toCompDocAddress(street, city, state, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveCompDocSite(
|
export function resolveCompDocSite(
|
||||||
row: Pick<WorkOrderTableRow, "site" | "location" | "status" | "frozenSite">,
|
row: CompDocIdentityRow,
|
||||||
location?: Location | null,
|
location?: Location | null,
|
||||||
): CompDocSiteInfo {
|
): CompDocSiteInfo {
|
||||||
const frozen = effectiveSite(row);
|
const frozen = effectiveSite(row);
|
||||||
if (frozen != null) {
|
if (frozen != null) {
|
||||||
return toCompDocSite(
|
return withCompDocIdentity(
|
||||||
frozen.address ?? "",
|
toCompDocAddress(
|
||||||
frozen.city ?? "",
|
frozen.address ?? "",
|
||||||
frozen.state ?? "",
|
frozen.city ?? "",
|
||||||
frozen.zip ?? "",
|
frozen.state ?? "",
|
||||||
|
frozen.zip ?? "",
|
||||||
|
),
|
||||||
|
row,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (location?.address || location?.city) {
|
if (location?.address || location?.city) {
|
||||||
return resolveLiveLocationSite(location);
|
return withCompDocIdentity(resolveLiveLocationSite(location), row);
|
||||||
}
|
}
|
||||||
return resolveRowLocationSite(row);
|
return withCompDocIdentity(resolveRowLocationSite(row), row);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { WorkOrderAdditionalContact } from "@/domain/work-orders/types/work-order-additional-contact";
|
||||||
import type {
|
import type {
|
||||||
WorkOrderFrozenCompany,
|
WorkOrderFrozenCompany,
|
||||||
WorkOrderFrozenPoc,
|
WorkOrderFrozenPoc,
|
||||||
|
|
@ -48,8 +49,20 @@ export function effectivePoc(row: PocSnapshotRow): WorkOrderFrozenPoc {
|
||||||
...(row.additionalContacts ?? []).map((contact) => ({
|
...(row.additionalContacts ?? []).map((contact) => ({
|
||||||
name: contact.name,
|
name: contact.name,
|
||||||
phone: contact.phone,
|
phone: contact.phone,
|
||||||
|
notes: contact.notes,
|
||||||
})),
|
})),
|
||||||
],
|
],
|
||||||
notes: row.pocNotes,
|
notes: row.pocNotes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function effectiveAdditionalContacts(row: PocSnapshotRow): WorkOrderAdditionalContact[] {
|
||||||
|
if (row.status === "Completed" && row.frozenPoc != null) {
|
||||||
|
return row.frozenPoc.contacts.slice(1).map((contact) => ({
|
||||||
|
name: contact.name ?? "",
|
||||||
|
phone: contact.phone ?? "",
|
||||||
|
notes: contact.notes ?? "",
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return row.additionalContacts ?? [];
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { render, screen } from "@testing-library/react";
|
import { render, screen } from "@testing-library/react";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { VendorDialogBody } from "@/app/(protected)/workorders/_components/list/table/cells/vendor-dialog-body";
|
||||||
import { VendorDialogCompanyCard } from "@/app/(protected)/workorders/_components/list/table/cells/vendor-dialog-company-card";
|
import { VendorDialogCompanyCard } from "@/app/(protected)/workorders/_components/list/table/cells/vendor-dialog-company-card";
|
||||||
import type { VendorDropdownItem } from "@/domain/work-orders/types/work-order";
|
import type { VendorDropdownItem } from "@/domain/work-orders/types/work-order";
|
||||||
|
|
||||||
|
|
@ -48,4 +49,42 @@ describe("VendorDialogCompanyCard completion snapshot", () => {
|
||||||
expect(screen.getByText("200 Vendor Ave, Chicago, IL, 60602")).toBeInTheDocument();
|
expect(screen.getByText("200 Vendor Ave, Chicago, IL, 60602")).toBeInTheDocument();
|
||||||
expect(screen.queryByText("900 Live St")).not.toBeInTheDocument();
|
expect(screen.queryByText("900 Live St")).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("shows the frozen technician instead of a renamed live roster contact", () => {
|
||||||
|
render(
|
||||||
|
<VendorDialogBody
|
||||||
|
selectedCompany="Frozen Vendor"
|
||||||
|
companyOptions={[{ key: "Frozen Vendor", label: "Frozen Vendor" }]}
|
||||||
|
selectedKey={String(LIVE_VENDOR.id)}
|
||||||
|
technicianOptions={[
|
||||||
|
{
|
||||||
|
key: String(LIVE_VENDOR.id),
|
||||||
|
label: LIVE_VENDOR.contactName,
|
||||||
|
name: LIVE_VENDOR.contactName,
|
||||||
|
company: LIVE_VENDOR.companyName,
|
||||||
|
phone: "",
|
||||||
|
vendor: LIVE_VENDOR,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
anchorCompanyName="Frozen Vendor"
|
||||||
|
companyVendorForAdd={LIVE_VENDOR}
|
||||||
|
tech="Frozen Tech"
|
||||||
|
phone="111"
|
||||||
|
notes=""
|
||||||
|
resolvedCompany="Frozen Vendor"
|
||||||
|
selectedVendor={LIVE_VENDOR}
|
||||||
|
frozenCompany={{ name: "Frozen Vendor", contactName: "Frozen Tech", phone: "111" }}
|
||||||
|
saveError={null}
|
||||||
|
onCompanyPick={() => undefined}
|
||||||
|
onPick={() => undefined}
|
||||||
|
onPhoneChange={() => undefined}
|
||||||
|
onNotesChange={() => undefined}
|
||||||
|
onTechnicianCreated={() => undefined}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getAllByText("Frozen Tech").length).toBeGreaterThan(0);
|
||||||
|
expect(screen.queryByText("Live Contact")).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByRole("button", { name: /\+ add technician/i })).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,16 @@ describe("resolveCompDocSite", () => {
|
||||||
site: "BK5",
|
site: "BK5",
|
||||||
location: "Live City, WI",
|
location: "Live City, WI",
|
||||||
status: "Completed",
|
status: "Completed",
|
||||||
|
company: "Live Co",
|
||||||
|
tech: "Live Tech",
|
||||||
frozenSite: {
|
frozenSite: {
|
||||||
|
code: "FROZEN",
|
||||||
address: "100 Frozen Ave",
|
address: "100 Frozen Ave",
|
||||||
city: "Chicago",
|
city: "Chicago",
|
||||||
state: "IL",
|
state: "IL",
|
||||||
zip: "60601",
|
zip: "60601",
|
||||||
},
|
},
|
||||||
|
frozenCompany: { name: "Frozen Co", contactName: "Frozen Tech" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
address: "900 Live St",
|
address: "900 Live St",
|
||||||
|
|
@ -24,12 +28,15 @@ describe("resolveCompDocSite", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
code: "FROZEN",
|
||||||
street: "100 Frozen Ave",
|
street: "100 Frozen Ave",
|
||||||
city: "Chicago",
|
city: "Chicago",
|
||||||
state: "IL",
|
state: "IL",
|
||||||
zip: "60601",
|
zip: "60601",
|
||||||
label: "Chicago, IL",
|
label: "Chicago, IL",
|
||||||
fullAddress: "100 Frozen Ave, Chicago, IL, 60601",
|
fullAddress: "100 Frozen Ave, Chicago, IL, 60601",
|
||||||
|
tech: "Frozen Tech",
|
||||||
|
company: "Frozen Co",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import {
|
import {
|
||||||
|
effectiveAdditionalContacts,
|
||||||
effectiveCompany,
|
effectiveCompany,
|
||||||
effectivePoc,
|
effectivePoc,
|
||||||
effectiveSite,
|
effectiveSite,
|
||||||
|
|
@ -61,15 +62,42 @@ describe("effective completion snapshot", () => {
|
||||||
pocName: "Live POC",
|
pocName: "Live POC",
|
||||||
pocPhone: "222",
|
pocPhone: "222",
|
||||||
pocNotes: "live",
|
pocNotes: "live",
|
||||||
additionalContacts: [{ name: "Backup", phone: "333" }],
|
additionalContacts: [{ name: "Backup", phone: "333", notes: "gate hours" }],
|
||||||
}),
|
}),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
contacts: [
|
contacts: [
|
||||||
{ name: "Live POC", phone: "222" },
|
{ name: "Live POC", phone: "222" },
|
||||||
{ name: "Backup", phone: "333" },
|
{ name: "Backup", phone: "333", notes: "gate hours" },
|
||||||
],
|
],
|
||||||
notes: "live",
|
notes: "live",
|
||||||
});
|
});
|
||||||
|
expect(
|
||||||
|
effectiveAdditionalContacts({
|
||||||
|
status: "Scheduled",
|
||||||
|
pocName: "Live POC",
|
||||||
|
pocPhone: "222",
|
||||||
|
pocNotes: "live",
|
||||||
|
additionalContacts: [{ name: "Backup", phone: "333", notes: "gate hours" }],
|
||||||
|
}),
|
||||||
|
).toEqual([{ name: "Backup", phone: "333", notes: "gate hours" }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps extra-contact notes on the open work-order path", () => {
|
||||||
|
expect(
|
||||||
|
effectiveAdditionalContacts({
|
||||||
|
status: "Scheduled",
|
||||||
|
pocName: "Primary",
|
||||||
|
pocPhone: "111",
|
||||||
|
pocNotes: "",
|
||||||
|
additionalContacts: [{ name: "Backup", phone: "333", notes: "gate hours" }],
|
||||||
|
frozenPoc: {
|
||||||
|
contacts: [
|
||||||
|
{ name: "Frozen", phone: "000" },
|
||||||
|
{ name: "Frozen Extra", phone: "999", notes: "ignored while open" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toEqual([{ name: "Backup", phone: "333", notes: "gate hours" }]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("treats missing additional contacts as an empty live contact list", () => {
|
it("treats missing additional contacts as an empty live contact list", () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue