From a5941a5149bd9b6af072f0cef38e38ac261d70e3 Mon Sep 17 00:00:00 2001 From: metatroncubeswdev Date: Fri, 16 Oct 2026 07:17:43 -0400 Subject: [PATCH] fix(locations): drop Shopify's literal "null" city from imported addresses Co-Authored-By: Claude Opus 5.5 --- app/lib/__tests__/format.test.ts | 14 ++++++++++++++ app/lib/format.ts | 9 +++++++++ app/services/config.server.ts | 6 ++++-- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 app/lib/__tests__/format.test.ts diff --git a/app/lib/__tests__/format.test.ts b/app/lib/__tests__/format.test.ts new file mode 100644 index 0000000..e2d63be --- /dev/null +++ b/app/lib/__tests__/format.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, it } from "vitest"; +import { cleanAddress } from "../format"; + +describe("cleanAddress", () => { + it("drops Shopify's literal null city", () => { + expect(cleanAddress("null ON, Canada")).toBe("ON, Canada"); + }); + it("drops parts that were only null", () => { + expect(cleanAddress("null, Toronto, Canada")).toBe("Toronto, Canada"); + }); + it("leaves real addresses alone, including words containing null", () => { + expect(cleanAddress("12 Nullarbor Rd, Waterloo ON N2V 1A1, Canada")).toBe("12 Nullarbor Rd, Waterloo ON N2V 1A1, Canada"); + }); +}); diff --git a/app/lib/format.ts b/app/lib/format.ts index 04b9384..e4454db 100644 --- a/app/lib/format.ts +++ b/app/lib/format.ts @@ -30,3 +30,12 @@ export const STATUS_TONE: Record = { pickup: "Pickup", delivery: "Delivery", shipping: "Shipping" }; export const rangesToText = (r?: { start: string; end: string }[]) => (r ?? []).map((x) => `${x.start}-${x.end}`).join(", "); + +/** Shopify's formatted address prints a missing city as the word "null" (e.g. "null ON, Canada"). */ +export function cleanAddress(address: string) { + return address + .split(",") + .map((part) => part.replace(/\bnull\b/g, "").replace(/\s+/g, " ").trim()) + .filter(Boolean) + .join(", "); +} diff --git a/app/services/config.server.ts b/app/services/config.server.ts index 8cd1457..52b277d 100644 --- a/app/services/config.server.ts +++ b/app/services/config.server.ts @@ -4,6 +4,7 @@ import type { Location, PeakDay as PeakRow, ProductRule as RuleRow, Shop } from "@prisma/client"; import prisma from "../db.server"; import type { LocationConfig, Method, PeakDay, ProductRule } from "../engine/types"; +import { cleanAddress } from "../lib/format"; import { restoreCheckoutFunctions } from "../lib/guard.server"; import { type AppSettings, withDefaults } from "./settings"; @@ -21,7 +22,7 @@ export function toLocationConfig(l: Location): LocationConfig { id: l.id, shopifyLocationId: l.shopifyLocationId ?? undefined, name: l.name, - address: l.address, + address: cleanAddress(l.address), timezone: l.timezone, lat: l.lat ?? undefined, lng: l.lng ?? undefined, @@ -102,6 +103,7 @@ type AdminGraphql = { graphql: (q: string, o?: { variables?: Record ({ shopifyLocationId: l.id, name: l.name, - address: l.address.formatted.join(", "), + address: cleanAddress(l.address.formatted.join(", ")), timezone: data.shop.ianaTimezone, lat: l.address.latitude, lng: l.address.longitude,