@final-commerce/common 2.4.0-staging.1 → 2.4.0-staging.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3051,6 +3051,18 @@ var stateFor = (hasShift, offerable, free) => {
3051
3051
  }
3052
3052
  return free === 0 ? "fullyBooked" /* FULLY_BOOKED */ : "available" /* AVAILABLE */;
3053
3053
  };
3054
+ function shopDayKey(instant, timeZone) {
3055
+ const { year, month, day } = zonedParts(instant, timeZone);
3056
+ const pad = (value) => String(value).padStart(2, "0");
3057
+ return `${year}-${pad(month)}-${pad(day)}`;
3058
+ }
3059
+ function shopDayRange(fromDayKey, count, timeZone) {
3060
+ const [year, month, day] = fromDayKey.split("-").map(Number);
3061
+ return {
3062
+ from: instantFromLocal(year, month, day, 0, timeZone),
3063
+ to: instantFromLocal(year, month, day + Math.max(1, count), 0, timeZone)
3064
+ };
3065
+ }
3054
3066
  function buildAvailability({
3055
3067
  productId,
3056
3068
  bookingRulesId,
@@ -3088,20 +3100,20 @@ function buildAvailability({
3088
3100
  const grids = resources.map((resource) => {
3089
3101
  const mine = byResource.get(resource.id) ?? [];
3090
3102
  const busy = (resource.seats ?? 1) === 1 ? mine : [];
3091
- const slots = buildGrid(rule, resource.timeZone, from, to, now, busy).filter(
3103
+ const slots2 = buildGrid(rule, resource.timeZone, from, to, now, busy).filter(
3092
3104
  (slot) => withinPresence(slot, resource.timeZone, resource.presence)
3093
3105
  );
3094
- return { resource, slots };
3106
+ return { resource, slots: slots2 };
3095
3107
  });
3096
3108
  const byInstant = /* @__PURE__ */ new Map();
3097
3109
  const freeSlotsPerResource = /* @__PURE__ */ new Map();
3098
- for (const { resource, slots } of grids) {
3110
+ for (const { resource, slots: slots2 } of grids) {
3099
3111
  const capacity = resource.seats ?? 1;
3100
3112
  const mine = byResource.get(resource.id) ?? [];
3101
- for (const slot of slots) {
3113
+ for (const slot of slots2) {
3102
3114
  const { taken, foreignProductId } = occupancyIn(mine, productId, slot.startAt, slot.bufferEndAt, shared);
3103
3115
  const free = foreignProductId ? 0 : Math.max(capacity - taken, 0);
3104
- const entry = byInstant.get(+slot.startAt) ?? { ...slot, capacity: 0, booked: 0, free: 0, resources: [] };
3116
+ const entry = byInstant.get(+slot.startAt) ?? { ...slot, capacity: 0, booked: 0, free: 0, resources: [], dayKey: shopDayKey(slot.startAt, resource.timeZone) };
3105
3117
  entry.capacity += capacity;
3106
3118
  entry.booked += foreignProductId ? capacity : taken;
3107
3119
  entry.free += free;
@@ -3111,27 +3123,35 @@ function buildAvailability({
3111
3123
  byInstant.set(+slot.startAt, entry);
3112
3124
  }
3113
3125
  }
3114
- const inWindow = grids.map(({ resource, slots }) => {
3126
+ const inWindow = grids.map(({ resource, slots: slots2 }) => {
3115
3127
  const free = freeSlotsPerResource.get(resource.id) ?? 0;
3116
3128
  return {
3117
3129
  resourceId: resource.id,
3118
3130
  name: resource.name,
3119
- slots: slots.length,
3131
+ slots: slots2.length,
3120
3132
  free,
3121
3133
  // Lazily: the shift grid is a second walk, and only an empty answer needs it.
3122
3134
  state: stateFor(
3123
3135
  () => buildGrid(rule, resource.timeZone, from, to, now).filter(
3124
3136
  (slot) => withinPresence(slot, resource.timeZone, resource.presence)
3125
3137
  ).length > 0,
3126
- slots.length,
3138
+ slots2.length,
3127
3139
  free
3128
3140
  )
3129
3141
  };
3130
3142
  });
3143
+ const slots = [...byInstant.values()].sort((first, second) => +first.startAt - +second.startAt);
3131
3144
  return {
3132
3145
  ...header,
3133
3146
  resources: inWindow,
3134
- slots: [...byInstant.values()].sort((first, second) => +first.startAt - +second.startAt)
3147
+ slots,
3148
+ /**
3149
+ * The clock every instant above reads on. Returned rather than assumed: without it a caller
3150
+ * has to fetch the zone from somewhere else and hope it is the same one the grid used.
3151
+ */
3152
+ timeZone: resources[0]?.timeZone ?? null,
3153
+ /** The shop days this answer covers, in order — what a day picker lists. */
3154
+ days: [...new Set(slots.map((slot) => slot.dayKey))]
3135
3155
  };
3136
3156
  }
3137
3157
  function presentAt(resources, rows, outletId) {
@@ -3326,6 +3346,8 @@ export {
3326
3346
  roundToPrecision,
3327
3347
  sameFamily,
3328
3348
  setOrderState,
3349
+ shopDayKey,
3350
+ shopDayRange,
3329
3351
  signReportForDisplay,
3330
3352
  slotsForWindow,
3331
3353
  stringifyMinorUnits,