Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added app/ui/public/b2-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 10 additions & 12 deletions app/ui/src/app/edit/components/address/AddressCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import AddressOverlay, {
} from "@/app/edit/components/address/AddressOverlay";
import { TIME_OPTIONS } from "@/app/edit/constants/timeOptions";
import type { AddressCard as AddressCardType } from "@/app/edit/types/delivery";
import {
hasRecipientContact,
recipientSummary,
} from "@/app/edit/utils/recipientSummary";
import {
ADDRESS_ROW_EDIT_ROOT,
ADDRESS_ROW_DESKTOP_WRAPPER,
Expand Down Expand Up @@ -257,15 +261,13 @@ export default function AddressCard({
<>
{/* Recipient column — locked */}
<div className={ADDRESS_ROW_LOCKED_RECIPIENT_COL}>
{(a.recipientName || a.phoneNumber) && (
{hasRecipientContact(a) && (
<button
type="button"
onClick={() => unlockAddress(a.id)}
className={`${ADDRESS_ROW_LOCKED_PLAIN_TEXT} ${ADDRESS_ROW_LOCKED_FIELD_BTN}`}
>
{[a.recipientName, a.phoneNumber]
.filter(Boolean)
.join(", ")}
{recipientSummary(a)}
</button>
)}
<button
Expand Down Expand Up @@ -553,11 +555,9 @@ export default function AddressCard({
<div className={MOBILE_ADDR_SUMMARY_SECTION}>
<span className={MOBILE_ADDR_EDIT_SECTION_LABEL}>Recipient</span>
<div className={MOBILE_ADDR_LOCKED_RECIPIENT_LINES}>
{(a.recipientName || a.phoneNumber) && (
{hasRecipientContact(a) && (
<span className={MOBILE_ADDR_LOCKED_VALUE}>
{[a.recipientName, a.phoneNumber]
.filter(Boolean)
.join(", ")}
{recipientSummary(a)}
</span>
)}
<span
Expand Down Expand Up @@ -616,11 +616,9 @@ export default function AddressCard({
className={MOBILE_ADDR_LOCKED_FIELD_BTN}
>
<div className={MOBILE_ADDR_LOCKED_RECIPIENT_LINES}>
{(a.recipientName || a.phoneNumber) && (
{hasRecipientContact(a) && (
<span className={MOBILE_ADDR_LOCKED_VALUE}>
{[a.recipientName, a.phoneNumber]
.filter(Boolean)
.join(", ")}
{recipientSummary(a)}
</span>
)}
<span
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import { readHasOptimizeResults } from "../../../utils/hasOptimizeResults";
import {
SIDEBAR_NAV_ITEM_ACTIVE,
SIDEBAR_NAV_ITEM_DISABLED,
SIDEBAR_NAV_ITEM_INACTIVE,
SIDEBAR_NAV_LABEL_ACTIVE,
SIDEBAR_NAV_LABEL_INACTIVE,
SIDEBAR_NAV_PILL_ACTIVE,
SIDEBAR_NAV_PILL_INACTIVE,
} from "@/app/edit/formStyles.v2";

Expand All @@ -12,26 +20,48 @@ const SIDEBAR_RESULTS_ICON = (
height="24"
viewBox="0 0 24 24"
fill="none"
aria-hidden
>
<path
d="M4.35 20.7C4.01667 20.8333 3.70833 20.7958 3.425 20.5875C3.14167 20.3792 3 20.1 3 19.75V5.75C3 5.53333 3.0625 5.34167 3.1875 5.175C3.3125 5.00833 3.48333 4.88333 3.7 4.8L9 3L15 5.1L19.65 3.3C19.9833 3.16667 20.2917 3.20417 20.575 3.4125C20.8583 3.62083 21 3.9 21 4.25V12.675C20.75 12.2917 20.4542 11.9417 20.1125 11.625C19.7708 11.3083 19.4 11.0333 19 10.8V5.7L16 6.85V10C15.65 10 15.3083 10.0292 14.975 10.0875C14.6417 10.1458 14.3167 10.2333 14 10.35V6.85L10 5.45V18.525L4.35 20.7ZM5 18.3L8 17.15V5.45L5 6.45V18.3ZM17.4125 17.5C17.7875 17.1667 17.9833 16.6667 18 16C18.0167 15.4333 17.8292 14.9583 17.4375 14.575C17.0458 14.1917 16.5667 14 16 14C15.4333 14 14.9583 14.1917 14.575 14.575C14.1917 14.9583 14 15.4333 14 16C14 16.5667 14.1917 17.0417 14.575 17.425C14.9583 17.8083 15.4333 18 16 18C16.5667 18 17.0375 17.8333 17.4125 17.5ZM16 20C14.9 20 13.9583 19.6083 13.175 18.825C12.3917 18.0417 12 17.1 12 16C12 14.9 12.3917 13.9583 13.175 13.175C13.9583 12.3917 14.9 12 16 12C17.1 12 18.0417 12.3917 18.825 13.175C19.6083 13.9583 20 14.9 20 16C20 16.3833 19.9542 16.7458 19.8625 17.0875C19.7708 17.4292 19.6333 17.75 19.45 18.05L22 20.6L20.6 22L18.05 19.45C17.75 19.6333 17.4292 19.7708 17.0875 19.8625C16.7458 19.9542 16.3833 20 16 20Z"
fill="var(--edit-text-primary)"
fill="currentColor"
/>
</svg>
);

export default function SidebarResultsButton() {
const pathname = usePathname();
const isResultsPage = pathname === "/results";
const hasStoredRoutes = !isResultsPage && readHasOptimizeResults();

if (isResultsPage) {
return (
<span className={SIDEBAR_NAV_ITEM_ACTIVE} aria-current="page">
<span
className={`${SIDEBAR_NAV_PILL_ACTIVE} text-[var(--edit-foreground)]`}
>
{SIDEBAR_RESULTS_ICON}
</span>
<span className={SIDEBAR_NAV_LABEL_ACTIVE}>Results</span>
</span>
);
}

if (hasStoredRoutes) {
return (
<Link href="/results" className={SIDEBAR_NAV_ITEM_INACTIVE}>
<span className={SIDEBAR_NAV_PILL_INACTIVE}>
{SIDEBAR_RESULTS_ICON}
</span>
<span className={SIDEBAR_NAV_LABEL_INACTIVE}>Results</span>
</Link>
);
}

return (
<Link
href="#"
className={SIDEBAR_NAV_ITEM_DISABLED}
aria-disabled="true"
tabIndex={-1}
>
{" "}
{/* TODO: add results page link when at least one route exists */}
<button type="button" disabled className={SIDEBAR_NAV_ITEM_DISABLED}>
<span className={SIDEBAR_NAV_PILL_INACTIVE}>{SIDEBAR_RESULTS_ICON}</span>
<span className={SIDEBAR_NAV_LABEL_INACTIVE}>Results</span>
</Link>
</button>
);
}
1 change: 1 addition & 0 deletions app/ui/src/app/edit/utils/csvParserUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const COLUMN_ALIASES: Record<string, string[]> = {
],
phone_number: [
"phone_number",
"recipient_phone",
"phone",
"tel",
"telephone",
Expand Down
14 changes: 14 additions & 0 deletions app/ui/src/app/edit/utils/hasOptimizeResults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/** True when sessionStorage has at least one route ready for /results. */
export function readHasOptimizeResults(): boolean {
if (typeof window === "undefined") return false;

const stored = sessionStorage.getItem("optimizeResults");
if (!stored) return false;

try {
const parsed: unknown = JSON.parse(stored);
return Array.isArray(parsed) && parsed.length > 0;
} catch {
return false;
}
}
23 changes: 23 additions & 0 deletions app/ui/src/app/edit/utils/recipientSummary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { AddressCard } from "../types/delivery";

type RecipientContactFields = Partial<{
recipientName: string;
addresseeName: string;
phoneNumber: string;
}>;

/** Display string for recipient name + phone (middle dot when both set). */
export function recipientSummary(a: RecipientContactFields): string {
const n = (a.recipientName ?? a.addresseeName ?? "").trim();
const p = (a.phoneNumber ?? "").trim();
if (n && p) return `${n} · ${p}`;
if (n) return n;
if (p) return p;
return "—";
}

export function hasRecipientContact(
a: Pick<AddressCard, "recipientName" | "phoneNumber">,
): boolean {
return Boolean(a.recipientName.trim() || a.phoneNumber.trim());
}
6 changes: 5 additions & 1 deletion app/ui/src/app/edit/utils/vroomToRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export function vroomToRoutes(

// arrival is in seconds; % 86400 extracts the within-day portion for display
const arrivalTimeStr = secondsToTimeString(step.arrival % 86400);
const deliveryQuantity = address?.deliveryQuantity ?? 0;

return {
id: step.job_external_id!,
Expand All @@ -64,7 +65,8 @@ export function vroomToRoutes(
lat,
lng,
sequence: idx + 1,
capacityUsed: step.load?.[0] ?? 0,
capacityUsed:
deliveryQuantity > 0 ? deliveryQuantity : (step.load?.[0] ?? 0),
timeWindow: {
kind: inferTimeWindowKind(
address?.deliveryTimeStart,
Expand All @@ -75,6 +77,8 @@ export function vroomToRoutes(
note: address?.notes ?? "",
addresseeName: address?.recipientName || undefined,
phoneNumber: address?.phoneNumber || undefined,
deliveryWindowStart: address?.deliveryTimeStart?.trim() || undefined,
deliveryWindowEnd: address?.deliveryTimeEnd?.trim() || undefined,
};
});

Expand Down
Loading
Loading