@aglyn/plugins-commerce 1.0.0-beta.285 → 1.0.0-beta.288

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.
Files changed (430) hide show
  1. package/README.md +1 -1
  2. package/package.json +13 -13
  3. package/src/lib/components/cart.js +25 -12
  4. package/src/lib/components/cart.js.map +1 -1
  5. package/src/lib/components/commerce-console-page.js +70 -13
  6. package/src/lib/components/commerce-console-page.js.map +1 -1
  7. package/src/lib/components/console/order-detail-dialog.component.js +2 -1
  8. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
  9. package/src/lib/components/console/order-webhooks-card.component.js +1 -1
  10. package/src/lib/components/console/order-webhooks-card.component.js.map +1 -1
  11. package/src/lib/components/console/payment-methods-card.component.js +1 -1
  12. package/src/lib/components/console/payment-methods-card.component.js.map +1 -1
  13. package/src/lib/components/console/pos/pos-cart-panel.component.d.ts +5 -0
  14. package/src/lib/components/console/pos/pos-cart-panel.component.js +18 -12
  15. package/src/lib/components/console/pos/pos-cart-panel.component.js.map +1 -1
  16. package/src/lib/components/console/pos/pos-hardware-api.d.ts +76 -5
  17. package/src/lib/components/console/pos/pos-hardware-api.js +53 -11
  18. package/src/lib/components/console/pos/pos-hardware-api.js.map +1 -1
  19. package/src/lib/components/console/pos/pos-hardware-buyer.component.d.ts +18 -0
  20. package/src/lib/components/console/pos/pos-hardware-buyer.component.js +629 -0
  21. package/src/lib/components/console/pos/pos-hardware-buyer.component.js.map +1 -0
  22. package/src/lib/components/console/pos/pos-hardware-sale-api.d.ts +162 -0
  23. package/src/lib/components/console/pos/pos-hardware-sale-api.js +122 -0
  24. package/src/lib/components/console/pos/pos-hardware-sale-api.js.map +1 -0
  25. package/src/lib/components/console/pos/pos-hardware-sale-terms.component.d.ts +39 -0
  26. package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js +251 -0
  27. package/src/lib/components/console/pos/pos-hardware-sale-terms.component.js.map +1 -0
  28. package/src/lib/components/console/pos/use-pos-display.js +50 -0
  29. package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
  30. package/src/lib/components/console/pos-cellular-control.component.d.ts +41 -0
  31. package/src/lib/components/console/pos-cellular-control.component.js +211 -0
  32. package/src/lib/components/console/pos-cellular-control.component.js.map +1 -0
  33. package/src/lib/components/console/pos-devices-card.component.d.ts +9 -1
  34. package/src/lib/components/console/pos-devices-card.component.js +47 -15
  35. package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
  36. package/src/lib/components/console/pos-display/pos-display-api.d.ts +6 -0
  37. package/src/lib/components/console/pos-display/pos-display-api.js +8 -1
  38. package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
  39. package/src/lib/components/console/pos-display-page.component.d.ts +13 -0
  40. package/src/lib/components/console/pos-display-page.component.js +44 -2
  41. package/src/lib/components/console/pos-display-page.component.js.map +1 -1
  42. package/src/lib/components/console/pos-hardware-card.component.d.ts +12 -4
  43. package/src/lib/components/console/pos-hardware-card.component.js +157 -36
  44. package/src/lib/components/console/pos-hardware-card.component.js.map +1 -1
  45. package/src/lib/components/console/pos-hardware-orders-staff-page.component.js +360 -80
  46. package/src/lib/components/console/pos-hardware-orders-staff-page.component.js.map +1 -1
  47. package/src/lib/components/console/pos-hardware-terms-page.component.d.ts +34 -0
  48. package/src/lib/components/console/pos-hardware-terms-page.component.js +257 -0
  49. package/src/lib/components/console/pos-hardware-terms-page.component.js.map +1 -0
  50. package/src/lib/components/console/pos-hardware-terms-sign-page.component.d.ts +27 -0
  51. package/src/lib/components/console/pos-hardware-terms-sign-page.component.js +104 -0
  52. package/src/lib/components/console/pos-hardware-terms-sign-page.component.js.map +1 -0
  53. package/src/lib/components/console/pos-hardware-waiting-card.component.d.ts +24 -0
  54. package/src/lib/components/console/pos-hardware-waiting-card.component.js +205 -0
  55. package/src/lib/components/console/pos-hardware-waiting-card.component.js.map +1 -0
  56. package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js +297 -201
  57. package/src/lib/components/console/pos-ops/pos-check-in-dialog.component.js.map +1 -1
  58. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.d.ts +3 -0
  59. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +260 -92
  60. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
  61. package/src/lib/components/console/pos-ops/pos-operations-bar.component.d.ts +9 -0
  62. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js +15 -6
  63. package/src/lib/components/console/pos-ops/pos-operations-bar.component.js.map +1 -1
  64. package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.d.ts +25 -0
  65. package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js +136 -0
  66. package/src/lib/components/console/pos-ops/pos-rain-check-dialog.component.js.map +1 -0
  67. package/src/lib/components/console/pos-ops/pos-shift-panel.component.d.ts +6 -0
  68. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js +48 -31
  69. package/src/lib/components/console/pos-ops/pos-shift-panel.component.js.map +1 -1
  70. package/src/lib/components/console/pos-page.component.d.ts +1 -1
  71. package/src/lib/components/console/pos-page.component.js +63 -12
  72. package/src/lib/components/console/pos-page.component.js.map +1 -1
  73. package/src/lib/components/console/pos-reader-splash-setting.component.js +1 -1
  74. package/src/lib/components/console/pos-reader-splash-setting.component.js.map +1 -1
  75. package/src/lib/components/console/product-check-in-fields.component.d.ts +4 -2
  76. package/src/lib/components/console/product-check-in-fields.component.js +60 -14
  77. package/src/lib/components/console/product-check-in-fields.component.js.map +1 -1
  78. package/src/lib/components/console/product-editor-dialog.component.js +44 -1
  79. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
  80. package/src/lib/components/console/product-hardware-sku-field.component.d.ts +19 -0
  81. package/src/lib/components/console/product-hardware-sku-field.component.js +92 -0
  82. package/src/lib/components/console/product-hardware-sku-field.component.js.map +1 -0
  83. package/src/lib/components/console/product-kiosk-offer-field.component.d.ts +22 -0
  84. package/src/lib/components/console/product-kiosk-offer-field.component.js +94 -0
  85. package/src/lib/components/console/product-kiosk-offer-field.component.js.map +1 -0
  86. package/src/lib/components/console/product-register-fields.component.d.ts +4 -0
  87. package/src/lib/components/console/product-register-fields.component.js +31 -2
  88. package/src/lib/components/console/product-register-fields.component.js.map +1 -1
  89. package/src/lib/components/console/products-hub-card.component.js +11 -2
  90. package/src/lib/components/console/products-hub-card.component.js.map +1 -1
  91. package/src/lib/components/console/register-hardware-card.component.d.ts +11 -0
  92. package/src/lib/components/console/register-hardware-card.component.js +56 -27
  93. package/src/lib/components/console/register-hardware-card.component.js.map +1 -1
  94. package/src/lib/components/console/reservation-guests-dialog.component.d.ts +28 -0
  95. package/src/lib/components/console/reservation-guests-dialog.component.js +189 -0
  96. package/src/lib/components/console/reservation-guests-dialog.component.js.map +1 -0
  97. package/src/lib/components/console/reservations-card.component.d.ts +9 -0
  98. package/src/lib/components/console/reservations-card.component.js +158 -23
  99. package/src/lib/components/console/reservations-card.component.js.map +1 -1
  100. package/src/lib/components/console/shippingeasy-card.component.js +1 -1
  101. package/src/lib/components/console/shippingeasy-card.component.js.map +1 -1
  102. package/src/lib/components/console/shipstation-card.component.d.ts +1 -1
  103. package/src/lib/components/console/shipstation-card.component.js +3 -3
  104. package/src/lib/components/console/shipstation-card.component.js.map +1 -1
  105. package/src/lib/components/product-detail.d.ts +4 -0
  106. package/src/lib/components/product-detail.js +40 -5
  107. package/src/lib/components/product-detail.js.map +1 -1
  108. package/src/lib/components/product-reviews.js +28 -11
  109. package/src/lib/components/product-reviews.js.map +1 -1
  110. package/src/lib/components/reservation-widget.js +28 -5
  111. package/src/lib/components/reservation-widget.js.map +1 -1
  112. package/src/lib/components/use-day-picker.d.ts +25 -0
  113. package/src/lib/components/use-day-picker.js +57 -0
  114. package/src/lib/components/use-day-picker.js.map +1 -0
  115. package/src/lib/constants/operator-alerts.d.ts +55 -0
  116. package/src/lib/constants/operator-alerts.js +156 -1
  117. package/src/lib/constants/operator-alerts.js.map +1 -1
  118. package/src/lib/declarations.console-server.js +54 -1
  119. package/src/lib/declarations.console-server.js.map +1 -1
  120. package/src/lib/declarations.d.ts +4 -2
  121. package/src/lib/declarations.js +15 -4
  122. package/src/lib/declarations.js.map +1 -1
  123. package/src/lib/declarations.server.js +9 -0
  124. package/src/lib/declarations.server.js.map +1 -1
  125. package/src/lib/model/commerce-cart.d.ts +9 -1
  126. package/src/lib/model/commerce-cart.js +4 -3
  127. package/src/lib/model/commerce-cart.js.map +1 -1
  128. package/src/lib/model/commerce-check-in-product.d.ts +26 -0
  129. package/src/lib/model/commerce-check-in-product.js +64 -2
  130. package/src/lib/model/commerce-check-in-product.js.map +1 -1
  131. package/src/lib/model/commerce-check-in-record.d.ts +127 -0
  132. package/src/lib/model/commerce-check-in-record.js +36 -0
  133. package/src/lib/model/commerce-check-in-record.js.map +1 -0
  134. package/src/lib/model/commerce-check-in.d.ts +91 -87
  135. package/src/lib/model/commerce-check-in.js +186 -62
  136. package/src/lib/model/commerce-check-in.js.map +1 -1
  137. package/src/lib/model/commerce-kiosk-offer.d.ts +31 -0
  138. package/src/lib/model/commerce-kiosk-offer.js +35 -0
  139. package/src/lib/model/commerce-kiosk-offer.js.map +1 -0
  140. package/src/lib/model/commerce-orders.d.ts +76 -0
  141. package/src/lib/model/commerce-orders.js +6 -0
  142. package/src/lib/model/commerce-orders.js.map +1 -1
  143. package/src/lib/model/commerce-pos-day-report.d.ts +54 -1
  144. package/src/lib/model/commerce-pos-day-report.js +39 -2
  145. package/src/lib/model/commerce-pos-day-report.js.map +1 -1
  146. package/src/lib/model/commerce-pos-offline.d.ts +1 -1
  147. package/src/lib/model/commerce-pos-offline.js +6 -1
  148. package/src/lib/model/commerce-pos-offline.js.map +1 -1
  149. package/src/lib/model/commerce-pos-ops.js +3 -2
  150. package/src/lib/model/commerce-pos-ops.js.map +1 -1
  151. package/src/lib/model/commerce-pos.d.ts +36 -3
  152. package/src/lib/model/commerce-pos.js +14 -6
  153. package/src/lib/model/commerce-pos.js.map +1 -1
  154. package/src/lib/model/commerce-receipt.js +3 -2
  155. package/src/lib/model/commerce-receipt.js.map +1 -1
  156. package/src/lib/model/commerce-reservations.d.ts +69 -4
  157. package/src/lib/model/commerce-reservations.js +57 -5
  158. package/src/lib/model/commerce-reservations.js.map +1 -1
  159. package/src/lib/model/commerce.d.ts +66 -0
  160. package/src/lib/model/commerce.js +15 -0
  161. package/src/lib/model/commerce.js.map +1 -1
  162. package/src/lib/model/order-list-fields.d.ts +11 -0
  163. package/src/lib/model/order-list-fields.js +17 -1
  164. package/src/lib/model/order-list-fields.js.map +1 -1
  165. package/src/lib/model/own-store-tax-summary.d.ts +152 -0
  166. package/src/lib/model/own-store-tax-summary.js +288 -0
  167. package/src/lib/model/own-store-tax-summary.js.map +1 -0
  168. package/src/lib/model/plugin-permissions.d.ts +74 -0
  169. package/src/lib/model/plugin-permissions.js +224 -7
  170. package/src/lib/model/plugin-permissions.js.map +1 -1
  171. package/src/lib/model/pos-cellular.d.ts +223 -0
  172. package/src/lib/model/pos-cellular.js +293 -0
  173. package/src/lib/model/pos-cellular.js.map +1 -0
  174. package/src/lib/model/pos-hardware-in-person.d.ts +98 -0
  175. package/src/lib/model/pos-hardware-in-person.js +224 -0
  176. package/src/lib/model/pos-hardware-in-person.js.map +1 -0
  177. package/src/lib/model/pos-hardware-tax-summary.d.ts +166 -0
  178. package/src/lib/model/pos-hardware-tax-summary.js +225 -0
  179. package/src/lib/model/pos-hardware-tax-summary.js.map +1 -0
  180. package/src/lib/model/pos-hardware-terms.d.ts +74 -0
  181. package/src/lib/model/pos-hardware-terms.js +115 -0
  182. package/src/lib/model/pos-hardware-terms.js.map +1 -0
  183. package/src/lib/model/pos-hardware.d.ts +349 -7
  184. package/src/lib/model/pos-hardware.js +291 -20
  185. package/src/lib/model/pos-hardware.js.map +1 -1
  186. package/src/lib/model/product-write.d.ts +10 -0
  187. package/src/lib/model/product-write.js +4 -2
  188. package/src/lib/model/product-write.js.map +1 -1
  189. package/src/lib/model/workspace-site-permissions.d.ts +26 -0
  190. package/src/lib/model/workspace-site-permissions.js +81 -0
  191. package/src/lib/model/workspace-site-permissions.js.map +1 -0
  192. package/src/lib/plugin.js +16 -0
  193. package/src/lib/plugin.js.map +1 -1
  194. package/src/lib/server/billing-webhook.js +25 -1
  195. package/src/lib/server/billing-webhook.js.map +1 -1
  196. package/src/lib/server/cancel-order.js +7 -5
  197. package/src/lib/server/cancel-order.js.map +1 -1
  198. package/src/lib/server/cart-checkout.js +20 -8
  199. package/src/lib/server/cart-checkout.js.map +1 -1
  200. package/src/lib/server/cart.js +29 -0
  201. package/src/lib/server/cart.js.map +1 -1
  202. package/src/lib/server/checkout.js +42 -13
  203. package/src/lib/server/checkout.js.map +1 -1
  204. package/src/lib/server/collection-membership.d.ts +4 -0
  205. package/src/lib/server/collection-membership.js +5 -10
  206. package/src/lib/server/collection-membership.js.map +1 -1
  207. package/src/lib/server/commerce-site-keys.d.ts +48 -0
  208. package/src/lib/server/commerce-site-keys.js +61 -0
  209. package/src/lib/server/commerce-site-keys.js.map +1 -0
  210. package/src/lib/server/draft-order.js +8 -5
  211. package/src/lib/server/draft-order.js.map +1 -1
  212. package/src/lib/server/fulfill-order.js +7 -5
  213. package/src/lib/server/fulfill-order.js.map +1 -1
  214. package/src/lib/server/gift-cards.js +8 -5
  215. package/src/lib/server/gift-cards.js.map +1 -1
  216. package/src/lib/server/local-fulfillment-status.js +9 -6
  217. package/src/lib/server/local-fulfillment-status.js.map +1 -1
  218. package/src/lib/server/member-post.js +6 -5
  219. package/src/lib/server/member-post.js.map +1 -1
  220. package/src/lib/server/membership-admin-password.d.ts +4 -2
  221. package/src/lib/server/membership-admin-password.js +10 -8
  222. package/src/lib/server/membership-admin-password.js.map +1 -1
  223. package/src/lib/server/membership-admin-remove.d.ts +7 -5
  224. package/src/lib/server/membership-admin-remove.js +9 -9
  225. package/src/lib/server/membership-admin-remove.js.map +1 -1
  226. package/src/lib/server/order-notifications.js +5 -2
  227. package/src/lib/server/order-notifications.js.map +1 -1
  228. package/src/lib/server/order-print.js +7 -5
  229. package/src/lib/server/order-print.js.map +1 -1
  230. package/src/lib/server/order-receipt-send.js +8 -5
  231. package/src/lib/server/order-receipt-send.js.map +1 -1
  232. package/src/lib/server/order-webhooks.js +8 -8
  233. package/src/lib/server/order-webhooks.js.map +1 -1
  234. package/src/lib/server/orders-shipping-prepare.js +9 -6
  235. package/src/lib/server/orders-shipping-prepare.js.map +1 -1
  236. package/src/lib/server/own-store-tax-return-source.d.ts +47 -0
  237. package/src/lib/server/own-store-tax-return-source.js +312 -0
  238. package/src/lib/server/own-store-tax-return-source.js.map +1 -0
  239. package/src/lib/server/payment-methods.js +13 -9
  240. package/src/lib/server/payment-methods.js.map +1 -1
  241. package/src/lib/server/pos-auth.d.ts +37 -6
  242. package/src/lib/server/pos-auth.js +40 -15
  243. package/src/lib/server/pos-auth.js.map +1 -1
  244. package/src/lib/server/pos-cellular-billing.d.ts +81 -0
  245. package/src/lib/server/pos-cellular-billing.js +711 -0
  246. package/src/lib/server/pos-cellular-billing.js.map +1 -0
  247. package/src/lib/server/pos-cellular-notify.d.ts +47 -0
  248. package/src/lib/server/pos-cellular-notify.js +150 -0
  249. package/src/lib/server/pos-cellular-notify.js.map +1 -0
  250. package/src/lib/server/pos-cellular.d.ts +88 -0
  251. package/src/lib/server/pos-cellular.js +339 -0
  252. package/src/lib/server/pos-cellular.js.map +1 -0
  253. package/src/lib/server/pos-check-in.d.ts +5 -1
  254. package/src/lib/server/pos-check-in.js +296 -28
  255. package/src/lib/server/pos-check-in.js.map +1 -1
  256. package/src/lib/server/pos-day-report.js +29 -3
  257. package/src/lib/server/pos-day-report.js.map +1 -1
  258. package/src/lib/server/pos-display.d.ts +16 -0
  259. package/src/lib/server/pos-display.js +129 -2
  260. package/src/lib/server/pos-display.js.map +1 -1
  261. package/src/lib/server/pos-hardware-admin.d.ts +10 -1
  262. package/src/lib/server/pos-hardware-admin.js +250 -84
  263. package/src/lib/server/pos-hardware-admin.js.map +1 -1
  264. package/src/lib/server/pos-hardware-attach.d.ts +105 -0
  265. package/src/lib/server/pos-hardware-attach.js +443 -0
  266. package/src/lib/server/pos-hardware-attach.js.map +1 -0
  267. package/src/lib/server/pos-hardware-buyer-lookup.d.ts +58 -0
  268. package/src/lib/server/pos-hardware-buyer-lookup.js +180 -0
  269. package/src/lib/server/pos-hardware-buyer-lookup.js.map +1 -0
  270. package/src/lib/server/pos-hardware-buyer-record.d.ts +29 -0
  271. package/src/lib/server/pos-hardware-buyer-record.js +86 -0
  272. package/src/lib/server/pos-hardware-buyer-record.js.map +1 -0
  273. package/src/lib/server/pos-hardware-cancel.d.ts +58 -0
  274. package/src/lib/server/pos-hardware-cancel.js +147 -0
  275. package/src/lib/server/pos-hardware-cancel.js.map +1 -0
  276. package/src/lib/server/pos-hardware-closure-notices.d.ts +27 -0
  277. package/src/lib/server/pos-hardware-closure-notices.js +85 -0
  278. package/src/lib/server/pos-hardware-closure-notices.js.map +1 -0
  279. package/src/lib/server/pos-hardware-closure.d.ts +60 -0
  280. package/src/lib/server/pos-hardware-closure.js +153 -0
  281. package/src/lib/server/pos-hardware-closure.js.map +1 -0
  282. package/src/lib/server/pos-hardware-in-person.d.ts +61 -0
  283. package/src/lib/server/pos-hardware-in-person.js +236 -0
  284. package/src/lib/server/pos-hardware-in-person.js.map +1 -0
  285. package/src/lib/server/pos-hardware-notify.d.ts +40 -2
  286. package/src/lib/server/pos-hardware-notify.js +195 -14
  287. package/src/lib/server/pos-hardware-notify.js.map +1 -1
  288. package/src/lib/server/pos-hardware-readers.d.ts +115 -0
  289. package/src/lib/server/pos-hardware-readers.js +430 -0
  290. package/src/lib/server/pos-hardware-readers.js.map +1 -0
  291. package/src/lib/server/pos-hardware-returns.d.ts +116 -0
  292. package/src/lib/server/pos-hardware-returns.js +502 -0
  293. package/src/lib/server/pos-hardware-returns.js.map +1 -0
  294. package/src/lib/server/pos-hardware-sale-fields.d.ts +28 -0
  295. package/src/lib/server/pos-hardware-sale-fields.js +44 -0
  296. package/src/lib/server/pos-hardware-sale-fields.js.map +1 -0
  297. package/src/lib/server/pos-hardware-sale.d.ts +54 -0
  298. package/src/lib/server/pos-hardware-sale.js +369 -0
  299. package/src/lib/server/pos-hardware-sale.js.map +1 -0
  300. package/src/lib/server/pos-hardware-tax-return-source.d.ts +99 -0
  301. package/src/lib/server/pos-hardware-tax-return-source.js +462 -0
  302. package/src/lib/server/pos-hardware-tax-return-source.js.map +1 -0
  303. package/src/lib/server/pos-hardware-terms.d.ts +64 -0
  304. package/src/lib/server/pos-hardware-terms.js +154 -0
  305. package/src/lib/server/pos-hardware-terms.js.map +1 -0
  306. package/src/lib/server/pos-hardware-user-eraser.d.ts +3 -0
  307. package/src/lib/server/pos-hardware-user-eraser.js +31 -7
  308. package/src/lib/server/pos-hardware-user-eraser.js.map +1 -1
  309. package/src/lib/server/pos-hardware-webhook.d.ts +5 -0
  310. package/src/lib/server/pos-hardware-webhook.js +51 -6
  311. package/src/lib/server/pos-hardware-webhook.js.map +1 -1
  312. package/src/lib/server/pos-hardware.d.ts +74 -1
  313. package/src/lib/server/pos-hardware.js +175 -10
  314. package/src/lib/server/pos-hardware.js.map +1 -1
  315. package/src/lib/server/pos-kiosk.d.ts +2 -0
  316. package/src/lib/server/pos-kiosk.js +17 -12
  317. package/src/lib/server/pos-kiosk.js.map +1 -1
  318. package/src/lib/server/pos-offline-card-order.d.ts +64 -0
  319. package/src/lib/server/pos-offline-card-order.js +102 -0
  320. package/src/lib/server/pos-offline-card-order.js.map +1 -0
  321. package/src/lib/server/pos-offline-card-reconcile.d.ts +67 -1
  322. package/src/lib/server/pos-offline-card-reconcile.js +215 -18
  323. package/src/lib/server/pos-offline-card-reconcile.js.map +1 -1
  324. package/src/lib/server/pos-offline-sync.d.ts +39 -0
  325. package/src/lib/server/pos-offline-sync.js +190 -55
  326. package/src/lib/server/pos-offline-sync.js.map +1 -1
  327. package/src/lib/server/pos-ops-gate.d.ts +28 -9
  328. package/src/lib/server/pos-ops-gate.js +50 -19
  329. package/src/lib/server/pos-ops-gate.js.map +1 -1
  330. package/src/lib/server/pos-ops-routes.js +24 -0
  331. package/src/lib/server/pos-ops-routes.js.map +1 -1
  332. package/src/lib/server/pos-order-refund-ids.d.ts +28 -0
  333. package/src/lib/server/pos-order-refund-ids.js +31 -0
  334. package/src/lib/server/pos-order-refund-ids.js.map +1 -0
  335. package/src/lib/server/pos-order.js +52 -49
  336. package/src/lib/server/pos-order.js.map +1 -1
  337. package/src/lib/server/pos-payment.js +1 -1
  338. package/src/lib/server/pos-payment.js.map +1 -1
  339. package/src/lib/server/pos-reader-splash-admin.js +30 -32
  340. package/src/lib/server/pos-reader-splash-admin.js.map +1 -1
  341. package/src/lib/server/pos-reader-splash-images-route.d.ts +17 -0
  342. package/src/lib/server/pos-reader-splash-images-route.js +113 -0
  343. package/src/lib/server/pos-reader-splash-images-route.js.map +1 -0
  344. package/src/lib/server/pos-reader-splash-images.d.ts +51 -0
  345. package/src/lib/server/pos-reader-splash-images.js +123 -0
  346. package/src/lib/server/pos-reader-splash-images.js.map +1 -0
  347. package/src/lib/server/pos-reader-splash.d.ts +68 -1
  348. package/src/lib/server/pos-reader-splash.js +182 -11
  349. package/src/lib/server/pos-reader-splash.js.map +1 -1
  350. package/src/lib/server/pos-readers.d.ts +29 -0
  351. package/src/lib/server/pos-readers.js +134 -35
  352. package/src/lib/server/pos-readers.js.map +1 -1
  353. package/src/lib/server/pos-refund-authority.d.ts +3 -1
  354. package/src/lib/server/pos-refund-authority.js +3 -2
  355. package/src/lib/server/pos-refund-authority.js.map +1 -1
  356. package/src/lib/server/pos-return.d.ts +10 -0
  357. package/src/lib/server/pos-return.js +29 -7
  358. package/src/lib/server/pos-return.js.map +1 -1
  359. package/src/lib/server/pos-sale.js +6 -1
  360. package/src/lib/server/pos-sale.js.map +1 -1
  361. package/src/lib/server/pos-shift.js +11 -0
  362. package/src/lib/server/pos-shift.js.map +1 -1
  363. package/src/lib/server/pos-staff-pin.js +29 -24
  364. package/src/lib/server/pos-staff-pin.js.map +1 -1
  365. package/src/lib/server/pos-terminal.d.ts +14 -4
  366. package/src/lib/server/pos-terminal.js +34 -38
  367. package/src/lib/server/pos-terminal.js.map +1 -1
  368. package/src/lib/server/printers.d.ts +7 -3
  369. package/src/lib/server/printers.js +18 -12
  370. package/src/lib/server/printers.js.map +1 -1
  371. package/src/lib/server/product-drafts.d.ts +11 -1
  372. package/src/lib/server/product-drafts.js +12 -8
  373. package/src/lib/server/product-drafts.js.map +1 -1
  374. package/src/lib/server/product.d.ts +15 -1
  375. package/src/lib/server/product.js +16 -3
  376. package/src/lib/server/product.js.map +1 -1
  377. package/src/lib/server/products-write.d.ts +26 -2
  378. package/src/lib/server/products-write.js +19 -7
  379. package/src/lib/server/products-write.js.map +1 -1
  380. package/src/lib/server/refund.js +55 -42
  381. package/src/lib/server/refund.js.map +1 -1
  382. package/src/lib/server/reservation-availability-query.d.ts +8 -0
  383. package/src/lib/server/reservation-availability-query.js +11 -1
  384. package/src/lib/server/reservation-availability-query.js.map +1 -1
  385. package/src/lib/server/reservation-availability.d.ts +1 -1
  386. package/src/lib/server/reservation-availability.js +7 -2
  387. package/src/lib/server/reservation-availability.js.map +1 -1
  388. package/src/lib/server/reservation-guests.d.ts +32 -0
  389. package/src/lib/server/reservation-guests.js +285 -0
  390. package/src/lib/server/reservation-guests.js.map +1 -0
  391. package/src/lib/server/reservation-walk-in.d.ts +11 -1
  392. package/src/lib/server/reservation-walk-in.js +56 -12
  393. package/src/lib/server/reservation-walk-in.js.map +1 -1
  394. package/src/lib/server/reserve.js +18 -5
  395. package/src/lib/server/reserve.js.map +1 -1
  396. package/src/lib/server/returns.js +9 -6
  397. package/src/lib/server/returns.js.map +1 -1
  398. package/src/lib/server/reviews.d.ts +22 -2
  399. package/src/lib/server/reviews.js +88 -20
  400. package/src/lib/server/reviews.js.map +1 -1
  401. package/src/lib/server/shipping-connectors.js +10 -11
  402. package/src/lib/server/shipping-connectors.js.map +1 -1
  403. package/src/lib/server/site-page-resolver.js +20 -3
  404. package/src/lib/server/site-page-resolver.js.map +1 -1
  405. package/src/lib/server/store-day.d.ts +33 -0
  406. package/src/lib/server/store-day.js +46 -0
  407. package/src/lib/server/store-day.js.map +1 -0
  408. package/src/lib/server/store-setup-ai-writer.d.ts +2 -1
  409. package/src/lib/server/store-setup-ai-writer.js +5 -6
  410. package/src/lib/server/store-setup-ai-writer.js.map +1 -1
  411. package/src/lib/server/storefront-tax.d.ts +13 -0
  412. package/src/lib/server/storefront-tax.js +8 -1
  413. package/src/lib/server/storefront-tax.js.map +1 -1
  414. package/src/lib/server/tax-return-source.d.ts +32 -3
  415. package/src/lib/server/tax-return-source.js +99 -20
  416. package/src/lib/server/tax-return-source.js.map +1 -1
  417. package/src/lib/server.js +100 -2
  418. package/src/lib/server.js.map +1 -1
  419. package/src/lib/testing/fake-firestore.js +58 -16
  420. package/src/lib/testing/fake-firestore.js.map +1 -1
  421. package/src/lib/testing/pos-ops-memory-firestore.js +18 -4
  422. package/src/lib/testing/pos-ops-memory-firestore.js.map +1 -1
  423. package/src/lib/testing/site-register-permissions.d.ts +29 -0
  424. package/src/lib/testing/site-register-permissions.js +38 -0
  425. package/src/lib/testing/site-register-permissions.js.map +1 -0
  426. package/src/lib/transfer/tracking.server.js +8 -5
  427. package/src/lib/transfer/tracking.server.js.map +1 -1
  428. package/src/lib/utils/add-to-cart.d.ts +2 -0
  429. package/src/lib/utils/add-to-cart.js +6 -3
  430. package/src/lib/utils/add-to-cart.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/reservations-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport * as CommerceModel from '../../model'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n deleteDoc,\n doc,\n getDocs,\n limit,\n orderBy,\n query,\n setDoc,\n updateDoc,\n where,\n} from 'firebase/firestore'\nimport { useCallback, useMemo, useState } from 'react'\nimport { useFirestore, useMerchantPayments, useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { PrerequisiteNotice } from '@aglyn/shared-ui-jsx/components/prerequisite-notice.component'\nimport {\n useFirestoreCollection,\n usePagedCollection,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\n\nexport interface ReservationsCardProps {\n hostId: string\n}\n\nconst STATUS_COLOR: Record<\n string,\n 'default' | 'success' | 'warning' | 'error' | 'info'\n> = {\n pending: 'warning',\n confirmed: 'info',\n checked_in: 'success',\n checked_out: 'default',\n cancelled: 'default',\n no_show: 'error',\n}\n\nconst usd = (cents: number | undefined) =>\n `$${((cents ?? 0) / 100).toFixed(2)}`\nconst day = (dayMs: number | undefined) =>\n dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—'\nconst nightLabel = (dayMs: number) =>\n new Date(dayMs).toLocaleDateString('en-US', {\n weekday: 'short',\n month: 'short',\n day: 'numeric',\n timeZone: 'UTC',\n })\n\n/** The Reservations card's look-ahead for a several-unit resource. */\nconst UNITS_LOOKAHEAD_NIGHTS = 14\n\n/** The desk's calendar day as the UTC-midnight `dayMs` stays are stored in. */\nfunction localTodayDayMs(): number {\n const now = new Date()\n return Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())\n}\n\n/** The units field's problem, or null when the typed value is a valid count. */\nfunction unitsProblem(units: number | undefined): string | null {\n if (units === undefined) return null\n if (\n !Number.isInteger(units) ||\n units < 1 ||\n units > CommerceModel.MAX_RESOURCE_UNITS\n ) {\n return `A whole number from 1 to ${CommerceModel.MAX_RESOURCE_UNITS}`\n }\n return null\n}\n\n/**\n * Reservations console (AGL-311): resources CRUD (nightly pricing,\n * seasons via multipliers, deposits) plus the reservations list with\n * check-in/out, no-show, cancel, and walk-in creation. The storefront\n * widget books against the same docs.\n */\nexport function ReservationsCard(props: ReservationsCardProps) {\n const { hostId } = props\n // Every reservation is paid when it is booked, so a store that cannot\n // charge turns each guest away; the card says so up front.\n const payments = useMerchantPayments(hostId)\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const {\n data: resourceDocs,\n status: resourcesStatus,\n /**\n * The rows this editor is seeded from are unconfirmed by the server\n * (AGL-1358). Editing spreads a whole stored resource into\n * `resourceDraft` and writes all of it back, so `merge: true` protects\n * nothing. `blocks` is the field that costs more than money: it is the\n * manually blocked date ranges `isRangeAvailable` reads, so a cached seed\n * re-opens dates that were closed and lets the next guest book a room\n * that is already spoken for.\n */\n fromCache: resourcesFromCache,\n } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'resources'), limit(50)),\n [firestore, hostId],\n { idField: '$id' },\n )\n /*\n * Ordered by the server, and a growing window rather than a fixed 300.\n *\n * `limit(300)` carried no `orderBy`, so Firestore returned DOCUMENT-ID\n * order and the client sort below arranged that pseudo-random sample by\n * check-in. The ordering is unchanged — earliest check-in first, exactly\n * what the sort did — it is now the QUERY's, so the window is the real\n * front of the list and the rest can be reached.\n */\n const {\n rows: reservations,\n hasMore,\n page,\n setPage,\n pageSize,\n setPageSize,\n } = usePagedCollection<any>(\n (pageLimit) =>\n query(\n collection(firestore, 'hosts', hostId, 'reservations'),\n orderBy('checkInDayMs', 'asc'),\n limit(pageLimit),\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n /*\n * Units left on each of the next nights, for resources with several units\n * (AGL-4044). One listen across the site's resources, on the stays that\n * have not ended, nearest check-out first: a range and an order on the same\n * field, which Firestore's automatic single-field index serves. Not read at\n * all while every resource has one unit, so a cabin-only site pays nothing.\n *\n * The 500 cap is the booking door's: it can only leave out stays that end\n * after 500 others that are all still running, which would be a stay far\n * past the two weeks this draws.\n */\n const hasSeveralUnits = (resourceDocs ?? []).some(\n (resource: any) => CommerceModel.resourceUnits(resource) > 1,\n )\n const todayDayMs = localTodayDayMs()\n const { data: currentStays } = useFirestoreCollection<any>(\n () =>\n hasSeveralUnits\n ? query(\n collection(firestore, 'hosts', hostId, 'reservations'),\n where('checkOutDayMs', '>', todayDayMs),\n orderBy('checkOutDayMs'),\n limit(500),\n )\n : null,\n [firestore, hostId, hasSeveralUnits, todayDayMs],\n { idField: '$id' },\n )\n const unitsAhead = useMemo(() => {\n const byResource: Record<string, CommerceModel.ResourceNightUnits[]> = {}\n if (!hasSeveralUnits) return byResource\n const nowMs = Date.now()\n for (const resource of resourceDocs ?? []) {\n if (CommerceModel.resourceUnits(resource) === 1) continue\n const stays = (currentStays ?? [])\n .filter((stay: any) => stay.resourceId === resource.$id)\n .map((stay: any) => ({\n checkInDayMs: Number(stay.checkInDayMs),\n checkOutDayMs: Number(stay.checkOutDayMs),\n status: stay.status as CommerceModel.ReservationStatus,\n createdAtMs: Number(stay.createdAtMs ?? 0),\n }))\n byResource[resource.$id] = CommerceModel.unitsLeftByNight(\n resource,\n stays,\n todayDayMs,\n UNITS_LOOKAHEAD_NIGHTS,\n nowMs,\n )\n }\n return byResource\n }, [hasSeveralUnits, resourceDocs, currentStays, todayDayMs])\n\n const resourceNames = useMemo(() => {\n const map: Record<string, string> = {}\n for (const resource of resourceDocs ?? []) {\n map[resource.$id] = resource.name\n }\n return map\n }, [resourceDocs])\n\n const [resourceDraft, setResourceDraft] = useState<\n (Partial<CommerceModel.HostResource> & { id: string | null }) | null\n >(null)\n const [walkIn, setWalkIn] = useState<{\n resourceId: string\n checkIn: string\n checkOut: string\n guestName: string\n /** One walk-in attempt: a retry of it finds its own stay (AGL-4046). */\n attemptId: string\n } | null>(null)\n const [walkInBusy, setWalkInBusy] = useState(false)\n\n const handleResourceSave = useCallback(async () => {\n if (!resourceDraft?.name?.trim() || !(resourceDraft.nightlyRateUsd! > 0)) {\n return\n }\n /**\n * `$id` comes off with `id` (AGL-1374).\n *\n * The editor is seeded `{ id: resource.$id, ...resource }`, and that\n * spread carries the listener's SYNTHETIC `$id` — `idField: '$id'`\n * stamps the document id onto the in-memory row, where nothing persists\n * it. Destructuring only `id` left `$id` in `data`, so every save wrote\n * it into the stored document as a real field. Nothing reads it; it is\n * the listener's bookkeeping leaking into storage, and once there no\n * reader can tell it from a field the card meant to write.\n */\n if (unitsProblem(resourceDraft.units)) return\n const seeded = resourceDraft as typeof resourceDraft & { $id?: string }\n const { id, $id: _syntheticId, units, ...fields } = seeded\n // Units are written as the count the model reads (AGL-4044), and a\n // cleared field as 1 rather than left out: `merge: true` would otherwise\n // keep a stored 12 the merchant just removed.\n const data = 'units' in seeded\n ? { ...fields, units: CommerceModel.resourceUnits({ units }) }\n : fields\n /**\n * Refuse an EDIT whose seed the server never confirmed (AGL-1358).\n * `data` is the whole stored row spread out of the listener, so\n * `merge: true` has nothing left to protect — every field is present,\n * `blocks` and the seasonal multipliers included.\n *\n * Only the edit path. A NEW resource is built from defaults at a fresh\n * uid and can overwrite nothing, and the first snapshot of any listener\n * is `fromCache: true`, so guarding a create would refuse a save that was\n * never unsafe.\n *\n * The guard WRAPS the write — an early return is a shape you can keep\n * while losing the protection.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'resource',\n unreadable: Boolean(id) && resourcesStatus === 'error',\n fromCache: Boolean(id) && resourcesFromCache,\n },\n async () => {\n await setDoc(\n doc(\n firestore,\n 'hosts',\n hostId,\n 'resources',\n id ?? Aglyn.createResourceUid(),\n ),\n {\n ...data,\n name: resourceDraft.name!.trim().slice(0, 120),\n },\n { merge: true },\n )\n },\n )\n // Before `setResourceDraft(null)`, so a refusal keeps the dialog open\n // with what was typed.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n setResourceDraft(null)\n enqueueSnackbar('Resource saved', { variant: 'success', persist: false })\n }, [\n resourceDraft,\n firestore,\n hostId,\n enqueueSnackbar,\n resourcesStatus,\n resourcesFromCache,\n ])\n\n const handleStatus = useCallback(\n (reservation: any, status: CommerceModel.ReservationStatus) => async () => {\n await updateDoc(\n doc(firestore, 'hosts', hostId, 'reservations', reservation.$id),\n { status },\n )\n },\n [firestore, hostId],\n )\n\n const handleWalkIn = useCallback(async () => {\n if (!walkIn?.resourceId || !walkIn.checkIn || !walkIn.checkOut) return\n const resource = (resourceDocs ?? []).find(\n (item: any) => item.$id === walkIn.resourceId,\n ) as CommerceModel.HostResource | undefined\n if (!resource) return\n const checkInDayMs = Date.parse(`${walkIn.checkIn}T00:00:00Z`)\n const checkOutDayMs = Date.parse(`${walkIn.checkOut}T00:00:00Z`)\n /*\n * The stay is priced FIRST, and its `problem` stops the walk-in: the quote\n * is the one rule for what can be booked (no nights, under the minimum\n * stay), shared with the booking widget and both native apps. Ignoring it\n * wrote a confirmed zero-night, $0 stay for a check-out on the arrival\n * day (AGL-3794).\n */\n const quote = CommerceModel.computeReservationQuote(\n resource,\n checkInDayMs,\n checkOutDayMs,\n )\n if (quote.problem) {\n return void enqueueSnackbar(quote.problem, {\n variant: 'warning',\n persist: false,\n })\n }\n /*\n * Every stay of THIS resource that ends after the walk-in arrives — the\n * same query `reserve.ts` checks a booking against, on the composite it\n * already has (AGL-3321). This used to test the rows on the card's\n * current page, so a stay on the next page did not block the dates and\n * the desk could double-book the room.\n */\n const overlapping = await getDocs(\n query(\n collection(firestore, 'hosts', hostId, 'reservations'),\n where('resourceId', '==', walkIn.resourceId),\n where('checkOutDayMs', '>', checkInDayMs),\n orderBy('checkOutDayMs'),\n limit(500),\n ),\n ).catch(() => null)\n if (!overlapping) {\n return void enqueueSnackbar('Could not check those dates — try again', {\n variant: 'warning',\n persist: false,\n })\n }\n // `createdAtMs` carried through because the pending hold lapses on it\n // (`reservationHoldsDates`). Dropping it made every unpaid `pending` row\n // block forever, so the front desk was refused a walk-in into a room that\n // an abandoned online checkout had left empty.\n const existing = overlapping.docs\n .map((snapshot) => snapshot.data() as any)\n .map((item: any) => ({\n checkInDayMs: item.checkInDayMs,\n checkOutDayMs: item.checkOutDayMs,\n status: item.status,\n createdAtMs: item.createdAtMs,\n }))\n // Count-based for a several-unit resource (AGL-4044): the walk-in takes\n // any unit that is free on every night, and is refused only when some\n // night has none left.\n if (\n !CommerceModel.isRangeAvailable(resource, existing, checkInDayMs, checkOutDayMs)\n ) {\n const message =\n CommerceModel.resourceUnits(resource) > 1\n ? 'Every unit is taken on at least one of those nights'\n : 'Those dates are taken'\n return void enqueueSnackbar(message, {\n variant: 'warning',\n persist: false,\n })\n }\n /*\n * The check above is the instant answer; the WRITE goes through\n * `/api/commerce/reservations/walk-in` (AGL-4046), which re-asks the same\n * question inside the transaction that books the stay. A client\n * read-then-write let two staff on two devices both take the last unit.\n */\n setWalkInBusy(true)\n try {\n const response = await authorizedFetch(\n user,\n '/api/commerce/reservations/walk-in',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n resourceId: walkIn.resourceId,\n checkInDayMs,\n checkOutDayMs,\n guestName: walkIn.guestName || undefined,\n reservationId: walkIn.attemptId,\n }),\n },\n )\n const answer = await response.json().catch(() => ({}))\n if (!response.ok) {\n return void enqueueSnackbar(\n answer?.error ?? 'Could not reserve the walk-in — try again',\n {\n variant: response.status === 409 || response.status === 400\n ? 'warning'\n : 'error',\n persist: false,\n },\n )\n }\n } catch {\n return void enqueueSnackbar('Could not reserve the walk-in — try again', {\n variant: 'error',\n persist: false,\n })\n } finally {\n setWalkInBusy(false)\n }\n setWalkIn(null)\n enqueueSnackbar('Walk-in reserved — collect payment at POS', {\n variant: 'success',\n persist: false,\n })\n }, [walkIn, resourceDocs, firestore, hostId, user, enqueueSnackbar])\n\n return (\n <CardDisplay\n header={'Reservations'}\n help={pluginDocsHelp('pos', { anchor: '#reservations' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n {payments.blocked ? (\n <PrerequisiteNotice severity=\"warning\" href={payments.href ?? undefined} actionLabel=\"Open Payments\">\n {`${payments.reason ?? ''} Guests pay when they reserve, so they can't reserve until it is set up.`}\n </PrerequisiteNotice>\n ) : null}\n <Typography variant=\"subtitle2\">{'Resources'}</Typography>\n {(resourceDocs ?? []).map((resource: any) => (\n <Stack key={resource.$id} spacing={0.5}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {[\n resource.name,\n `$${resource.nightlyRateUsd}/night`,\n ...(CommerceModel.resourceUnits(resource) > 1\n ? [`${CommerceModel.resourceUnits(resource)} units`]\n : []),\n ].join(' · ')}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`id: ${resource.$id}`}\n </Typography>\n </Stack>\n <Button\n size=\"small\"\n onClick={() => setResourceDraft({ id: resource.$id, ...resource })}\n >\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Remove this resource?',\n description:\n 'Existing reservations keep their records; the widget ' +\n 'stops accepting new stays.',\n confirmationText: 'Remove',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await deleteDoc(\n doc(firestore, 'hosts', hostId, 'resources', resource.$id),\n )\n }}\n >\n {'Remove'}\n </Button>\n </Stack>\n {unitsAhead[resource.$id] ? (\n <Stack\n direction=\"row\"\n useFlexGap\n aria-label={`Units left on the next ${UNITS_LOOKAHEAD_NIGHTS} nights`}\n sx={{ flexWrap: 'wrap', gap: 0.5 }}\n >\n {unitsAhead[resource.$id].map((night) => (\n <Chip\n key={night.dayMs}\n size=\"small\"\n variant=\"outlined\"\n color={\n night.unitsLeft === 0\n ? 'error'\n : night.unitsLeft <= CommerceModel.FEW_UNITS_LEFT\n ? 'warning'\n : 'default'\n }\n label={`${nightLabel(night.dayMs)} · ${night.unitsLeft} of ${night.units} left`}\n />\n ))}\n </Stack>\n ) : null}\n </Stack>\n ))}\n <Stack direction=\"row\" spacing={1}>\n <Button\n size=\"small\"\n onClick={() =>\n setResourceDraft({\n id: null,\n name: '',\n nightlyRateUsd: 100,\n depositPct: 30,\n minNights: 1,\n })\n }\n >\n {'Add resource'}\n </Button>\n <Button\n size=\"small\"\n disabled={(resourceDocs?.length ?? 0) === 0}\n onClick={() =>\n setWalkIn({\n resourceId: resourceDocs?.[0]?.$id ?? '',\n checkIn: '',\n checkOut: '',\n guestName: '',\n attemptId: Aglyn.createResourceUid(),\n })\n }\n >\n {'Walk-in'}\n </Button>\n </Stack>\n\n <Typography variant=\"subtitle2\" sx={{ mt: 1 }}>\n {'Upcoming & recent stays'}\n </Typography>\n {reservations.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Reservations from the widget (and walk-ins) appear here.'}\n </Typography>\n ) : (\n reservations.map((reservation: any) => (\n <Stack\n key={reservation.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {`${resourceNames[reservation.resourceId] ?? '?'} · ` +\n `${day(reservation.checkInDayMs)} → ${day(reservation.checkOutDayMs)}`}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {[\n reservation.guestName ?? reservation.guestEmail ?? 'Guest',\n `${usd(reservation.paidCents)} / ${usd(reservation.totalCents)} paid`,\n ].join(' · ')}\n </Typography>\n </Stack>\n <Chip\n label={String(reservation.status).replace('_', ' ')}\n size=\"small\"\n variant=\"outlined\"\n color={STATUS_COLOR[reservation.status] ?? 'default'}\n />\n {reservation.status === 'confirmed' ? (\n <>\n <Button size=\"small\" onClick={handleStatus(reservation, 'checked_in')}>\n {'Check in'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleStatus(reservation, 'no_show')}\n >\n {'No-show'}\n </Button>\n </>\n ) : null}\n {reservation.status === 'checked_in' ? (\n <Button\n size=\"small\"\n onClick={async () => {\n // Folio settlement (AGL-317): surface unpaid room\n // charges before the guest leaves.\n const folio = (reservation.folio ?? []) as Array<{\n amountCents: number\n }>\n const folioCents = folio.reduce(\n (sum, entry) => sum + (entry.amountCents ?? 0),\n 0,\n )\n const balanceCents =\n (reservation.totalCents ?? 0) -\n (reservation.paidCents ?? 0)\n if (folioCents > 0 || balanceCents > 0) {\n const confirmed = await confirm({\n title: 'Check out with open balance?',\n description:\n `${folioCents > 0 ? `Room charges: ${usd(folioCents)} (already recorded as paid POS orders). ` : ''}` +\n `${balanceCents > 0 ? `Stay balance due: ${usd(balanceCents)} — collect at the register.` : ''}`,\n confirmationText: 'Check out',\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n }\n await handleStatus(reservation, 'checked_out')()\n }}\n >\n {'Check out'}\n </Button>\n ) : null}\n {['pending', 'confirmed'].includes(reservation.status) ? (\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleStatus(reservation, 'cancelled')}\n >\n {'Cancel'}\n </Button>\n ) : null}\n </Stack>\n ))\n )}\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={reservations.length}\n hasMore={hasMore}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n </Stack>\n\n <Dialog\n open={Boolean(resourceDraft)}\n onClose={() => setResourceDraft(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>\n {resourceDraft?.id ? 'Edit resource' : 'New resource'}\n </DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <TextField\n label=\"Name\"\n value={resourceDraft?.name ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev ? { ...prev, name: event.target.value } : prev,\n )\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n placeholder=\"Lakeside cabin\"\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Spots or units available\"\n placeholder=\"1\"\n value={resourceDraft?.units ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n units:\n event.target.value.replace(/\\D/g, '') === ''\n ? undefined\n : Number(event.target.value.replace(/\\D/g, '')),\n }\n : prev,\n )\n }\n error={Boolean(unitsProblem(resourceDraft?.units))}\n helperText={\n unitsProblem(resourceDraft?.units) ??\n 'How many identical ones you have, like 12 RV hookups'\n }\n size=\"small\"\n fullWidth\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n <TextField\n label=\"Sleeps\"\n value={resourceDraft?.capacity ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n capacity:\n Math.round(Number(event.target.value)) || undefined,\n }\n : prev,\n )\n }\n helperText=\"Guests per unit, for display\"\n size=\"small\"\n fullWidth\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n </Stack>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Nightly rate ($)\"\n value={resourceDraft?.nightlyRateUsd ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n nightlyRateUsd: Number(event.target.value) || 0,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n <TextField\n label=\"Weekend ×\"\n placeholder=\"1\"\n value={resourceDraft?.weekendMultiplier ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n weekendMultiplier:\n Number(event.target.value) || undefined,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n </Stack>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Min nights\"\n value={resourceDraft?.minNights ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n minNights:\n Math.round(Number(event.target.value)) || undefined,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n <TextField\n label=\"Deposit %\"\n placeholder=\"100 = pay in full\"\n value={resourceDraft?.depositPct ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n depositPct:\n Math.round(Number(event.target.value)) || undefined,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n <TextField\n label=\"Free cancel (hrs)\"\n value={resourceDraft?.cancellationHours ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n cancellationHours:\n Math.round(Number(event.target.value)) || undefined,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setResourceDraft(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={\n !resourceDraft?.name?.trim() ||\n !((resourceDraft?.nightlyRateUsd ?? 0) > 0) ||\n Boolean(unitsProblem(resourceDraft?.units))\n }\n onClick={handleResourceSave}\n >\n {'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n\n <Dialog\n open={Boolean(walkIn)}\n onClose={() => setWalkIn(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'Walk-in reservation'}</DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <TextField\n label=\"Resource\"\n value={walkIn?.resourceId ?? ''}\n onChange={(event) =>\n setWalkIn((prev) =>\n prev ? { ...prev, resourceId: event.target.value } : prev,\n )\n }\n size=\"small\"\n select\n sx={{ mt: 1 }}\n >\n {(resourceDocs ?? []).map((resource: any) => (\n <MenuItem key={resource.$id} value={resource.$id}>\n {resource.name}\n </MenuItem>\n ))}\n </TextField>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Check-in\"\n type=\"date\"\n value={walkIn?.checkIn ?? ''}\n onChange={(event) =>\n setWalkIn((prev) =>\n prev ? { ...prev, checkIn: event.target.value } : prev,\n )\n }\n size=\"small\"\n fullWidth\n slotProps={{ inputLabel: { shrink: true } }}\n />\n <TextField\n label=\"Check-out\"\n type=\"date\"\n value={walkIn?.checkOut ?? ''}\n onChange={(event) =>\n setWalkIn((prev) =>\n prev ? { ...prev, checkOut: event.target.value } : prev,\n )\n }\n size=\"small\"\n fullWidth\n slotProps={{ inputLabel: { shrink: true } }}\n />\n </Stack>\n <TextField\n label=\"Guest name\"\n value={walkIn?.guestName ?? ''}\n onChange={(event) =>\n setWalkIn((prev) =>\n prev ? { ...prev, guestName: event.target.value } : prev,\n )\n }\n size=\"small\"\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setWalkIn(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={\n walkInBusy ||\n !walkIn?.resourceId ||\n !walkIn?.checkIn ||\n !walkIn?.checkOut\n }\n onClick={handleWalkIn}\n >\n {'Reserve'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nReservationsCard.displayName = 'ReservationsCard'\n\nexport default ReservationsCard\n"],"names":["Aglyn","CommerceModel","CardDisplay","useConfirmationContext","ListPagination","useSnackbar","Button","Chip","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","TextField","Typography","collection","deleteDoc","doc","getDocs","limit","orderBy","query","setDoc","updateDoc","where","useCallback","useMemo","useState","useFirestore","useMerchantPayments","useUser","authorizedFetch","PrerequisiteNotice","useFirestoreCollection","usePagedCollection","writeGuardedBySeed","pluginDocsHelp","STATUS_COLOR","pending","confirmed","checked_in","checked_out","cancelled","no_show","usd","cents","toFixed","day","dayMs","Date","toISOString","slice","nightLabel","toLocaleDateString","weekday","month","timeZone","UNITS_LOOKAHEAD_NIGHTS","localTodayDayMs","now","UTC","getFullYear","getMonth","getDate","unitsProblem","units","undefined","Number","isInteger","MAX_RESOURCE_UNITS","ReservationsCard","props","payments","resourceDraft","hostId","firestore","data","user","enqueueSnackbar","confirm","resourceDocs","status","resourcesStatus","fromCache","resourcesFromCache","idField","rows","reservations","hasMore","page","setPage","pageSize","setPageSize","pageLimit","hasSeveralUnits","some","resource","resourceUnits","todayDayMs","currentStays","unitsAhead","byResource","nowMs","stays","filter","stay","resourceId","$id","map","checkInDayMs","checkOutDayMs","createdAtMs","unitsLeftByNight","resourceNames","name","setResourceDraft","walkIn","setWalkIn","walkInBusy","setWalkInBusy","handleResourceSave","trim","nightlyRateUsd","seeded","id","_syntheticId","fields","verdict","subject","unreadable","Boolean","createResourceUid","merge","ok","message","variant","persist","handleStatus","reservation","handleWalkIn","checkIn","checkOut","find","item","parse","quote","computeReservationQuote","problem","overlapping","catch","existing","docs","snapshot","isRangeAvailable","response","method","headers","body","JSON","stringify","guestName","reservationId","attemptId","answer","json","error","header","help","anchor","contentGutterX","contentGutterY","spacing","blocked","severity","href","actionLabel","reason","direction","sx","alignItems","flex","minWidth","noWrap","join","color","size","onClick","title","description","confirmationText","confirmationButtonProps","then","useFlexGap","aria-label","flexWrap","gap","night","unitsLeft","FEW_UNITS_LEFT","label","depositPct","minNights","disabled","length","mt","guestEmail","paidCents","totalCents","String","replace","folio","folioCents","reduce","sum","entry","amountCents","balanceCents","includes","rowCount","onPageChange","onPageSizeChange","open","onClose","maxWidth","fullWidth","display","flexDirection","value","onChange","event","prev","target","autoFocus","placeholder","helperText","slotProps","htmlInput","inputMode","capacity","Math","round","weekendMultiplier","cancellationHours","select","type","inputLabel","shrink","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/reservations-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport * as CommerceModel from '../../model'\nimport { reservationPermissionRefusal } from '../../model/plugin-permissions'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport {\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n deleteDoc,\n doc,\n getDocs,\n limit,\n orderBy,\n query,\n setDoc,\n updateDoc,\n where,\n} from 'firebase/firestore'\nimport { lazy, Suspense, useCallback, useMemo, useState } from 'react'\nimport { useFirestore, useMerchantPayments, useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { PrerequisiteNotice } from '@aglyn/shared-ui-jsx/components/prerequisite-notice.component'\nimport {\n useFirestoreCollection,\n usePagedCollection,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport { pluginDocsHelp } from '@aglyn/aglyn'\n\nexport interface ReservationsCardProps {\n hostId: string\n /**\n * \"Manage reservations\" (`commerce.reservations`, AGL-4047) on this site:\n * edit, cancel and check out stays and change what can be booked. The rules\n * decide it; this only disables the controls with the reason. Absent reads\n * as held, so a surface that does not pass it shows the card as before.\n */\n canManage?: boolean\n /** \"Book walk-ins and change guests\" (`commerce.walkIns`), which the routes ask. */\n canWalkIn?: boolean\n}\n\n/** A stay's guest count after booking (AGL-4043), loaded the first time it opens. */\nconst ReservationGuestsDialog = lazy(() => import('./reservation-guests-dialog.component'))\n\n/** The statuses whose guest count staff can still change. */\nconst GUESTS_OPEN_STATUSES = ['pending', 'confirmed', 'checked_in']\n\nconst STATUS_COLOR: Record<\n string,\n 'default' | 'success' | 'warning' | 'error' | 'info'\n> = {\n pending: 'warning',\n confirmed: 'info',\n checked_in: 'success',\n checked_out: 'default',\n cancelled: 'default',\n no_show: 'error',\n}\n\nconst usd = (cents: number | undefined) =>\n `$${((cents ?? 0) / 100).toFixed(2)}`\nconst day = (dayMs: number | undefined) =>\n dayMs ? new Date(dayMs).toISOString().slice(0, 10) : '—'\nconst nightLabel = (dayMs: number) =>\n new Date(dayMs).toLocaleDateString('en-US', {\n weekday: 'short',\n month: 'short',\n day: 'numeric',\n timeZone: 'UTC',\n })\n\n/** The Reservations card's look-ahead for a several-unit resource. */\nconst UNITS_LOOKAHEAD_NIGHTS = 14\n\n/** The desk's calendar day as the UTC-midnight `dayMs` stays are stored in. */\nfunction localTodayDayMs(): number {\n const now = new Date()\n return Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())\n}\n\n/** The units field's problem, or null when the typed value is a valid count. */\nfunction unitsProblem(units: number | undefined): string | null {\n if (units === undefined) return null\n if (\n !Number.isInteger(units) ||\n units < 1 ||\n units > CommerceModel.MAX_RESOURCE_UNITS\n ) {\n return `A whole number from 1 to ${CommerceModel.MAX_RESOURCE_UNITS}`\n }\n return null\n}\n\n/**\n * The \"Only N left\" field's problem (AGL-4044), or null when the typed value\n * is a valid threshold: 0 (never) up to the most units a resource can hold.\n */\nfunction fewLeftAtProblem(fewLeftAt: number | undefined): string | null {\n if (fewLeftAt === undefined) return null\n if (\n !Number.isInteger(fewLeftAt) ||\n fewLeftAt < 0 ||\n fewLeftAt > CommerceModel.MAX_RESOURCE_UNITS\n ) {\n return `A whole number from 0 to ${CommerceModel.MAX_RESOURCE_UNITS}`\n }\n return null\n}\n\n/**\n * Reservations console (AGL-311): resources CRUD (nightly pricing,\n * seasons via multipliers, deposits) plus the reservations list with\n * check-in/out, no-show, cancel, and walk-in creation. The storefront\n * widget books against the same docs.\n */\nexport function ReservationsCard(props: ReservationsCardProps) {\n const { hostId, canManage = true, canWalkIn = true } = props\n // The permissions this member lacks here, named, for the line under the\n // card's actions (AGL-4047): a disabled control says why.\n const missing = [\n ...(canManage ? [] : [reservationPermissionRefusal('commerce.reservations')]),\n ...(canWalkIn ? [] : [reservationPermissionRefusal('commerce.walkIns')]),\n ]\n // Every reservation is paid when it is booked, so a store that cannot\n // charge turns each guest away; the card says so up front.\n const payments = useMerchantPayments(hostId)\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const {\n data: resourceDocs,\n status: resourcesStatus,\n /**\n * The rows this editor is seeded from are unconfirmed by the server\n * (AGL-1358). Editing spreads a whole stored resource into\n * `resourceDraft` and writes all of it back, so `merge: true` protects\n * nothing. `blocks` is the field that costs more than money: it is the\n * manually blocked date ranges `isRangeAvailable` reads, so a cached seed\n * re-opens dates that were closed and lets the next guest book a room\n * that is already spoken for.\n */\n fromCache: resourcesFromCache,\n } = useFirestoreCollection<any>(\n () => query(collection(firestore, 'hosts', hostId, 'resources'), limit(50)),\n [firestore, hostId],\n { idField: '$id' },\n )\n /*\n * Ordered by the server, and a growing window rather than a fixed 300.\n *\n * `limit(300)` carried no `orderBy`, so Firestore returned DOCUMENT-ID\n * order and the client sort below arranged that pseudo-random sample by\n * check-in. The ordering is unchanged — earliest check-in first, exactly\n * what the sort did — it is now the QUERY's, so the window is the real\n * front of the list and the rest can be reached.\n */\n const {\n rows: reservations,\n hasMore,\n page,\n setPage,\n pageSize,\n setPageSize,\n } = usePagedCollection<any>(\n (pageLimit) =>\n query(\n collection(firestore, 'hosts', hostId, 'reservations'),\n orderBy('checkInDayMs', 'asc'),\n limit(pageLimit),\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n /*\n * Units left on each of the next nights, for resources with several units\n * (AGL-4044). One listen across the site's resources, on the stays that\n * have not ended, nearest check-out first: a range and an order on the same\n * field, which Firestore's automatic single-field index serves. Not read at\n * all while every resource has one unit, so a cabin-only site pays nothing.\n *\n * The 500 cap is the booking door's: it can only leave out stays that end\n * after 500 others that are all still running, which would be a stay far\n * past the two weeks this draws.\n */\n const hasSeveralUnits = (resourceDocs ?? []).some(\n (resource: any) => CommerceModel.resourceUnits(resource) > 1,\n )\n const todayDayMs = localTodayDayMs()\n const { data: currentStays } = useFirestoreCollection<any>(\n () =>\n hasSeveralUnits\n ? query(\n collection(firestore, 'hosts', hostId, 'reservations'),\n where('checkOutDayMs', '>', todayDayMs),\n orderBy('checkOutDayMs'),\n limit(500),\n )\n : null,\n [firestore, hostId, hasSeveralUnits, todayDayMs],\n { idField: '$id' },\n )\n const unitsAhead = useMemo(() => {\n const byResource: Record<string, CommerceModel.ResourceNightUnits[]> = {}\n if (!hasSeveralUnits) return byResource\n const nowMs = Date.now()\n for (const resource of resourceDocs ?? []) {\n if (CommerceModel.resourceUnits(resource) === 1) continue\n const stays = (currentStays ?? [])\n .filter((stay: any) => stay.resourceId === resource.$id)\n .map((stay: any) => ({\n checkInDayMs: Number(stay.checkInDayMs),\n checkOutDayMs: Number(stay.checkOutDayMs),\n status: stay.status as CommerceModel.ReservationStatus,\n createdAtMs: Number(stay.createdAtMs ?? 0),\n }))\n byResource[resource.$id] = CommerceModel.unitsLeftByNight(\n resource,\n stays,\n todayDayMs,\n UNITS_LOOKAHEAD_NIGHTS,\n nowMs,\n )\n }\n return byResource\n }, [hasSeveralUnits, resourceDocs, currentStays, todayDayMs])\n\n const resourceNames = useMemo(() => {\n const map: Record<string, string> = {}\n for (const resource of resourceDocs ?? []) {\n map[resource.$id] = resource.name\n }\n return map\n }, [resourceDocs])\n\n const [resourceDraft, setResourceDraft] = useState<\n (Partial<CommerceModel.HostResource> & { id: string | null }) | null\n >(null)\n const [walkIn, setWalkIn] = useState<{\n resourceId: string\n checkIn: string\n checkOut: string\n guestName: string\n /** How many guests (AGL-4043); '' sends none. */\n guests: string\n /** One walk-in attempt: a retry of it finds its own stay (AGL-4046). */\n attemptId: string\n } | null>(null)\n const [walkInBusy, setWalkInBusy] = useState(false)\n /** The stay whose guests are being changed (AGL-4043). */\n const [guestsFor, setGuestsFor] = useState<string | null>(null)\n\n const handleResourceSave = useCallback(async () => {\n if (!resourceDraft?.name?.trim() || !(resourceDraft.nightlyRateUsd! > 0)) {\n return\n }\n /**\n * `$id` comes off with `id` (AGL-1374).\n *\n * The editor is seeded `{ id: resource.$id, ...resource }`, and that\n * spread carries the listener's SYNTHETIC `$id` — `idField: '$id'`\n * stamps the document id onto the in-memory row, where nothing persists\n * it. Destructuring only `id` left `$id` in `data`, so every save wrote\n * it into the stored document as a real field. Nothing reads it; it is\n * the listener's bookkeeping leaking into storage, and once there no\n * reader can tell it from a field the card meant to write.\n */\n if (unitsProblem(resourceDraft.units)) return\n if (fewLeftAtProblem(resourceDraft.fewLeftAt)) return\n const seeded = resourceDraft as typeof resourceDraft & { $id?: string }\n const { id, $id: _syntheticId, units, fewLeftAt, ...fields } = seeded\n // Units are written as the count the model reads (AGL-4044), and a\n // cleared field as 1 rather than left out: `merge: true` would otherwise\n // keep a stored 12 the merchant just removed. The \"Only N left\" threshold\n // the same way: a cleared field is written as the default it reads as.\n const data = {\n ...fields,\n ...('units' in seeded ? { units: CommerceModel.resourceUnits({ units }) } : {}),\n ...('fewLeftAt' in seeded\n ? { fewLeftAt: CommerceModel.resourceFewLeftAt({ fewLeftAt }) }\n : {}),\n }\n /**\n * Refuse an EDIT whose seed the server never confirmed (AGL-1358).\n * `data` is the whole stored row spread out of the listener, so\n * `merge: true` has nothing left to protect — every field is present,\n * `blocks` and the seasonal multipliers included.\n *\n * Only the edit path. A NEW resource is built from defaults at a fresh\n * uid and can overwrite nothing, and the first snapshot of any listener\n * is `fromCache: true`, so guarding a create would refuse a save that was\n * never unsafe.\n *\n * The guard WRAPS the write — an early return is a shape you can keep\n * while losing the protection.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'resource',\n unreadable: Boolean(id) && resourcesStatus === 'error',\n fromCache: Boolean(id) && resourcesFromCache,\n },\n async () => {\n await setDoc(\n doc(\n firestore,\n 'hosts',\n hostId,\n 'resources',\n id ?? Aglyn.createResourceUid(),\n ),\n {\n ...data,\n name: resourceDraft.name!.trim().slice(0, 120),\n },\n { merge: true },\n )\n },\n )\n // Before `setResourceDraft(null)`, so a refusal keeps the dialog open\n // with what was typed.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n setResourceDraft(null)\n enqueueSnackbar('Resource saved', { variant: 'success', persist: false })\n }, [\n resourceDraft,\n firestore,\n hostId,\n enqueueSnackbar,\n resourcesStatus,\n resourcesFromCache,\n ])\n\n const handleStatus = useCallback(\n (reservation: any, status: CommerceModel.ReservationStatus) => async () => {\n await updateDoc(\n doc(firestore, 'hosts', hostId, 'reservations', reservation.$id),\n { status },\n )\n },\n [firestore, hostId],\n )\n\n const handleWalkIn = useCallback(async () => {\n if (!walkIn?.resourceId || !walkIn.checkIn || !walkIn.checkOut) return\n const resource = (resourceDocs ?? []).find(\n (item: any) => item.$id === walkIn.resourceId,\n ) as CommerceModel.HostResource | undefined\n if (!resource) return\n const checkInDayMs = Date.parse(`${walkIn.checkIn}T00:00:00Z`)\n const checkOutDayMs = Date.parse(`${walkIn.checkOut}T00:00:00Z`)\n const guests = walkIn.guests.trim() ? Number(walkIn.guests) : undefined\n const guestsProblem = CommerceModel.reservationGuestsProblem(guests, resource)\n if (guestsProblem) {\n return void enqueueSnackbar(guestsProblem, { variant: 'warning', persist: false })\n }\n /*\n * The stay is priced FIRST, and its `problem` stops the walk-in: the quote\n * is the one rule for what can be booked (no nights, under the minimum\n * stay), shared with the booking widget and both native apps. Ignoring it\n * wrote a confirmed zero-night, $0 stay for a check-out on the arrival\n * day (AGL-3794).\n */\n const quote = CommerceModel.computeReservationQuote(\n resource,\n checkInDayMs,\n checkOutDayMs,\n )\n if (quote.problem) {\n return void enqueueSnackbar(quote.problem, {\n variant: 'warning',\n persist: false,\n })\n }\n /*\n * Every stay of THIS resource that ends after the walk-in arrives — the\n * same query `reserve.ts` checks a booking against, on the composite it\n * already has (AGL-3321). This used to test the rows on the card's\n * current page, so a stay on the next page did not block the dates and\n * the desk could double-book the room.\n */\n const overlapping = await getDocs(\n query(\n collection(firestore, 'hosts', hostId, 'reservations'),\n where('resourceId', '==', walkIn.resourceId),\n where('checkOutDayMs', '>', checkInDayMs),\n orderBy('checkOutDayMs'),\n limit(500),\n ),\n ).catch(() => null)\n if (!overlapping) {\n return void enqueueSnackbar('Could not check those dates — try again', {\n variant: 'warning',\n persist: false,\n })\n }\n // `createdAtMs` carried through because the pending hold lapses on it\n // (`reservationHoldsDates`). Dropping it made every unpaid `pending` row\n // block forever, so the front desk was refused a walk-in into a room that\n // an abandoned online checkout had left empty.\n const existing = overlapping.docs\n .map((snapshot) => snapshot.data() as any)\n .map((item: any) => ({\n checkInDayMs: item.checkInDayMs,\n checkOutDayMs: item.checkOutDayMs,\n status: item.status,\n createdAtMs: item.createdAtMs,\n }))\n // Count-based for a several-unit resource (AGL-4044): the walk-in takes\n // any unit that is free on every night, and is refused only when some\n // night has none left.\n if (\n !CommerceModel.isRangeAvailable(resource, existing, checkInDayMs, checkOutDayMs)\n ) {\n const message =\n CommerceModel.resourceUnits(resource) > 1\n ? 'Every unit is taken on at least one of those nights'\n : 'Those dates are taken'\n return void enqueueSnackbar(message, {\n variant: 'warning',\n persist: false,\n })\n }\n /*\n * The check above is the instant answer; the WRITE goes through\n * `/api/commerce/reservations/walk-in` (AGL-4046), which re-asks the same\n * question inside the transaction that books the stay. A client\n * read-then-write let two staff on two devices both take the last unit.\n */\n setWalkInBusy(true)\n try {\n const response = await authorizedFetch(\n user,\n '/api/commerce/reservations/walk-in',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n resourceId: walkIn.resourceId,\n checkInDayMs,\n checkOutDayMs,\n guestName: walkIn.guestName || undefined,\n ...(guests !== undefined ? { guests } : {}),\n reservationId: walkIn.attemptId,\n }),\n },\n )\n const answer = await response.json().catch(() => ({}))\n if (!response.ok) {\n return void enqueueSnackbar(\n answer?.error ?? 'Could not reserve the walk-in — try again',\n {\n variant: response.status === 409 || response.status === 400\n ? 'warning'\n : 'error',\n persist: false,\n },\n )\n }\n } catch {\n return void enqueueSnackbar('Could not reserve the walk-in — try again', {\n variant: 'error',\n persist: false,\n })\n } finally {\n setWalkInBusy(false)\n }\n setWalkIn(null)\n enqueueSnackbar('Walk-in reserved — collect payment at POS', {\n variant: 'success',\n persist: false,\n })\n }, [walkIn, resourceDocs, firestore, hostId, user, enqueueSnackbar])\n\n return (\n <CardDisplay\n header={'Reservations'}\n help={pluginDocsHelp('pos', { anchor: '#reservations' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n {payments.blocked ? (\n <PrerequisiteNotice severity=\"warning\" href={payments.href ?? undefined} actionLabel=\"Open Payments\">\n {`${payments.reason ?? ''} Guests pay when they reserve, so they can't reserve until it is set up.`}\n </PrerequisiteNotice>\n ) : null}\n <Typography variant=\"subtitle2\">{'Resources'}</Typography>\n {(resourceDocs ?? []).map((resource: any) => (\n <Stack key={resource.$id} spacing={0.5}>\n <Stack\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {[\n resource.name,\n `$${resource.nightlyRateUsd}/night`,\n ...(CommerceModel.resourceUnits(resource) > 1\n ? [`${CommerceModel.resourceUnits(resource)} units`]\n : []),\n ].join(' · ')}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`id: ${resource.$id}`}\n </Typography>\n </Stack>\n <Button\n size=\"small\"\n disabled={!canManage}\n onClick={() => setResourceDraft({ id: resource.$id, ...resource })}\n >\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n disabled={!canManage}\n onClick={async () => {\n const confirmed = await confirm({\n title: 'Remove this resource?',\n description:\n 'Existing reservations keep their records; the widget ' +\n 'stops accepting new stays.',\n confirmationText: 'Remove',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await deleteDoc(\n doc(firestore, 'hosts', hostId, 'resources', resource.$id),\n )\n }}\n >\n {'Remove'}\n </Button>\n </Stack>\n {unitsAhead[resource.$id] ? (\n <Stack\n direction=\"row\"\n useFlexGap\n aria-label={`Units left on the next ${UNITS_LOOKAHEAD_NIGHTS} nights`}\n sx={{ flexWrap: 'wrap', gap: 0.5 }}\n >\n {unitsAhead[resource.$id].map((night) => (\n <Chip\n key={night.dayMs}\n size=\"small\"\n variant=\"outlined\"\n color={\n night.unitsLeft === 0\n ? 'error'\n : night.unitsLeft <=\n CommerceModel.resourceFewLeftAt(resource)\n ? 'warning'\n : 'default'\n }\n label={`${nightLabel(night.dayMs)} · ${night.unitsLeft} of ${night.units} left`}\n />\n ))}\n </Stack>\n ) : null}\n </Stack>\n ))}\n <Stack direction=\"row\" spacing={1}>\n <Button\n size=\"small\"\n disabled={!canManage}\n onClick={() =>\n setResourceDraft({\n id: null,\n name: '',\n nightlyRateUsd: 100,\n depositPct: 30,\n minNights: 1,\n })\n }\n >\n {'Add resource'}\n </Button>\n <Button\n size=\"small\"\n disabled={!canWalkIn || (resourceDocs?.length ?? 0) === 0}\n onClick={() =>\n setWalkIn({\n resourceId: resourceDocs?.[0]?.$id ?? '',\n checkIn: '',\n checkOut: '',\n guestName: '',\n guests: '',\n attemptId: Aglyn.createResourceUid(),\n })\n }\n >\n {'Walk-in'}\n </Button>\n </Stack>\n {missing.map((reason) => (\n <Typography key={reason} variant=\"caption\" color=\"text.secondary\">\n {reason}\n </Typography>\n ))}\n\n <Typography variant=\"subtitle2\" sx={{ mt: 1 }}>\n {'Upcoming & recent stays'}\n </Typography>\n {reservations.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Reservations from the widget (and walk-ins) appear here.'}\n </Typography>\n ) : (\n reservations.map((reservation: any) => (\n <Stack\n key={reservation.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {`${resourceNames[reservation.resourceId] ?? '?'} · ` +\n `${day(reservation.checkInDayMs)} → ${day(reservation.checkOutDayMs)}`}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {[\n reservation.guestName ?? reservation.guestEmail ?? 'Guest',\n ...(reservation.guests\n ? [`${CommerceModel.reservationGuests(reservation)} guest${CommerceModel.reservationGuests(reservation) === 1 ? '' : 's'}`]\n : []),\n `${usd(reservation.paidCents)} / ${usd(reservation.totalCents)} paid`,\n ].join(' · ')}\n </Typography>\n </Stack>\n <Chip\n label={String(reservation.status).replace('_', ' ')}\n size=\"small\"\n variant=\"outlined\"\n color={STATUS_COLOR[reservation.status] ?? 'default'}\n />\n {reservation.status === 'confirmed' ? (\n <>\n <Button size=\"small\" disabled={!canManage} onClick={handleStatus(reservation, 'checked_in')}>\n {'Check in'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n disabled={!canManage}\n onClick={handleStatus(reservation, 'no_show')}\n >\n {'No-show'}\n </Button>\n </>\n ) : null}\n {reservation.status === 'checked_in' ? (\n <Button\n size=\"small\"\n disabled={!canManage}\n onClick={async () => {\n // Folio settlement (AGL-317): surface unpaid room\n // charges before the guest leaves.\n const folio = (reservation.folio ?? []) as Array<{\n amountCents: number\n }>\n const folioCents = folio.reduce(\n (sum, entry) => sum + (entry.amountCents ?? 0),\n 0,\n )\n const balanceCents =\n (reservation.totalCents ?? 0) -\n (reservation.paidCents ?? 0)\n if (folioCents > 0 || balanceCents > 0) {\n const confirmed = await confirm({\n title: 'Check out with open balance?',\n description:\n `${folioCents > 0 ? `Room charges: ${usd(folioCents)} (already recorded as paid POS orders). ` : ''}` +\n `${balanceCents > 0 ? `Stay balance due: ${usd(balanceCents)} — collect at the register.` : ''}`,\n confirmationText: 'Check out',\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n }\n await handleStatus(reservation, 'checked_out')()\n }}\n >\n {'Check out'}\n </Button>\n ) : null}\n {GUESTS_OPEN_STATUSES.includes(reservation.status) ? (\n <Button size=\"small\" disabled={!canWalkIn} onClick={() => setGuestsFor(reservation.$id)}>\n {'Guests'}\n </Button>\n ) : null}\n {['pending', 'confirmed'].includes(reservation.status) ? (\n <Button\n size=\"small\"\n color=\"error\"\n disabled={!canManage}\n onClick={handleStatus(reservation, 'cancelled')}\n >\n {'Cancel'}\n </Button>\n ) : null}\n </Stack>\n ))\n )}\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={reservations.length}\n hasMore={hasMore}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n </Stack>\n\n {guestsFor ? (\n <Suspense fallback={null}>\n <ReservationGuestsDialog\n reservationId={guestsFor}\n hostId={hostId}\n onClose={() => setGuestsFor(null)}\n onDone={(answer) => {\n setGuestsFor(null)\n enqueueSnackbar(\n answer.unchanged\n ? `Still ${answer.guests} guest${answer.guests === 1 ? '' : 's'}`\n : `Guests changed to ${answer.guests}`,\n { variant: 'success', persist: false },\n )\n }}\n />\n </Suspense>\n ) : null}\n\n <Dialog\n open={Boolean(resourceDraft)}\n onClose={() => setResourceDraft(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>\n {resourceDraft?.id ? 'Edit resource' : 'New resource'}\n </DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <TextField\n label=\"Name\"\n value={resourceDraft?.name ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev ? { ...prev, name: event.target.value } : prev,\n )\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n placeholder=\"Lakeside cabin\"\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Spots or units available\"\n placeholder=\"1\"\n value={resourceDraft?.units ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n units:\n event.target.value.replace(/\\D/g, '') === ''\n ? undefined\n : Number(event.target.value.replace(/\\D/g, '')),\n }\n : prev,\n )\n }\n error={Boolean(unitsProblem(resourceDraft?.units))}\n helperText={\n unitsProblem(resourceDraft?.units) ??\n 'How many identical ones you have, like 12 RV hookups'\n }\n size=\"small\"\n fullWidth\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n <TextField\n label=\"Sleeps\"\n value={resourceDraft?.capacity ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n capacity:\n Math.round(Number(event.target.value)) || undefined,\n }\n : prev,\n )\n }\n helperText=\"Guests per unit, for display\"\n size=\"small\"\n fullWidth\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n </Stack>\n {CommerceModel.resourceUnits(resourceDraft) > 1 ? (\n <TextField\n label=\"Show “Only N left” at\"\n placeholder={String(CommerceModel.FEW_UNITS_LEFT)}\n value={resourceDraft?.fewLeftAt ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n fewLeftAt:\n event.target.value.replace(/\\D/g, '') === ''\n ? undefined\n : Number(event.target.value.replace(/\\D/g, '')),\n }\n : prev,\n )\n }\n error={Boolean(fewLeftAtProblem(resourceDraft?.fewLeftAt))}\n helperText={\n fewLeftAtProblem(resourceDraft?.fewLeftAt) ??\n 'The booking widget says “Only 2 left” once this many or fewer are free on a night. 0 never shows it.'\n }\n size=\"small\"\n fullWidth\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n ) : null}\n <TextField\n select\n label=\"At check-in\"\n value={resourceDraft?.checkInPerGuest ? 'guest' : 'stay'}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev ? { ...prev, checkInPerGuest: event.target.value === 'guest' } : prev,\n )\n }\n helperText=\"One per guest gives each guest their own check-in and wristband. The check-in screen can set every stay at once.\"\n size=\"small\"\n fullWidth\n >\n <MenuItem value=\"stay\">{'One check-in per stay'}</MenuItem>\n <MenuItem value=\"guest\">{'One check-in per guest'}</MenuItem>\n </TextField>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Nightly rate ($)\"\n value={resourceDraft?.nightlyRateUsd ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n nightlyRateUsd: Number(event.target.value) || 0,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n <TextField\n label=\"Weekend ×\"\n placeholder=\"1\"\n value={resourceDraft?.weekendMultiplier ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n weekendMultiplier:\n Number(event.target.value) || undefined,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'decimal' } }}\n />\n </Stack>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Min nights\"\n value={resourceDraft?.minNights ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n minNights:\n Math.round(Number(event.target.value)) || undefined,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n <TextField\n label=\"Deposit %\"\n placeholder=\"100 = pay in full\"\n value={resourceDraft?.depositPct ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n depositPct:\n Math.round(Number(event.target.value)) || undefined,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n <TextField\n label=\"Free cancel (hrs)\"\n value={resourceDraft?.cancellationHours ?? ''}\n onChange={(event) =>\n setResourceDraft((prev) =>\n prev\n ? {\n ...prev,\n cancellationHours:\n Math.round(Number(event.target.value)) || undefined,\n }\n : prev,\n )\n }\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setResourceDraft(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={\n !resourceDraft?.name?.trim() ||\n !((resourceDraft?.nightlyRateUsd ?? 0) > 0) ||\n Boolean(unitsProblem(resourceDraft?.units)) ||\n Boolean(fewLeftAtProblem(resourceDraft?.fewLeftAt))\n }\n onClick={handleResourceSave}\n >\n {'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n\n <Dialog\n open={Boolean(walkIn)}\n onClose={() => setWalkIn(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>{'Walk-in reservation'}</DialogTitle>\n <DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <TextField\n label=\"Resource\"\n value={walkIn?.resourceId ?? ''}\n onChange={(event) =>\n setWalkIn((prev) =>\n prev ? { ...prev, resourceId: event.target.value } : prev,\n )\n }\n size=\"small\"\n select\n sx={{ mt: 1 }}\n >\n {(resourceDocs ?? []).map((resource: any) => (\n <MenuItem key={resource.$id} value={resource.$id}>\n {resource.name}\n </MenuItem>\n ))}\n </TextField>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n label=\"Check-in\"\n type=\"date\"\n value={walkIn?.checkIn ?? ''}\n onChange={(event) =>\n setWalkIn((prev) =>\n prev ? { ...prev, checkIn: event.target.value } : prev,\n )\n }\n size=\"small\"\n fullWidth\n slotProps={{ inputLabel: { shrink: true } }}\n />\n <TextField\n label=\"Check-out\"\n type=\"date\"\n value={walkIn?.checkOut ?? ''}\n onChange={(event) =>\n setWalkIn((prev) =>\n prev ? { ...prev, checkOut: event.target.value } : prev,\n )\n }\n size=\"small\"\n fullWidth\n slotProps={{ inputLabel: { shrink: true } }}\n />\n </Stack>\n <TextField\n label=\"Guest name\"\n value={walkIn?.guestName ?? ''}\n onChange={(event) =>\n setWalkIn((prev) =>\n prev ? { ...prev, guestName: event.target.value } : prev,\n )\n }\n size=\"small\"\n />\n <TextField\n label=\"Guests\"\n value={walkIn?.guests ?? ''}\n onChange={(event) =>\n setWalkIn((prev) =>\n prev ? { ...prev, guests: event.target.value.replace(/\\D/g, '') } : prev,\n )\n }\n helperText={`Optional, up to ${CommerceModel.resourceGuestCeiling(\n (resourceDocs ?? []).find((item: any) => item.$id === walkIn?.resourceId),\n )}. Each guest gets a check-in when the stay is checked in per guest.`}\n size=\"small\"\n slotProps={{ htmlInput: { inputMode: 'numeric' } }}\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setWalkIn(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={\n walkInBusy ||\n !walkIn?.resourceId ||\n !walkIn?.checkIn ||\n !walkIn?.checkOut\n }\n onClick={handleWalkIn}\n >\n {'Reserve'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nReservationsCard.displayName = 'ReservationsCard'\n\nexport default ReservationsCard\n"],"names":["Aglyn","CommerceModel","reservationPermissionRefusal","CardDisplay","useConfirmationContext","ListPagination","useSnackbar","Button","Chip","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","TextField","Typography","collection","deleteDoc","doc","getDocs","limit","orderBy","query","setDoc","updateDoc","where","lazy","Suspense","useCallback","useMemo","useState","useFirestore","useMerchantPayments","useUser","authorizedFetch","PrerequisiteNotice","useFirestoreCollection","usePagedCollection","writeGuardedBySeed","pluginDocsHelp","ReservationGuestsDialog","GUESTS_OPEN_STATUSES","STATUS_COLOR","pending","confirmed","checked_in","checked_out","cancelled","no_show","usd","cents","toFixed","day","dayMs","Date","toISOString","slice","nightLabel","toLocaleDateString","weekday","month","timeZone","UNITS_LOOKAHEAD_NIGHTS","localTodayDayMs","now","UTC","getFullYear","getMonth","getDate","unitsProblem","units","undefined","Number","isInteger","MAX_RESOURCE_UNITS","fewLeftAtProblem","fewLeftAt","ReservationsCard","props","payments","resourceDraft","hostId","canManage","canWalkIn","missing","firestore","data","user","enqueueSnackbar","confirm","resourceDocs","status","resourcesStatus","fromCache","resourcesFromCache","idField","rows","reservations","hasMore","page","setPage","pageSize","setPageSize","pageLimit","hasSeveralUnits","some","resource","resourceUnits","todayDayMs","currentStays","unitsAhead","byResource","nowMs","stays","filter","stay","resourceId","$id","map","checkInDayMs","checkOutDayMs","createdAtMs","unitsLeftByNight","resourceNames","name","setResourceDraft","walkIn","setWalkIn","walkInBusy","setWalkInBusy","guestsFor","setGuestsFor","handleResourceSave","trim","nightlyRateUsd","seeded","id","_syntheticId","fields","resourceFewLeftAt","verdict","subject","unreadable","Boolean","createResourceUid","merge","ok","message","variant","persist","handleStatus","reservation","handleWalkIn","checkIn","checkOut","find","item","parse","guests","guestsProblem","reservationGuestsProblem","quote","computeReservationQuote","problem","overlapping","catch","existing","docs","snapshot","isRangeAvailable","response","method","headers","body","JSON","stringify","guestName","reservationId","attemptId","answer","json","error","header","help","anchor","contentGutterX","contentGutterY","spacing","blocked","severity","href","actionLabel","reason","direction","sx","alignItems","flex","minWidth","noWrap","join","color","size","disabled","onClick","title","description","confirmationText","confirmationButtonProps","then","useFlexGap","aria-label","flexWrap","gap","night","unitsLeft","label","depositPct","minNights","length","mt","guestEmail","reservationGuests","paidCents","totalCents","String","replace","folio","folioCents","reduce","sum","entry","amountCents","balanceCents","includes","rowCount","onPageChange","onPageSizeChange","fallback","onClose","onDone","unchanged","open","maxWidth","fullWidth","display","flexDirection","value","onChange","event","prev","target","autoFocus","placeholder","helperText","slotProps","htmlInput","inputMode","capacity","Math","round","FEW_UNITS_LEFT","select","checkInPerGuest","weekendMultiplier","cancellationHours","type","inputLabel","shrink","resourceGuestCeiling","displayName"],"mappings":"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"}
@@ -210,7 +210,7 @@ const EMPTY_KEYS = {
210
210
  !connected ? /*#__PURE__*/ _jsx(Typography, {
211
211
  variant: "body2",
212
212
  color: "text.secondary",
213
- children: 'Labeling in ShippingEasy? Connect it with the API key, API secret and store API key from your ' + 'ShippingEasy account: each order is sent there as it is paid, and each label you buy there ' + 'marks the order shipped here and emails your customer the tracking link. Only a site admin ' + 'can connect it.'
213
+ children: 'Labeling in ShippingEasy? Connect it with the API key, API secret and store API key from your ' + 'ShippingEasy account: each order is sent there as it is paid, and each label you buy there ' + 'marks the order shipped here and emails your customer the tracking link. Connecting it takes ' + 'the "Connect shipping apps" permission.'
214
214
  }) : /*#__PURE__*/ _jsxs(_Fragment, {
215
215
  children: [
216
216
  /*#__PURE__*/ _jsx("div", {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/shippingeasy-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { PLATFORM_BRAND_NAME } from '@aglyn/aglyn/app-utils/platform-brand'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { CopyField } from '@aglyn/shared-ui-jsx/components/copy-field.component'\nimport ScrollTable from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { StatusChip } from '@aglyn/shared-ui-jsx/components/status-chip.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Stack,\n TableBody,\n TableCell,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useState } from 'react'\n\nexport interface ShippingEasyCardProps {\n hostId: string\n}\n\n/** What the connectors route answers about a ShippingEasy connection. */\ninterface ConnectionStatus {\n /** Whether this deployment can keep an API secret at all. */\n available?: boolean\n connected: boolean\n apiKeyEnding?: string\n storeApiKeyEnding?: string\n createdAtMs?: number\n updatedAtMs?: number\n lastPushAtMs?: number\n lastCallbackAtMs?: number\n lastError?: { message: string; atMs: number; orderNumber?: string } | null\n sync?: { sent: number; already: number; failed: number; more: boolean }\n}\n\n/** The address ShippingEasy posts shipments to: this console's own origin, never a guess. */\nexport function shippingEasyCallbackUrl(hostId: string, origin?: string): string {\n const base = origin ?? (typeof window === 'undefined' ? '' : window.location.origin)\n return `${base}/api/commerce/shippingeasy/${encodeURIComponent(hostId)}`\n}\n\n/** What one \"Send open orders\" did, in a sentence. */\nexport function describeShippingEasySync(sync: NonNullable<ConnectionStatus['sync']>): string {\n const parts: string[] = []\n parts.push(sync.sent === 1 ? '1 order sent to ShippingEasy' : `${sync.sent} orders sent to ShippingEasy`)\n if (sync.already) parts.push(`${sync.already} already there`)\n if (sync.failed) parts.push(`${sync.failed} not sent`)\n return `${parts.join(', ')}.${sync.more ? ' More open orders are waiting: select Send open orders again.' : ''}`\n}\n\nconst when = (ms: number | undefined): string =>\n ms ? new Date(ms).toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' }) : 'Not yet'\n\n/** One fixed fact of the connection: a label and its value. */\nfunction FactRow(props: { label: string; value: string }) {\n return (\n <TableRow>\n <TableCell component=\"th\" scope=\"row\">\n {props.label}\n </TableCell>\n <TableCell>{props.value}</TableCell>\n </TableRow>\n )\n}\n\nconst EMPTY_KEYS = { apiKey: '', apiSecret: '', storeApiKey: '' }\n\n/**\n * Connect ShippingEasy (AGL-3633): the merchant's API key, API secret and\n * store API key, from their own ShippingEasy account; the callback URL to\n * paste into the API store; send open orders; and disconnect. Paid orders go\n * to ShippingEasy as they are paid, and each label bought there marks the\n * order shipped here. The secret is sealed on the server and never shown\n * again; the card renders nothing on a deployment that cannot seal one.\n */\nexport function ShippingEasyCard(props: ShippingEasyCardProps) {\n const { hostId } = props\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const [status, setStatus] = useState<ConnectionStatus | null>(null)\n const [loadError, setLoadError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [editing, setEditing] = useState(false)\n const [keys, setKeys] = useState(EMPTY_KEYS)\n const [confirmDisconnect, setConfirmDisconnect] = useState(false)\n\n const uid = user?.uid\n useEffect(() => {\n if (!uid || !user) return\n let live = true\n authorizedFetch(\n user as never,\n `/api/commerce/shipping-connectors?connector=shippingeasy&hostId=${encodeURIComponent(hostId)}`,\n )\n .then(async (response) => {\n const body = await response.json().catch(() => ({}))\n if (!live) return\n if (!response.ok) return setLoadError(body?.error ?? 'The connection could not be read.')\n setLoadError(null)\n setStatus(body as ConnectionStatus)\n })\n .catch(() => live && setLoadError('The connection could not be read.'))\n return () => {\n live = false\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- `user` changes identity every render; `uid` is what matters.\n }, [uid, hostId])\n\n const act = useCallback(\n async (action: 'connect' | 'sync' | 'disconnect', extra: Record<string, string> = {}): Promise<boolean> => {\n setBusy(true)\n try {\n const response = await authorizedFetch(user as never, '/api/commerce/shipping-connectors', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, connector: 'shippingeasy', action, ...extra }),\n })\n const body = (await response.json().catch(() => ({}))) as ConnectionStatus & { error?: string }\n if (!response.ok) {\n enqueueSnackbar(body?.error ?? 'That did not work. Try again.', { variant: 'error', allowDuplicate: true })\n return false\n }\n setStatus(body)\n if (action === 'disconnect') {\n enqueueSnackbar('ShippingEasy is disconnected. New orders are no longer sent to it.', { variant: 'success' })\n } else if (action === 'sync' && body.sync) {\n enqueueSnackbar(describeShippingEasySync(body.sync), { variant: body.sync.failed ? 'warning' : 'success' })\n } else if (action === 'connect') {\n enqueueSnackbar('ShippingEasy is connected. Paste the callback URL into your ShippingEasy API store.', {\n variant: 'success',\n })\n }\n return true\n } finally {\n setBusy(false)\n }\n },\n [user, hostId, enqueueSnackbar],\n )\n\n // A deployment with no secret keyring cannot keep a secret: nothing to offer.\n if (status && status.available === false && !status.connected) return null\n\n const connected = Boolean(status?.connected)\n const openKeys = () => {\n setKeys(EMPTY_KEYS)\n setEditing(true)\n }\n const actions = !status ? null : connected ? (\n <Stack direction=\"row\" spacing={1}>\n <Button size=\"small\" disabled={busy} onClick={() => void act('sync')}>\n {'Send open orders'}\n </Button>\n <Button size=\"small\" disabled={busy} onClick={openKeys}>\n {'Change keys'}\n </Button>\n <Button size=\"small\" color=\"error\" disabled={busy} onClick={() => setConfirmDisconnect(true)}>\n {'Disconnect'}\n </Button>\n </Stack>\n ) : (\n <Button size=\"small\" variant=\"contained\" disabled={busy} onClick={openKeys}>\n {'Connect ShippingEasy'}\n </Button>\n )\n\n const complete = Boolean(keys.apiKey.trim() && keys.apiSecret.trim() && keys.storeApiKey.trim())\n const save = async () => {\n if (await act('connect', keys)) {\n setEditing(false)\n setKeys(EMPTY_KEYS)\n }\n }\n\n return (\n <CardDisplay\n header={'ShippingEasy'}\n help={pluginDocsHelp('shippingEasy', { anchor: '#connect' })}\n HeaderProps={{ action: actions }}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n {loadError ? <Alert severity=\"error\">{loadError}</Alert> : null}\n {!connected ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {\n 'Labeling in ShippingEasy? Connect it with the API key, API secret and store API key from your ' +\n 'ShippingEasy account: each order is sent there as it is paid, and each label you buy there ' +\n 'marks the order shipped here and emails your customer the tracking link. Only a site admin ' +\n 'can connect it.'\n }\n </Typography>\n ) : (\n <>\n <div>\n {status?.lastError ? (\n <StatusChip label=\"Needs attention\" tone=\"warning\" data-testid=\"shippingeasy-status\" />\n ) : (\n <StatusChip label=\"Connected\" tone=\"success\" data-testid=\"shippingeasy-status\" />\n )}\n </div>\n {status?.lastError ? (\n <Alert severity=\"warning\">\n {`${status.lastError.message} (${when(status.lastError.atMs)})`}\n </Alert>\n ) : null}\n <CopyField\n label=\"Callback URL\"\n value={shippingEasyCallbackUrl(hostId)}\n helperText=\"Paste this into your API store's settings in ShippingEasy, so each label marks the order shipped here.\"\n onCopied={() => enqueueSnackbar('Callback URL copied', { variant: 'success', persist: false })}\n onCopyFailed={() => enqueueSnackbar('Select the callback URL and copy it.', { variant: 'info' })}\n />\n <ScrollTable size=\"small\" aria-label=\"ShippingEasy connection\">\n <TableBody>\n <FactRow label=\"API key\" value={status?.apiKeyEnding ? `Ends in ${status.apiKeyEnding}` : ''} />\n <FactRow label=\"Store API key\" value={status?.storeApiKeyEnding ? `Ends in ${status.storeApiKeyEnding}` : ''} />\n <FactRow label=\"Last order sent\" value={when(status?.lastPushAtMs)} />\n <FactRow label=\"Last shipment received\" value={when(status?.lastCallbackAtMs)} />\n </TableBody>\n </ScrollTable>\n </>\n )}\n </Stack>\n <Dialog open={editing} onClose={() => !busy && setEditing(false)} fullWidth maxWidth=\"sm\">\n <DialogTitle>{connected ? 'Change ShippingEasy keys' : 'Connect ShippingEasy'}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <DialogContentText>\n {\n 'In ShippingEasy, the API key and API secret are under Settings → API Credentials, and the ' +\n 'store API key is on your API store under Settings → Stores & Orders. The secret is kept ' +\n 'encrypted and is never shown again.'\n }\n </DialogContentText>\n <TextField\n label=\"API key\"\n value={keys.apiKey}\n onChange={(event) => setKeys((current) => ({ ...current, apiKey: event.target.value }))}\n autoComplete=\"off\"\n fullWidth\n required\n />\n <TextField\n label=\"API secret\"\n type=\"password\"\n value={keys.apiSecret}\n onChange={(event) => setKeys((current) => ({ ...current, apiSecret: event.target.value }))}\n autoComplete=\"new-password\"\n fullWidth\n required\n />\n <TextField\n label=\"Store API key\"\n value={keys.storeApiKey}\n onChange={(event) => setKeys((current) => ({ ...current, storeApiKey: event.target.value }))}\n autoComplete=\"off\"\n fullWidth\n required\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button disabled={busy} onClick={() => setEditing(false)}>\n {'Cancel'}\n </Button>\n <Button variant=\"contained\" disabled={busy || !complete} onClick={() => void save()}>\n {connected ? 'Save keys' : 'Connect'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog open={confirmDisconnect} onClose={() => setConfirmDisconnect(false)}>\n <DialogTitle>{'Disconnect ShippingEasy?'}</DialogTitle>\n <DialogContent>\n <DialogContentText>\n {\n 'New orders stop going to ShippingEasy, and shipments it sends back are refused. Orders ' +\n 'already there stay there, and orders already shipped stay shipped. The keys are deleted ' +\n `from ${PLATFORM_BRAND_NAME}.`\n }\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setConfirmDisconnect(false)}>{'Cancel'}</Button>\n <Button\n color=\"error\"\n disabled={busy}\n onClick={() => {\n setConfirmDisconnect(false)\n void act('disconnect')\n }}\n >\n {'Disconnect'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nShippingEasyCard.displayName = 'ShippingEasyCard'\n\nexport default ShippingEasyCard\n"],"names":["pluginDocsHelp","PLATFORM_BRAND_NAME","CardDisplay","CopyField","ScrollTable","StatusChip","useSnackbar","authorizedFetch","useUser","Alert","Button","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","Stack","TableBody","TableCell","TableRow","TextField","Typography","useCallback","useEffect","useState","shippingEasyCallbackUrl","hostId","origin","base","window","location","encodeURIComponent","describeShippingEasySync","sync","parts","push","sent","already","failed","join","more","when","ms","Date","toLocaleString","undefined","dateStyle","timeStyle","FactRow","props","component","scope","label","value","EMPTY_KEYS","apiKey","apiSecret","storeApiKey","ShippingEasyCard","data","user","enqueueSnackbar","status","setStatus","loadError","setLoadError","busy","setBusy","editing","setEditing","keys","setKeys","confirmDisconnect","setConfirmDisconnect","uid","live","then","response","body","json","catch","ok","error","act","action","extra","method","headers","JSON","stringify","connector","variant","allowDuplicate","available","connected","Boolean","openKeys","actions","direction","spacing","size","disabled","onClick","color","complete","trim","save","header","help","anchor","HeaderProps","contentGutterX","contentGutterY","severity","div","lastError","tone","data-testid","message","atMs","helperText","onCopied","persist","onCopyFailed","aria-label","apiKeyEnding","storeApiKeyEnding","lastPushAtMs","lastCallbackAtMs","open","onClose","fullWidth","maxWidth","sx","pt","onChange","event","current","target","autoComplete","required","type","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/shippingeasy-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { PLATFORM_BRAND_NAME } from '@aglyn/aglyn/app-utils/platform-brand'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { CopyField } from '@aglyn/shared-ui-jsx/components/copy-field.component'\nimport ScrollTable from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { StatusChip } from '@aglyn/shared-ui-jsx/components/status-chip.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Stack,\n TableBody,\n TableCell,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useState } from 'react'\n\nexport interface ShippingEasyCardProps {\n hostId: string\n}\n\n/** What the connectors route answers about a ShippingEasy connection. */\ninterface ConnectionStatus {\n /** Whether this deployment can keep an API secret at all. */\n available?: boolean\n connected: boolean\n apiKeyEnding?: string\n storeApiKeyEnding?: string\n createdAtMs?: number\n updatedAtMs?: number\n lastPushAtMs?: number\n lastCallbackAtMs?: number\n lastError?: { message: string; atMs: number; orderNumber?: string } | null\n sync?: { sent: number; already: number; failed: number; more: boolean }\n}\n\n/** The address ShippingEasy posts shipments to: this console's own origin, never a guess. */\nexport function shippingEasyCallbackUrl(hostId: string, origin?: string): string {\n const base = origin ?? (typeof window === 'undefined' ? '' : window.location.origin)\n return `${base}/api/commerce/shippingeasy/${encodeURIComponent(hostId)}`\n}\n\n/** What one \"Send open orders\" did, in a sentence. */\nexport function describeShippingEasySync(sync: NonNullable<ConnectionStatus['sync']>): string {\n const parts: string[] = []\n parts.push(sync.sent === 1 ? '1 order sent to ShippingEasy' : `${sync.sent} orders sent to ShippingEasy`)\n if (sync.already) parts.push(`${sync.already} already there`)\n if (sync.failed) parts.push(`${sync.failed} not sent`)\n return `${parts.join(', ')}.${sync.more ? ' More open orders are waiting: select Send open orders again.' : ''}`\n}\n\nconst when = (ms: number | undefined): string =>\n ms ? new Date(ms).toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' }) : 'Not yet'\n\n/** One fixed fact of the connection: a label and its value. */\nfunction FactRow(props: { label: string; value: string }) {\n return (\n <TableRow>\n <TableCell component=\"th\" scope=\"row\">\n {props.label}\n </TableCell>\n <TableCell>{props.value}</TableCell>\n </TableRow>\n )\n}\n\nconst EMPTY_KEYS = { apiKey: '', apiSecret: '', storeApiKey: '' }\n\n/**\n * Connect ShippingEasy (AGL-3633): the merchant's API key, API secret and\n * store API key, from their own ShippingEasy account; the callback URL to\n * paste into the API store; send open orders; and disconnect. Paid orders go\n * to ShippingEasy as they are paid, and each label bought there marks the\n * order shipped here. The secret is sealed on the server and never shown\n * again; the card renders nothing on a deployment that cannot seal one.\n */\nexport function ShippingEasyCard(props: ShippingEasyCardProps) {\n const { hostId } = props\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const [status, setStatus] = useState<ConnectionStatus | null>(null)\n const [loadError, setLoadError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [editing, setEditing] = useState(false)\n const [keys, setKeys] = useState(EMPTY_KEYS)\n const [confirmDisconnect, setConfirmDisconnect] = useState(false)\n\n const uid = user?.uid\n useEffect(() => {\n if (!uid || !user) return\n let live = true\n authorizedFetch(\n user as never,\n `/api/commerce/shipping-connectors?connector=shippingeasy&hostId=${encodeURIComponent(hostId)}`,\n )\n .then(async (response) => {\n const body = await response.json().catch(() => ({}))\n if (!live) return\n if (!response.ok) return setLoadError(body?.error ?? 'The connection could not be read.')\n setLoadError(null)\n setStatus(body as ConnectionStatus)\n })\n .catch(() => live && setLoadError('The connection could not be read.'))\n return () => {\n live = false\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- `user` changes identity every render; `uid` is what matters.\n }, [uid, hostId])\n\n const act = useCallback(\n async (action: 'connect' | 'sync' | 'disconnect', extra: Record<string, string> = {}): Promise<boolean> => {\n setBusy(true)\n try {\n const response = await authorizedFetch(user as never, '/api/commerce/shipping-connectors', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, connector: 'shippingeasy', action, ...extra }),\n })\n const body = (await response.json().catch(() => ({}))) as ConnectionStatus & { error?: string }\n if (!response.ok) {\n enqueueSnackbar(body?.error ?? 'That did not work. Try again.', { variant: 'error', allowDuplicate: true })\n return false\n }\n setStatus(body)\n if (action === 'disconnect') {\n enqueueSnackbar('ShippingEasy is disconnected. New orders are no longer sent to it.', { variant: 'success' })\n } else if (action === 'sync' && body.sync) {\n enqueueSnackbar(describeShippingEasySync(body.sync), { variant: body.sync.failed ? 'warning' : 'success' })\n } else if (action === 'connect') {\n enqueueSnackbar('ShippingEasy is connected. Paste the callback URL into your ShippingEasy API store.', {\n variant: 'success',\n })\n }\n return true\n } finally {\n setBusy(false)\n }\n },\n [user, hostId, enqueueSnackbar],\n )\n\n // A deployment with no secret keyring cannot keep a secret: nothing to offer.\n if (status && status.available === false && !status.connected) return null\n\n const connected = Boolean(status?.connected)\n const openKeys = () => {\n setKeys(EMPTY_KEYS)\n setEditing(true)\n }\n const actions = !status ? null : connected ? (\n <Stack direction=\"row\" spacing={1}>\n <Button size=\"small\" disabled={busy} onClick={() => void act('sync')}>\n {'Send open orders'}\n </Button>\n <Button size=\"small\" disabled={busy} onClick={openKeys}>\n {'Change keys'}\n </Button>\n <Button size=\"small\" color=\"error\" disabled={busy} onClick={() => setConfirmDisconnect(true)}>\n {'Disconnect'}\n </Button>\n </Stack>\n ) : (\n <Button size=\"small\" variant=\"contained\" disabled={busy} onClick={openKeys}>\n {'Connect ShippingEasy'}\n </Button>\n )\n\n const complete = Boolean(keys.apiKey.trim() && keys.apiSecret.trim() && keys.storeApiKey.trim())\n const save = async () => {\n if (await act('connect', keys)) {\n setEditing(false)\n setKeys(EMPTY_KEYS)\n }\n }\n\n return (\n <CardDisplay\n header={'ShippingEasy'}\n help={pluginDocsHelp('shippingEasy', { anchor: '#connect' })}\n HeaderProps={{ action: actions }}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n {loadError ? <Alert severity=\"error\">{loadError}</Alert> : null}\n {!connected ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {\n 'Labeling in ShippingEasy? Connect it with the API key, API secret and store API key from your ' +\n 'ShippingEasy account: each order is sent there as it is paid, and each label you buy there ' +\n 'marks the order shipped here and emails your customer the tracking link. Connecting it takes ' +\n 'the \"Connect shipping apps\" permission.'\n }\n </Typography>\n ) : (\n <>\n <div>\n {status?.lastError ? (\n <StatusChip label=\"Needs attention\" tone=\"warning\" data-testid=\"shippingeasy-status\" />\n ) : (\n <StatusChip label=\"Connected\" tone=\"success\" data-testid=\"shippingeasy-status\" />\n )}\n </div>\n {status?.lastError ? (\n <Alert severity=\"warning\">\n {`${status.lastError.message} (${when(status.lastError.atMs)})`}\n </Alert>\n ) : null}\n <CopyField\n label=\"Callback URL\"\n value={shippingEasyCallbackUrl(hostId)}\n helperText=\"Paste this into your API store's settings in ShippingEasy, so each label marks the order shipped here.\"\n onCopied={() => enqueueSnackbar('Callback URL copied', { variant: 'success', persist: false })}\n onCopyFailed={() => enqueueSnackbar('Select the callback URL and copy it.', { variant: 'info' })}\n />\n <ScrollTable size=\"small\" aria-label=\"ShippingEasy connection\">\n <TableBody>\n <FactRow label=\"API key\" value={status?.apiKeyEnding ? `Ends in ${status.apiKeyEnding}` : ''} />\n <FactRow label=\"Store API key\" value={status?.storeApiKeyEnding ? `Ends in ${status.storeApiKeyEnding}` : ''} />\n <FactRow label=\"Last order sent\" value={when(status?.lastPushAtMs)} />\n <FactRow label=\"Last shipment received\" value={when(status?.lastCallbackAtMs)} />\n </TableBody>\n </ScrollTable>\n </>\n )}\n </Stack>\n <Dialog open={editing} onClose={() => !busy && setEditing(false)} fullWidth maxWidth=\"sm\">\n <DialogTitle>{connected ? 'Change ShippingEasy keys' : 'Connect ShippingEasy'}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <DialogContentText>\n {\n 'In ShippingEasy, the API key and API secret are under Settings → API Credentials, and the ' +\n 'store API key is on your API store under Settings → Stores & Orders. The secret is kept ' +\n 'encrypted and is never shown again.'\n }\n </DialogContentText>\n <TextField\n label=\"API key\"\n value={keys.apiKey}\n onChange={(event) => setKeys((current) => ({ ...current, apiKey: event.target.value }))}\n autoComplete=\"off\"\n fullWidth\n required\n />\n <TextField\n label=\"API secret\"\n type=\"password\"\n value={keys.apiSecret}\n onChange={(event) => setKeys((current) => ({ ...current, apiSecret: event.target.value }))}\n autoComplete=\"new-password\"\n fullWidth\n required\n />\n <TextField\n label=\"Store API key\"\n value={keys.storeApiKey}\n onChange={(event) => setKeys((current) => ({ ...current, storeApiKey: event.target.value }))}\n autoComplete=\"off\"\n fullWidth\n required\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button disabled={busy} onClick={() => setEditing(false)}>\n {'Cancel'}\n </Button>\n <Button variant=\"contained\" disabled={busy || !complete} onClick={() => void save()}>\n {connected ? 'Save keys' : 'Connect'}\n </Button>\n </DialogActions>\n </Dialog>\n <Dialog open={confirmDisconnect} onClose={() => setConfirmDisconnect(false)}>\n <DialogTitle>{'Disconnect ShippingEasy?'}</DialogTitle>\n <DialogContent>\n <DialogContentText>\n {\n 'New orders stop going to ShippingEasy, and shipments it sends back are refused. Orders ' +\n 'already there stay there, and orders already shipped stay shipped. The keys are deleted ' +\n `from ${PLATFORM_BRAND_NAME}.`\n }\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setConfirmDisconnect(false)}>{'Cancel'}</Button>\n <Button\n color=\"error\"\n disabled={busy}\n onClick={() => {\n setConfirmDisconnect(false)\n void act('disconnect')\n }}\n >\n {'Disconnect'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nShippingEasyCard.displayName = 'ShippingEasyCard'\n\nexport default ShippingEasyCard\n"],"names":["pluginDocsHelp","PLATFORM_BRAND_NAME","CardDisplay","CopyField","ScrollTable","StatusChip","useSnackbar","authorizedFetch","useUser","Alert","Button","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","Stack","TableBody","TableCell","TableRow","TextField","Typography","useCallback","useEffect","useState","shippingEasyCallbackUrl","hostId","origin","base","window","location","encodeURIComponent","describeShippingEasySync","sync","parts","push","sent","already","failed","join","more","when","ms","Date","toLocaleString","undefined","dateStyle","timeStyle","FactRow","props","component","scope","label","value","EMPTY_KEYS","apiKey","apiSecret","storeApiKey","ShippingEasyCard","data","user","enqueueSnackbar","status","setStatus","loadError","setLoadError","busy","setBusy","editing","setEditing","keys","setKeys","confirmDisconnect","setConfirmDisconnect","uid","live","then","response","body","json","catch","ok","error","act","action","extra","method","headers","JSON","stringify","connector","variant","allowDuplicate","available","connected","Boolean","openKeys","actions","direction","spacing","size","disabled","onClick","color","complete","trim","save","header","help","anchor","HeaderProps","contentGutterX","contentGutterY","severity","div","lastError","tone","data-testid","message","atMs","helperText","onCopied","persist","onCopyFailed","aria-label","apiKeyEnding","storeApiKeyEnding","lastPushAtMs","lastCallbackAtMs","open","onClose","fullWidth","maxWidth","sx","pt","onChange","event","current","target","autoComplete","required","type","displayName"],"mappings":"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"}
@@ -25,7 +25,7 @@ export declare const SHIPSTATION_STATUS_ROWS: ReadonlyArray<readonly [string, st
25
25
  * Connect ShipStation (AGL-3613): the URL, username and password a merchant
26
26
  * pastes into ShipStation's Custom Store, the status names to map, a new
27
27
  * password and a disconnect. The password is kept sealed on the server and
28
- * a site admin can show it again; the card renders nothing on a deployment
28
+ * whoever holds "Connect shipping apps" can show it again; the card renders nothing on a deployment
29
29
  * that cannot seal one.
30
30
  */
31
31
  export declare function ShipStationCard(props: ShipStationCardProps): import("react").JSX.Element;
@@ -58,7 +58,7 @@ const when = (ms)=>ms ? new Date(ms).toLocaleString(undefined, {
58
58
  * Connect ShipStation (AGL-3613): the URL, username and password a merchant
59
59
  * pastes into ShipStation's Custom Store, the status names to map, a new
60
60
  * password and a disconnect. The password is kept sealed on the server and
61
- * a site admin can show it again; the card renders nothing on a deployment
61
+ * whoever holds "Connect shipping apps" can show it again; the card renders nothing on a deployment
62
62
  * that cannot seal one.
63
63
  */ export function ShipStationCard(props) {
64
64
  var _ref;
@@ -205,7 +205,7 @@ const when = (ms)=>ms ? new Date(ms).toLocaleString(undefined, {
205
205
  !connected ? /*#__PURE__*/ _jsx(Typography, {
206
206
  variant: "body2",
207
207
  color: "text.secondary",
208
- children: 'Already labeling in ShipStation? Connect it as a Custom Store: ShipStation imports the ' + 'orders you still have to ship, and each label you buy there marks the order shipped ' + 'here and emails your customer the tracking link. Only a site admin can connect it.'
208
+ children: 'Already labeling in ShipStation? Connect it as a Custom Store: ShipStation imports the ' + 'orders you still have to ship, and each label you buy there marks the order shipped ' + 'here and emails your customer the tracking link. Connecting it takes the "Connect shipping ' + 'apps" permission.'
209
209
  }) : /*#__PURE__*/ _jsxs(_Fragment, {
210
210
  children: [
211
211
  password ? /*#__PURE__*/ _jsxs(Alert, {
@@ -256,7 +256,7 @@ const when = (ms)=>ms ? new Date(ms).toLocaleString(undefined, {
256
256
  children: /*#__PURE__*/ _jsx(Typography, {
257
257
  variant: "body2",
258
258
  color: "text.secondary",
259
- children: 'Hidden. Only a site admin can show it.'
259
+ children: 'Hidden. Showing it takes the "Connect shipping apps" permission.'
260
260
  })
261
261
  }),
262
262
  /*#__PURE__*/ _jsx(TableCell, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/shipstation-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n AlertTitle,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Stack,\n TableBody,\n TableCell,\n TableRow,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useState } from 'react'\nimport ScrollTable from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { SHIPSTATION_STATUS_NAMES } from '../../model/shipstation'\n\nexport interface ShipStationCardProps {\n hostId: string\n}\n\n/** What the connectors route answers about a connection. */\ninterface ConnectionStatus {\n /** Whether this deployment can keep a ShipStation password at all. */\n available?: boolean\n connected: boolean\n username?: string\n createdAtMs?: number\n rotatedAtMs?: number\n lastExportAtMs?: number\n lastShipNoticeAtMs?: number\n}\n\n/** The address ShipStation calls: this console's own origin, never a guess. */\nexport function shipStationEndpoint(hostId: string, origin?: string): string {\n const base = origin ?? (typeof window === 'undefined' ? '' : window.location.origin)\n return `${base}/api/commerce/shipstation/${encodeURIComponent(hostId)}`\n}\n\n/** The status names to type into ShipStation's Custom Store form, in its order. */\nexport const SHIPSTATION_STATUS_ROWS: ReadonlyArray<readonly [string, string]> = [\n ['Unpaid Status', SHIPSTATION_STATUS_NAMES.unpaid],\n ['Paid Status', SHIPSTATION_STATUS_NAMES.paid],\n ['Shipped Status', SHIPSTATION_STATUS_NAMES.shipped],\n ['Canceled Status', SHIPSTATION_STATUS_NAMES.canceled],\n ['On-Hold Status', SHIPSTATION_STATUS_NAMES.onHold],\n]\n\nconst when = (ms: number | undefined): string =>\n ms ? new Date(ms).toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' }) : 'Not yet'\n\n/**\n * Connect ShipStation (AGL-3613): the URL, username and password a merchant\n * pastes into ShipStation's Custom Store, the status names to map, a new\n * password and a disconnect. The password is kept sealed on the server and\n * a site admin can show it again; the card renders nothing on a deployment\n * that cannot seal one.\n */\nexport function ShipStationCard(props: ShipStationCardProps) {\n const { hostId } = props\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const [status, setStatus] = useState<ConnectionStatus | null>(null)\n const [loadError, setLoadError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [password, setPassword] = useState<string | null>(null)\n const [confirmDisconnect, setConfirmDisconnect] = useState(false)\n\n // Keyed on the account, not the user object: the object is new on every\n // render, and the status is the same until somebody else signs in.\n const uid = user?.uid\n useEffect(() => {\n if (!uid || !user) return\n let live = true\n authorizedFetch(user as never, `/api/commerce/shipping-connectors?hostId=${encodeURIComponent(hostId)}`)\n .then(async (response) => {\n const body = await response.json().catch(() => ({}))\n if (!live) return\n if (!response.ok) return setLoadError(body?.error ?? 'The connection could not be read.')\n setLoadError(null)\n setStatus(body as ConnectionStatus)\n })\n .catch(() => live && setLoadError('The connection could not be read.'))\n return () => {\n live = false\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- `user` changes identity every render; `uid` is what matters.\n }, [uid, hostId])\n\n const act = useCallback(\n async (action: 'connect' | 'rotate' | 'reveal' | 'disconnect') => {\n setBusy(true)\n try {\n const response = await authorizedFetch(user as never, '/api/commerce/shipping-connectors', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, action }),\n })\n const body = await response.json().catch(() => ({}))\n if (!response.ok) {\n enqueueSnackbar(body?.error ?? 'That did not work. Try again.', { variant: 'error', allowDuplicate: true })\n return\n }\n setStatus(body as ConnectionStatus)\n setPassword(typeof body?.password === 'string' ? body.password : null)\n if (action === 'disconnect') {\n enqueueSnackbar('ShipStation is disconnected. It can no longer read your orders.', { variant: 'success' })\n }\n } finally {\n setBusy(false)\n }\n },\n [user, hostId, enqueueSnackbar],\n )\n\n const copy = (label: string, value: string) => {\n void navigator.clipboard\n ?.writeText(value)\n .then(() => enqueueSnackbar(`${label} copied`, { variant: 'success', persist: false }))\n .catch(() => enqueueSnackbar(`Select the ${label.toLowerCase()} and copy it.`, { variant: 'info' }))\n }\n\n // A deployment with no secret keyring cannot keep a password: nothing to offer.\n if (status && status.available === false && !status.connected) return null\n\n const connected = Boolean(status?.connected)\n const actions = !status ? null : connected ? (\n <Stack direction=\"row\" spacing={1}>\n <Button size=\"small\" disabled={busy} onClick={() => void act('rotate')}>\n {'New password'}\n </Button>\n <Button size=\"small\" color=\"error\" disabled={busy} onClick={() => setConfirmDisconnect(true)}>\n {'Disconnect'}\n </Button>\n </Stack>\n ) : (\n <Button size=\"small\" variant=\"contained\" disabled={busy} onClick={() => void act('connect')}>\n {'Connect ShipStation'}\n </Button>\n )\n\n const endpoint = shipStationEndpoint(hostId)\n const credentialRows: Array<[string, string, boolean]> = [\n ['URL to custom XML page', endpoint, true],\n ['Username', status?.username ?? '', true],\n ]\n if (password) credentialRows.push(['Password', password, true])\n\n return (\n <CardDisplay\n header={'ShipStation'}\n help={pluginDocsHelp('shipStation', { anchor: '#connect' })}\n HeaderProps={{ action: actions }}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n {loadError ? <Alert severity=\"error\">{loadError}</Alert> : null}\n {!connected ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {\n 'Already labeling in ShipStation? Connect it as a Custom Store: ShipStation imports the ' +\n 'orders you still have to ship, and each label you buy there marks the order shipped ' +\n 'here and emails your customer the tracking link. Only a site admin can connect it.'\n }\n </Typography>\n ) : (\n <>\n {password ? (\n <Alert severity=\"info\">\n <AlertTitle>{'Paste these into ShipStation'}</AlertTitle>\n {\n 'Anyone with this password can read the name and address on every order you ship. ' +\n 'If it gets out, make a new password: the old one stops working at once.'\n }\n </Alert>\n ) : null}\n <ScrollTable size=\"small\" aria-label=\"ShipStation connection\">\n <TableBody>\n {credentialRows.map(([label, value]) => (\n <TableRow key={label}>\n <TableCell component=\"th\" scope=\"row\">\n {label}\n </TableCell>\n <TableCell sx={{ wordBreak: 'break-all' }}>{value}</TableCell>\n <TableCell align=\"right\">\n <Button size=\"small\" onClick={() => copy(label, value)}>\n {'Copy'}\n </Button>\n </TableCell>\n </TableRow>\n ))}\n {!password ? (\n <TableRow>\n <TableCell component=\"th\" scope=\"row\">\n {'Password'}\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Hidden. Only a site admin can show it.'}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <Button size=\"small\" disabled={busy} onClick={() => void act('reveal')}>\n {'Show'}\n </Button>\n </TableCell>\n </TableRow>\n ) : null}\n </TableBody>\n </ScrollTable>\n <Typography variant=\"subtitle2\">{'Status names to type into ShipStation'}</Typography>\n <ScrollTable size=\"small\" aria-label=\"ShipStation status names\">\n <TableBody>\n {SHIPSTATION_STATUS_ROWS.map(([field, value]) => (\n <TableRow key={field}>\n <TableCell component=\"th\" scope=\"row\">\n {field}\n </TableCell>\n <TableCell>{value}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Last order import: ${when(status?.lastExportAtMs)}. Last shipment received: ${when(status?.lastShipNoticeAtMs)}.`}\n </Typography>\n </>\n )}\n </Stack>\n <Dialog open={confirmDisconnect} onClose={() => setConfirmDisconnect(false)}>\n <DialogTitle>{'Disconnect ShipStation?'}</DialogTitle>\n <DialogContent>\n <DialogContentText>\n {\n 'ShipStation stops importing orders from this site, and shipments it sends back are ' +\n 'refused. Orders already shipped stay shipped. You can connect again later with a new password.'\n }\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setConfirmDisconnect(false)}>{'Cancel'}</Button>\n <Button\n color=\"error\"\n disabled={busy}\n onClick={() => {\n setConfirmDisconnect(false)\n void act('disconnect')\n }}\n >\n {'Disconnect'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nShipStationCard.displayName = 'ShipStationCard'\n\nexport default ShipStationCard\n"],"names":["pluginDocsHelp","CardDisplay","useSnackbar","authorizedFetch","useUser","Alert","AlertTitle","Button","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","Stack","TableBody","TableCell","TableRow","Typography","useCallback","useEffect","useState","ScrollTable","SHIPSTATION_STATUS_NAMES","shipStationEndpoint","hostId","origin","base","window","location","encodeURIComponent","SHIPSTATION_STATUS_ROWS","unpaid","paid","shipped","canceled","onHold","when","ms","Date","toLocaleString","undefined","dateStyle","timeStyle","ShipStationCard","props","data","user","enqueueSnackbar","status","setStatus","loadError","setLoadError","busy","setBusy","password","setPassword","confirmDisconnect","setConfirmDisconnect","uid","live","then","response","body","json","catch","ok","error","act","action","method","headers","JSON","stringify","variant","allowDuplicate","copy","label","value","navigator","clipboard","writeText","persist","toLowerCase","available","connected","Boolean","actions","direction","spacing","size","disabled","onClick","color","endpoint","credentialRows","username","push","header","help","anchor","HeaderProps","contentGutterX","contentGutterY","severity","aria-label","map","component","scope","sx","wordBreak","align","field","lastExportAtMs","lastShipNoticeAtMs","open","onClose","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/shipstation-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n AlertTitle,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Stack,\n TableBody,\n TableCell,\n TableRow,\n Typography,\n} from '@mui/material'\nimport { useCallback, useEffect, useState } from 'react'\nimport ScrollTable from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { SHIPSTATION_STATUS_NAMES } from '../../model/shipstation'\n\nexport interface ShipStationCardProps {\n hostId: string\n}\n\n/** What the connectors route answers about a connection. */\ninterface ConnectionStatus {\n /** Whether this deployment can keep a ShipStation password at all. */\n available?: boolean\n connected: boolean\n username?: string\n createdAtMs?: number\n rotatedAtMs?: number\n lastExportAtMs?: number\n lastShipNoticeAtMs?: number\n}\n\n/** The address ShipStation calls: this console's own origin, never a guess. */\nexport function shipStationEndpoint(hostId: string, origin?: string): string {\n const base = origin ?? (typeof window === 'undefined' ? '' : window.location.origin)\n return `${base}/api/commerce/shipstation/${encodeURIComponent(hostId)}`\n}\n\n/** The status names to type into ShipStation's Custom Store form, in its order. */\nexport const SHIPSTATION_STATUS_ROWS: ReadonlyArray<readonly [string, string]> = [\n ['Unpaid Status', SHIPSTATION_STATUS_NAMES.unpaid],\n ['Paid Status', SHIPSTATION_STATUS_NAMES.paid],\n ['Shipped Status', SHIPSTATION_STATUS_NAMES.shipped],\n ['Canceled Status', SHIPSTATION_STATUS_NAMES.canceled],\n ['On-Hold Status', SHIPSTATION_STATUS_NAMES.onHold],\n]\n\nconst when = (ms: number | undefined): string =>\n ms ? new Date(ms).toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' }) : 'Not yet'\n\n/**\n * Connect ShipStation (AGL-3613): the URL, username and password a merchant\n * pastes into ShipStation's Custom Store, the status names to map, a new\n * password and a disconnect. The password is kept sealed on the server and\n * whoever holds \"Connect shipping apps\" can show it again; the card renders nothing on a deployment\n * that cannot seal one.\n */\nexport function ShipStationCard(props: ShipStationCardProps) {\n const { hostId } = props\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const [status, setStatus] = useState<ConnectionStatus | null>(null)\n const [loadError, setLoadError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [password, setPassword] = useState<string | null>(null)\n const [confirmDisconnect, setConfirmDisconnect] = useState(false)\n\n // Keyed on the account, not the user object: the object is new on every\n // render, and the status is the same until somebody else signs in.\n const uid = user?.uid\n useEffect(() => {\n if (!uid || !user) return\n let live = true\n authorizedFetch(user as never, `/api/commerce/shipping-connectors?hostId=${encodeURIComponent(hostId)}`)\n .then(async (response) => {\n const body = await response.json().catch(() => ({}))\n if (!live) return\n if (!response.ok) return setLoadError(body?.error ?? 'The connection could not be read.')\n setLoadError(null)\n setStatus(body as ConnectionStatus)\n })\n .catch(() => live && setLoadError('The connection could not be read.'))\n return () => {\n live = false\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- `user` changes identity every render; `uid` is what matters.\n }, [uid, hostId])\n\n const act = useCallback(\n async (action: 'connect' | 'rotate' | 'reveal' | 'disconnect') => {\n setBusy(true)\n try {\n const response = await authorizedFetch(user as never, '/api/commerce/shipping-connectors', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, action }),\n })\n const body = await response.json().catch(() => ({}))\n if (!response.ok) {\n enqueueSnackbar(body?.error ?? 'That did not work. Try again.', { variant: 'error', allowDuplicate: true })\n return\n }\n setStatus(body as ConnectionStatus)\n setPassword(typeof body?.password === 'string' ? body.password : null)\n if (action === 'disconnect') {\n enqueueSnackbar('ShipStation is disconnected. It can no longer read your orders.', { variant: 'success' })\n }\n } finally {\n setBusy(false)\n }\n },\n [user, hostId, enqueueSnackbar],\n )\n\n const copy = (label: string, value: string) => {\n void navigator.clipboard\n ?.writeText(value)\n .then(() => enqueueSnackbar(`${label} copied`, { variant: 'success', persist: false }))\n .catch(() => enqueueSnackbar(`Select the ${label.toLowerCase()} and copy it.`, { variant: 'info' }))\n }\n\n // A deployment with no secret keyring cannot keep a password: nothing to offer.\n if (status && status.available === false && !status.connected) return null\n\n const connected = Boolean(status?.connected)\n const actions = !status ? null : connected ? (\n <Stack direction=\"row\" spacing={1}>\n <Button size=\"small\" disabled={busy} onClick={() => void act('rotate')}>\n {'New password'}\n </Button>\n <Button size=\"small\" color=\"error\" disabled={busy} onClick={() => setConfirmDisconnect(true)}>\n {'Disconnect'}\n </Button>\n </Stack>\n ) : (\n <Button size=\"small\" variant=\"contained\" disabled={busy} onClick={() => void act('connect')}>\n {'Connect ShipStation'}\n </Button>\n )\n\n const endpoint = shipStationEndpoint(hostId)\n const credentialRows: Array<[string, string, boolean]> = [\n ['URL to custom XML page', endpoint, true],\n ['Username', status?.username ?? '', true],\n ]\n if (password) credentialRows.push(['Password', password, true])\n\n return (\n <CardDisplay\n header={'ShipStation'}\n help={pluginDocsHelp('shipStation', { anchor: '#connect' })}\n HeaderProps={{ action: actions }}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={2}>\n {loadError ? <Alert severity=\"error\">{loadError}</Alert> : null}\n {!connected ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {\n 'Already labeling in ShipStation? Connect it as a Custom Store: ShipStation imports the ' +\n 'orders you still have to ship, and each label you buy there marks the order shipped ' +\n 'here and emails your customer the tracking link. Connecting it takes the \"Connect shipping ' +\n 'apps\" permission.'\n }\n </Typography>\n ) : (\n <>\n {password ? (\n <Alert severity=\"info\">\n <AlertTitle>{'Paste these into ShipStation'}</AlertTitle>\n {\n 'Anyone with this password can read the name and address on every order you ship. ' +\n 'If it gets out, make a new password: the old one stops working at once.'\n }\n </Alert>\n ) : null}\n <ScrollTable size=\"small\" aria-label=\"ShipStation connection\">\n <TableBody>\n {credentialRows.map(([label, value]) => (\n <TableRow key={label}>\n <TableCell component=\"th\" scope=\"row\">\n {label}\n </TableCell>\n <TableCell sx={{ wordBreak: 'break-all' }}>{value}</TableCell>\n <TableCell align=\"right\">\n <Button size=\"small\" onClick={() => copy(label, value)}>\n {'Copy'}\n </Button>\n </TableCell>\n </TableRow>\n ))}\n {!password ? (\n <TableRow>\n <TableCell component=\"th\" scope=\"row\">\n {'Password'}\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Hidden. Showing it takes the \"Connect shipping apps\" permission.'}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <Button size=\"small\" disabled={busy} onClick={() => void act('reveal')}>\n {'Show'}\n </Button>\n </TableCell>\n </TableRow>\n ) : null}\n </TableBody>\n </ScrollTable>\n <Typography variant=\"subtitle2\">{'Status names to type into ShipStation'}</Typography>\n <ScrollTable size=\"small\" aria-label=\"ShipStation status names\">\n <TableBody>\n {SHIPSTATION_STATUS_ROWS.map(([field, value]) => (\n <TableRow key={field}>\n <TableCell component=\"th\" scope=\"row\">\n {field}\n </TableCell>\n <TableCell>{value}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Last order import: ${when(status?.lastExportAtMs)}. Last shipment received: ${when(status?.lastShipNoticeAtMs)}.`}\n </Typography>\n </>\n )}\n </Stack>\n <Dialog open={confirmDisconnect} onClose={() => setConfirmDisconnect(false)}>\n <DialogTitle>{'Disconnect ShipStation?'}</DialogTitle>\n <DialogContent>\n <DialogContentText>\n {\n 'ShipStation stops importing orders from this site, and shipments it sends back are ' +\n 'refused. Orders already shipped stay shipped. You can connect again later with a new password.'\n }\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setConfirmDisconnect(false)}>{'Cancel'}</Button>\n <Button\n color=\"error\"\n disabled={busy}\n onClick={() => {\n setConfirmDisconnect(false)\n void act('disconnect')\n }}\n >\n {'Disconnect'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nShipStationCard.displayName = 'ShipStationCard'\n\nexport default ShipStationCard\n"],"names":["pluginDocsHelp","CardDisplay","useSnackbar","authorizedFetch","useUser","Alert","AlertTitle","Button","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","Stack","TableBody","TableCell","TableRow","Typography","useCallback","useEffect","useState","ScrollTable","SHIPSTATION_STATUS_NAMES","shipStationEndpoint","hostId","origin","base","window","location","encodeURIComponent","SHIPSTATION_STATUS_ROWS","unpaid","paid","shipped","canceled","onHold","when","ms","Date","toLocaleString","undefined","dateStyle","timeStyle","ShipStationCard","props","data","user","enqueueSnackbar","status","setStatus","loadError","setLoadError","busy","setBusy","password","setPassword","confirmDisconnect","setConfirmDisconnect","uid","live","then","response","body","json","catch","ok","error","act","action","method","headers","JSON","stringify","variant","allowDuplicate","copy","label","value","navigator","clipboard","writeText","persist","toLowerCase","available","connected","Boolean","actions","direction","spacing","size","disabled","onClick","color","endpoint","credentialRows","username","push","header","help","anchor","HeaderProps","contentGutterX","contentGutterY","severity","aria-label","map","component","scope","sx","wordBreak","align","field","lastExportAtMs","lastShipNoticeAtMs","open","onClose","displayName"],"mappings":"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"}
@@ -48,6 +48,8 @@ interface DetailVariant {
48
48
  soldOut: boolean;
49
49
  imageUrl?: string;
50
50
  sku?: string;
51
+ /** The buyer may choose the day they will use it (AGL-4043). */
52
+ asksUseDate?: true;
51
53
  }
52
54
  interface Detail {
53
55
  id: string;
@@ -66,6 +68,8 @@ interface Detail {
66
68
  };
67
69
  /** Buyer picks one-time or subscribe at the same price (AGL-545). */
68
70
  subscriptionOptional?: boolean;
71
+ /** The store's time zone, when a variant asks for a use day (AGL-4043). */
72
+ useDayTimeZone?: string;
69
73
  }
70
74
  /** How one option is offered on the page. */
71
75
  export interface OptionPresentation {