@spacesync/client 0.1.7 → 0.1.10
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/analog-clock-picker.js +379 -3
- package/dist/analog-clock-picker.js.map +1 -1
- package/dist/api.d.ts +9 -1
- package/dist/api.js +84 -1
- package/dist/api.js.map +1 -1
- package/dist/booking-schedule-calendars.d.ts +33 -35
- package/dist/booking-schedule-calendars.js +716 -432
- package/dist/booking-schedule-calendars.js.map +1 -1
- package/dist/booking-schedule.d.ts +71 -0
- package/dist/booking-schedule.js +3 -0
- package/dist/booking-schedule.js.map +1 -0
- package/dist/booking-space-layout-picker.d.ts +20 -0
- package/dist/booking-space-layout-picker.js +68 -0
- package/dist/booking-space-layout-picker.js.map +1 -0
- package/dist/chat-stick-to-bottom.js +1 -1
- package/dist/chunk-CKCXQBHQ.js +764 -0
- package/dist/chunk-CKCXQBHQ.js.map +1 -0
- package/dist/{chunk-H3CNZCYU.js → chunk-F7MU5T46.js} +186 -62
- package/dist/chunk-F7MU5T46.js.map +1 -0
- package/dist/chunk-OTSA5ROL.js +209 -0
- package/dist/chunk-OTSA5ROL.js.map +1 -0
- package/dist/file-viewer-dialog.js +1 -1
- package/dist/floor-switcher.js +1 -1
- package/dist/image-picker-field.d.ts +2 -1
- package/dist/image-picker-field.js +77 -28
- package/dist/image-picker-field.js.map +1 -1
- package/dist/layout-canvas-view-DOjyUNJH.d.ts +65 -0
- package/dist/layout-canvas-view.d.ts +2 -57
- package/dist/layout-canvas-view.js +7 -741
- package/dist/layout-canvas-view.js.map +1 -1
- package/dist/platform-support-message-composer.js +1 -1
- package/dist/ui.d.ts +19 -10
- package/dist/ui.js +1 -1
- package/package.json +9 -2
- package/dist/chunk-34332W2P.js +0 -381
- package/dist/chunk-34332W2P.js.map +0 -1
- package/dist/chunk-H3CNZCYU.js.map +0 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// src/lib/booking-schedule.ts
|
|
2
|
+
function localDateYmd(d) {
|
|
3
|
+
const y = d.getFullYear();
|
|
4
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
5
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
6
|
+
return `${y}-${m}-${day}`;
|
|
7
|
+
}
|
|
8
|
+
function todayLocalYmd(now = /* @__PURE__ */ new Date()) {
|
|
9
|
+
return localDateYmd(now);
|
|
10
|
+
}
|
|
11
|
+
function pricingTodayYmd(now = /* @__PURE__ */ new Date()) {
|
|
12
|
+
return todayLocalYmd(now);
|
|
13
|
+
}
|
|
14
|
+
var PRICING_TODAY = todayLocalYmd();
|
|
15
|
+
function currentMonthYm(now = /* @__PURE__ */ new Date()) {
|
|
16
|
+
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
|
|
17
|
+
}
|
|
18
|
+
function currentWeekStart(now = /* @__PURE__ */ new Date()) {
|
|
19
|
+
const d = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
20
|
+
const day = d.getDay();
|
|
21
|
+
const offset = day === 0 ? -6 : 1 - day;
|
|
22
|
+
d.setDate(d.getDate() + offset);
|
|
23
|
+
return localDateYmd(d);
|
|
24
|
+
}
|
|
25
|
+
function computeMinMonth(now = /* @__PURE__ */ new Date()) {
|
|
26
|
+
if (now.getDate() === 1) {
|
|
27
|
+
return currentMonthYm(now);
|
|
28
|
+
}
|
|
29
|
+
const n = new Date(now.getFullYear(), now.getMonth() + 1, 1);
|
|
30
|
+
return currentMonthYm(n);
|
|
31
|
+
}
|
|
32
|
+
function computeMinWeekStart(now = /* @__PURE__ */ new Date()) {
|
|
33
|
+
const day = now.getDay();
|
|
34
|
+
if (day === 1) return todayLocalYmd(now);
|
|
35
|
+
const d = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
36
|
+
const skip = day === 0 ? 1 : 8 - day;
|
|
37
|
+
d.setDate(d.getDate() + skip);
|
|
38
|
+
return localDateYmd(d);
|
|
39
|
+
}
|
|
40
|
+
var MIN_MONTH = computeMinMonth();
|
|
41
|
+
var MIN_WEEK_START = computeMinWeekStart();
|
|
42
|
+
var IS_PARTIAL_MONTH = (/* @__PURE__ */ new Date()).getDate() !== 1;
|
|
43
|
+
function monthLabel(ym) {
|
|
44
|
+
const [y, m] = ym.split("-").map(Number);
|
|
45
|
+
return new Date(y, m - 1, 1).toLocaleDateString("en-US", { month: "long", year: "numeric" });
|
|
46
|
+
}
|
|
47
|
+
function monthCount(from, to) {
|
|
48
|
+
if (!from || !to || !from.includes("-") || !to.includes("-")) return 0;
|
|
49
|
+
const [fy, fm] = from.split("-").map(Number);
|
|
50
|
+
const [ty, tm] = to.split("-").map(Number);
|
|
51
|
+
return (ty - fy) * 12 + (tm - fm) + 1;
|
|
52
|
+
}
|
|
53
|
+
function weekRangeLabel(weekFrom, weekCount) {
|
|
54
|
+
if (!weekFrom || isNaN((/* @__PURE__ */ new Date(weekFrom + "T00:00:00")).getTime())) return "\u2014";
|
|
55
|
+
const end = parseDateOnly(weekFrom);
|
|
56
|
+
end.setDate(end.getDate() + weekCount * 7 - 1);
|
|
57
|
+
const s = parseDateOnly(weekFrom).toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
58
|
+
const e = end.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
59
|
+
return `${s} \u2013 ${e}`;
|
|
60
|
+
}
|
|
61
|
+
function weekCountBetween(weekFrom, weekToMon) {
|
|
62
|
+
if (!weekFrom || !weekToMon) return 0;
|
|
63
|
+
if (weekToMon < weekFrom) return 1;
|
|
64
|
+
return Math.floor(diffDays(weekFrom, weekToMon) / 7) + 1;
|
|
65
|
+
}
|
|
66
|
+
function addMonthsYm(ym, delta) {
|
|
67
|
+
const [y, m] = ym.split("-").map(Number);
|
|
68
|
+
const d = new Date(y, (m ?? 1) - 1 + delta, 1);
|
|
69
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
|
|
70
|
+
}
|
|
71
|
+
function parseDateOnly(date) {
|
|
72
|
+
const [y, m, d] = date.split("-").map(Number);
|
|
73
|
+
return new Date(y, m - 1, d);
|
|
74
|
+
}
|
|
75
|
+
function diffDays(a, b) {
|
|
76
|
+
const da = parseDateOnly(a);
|
|
77
|
+
const db = parseDateOnly(b);
|
|
78
|
+
return Math.max(0, Math.round((db.getTime() - da.getTime()) / 864e5));
|
|
79
|
+
}
|
|
80
|
+
function addDays(date, days) {
|
|
81
|
+
const d = parseDateOnly(date);
|
|
82
|
+
d.setDate(d.getDate() + days);
|
|
83
|
+
return localDateYmd(d);
|
|
84
|
+
}
|
|
85
|
+
function hmMinutes(hm) {
|
|
86
|
+
const [h, m] = hm.split(":").map(Number);
|
|
87
|
+
if (!Number.isFinite(h) || !Number.isFinite(m)) return null;
|
|
88
|
+
return h * 60 + m;
|
|
89
|
+
}
|
|
90
|
+
function isSlotCharge(chargeBy) {
|
|
91
|
+
return chargeBy === "hours" || chargeBy === "minutes";
|
|
92
|
+
}
|
|
93
|
+
function snapScheduleEndTime(from, end, chargeBy) {
|
|
94
|
+
const fromMin = hmMinutes(from);
|
|
95
|
+
if (fromMin == null) return end || "10:00";
|
|
96
|
+
const delta = chargeBy === "minutes" ? 1 : 60;
|
|
97
|
+
const next = fromMin + delta;
|
|
98
|
+
return `${String(Math.floor(next / 60)).padStart(2, "0")}:${String(next % 60).padStart(2, "0")}`;
|
|
99
|
+
}
|
|
100
|
+
function minNeededTimeHm(prepMinutes, now = /* @__PURE__ */ new Date()) {
|
|
101
|
+
const earliest = new Date(now.getTime() + prepMinutes * 6e4);
|
|
102
|
+
if (earliest.getSeconds() > 0 || earliest.getMilliseconds() > 0) {
|
|
103
|
+
earliest.setMinutes(earliest.getMinutes() + 1);
|
|
104
|
+
}
|
|
105
|
+
earliest.setSeconds(0, 0);
|
|
106
|
+
return `${String(earliest.getHours()).padStart(2, "0")}:${String(earliest.getMinutes()).padStart(2, "0")}`;
|
|
107
|
+
}
|
|
108
|
+
function partialElapsed(config, booking, now = /* @__PURE__ */ new Date()) {
|
|
109
|
+
const today = todayLocalYmd(now);
|
|
110
|
+
if (config.chargeBy === "months") {
|
|
111
|
+
const cur = currentMonthYm(now);
|
|
112
|
+
const min = computeMinMonth(now);
|
|
113
|
+
if (!booking.monthFrom || booking.monthFrom !== cur || booking.monthFrom >= min) return null;
|
|
114
|
+
const days = diffDays(`${booking.monthFrom}-01`, today);
|
|
115
|
+
return days > 0 ? { amount: days, unit: "days" } : null;
|
|
116
|
+
}
|
|
117
|
+
if (config.chargeBy === "weeks") {
|
|
118
|
+
const cur = currentWeekStart(now);
|
|
119
|
+
const min = computeMinWeekStart(now);
|
|
120
|
+
if (!booking.weekFrom || booking.weekFrom !== cur || booking.weekFrom >= min) return null;
|
|
121
|
+
const days = diffDays(booking.weekFrom, today);
|
|
122
|
+
return days > 0 ? { amount: days, unit: "days" } : null;
|
|
123
|
+
}
|
|
124
|
+
if (config.chargeBy === "days") {
|
|
125
|
+
if (!booking.startDate) return null;
|
|
126
|
+
if (booking.startDate < today) {
|
|
127
|
+
const days = diffDays(booking.startDate, today);
|
|
128
|
+
return days > 0 ? { amount: days, unit: "days" } : null;
|
|
129
|
+
}
|
|
130
|
+
if (booking.oneDayBooking !== false && booking.startDate === today) {
|
|
131
|
+
const hours = now.getHours() + now.getMinutes() / 60;
|
|
132
|
+
const rounded = Math.floor(hours);
|
|
133
|
+
return rounded > 0 ? { amount: rounded, unit: "hours" } : null;
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
if (isSlotCharge(config.chargeBy)) {
|
|
138
|
+
if (booking.scheduleDate !== today || !booking.scheduleTime) return null;
|
|
139
|
+
const startMin = hmMinutes(booking.scheduleTime);
|
|
140
|
+
const nowMin = now.getHours() * 60 + now.getMinutes();
|
|
141
|
+
if (startMin == null || startMin >= nowMin) return null;
|
|
142
|
+
const elapsed = nowMin - startMin;
|
|
143
|
+
if (config.chargeBy === "minutes") {
|
|
144
|
+
return elapsed > 0 ? { amount: elapsed, unit: "minutes" } : null;
|
|
145
|
+
}
|
|
146
|
+
const hours = Math.floor(elapsed / 60);
|
|
147
|
+
return hours > 0 ? { amount: hours, unit: "hours" } : null;
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
function formatPartialElapsedLabel(elapsed) {
|
|
152
|
+
const { amount, unit } = elapsed;
|
|
153
|
+
if (unit === "days") return `${amount} day${amount !== 1 ? "s" : ""}`;
|
|
154
|
+
if (unit === "hours") return `${amount} hour${amount !== 1 ? "s" : ""}`;
|
|
155
|
+
return `${amount} minute${amount !== 1 ? "s" : ""}`;
|
|
156
|
+
}
|
|
157
|
+
function applyBookingScheduleDefaults(config, booking, options) {
|
|
158
|
+
const now = options?.now ?? /* @__PURE__ */ new Date();
|
|
159
|
+
const today = todayLocalYmd(now);
|
|
160
|
+
const patch = {};
|
|
161
|
+
if (isSlotCharge(config.chargeBy)) {
|
|
162
|
+
if (!booking.scheduleDate) patch.scheduleDate = today;
|
|
163
|
+
if (!booking.scheduleTime) patch.scheduleTime = "09:00";
|
|
164
|
+
const from = patch.scheduleTime ?? booking.scheduleTime ?? "09:00";
|
|
165
|
+
if (!booking.scheduleEndTime) {
|
|
166
|
+
patch.scheduleEndTime = snapScheduleEndTime(from, "", config.chargeBy);
|
|
167
|
+
}
|
|
168
|
+
return patch;
|
|
169
|
+
}
|
|
170
|
+
if (config.chargeBy === "days") {
|
|
171
|
+
if (!booking.startDate) {
|
|
172
|
+
patch.startDate = today;
|
|
173
|
+
patch.endDate = addDays(today, 1);
|
|
174
|
+
patch.oneDayBooking = true;
|
|
175
|
+
} else if (!booking.endDate) {
|
|
176
|
+
patch.endDate = addDays(booking.startDate, 1);
|
|
177
|
+
}
|
|
178
|
+
if (booking.oneDayBooking === void 0) patch.oneDayBooking = true;
|
|
179
|
+
return patch;
|
|
180
|
+
}
|
|
181
|
+
if (config.chargeBy === "weeks") {
|
|
182
|
+
if (!booking.weekFrom) patch.weekFrom = computeMinWeekStart(now);
|
|
183
|
+
if (!booking.weekCount) patch.weekCount = 1;
|
|
184
|
+
return patch;
|
|
185
|
+
}
|
|
186
|
+
if (config.chargeBy === "months") {
|
|
187
|
+
const min = computeMinMonth(now);
|
|
188
|
+
if (!booking.monthFrom) patch.monthFrom = min;
|
|
189
|
+
if (!booking.monthTo) patch.monthTo = patch.monthFrom ?? booking.monthFrom ?? min;
|
|
190
|
+
return patch;
|
|
191
|
+
}
|
|
192
|
+
if (config.chargeBy === "quantity") {
|
|
193
|
+
if (!booking.scheduleDate) patch.scheduleDate = today;
|
|
194
|
+
let time = booking.scheduleTime || "09:00";
|
|
195
|
+
const prep = options?.preparationMinutes ?? 0;
|
|
196
|
+
if (prep > 0 && (patch.scheduleDate ?? booking.scheduleDate ?? today) === today) {
|
|
197
|
+
const floor = minNeededTimeHm(prep, now);
|
|
198
|
+
if (time < floor) time = floor;
|
|
199
|
+
}
|
|
200
|
+
if (!booking.scheduleTime) patch.scheduleTime = time;
|
|
201
|
+
if (!booking.itemQuantity) patch.itemQuantity = 1;
|
|
202
|
+
return patch;
|
|
203
|
+
}
|
|
204
|
+
return patch;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export { IS_PARTIAL_MONTH, MIN_MONTH, MIN_WEEK_START, PRICING_TODAY, addDays, addMonthsYm, applyBookingScheduleDefaults, computeMinMonth, computeMinWeekStart, currentMonthYm, currentWeekStart, diffDays, formatPartialElapsedLabel, localDateYmd, monthCount, monthLabel, partialElapsed, pricingTodayYmd, todayLocalYmd, weekCountBetween, weekRangeLabel };
|
|
208
|
+
//# sourceMappingURL=chunk-OTSA5ROL.js.map
|
|
209
|
+
//# sourceMappingURL=chunk-OTSA5ROL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/booking-schedule.ts"],"names":[],"mappings":";AA4CO,SAAS,aAAa,CAAA,EAAiB;AAC5C,EAAA,MAAM,CAAA,GAAI,EAAE,WAAA,EAAY;AACxB,EAAA,MAAM,CAAA,GAAI,OAAO,CAAA,CAAE,QAAA,KAAa,CAAC,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAA;AAClD,EAAA,MAAM,GAAA,GAAM,OAAO,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AAC/C,EAAA,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,IAAI,GAAG,CAAA,CAAA;AACzB;AAEO,SAAS,aAAA,CAAc,GAAA,mBAAY,IAAI,IAAA,EAAK,EAAW;AAC5D,EAAA,OAAO,aAAa,GAAG,CAAA;AACzB;AAGO,SAAS,eAAA,CAAgB,GAAA,mBAAY,IAAI,IAAA,EAAK,EAAW;AAC9D,EAAA,OAAO,cAAc,GAAG,CAAA;AAC1B;AAEO,IAAM,gBAAgB,aAAA;AAEtB,SAAS,cAAA,CAAe,GAAA,mBAAY,IAAI,IAAA,EAAK,EAAW;AAC7D,EAAA,OAAO,CAAA,EAAG,GAAA,CAAI,WAAA,EAAa,IAAI,MAAA,CAAO,GAAA,CAAI,QAAA,EAAS,GAAI,CAAC,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAC5E;AAGO,SAAS,gBAAA,CAAiB,GAAA,mBAAY,IAAI,IAAA,EAAK,EAAW;AAC/D,EAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,GAAA,CAAI,WAAA,EAAY,EAAG,GAAA,CAAI,QAAA,EAAS,EAAG,GAAA,CAAI,OAAA,EAAS,CAAA;AACnE,EAAA,MAAM,GAAA,GAAM,EAAE,MAAA,EAAO;AACrB,EAAA,MAAM,MAAA,GAAS,GAAA,KAAQ,CAAA,GAAI,EAAA,GAAK,CAAA,GAAI,GAAA;AACpC,EAAA,CAAA,CAAE,OAAA,CAAQ,CAAA,CAAE,OAAA,EAAQ,GAAI,MAAM,CAAA;AAC9B,EAAA,OAAO,aAAa,CAAC,CAAA;AACvB;AAGO,SAAS,eAAA,CAAgB,GAAA,mBAAY,IAAI,IAAA,EAAK,EAAW;AAC9D,EAAA,IAAI,GAAA,CAAI,OAAA,EAAQ,KAAM,CAAA,EAAG;AACvB,IAAA,OAAO,eAAe,GAAG,CAAA;AAAA,EAC3B;AACA,EAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,GAAA,CAAI,WAAA,IAAe,GAAA,CAAI,QAAA,EAAS,GAAI,CAAA,EAAG,CAAC,CAAA;AAC3D,EAAA,OAAO,eAAe,CAAC,CAAA;AACzB;AAGO,SAAS,mBAAA,CAAoB,GAAA,mBAAY,IAAI,IAAA,EAAK,EAAW;AAClE,EAAA,MAAM,GAAA,GAAM,IAAI,MAAA,EAAO;AACvB,EAAA,IAAI,GAAA,KAAQ,CAAA,EAAG,OAAO,aAAA,CAAc,GAAG,CAAA;AACvC,EAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,GAAA,CAAI,WAAA,EAAY,EAAG,GAAA,CAAI,QAAA,EAAS,EAAG,GAAA,CAAI,OAAA,EAAS,CAAA;AACnE,EAAA,MAAM,IAAA,GAAO,GAAA,KAAQ,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,GAAA;AACjC,EAAA,CAAA,CAAE,OAAA,CAAQ,CAAA,CAAE,OAAA,EAAQ,GAAI,IAAI,CAAA;AAC5B,EAAA,OAAO,aAAa,CAAC,CAAA;AACvB;AAEO,IAAM,YAAY,eAAA;AAClB,IAAM,iBAAiB,mBAAA;AAEvB,IAAM,gBAAA,GAAA,iBAAmB,IAAI,IAAA,EAAK,EAAE,SAAQ,KAAM;AAElD,SAAS,WAAW,EAAA,EAAoB;AAC7C,EAAA,MAAM,CAAC,GAAG,CAAC,CAAA,GAAI,GAAG,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AACvC,EAAA,OAAO,IAAI,IAAA,CAAK,CAAA,EAAG,CAAA,GAAI,GAAG,CAAC,CAAA,CAAE,kBAAA,CAAmB,OAAA,EAAS,EAAE,KAAA,EAAO,MAAA,EAAQ,IAAA,EAAM,WAAW,CAAA;AAC7F;AAEO,SAAS,UAAA,CAAW,MAAc,EAAA,EAAoB;AAC3D,EAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,EAAA,IAAM,CAAC,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,IAAK,CAAC,EAAA,CAAG,QAAA,CAAS,GAAG,GAAG,OAAO,CAAA;AACrE,EAAA,MAAM,CAAC,IAAI,EAAE,CAAA,GAAI,KAAK,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AAC3C,EAAA,MAAM,CAAC,IAAI,EAAE,CAAA,GAAI,GAAG,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AACzC,EAAA,OAAA,CAAQ,EAAA,GAAK,EAAA,IAAM,EAAA,IAAM,EAAA,GAAK,EAAA,CAAA,GAAM,CAAA;AACtC;AAEO,SAAS,cAAA,CAAe,UAAkB,SAAA,EAA2B;AAC1E,EAAA,IAAI,CAAC,QAAA,IAAY,KAAA,CAAA,iBAAM,IAAI,IAAA,CAAK,QAAA,GAAW,WAAW,CAAA,EAAE,OAAA,EAAS,CAAA,EAAG,OAAO,QAAA;AAC3E,EAAA,MAAM,GAAA,GAAM,cAAc,QAAQ,CAAA;AAClC,EAAA,GAAA,CAAI,QAAQ,GAAA,CAAI,OAAA,EAAQ,GAAI,SAAA,GAAY,IAAI,CAAC,CAAA;AAC7C,EAAA,MAAM,CAAA,GAAI,aAAA,CAAc,QAAQ,CAAA,CAAE,kBAAA,CAAmB,OAAA,EAAS,EAAE,KAAA,EAAO,OAAA,EAAS,GAAA,EAAK,SAAA,EAAW,CAAA;AAChG,EAAA,MAAM,CAAA,GAAI,GAAA,CAAI,kBAAA,CAAmB,OAAA,EAAS,EAAE,KAAA,EAAO,OAAA,EAAS,GAAA,EAAK,SAAA,EAAW,IAAA,EAAM,SAAA,EAAW,CAAA;AAC7F,EAAA,OAAO,CAAA,EAAG,CAAC,CAAA,QAAA,EAAM,CAAC,CAAA,CAAA;AACpB;AAGO,SAAS,gBAAA,CAAiB,UAAkB,SAAA,EAA2B;AAC5E,EAAA,IAAI,CAAC,QAAA,IAAY,CAAC,SAAA,EAAW,OAAO,CAAA;AACpC,EAAA,IAAI,SAAA,GAAY,UAAU,OAAO,CAAA;AACjC,EAAA,OAAO,KAAK,KAAA,CAAM,QAAA,CAAS,UAAU,SAAS,CAAA,GAAI,CAAC,CAAA,GAAI,CAAA;AACzD;AAEO,SAAS,WAAA,CAAY,IAAY,KAAA,EAAuB;AAC7D,EAAA,MAAM,CAAC,GAAG,CAAC,CAAA,GAAI,GAAG,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AACvC,EAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,CAAA,EAAA,CAAI,KAAK,CAAA,IAAK,CAAA,GAAI,OAAO,CAAC,CAAA;AAC7C,EAAA,OAAO,CAAA,EAAG,CAAA,CAAE,WAAA,EAAa,IAAI,MAAA,CAAO,CAAA,CAAE,QAAA,EAAS,GAAI,CAAC,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AACxE;AAEA,SAAS,cAAc,IAAA,EAAoB;AACzC,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,KAAK,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AAC5C,EAAA,OAAO,IAAI,IAAA,CAAK,CAAA,EAAG,CAAA,GAAI,GAAG,CAAC,CAAA;AAC7B;AAEO,SAAS,QAAA,CAAS,GAAW,CAAA,EAAmB;AACrD,EAAA,MAAM,EAAA,GAAK,cAAc,CAAC,CAAA;AAC1B,EAAA,MAAM,EAAA,GAAK,cAAc,CAAC,CAAA;AAC1B,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,KAAA,CAAA,CAAO,EAAA,CAAG,OAAA,EAAQ,GAAI,EAAA,CAAG,OAAA,EAAQ,IAAK,KAAU,CAAC,CAAA;AAC3E;AAEO,SAAS,OAAA,CAAQ,MAAc,IAAA,EAAsB;AAC1D,EAAA,MAAM,CAAA,GAAI,cAAc,IAAI,CAAA;AAC5B,EAAA,CAAA,CAAE,OAAA,CAAQ,CAAA,CAAE,OAAA,EAAQ,GAAI,IAAI,CAAA;AAC5B,EAAA,OAAO,aAAa,CAAC,CAAA;AACvB;AAEA,SAAS,UAAU,EAAA,EAA2B;AAC5C,EAAA,MAAM,CAAC,GAAG,CAAC,CAAA,GAAI,GAAG,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AACvC,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,EAAG,OAAO,IAAA;AACvD,EAAA,OAAO,IAAI,EAAA,GAAK,CAAA;AAClB;AAEA,SAAS,aAAa,QAAA,EAAqC;AACzD,EAAA,OAAO,QAAA,KAAa,WAAW,QAAA,KAAa,SAAA;AAC9C;AAMA,SAAS,mBAAA,CAAoB,IAAA,EAAc,GAAA,EAAa,QAAA,EAAoC;AAE1F,EAAA,MAAM,OAAA,GAAU,UAAU,IAAI,CAAA;AAC9B,EAAA,IAAI,OAAA,IAAW,IAAA,EAAM,OAAO,GAAA,IAAO,OAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,QAAA,KAAa,SAAA,GAAY,CAAA,GAAI,EAAA;AAC3C,EAAA,MAAM,OAAO,OAAA,GAAU,KAAA;AACvB,EAAA,OAAO,CAAA,EAAG,OAAO,IAAA,CAAK,KAAA,CAAM,OAAO,EAAE,CAAC,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA,EAAI,OAAO,IAAA,GAAO,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAChG;AAEA,SAAS,eAAA,CAAgB,WAAA,EAAqB,GAAA,mBAAY,IAAI,MAAK,EAAW;AAC5E,EAAA,MAAM,WAAW,IAAI,IAAA,CAAK,IAAI,OAAA,EAAQ,GAAI,cAAc,GAAM,CAAA;AAC9D,EAAA,IAAI,SAAS,UAAA,EAAW,GAAI,KAAK,QAAA,CAAS,eAAA,KAAoB,CAAA,EAAG;AAC/D,IAAA,QAAA,CAAS,UAAA,CAAW,QAAA,CAAS,UAAA,EAAW,GAAI,CAAC,CAAA;AAAA,EAC/C;AACA,EAAA,QAAA,CAAS,UAAA,CAAW,GAAG,CAAC,CAAA;AACxB,EAAA,OAAO,GAAG,MAAA,CAAO,QAAA,CAAS,UAAU,CAAA,CAAE,SAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,SAAS,UAAA,EAAY,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAC1G;AAGO,SAAS,eACd,MAAA,EACA,OAAA,EACA,GAAA,mBAAY,IAAI,MAAK,EACE;AACvB,EAAA,MAAM,KAAA,GAAQ,cAAc,GAAG,CAAA;AAE/B,EAAA,IAAI,MAAA,CAAO,aAAa,QAAA,EAAU;AAChC,IAAA,MAAM,GAAA,GAAM,eAAe,GAAG,CAAA;AAC9B,IAAA,MAAM,GAAA,GAAM,gBAAgB,GAAG,CAAA;AAC/B,IAAA,IAAI,CAAC,QAAQ,SAAA,IAAa,OAAA,CAAQ,cAAc,GAAA,IAAO,OAAA,CAAQ,SAAA,IAAa,GAAA,EAAK,OAAO,IAAA;AACxF,IAAA,MAAM,OAAO,QAAA,CAAS,CAAA,EAAG,OAAA,CAAQ,SAAS,OAAO,KAAK,CAAA;AACtD,IAAA,OAAO,OAAO,CAAA,GAAI,EAAE,QAAQ,IAAA,EAAM,IAAA,EAAM,QAAO,GAAI,IAAA;AAAA,EACrD;AAEA,EAAA,IAAI,MAAA,CAAO,aAAa,OAAA,EAAS;AAC/B,IAAA,MAAM,GAAA,GAAM,iBAAiB,GAAG,CAAA;AAChC,IAAA,MAAM,GAAA,GAAM,oBAAoB,GAAG,CAAA;AACnC,IAAA,IAAI,CAAC,QAAQ,QAAA,IAAY,OAAA,CAAQ,aAAa,GAAA,IAAO,OAAA,CAAQ,QAAA,IAAY,GAAA,EAAK,OAAO,IAAA;AACrF,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,OAAA,CAAQ,QAAA,EAAU,KAAK,CAAA;AAC7C,IAAA,OAAO,OAAO,CAAA,GAAI,EAAE,QAAQ,IAAA,EAAM,IAAA,EAAM,QAAO,GAAI,IAAA;AAAA,EACrD;AAEA,EAAA,IAAI,MAAA,CAAO,aAAa,MAAA,EAAQ;AAC9B,IAAA,IAAI,CAAC,OAAA,CAAQ,SAAA,EAAW,OAAO,IAAA;AAC/B,IAAA,IAAI,OAAA,CAAQ,YAAY,KAAA,EAAO;AAC7B,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,OAAA,CAAQ,SAAA,EAAW,KAAK,CAAA;AAC9C,MAAA,OAAO,OAAO,CAAA,GAAI,EAAE,QAAQ,IAAA,EAAM,IAAA,EAAM,QAAO,GAAI,IAAA;AAAA,IACrD;AACA,IAAA,IAAI,OAAA,CAAQ,aAAA,KAAkB,KAAA,IAAS,OAAA,CAAQ,cAAc,KAAA,EAAO;AAClE,MAAA,MAAM,QAAQ,GAAA,CAAI,QAAA,EAAS,GAAI,GAAA,CAAI,YAAW,GAAI,EAAA;AAClD,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAChC,MAAA,OAAO,UAAU,CAAA,GAAI,EAAE,QAAQ,OAAA,EAAS,IAAA,EAAM,SAAQ,GAAI,IAAA;AAAA,IAC5D;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,YAAA,CAAa,MAAA,CAAO,QAAQ,CAAA,EAAG;AACjC,IAAA,IAAI,QAAQ,YAAA,KAAiB,KAAA,IAAS,CAAC,OAAA,CAAQ,cAAc,OAAO,IAAA;AACpE,IAAA,MAAM,QAAA,GAAW,SAAA,CAAU,OAAA,CAAQ,YAAY,CAAA;AAC/C,IAAA,MAAM,SAAS,GAAA,CAAI,QAAA,EAAS,GAAI,EAAA,GAAK,IAAI,UAAA,EAAW;AACpD,IAAA,IAAI,QAAA,IAAY,IAAA,IAAQ,QAAA,IAAY,MAAA,EAAQ,OAAO,IAAA;AACnD,IAAA,MAAM,UAAU,MAAA,GAAS,QAAA;AACzB,IAAA,IAAI,MAAA,CAAO,aAAa,SAAA,EAAW;AACjC,MAAA,OAAO,UAAU,CAAA,GAAI,EAAE,QAAQ,OAAA,EAAS,IAAA,EAAM,WAAU,GAAI,IAAA;AAAA,IAC9D;AACA,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,EAAE,CAAA;AACrC,IAAA,OAAO,QAAQ,CAAA,GAAI,EAAE,QAAQ,KAAA,EAAO,IAAA,EAAM,SAAQ,GAAI,IAAA;AAAA,EACxD;AAEA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,0BAA0B,OAAA,EAAiC;AACzE,EAAA,MAAM,EAAE,MAAA,EAAQ,IAAA,EAAK,GAAI,OAAA;AACzB,EAAA,IAAI,IAAA,KAAS,QAAQ,OAAO,CAAA,EAAG,MAAM,CAAA,IAAA,EAAO,MAAA,KAAW,CAAA,GAAI,GAAA,GAAM,EAAE,CAAA,CAAA;AACnE,EAAA,IAAI,IAAA,KAAS,SAAS,OAAO,CAAA,EAAG,MAAM,CAAA,KAAA,EAAQ,MAAA,KAAW,CAAA,GAAI,GAAA,GAAM,EAAE,CAAA,CAAA;AACrE,EAAA,OAAO,GAAG,MAAM,CAAA,OAAA,EAAU,MAAA,KAAW,CAAA,GAAI,MAAM,EAAE,CAAA,CAAA;AACnD;AAGO,SAAS,4BAAA,CACd,MAAA,EACA,OAAA,EACA,OAAA,EACuB;AACvB,EAAA,MAAM,GAAA,GAAM,OAAA,EAAS,GAAA,oBAAO,IAAI,IAAA,EAAK;AACrC,EAAA,MAAM,KAAA,GAAQ,cAAc,GAAG,CAAA;AAC/B,EAAA,MAAM,QAA+B,EAAC;AAEtC,EAAA,IAAI,YAAA,CAAa,MAAA,CAAO,QAAQ,CAAA,EAAG;AACjC,IAAA,IAAI,CAAC,OAAA,CAAQ,YAAA,EAAc,KAAA,CAAM,YAAA,GAAe,KAAA;AAChD,IAAA,IAAI,CAAC,OAAA,CAAQ,YAAA,EAAc,KAAA,CAAM,YAAA,GAAe,OAAA;AAChD,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,YAAA,IAAgB,OAAA,CAAQ,YAAA,IAAgB,OAAA;AAC3D,IAAA,IAAI,CAAC,QAAQ,eAAA,EAAiB;AAC5B,MAAA,KAAA,CAAM,eAAA,GAAkB,mBAAA,CAAoB,IAAA,EAAM,EAAA,EAAI,OAAO,QAAQ,CAAA;AAAA,IACvE;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,MAAA,CAAO,aAAa,MAAA,EAAQ;AAC9B,IAAA,IAAI,CAAC,QAAQ,SAAA,EAAW;AACtB,MAAA,KAAA,CAAM,SAAA,GAAY,KAAA;AAClB,MAAA,KAAA,CAAM,OAAA,GAAU,OAAA,CAAQ,KAAA,EAAO,CAAC,CAAA;AAChC,MAAA,KAAA,CAAM,aAAA,GAAgB,IAAA;AAAA,IACxB,CAAA,MAAA,IAAW,CAAC,OAAA,CAAQ,OAAA,EAAS;AAC3B,MAAA,KAAA,CAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,CAAQ,SAAA,EAAW,CAAC,CAAA;AAAA,IAC9C;AACA,IAAA,IAAI,OAAA,CAAQ,aAAA,KAAkB,MAAA,EAAW,KAAA,CAAM,aAAA,GAAgB,IAAA;AAC/D,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,MAAA,CAAO,aAAa,OAAA,EAAS;AAC/B,IAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,EAAU,KAAA,CAAM,QAAA,GAAW,oBAAoB,GAAG,CAAA;AAC/D,IAAA,IAAI,CAAC,OAAA,CAAQ,SAAA,EAAW,KAAA,CAAM,SAAA,GAAY,CAAA;AAC1C,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,MAAA,CAAO,aAAa,QAAA,EAAU;AAChC,IAAA,MAAM,GAAA,GAAM,gBAAgB,GAAG,CAAA;AAC/B,IAAA,IAAI,CAAC,OAAA,CAAQ,SAAA,EAAW,KAAA,CAAM,SAAA,GAAY,GAAA;AAC1C,IAAA,IAAI,CAAC,QAAQ,OAAA,EAAS,KAAA,CAAM,UAAU,KAAA,CAAM,SAAA,IAAa,QAAQ,SAAA,IAAa,GAAA;AAC9E,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,MAAA,CAAO,aAAa,UAAA,EAAY;AAClC,IAAA,IAAI,CAAC,OAAA,CAAQ,YAAA,EAAc,KAAA,CAAM,YAAA,GAAe,KAAA;AAChD,IAAA,IAAI,IAAA,GAAO,QAAQ,YAAA,IAAgB,OAAA;AACnC,IAAA,MAAM,IAAA,GAAO,SAAS,kBAAA,IAAsB,CAAA;AAC5C,IAAA,IAAI,OAAO,CAAA,IAAA,CAAM,KAAA,CAAM,gBAAgB,OAAA,CAAQ,YAAA,IAAgB,WAAW,KAAA,EAAO;AAC/E,MAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,EAAM,GAAG,CAAA;AACvC,MAAA,IAAI,IAAA,GAAO,OAAO,IAAA,GAAO,KAAA;AAAA,IAC3B;AACA,IAAA,IAAI,CAAC,OAAA,CAAQ,YAAA,EAAc,KAAA,CAAM,YAAA,GAAe,IAAA;AAChD,IAAA,IAAI,CAAC,OAAA,CAAQ,YAAA,EAAc,KAAA,CAAM,YAAA,GAAe,CAAA;AAChD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,KAAA;AACT","file":"chunk-OTSA5ROL.js","sourcesContent":["/**\n * Date / schedule helpers used by booking-schedule calendars.\n */\n\nexport type RepeatType = \"none\" | \"daily\" | \"weekly\" | \"monthly\";\nexport type BookingMode = \"slots\" | \"schedule\";\nexport type ScheduleChargeBy = \"minutes\" | \"hours\" | \"days\" | \"weeks\" | \"months\" | \"quantity\";\n\nexport type PartialElapsedUnit = \"days\" | \"hours\" | \"minutes\";\n\nexport interface PartialElapsed {\n amount: number;\n unit: PartialElapsedUnit;\n}\n\n/** Editor state for slot / schedule / daily / item shaped tiers */\nexport interface BookingState {\n slotCount: number;\n bookingDate: string;\n bookingMode: BookingMode;\n scheduleDate: string;\n scheduleTime: string;\n scheduleEndTime: string;\n repeatType: RepeatType;\n repeatEveryDays: number;\n repeatEveryWeeks: number;\n repeatOnDays: string[];\n repeatEveryMonths: number;\n repeatUntilDate: string;\n startDate: string;\n endDate: string;\n monthFrom: string;\n monthTo: string;\n weekFrom: string;\n weekCount: number;\n itemQuantity: number;\n oneDayBooking?: boolean;\n}\n\nexport interface ScheduleDefaultsConfig {\n chargeBy: ScheduleChargeBy;\n}\n\n/** YYYY-MM-DD in local timezone (never UTC ISO split). */\nexport function localDateYmd(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\nexport function todayLocalYmd(now: Date = new Date()): string {\n return localDateYmd(now);\n}\n\n/** @deprecated Prefer `todayLocalYmd()` — kept for existing imports. */\nexport function pricingTodayYmd(now: Date = new Date()): string {\n return todayLocalYmd(now);\n}\n\nexport const PRICING_TODAY = todayLocalYmd();\n\nexport function currentMonthYm(now: Date = new Date()): string {\n return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}`;\n}\n\n/** Monday of the current local week (YYYY-MM-DD). */\nexport function currentWeekStart(now: Date = new Date()): string {\n const d = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const day = d.getDay();\n const offset = day === 0 ? -6 : 1 - day;\n d.setDate(d.getDate() + offset);\n return localDateYmd(d);\n}\n\n/** First full month default: next month if today is past the 1st, else current month. */\nexport function computeMinMonth(now: Date = new Date()): string {\n if (now.getDate() === 1) {\n return currentMonthYm(now);\n }\n const n = new Date(now.getFullYear(), now.getMonth() + 1, 1);\n return currentMonthYm(n);\n}\n\n/** First full week default: next Monday unless today is already Monday. */\nexport function computeMinWeekStart(now: Date = new Date()): string {\n const day = now.getDay();\n if (day === 1) return todayLocalYmd(now);\n const d = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const skip = day === 0 ? 1 : 8 - day;\n d.setDate(d.getDate() + skip);\n return localDateYmd(d);\n}\n\nexport const MIN_MONTH = computeMinMonth();\nexport const MIN_WEEK_START = computeMinWeekStart();\n\nexport const IS_PARTIAL_MONTH = new Date().getDate() !== 1;\n\nexport function monthLabel(ym: string): string {\n const [y, m] = ym.split(\"-\").map(Number);\n return new Date(y, m - 1, 1).toLocaleDateString(\"en-US\", { month: \"long\", year: \"numeric\" });\n}\n\nexport function monthCount(from: string, to: string): number {\n if (!from || !to || !from.includes(\"-\") || !to.includes(\"-\")) return 0;\n const [fy, fm] = from.split(\"-\").map(Number);\n const [ty, tm] = to.split(\"-\").map(Number);\n return (ty - fy) * 12 + (tm - fm) + 1;\n}\n\nexport function weekRangeLabel(weekFrom: string, weekCount: number): string {\n if (!weekFrom || isNaN(new Date(weekFrom + \"T00:00:00\").getTime())) return \"—\";\n const end = parseDateOnly(weekFrom);\n end.setDate(end.getDate() + weekCount * 7 - 1);\n const s = parseDateOnly(weekFrom).toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n const e = end.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\", year: \"numeric\" });\n return `${s} – ${e}`;\n}\n\n/** Inclusive number of Mon-anchored weeks from `weekFrom` through `weekToMon`. */\nexport function weekCountBetween(weekFrom: string, weekToMon: string): number {\n if (!weekFrom || !weekToMon) return 0;\n if (weekToMon < weekFrom) return 1;\n return Math.floor(diffDays(weekFrom, weekToMon) / 7) + 1;\n}\n\nexport function addMonthsYm(ym: string, delta: number): string {\n const [y, m] = ym.split(\"-\").map(Number);\n const d = new Date(y, (m ?? 1) - 1 + delta, 1);\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}`;\n}\n\nfunction parseDateOnly(date: string): Date {\n const [y, m, d] = date.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\n\nexport function diffDays(a: string, b: string): number {\n const da = parseDateOnly(a);\n const db = parseDateOnly(b);\n return Math.max(0, Math.round((db.getTime() - da.getTime()) / 86_400_000));\n}\n\nexport function addDays(date: string, days: number): string {\n const d = parseDateOnly(date);\n d.setDate(d.getDate() + days);\n return localDateYmd(d);\n}\n\nfunction hmMinutes(hm: string): number | null {\n const [h, m] = hm.split(\":\").map(Number);\n if (!Number.isFinite(h) || !Number.isFinite(m)) return null;\n return h * 60 + m;\n}\n\nfunction isSlotCharge(chargeBy: ScheduleChargeBy): boolean {\n return chargeBy === \"hours\" || chargeBy === \"minutes\";\n}\n\nfunction isPeriodCharge(chargeBy: ScheduleChargeBy): boolean {\n return chargeBy === \"days\" || chargeBy === \"weeks\" || chargeBy === \"months\";\n}\n\nfunction snapScheduleEndTime(from: string, end: string, chargeBy: ScheduleChargeBy): string {\n if (end && end > from) return end;\n const fromMin = hmMinutes(from);\n if (fromMin == null) return end || \"10:00\";\n const delta = chargeBy === \"minutes\" ? 1 : 60;\n const next = fromMin + delta;\n return `${String(Math.floor(next / 60)).padStart(2, \"0\")}:${String(next % 60).padStart(2, \"0\")}`;\n}\n\nfunction minNeededTimeHm(prepMinutes: number, now: Date = new Date()): string {\n const earliest = new Date(now.getTime() + prepMinutes * 60_000);\n if (earliest.getSeconds() > 0 || earliest.getMilliseconds() > 0) {\n earliest.setMinutes(earliest.getMinutes() + 1);\n }\n earliest.setSeconds(0, 0);\n return `${String(earliest.getHours()).padStart(2, \"0\")}:${String(earliest.getMinutes()).padStart(2, \"0\")}`;\n}\n\n/** Elapsed time in the selected in-progress booking period, if any. */\nexport function partialElapsed(\n config: ScheduleDefaultsConfig,\n booking: BookingState,\n now: Date = new Date(),\n): PartialElapsed | null {\n const today = todayLocalYmd(now);\n\n if (config.chargeBy === \"months\") {\n const cur = currentMonthYm(now);\n const min = computeMinMonth(now);\n if (!booking.monthFrom || booking.monthFrom !== cur || booking.monthFrom >= min) return null;\n const days = diffDays(`${booking.monthFrom}-01`, today);\n return days > 0 ? { amount: days, unit: \"days\" } : null;\n }\n\n if (config.chargeBy === \"weeks\") {\n const cur = currentWeekStart(now);\n const min = computeMinWeekStart(now);\n if (!booking.weekFrom || booking.weekFrom !== cur || booking.weekFrom >= min) return null;\n const days = diffDays(booking.weekFrom, today);\n return days > 0 ? { amount: days, unit: \"days\" } : null;\n }\n\n if (config.chargeBy === \"days\") {\n if (!booking.startDate) return null;\n if (booking.startDate < today) {\n const days = diffDays(booking.startDate, today);\n return days > 0 ? { amount: days, unit: \"days\" } : null;\n }\n if (booking.oneDayBooking !== false && booking.startDate === today) {\n const hours = now.getHours() + now.getMinutes() / 60;\n const rounded = Math.floor(hours);\n return rounded > 0 ? { amount: rounded, unit: \"hours\" } : null;\n }\n return null;\n }\n\n if (isSlotCharge(config.chargeBy)) {\n if (booking.scheduleDate !== today || !booking.scheduleTime) return null;\n const startMin = hmMinutes(booking.scheduleTime);\n const nowMin = now.getHours() * 60 + now.getMinutes();\n if (startMin == null || startMin >= nowMin) return null;\n const elapsed = nowMin - startMin;\n if (config.chargeBy === \"minutes\") {\n return elapsed > 0 ? { amount: elapsed, unit: \"minutes\" } : null;\n }\n const hours = Math.floor(elapsed / 60);\n return hours > 0 ? { amount: hours, unit: \"hours\" } : null;\n }\n\n return null;\n}\n\nexport function formatPartialElapsedLabel(elapsed: PartialElapsed): string {\n const { amount, unit } = elapsed;\n if (unit === \"days\") return `${amount} day${amount !== 1 ? \"s\" : \"\"}`;\n if (unit === \"hours\") return `${amount} hour${amount !== 1 ? \"s\" : \"\"}`;\n return `${amount} minute${amount !== 1 ? \"s\" : \"\"}`;\n}\n\n/** Patch empty schedule fields with tier-appropriate defaults. */\nexport function applyBookingScheduleDefaults(\n config: ScheduleDefaultsConfig,\n booking: BookingState,\n options?: { preparationMinutes?: number; now?: Date },\n): Partial<BookingState> {\n const now = options?.now ?? new Date();\n const today = todayLocalYmd(now);\n const patch: Partial<BookingState> = {};\n\n if (isSlotCharge(config.chargeBy)) {\n if (!booking.scheduleDate) patch.scheduleDate = today;\n if (!booking.scheduleTime) patch.scheduleTime = \"09:00\";\n const from = patch.scheduleTime ?? booking.scheduleTime ?? \"09:00\";\n if (!booking.scheduleEndTime) {\n patch.scheduleEndTime = snapScheduleEndTime(from, \"\", config.chargeBy);\n }\n return patch;\n }\n\n if (config.chargeBy === \"days\") {\n if (!booking.startDate) {\n patch.startDate = today;\n patch.endDate = addDays(today, 1);\n patch.oneDayBooking = true;\n } else if (!booking.endDate) {\n patch.endDate = addDays(booking.startDate, 1);\n }\n if (booking.oneDayBooking === undefined) patch.oneDayBooking = true;\n return patch;\n }\n\n if (config.chargeBy === \"weeks\") {\n if (!booking.weekFrom) patch.weekFrom = computeMinWeekStart(now);\n if (!booking.weekCount) patch.weekCount = 1;\n return patch;\n }\n\n if (config.chargeBy === \"months\") {\n const min = computeMinMonth(now);\n if (!booking.monthFrom) patch.monthFrom = min;\n if (!booking.monthTo) patch.monthTo = patch.monthFrom ?? booking.monthFrom ?? min;\n return patch;\n }\n\n if (config.chargeBy === \"quantity\") {\n if (!booking.scheduleDate) patch.scheduleDate = today;\n let time = booking.scheduleTime || \"09:00\";\n const prep = options?.preparationMinutes ?? 0;\n if (prep > 0 && (patch.scheduleDate ?? booking.scheduleDate ?? today) === today) {\n const floor = minNeededTimeHm(prep, now);\n if (time < floor) time = floor;\n }\n if (!booking.scheduleTime) patch.scheduleTime = time;\n if (!booking.itemQuantity) patch.itemQuantity = 1;\n return patch;\n }\n\n return patch;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ResponsiveDialog, ResponsiveDialogContent, ResponsiveDialogTitle } from './chunk-
|
|
1
|
+
import { ResponsiveDialog, ResponsiveDialogContent, ResponsiveDialogTitle } from './chunk-F7MU5T46.js';
|
|
2
2
|
import './chunk-RV5PMZYZ.js';
|
|
3
3
|
import './chunk-L65F4EMK.js';
|
|
4
4
|
import './chunk-PBNBLCC2.js';
|
package/dist/floor-switcher.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from './chunk-
|
|
1
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from './chunk-F7MU5T46.js';
|
|
2
2
|
import { Label } from './chunk-RV5PMZYZ.js';
|
|
3
3
|
import './chunk-L65F4EMK.js';
|
|
4
4
|
import './chunk-PBNBLCC2.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
declare function ImagePickerField({ label, value, onFileSelected, onRemove, description, previewAlt, disabled, }: {
|
|
3
|
+
declare function ImagePickerField({ label, value, onFileSelected, onRemove, description, previewAlt, disabled, busy, }: {
|
|
4
4
|
label?: string;
|
|
5
5
|
/** Preview URL supplied by the parent (`blob:`, signed HTTPS, or empty). */
|
|
6
6
|
value?: string;
|
|
@@ -9,6 +9,7 @@ declare function ImagePickerField({ label, value, onFileSelected, onRemove, desc
|
|
|
9
9
|
description?: string;
|
|
10
10
|
previewAlt?: string;
|
|
11
11
|
disabled?: boolean;
|
|
12
|
+
busy?: boolean;
|
|
12
13
|
}): React.JSX.Element;
|
|
13
14
|
|
|
14
15
|
export { ImagePickerField };
|
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
import { Button } from './chunk-VHINHHZQ.js';
|
|
2
|
-
import './chunk-DMPSQ22Q.js';
|
|
3
|
-
import { useRef } from 'react';
|
|
4
|
-
import { ImagePlus, Trash2, Upload } from 'lucide-react';
|
|
2
|
+
import { cn } from './chunk-DMPSQ22Q.js';
|
|
3
|
+
import { useRef, useState, useEffect } from 'react';
|
|
4
|
+
import { ImagePlus, Trash2, Loader2, Upload } from 'lucide-react';
|
|
5
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
|
+
function ImageBusyOverlay({ label = "Uploading\u2026" }) {
|
|
8
|
+
return /* @__PURE__ */ jsx(
|
|
9
|
+
"div",
|
|
10
|
+
{
|
|
11
|
+
className: "absolute inset-0 z-10 flex items-center justify-center rounded-[inherit] bg-background/75 backdrop-blur-[2px] animate-in fade-in duration-200",
|
|
12
|
+
role: "status",
|
|
13
|
+
"aria-live": "polite",
|
|
14
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-full border border-border bg-card px-3 py-1.5 text-sm text-foreground shadow-sm", children: [
|
|
15
|
+
/* @__PURE__ */ jsx(Loader2, { size: 14, className: "animate-spin text-blue-600" }),
|
|
16
|
+
label
|
|
17
|
+
] })
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function PreviewImage({ src, alt }) {
|
|
22
|
+
const [ready, setReady] = useState(false);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
setReady(false);
|
|
25
|
+
}, [src]);
|
|
26
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative aspect-[4/3] w-full overflow-hidden bg-muted", children: [
|
|
27
|
+
!ready ? /* @__PURE__ */ jsx(
|
|
28
|
+
"span",
|
|
29
|
+
{
|
|
30
|
+
className: "absolute inset-0 z-[1] flex items-center justify-center animate-in fade-in duration-200",
|
|
31
|
+
role: "status",
|
|
32
|
+
"aria-label": "Loading image",
|
|
33
|
+
children: /* @__PURE__ */ jsx(Loader2, { size: 18, className: "animate-spin text-muted-foreground" })
|
|
34
|
+
}
|
|
35
|
+
) : null,
|
|
36
|
+
/* @__PURE__ */ jsx(
|
|
37
|
+
"img",
|
|
38
|
+
{
|
|
39
|
+
src,
|
|
40
|
+
alt,
|
|
41
|
+
onLoad: () => setReady(true),
|
|
42
|
+
className: cn(
|
|
43
|
+
"aspect-[4/3] w-full object-cover transition-opacity duration-300 ease-out",
|
|
44
|
+
ready ? "opacity-100" : "opacity-0"
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
] });
|
|
49
|
+
}
|
|
7
50
|
function ImagePickerField({
|
|
8
51
|
label = "Image",
|
|
9
52
|
value,
|
|
@@ -11,18 +54,21 @@ function ImagePickerField({
|
|
|
11
54
|
onRemove,
|
|
12
55
|
description,
|
|
13
56
|
previewAlt = "Selected image",
|
|
14
|
-
disabled = false
|
|
57
|
+
disabled = false,
|
|
58
|
+
busy = false
|
|
15
59
|
}) {
|
|
16
60
|
const inputRef = useRef(null);
|
|
61
|
+
const locked = disabled || busy;
|
|
17
62
|
const handleFileChange = (files) => {
|
|
18
63
|
const file = files?.[0];
|
|
19
|
-
if (!file ||
|
|
64
|
+
if (!file || locked) return;
|
|
20
65
|
onFileSelected(file);
|
|
21
66
|
};
|
|
22
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
23
|
-
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: label }),
|
|
24
|
-
value ? /* @__PURE__ */ jsxs("div", { className: "max-w-sm overflow-hidden rounded-xl border border-border bg-card", children: [
|
|
25
|
-
/* @__PURE__ */ jsx(
|
|
67
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", "aria-busy": busy, children: [
|
|
68
|
+
label ? /* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: label }) : null,
|
|
69
|
+
value ? /* @__PURE__ */ jsxs("div", { className: "relative max-w-sm overflow-hidden rounded-xl border border-border bg-card", children: [
|
|
70
|
+
/* @__PURE__ */ jsx(PreviewImage, { src: value, alt: previewAlt }),
|
|
71
|
+
busy ? /* @__PURE__ */ jsx(ImageBusyOverlay, {}) : null,
|
|
26
72
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 border-t border-border px-3 py-2", children: [
|
|
27
73
|
/* @__PURE__ */ jsxs(
|
|
28
74
|
Button,
|
|
@@ -30,7 +76,7 @@ function ImagePickerField({
|
|
|
30
76
|
type: "button",
|
|
31
77
|
variant: "link",
|
|
32
78
|
size: "sm",
|
|
33
|
-
disabled,
|
|
79
|
+
disabled: locked,
|
|
34
80
|
onClick: () => inputRef.current?.click(),
|
|
35
81
|
className: "h-auto gap-1.5 p-0 text-xs font-medium text-blue-600 dark:text-blue-400",
|
|
36
82
|
children: [
|
|
@@ -45,7 +91,7 @@ function ImagePickerField({
|
|
|
45
91
|
type: "button",
|
|
46
92
|
variant: "link",
|
|
47
93
|
size: "sm",
|
|
48
|
-
disabled,
|
|
94
|
+
disabled: locked,
|
|
49
95
|
onClick: onRemove,
|
|
50
96
|
className: "h-auto gap-1.5 p-0 text-xs font-medium text-red-600",
|
|
51
97
|
children: [
|
|
@@ -55,28 +101,31 @@ function ImagePickerField({
|
|
|
55
101
|
}
|
|
56
102
|
) : null
|
|
57
103
|
] })
|
|
58
|
-
] }) : /* @__PURE__ */ jsxs(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
104
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "relative max-w-sm overflow-hidden rounded-xl", children: [
|
|
105
|
+
/* @__PURE__ */ jsxs(
|
|
106
|
+
Button,
|
|
107
|
+
{
|
|
108
|
+
type: "button",
|
|
109
|
+
variant: "outline",
|
|
110
|
+
disabled: locked,
|
|
111
|
+
onClick: () => inputRef.current?.click(),
|
|
112
|
+
className: "flex aspect-[4/3] h-auto w-full flex-col items-center justify-center gap-2 rounded-xl border-dashed bg-muted/50 px-4 py-5 text-center shadow-none hover:border-blue-300 hover:bg-blue-50/30 dark:hover:bg-blue-950/25",
|
|
113
|
+
children: [
|
|
114
|
+
/* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 items-center justify-center rounded-xl border border-border bg-card", children: busy ? /* @__PURE__ */ jsx(Loader2, { size: 15, className: "animate-spin text-blue-600" }) : /* @__PURE__ */ jsx(Upload, { size: 15, className: "text-muted-foreground" }) }),
|
|
115
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground", children: busy ? "Uploading\u2026" : "Choose image" }),
|
|
116
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-normal text-muted-foreground whitespace-normal", children: description ?? "JPG, PNG, WebP or GIF." })
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
busy ? /* @__PURE__ */ jsx(ImageBusyOverlay, {}) : null
|
|
121
|
+
] }),
|
|
73
122
|
/* @__PURE__ */ jsx(
|
|
74
123
|
"input",
|
|
75
124
|
{
|
|
76
125
|
ref: inputRef,
|
|
77
126
|
type: "file",
|
|
78
|
-
accept: "image
|
|
79
|
-
disabled,
|
|
127
|
+
accept: "image/jpeg,image/png,image/webp,image/gif,.jpg,.jpeg,.png,.webp,.gif",
|
|
128
|
+
disabled: locked,
|
|
80
129
|
className: "hidden",
|
|
81
130
|
onChange: (event) => {
|
|
82
131
|
handleFileChange(event.target.files);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/files/image-picker-field.tsx"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"sources":["../src/files/image-picker-field.tsx"],"names":[],"mappings":";;;;;;AAKA,SAAS,gBAAA,CAAiB,EAAE,KAAA,GAAQ,iBAAA,EAAa,EAAuB;AACtE,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,+IAAA;AAAA,MACV,IAAA,EAAK,QAAA;AAAA,MACL,WAAA,EAAU,QAAA;AAAA,MAEV,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iHAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,4BAAA,EAA6B,CAAA;AAAA,QACzD;AAAA,OAAA,EACH;AAAA;AAAA,GACF;AAEJ;AAEA,SAAS,YAAA,CAAa,EAAE,GAAA,EAAK,GAAA,EAAI,EAAiC;AAChE,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,KAAK,CAAA;AAExC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,QAAA,CAAS,KAAK,CAAA;AAAA,EAChB,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AAER,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uDAAA,EACZ,QAAA,EAAA;AAAA,IAAA,CAAC,KAAA,mBACA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,yFAAA;AAAA,QACV,IAAA,EAAK,QAAA;AAAA,QACL,YAAA,EAAW,eAAA;AAAA,QAEX,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,IAAA,EAAM,EAAA,EAAI,WAAU,oCAAA,EAAqC;AAAA;AAAA,KACpE,GACE,IAAA;AAAA,oBACJ,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,GAAA;AAAA,QACA,MAAA,EAAQ,MAAM,QAAA,CAAS,IAAI,CAAA;AAAA,QAC3B,SAAA,EAAW,EAAA;AAAA,UACT,2EAAA;AAAA,UACA,QAAQ,aAAA,GAAgB;AAAA;AAC1B;AAAA;AACF,GAAA,EACF,CAAA;AAEJ;AAEO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,KAAA,GAAQ,OAAA;AAAA,EACR,KAAA;AAAA,EACA,cAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA,GAAa,gBAAA;AAAA,EACb,QAAA,GAAW,KAAA;AAAA,EACX,IAAA,GAAO;AACT,CAAA,EAUG;AACD,EAAA,MAAM,QAAA,GAAW,OAAyB,IAAI,CAAA;AAC9C,EAAA,MAAM,SAAS,QAAA,IAAY,IAAA;AAE3B,EAAA,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAA2B;AACnD,IAAA,MAAM,IAAA,GAAO,QAAQ,CAAC,CAAA;AACtB,IAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACrB,IAAA,cAAA,CAAe,IAAI,CAAA;AAAA,EACrB,CAAA;AAEA,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uBAAA,EAAwB,aAAW,IAAA,EAC/C,QAAA,EAAA;AAAA,IAAA,KAAA,mBACC,GAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,2CAAA,EAA6C,iBAAM,CAAA,GAClE,IAAA;AAAA,IACH,KAAA,mBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2EAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,YAAA,EAAA,EAAa,GAAA,EAAK,KAAA,EAAO,GAAA,EAAK,UAAA,EAAY,CAAA;AAAA,MAC1C,IAAA,mBAAO,GAAA,CAAC,gBAAA,EAAA,EAAiB,CAAA,GAAK,IAAA;AAAA,sBAC/B,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0EAAA,EACb,QAAA,EAAA;AAAA,wBAAA,IAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,OAAA,EAAQ,MAAA;AAAA,YACR,IAAA,EAAK,IAAA;AAAA,YACL,QAAA,EAAU,MAAA;AAAA,YACV,OAAA,EAAS,MAAM,QAAA,CAAS,OAAA,EAAS,KAAA,EAAM;AAAA,YACvC,SAAA,EAAU,yEAAA;AAAA,YAEV,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,SAAA,EAAA,EAAU,MAAM,EAAA,EAAI,CAAA;AAAA,cAAE;AAAA;AAAA;AAAA,SAEzB;AAAA,QACC,QAAA,mBACC,IAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,OAAA,EAAQ,MAAA;AAAA,YACR,IAAA,EAAK,IAAA;AAAA,YACL,QAAA,EAAU,MAAA;AAAA,YACV,OAAA,EAAS,QAAA;AAAA,YACT,SAAA,EAAU,qDAAA;AAAA,YAEV,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,MAAM,EAAA,EAAI,CAAA;AAAA,cAAE;AAAA;AAAA;AAAA,SAEtB,GACE;AAAA,OAAA,EACN;AAAA,KAAA,EACF,CAAA,mBAEA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8CAAA,EACb,QAAA,EAAA;AAAA,sBAAA,IAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,OAAA,EAAQ,SAAA;AAAA,UACR,QAAA,EAAU,MAAA;AAAA,UACV,OAAA,EAAS,MAAM,QAAA,CAAS,OAAA,EAAS,KAAA,EAAM;AAAA,UACvC,SAAA,EAAU,uNAAA;AAAA,UAEV,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,UAAK,SAAA,EAAU,kFAAA,EACb,QAAA,EAAA,IAAA,mBACC,GAAA,CAAC,WAAQ,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,4BAAA,EAA6B,oBAE1D,GAAA,CAAC,MAAA,EAAA,EAAO,MAAM,EAAA,EAAI,SAAA,EAAU,yBAAwB,CAAA,EAExD,CAAA;AAAA,gCACC,MAAA,EAAA,EAAK,SAAA,EAAU,qCAAA,EACb,QAAA,EAAA,IAAA,GAAO,oBAAe,cAAA,EACzB,CAAA;AAAA,4BACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iEAAA,EACb,yBAAe,wBAAA,EAClB;AAAA;AAAA;AAAA,OACF;AAAA,MACC,IAAA,mBAAO,GAAA,CAAC,gBAAA,EAAA,EAAiB,CAAA,GAAK;AAAA,KAAA,EACjC,CAAA;AAAA,oBAEF,GAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAK,MAAA;AAAA,QACL,MAAA,EAAO,sEAAA;AAAA,QACP,QAAA,EAAU,MAAA;AAAA,QACV,SAAA,EAAU,QAAA;AAAA,QACV,QAAA,EAAU,CAAC,KAAA,KAAU;AACnB,UAAA,gBAAA,CAAiB,KAAA,CAAM,OAAO,KAAK,CAAA;AACnC,UAAA,KAAA,CAAM,OAAO,KAAA,GAAQ,EAAA;AAAA,QACvB;AAAA;AAAA;AACF,GAAA,EACF,CAAA;AAEJ","file":"image-picker-field.js","sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { ImagePlus, Loader2, Trash2, Upload } from \"lucide-react\";\nimport { Button } from \"../ui/button\";\nimport { cn } from \"../ui/utils\";\n\nfunction ImageBusyOverlay({ label = \"Uploading…\" }: { label?: string }) {\n return (\n <div\n className=\"absolute inset-0 z-10 flex items-center justify-center rounded-[inherit] bg-background/75 backdrop-blur-[2px] animate-in fade-in duration-200\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <div className=\"flex items-center gap-2 rounded-full border border-border bg-card px-3 py-1.5 text-sm text-foreground shadow-sm\">\n <Loader2 size={14} className=\"animate-spin text-blue-600\" />\n {label}\n </div>\n </div>\n );\n}\n\nfunction PreviewImage({ src, alt }: { src: string; alt: string }) {\n const [ready, setReady] = useState(false);\n\n useEffect(() => {\n setReady(false);\n }, [src]);\n\n return (\n <div className=\"relative aspect-[4/3] w-full overflow-hidden bg-muted\">\n {!ready ? (\n <span\n className=\"absolute inset-0 z-[1] flex items-center justify-center animate-in fade-in duration-200\"\n role=\"status\"\n aria-label=\"Loading image\"\n >\n <Loader2 size={18} className=\"animate-spin text-muted-foreground\" />\n </span>\n ) : null}\n <img\n src={src}\n alt={alt}\n onLoad={() => setReady(true)}\n className={cn(\n \"aspect-[4/3] w-full object-cover transition-opacity duration-300 ease-out\",\n ready ? \"opacity-100\" : \"opacity-0\",\n )}\n />\n </div>\n );\n}\n\nexport function ImagePickerField({\n label = \"Image\",\n value,\n onFileSelected,\n onRemove,\n description,\n previewAlt = \"Selected image\",\n disabled = false,\n busy = false,\n}: {\n label?: string;\n /** Preview URL supplied by the parent (`blob:`, signed HTTPS, or empty). */\n value?: string;\n onFileSelected: (file: File) => void;\n onRemove?: () => void;\n description?: string;\n previewAlt?: string;\n disabled?: boolean;\n busy?: boolean;\n}) {\n const inputRef = useRef<HTMLInputElement>(null);\n const locked = disabled || busy;\n\n const handleFileChange = (files: FileList | null) => {\n const file = files?.[0];\n if (!file || locked) return;\n onFileSelected(file);\n };\n\n return (\n <div className=\"flex flex-col gap-1.5\" aria-busy={busy}>\n {label ? (\n <label className=\"text-xs font-medium text-muted-foreground\">{label}</label>\n ) : null}\n {value ? (\n <div className=\"relative max-w-sm overflow-hidden rounded-xl border border-border bg-card\">\n <PreviewImage src={value} alt={previewAlt} />\n {busy ? <ImageBusyOverlay /> : null}\n <div className=\"flex items-center justify-between gap-2 border-t border-border px-3 py-2\">\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n disabled={locked}\n onClick={() => inputRef.current?.click()}\n className=\"h-auto gap-1.5 p-0 text-xs font-medium text-blue-600 dark:text-blue-400\"\n >\n <ImagePlus size={13} />\n Change image\n </Button>\n {onRemove ? (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n disabled={locked}\n onClick={onRemove}\n className=\"h-auto gap-1.5 p-0 text-xs font-medium text-red-600\"\n >\n <Trash2 size={13} />\n Remove\n </Button>\n ) : null}\n </div>\n </div>\n ) : (\n <div className=\"relative max-w-sm overflow-hidden rounded-xl\">\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={locked}\n onClick={() => inputRef.current?.click()}\n className=\"flex aspect-[4/3] h-auto w-full flex-col items-center justify-center gap-2 rounded-xl border-dashed bg-muted/50 px-4 py-5 text-center shadow-none hover:border-blue-300 hover:bg-blue-50/30 dark:hover:bg-blue-950/25\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-xl border border-border bg-card\">\n {busy ? (\n <Loader2 size={15} className=\"animate-spin text-blue-600\" />\n ) : (\n <Upload size={15} className=\"text-muted-foreground\" />\n )}\n </span>\n <span className=\"text-xs font-medium text-foreground\">\n {busy ? \"Uploading…\" : \"Choose image\"}\n </span>\n <span className=\"text-[11px] font-normal text-muted-foreground whitespace-normal\">\n {description ?? \"JPG, PNG, WebP or GIF.\"}\n </span>\n </Button>\n {busy ? <ImageBusyOverlay /> : null}\n </div>\n )}\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"image/jpeg,image/png,image/webp,image/gif,.jpg,.jpeg,.png,.webp,.gif\"\n disabled={locked}\n className=\"hidden\"\n onChange={(event) => {\n handleFileChange(event.target.files);\n event.target.value = \"\";\n }}\n />\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type LayoutCanvasResourceType = "desks" | "rooms" | "other";
|
|
5
|
+
interface LayoutCanvasRect {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
w: number;
|
|
9
|
+
h: number;
|
|
10
|
+
}
|
|
11
|
+
interface LayoutCanvasFloorLayout {
|
|
12
|
+
placedItems: Record<string, LayoutCanvasRect>;
|
|
13
|
+
bgImage: string | null;
|
|
14
|
+
canvasWidth?: number;
|
|
15
|
+
canvasHeight?: number;
|
|
16
|
+
}
|
|
17
|
+
interface LayoutCanvasPlanHint {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
color?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface LayoutCanvasViewRow {
|
|
24
|
+
resource: {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
pricingPlanId: string;
|
|
28
|
+
resourceType: LayoutCanvasResourceType;
|
|
29
|
+
totalSlots?: number;
|
|
30
|
+
};
|
|
31
|
+
merged: {
|
|
32
|
+
occupied: boolean;
|
|
33
|
+
manual?: boolean;
|
|
34
|
+
expectedFreeLabel?: string;
|
|
35
|
+
};
|
|
36
|
+
plan?: LayoutCanvasPlanHint;
|
|
37
|
+
}
|
|
38
|
+
interface LayoutCanvasResourceQuickBook {
|
|
39
|
+
/** When omitted, popover shows that booking is unavailable for this member. */
|
|
40
|
+
onBook?: (resourceId: string) => void;
|
|
41
|
+
/** Optional href for the book action (middle-click / fallback). */
|
|
42
|
+
getBookingHref?: (resourceId: string) => string;
|
|
43
|
+
}
|
|
44
|
+
interface LayoutCanvasViewProps {
|
|
45
|
+
layout: LayoutCanvasFloorLayout;
|
|
46
|
+
rows: LayoutCanvasViewRow[];
|
|
47
|
+
onResourceSelect?: (id: string) => void;
|
|
48
|
+
/** Hover/tap popover with a quick book action (member live space). */
|
|
49
|
+
resourceQuickBook?: LayoutCanvasResourceQuickBook;
|
|
50
|
+
/** When set with `onSearchQueryChange`, shows a search bar and dims non-matching resources. */
|
|
51
|
+
searchQuery?: string;
|
|
52
|
+
onSearchQueryChange?: (value: string) => void;
|
|
53
|
+
searchPlaceholder?: string;
|
|
54
|
+
/** Occupancy green/red dots. Off for booking pickers. */
|
|
55
|
+
showStatusDot?: boolean;
|
|
56
|
+
selectedIds?: string[];
|
|
57
|
+
/** Rendered on the left of the zoom toolbar (e.g. floor select). */
|
|
58
|
+
toolbarStart?: ReactNode;
|
|
59
|
+
className?: string;
|
|
60
|
+
viewportClassName?: string;
|
|
61
|
+
}
|
|
62
|
+
declare function matchesCanvasResourceSearch(resourceName: string, planName: string | undefined, query: string): boolean;
|
|
63
|
+
declare function LayoutCanvasView({ layout, rows, onResourceSelect, resourceQuickBook, searchQuery, onSearchQueryChange, searchPlaceholder, showStatusDot, selectedIds, toolbarStart, className, viewportClassName, }: LayoutCanvasViewProps): React.JSX.Element;
|
|
64
|
+
|
|
65
|
+
export { type LayoutCanvasFloorLayout as L, type LayoutCanvasViewRow as a, type LayoutCanvasResourceQuickBook as b, LayoutCanvasView as c, type LayoutCanvasViewProps as d, matchesCanvasResourceSearch as m };
|
|
@@ -1,57 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
type LayoutCanvasResourceType = "desks" | "rooms" | "other";
|
|
4
|
-
interface LayoutCanvasRect {
|
|
5
|
-
x: number;
|
|
6
|
-
y: number;
|
|
7
|
-
w: number;
|
|
8
|
-
h: number;
|
|
9
|
-
}
|
|
10
|
-
interface LayoutCanvasFloorLayout {
|
|
11
|
-
placedItems: Record<string, LayoutCanvasRect>;
|
|
12
|
-
bgImage: string | null;
|
|
13
|
-
canvasWidth?: number;
|
|
14
|
-
canvasHeight?: number;
|
|
15
|
-
}
|
|
16
|
-
interface LayoutCanvasPlanHint {
|
|
17
|
-
id: string;
|
|
18
|
-
name: string;
|
|
19
|
-
color?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface LayoutCanvasViewRow {
|
|
23
|
-
resource: {
|
|
24
|
-
id: string;
|
|
25
|
-
name: string;
|
|
26
|
-
pricingPlanId: string;
|
|
27
|
-
resourceType: LayoutCanvasResourceType;
|
|
28
|
-
totalSlots?: number;
|
|
29
|
-
};
|
|
30
|
-
merged: {
|
|
31
|
-
occupied: boolean;
|
|
32
|
-
manual?: boolean;
|
|
33
|
-
expectedFreeLabel?: string;
|
|
34
|
-
};
|
|
35
|
-
plan?: LayoutCanvasPlanHint;
|
|
36
|
-
}
|
|
37
|
-
interface LayoutCanvasResourceQuickBook {
|
|
38
|
-
/** When omitted, popover shows that booking is unavailable for this member. */
|
|
39
|
-
onBook?: (resourceId: string) => void;
|
|
40
|
-
/** Optional href for the book action (middle-click / fallback). */
|
|
41
|
-
getBookingHref?: (resourceId: string) => string;
|
|
42
|
-
}
|
|
43
|
-
interface LayoutCanvasViewProps {
|
|
44
|
-
layout: LayoutCanvasFloorLayout;
|
|
45
|
-
rows: LayoutCanvasViewRow[];
|
|
46
|
-
onResourceSelect?: (id: string) => void;
|
|
47
|
-
/** Hover/tap popover with a quick book action (member live space). */
|
|
48
|
-
resourceQuickBook?: LayoutCanvasResourceQuickBook;
|
|
49
|
-
/** When set with `onSearchQueryChange`, shows a search bar and dims non-matching resources. */
|
|
50
|
-
searchQuery?: string;
|
|
51
|
-
onSearchQueryChange?: (value: string) => void;
|
|
52
|
-
searchPlaceholder?: string;
|
|
53
|
-
}
|
|
54
|
-
declare function matchesCanvasResourceSearch(resourceName: string, planName: string | undefined, query: string): boolean;
|
|
55
|
-
declare function LayoutCanvasView({ layout, rows, onResourceSelect, resourceQuickBook, searchQuery, onSearchQueryChange, searchPlaceholder, }: LayoutCanvasViewProps): React.JSX.Element;
|
|
56
|
-
|
|
57
|
-
export { type LayoutCanvasResourceQuickBook, LayoutCanvasView, type LayoutCanvasViewProps, type LayoutCanvasViewRow, matchesCanvasResourceSearch };
|
|
1
|
+
import 'react';
|
|
2
|
+
export { b as LayoutCanvasResourceQuickBook, c as LayoutCanvasView, d as LayoutCanvasViewProps, a as LayoutCanvasViewRow, m as matchesCanvasResourceSearch } from './layout-canvas-view-DOjyUNJH.js';
|