diff --git a/.eslintignore b/.eslintignore index 3796499..78a49d5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,4 @@ public/build shopify-app-remix */*.yml .shopify +extensions/*/assets/*.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6dbd755..da95435 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm - name: Install dependencies run: npm ci @@ -22,3 +22,7 @@ jobs: run: npm run typecheck - name: Unit tests run: npm test -- --run + - name: Build admin app + run: npm run build + - name: Build storefront widget + run: npm run build:widget diff --git a/app/routes/apps.scheduling.availability.tsx b/app/routes/apps.scheduling.availability.tsx new file mode 100644 index 0000000..bdde857 --- /dev/null +++ b/app/routes/apps.scheduling.availability.tsx @@ -0,0 +1,113 @@ +import type { LoaderFunctionArgs } from "@remix-run/node"; +import { DateTime } from "luxon"; +import type { Method } from "@prisma/client"; +import { authenticate } from "../shopify.server"; +import db from "../db.server"; +import { getAvailability } from "../services/scheduling.server"; + +// Public endpoint, reachable only through Shopify's App Proxy (signature +// verified by authenticate.public.appProxy) — this is what the storefront +// Theme App Extension calls. Requests to https://{shop}/apps/scheduling/* +// forward here because shopify.app.toml's [app_proxy].url already includes +// the /apps/scheduling prefix, so this file's path (apps.scheduling.*) +// mirrors the shop-facing URL exactly. +// +// No capacity consumption is wired up yet (Booking/SlotHold don't exist +// until Phase 4), so every slot's `consumed` is implicitly 0 here — that's +// expected for Phase 3, not a bug to fix in this file. + +const VALID_METHODS = new Set(["SHIPPING", "LOCAL_DELIVERY", "PICKUP"]); +const MAX_DAYS = 60; +const DEFAULT_DAYS = 14; + +function toIsoDate(date: Date): string { + return date.toISOString().slice(0, 10); +} + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const { session } = await authenticate.public.appProxy(request); + if (!session) { + return Response.json({ error: "Shop not found" }, { status: 404 }); + } + + const url = new URL(request.url); + const methodParam = url.searchParams.get("method"); + const locationIdParam = url.searchParams.get("locationId"); + const daysParam = Number(url.searchParams.get("days") ?? DEFAULT_DAYS); + const days = Number.isFinite(daysParam) && daysParam > 0 ? Math.min(daysParam, MAX_DAYS) : DEFAULT_DAYS; + + if (!methodParam || !VALID_METHODS.has(methodParam as Method)) { + return Response.json({ error: "Invalid or missing method" }, { status: 400 }); + } + const method = methodParam as Method; + + const location = locationIdParam + ? await db.location.findFirst({ + where: { id: locationIdParam, shopDomain: session.shop, active: true }, + }) + : await db.location.findFirst({ + where: { shopDomain: session.shop, active: true }, + orderBy: { createdAt: "asc" }, + }); + + if (!location) { + return Response.json({ error: "No active location configured" }, { status: 404 }); + } + + const now = DateTime.now().setZone(location.timezone); + const startDate = now.toISODate()!; + const endDate = now.plus({ days }).toISODate()!; + const rangeStart = DateTime.fromISO(startDate, { zone: "utc" }).toJSDate(); + const rangeEnd = DateTime.fromISO(endDate, { zone: "utc" }).toJSDate(); + + const [slotTemplates, overrides, blackouts] = await Promise.all([ + db.slotTemplate.findMany({ + where: { shopDomain: session.shop, locationId: location.id, method }, + }), + db.slotOverride.findMany({ + where: { + shopDomain: session.shop, + locationId: location.id, + method, + date: { gte: rangeStart, lte: rangeEnd }, + }, + }), + db.blackoutDate.findMany({ + where: { + shopDomain: session.shop, + date: { gte: rangeStart, lte: rangeEnd }, + AND: [{ OR: [{ locationId: location.id }, { locationId: null }] }, { OR: [{ method }, { method: null }] }], + }, + }), + ]); + + const availability = getAvailability({ + timezone: location.timezone, + dateRange: { startDate, endDate }, + slotTemplates: slotTemplates.map((t) => ({ + weekday: t.weekday, + startMin: t.startMin, + endMin: t.endMin, + capacity: t.capacity, + cutoffMin: t.cutoffMin, + leadTimeMin: t.leadTimeMin, + })), + overrides: overrides.map((o) => ({ + date: toIsoDate(o.date), + closed: o.closed, + startMin: o.startMin, + endMin: o.endMin, + capacity: o.capacity, + })), + blackoutDates: blackouts.map((b) => ({ date: toIsoDate(b.date) })), + now, + }); + + return Response.json({ + locationId: location.id, + locationName: location.name, + timezone: location.timezone, + method, + dates: availability, + }); +}; diff --git a/extensions/datetime-widget/assets/datetime-widget.css b/extensions/datetime-widget/assets/datetime-widget.css new file mode 100644 index 0000000..d577d04 --- /dev/null +++ b/extensions/datetime-widget/assets/datetime-widget.css @@ -0,0 +1,57 @@ +.dd-widget { + display: flex; + flex-direction: column; + gap: 0.75rem; + font-family: inherit; + min-height: 3.5rem; /* reserves space before JS renders content, to avoid layout shift */ +} + +.dd-widget__heading { + font-size: 1rem; + font-weight: 600; + margin: 0; +} + +.dd-widget__row { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; +} + +.dd-widget__pill { + border: 1px solid currentColor; + border-radius: 999px; + background: transparent; + padding: 0.4rem 0.9rem; + font-size: 0.875rem; + cursor: pointer; + color: inherit; +} + +.dd-widget__pill[aria-pressed="true"] { + background: currentColor; + color: Canvas; +} + +.dd-widget__status { + font-size: 0.875rem; + opacity: 0.75; + margin: 0; +} + +.dd-widget__confirmation { + display: flex; + align-items: center; + gap: 0.75rem; + font-size: 0.9rem; +} + +.dd-widget__link { + background: none; + border: none; + padding: 0; + text-decoration: underline; + cursor: pointer; + color: inherit; + font: inherit; +} diff --git a/extensions/datetime-widget/assets/datetime-widget.js b/extensions/datetime-widget/assets/datetime-widget.js new file mode 100644 index 0000000..07700fe --- /dev/null +++ b/extensions/datetime-widget/assets/datetime-widget.js @@ -0,0 +1 @@ +"use strict";(()=>{var g=Object.defineProperty;var u=(n,t,e)=>t in n?g(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var l=(n,t,e)=>u(n,typeof t!="symbol"?t+"":t,e);var f="/apps/scheduling";function r(n){let t=Math.floor(n/60),e=n%60,i=t<12?"AM":"PM";return`${t%12===0?12:t%12}:${e.toString().padStart(2,"0")} ${i}`}function c(n){let[t,e,i]=n.split("-").map(Number);return new Date(Date.UTC(t,e-1,i)).toLocaleDateString(void 0,{weekday:"short",month:"short",day:"numeric",timeZone:"UTC"})}function b(n){let t=n.dataset,e=[];return t.showShipping==="true"&&e.push({value:"SHIPPING",label:t.labelShipping||"Shipping",attrLabel:t.attrLabelShipping||"Shipping date"}),t.showLocalDelivery==="true"&&e.push({value:"LOCAL_DELIVERY",label:t.labelLocalDelivery||"Local delivery",attrLabel:t.attrLabelLocalDelivery||"Delivery date"}),t.showPickup==="true"&&e.push({value:"PICKUP",label:t.labelPickup||"Pickup",attrLabel:t.attrLabelPickup||"Pickup date"}),{root:n,heading:t.heading||"",locationId:t.locationId||null,methods:e,labels:{chooseDate:t.labelChooseDate||"Choose a date",chooseTime:t.labelChooseTime||"Choose a time",noDates:t.labelNoDates||"No dates are available right now.",confirmed:t.labelConfirmed||"Confirmed for",change:t.labelChange||"Change",loading:t.labelLoading||"Loading available dates\u2026",error:t.labelError||"Couldn't load available dates. Please try again."}}}async function p(n,t){let e=new URLSearchParams({method:n,days:"14"});t&&e.set("locationId",t);let i=await fetch(`${f}/availability?${e.toString()}`,{headers:{Accept:"application/json"}}),s=await i.json();if(!i.ok)throw new Error(s.error||`Request failed (${i.status})`);return s}async function w(n,t){await fetch("/cart/update.js",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({attributes:{[n]:t.display,...t}})})}var h=class{constructor(t){l(this,"config");l(this,"el",{heading:document.createElement("h3"),methodRow:document.createElement("div"),dateRow:document.createElement("div"),timeRow:document.createElement("div"),status:document.createElement("p"),confirmation:document.createElement("div")});l(this,"selectedMethod",null);l(this,"selectedDate",null);l(this,"availability",null);this.config=t}mount(){let{root:t,heading:e,methods:i}=this.config;t.classList.add("dd-widget--ready"),t.innerHTML="",i.length!==0&&(e&&(this.el.heading.className="dd-widget__heading",this.el.heading.textContent=e,t.appendChild(this.el.heading)),this.el.methodRow.className="dd-widget__row dd-widget__methods",this.el.dateRow.className="dd-widget__row dd-widget__dates",this.el.timeRow.className="dd-widget__row dd-widget__times",this.el.status.className="dd-widget__status",this.el.confirmation.className="dd-widget__confirmation",this.el.confirmation.hidden=!0,t.append(this.el.confirmation,this.el.methodRow,this.el.dateRow,this.el.timeRow,this.el.status),i.length===1?this.selectMethod(i[0]):this.renderMethods())}renderMethods(){var t;this.el.methodRow.innerHTML="";for(let e of this.config.methods){let i=document.createElement("button");i.type="button",i.className="dd-widget__pill",i.textContent=e.label,i.setAttribute("aria-pressed",String(((t=this.selectedMethod)==null?void 0:t.value)===e.value)),i.addEventListener("click",()=>this.selectMethod(e)),this.el.methodRow.appendChild(i)}}async selectMethod(t){this.selectedMethod=t,this.selectedDate=null,this.el.timeRow.innerHTML="",this.el.confirmation.hidden=!0,this.config.methods.length>1&&this.renderMethods(),this.el.status.textContent=this.config.labels.loading,this.el.dateRow.innerHTML="";try{this.availability=await p(t.value,this.config.locationId),this.renderDates()}catch{this.el.status.textContent=this.config.labels.error}}renderDates(){var e,i;let t=Object.keys((i=(e=this.availability)==null?void 0:e.dates)!=null?i:{}).sort();if(this.el.dateRow.innerHTML="",t.length===0){this.el.status.textContent=this.config.labels.noDates;return}this.el.status.textContent=this.config.labels.chooseDate;for(let s of t){let a=document.createElement("button");a.type="button",a.className="dd-widget__pill",a.textContent=c(s),a.setAttribute("aria-pressed",String(this.selectedDate===s)),a.addEventListener("click",()=>this.selectDate(s)),this.el.dateRow.appendChild(a)}}selectDate(t){var i,s;this.selectedDate=t;for(let a of Array.from(this.el.dateRow.children))a.setAttribute("aria-pressed",String(a.textContent===c(t)));let e=(s=(i=this.availability)==null?void 0:i.dates[t])!=null?s:[];this.el.timeRow.innerHTML="",this.el.status.textContent=this.config.labels.chooseTime;for(let a of e){let o=document.createElement("button");o.type="button",o.className="dd-widget__pill",o.textContent=`${r(a.startMin)}\u2013${r(a.endMin)}`,o.addEventListener("click",()=>this.selectSlot(t,a)),this.el.timeRow.appendChild(o)}}async selectSlot(t,e){let i=this.selectedMethod,s=this.availability,a=`${c(t)}, ${r(e.startMin)}\u2013${r(e.endMin)}`;this.el.status.textContent=this.config.labels.loading;try{await w(i.attrLabel,{display:a,dd_method:i.value,dd_date:t,dd_start_min:String(e.startMin),dd_end_min:String(e.endMin),dd_location_id:s.locationId}),this.el.status.textContent="",this.el.methodRow.hidden=!0,this.el.dateRow.hidden=!0,this.el.timeRow.hidden=!0,this.el.confirmation.hidden=!1,this.el.confirmation.innerHTML="";let o=document.createElement("p");o.textContent=`${this.config.labels.confirmed} ${a}`;let d=document.createElement("button");d.type="button",d.className="dd-widget__link",d.textContent=this.config.labels.change,d.addEventListener("click",()=>{this.el.methodRow.hidden=!1,this.el.dateRow.hidden=!1,this.el.timeRow.hidden=!1,this.el.confirmation.hidden=!0}),this.el.confirmation.append(o,d)}catch{this.el.status.textContent=this.config.labels.error}}};function m(){document.querySelectorAll("[data-dd-widget]").forEach(t=>{new h(b(t)).mount()})}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",m):m();})(); diff --git a/extensions/datetime-widget/blocks/app-embed.liquid b/extensions/datetime-widget/blocks/app-embed.liquid new file mode 100644 index 0000000..fc54cdf --- /dev/null +++ b/extensions/datetime-widget/blocks/app-embed.liquid @@ -0,0 +1,10 @@ +{{ 'datetime-widget.css' | asset_url | stylesheet_tag }} +{{ 'datetime-widget.js' | asset_url | script_tag }} + +{% schema %} +{ + "name": "t:app_embed.name", + "target": "body", + "settings": [] +} +{% endschema %} diff --git a/extensions/datetime-widget/blocks/datetime-picker.liquid b/extensions/datetime-widget/blocks/datetime-picker.liquid new file mode 100644 index 0000000..4c5e7e8 --- /dev/null +++ b/extensions/datetime-widget/blocks/datetime-picker.liquid @@ -0,0 +1,64 @@ +
+ +
+ +{% schema %} +{ + "name": "t:datetime_picker.name", + "target": "section", + "settings": [ + { + "type": "text", + "id": "heading", + "label": "t:datetime_picker.heading_label", + "default": "Choose your delivery date" + }, + { + "type": "checkbox", + "id": "show_shipping", + "label": "t:datetime_picker.show_shipping_label", + "default": true + }, + { + "type": "checkbox", + "id": "show_local_delivery", + "label": "t:datetime_picker.show_local_delivery_label", + "default": true + }, + { + "type": "checkbox", + "id": "show_pickup", + "label": "t:datetime_picker.show_pickup_label", + "default": true + }, + { + "type": "text", + "id": "location_id", + "label": "t:datetime_picker.location_id_label", + "info": "t:datetime_picker.location_id_info" + } + ] +} +{% endschema %} diff --git a/extensions/datetime-widget/locales/en.default.json b/extensions/datetime-widget/locales/en.default.json new file mode 100644 index 0000000..8b84f80 --- /dev/null +++ b/extensions/datetime-widget/locales/en.default.json @@ -0,0 +1,18 @@ +{ + "widget": { + "method_shipping": "Shipping", + "method_local_delivery": "Local delivery", + "method_pickup": "Pickup", + "date_label_shipping": "Shipping date", + "date_label_local_delivery": "Delivery date", + "date_label_pickup": "Pickup date", + "choose_date": "Choose a date", + "choose_time": "Choose a time", + "no_dates": "No dates are available right now.", + "confirmed": "Confirmed for", + "change": "Change", + "loading": "Loading available dates…", + "error": "Couldn't load available dates. Please try again.", + "enable_js": "Please enable JavaScript to choose a delivery date and time." + } +} diff --git a/extensions/datetime-widget/locales/en.default.schema.json b/extensions/datetime-widget/locales/en.default.schema.json new file mode 100644 index 0000000..82b733a --- /dev/null +++ b/extensions/datetime-widget/locales/en.default.schema.json @@ -0,0 +1,14 @@ +{ + "app_embed": { + "name": "Delivery Date & Time" + }, + "datetime_picker": { + "name": "Date & Time Picker", + "heading_label": "Heading", + "show_shipping_label": "Show Shipping", + "show_local_delivery_label": "Show Local Delivery", + "show_pickup_label": "Show Pickup", + "location_id_label": "Location ID (advanced)", + "location_id_info": "Leave blank to use the shop's default location." + } +} diff --git a/extensions/datetime-widget/shopify.extension.toml b/extensions/datetime-widget/shopify.extension.toml new file mode 100644 index 0000000..61eea4f --- /dev/null +++ b/extensions/datetime-widget/shopify.extension.toml @@ -0,0 +1,2 @@ +name = "Delivery Date & Time" +type = "theme" diff --git a/extensions/datetime-widget/src/datetime-widget.ts b/extensions/datetime-widget/src/datetime-widget.ts new file mode 100644 index 0000000..b0b85d3 --- /dev/null +++ b/extensions/datetime-widget/src/datetime-widget.ts @@ -0,0 +1,295 @@ +// Storefront widget for the Theme App Extension. Vanilla TS, no framework +// (IMPLEMENTATION_PLAN.md §1 sanctions "Preact or vanilla TS" — vanilla +// keeps the bundle tiny and avoids a runtime dependency for something this +// small). Bundled to ../assets/datetime-widget.js via esbuild +// (`npm run build:widget` at the repo root) — Theme App Extensions ship +// static assets as-is, there's no CLI build step for this extension type. +// +// The widget only *collects* a selection and writes it to cart attributes. +// It never enforces anything — that's the Validation Function's job +// (Phase 4), per CLAUDE.md's non-negotiable that enforcement is +// server-side. Losing network, JS, or an ad-blocker here should degrade to +// "no slot picked" (which the Function then rejects at checkout), not to a +// bypass. + +type Method = "SHIPPING" | "LOCAL_DELIVERY" | "PICKUP"; + +interface SlotDto { + date: string; + startMin: number; + endMin: number; + capacity: number; + remainingCapacity: number; +} + +interface AvailabilityResponse { + locationId: string; + locationName: string; + timezone: string; + method: Method; + dates: Record; + error?: string; +} + +interface WidgetConfig { + root: HTMLElement; + heading: string; + locationId: string | null; + methods: Array<{ value: Method; label: string; attrLabel: string }>; + labels: { + chooseDate: string; + chooseTime: string; + noDates: string; + confirmed: string; + change: string; + loading: string; + error: string; + }; +} + +const PROXY_BASE = "/apps/scheduling"; + +function minutesToDisplayTime(minutes: number): string { + const h24 = Math.floor(minutes / 60); + const m = minutes % 60; + const period = h24 < 12 ? "AM" : "PM"; + const h12 = h24 % 12 === 0 ? 12 : h24 % 12; + return `${h12}:${m.toString().padStart(2, "0")} ${period}`; +} + +function formatDateLabel(dateIso: string): string { + // Parsed as a plain calendar date (no timezone conversion) — this string + // already represents the location-local calendar day from the API. + const [year, month, day] = dateIso.split("-").map(Number); + const date = new Date(Date.UTC(year, month - 1, day)); + return date.toLocaleDateString(undefined, { weekday: "short", month: "short", day: "numeric", timeZone: "UTC" }); +} + +function readConfig(root: HTMLElement): WidgetConfig { + const d = root.dataset; + const methods: WidgetConfig["methods"] = []; + if (d.showShipping === "true") { + methods.push({ value: "SHIPPING", label: d.labelShipping || "Shipping", attrLabel: d.attrLabelShipping || "Shipping date" }); + } + if (d.showLocalDelivery === "true") { + methods.push({ + value: "LOCAL_DELIVERY", + label: d.labelLocalDelivery || "Local delivery", + attrLabel: d.attrLabelLocalDelivery || "Delivery date", + }); + } + if (d.showPickup === "true") { + methods.push({ value: "PICKUP", label: d.labelPickup || "Pickup", attrLabel: d.attrLabelPickup || "Pickup date" }); + } + + return { + root, + heading: d.heading || "", + locationId: d.locationId || null, + methods, + labels: { + chooseDate: d.labelChooseDate || "Choose a date", + chooseTime: d.labelChooseTime || "Choose a time", + noDates: d.labelNoDates || "No dates are available right now.", + confirmed: d.labelConfirmed || "Confirmed for", + change: d.labelChange || "Change", + loading: d.labelLoading || "Loading available dates…", + error: d.labelError || "Couldn't load available dates. Please try again.", + }, + }; +} + +async function fetchAvailability(method: Method, locationId: string | null): Promise { + const params = new URLSearchParams({ method, days: "14" }); + if (locationId) params.set("locationId", locationId); + const res = await fetch(`${PROXY_BASE}/availability?${params.toString()}`, { + headers: { Accept: "application/json" }, + }); + const body = (await res.json()) as AvailabilityResponse; + if (!res.ok) throw new Error(body.error || `Request failed (${res.status})`); + return body; +} + +async function writeCartAttribute(key: string, value: Record): Promise { + await fetch("/cart/update.js", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ attributes: { [key]: value.display, ...value } }), + }); +} + +class DateTimeWidget { + private config: WidgetConfig; + private el = { + heading: document.createElement("h3"), + methodRow: document.createElement("div"), + dateRow: document.createElement("div"), + timeRow: document.createElement("div"), + status: document.createElement("p"), + confirmation: document.createElement("div"), + }; + private selectedMethod: WidgetConfig["methods"][number] | null = null; + private selectedDate: string | null = null; + private availability: AvailabilityResponse | null = null; + + constructor(config: WidgetConfig) { + this.config = config; + } + + mount() { + const { root, heading, methods } = this.config; + root.classList.add("dd-widget--ready"); + root.innerHTML = ""; + + if (methods.length === 0) return; // merchant disabled every method — render nothing + + if (heading) { + this.el.heading.className = "dd-widget__heading"; + this.el.heading.textContent = heading; + root.appendChild(this.el.heading); + } + + this.el.methodRow.className = "dd-widget__row dd-widget__methods"; + this.el.dateRow.className = "dd-widget__row dd-widget__dates"; + this.el.timeRow.className = "dd-widget__row dd-widget__times"; + this.el.status.className = "dd-widget__status"; + this.el.confirmation.className = "dd-widget__confirmation"; + this.el.confirmation.hidden = true; + + root.append(this.el.confirmation, this.el.methodRow, this.el.dateRow, this.el.timeRow, this.el.status); + + if (methods.length === 1) { + this.selectMethod(methods[0]); + } else { + this.renderMethods(); + } + } + + private renderMethods() { + this.el.methodRow.innerHTML = ""; + for (const method of this.config.methods) { + const button = document.createElement("button"); + button.type = "button"; + button.className = "dd-widget__pill"; + button.textContent = method.label; + button.setAttribute("aria-pressed", String(this.selectedMethod?.value === method.value)); + button.addEventListener("click", () => this.selectMethod(method)); + this.el.methodRow.appendChild(button); + } + } + + private async selectMethod(method: WidgetConfig["methods"][number]) { + this.selectedMethod = method; + this.selectedDate = null; + this.el.timeRow.innerHTML = ""; + this.el.confirmation.hidden = true; + if (this.config.methods.length > 1) this.renderMethods(); + + this.el.status.textContent = this.config.labels.loading; + this.el.dateRow.innerHTML = ""; + + try { + this.availability = await fetchAvailability(method.value, this.config.locationId); + this.renderDates(); + } catch { + this.el.status.textContent = this.config.labels.error; + } + } + + private renderDates() { + const dates = Object.keys(this.availability?.dates ?? {}).sort(); + this.el.dateRow.innerHTML = ""; + + if (dates.length === 0) { + this.el.status.textContent = this.config.labels.noDates; + return; + } + + this.el.status.textContent = this.config.labels.chooseDate; + for (const date of dates) { + const button = document.createElement("button"); + button.type = "button"; + button.className = "dd-widget__pill"; + button.textContent = formatDateLabel(date); + button.setAttribute("aria-pressed", String(this.selectedDate === date)); + button.addEventListener("click", () => this.selectDate(date)); + this.el.dateRow.appendChild(button); + } + } + + private selectDate(date: string) { + this.selectedDate = date; + for (const child of Array.from(this.el.dateRow.children)) { + child.setAttribute("aria-pressed", String(child.textContent === formatDateLabel(date))); + } + + const slots = this.availability?.dates[date] ?? []; + this.el.timeRow.innerHTML = ""; + this.el.status.textContent = this.config.labels.chooseTime; + + for (const slot of slots) { + const button = document.createElement("button"); + button.type = "button"; + button.className = "dd-widget__pill"; + button.textContent = `${minutesToDisplayTime(slot.startMin)}–${minutesToDisplayTime(slot.endMin)}`; + button.addEventListener("click", () => this.selectSlot(date, slot)); + this.el.timeRow.appendChild(button); + } + } + + private async selectSlot(date: string, slot: SlotDto) { + const method = this.selectedMethod!; + const availability = this.availability!; + const display = `${formatDateLabel(date)}, ${minutesToDisplayTime(slot.startMin)}–${minutesToDisplayTime(slot.endMin)}`; + + this.el.status.textContent = this.config.labels.loading; + + try { + await writeCartAttribute(method.attrLabel, { + display, + dd_method: method.value, + dd_date: date, + dd_start_min: String(slot.startMin), + dd_end_min: String(slot.endMin), + dd_location_id: availability.locationId, + }); + + this.el.status.textContent = ""; + this.el.methodRow.hidden = true; + this.el.dateRow.hidden = true; + this.el.timeRow.hidden = true; + this.el.confirmation.hidden = false; + this.el.confirmation.innerHTML = ""; + + const summary = document.createElement("p"); + summary.textContent = `${this.config.labels.confirmed} ${display}`; + const changeButton = document.createElement("button"); + changeButton.type = "button"; + changeButton.className = "dd-widget__link"; + changeButton.textContent = this.config.labels.change; + changeButton.addEventListener("click", () => { + this.el.methodRow.hidden = false; + this.el.dateRow.hidden = false; + this.el.timeRow.hidden = false; + this.el.confirmation.hidden = true; + }); + + this.el.confirmation.append(summary, changeButton); + } catch { + this.el.status.textContent = this.config.labels.error; + } + } +} + +function init() { + const roots = document.querySelectorAll("[data-dd-widget]"); + roots.forEach((root) => { + new DateTimeWidget(readConfig(root)).mount(); + }); +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); +} else { + init(); +} diff --git a/package-lock.json b/package-lock.json index b507e8e..0063270 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "@types/node": "^22.2.0", "@types/react": "^18.2.31", "@types/react-dom": "^18.2.14", + "esbuild": "^0.24.2", "eslint": "^8.42.0", "eslint-config-prettier": "^10.0.1", "prettier": "^3.2.4", @@ -770,9 +771,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.6.tgz", - "integrity": "sha512-bSC9YVUjADDy1gae8RrioINU6e1lCkg3VGVwm0QQ2E1CWcC4gnMce9+B6RpxuSsrsXsk1yojn7sp1fnG8erE2g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", "cpu": [ "arm" ], @@ -782,13 +783,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.6.tgz", - "integrity": "sha512-YnYSCceN/dUzUr5kdtUzB+wZprCafuD89Hs0Aqv9QSdwhYQybhXTaSTcrl6X/aWThn1a/j0eEpUBGOE7269REg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", "cpu": [ "arm64" ], @@ -798,13 +799,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.6.tgz", - "integrity": "sha512-MVcYcgSO7pfu/x34uX9u2QIZHmXAB7dEiLQC5bBl5Ryqtpj9lT2sg3gNDEsrPEmimSJW2FXIaxqSQ501YLDsZQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", "cpu": [ "x64" ], @@ -814,13 +815,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.6.tgz", - "integrity": "sha512-bsDRvlbKMQMt6Wl08nHtFz++yoZHsyTOxnjfB2Q95gato+Yi4WnRl13oC2/PJJA9yLCoRv9gqT/EYX0/zDsyMA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", "cpu": [ "arm64" ], @@ -830,13 +831,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.6.tgz", - "integrity": "sha512-xh2A5oPrYRfMFz74QXIQTQo8uA+hYzGWJFoeTE8EvoZGHb+idyV4ATaukaUvnnxJiauhs/fPx3vYhU4wiGfosg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", "cpu": [ "x64" ], @@ -846,13 +847,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.6.tgz", - "integrity": "sha512-EnUwjRc1inT4ccZh4pB3v1cIhohE2S4YXlt1OvI7sw/+pD+dIE4smwekZlEPIwY6PhU6oDWwITrQQm5S2/iZgg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", "cpu": [ "arm64" ], @@ -862,13 +863,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.6.tgz", - "integrity": "sha512-Uh3HLWGzH6FwpviUcLMKPCbZUAFzv67Wj5MTwK6jn89b576SR2IbEp+tqUHTr8DIl0iDmBAf51MVaP7pw6PY5Q==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", "cpu": [ "x64" ], @@ -878,13 +879,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.6.tgz", - "integrity": "sha512-7YdGiurNt7lqO0Bf/U9/arrPWPqdPqcV6JCZda4LZgEn+PTQ5SMEI4MGR52Bfn3+d6bNEGcWFzlIxiQdS48YUw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", "cpu": [ "arm" ], @@ -894,13 +895,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.6.tgz", - "integrity": "sha512-bUR58IFOMJX523aDVozswnlp5yry7+0cRLCXDsxnUeQYJik1DukMY+apBsLOZJblpH+K7ox7YrKrHmJoWqVR9w==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", "cpu": [ "arm64" ], @@ -910,13 +911,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.6.tgz", - "integrity": "sha512-ujp8uoQCM9FRcbDfkqECoARsLnLfCUhKARTP56TFPog8ie9JG83D5GVKjQ6yVrEVdMie1djH86fm98eY3quQkQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", "cpu": [ "ia32" ], @@ -926,13 +927,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.6.tgz", - "integrity": "sha512-y2NX1+X/Nt+izj9bLoiaYB9YXT/LoaQFYvCkVD77G/4F+/yuVXYCWz4SE9yr5CBMbOxOfBcy/xFL4LlOeNlzYQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", "cpu": [ "loong64" ], @@ -942,13 +943,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.6.tgz", - "integrity": "sha512-09AXKB1HDOzXD+j3FdXCiL/MWmZP0Ex9eR8DLMBVcHorrWJxWmY8Nms2Nm41iRM64WVx7bA/JVHMv081iP2kUA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", "cpu": [ "mips64el" ], @@ -958,13 +959,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.6.tgz", - "integrity": "sha512-AmLhMzkM8JuqTIOhxnX4ubh0XWJIznEynRnZAVdA2mMKE6FAfwT2TWKTwdqMG+qEaeyDPtfNoZRpJbD4ZBv0Tg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", "cpu": [ "ppc64" ], @@ -974,13 +975,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.6.tgz", - "integrity": "sha512-Y4Ri62PfavhLQhFbqucysHOmRamlTVK10zPWlqjNbj2XMea+BOs4w6ASKwQwAiqf9ZqcY9Ab7NOU4wIgpxwoSQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", "cpu": [ "riscv64" ], @@ -990,13 +991,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.6.tgz", - "integrity": "sha512-SPUiz4fDbnNEm3JSdUW8pBJ/vkop3M1YwZAVwvdwlFLoJwKEZ9L98l3tzeyMzq27CyepDQ3Qgoba44StgbiN5Q==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", "cpu": [ "s390x" ], @@ -1006,13 +1007,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.6.tgz", - "integrity": "sha512-a3yHLmOodHrzuNgdpB7peFGPx1iJ2x6m+uDvhP2CKdr2CwOaqEFMeSqYAHU7hG+RjCq8r2NFujcd/YsEsFgTGw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", "cpu": [ "x64" ], @@ -1022,7 +1023,7 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/netbsd-arm64": { @@ -1042,9 +1043,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.6.tgz", - "integrity": "sha512-EanJqcU/4uZIBreTrnbnre2DXgXSa+Gjap7ifRfllpmyAU7YMvaXmljdArptTHmjrkkKm9BK6GH5D5Yo+p6y5A==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", "cpu": [ "x64" ], @@ -1054,7 +1055,7 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/openbsd-arm64": { @@ -1074,9 +1075,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.6.tgz", - "integrity": "sha512-xaxeSunhQRsTNGFanoOkkLtnmMn5QbA0qBhNet/XLVsc+OVkpIWPHcr3zTW2gxVU5YOHFbIHR9ODuaUdNza2Vw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", "cpu": [ "x64" ], @@ -1086,7 +1087,7 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/openharmony-arm64": { @@ -1106,9 +1107,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.6.tgz", - "integrity": "sha512-gnMnMPg5pfMkZvhHee21KbKdc6W3GR8/JuE0Da1kjwpK6oiFU3nqfHuVPgUX2rsOx9N2SadSQTIYV1CIjYG+xw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", "cpu": [ "x64" ], @@ -1118,13 +1119,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.6.tgz", - "integrity": "sha512-G95n7vP1UnGJPsVdKXllAJPtqjMvFYbN20e8RK8LVLhlTiSOH1sd7+Gt7rm70xiG+I5tM58nYgwWrLs6I1jHqg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", "cpu": [ "arm64" ], @@ -1134,13 +1135,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.6.tgz", - "integrity": "sha512-96yEFzLhq5bv9jJo5JhTs1gI+1cKQ83cUpyxHuGqXVwQtY5Eq54ZEsKs8veKtiKwlrNimtckHEkj4mRh4pPjsg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", "cpu": [ "ia32" ], @@ -1150,13 +1151,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.6.tgz", - "integrity": "sha512-n6d8MOyUrNp6G4VSpRcgjs5xj4A91svJSaiwLIDWVWEsZtpN5FA9NlBbZHDmAJc2e8e6SF4tkBD3HAvPF+7igA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", "cpu": [ "x64" ], @@ -1166,7 +1167,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -3770,6 +3771,395 @@ } } }, + "node_modules/@remix-run/dev/node_modules/@esbuild/android-arm": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.6.tgz", + "integrity": "sha512-bSC9YVUjADDy1gae8RrioINU6e1lCkg3VGVwm0QQ2E1CWcC4gnMce9+B6RpxuSsrsXsk1yojn7sp1fnG8erE2g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/android-arm64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.6.tgz", + "integrity": "sha512-YnYSCceN/dUzUr5kdtUzB+wZprCafuD89Hs0Aqv9QSdwhYQybhXTaSTcrl6X/aWThn1a/j0eEpUBGOE7269REg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/android-x64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.6.tgz", + "integrity": "sha512-MVcYcgSO7pfu/x34uX9u2QIZHmXAB7dEiLQC5bBl5Ryqtpj9lT2sg3gNDEsrPEmimSJW2FXIaxqSQ501YLDsZQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/darwin-arm64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.6.tgz", + "integrity": "sha512-bsDRvlbKMQMt6Wl08nHtFz++yoZHsyTOxnjfB2Q95gato+Yi4WnRl13oC2/PJJA9yLCoRv9gqT/EYX0/zDsyMA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/darwin-x64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.6.tgz", + "integrity": "sha512-xh2A5oPrYRfMFz74QXIQTQo8uA+hYzGWJFoeTE8EvoZGHb+idyV4ATaukaUvnnxJiauhs/fPx3vYhU4wiGfosg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.6.tgz", + "integrity": "sha512-EnUwjRc1inT4ccZh4pB3v1cIhohE2S4YXlt1OvI7sw/+pD+dIE4smwekZlEPIwY6PhU6oDWwITrQQm5S2/iZgg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/freebsd-x64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.6.tgz", + "integrity": "sha512-Uh3HLWGzH6FwpviUcLMKPCbZUAFzv67Wj5MTwK6jn89b576SR2IbEp+tqUHTr8DIl0iDmBAf51MVaP7pw6PY5Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/linux-arm": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.6.tgz", + "integrity": "sha512-7YdGiurNt7lqO0Bf/U9/arrPWPqdPqcV6JCZda4LZgEn+PTQ5SMEI4MGR52Bfn3+d6bNEGcWFzlIxiQdS48YUw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/linux-arm64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.6.tgz", + "integrity": "sha512-bUR58IFOMJX523aDVozswnlp5yry7+0cRLCXDsxnUeQYJik1DukMY+apBsLOZJblpH+K7ox7YrKrHmJoWqVR9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/linux-ia32": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.6.tgz", + "integrity": "sha512-ujp8uoQCM9FRcbDfkqECoARsLnLfCUhKARTP56TFPog8ie9JG83D5GVKjQ6yVrEVdMie1djH86fm98eY3quQkQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/linux-loong64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.6.tgz", + "integrity": "sha512-y2NX1+X/Nt+izj9bLoiaYB9YXT/LoaQFYvCkVD77G/4F+/yuVXYCWz4SE9yr5CBMbOxOfBcy/xFL4LlOeNlzYQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/linux-mips64el": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.6.tgz", + "integrity": "sha512-09AXKB1HDOzXD+j3FdXCiL/MWmZP0Ex9eR8DLMBVcHorrWJxWmY8Nms2Nm41iRM64WVx7bA/JVHMv081iP2kUA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/linux-ppc64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.6.tgz", + "integrity": "sha512-AmLhMzkM8JuqTIOhxnX4ubh0XWJIznEynRnZAVdA2mMKE6FAfwT2TWKTwdqMG+qEaeyDPtfNoZRpJbD4ZBv0Tg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/linux-riscv64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.6.tgz", + "integrity": "sha512-Y4Ri62PfavhLQhFbqucysHOmRamlTVK10zPWlqjNbj2XMea+BOs4w6ASKwQwAiqf9ZqcY9Ab7NOU4wIgpxwoSQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/linux-s390x": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.6.tgz", + "integrity": "sha512-SPUiz4fDbnNEm3JSdUW8pBJ/vkop3M1YwZAVwvdwlFLoJwKEZ9L98l3tzeyMzq27CyepDQ3Qgoba44StgbiN5Q==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/linux-x64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.6.tgz", + "integrity": "sha512-a3yHLmOodHrzuNgdpB7peFGPx1iJ2x6m+uDvhP2CKdr2CwOaqEFMeSqYAHU7hG+RjCq8r2NFujcd/YsEsFgTGw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/netbsd-x64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.6.tgz", + "integrity": "sha512-EanJqcU/4uZIBreTrnbnre2DXgXSa+Gjap7ifRfllpmyAU7YMvaXmljdArptTHmjrkkKm9BK6GH5D5Yo+p6y5A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/openbsd-x64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.6.tgz", + "integrity": "sha512-xaxeSunhQRsTNGFanoOkkLtnmMn5QbA0qBhNet/XLVsc+OVkpIWPHcr3zTW2gxVU5YOHFbIHR9ODuaUdNza2Vw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/sunos-x64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.6.tgz", + "integrity": "sha512-gnMnMPg5pfMkZvhHee21KbKdc6W3GR8/JuE0Da1kjwpK6oiFU3nqfHuVPgUX2rsOx9N2SadSQTIYV1CIjYG+xw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/win32-arm64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.6.tgz", + "integrity": "sha512-G95n7vP1UnGJPsVdKXllAJPtqjMvFYbN20e8RK8LVLhlTiSOH1sd7+Gt7rm70xiG+I5tM58nYgwWrLs6I1jHqg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/win32-ia32": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.6.tgz", + "integrity": "sha512-96yEFzLhq5bv9jJo5JhTs1gI+1cKQ83cUpyxHuGqXVwQtY5Eq54ZEsKs8veKtiKwlrNimtckHEkj4mRh4pPjsg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/@esbuild/win32-x64": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.6.tgz", + "integrity": "sha512-n6d8MOyUrNp6G4VSpRcgjs5xj4A91svJSaiwLIDWVWEsZtpN5FA9NlBbZHDmAJc2e8e6SF4tkBD3HAvPF+7igA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@remix-run/dev/node_modules/esbuild": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.6.tgz", + "integrity": "sha512-TKFRp9TxrJDdRWfSsSERKEovm6v30iHnrjlcGhLBOtReE28Yp1VSBRfO3GTaOFMoxsNerx4TjrhzSuma9ha83Q==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.6", + "@esbuild/android-arm64": "0.17.6", + "@esbuild/android-x64": "0.17.6", + "@esbuild/darwin-arm64": "0.17.6", + "@esbuild/darwin-x64": "0.17.6", + "@esbuild/freebsd-arm64": "0.17.6", + "@esbuild/freebsd-x64": "0.17.6", + "@esbuild/linux-arm": "0.17.6", + "@esbuild/linux-arm64": "0.17.6", + "@esbuild/linux-ia32": "0.17.6", + "@esbuild/linux-loong64": "0.17.6", + "@esbuild/linux-mips64el": "0.17.6", + "@esbuild/linux-ppc64": "0.17.6", + "@esbuild/linux-riscv64": "0.17.6", + "@esbuild/linux-s390x": "0.17.6", + "@esbuild/linux-x64": "0.17.6", + "@esbuild/netbsd-x64": "0.17.6", + "@esbuild/openbsd-x64": "0.17.6", + "@esbuild/sunos-x64": "0.17.6", + "@esbuild/win32-arm64": "0.17.6", + "@esbuild/win32-ia32": "0.17.6", + "@esbuild/win32-x64": "0.17.6" + } + }, "node_modules/@remix-run/dev/node_modules/prettier": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", @@ -5453,6 +5843,412 @@ "vite-node": "^1.2.0" } }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@vanilla-extract/integration/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, "node_modules/@vanilla-extract/integration/node_modules/vite-node": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz", @@ -7958,40 +8754,43 @@ } }, "node_modules/esbuild": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.6.tgz", - "integrity": "sha512-TKFRp9TxrJDdRWfSsSERKEovm6v30iHnrjlcGhLBOtReE28Yp1VSBRfO3GTaOFMoxsNerx4TjrhzSuma9ha83Q==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", "hasInstallScript": true, "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.6", - "@esbuild/android-arm64": "0.17.6", - "@esbuild/android-x64": "0.17.6", - "@esbuild/darwin-arm64": "0.17.6", - "@esbuild/darwin-x64": "0.17.6", - "@esbuild/freebsd-arm64": "0.17.6", - "@esbuild/freebsd-x64": "0.17.6", - "@esbuild/linux-arm": "0.17.6", - "@esbuild/linux-arm64": "0.17.6", - "@esbuild/linux-ia32": "0.17.6", - "@esbuild/linux-loong64": "0.17.6", - "@esbuild/linux-mips64el": "0.17.6", - "@esbuild/linux-ppc64": "0.17.6", - "@esbuild/linux-riscv64": "0.17.6", - "@esbuild/linux-s390x": "0.17.6", - "@esbuild/linux-x64": "0.17.6", - "@esbuild/netbsd-x64": "0.17.6", - "@esbuild/openbsd-x64": "0.17.6", - "@esbuild/sunos-x64": "0.17.6", - "@esbuild/win32-arm64": "0.17.6", - "@esbuild/win32-ia32": "0.17.6", - "@esbuild/win32-x64": "0.17.6" + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" } }, "node_modules/esbuild-plugins-node-modules-polyfill": { @@ -8011,6 +8810,54 @@ "esbuild": ">=0.14.0 <=0.28.x" } }, + "node_modules/esbuild/node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild/node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", diff --git a/package.json b/package.json index de7e8d4..02320ab 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "private": true, "scripts": { "build": "remix vite:build", + "predev": "npm run build:widget", "dev": "shopify app dev", + "predeploy": "npm run build:widget", "config:link": "shopify app config link", "generate": "shopify app generate", "deploy": "shopify app deploy", @@ -16,6 +18,7 @@ "typecheck": "tsc --noEmit", "test": "vitest", "test:e2e": "playwright test", + "build:widget": "esbuild extensions/datetime-widget/src/datetime-widget.ts --bundle --minify --target=es2019 --outfile=extensions/datetime-widget/assets/datetime-widget.js", "worker": "tsx jobs/worker.ts", "shopify": "shopify", "prisma": "prisma", @@ -56,6 +59,7 @@ "@types/node": "^22.2.0", "@types/react": "^18.2.31", "@types/react-dom": "^18.2.14", + "esbuild": "^0.24.2", "eslint": "^8.42.0", "eslint-config-prettier": "^10.0.1", "prettier": "^3.2.4",