4 Commits

Author SHA1 Message Date
metatroncubeswdev
b29962bf9c feat: finish multi-pin pickup end-to-end; fix checkout-datetime followups
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>
2026-09-10 16:47:59 -04:00
metatroncubeswdev
1262e0f5ab feat: cross-theme cart placement for the storefront widget
Some checks failed
CI / Lint, Unit & Integration Tests (push) Has been cancelled
Many themes only expose "Add section" for the cart's checkout area, not
"Add block" next to the actual Checkout button — Shopify gives apps no
supported way to inject a block into an arbitrary spot in a theme's own
section markup, so a manually-placed app block can only ever land as a
disconnected standalone section on those themes.

Add a JS-based fallback via the app embed (already loaded site-wide,
independent of block placement): app-embed.liquid now carries the same
config settings as the block plus an "auto-place on cart page" toggle
(default on), emitted as an inert <template> with the widget's config as
data-* attributes. datetime-widget.ts's maybeAutoPlaceOnCart() finds the
theme's own Checkout button by CSS selector (a few common patterns, most
specific first) and inserts a live widget immediately before it — skipped
entirely if a block-placed widget already exists on the page, or no
Checkout button can be found by any known selector.

Also fix shopify.app.toml: automatically_update_urls_on_dev was left on
after the app got a real, permanent production domain
(metatron-delivery.thedomainnest.com) — leaving it on meant a future local
`shopify app dev` session would silently overwrite the live app's
application_url with a temporary Cloudflare tunnel, breaking the deployed
app until someone noticed and redeployed with the real URL.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 18:19:59 -04:00
metatroncubeswdev
e116a6c87a fix: Theme App Extension only allows assets/blocks/snippets/locales dirs
`shopify app dev` failed dev preview with "Only assets, blocks, snippets,
locales directories are allowed" — the widget's TypeScript source lived in
extensions/datetime-widget/src/, which isn't one of the four directories a
Theme App Extension may contain. Moved it to widget-src/datetime-widget/
(a plain, non-extension folder outside extensions/) and updated
build:widget's esbuild input path accordingly; the bundled output still
lands in the same place (extensions/datetime-widget/assets/).

Also fixed a theme-check warning surfaced during the same run:
`script_tag` renders a parser-blocking <script> with no way to defer it —
switched to a manual <script defer> tag for the widget's JS asset.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 21:51:54 -04:00
metatroncubeswdev
6c633af598 feat: Phase 3 — storefront widget + cart attributes
Theme App Extension (extensions/datetime-widget/) hand-scaffolded from
Shopify's documented structure, since `shopify app generate extension`
needs the same interactive Partner login `shopify app init`/`dev` do
(unavailable in this session) — user confirmed this approach.

- blocks/app-embed.liquid: site-wide toggle that loads the widget's JS/CSS
  once (target: body)
- blocks/datetime-picker.liquid: the actual app block merchants add to a
  cart/product page section, with per-method show/hide toggles and an
  optional location override, all theme-editor-configurable
- src/datetime-widget.ts: vanilla TS (no framework, ~2kb gzipped) — renders
  method -> date -> slot, calls the app-proxy availability endpoint, and on
  selection writes to /cart/update.js cart attributes using a *method-
  specific* attribute name ("Pickup date" vs "Delivery date" vs "Shipping
  date", from locales/en.default.json) rather than one generic label — this
  is the direct fix for the "estimated delivery date on a pickup order"
  complaint PRODUCT_STRATEGY.md §3.1 calls out. Only collects a selection;
  never enforces anything itself (Phase 4's Validation Function does that).
- locales/en.default.json + en.default.schema.json: i18n from day one
- app/routes/apps.scheduling.availability.tsx: the public app-proxy
  endpoint the widget calls. Path is `apps.scheduling.availability` (not
  the plan's suggested `api.availability`) because shopify.app.toml's
  [app_proxy].url already includes the /apps/scheduling prefix, and
  Shopify forwards a shop-facing /apps/scheduling/availability request to
  {url}/availability against that full url — so the Remix route path has
  to mirror the proxy path exactly for the forwarding to land correctly.
  Resolves (location, method) -> DB rows -> getAvailability(), scoped by
  shopDomain throughout. No consumption wired up (Booking doesn't exist
  until Phase 4), so this correctly shows full capacity everywhere for now.

Theme App Extensions have no CLI build step, so `npm run build:widget`
(esbuild, added as a devDependency) bundles src/ into assets/ and is wired
as a predev/predeploy hook so `shopify app dev`/`deploy` never ship a stale
bundle. CI now also runs both `npm run build` and `npm run build:widget`.

Verified: lint, typecheck, unit tests, both builds pass; a live script
exercising the exact DB-query + getAvailability path the availability route
uses (bypassing HTTP, since real app-proxy signature verification needs a
live tunnel) returned correct results against the Postgres container —
correct EDT offset, correct capacity, and exactly the weekday-filtered set
of open dates for the seeded bakery template.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 18:02:33 -04:00