Some checks failed
CI / Lint, Unit & Integration Tests (push) Has been cancelled
Multi-pin pickup selection (study §3.4) — previously a standalone unused endpoint + TODO comments: - app/services/pickup-locations.server.ts: pure filterPickupLocationIds + I/O resolvePickupLocations (active + has a PICKUP slot template + ProductRule allowedLocationIds + inventory exclusion). - resolveAvailabilityRequest returns pickupLocations[] on method=PICKUP and defaults the active location to the first eligible pickup point. - apps.scheduling.locations.tsx refactored onto the shared resolver (was a second copy of the logic). - Storefront widget: pickup-location chooser (name + address, optional multi-pin Google map) when >1 eligible point and none block-configured; picking one re-requests availability for that location. New styles + widget.choose_pickup_location locale (en + fr). - Checkout extension Checkout.jsx: same chooser before the date list. - tests/unit/pickup-locations.test.ts (5 cases); suite 161 green. checkout-datetime follow-up fixes from the 808a3b7 review: - typescript devDep ^7.0.2 -> ^5.6.3 (there is no typescript@7 on npm). - Deleted dead shopify.d.ts (Preact-global shim, unused after the React rewrite) and dropped it from tsconfig include. Also stages the CLI-written `uid` lines in the checkout-datetime and payment-customization extension tomls. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
49 lines
2.1 KiB
TypeScript
49 lines
2.1 KiB
TypeScript
import type { LoaderFunctionArgs } from "@remix-run/node";
|
|
import { authenticate } from "../shopify.server";
|
|
import db from "../db.server";
|
|
import {
|
|
resolveProductRuleConstraints,
|
|
resolveProductRefs,
|
|
productRefsFromCartLines,
|
|
} from "../services/product-rules.server";
|
|
import { parseCartLinesParam, parseProductIdsParam, parseGidListParam } from "../lib/cart-rule-params";
|
|
import { resolvePickupLocations } from "../services/pickup-locations.server";
|
|
|
|
// Standalone list of eligible pickup points (study §3.4 multi-pin pickup).
|
|
// The same data is also returned inline on `method=PICKUP` availability
|
|
// responses (`pickupLocations`) — this endpoint stays for callers that just
|
|
// want the list without asking for a specific location's calendar. Shared
|
|
// resolution logic lives in pickup-locations.server.ts so the two paths
|
|
// can't drift.
|
|
export const loader = async ({ request }: LoaderFunctionArgs) => {
|
|
const { session, admin } = await authenticate.public.appProxy(request);
|
|
if (!session) {
|
|
return Response.json({ error: "Shop not found" }, { status: 404 });
|
|
}
|
|
|
|
const url = new URL(request.url);
|
|
|
|
const productIds = parseProductIdsParam(url.searchParams.get("productIds"));
|
|
const productRefs = admin && productIds.length > 0 ? await resolveProductRefs(admin, productIds) : [];
|
|
const cartProductRefs = [
|
|
...productRefs,
|
|
...productRefsFromCartLines(parseCartLinesParam(url.searchParams.get("cartLines"))),
|
|
];
|
|
|
|
const productRules = await db.productRule.findMany({ where: { shopDomain: session.shop, active: true } });
|
|
const ruleConstraints = resolveProductRuleConstraints(productRules, cartProductRefs);
|
|
|
|
// A rule that forbids PICKUP for this cart ⇒ no pickup points at all.
|
|
if (ruleConstraints.allowedMethods != null && !ruleConstraints.allowedMethods.includes("PICKUP")) {
|
|
return Response.json({ locations: [] });
|
|
}
|
|
|
|
const locations = await resolvePickupLocations(session.shop, {
|
|
allowedLocationIds: ruleConstraints.allowedLocationIds,
|
|
admin: admin ?? undefined,
|
|
productVariantGids: parseGidListParam(url.searchParams.get("variantIds")),
|
|
});
|
|
|
|
return Response.json({ locations });
|
|
};
|