import type { LoaderFunctionArgs } from "@remix-run/node"; import { authenticate } from "../shopify.server"; import db from "../db.server"; import { resolveProductRuleConstraints, resolveProductRefs } from "../services/product-rules.server"; import { productRefsFromCartLines } from "../services/product-rules.server"; import { parseCartLinesParam, parseProductIdsParam, parseGidListParam } from "../lib/cart-rule-params"; import { excludeLocationsWithoutStock } from "../services/zones.server"; 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 method = "PICKUP"; const productIds = parseProductIdsParam(url.searchParams.get("productIds")); const productRefs = admin && productIds.length > 0 ? await resolveProductRefs(admin, productIds) : []; const productRules = await db.productRule.findMany({ where: { shopDomain: session.shop, active: true } }); const cartProductRefs = [...productRefs, ...productRefsFromCartLines(parseCartLinesParam(url.searchParams.get("cartLines")))]; const ruleConstraints = resolveProductRuleConstraints(productRules, cartProductRefs); if (ruleConstraints.allowedMethods != null && !ruleConstraints.allowedMethods.includes(method)) { return Response.json({ locations: [] }); } const locationWhere = ruleConstraints.allowedLocationIds != null ? { id: { in: ruleConstraints.allowedLocationIds } } : {}; // Only locations that offer PICKUP (they have slot templates for it) // Wait, the location model doesn't store methods, methods are on SlotTemplate. // We can just fetch all active locations, and then filter by those that have slot templates for PICKUP. const candidates = await db.location.findMany({ where: { shopDomain: session.shop, active: true, ...locationWhere }, orderBy: { createdAt: "asc" }, }); const templates = await db.slotTemplate.findMany({ where: { shopDomain: session.shop, method }, select: { locationId: true } }); const locationsWithPickup = new Set(templates.map(t => t.locationId)); const eligibleCandidates = candidates.filter(c => locationsWithPickup.has(c.id)); const productVariantGids = parseGidListParam(url.searchParams.get("variantIds")); const stockCheckEnabled = Boolean(admin) && productVariantGids.length > 0; const stocked = stockCheckEnabled ? await excludeLocationsWithoutStock(admin!, eligibleCandidates.map(c => c.id), productVariantGids) : new Set(eligibleCandidates.map(c => c.id)); const finalLocations = eligibleCandidates .filter(c => stocked.has(c.id)) .map(c => ({ id: c.id, name: c.name, lat: c.lat, lng: c.lng, address: c.address, })); return Response.json({ locations: finalLocations }); };