fix: fix several different data parsing issues

This commit is contained in:
2026-04-18 14:47:06 +00:00
parent 5141ed20f9
commit f91d8debcb
16 changed files with 632 additions and 49 deletions
+94 -36
View File
@@ -27,6 +27,21 @@
country?: string;
}
interface CompanySite {
id?: number;
uid?: string;
name?: string;
defaultFlag?: boolean;
inactiveFlag?: boolean;
addressLine1?: string | null;
addressLine2?: string | null;
city?: string | null;
state?: string | null;
zip?: string | null;
country?: string | null;
phone?: string | null;
}
export let isOpen = false;
export let onSuccess: () => void = () => {};
export let opportunityTypes: OpportunityType[] = [];
@@ -48,6 +63,8 @@
let contacts: CompanyContact[] = [];
let selectedContactId = "";
let companyAddress: CompanyAddress | null = null;
let allAddresses: CompanySite[] = [];
let selectedSiteUid: string | null = null;
let isLoadingCompanyDetails = false;
// ── UI state ──
@@ -112,6 +129,11 @@
(c) => String(c.cwId) === selectedContactId,
);
$: activeContacts = contacts.filter((c) => !c.inactive);
$: activeSites = allAddresses.filter((a) => !a.inactiveFlag);
$: selectedSite =
selectedSiteUid !== null
? (activeSites.find((a) => a.uid === selectedSiteUid) ?? null)
: (activeSites.find((a) => a.defaultFlag) ?? activeSites[0] ?? null);
// ── Default close date to 30 days from now ──
$: if (isOpen && !expectedCloseDate) {
@@ -211,6 +233,8 @@
contacts = [];
selectedContactId = "";
companyAddress = null;
allAddresses = [];
selectedSiteUid = null;
}
function handleCompanyKeydown(e: KeyboardEvent) {
@@ -247,6 +271,8 @@
contacts = [];
selectedContactId = "";
companyAddress = null;
allAddresses = [];
selectedSiteUid = null;
}
// ── Load company details (contacts + address) ──
@@ -259,6 +285,7 @@
cw_Data?: {
allContacts?: CompanyContact[];
address?: CompanyAddress;
allAddresses?: CompanySite[];
};
};
}>(`/api/companies/${companyOptimaId}/details`);
@@ -268,6 +295,12 @@
const allContacts: CompanyContact[] = data.cw_Data?.allContacts ?? [];
contacts = allContacts;
companyAddress = data.cw_Data?.address ?? null;
allAddresses = data.cw_Data?.allAddresses ?? [];
// Auto-select default/first active site
const activeAddr = allAddresses.filter((a) => !a.inactiveFlag);
const defaultAddr = activeAddr.find((a) => a.defaultFlag) ?? activeAddr[0];
selectedSiteUid = defaultAddr?.uid ?? null;
// Auto-select first active contact as default
const active = allContacts.filter((c: CompanyContact) => !c.inactive);
@@ -393,6 +426,8 @@
contacts = [];
selectedContactId = "";
companyAddress = null;
allAddresses = [];
selectedSiteUid = null;
isLoadingCompanyDetails = false;
isSubmitting = false;
submitError = "";
@@ -1116,39 +1151,63 @@
</svg>
Loading site information…
</div>
{:else if companyAddress}
<div class="co-site-card">
<div class="co-site-card-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
width="20"
height="20"
>
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" />
<circle cx="12" cy="10" r="3" />
</svg>
{:else if activeSites.length > 0}
{#if activeSites.length > 1}
<div class="co-form-grid">
<div class="co-form-group co-full-width">
<label for="co-site-select">Site</label>
<select
id="co-site-select"
bind:value={selectedSiteUid}
disabled={isSubmitting}
>
{#each activeSites as site}
<option value={site.uid}>
{site.name || site.addressLine1 || "Unnamed Site"}{site.defaultFlag ? " (Default)" : ""}
</option>
{/each}
</select>
</div>
</div>
<div class="co-site-card-details">
<p class="co-site-label">Primary Address</p>
<p class="co-site-line">{companyAddress.line1 ?? ""}</p>
{#if companyAddress.line2}
<p class="co-site-line">{companyAddress.line2}</p>
{/if}
<p class="co-site-line">
{companyAddress.city ?? ""}{companyAddress.city &&
companyAddress.state
? ", "
: ""}{companyAddress.state ?? ""}
{companyAddress.zip ?? ""}
</p>
{#if companyAddress.country && companyAddress.country !== "United States"}
<p class="co-site-line">{companyAddress.country}</p>
{/if}
{/if}
{#if selectedSite}
<div class="co-site-card">
<div class="co-site-card-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
width="20"
height="20"
>
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" />
<circle cx="12" cy="10" r="3" />
</svg>
</div>
<div class="co-site-card-details">
{#if selectedSite.name}
<p class="co-site-label">{selectedSite.name}</p>
{/if}
{#if selectedSite.addressLine1}
<p class="co-site-line">{selectedSite.addressLine1}</p>
{/if}
{#if selectedSite.addressLine2}
<p class="co-site-line">{selectedSite.addressLine2}</p>
{/if}
<p class="co-site-line">
{selectedSite.city ?? ""}{selectedSite.city && selectedSite.state ? ", " : ""}{selectedSite.state ?? ""}
{selectedSite.zip ?? ""}
</p>
{#if selectedSite.country && selectedSite.country !== "United States"}
<p class="co-site-line">{selectedSite.country}</p>
{/if}
{#if selectedSite.phone}
<p class="co-site-line">{selectedSite.phone}</p>
{/if}
</div>
</div>
</div>
{/if}
{:else}
<div class="co-empty-state">
<svg
@@ -1293,14 +1352,13 @@
: "—"}
</dd>
</div>
{#if companyAddress}
{#if selectedSite}
<div class="co-review-item">
<dt>Site</dt>
<dd>
{companyAddress.city ?? ""}{companyAddress.city &&
companyAddress.state
? ", "
: ""}{companyAddress.state ?? ""}
{selectedSite.name
? selectedSite.name
: `${selectedSite.city ?? ""}${selectedSite.city && selectedSite.state ? ", " : ""}${selectedSite.state ?? ""}`}
</dd>
</div>
{/if}
@@ -8,12 +8,16 @@ export const company = {
includeAddress?: boolean;
includePrimaryContact?: boolean;
includeAllContacts?: boolean;
includeAllAddresses?: boolean;
},
) {
const params: Record<string, string> = {};
if (options?.includeAddress) params.includeAddress = "true";
if (options?.includePrimaryContact) params.includePrimaryContact = "true";
if (options?.includeAllContacts) params.includeAllContacts = "true";
if (options?.includeAllAddresses) params.includeAllAddresses = "true";
const company = await api.get(`/v1/company/companies/${id}`, {
params,
@@ -21,6 +25,8 @@ export const company = {
Authorization: `Bearer ${accessToken}`,
},
});
console.log(company.data);
return company.data;
},
async fetchMany(
@@ -9,10 +9,13 @@ export const GET: RequestHandler = async ({ params, locals }) => {
return json({ data: null }, { status: 401 });
}
console.log("Here")
try {
const result = await optima.company.fetch(accessToken, params.id, {
includeAllContacts: true,
includeAddress: true,
includeAllAddresses: true,
});
return json({ data: result?.data ?? null });
} catch (err) {
@@ -51,6 +51,7 @@ export const load: PageServerLoad = async ({ locals, params }) => {
includeAddress: permissions["company.fetch.address"] === true,
includePrimaryContact: true,
includeAllContacts: permissions["company.fetch.contacts"] === true,
includeAllAddresses: permissions["company.fetch.address"] === true,
}),
);
@@ -15,6 +15,27 @@
export let permissions: PermissionMap;
export let isMobile: boolean;
export let mobileActiveTab: string | null;
// Selected site for the sites dropdown
let selectedSiteUid: string | null = null;
$: allAddresses = company?.cw_Data?.allAddresses ?? [];
$: activeSites = allAddresses.filter((a) => !a.inactiveFlag);
$: selectedSite =
selectedSiteUid !== null
? activeSites.find((a) => a.uid === selectedSiteUid) ?? null
: activeSites.find((a) => a.defaultFlag) ?? activeSites[0] ?? null;
function formatSiteAddress(site: (typeof activeSites)[number]): string[] {
const lines: string[] = [];
if (site.addressLine1) lines.push(site.addressLine1);
if (site.addressLine2) lines.push(site.addressLine2);
const cityStateZip = [site.city, site.state, site.zip]
.filter(Boolean)
.join(", ");
if (cityStateZip) lines.push(cityStateZip);
if (site.country) lines.push(site.country);
return lines;
}
</script>
<div
@@ -170,7 +191,54 @@
</div>
{/if}
{#if permissions["company.fetch.address"] && formatAddress(company).length > 0}
{#if permissions["company.fetch.address"] && activeSites.length > 0}
<div class="info-row">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
class="info-icon"
>
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z" />
<circle cx="12" cy="10" r="3" />
</svg>
<div class="info-content">
{#if activeSites.length > 1}
<select
class="site-select"
bind:value={selectedSiteUid}
on:change={(e) => (selectedSiteUid = e.currentTarget.value)}
>
{#each activeSites as site}
<option value={site.uid}>
{site.name}{site.defaultFlag ? " (Default)" : ""}
</option>
{/each}
</select>
{:else}
<span class="info-label"
>{activeSites[0]?.name ?? "Address"}</span
>
{/if}
{#if selectedSite}
{@const lines = formatSiteAddress(selectedSite)}
{#if lines.length > 0}
<span class="info-value address-multiline">
{#each lines as line}
{line}<br />
{/each}
</span>
{/if}
{#if selectedSite.phone}
<span class="info-value site-phone"
>{formatPhone(selectedSite.phone)}</span
>
{/if}
{/if}
</div>
</div>
{:else if permissions["company.fetch.address"] && formatAddress(company).length > 0}
<div class="info-row">
<svg
viewBox="0 0 24 24"
+15
View File
@@ -27,6 +27,21 @@ export interface CompanyData {
zip?: string;
country?: string;
};
allAddresses?: Array<{
id: number;
uid: string;
name: string;
description?: string | null;
defaultFlag: boolean;
inactiveFlag: boolean;
addressLine1?: string | null;
addressLine2?: string | null;
city?: string | null;
state?: string | null;
zip?: string | null;
country?: string | null;
phone?: string | null;
}>;
primaryContact?: {
firstName?: string;
lastName?: string;
+23
View File
@@ -411,6 +411,29 @@
line-height: 1.6;
}
.site-select {
width: 100%;
padding: 4px 6px;
border: 1px solid var(--border-color, #e5e7eb);
border-radius: 6px;
background: var(--bg-secondary, #f9fafb);
color: var(--text-primary, #111827);
font-size: 12px;
cursor: pointer;
margin-bottom: 6px;
}
.site-select:focus {
outline: none;
border-color: var(--accent-color, #6366f1);
}
.info-value.site-phone {
font-size: 12px;
color: var(--text-muted);
margin-top: 2px;
}
/* Primary contact section */
.primary-contact-section {
margin-top: 8px;