@aglyn/plugins-commerce 1.0.0-beta.278 → 1.0.0-beta.283
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/package.json +17 -14
- package/src/lib/components/commerce-console-page.js +33 -1
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/payments-settings-card.component.js +1 -1
- package/src/lib/components/console/payments-settings-card.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-hardware-api.d.ts +122 -0
- package/src/lib/components/console/pos/pos-hardware-api.js +90 -0
- package/src/lib/components/console/pos/pos-hardware-api.js.map +1 -0
- package/src/lib/components/console/pos/pos-reader-splash-api.d.ts +58 -0
- package/src/lib/components/console/pos/pos-reader-splash-api.js +101 -0
- package/src/lib/components/console/pos/pos-reader-splash-api.js.map +1 -0
- package/src/lib/components/console/pos-devices-card.component.js +5 -0
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-hardware-card.component.d.ts +26 -0
- package/src/lib/components/console/pos-hardware-card.component.js +456 -0
- package/src/lib/components/console/pos-hardware-card.component.js.map +1 -0
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.d.ts +14 -0
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js +519 -0
- package/src/lib/components/console/pos-hardware-orders-staff-page.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.d.ts +27 -0
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js +444 -0
- package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-check-in-zone.component.d.ts +9 -0
- package/src/lib/components/console/pos-ops/pos-check-in-zone.component.js +37 -0
- package/src/lib/components/console/pos-ops/pos-check-in-zone.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.d.ts +24 -0
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +346 -0
- package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-customer-lookup.component.d.ts +5 -1
- package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js +83 -4
- package/src/lib/components/console/pos-ops/pos-customer-lookup.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-day-totals-card.component.d.ts +35 -0
- package/src/lib/components/console/pos-ops/pos-day-totals-card.component.js +546 -0
- package/src/lib/components/console/pos-ops/pos-day-totals-card.component.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +2 -1
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +20 -1
- package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -1
- package/src/lib/components/console/pos-ops/pos-ops-api.d.ts +1 -1
- package/src/lib/components/console/pos-ops/pos-ops-api.js.map +1 -1
- package/src/lib/components/console/pos-page.component.js +6 -3
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/pos-reader-splash-setting.component.d.ts +22 -0
- package/src/lib/components/console/pos-reader-splash-setting.component.js +275 -0
- package/src/lib/components/console/pos-reader-splash-setting.component.js.map +1 -0
- package/src/lib/components/console/pos-reader-splash-staff-page.component.d.ts +14 -0
- package/src/lib/components/console/pos-reader-splash-staff-page.component.js +301 -0
- package/src/lib/components/console/pos-reader-splash-staff-page.component.js.map +1 -0
- package/src/lib/components/console/pos-zones.d.ts +37 -3
- package/src/lib/components/console/pos-zones.js +11 -1
- package/src/lib/components/console/pos-zones.js.map +1 -1
- package/src/lib/components/console/product-check-in-fields.component.d.ts +20 -0
- package/src/lib/components/console/product-check-in-fields.component.js +172 -0
- package/src/lib/components/console/product-check-in-fields.component.js.map +1 -0
- package/src/lib/components/console/product-editor-dialog.component.js +48 -9
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-register-fields.component.d.ts +12 -0
- package/src/lib/components/console/product-register-fields.component.js +39 -1
- package/src/lib/components/console/product-register-fields.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +21 -6
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/reservations-card.component.js +239 -70
- package/src/lib/components/console/reservations-card.component.js.map +1 -1
- package/src/lib/components/reservation-widget.js +16 -0
- package/src/lib/components/reservation-widget.js.map +1 -1
- package/src/lib/constants/operator-alerts.d.ts +6 -0
- package/src/lib/constants/operator-alerts.js +20 -1
- package/src/lib/constants/operator-alerts.js.map +1 -1
- package/src/lib/declarations.console-server.js +7 -0
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.d.ts +26 -0
- package/src/lib/declarations.js +34 -0
- package/src/lib/declarations.js.map +1 -0
- package/src/lib/model/commerce-check-in-product.d.ts +37 -0
- package/src/lib/model/commerce-check-in-product.js +49 -0
- package/src/lib/model/commerce-check-in-product.js.map +1 -0
- package/src/lib/model/commerce-check-in.d.ts +187 -0
- package/src/lib/model/commerce-check-in.js +468 -0
- package/src/lib/model/commerce-check-in.js.map +1 -0
- package/src/lib/model/commerce-pos-day-report.d.ts +209 -0
- package/src/lib/model/commerce-pos-day-report.js +572 -0
- package/src/lib/model/commerce-pos-day-report.js.map +1 -0
- package/src/lib/model/commerce-pos-offline.d.ts +65 -3
- package/src/lib/model/commerce-pos-offline.js +104 -7
- package/src/lib/model/commerce-pos-offline.js.map +1 -1
- package/src/lib/model/commerce-pos-ops.d.ts +3 -0
- package/src/lib/model/commerce-pos-ops.js +1 -0
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +43 -3
- package/src/lib/model/commerce-pos.js +73 -5
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-reservations.d.ts +73 -7
- package/src/lib/model/commerce-reservations.js +90 -10
- package/src/lib/model/commerce-reservations.js.map +1 -1
- package/src/lib/model/commerce.d.ts +40 -0
- package/src/lib/model/commerce.js +22 -4
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/index.d.ts +1 -0
- package/src/lib/model/index.js +1 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/plugin-permissions.d.ts +1 -1
- package/src/lib/model/plugin-permissions.js +2 -1
- package/src/lib/model/plugin-permissions.js.map +1 -1
- package/src/lib/model/pos-hardware.d.ts +288 -0
- package/src/lib/model/pos-hardware.js +499 -0
- package/src/lib/model/pos-hardware.js.map +1 -0
- package/src/lib/model/pos-offline-card-limits.d.ts +20 -0
- package/src/lib/model/pos-offline-card-limits.js +28 -0
- package/src/lib/model/pos-offline-card-limits.js.map +1 -0
- package/src/lib/model/pos-reader-splash.d.ts +114 -0
- package/src/lib/model/pos-reader-splash.js +141 -0
- package/src/lib/model/pos-reader-splash.js.map +1 -0
- package/src/lib/model/product-write.d.ts +6 -0
- package/src/lib/plugin-config.d.ts +10 -0
- package/src/lib/plugin-config.js +40 -0
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +28 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/cart-checkout.js +3 -1
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/cart.js +12 -1
- package/src/lib/server/cart.js.map +1 -1
- package/src/lib/server/catalog.js +49 -12
- package/src/lib/server/catalog.js.map +1 -1
- package/src/lib/server/checkout-extras.js +1 -1
- package/src/lib/server/checkout-extras.js.map +1 -1
- package/src/lib/server/checkout.js +7 -0
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/person-eraser.d.ts +8 -1
- package/src/lib/server/person-eraser.js +23 -1
- package/src/lib/server/person-eraser.js.map +1 -1
- package/src/lib/server/pos-check-in.d.ts +49 -0
- package/src/lib/server/pos-check-in.js +652 -0
- package/src/lib/server/pos-check-in.js.map +1 -0
- package/src/lib/server/pos-day-report.d.ts +46 -0
- package/src/lib/server/pos-day-report.js +299 -0
- package/src/lib/server/pos-day-report.js.map +1 -0
- package/src/lib/server/pos-hardware-admin.d.ts +50 -0
- package/src/lib/server/pos-hardware-admin.js +366 -0
- package/src/lib/server/pos-hardware-admin.js.map +1 -0
- package/src/lib/server/pos-hardware-notify.d.ts +27 -0
- package/src/lib/server/pos-hardware-notify.js +142 -0
- package/src/lib/server/pos-hardware-notify.js.map +1 -0
- package/src/lib/server/pos-hardware-user-eraser.d.ts +26 -0
- package/src/lib/server/pos-hardware-user-eraser.js +67 -0
- package/src/lib/server/pos-hardware-user-eraser.js.map +1 -0
- package/src/lib/server/pos-hardware-webhook.d.ts +31 -0
- package/src/lib/server/pos-hardware-webhook.js +176 -0
- package/src/lib/server/pos-hardware-webhook.js.map +1 -0
- package/src/lib/server/pos-hardware.d.ts +58 -0
- package/src/lib/server/pos-hardware.js +234 -0
- package/src/lib/server/pos-hardware.js.map +1 -0
- package/src/lib/server/pos-offline-card-reconcile.d.ts +38 -0
- package/src/lib/server/pos-offline-card-reconcile.js +58 -0
- package/src/lib/server/pos-offline-card-reconcile.js.map +1 -0
- package/src/lib/server/pos-offline-sync.d.ts +32 -0
- package/src/lib/server/pos-offline-sync.js +191 -15
- package/src/lib/server/pos-offline-sync.js.map +1 -1
- package/src/lib/server/pos-ops-routes.d.ts +4 -2
- package/src/lib/server/pos-ops-routes.js +14 -2
- package/src/lib/server/pos-ops-routes.js.map +1 -1
- package/src/lib/server/pos-order.js +39 -51
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.js +8 -4
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-reader-splash-admin.d.ts +36 -0
- package/src/lib/server/pos-reader-splash-admin.js +295 -0
- package/src/lib/server/pos-reader-splash-admin.js.map +1 -0
- package/src/lib/server/pos-reader-splash-render.d.ts +40 -0
- package/src/lib/server/pos-reader-splash-render.js +138 -0
- package/src/lib/server/pos-reader-splash-render.js.map +1 -0
- package/src/lib/server/pos-reader-splash-server.d.ts +32 -0
- package/src/lib/server/pos-reader-splash-server.js +32 -0
- package/src/lib/server/pos-reader-splash-server.js.map +1 -0
- package/src/lib/server/pos-reader-splash.d.ts +105 -0
- package/src/lib/server/pos-reader-splash.js +548 -0
- package/src/lib/server/pos-reader-splash.js.map +1 -0
- package/src/lib/server/pos-sale.d.ts +2 -1
- package/src/lib/server/pos-sale.js +3 -1
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-terminal.d.ts +67 -4
- package/src/lib/server/pos-terminal.js +239 -32
- package/src/lib/server/pos-terminal.js.map +1 -1
- package/src/lib/server/process-restock.js +4 -0
- package/src/lib/server/process-restock.js.map +1 -1
- package/src/lib/server/product-card.js +2 -2
- package/src/lib/server/product-card.js.map +1 -1
- package/src/lib/server/product-catalog.d.ts +2 -0
- package/src/lib/server/product-catalog.js +11 -4
- package/src/lib/server/product-catalog.js.map +1 -1
- package/src/lib/server/product.js +3 -1
- package/src/lib/server/product.js.map +1 -1
- package/src/lib/server/related.js +8 -1
- package/src/lib/server/related.js.map +1 -1
- package/src/lib/server/reservation-availability-query.d.ts +35 -0
- package/src/lib/server/reservation-availability-query.js +34 -0
- package/src/lib/server/reservation-availability-query.js.map +1 -0
- package/src/lib/server/reservation-availability.d.ts +21 -0
- package/src/lib/server/reservation-availability.js +64 -10
- package/src/lib/server/reservation-availability.js.map +1 -1
- package/src/lib/server/reservation-walk-in.d.ts +28 -0
- package/src/lib/server/reservation-walk-in.js +166 -0
- package/src/lib/server/reservation-walk-in.js.map +1 -0
- package/src/lib/server/reserve.js +13 -10
- package/src/lib/server/reserve.js.map +1 -1
- package/src/lib/server/reviews.js +3 -1
- package/src/lib/server/reviews.js.map +1 -1
- package/src/lib/server/site-page-resolver.js +5 -2
- package/src/lib/server/site-page-resolver.js.map +1 -1
- package/src/lib/server.js +26 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/fake-firestore.js +72 -0
- package/src/lib/testing/fake-firestore.js.map +1 -1
|
@@ -25,7 +25,8 @@ import { useSnackbar } from "@aglyn/shared-ui-snackstack";
|
|
|
25
25
|
import { Button, Chip, Dialog, DialogActions, DialogContent, DialogTitle, MenuItem, Stack, TextField, Typography } from "@mui/material";
|
|
26
26
|
import { collection, deleteDoc, doc, getDocs, limit, orderBy, query, setDoc, updateDoc, where } from "firebase/firestore";
|
|
27
27
|
import { useCallback, useMemo, useState } from "react";
|
|
28
|
-
import { useFirestore, useMerchantPayments } from "@aglyn/tenant-feature-instance";
|
|
28
|
+
import { useFirestore, useMerchantPayments, useUser } from "@aglyn/tenant-feature-instance";
|
|
29
|
+
import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
|
|
29
30
|
import { PrerequisiteNotice } from "@aglyn/shared-ui-jsx/components/prerequisite-notice.component";
|
|
30
31
|
import { useFirestoreCollection, usePagedCollection, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
|
|
31
32
|
import { pluginDocsHelp } from "@aglyn/aglyn";
|
|
@@ -39,19 +40,38 @@ const STATUS_COLOR = {
|
|
|
39
40
|
};
|
|
40
41
|
const usd = (cents)=>`$${((cents != null ? cents : 0) / 100).toFixed(2)}`;
|
|
41
42
|
const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
43
|
+
const nightLabel = (dayMs)=>new Date(dayMs).toLocaleDateString('en-US', {
|
|
44
|
+
weekday: 'short',
|
|
45
|
+
month: 'short',
|
|
46
|
+
day: 'numeric',
|
|
47
|
+
timeZone: 'UTC'
|
|
48
|
+
});
|
|
49
|
+
/** The Reservations card's look-ahead for a several-unit resource. */ const UNITS_LOOKAHEAD_NIGHTS = 14;
|
|
50
|
+
/** The desk's calendar day as the UTC-midnight `dayMs` stays are stored in. */ function localTodayDayMs() {
|
|
51
|
+
const now = new Date();
|
|
52
|
+
return Date.UTC(now.getFullYear(), now.getMonth(), now.getDate());
|
|
53
|
+
}
|
|
54
|
+
/** The units field's problem, or null when the typed value is a valid count. */ function unitsProblem(units) {
|
|
55
|
+
if (units === undefined) return null;
|
|
56
|
+
if (!Number.isInteger(units) || units < 1 || units > CommerceModel.MAX_RESOURCE_UNITS) {
|
|
57
|
+
return `A whole number from 1 to ${CommerceModel.MAX_RESOURCE_UNITS}`;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
42
61
|
/**
|
|
43
62
|
* Reservations console (AGL-311): resources CRUD (nightly pricing,
|
|
44
63
|
* seasons via multipliers, deposits) plus the reservations list with
|
|
45
64
|
* check-in/out, no-show, cancel, and walk-in creation. The storefront
|
|
46
65
|
* widget books against the same docs.
|
|
47
66
|
*/ export function ReservationsCard(props) {
|
|
48
|
-
var _payments_href, _payments_reason, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9, _ref10, _ref11;
|
|
67
|
+
var _payments_href, _payments_reason, _ref, _ref1, _ref2, _unitsProblem, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9, _ref10, _ref11, _ref12, _ref13;
|
|
49
68
|
var _resourceDraft_name;
|
|
50
69
|
const { hostId } = props;
|
|
51
70
|
// Every reservation is paid when it is booked, so a store that cannot
|
|
52
71
|
// charge turns each guest away; the card says so up front.
|
|
53
72
|
const payments = useMerchantPayments(hostId);
|
|
54
73
|
const firestore = useFirestore();
|
|
74
|
+
const { data: user } = useUser();
|
|
55
75
|
const { enqueueSnackbar } = useSnackbar();
|
|
56
76
|
const { confirm } = useConfirmationContext();
|
|
57
77
|
const { data: resourceDocs, status: resourcesStatus, /**
|
|
@@ -82,6 +102,50 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
82
102
|
], {
|
|
83
103
|
idField: '$id'
|
|
84
104
|
});
|
|
105
|
+
/*
|
|
106
|
+
* Units left on each of the next nights, for resources with several units
|
|
107
|
+
* (AGL-4044). One listen across the site's resources, on the stays that
|
|
108
|
+
* have not ended, nearest check-out first: a range and an order on the same
|
|
109
|
+
* field, which Firestore's automatic single-field index serves. Not read at
|
|
110
|
+
* all while every resource has one unit, so a cabin-only site pays nothing.
|
|
111
|
+
*
|
|
112
|
+
* The 500 cap is the booking door's: it can only leave out stays that end
|
|
113
|
+
* after 500 others that are all still running, which would be a stay far
|
|
114
|
+
* past the two weeks this draws.
|
|
115
|
+
*/ const hasSeveralUnits = (resourceDocs != null ? resourceDocs : []).some((resource)=>CommerceModel.resourceUnits(resource) > 1);
|
|
116
|
+
const todayDayMs = localTodayDayMs();
|
|
117
|
+
const { data: currentStays } = useFirestoreCollection(()=>hasSeveralUnits ? query(collection(firestore, 'hosts', hostId, 'reservations'), where('checkOutDayMs', '>', todayDayMs), orderBy('checkOutDayMs'), limit(500)) : null, [
|
|
118
|
+
firestore,
|
|
119
|
+
hostId,
|
|
120
|
+
hasSeveralUnits,
|
|
121
|
+
todayDayMs
|
|
122
|
+
], {
|
|
123
|
+
idField: '$id'
|
|
124
|
+
});
|
|
125
|
+
const unitsAhead = useMemo(()=>{
|
|
126
|
+
const byResource = {};
|
|
127
|
+
if (!hasSeveralUnits) return byResource;
|
|
128
|
+
const nowMs = Date.now();
|
|
129
|
+
for (const resource of resourceDocs != null ? resourceDocs : []){
|
|
130
|
+
if (CommerceModel.resourceUnits(resource) === 1) continue;
|
|
131
|
+
const stays = (currentStays != null ? currentStays : []).filter((stay)=>stay.resourceId === resource.$id).map((stay)=>{
|
|
132
|
+
var _stay_createdAtMs;
|
|
133
|
+
return {
|
|
134
|
+
checkInDayMs: Number(stay.checkInDayMs),
|
|
135
|
+
checkOutDayMs: Number(stay.checkOutDayMs),
|
|
136
|
+
status: stay.status,
|
|
137
|
+
createdAtMs: Number((_stay_createdAtMs = stay.createdAtMs) != null ? _stay_createdAtMs : 0)
|
|
138
|
+
};
|
|
139
|
+
});
|
|
140
|
+
byResource[resource.$id] = CommerceModel.unitsLeftByNight(resource, stays, todayDayMs, UNITS_LOOKAHEAD_NIGHTS, nowMs);
|
|
141
|
+
}
|
|
142
|
+
return byResource;
|
|
143
|
+
}, [
|
|
144
|
+
hasSeveralUnits,
|
|
145
|
+
resourceDocs,
|
|
146
|
+
currentStays,
|
|
147
|
+
todayDayMs
|
|
148
|
+
]);
|
|
85
149
|
const resourceNames = useMemo(()=>{
|
|
86
150
|
const map = {};
|
|
87
151
|
for (const resource of resourceDocs != null ? resourceDocs : []){
|
|
@@ -93,6 +157,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
93
157
|
]);
|
|
94
158
|
const [resourceDraft, setResourceDraft] = useState(null);
|
|
95
159
|
const [walkIn, setWalkIn] = useState(null);
|
|
160
|
+
const [walkInBusy, setWalkInBusy] = useState(false);
|
|
96
161
|
const handleResourceSave = useCallback(async ()=>{
|
|
97
162
|
var _resourceDraft_name;
|
|
98
163
|
if (!(resourceDraft == null ? void 0 : (_resourceDraft_name = resourceDraft.name) == null ? void 0 : _resourceDraft_name.trim()) || !(resourceDraft.nightlyRateUsd > 0)) {
|
|
@@ -108,11 +173,21 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
108
173
|
* it into the stored document as a real field. Nothing reads it; it is
|
|
109
174
|
* the listener's bookkeeping leaking into storage, and once there no
|
|
110
175
|
* reader can tell it from a field the card meant to write.
|
|
111
|
-
*/
|
|
112
|
-
const
|
|
176
|
+
*/ if (unitsProblem(resourceDraft.units)) return;
|
|
177
|
+
const seeded = resourceDraft;
|
|
178
|
+
const { id, $id: _syntheticId, units } = seeded, fields = _object_without_properties_loose(seeded, [
|
|
113
179
|
"id",
|
|
114
|
-
"$id"
|
|
180
|
+
"$id",
|
|
181
|
+
"units"
|
|
115
182
|
]);
|
|
183
|
+
// Units are written as the count the model reads (AGL-4044), and a
|
|
184
|
+
// cleared field as 1 rather than left out: `merge: true` would otherwise
|
|
185
|
+
// keep a stored 12 the merchant just removed.
|
|
186
|
+
const data = 'units' in seeded ? _extends({}, fields, {
|
|
187
|
+
units: CommerceModel.resourceUnits({
|
|
188
|
+
units
|
|
189
|
+
})
|
|
190
|
+
}) : fields;
|
|
116
191
|
/**
|
|
117
192
|
* Refuse an EDIT whose seed the server never confirmed (AGL-1358).
|
|
118
193
|
* `data` is the whole stored row spread out of the listener, so
|
|
@@ -208,25 +283,53 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
208
283
|
status: item.status,
|
|
209
284
|
createdAtMs: item.createdAtMs
|
|
210
285
|
}));
|
|
286
|
+
// Count-based for a several-unit resource (AGL-4044): the walk-in takes
|
|
287
|
+
// any unit that is free on every night, and is refused only when some
|
|
288
|
+
// night has none left.
|
|
211
289
|
if (!CommerceModel.isRangeAvailable(resource, existing, checkInDayMs, checkOutDayMs)) {
|
|
212
|
-
|
|
290
|
+
const message = CommerceModel.resourceUnits(resource) > 1 ? 'Every unit is taken on at least one of those nights' : 'Those dates are taken';
|
|
291
|
+
return void enqueueSnackbar(message, {
|
|
213
292
|
variant: 'warning',
|
|
214
293
|
persist: false
|
|
215
294
|
});
|
|
216
295
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
296
|
+
/*
|
|
297
|
+
* The check above is the instant answer; the WRITE goes through
|
|
298
|
+
* `/api/commerce/reservations/walk-in` (AGL-4046), which re-asks the same
|
|
299
|
+
* question inside the transaction that books the stay. A client
|
|
300
|
+
* read-then-write let two staff on two devices both take the last unit.
|
|
301
|
+
*/ setWalkInBusy(true);
|
|
302
|
+
try {
|
|
303
|
+
const response = await authorizedFetch(user, '/api/commerce/reservations/walk-in', {
|
|
304
|
+
method: 'POST',
|
|
305
|
+
headers: {
|
|
306
|
+
'Content-Type': 'application/json'
|
|
307
|
+
},
|
|
308
|
+
body: JSON.stringify({
|
|
309
|
+
hostId,
|
|
310
|
+
resourceId: walkIn.resourceId,
|
|
311
|
+
checkInDayMs,
|
|
312
|
+
checkOutDayMs,
|
|
313
|
+
guestName: walkIn.guestName || undefined,
|
|
314
|
+
reservationId: walkIn.attemptId
|
|
315
|
+
})
|
|
316
|
+
});
|
|
317
|
+
const answer = await response.json().catch(()=>({}));
|
|
318
|
+
if (!response.ok) {
|
|
319
|
+
var _ref;
|
|
320
|
+
return void enqueueSnackbar((_ref = answer == null ? void 0 : answer.error) != null ? _ref : 'Could not reserve the walk-in — try again', {
|
|
321
|
+
variant: response.status === 409 || response.status === 400 ? 'warning' : 'error',
|
|
322
|
+
persist: false
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
} catch (unused) {
|
|
326
|
+
return void enqueueSnackbar('Could not reserve the walk-in — try again', {
|
|
327
|
+
variant: 'error',
|
|
328
|
+
persist: false
|
|
329
|
+
});
|
|
330
|
+
} finally{
|
|
331
|
+
setWalkInBusy(false);
|
|
332
|
+
}
|
|
230
333
|
setWalkIn(null);
|
|
231
334
|
enqueueSnackbar('Walk-in reserved — collect payment at POS', {
|
|
232
335
|
variant: 'success',
|
|
@@ -237,6 +340,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
237
340
|
resourceDocs,
|
|
238
341
|
firestore,
|
|
239
342
|
hostId,
|
|
343
|
+
user,
|
|
240
344
|
enqueueSnackbar
|
|
241
345
|
]);
|
|
242
346
|
return /*#__PURE__*/ _jsxs(CardDisplay, {
|
|
@@ -261,55 +365,81 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
261
365
|
children: 'Resources'
|
|
262
366
|
}),
|
|
263
367
|
(resourceDocs != null ? resourceDocs : []).map((resource)=>/*#__PURE__*/ _jsxs(Stack, {
|
|
264
|
-
|
|
265
|
-
spacing: 1,
|
|
266
|
-
sx: {
|
|
267
|
-
alignItems: 'center'
|
|
268
|
-
},
|
|
368
|
+
spacing: 0.5,
|
|
269
369
|
children: [
|
|
270
370
|
/*#__PURE__*/ _jsxs(Stack, {
|
|
371
|
+
direction: "row",
|
|
372
|
+
spacing: 1,
|
|
271
373
|
sx: {
|
|
272
|
-
|
|
273
|
-
minWidth: 0
|
|
374
|
+
alignItems: 'center'
|
|
274
375
|
},
|
|
275
376
|
children: [
|
|
276
|
-
/*#__PURE__*/
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
377
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
378
|
+
sx: {
|
|
379
|
+
flex: 1,
|
|
380
|
+
minWidth: 0
|
|
381
|
+
},
|
|
382
|
+
children: [
|
|
383
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
384
|
+
variant: "body2",
|
|
385
|
+
noWrap: true,
|
|
386
|
+
children: [
|
|
387
|
+
resource.name,
|
|
388
|
+
`$${resource.nightlyRateUsd}/night`,
|
|
389
|
+
...CommerceModel.resourceUnits(resource) > 1 ? [
|
|
390
|
+
`${CommerceModel.resourceUnits(resource)} units`
|
|
391
|
+
] : []
|
|
392
|
+
].join(' · ')
|
|
393
|
+
}),
|
|
394
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
395
|
+
variant: "caption",
|
|
396
|
+
color: "text.secondary",
|
|
397
|
+
noWrap: true,
|
|
398
|
+
children: `id: ${resource.$id}`
|
|
399
|
+
})
|
|
400
|
+
]
|
|
280
401
|
}),
|
|
281
|
-
/*#__PURE__*/ _jsx(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
402
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
403
|
+
size: "small",
|
|
404
|
+
onClick: ()=>setResourceDraft(_extends({
|
|
405
|
+
id: resource.$id
|
|
406
|
+
}, resource)),
|
|
407
|
+
children: 'Edit'
|
|
408
|
+
}),
|
|
409
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
410
|
+
size: "small",
|
|
411
|
+
color: "error",
|
|
412
|
+
onClick: async ()=>{
|
|
413
|
+
const confirmed = await confirm({
|
|
414
|
+
title: 'Remove this resource?',
|
|
415
|
+
description: 'Existing reservations keep their records; the widget ' + 'stops accepting new stays.',
|
|
416
|
+
confirmationText: 'Remove',
|
|
417
|
+
confirmationButtonProps: {
|
|
418
|
+
color: 'error'
|
|
419
|
+
}
|
|
420
|
+
}).then(()=>true).catch(()=>false);
|
|
421
|
+
if (!confirmed) return;
|
|
422
|
+
await deleteDoc(doc(firestore, 'hosts', hostId, 'resources', resource.$id));
|
|
423
|
+
},
|
|
424
|
+
children: 'Remove'
|
|
286
425
|
})
|
|
287
426
|
]
|
|
288
427
|
}),
|
|
289
|
-
/*#__PURE__*/ _jsx(
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
297
|
-
size: "small",
|
|
298
|
-
color: "error",
|
|
299
|
-
onClick: async ()=>{
|
|
300
|
-
const confirmed = await confirm({
|
|
301
|
-
title: 'Remove this resource?',
|
|
302
|
-
description: 'Existing reservations keep their records; the widget ' + 'stops accepting new stays.',
|
|
303
|
-
confirmationText: 'Remove',
|
|
304
|
-
confirmationButtonProps: {
|
|
305
|
-
color: 'error'
|
|
306
|
-
}
|
|
307
|
-
}).then(()=>true).catch(()=>false);
|
|
308
|
-
if (!confirmed) return;
|
|
309
|
-
await deleteDoc(doc(firestore, 'hosts', hostId, 'resources', resource.$id));
|
|
428
|
+
unitsAhead[resource.$id] ? /*#__PURE__*/ _jsx(Stack, {
|
|
429
|
+
direction: "row",
|
|
430
|
+
useFlexGap: true,
|
|
431
|
+
"aria-label": `Units left on the next ${UNITS_LOOKAHEAD_NIGHTS} nights`,
|
|
432
|
+
sx: {
|
|
433
|
+
flexWrap: 'wrap',
|
|
434
|
+
gap: 0.5
|
|
310
435
|
},
|
|
311
|
-
children:
|
|
312
|
-
|
|
436
|
+
children: unitsAhead[resource.$id].map((night)=>/*#__PURE__*/ _jsx(Chip, {
|
|
437
|
+
size: "small",
|
|
438
|
+
variant: "outlined",
|
|
439
|
+
color: night.unitsLeft === 0 ? 'error' : night.unitsLeft <= CommerceModel.FEW_UNITS_LEFT ? 'warning' : 'default',
|
|
440
|
+
label: `${nightLabel(night.dayMs)} · ${night.unitsLeft} of ${night.units} left`
|
|
441
|
+
}, night.dayMs))
|
|
442
|
+
}) : null
|
|
313
443
|
]
|
|
314
444
|
}, resource.$id)),
|
|
315
445
|
/*#__PURE__*/ _jsxs(Stack, {
|
|
@@ -337,7 +467,8 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
337
467
|
resourceId: (_ref = resourceDocs == null ? void 0 : (_resourceDocs_ = resourceDocs[0]) == null ? void 0 : _resourceDocs_.$id) != null ? _ref : '',
|
|
338
468
|
checkIn: '',
|
|
339
469
|
checkOut: '',
|
|
340
|
-
guestName: ''
|
|
470
|
+
guestName: '',
|
|
471
|
+
attemptId: Aglyn.createResourceUid()
|
|
341
472
|
});
|
|
342
473
|
},
|
|
343
474
|
children: 'Walk-in'
|
|
@@ -482,13 +613,51 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
482
613
|
},
|
|
483
614
|
placeholder: "Lakeside cabin"
|
|
484
615
|
}),
|
|
616
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
617
|
+
direction: "row",
|
|
618
|
+
spacing: 1,
|
|
619
|
+
children: [
|
|
620
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
621
|
+
label: "Spots or units available",
|
|
622
|
+
placeholder: "1",
|
|
623
|
+
value: (_ref2 = resourceDraft == null ? void 0 : resourceDraft.units) != null ? _ref2 : '',
|
|
624
|
+
onChange: (event)=>setResourceDraft((prev)=>prev ? _extends({}, prev, {
|
|
625
|
+
units: event.target.value.replace(/\D/g, '') === '' ? undefined : Number(event.target.value.replace(/\D/g, ''))
|
|
626
|
+
}) : prev),
|
|
627
|
+
error: Boolean(unitsProblem(resourceDraft == null ? void 0 : resourceDraft.units)),
|
|
628
|
+
helperText: (_unitsProblem = unitsProblem(resourceDraft == null ? void 0 : resourceDraft.units)) != null ? _unitsProblem : 'How many identical ones you have, like 12 RV hookups',
|
|
629
|
+
size: "small",
|
|
630
|
+
fullWidth: true,
|
|
631
|
+
slotProps: {
|
|
632
|
+
htmlInput: {
|
|
633
|
+
inputMode: 'numeric'
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}),
|
|
637
|
+
/*#__PURE__*/ _jsx(TextField, {
|
|
638
|
+
label: "Sleeps",
|
|
639
|
+
value: (_ref3 = resourceDraft == null ? void 0 : resourceDraft.capacity) != null ? _ref3 : '',
|
|
640
|
+
onChange: (event)=>setResourceDraft((prev)=>prev ? _extends({}, prev, {
|
|
641
|
+
capacity: Math.round(Number(event.target.value)) || undefined
|
|
642
|
+
}) : prev),
|
|
643
|
+
helperText: "Guests per unit, for display",
|
|
644
|
+
size: "small",
|
|
645
|
+
fullWidth: true,
|
|
646
|
+
slotProps: {
|
|
647
|
+
htmlInput: {
|
|
648
|
+
inputMode: 'numeric'
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
})
|
|
652
|
+
]
|
|
653
|
+
}),
|
|
485
654
|
/*#__PURE__*/ _jsxs(Stack, {
|
|
486
655
|
direction: "row",
|
|
487
656
|
spacing: 1,
|
|
488
657
|
children: [
|
|
489
658
|
/*#__PURE__*/ _jsx(TextField, {
|
|
490
659
|
label: "Nightly rate ($)",
|
|
491
|
-
value: (
|
|
660
|
+
value: (_ref4 = resourceDraft == null ? void 0 : resourceDraft.nightlyRateUsd) != null ? _ref4 : '',
|
|
492
661
|
onChange: (event)=>setResourceDraft((prev)=>prev ? _extends({}, prev, {
|
|
493
662
|
nightlyRateUsd: Number(event.target.value) || 0
|
|
494
663
|
}) : prev),
|
|
@@ -502,7 +671,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
502
671
|
/*#__PURE__*/ _jsx(TextField, {
|
|
503
672
|
label: "Weekend ×",
|
|
504
673
|
placeholder: "1",
|
|
505
|
-
value: (
|
|
674
|
+
value: (_ref5 = resourceDraft == null ? void 0 : resourceDraft.weekendMultiplier) != null ? _ref5 : '',
|
|
506
675
|
onChange: (event)=>setResourceDraft((prev)=>prev ? _extends({}, prev, {
|
|
507
676
|
weekendMultiplier: Number(event.target.value) || undefined
|
|
508
677
|
}) : prev),
|
|
@@ -521,7 +690,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
521
690
|
children: [
|
|
522
691
|
/*#__PURE__*/ _jsx(TextField, {
|
|
523
692
|
label: "Min nights",
|
|
524
|
-
value: (
|
|
693
|
+
value: (_ref6 = resourceDraft == null ? void 0 : resourceDraft.minNights) != null ? _ref6 : '',
|
|
525
694
|
onChange: (event)=>setResourceDraft((prev)=>prev ? _extends({}, prev, {
|
|
526
695
|
minNights: Math.round(Number(event.target.value)) || undefined
|
|
527
696
|
}) : prev),
|
|
@@ -535,7 +704,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
535
704
|
/*#__PURE__*/ _jsx(TextField, {
|
|
536
705
|
label: "Deposit %",
|
|
537
706
|
placeholder: "100 = pay in full",
|
|
538
|
-
value: (
|
|
707
|
+
value: (_ref7 = resourceDraft == null ? void 0 : resourceDraft.depositPct) != null ? _ref7 : '',
|
|
539
708
|
onChange: (event)=>setResourceDraft((prev)=>prev ? _extends({}, prev, {
|
|
540
709
|
depositPct: Math.round(Number(event.target.value)) || undefined
|
|
541
710
|
}) : prev),
|
|
@@ -548,7 +717,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
548
717
|
}),
|
|
549
718
|
/*#__PURE__*/ _jsx(TextField, {
|
|
550
719
|
label: "Free cancel (hrs)",
|
|
551
|
-
value: (
|
|
720
|
+
value: (_ref8 = resourceDraft == null ? void 0 : resourceDraft.cancellationHours) != null ? _ref8 : '',
|
|
552
721
|
onChange: (event)=>setResourceDraft((prev)=>prev ? _extends({}, prev, {
|
|
553
722
|
cancellationHours: Math.round(Number(event.target.value)) || undefined
|
|
554
723
|
}) : prev),
|
|
@@ -572,7 +741,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
572
741
|
/*#__PURE__*/ _jsx(Button, {
|
|
573
742
|
variant: "contained",
|
|
574
743
|
color: "primary",
|
|
575
|
-
disabled: !(resourceDraft == null ? void 0 : (_resourceDraft_name = resourceDraft.name) == null ? void 0 : _resourceDraft_name.trim()) || !(((
|
|
744
|
+
disabled: !(resourceDraft == null ? void 0 : (_resourceDraft_name = resourceDraft.name) == null ? void 0 : _resourceDraft_name.trim()) || !(((_ref9 = resourceDraft == null ? void 0 : resourceDraft.nightlyRateUsd) != null ? _ref9 : 0) > 0) || Boolean(unitsProblem(resourceDraft == null ? void 0 : resourceDraft.units)),
|
|
576
745
|
onClick: handleResourceSave,
|
|
577
746
|
children: 'Save'
|
|
578
747
|
})
|
|
@@ -598,7 +767,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
598
767
|
children: [
|
|
599
768
|
/*#__PURE__*/ _jsx(TextField, {
|
|
600
769
|
label: "Resource",
|
|
601
|
-
value: (
|
|
770
|
+
value: (_ref10 = walkIn == null ? void 0 : walkIn.resourceId) != null ? _ref10 : '',
|
|
602
771
|
onChange: (event)=>setWalkIn((prev)=>prev ? _extends({}, prev, {
|
|
603
772
|
resourceId: event.target.value
|
|
604
773
|
}) : prev),
|
|
@@ -619,7 +788,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
619
788
|
/*#__PURE__*/ _jsx(TextField, {
|
|
620
789
|
label: "Check-in",
|
|
621
790
|
type: "date",
|
|
622
|
-
value: (
|
|
791
|
+
value: (_ref11 = walkIn == null ? void 0 : walkIn.checkIn) != null ? _ref11 : '',
|
|
623
792
|
onChange: (event)=>setWalkIn((prev)=>prev ? _extends({}, prev, {
|
|
624
793
|
checkIn: event.target.value
|
|
625
794
|
}) : prev),
|
|
@@ -634,7 +803,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
634
803
|
/*#__PURE__*/ _jsx(TextField, {
|
|
635
804
|
label: "Check-out",
|
|
636
805
|
type: "date",
|
|
637
|
-
value: (
|
|
806
|
+
value: (_ref12 = walkIn == null ? void 0 : walkIn.checkOut) != null ? _ref12 : '',
|
|
638
807
|
onChange: (event)=>setWalkIn((prev)=>prev ? _extends({}, prev, {
|
|
639
808
|
checkOut: event.target.value
|
|
640
809
|
}) : prev),
|
|
@@ -650,7 +819,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
650
819
|
}),
|
|
651
820
|
/*#__PURE__*/ _jsx(TextField, {
|
|
652
821
|
label: "Guest name",
|
|
653
|
-
value: (
|
|
822
|
+
value: (_ref13 = walkIn == null ? void 0 : walkIn.guestName) != null ? _ref13 : '',
|
|
654
823
|
onChange: (event)=>setWalkIn((prev)=>prev ? _extends({}, prev, {
|
|
655
824
|
guestName: event.target.value
|
|
656
825
|
}) : prev),
|
|
@@ -667,7 +836,7 @@ const day = (dayMs)=>dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—';
|
|
|
667
836
|
/*#__PURE__*/ _jsx(Button, {
|
|
668
837
|
variant: "contained",
|
|
669
838
|
color: "primary",
|
|
670
|
-
disabled: !(walkIn == null ? void 0 : walkIn.resourceId) || !(walkIn == null ? void 0 : walkIn.checkIn) || !(walkIn == null ? void 0 : walkIn.checkOut),
|
|
839
|
+
disabled: walkInBusy || !(walkIn == null ? void 0 : walkIn.resourceId) || !(walkIn == null ? void 0 : walkIn.checkIn) || !(walkIn == null ? void 0 : walkIn.checkOut),
|
|
671
840
|
onClick: handleWalkIn,
|
|
672
841
|
children: 'Reserve'
|
|
673
842
|
})
|