66 lines
2.9 KiB
TypeScript
66 lines
2.9 KiB
TypeScript
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 });
|
|
};
|