@aglyn/plugins-commerce 1.0.0-beta.143

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 (417) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +10 -0
  3. package/package.json +57 -0
  4. package/src/index.d.ts +38 -0
  5. package/src/index.js +38 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/account.d.ts +31 -0
  8. package/src/lib/components/account.js +645 -0
  9. package/src/lib/components/account.js.map +1 -0
  10. package/src/lib/components/cart.d.ts +38 -0
  11. package/src/lib/components/cart.js +851 -0
  12. package/src/lib/components/cart.js.map +1 -0
  13. package/src/lib/components/commerce-console-page.d.ts +32 -0
  14. package/src/lib/components/commerce-console-page.js +296 -0
  15. package/src/lib/components/commerce-console-page.js.map +1 -0
  16. package/src/lib/components/commerce-console-sections.d.ts +34 -0
  17. package/src/lib/components/commerce-console-sections.js +62 -0
  18. package/src/lib/components/commerce-console-sections.js.map +1 -0
  19. package/src/lib/components/console/catalog-organization-card.component.d.ts +14 -0
  20. package/src/lib/components/console/catalog-organization-card.component.js +1087 -0
  21. package/src/lib/components/console/catalog-organization-card.component.js.map +1 -0
  22. package/src/lib/components/console/commerce-analytics-card.component.d.ts +27 -0
  23. package/src/lib/components/console/commerce-analytics-card.component.js +310 -0
  24. package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -0
  25. package/src/lib/components/console/commerce-glance-card.component.d.ts +20 -0
  26. package/src/lib/components/console/commerce-glance-card.component.js +340 -0
  27. package/src/lib/components/console/commerce-glance-card.component.js.map +1 -0
  28. package/src/lib/components/console/commerce-stat-tile.component.d.ts +37 -0
  29. package/src/lib/components/console/commerce-stat-tile.component.js +72 -0
  30. package/src/lib/components/console/commerce-stat-tile.component.js.map +1 -0
  31. package/src/lib/components/console/discounts-card.component.d.ts +14 -0
  32. package/src/lib/components/console/discounts-card.component.js +443 -0
  33. package/src/lib/components/console/discounts-card.component.js.map +1 -0
  34. package/src/lib/components/console/entitlement-gate.component.d.ts +76 -0
  35. package/src/lib/components/console/entitlement-gate.component.js +115 -0
  36. package/src/lib/components/console/entitlement-gate.component.js.map +1 -0
  37. package/src/lib/components/console/gift-cards-card.component.d.ts +29 -0
  38. package/src/lib/components/console/gift-cards-card.component.js +379 -0
  39. package/src/lib/components/console/gift-cards-card.component.js.map +1 -0
  40. package/src/lib/components/console/host-coupons-card.component.d.ts +14 -0
  41. package/src/lib/components/console/host-coupons-card.component.js +252 -0
  42. package/src/lib/components/console/host-coupons-card.component.js.map +1 -0
  43. package/src/lib/components/console/host-orders-card.component.d.ts +13 -0
  44. package/src/lib/components/console/host-orders-card.component.js +861 -0
  45. package/src/lib/components/console/host-orders-card.component.js.map +1 -0
  46. package/src/lib/components/console/locations-card.component.d.ts +14 -0
  47. package/src/lib/components/console/locations-card.component.js +256 -0
  48. package/src/lib/components/console/locations-card.component.js.map +1 -0
  49. package/src/lib/components/console/member-posts-card.component.d.ts +8 -0
  50. package/src/lib/components/console/member-posts-card.component.js +283 -0
  51. package/src/lib/components/console/member-posts-card.component.js.map +1 -0
  52. package/src/lib/components/console/newest-site-users-card.component.d.ts +36 -0
  53. package/src/lib/components/console/newest-site-users-card.component.js +126 -0
  54. package/src/lib/components/console/newest-site-users-card.component.js.map +1 -0
  55. package/src/lib/components/console/order-detail-dialog.component.d.ts +28 -0
  56. package/src/lib/components/console/order-detail-dialog.component.js +976 -0
  57. package/src/lib/components/console/order-detail-dialog.component.js.map +1 -0
  58. package/src/lib/components/console/paid-media.d.ts +127 -0
  59. package/src/lib/components/console/paid-media.js +397 -0
  60. package/src/lib/components/console/paid-media.js.map +1 -0
  61. package/src/lib/components/console/payments-settings-card.component.d.ts +13 -0
  62. package/src/lib/components/console/payments-settings-card.component.js +295 -0
  63. package/src/lib/components/console/payments-settings-card.component.js.map +1 -0
  64. package/src/lib/components/console/pos-page.component.d.ts +13 -0
  65. package/src/lib/components/console/pos-page.component.js +916 -0
  66. package/src/lib/components/console/pos-page.component.js.map +1 -0
  67. package/src/lib/components/console/product-editor-dialog.component.d.ts +32 -0
  68. package/src/lib/components/console/product-editor-dialog.component.js +1374 -0
  69. package/src/lib/components/console/product-editor-dialog.component.js.map +1 -0
  70. package/src/lib/components/console/products-hub-card.component.d.ts +16 -0
  71. package/src/lib/components/console/products-hub-card.component.js +1280 -0
  72. package/src/lib/components/console/products-hub-card.component.js.map +1 -0
  73. package/src/lib/components/console/products-hub-zone.component.d.ts +50 -0
  74. package/src/lib/components/console/products-hub-zone.component.js +200 -0
  75. package/src/lib/components/console/products-hub-zone.component.js.map +1 -0
  76. package/src/lib/components/console/recovery-queue-card.component.d.ts +39 -0
  77. package/src/lib/components/console/recovery-queue-card.component.js +262 -0
  78. package/src/lib/components/console/recovery-queue-card.component.js.map +1 -0
  79. package/src/lib/components/console/registers-card.component.d.ts +21 -0
  80. package/src/lib/components/console/registers-card.component.js +296 -0
  81. package/src/lib/components/console/registers-card.component.js.map +1 -0
  82. package/src/lib/components/console/reservations-card.component.d.ts +14 -0
  83. package/src/lib/components/console/reservations-card.component.js +650 -0
  84. package/src/lib/components/console/reservations-card.component.js.map +1 -0
  85. package/src/lib/components/console/reviews-moderation-card.component.d.ts +8 -0
  86. package/src/lib/components/console/reviews-moderation-card.component.js +235 -0
  87. package/src/lib/components/console/reviews-moderation-card.component.js.map +1 -0
  88. package/src/lib/components/console/shipping-settings-card.component.d.ts +38 -0
  89. package/src/lib/components/console/shipping-settings-card.component.js +560 -0
  90. package/src/lib/components/console/shipping-settings-card.component.js.map +1 -0
  91. package/src/lib/components/console/stock-movements-card.component.d.ts +31 -0
  92. package/src/lib/components/console/stock-movements-card.component.js +333 -0
  93. package/src/lib/components/console/stock-movements-card.component.js.map +1 -0
  94. package/src/lib/components/console/store-settings-card.component.d.ts +14 -0
  95. package/src/lib/components/console/store-settings-card.component.js +300 -0
  96. package/src/lib/components/console/store-settings-card.component.js.map +1 -0
  97. package/src/lib/components/console/storefront-tax-summary-card.component.d.ts +73 -0
  98. package/src/lib/components/console/storefront-tax-summary-card.component.js +408 -0
  99. package/src/lib/components/console/storefront-tax-summary-card.component.js.map +1 -0
  100. package/src/lib/components/console/suppliers-card.component.d.ts +8 -0
  101. package/src/lib/components/console/suppliers-card.component.js +328 -0
  102. package/src/lib/components/console/suppliers-card.component.js.map +1 -0
  103. package/src/lib/components/console/tax-settings-card.component.d.ts +14 -0
  104. package/src/lib/components/console/tax-settings-card.component.js +473 -0
  105. package/src/lib/components/console/tax-settings-card.component.js.map +1 -0
  106. package/src/lib/components/gate.d.ts +39 -0
  107. package/src/lib/components/gate.js +202 -0
  108. package/src/lib/components/gate.js.map +1 -0
  109. package/src/lib/components/gated-video.d.ts +40 -0
  110. package/src/lib/components/gated-video.js +366 -0
  111. package/src/lib/components/gated-video.js.map +1 -0
  112. package/src/lib/components/member-feed.d.ts +32 -0
  113. package/src/lib/components/member-feed.js +198 -0
  114. package/src/lib/components/member-feed.js.map +1 -0
  115. package/src/lib/components/member-recovery.d.ts +35 -0
  116. package/src/lib/components/member-recovery.js +313 -0
  117. package/src/lib/components/member-recovery.js.map +1 -0
  118. package/src/lib/components/member-signin.d.ts +35 -0
  119. package/src/lib/components/member-signin.js +257 -0
  120. package/src/lib/components/member-signin.js.map +1 -0
  121. package/src/lib/components/member-signup.d.ts +34 -0
  122. package/src/lib/components/member-signup.js +287 -0
  123. package/src/lib/components/member-signup.js.map +1 -0
  124. package/src/lib/components/newsletter-signup.d.ts +39 -0
  125. package/src/lib/components/newsletter-signup.js +229 -0
  126. package/src/lib/components/newsletter-signup.js.map +1 -0
  127. package/src/lib/components/product-detail.d.ts +38 -0
  128. package/src/lib/components/product-detail.js +1022 -0
  129. package/src/lib/components/product-detail.js.map +1 -0
  130. package/src/lib/components/product-grid.d.ts +67 -0
  131. package/src/lib/components/product-grid.js +909 -0
  132. package/src/lib/components/product-grid.js.map +1 -0
  133. package/src/lib/components/product-reviews.d.ts +32 -0
  134. package/src/lib/components/product-reviews.js +349 -0
  135. package/src/lib/components/product-reviews.js.map +1 -0
  136. package/src/lib/components/related-products.d.ts +33 -0
  137. package/src/lib/components/related-products.js +232 -0
  138. package/src/lib/components/related-products.js.map +1 -0
  139. package/src/lib/components/reservation-widget.d.ts +33 -0
  140. package/src/lib/components/reservation-widget.js +418 -0
  141. package/src/lib/components/reservation-widget.js.map +1 -0
  142. package/src/lib/components/storefront-payment-element-fallback.d.ts +18 -0
  143. package/src/lib/components/storefront-payment-element-fallback.js +51 -0
  144. package/src/lib/components/storefront-payment-element-fallback.js.map +1 -0
  145. package/src/lib/components/storefront-payment-element.d.ts +78 -0
  146. package/src/lib/components/storefront-payment-element.js +156 -0
  147. package/src/lib/components/storefront-payment-element.js.map +1 -0
  148. package/src/lib/components/wishlist.d.ts +46 -0
  149. package/src/lib/components/wishlist.js +304 -0
  150. package/src/lib/components/wishlist.js.map +1 -0
  151. package/src/lib/constants/bundle-common.d.ts +18 -0
  152. package/src/lib/constants/bundle-common.js +18 -0
  153. package/src/lib/constants/bundle-common.js.map +1 -0
  154. package/src/lib/constants/product-filters.d.ts +35 -0
  155. package/src/lib/constants/product-filters.js +109 -0
  156. package/src/lib/constants/product-filters.js.map +1 -0
  157. package/src/lib/model/commerce-cart.d.ts +52 -0
  158. package/src/lib/model/commerce-cart.js +102 -0
  159. package/src/lib/model/commerce-cart.js.map +1 -0
  160. package/src/lib/model/commerce-connect-transfer.d.ts +243 -0
  161. package/src/lib/model/commerce-connect-transfer.js +231 -0
  162. package/src/lib/model/commerce-connect-transfer.js.map +1 -0
  163. package/src/lib/model/commerce-discounts.d.ts +164 -0
  164. package/src/lib/model/commerce-discounts.js +231 -0
  165. package/src/lib/model/commerce-discounts.js.map +1 -0
  166. package/src/lib/model/commerce-dispute.d.ts +124 -0
  167. package/src/lib/model/commerce-dispute.js +225 -0
  168. package/src/lib/model/commerce-dispute.js.map +1 -0
  169. package/src/lib/model/commerce-gift-cards.d.ts +107 -0
  170. package/src/lib/model/commerce-gift-cards.js +121 -0
  171. package/src/lib/model/commerce-gift-cards.js.map +1 -0
  172. package/src/lib/model/commerce-io.d.ts +36 -0
  173. package/src/lib/model/commerce-io.js +245 -0
  174. package/src/lib/model/commerce-io.js.map +1 -0
  175. package/src/lib/model/commerce-orders.d.ts +1040 -0
  176. package/src/lib/model/commerce-orders.js +1022 -0
  177. package/src/lib/model/commerce-orders.js.map +1 -0
  178. package/src/lib/model/commerce-promotions.d.ts +188 -0
  179. package/src/lib/model/commerce-promotions.js +199 -0
  180. package/src/lib/model/commerce-promotions.js.map +1 -0
  181. package/src/lib/model/commerce-reservations.d.ts +175 -0
  182. package/src/lib/model/commerce-reservations.js +157 -0
  183. package/src/lib/model/commerce-reservations.js.map +1 -0
  184. package/src/lib/model/commerce-shipping.d.ts +316 -0
  185. package/src/lib/model/commerce-shipping.js +484 -0
  186. package/src/lib/model/commerce-shipping.js.map +1 -0
  187. package/src/lib/model/commerce-stock-holds.d.ts +199 -0
  188. package/src/lib/model/commerce-stock-holds.js +190 -0
  189. package/src/lib/model/commerce-stock-holds.js.map +1 -0
  190. package/src/lib/model/commerce-subscription-status.d.ts +67 -0
  191. package/src/lib/model/commerce-subscription-status.js +76 -0
  192. package/src/lib/model/commerce-subscription-status.js.map +1 -0
  193. package/src/lib/model/commerce-tax-decision.d.ts +222 -0
  194. package/src/lib/model/commerce-tax-decision.js +165 -0
  195. package/src/lib/model/commerce-tax-decision.js.map +1 -0
  196. package/src/lib/model/commerce-tax.d.ts +176 -0
  197. package/src/lib/model/commerce-tax.js +92 -0
  198. package/src/lib/model/commerce-tax.js.map +1 -0
  199. package/src/lib/model/commerce.d.ts +551 -0
  200. package/src/lib/model/commerce.js +739 -0
  201. package/src/lib/model/commerce.js.map +1 -0
  202. package/src/lib/model/index.d.ts +40 -0
  203. package/src/lib/model/index.js +40 -0
  204. package/src/lib/model/index.js.map +1 -0
  205. package/src/lib/model/order-figures.d.ts +48 -0
  206. package/src/lib/model/order-figures.js +74 -0
  207. package/src/lib/model/order-figures.js.map +1 -0
  208. package/src/lib/model/plugin-permissions.d.ts +23 -0
  209. package/src/lib/model/plugin-permissions.js +34 -0
  210. package/src/lib/model/plugin-permissions.js.map +1 -0
  211. package/src/lib/model/purchase-analytics.d.ts +186 -0
  212. package/src/lib/model/purchase-analytics.js +216 -0
  213. package/src/lib/model/purchase-analytics.js.map +1 -0
  214. package/src/lib/plugin-config.d.ts +62 -0
  215. package/src/lib/plugin-config.js +78 -0
  216. package/src/lib/plugin-config.js.map +1 -0
  217. package/src/lib/plugin.d.ts +28 -0
  218. package/src/lib/plugin.js +147 -0
  219. package/src/lib/plugin.js.map +1 -0
  220. package/src/lib/server/billing-webhook.d.ts +26 -0
  221. package/src/lib/server/billing-webhook.js +4011 -0
  222. package/src/lib/server/billing-webhook.js.map +1 -0
  223. package/src/lib/server/cancel-order.d.ts +87 -0
  224. package/src/lib/server/cancel-order.js +368 -0
  225. package/src/lib/server/cancel-order.js.map +1 -0
  226. package/src/lib/server/cart-checkout.d.ts +25 -0
  227. package/src/lib/server/cart-checkout.js +976 -0
  228. package/src/lib/server/cart-checkout.js.map +1 -0
  229. package/src/lib/server/cart-cookie.d.ts +32 -0
  230. package/src/lib/server/cart-cookie.js +77 -0
  231. package/src/lib/server/cart-cookie.js.map +1 -0
  232. package/src/lib/server/cart.d.ts +34 -0
  233. package/src/lib/server/cart.js +181 -0
  234. package/src/lib/server/cart.js.map +1 -0
  235. package/src/lib/server/catalog.d.ts +127 -0
  236. package/src/lib/server/catalog.js +277 -0
  237. package/src/lib/server/catalog.js.map +1 -0
  238. package/src/lib/server/checkout.d.ts +36 -0
  239. package/src/lib/server/checkout.js +915 -0
  240. package/src/lib/server/checkout.js.map +1 -0
  241. package/src/lib/server/connect.d.ts +26 -0
  242. package/src/lib/server/connect.js +238 -0
  243. package/src/lib/server/connect.js.map +1 -0
  244. package/src/lib/server/contact-refund.d.ts +117 -0
  245. package/src/lib/server/contact-refund.js +196 -0
  246. package/src/lib/server/contact-refund.js.map +1 -0
  247. package/src/lib/server/download.d.ts +39 -0
  248. package/src/lib/server/download.js +206 -0
  249. package/src/lib/server/download.js.map +1 -0
  250. package/src/lib/server/draft-order.d.ts +26 -0
  251. package/src/lib/server/draft-order.js +706 -0
  252. package/src/lib/server/draft-order.js.map +1 -0
  253. package/src/lib/server/feed.d.ts +24 -0
  254. package/src/lib/server/feed.js +59 -0
  255. package/src/lib/server/feed.js.map +1 -0
  256. package/src/lib/server/fulfill-order.d.ts +97 -0
  257. package/src/lib/server/fulfill-order.js +235 -0
  258. package/src/lib/server/fulfill-order.js.map +1 -0
  259. package/src/lib/server/gate.d.ts +36 -0
  260. package/src/lib/server/gate.js +112 -0
  261. package/src/lib/server/gate.js.map +1 -0
  262. package/src/lib/server/gift-cards.d.ts +42 -0
  263. package/src/lib/server/gift-cards.js +219 -0
  264. package/src/lib/server/gift-cards.js.map +1 -0
  265. package/src/lib/server/low-stock.d.ts +49 -0
  266. package/src/lib/server/low-stock.js +60 -0
  267. package/src/lib/server/low-stock.js.map +1 -0
  268. package/src/lib/server/manual-tax-rate.d.ts +82 -0
  269. package/src/lib/server/manual-tax-rate.js +113 -0
  270. package/src/lib/server/manual-tax-rate.js.map +1 -0
  271. package/src/lib/server/member-feed.d.ts +24 -0
  272. package/src/lib/server/member-feed.js +72 -0
  273. package/src/lib/server/member-feed.js.map +1 -0
  274. package/src/lib/server/member-name-search.d.ts +37 -0
  275. package/src/lib/server/member-name-search.js +42 -0
  276. package/src/lib/server/member-name-search.js.map +1 -0
  277. package/src/lib/server/member-post.d.ts +23 -0
  278. package/src/lib/server/member-post.js +166 -0
  279. package/src/lib/server/member-post.js.map +1 -0
  280. package/src/lib/server/membership-account.d.ts +37 -0
  281. package/src/lib/server/membership-account.js +148 -0
  282. package/src/lib/server/membership-account.js.map +1 -0
  283. package/src/lib/server/membership-admin-password.d.ts +33 -0
  284. package/src/lib/server/membership-admin-password.js +202 -0
  285. package/src/lib/server/membership-admin-password.js.map +1 -0
  286. package/src/lib/server/membership-content.d.ts +23 -0
  287. package/src/lib/server/membership-content.js +105 -0
  288. package/src/lib/server/membership-content.js.map +1 -0
  289. package/src/lib/server/membership-login.d.ts +19 -0
  290. package/src/lib/server/membership-login.js +137 -0
  291. package/src/lib/server/membership-login.js.map +1 -0
  292. package/src/lib/server/membership-logout.d.ts +19 -0
  293. package/src/lib/server/membership-logout.js +35 -0
  294. package/src/lib/server/membership-logout.js.map +1 -0
  295. package/src/lib/server/membership-recover.d.ts +60 -0
  296. package/src/lib/server/membership-recover.js +244 -0
  297. package/src/lib/server/membership-recover.js.map +1 -0
  298. package/src/lib/server/membership-register.d.ts +22 -0
  299. package/src/lib/server/membership-register.js +241 -0
  300. package/src/lib/server/membership-register.js.map +1 -0
  301. package/src/lib/server/membership-reset.d.ts +26 -0
  302. package/src/lib/server/membership-reset.js +88 -0
  303. package/src/lib/server/membership-reset.js.map +1 -0
  304. package/src/lib/server/membership-wishlist.d.ts +23 -0
  305. package/src/lib/server/membership-wishlist.js +89 -0
  306. package/src/lib/server/membership-wishlist.js.map +1 -0
  307. package/src/lib/server/membership.d.ts +96 -0
  308. package/src/lib/server/membership.js +222 -0
  309. package/src/lib/server/membership.js.map +1 -0
  310. package/src/lib/server/native-checkout.d.ts +170 -0
  311. package/src/lib/server/native-checkout.js +193 -0
  312. package/src/lib/server/native-checkout.js.map +1 -0
  313. package/src/lib/server/newsletter.d.ts +23 -0
  314. package/src/lib/server/newsletter.js +323 -0
  315. package/src/lib/server/newsletter.js.map +1 -0
  316. package/src/lib/server/notify-restock.d.ts +22 -0
  317. package/src/lib/server/notify-restock.js +84 -0
  318. package/src/lib/server/notify-restock.js.map +1 -0
  319. package/src/lib/server/order-analytics.d.ts +134 -0
  320. package/src/lib/server/order-analytics.js +263 -0
  321. package/src/lib/server/order-analytics.js.map +1 -0
  322. package/src/lib/server/order-figures.d.ts +33 -0
  323. package/src/lib/server/order-figures.js +220 -0
  324. package/src/lib/server/order-figures.js.map +1 -0
  325. package/src/lib/server/paid-media-delivery.d.ts +173 -0
  326. package/src/lib/server/paid-media-delivery.js +212 -0
  327. package/src/lib/server/paid-media-delivery.js.map +1 -0
  328. package/src/lib/server/pos-order.d.ts +54 -0
  329. package/src/lib/server/pos-order.js +1137 -0
  330. package/src/lib/server/pos-order.js.map +1 -0
  331. package/src/lib/server/process-abandoned.d.ts +54 -0
  332. package/src/lib/server/process-abandoned.js +222 -0
  333. package/src/lib/server/process-abandoned.js.map +1 -0
  334. package/src/lib/server/process-restock.d.ts +42 -0
  335. package/src/lib/server/process-restock.js +219 -0
  336. package/src/lib/server/process-restock.js.map +1 -0
  337. package/src/lib/server/product-card.d.ts +29 -0
  338. package/src/lib/server/product-card.js +54 -0
  339. package/src/lib/server/product-card.js.map +1 -0
  340. package/src/lib/server/product.d.ts +70 -0
  341. package/src/lib/server/product.js +105 -0
  342. package/src/lib/server/product.js.map +1 -0
  343. package/src/lib/server/promotion-hold.d.ts +144 -0
  344. package/src/lib/server/promotion-hold.js +174 -0
  345. package/src/lib/server/promotion-hold.js.map +1 -0
  346. package/src/lib/server/reconcile-stock.d.ts +106 -0
  347. package/src/lib/server/reconcile-stock.js +349 -0
  348. package/src/lib/server/reconcile-stock.js.map +1 -0
  349. package/src/lib/server/refund.d.ts +45 -0
  350. package/src/lib/server/refund.js +607 -0
  351. package/src/lib/server/refund.js.map +1 -0
  352. package/src/lib/server/related.d.ts +24 -0
  353. package/src/lib/server/related.js +104 -0
  354. package/src/lib/server/related.js.map +1 -0
  355. package/src/lib/server/reservation-availability.d.ts +23 -0
  356. package/src/lib/server/reservation-availability.js +111 -0
  357. package/src/lib/server/reservation-availability.js.map +1 -0
  358. package/src/lib/server/reserve-stock.d.ts +156 -0
  359. package/src/lib/server/reserve-stock.js +146 -0
  360. package/src/lib/server/reserve-stock.js.map +1 -0
  361. package/src/lib/server/reserve.d.ts +25 -0
  362. package/src/lib/server/reserve.js +426 -0
  363. package/src/lib/server/reserve.js.map +1 -0
  364. package/src/lib/server/restock-flag.d.ts +202 -0
  365. package/src/lib/server/restock-flag.js +449 -0
  366. package/src/lib/server/restock-flag.js.map +1 -0
  367. package/src/lib/server/reviews.d.ts +51 -0
  368. package/src/lib/server/reviews.js +132 -0
  369. package/src/lib/server/reviews.js.map +1 -0
  370. package/src/lib/server/site-page-enricher.d.ts +42 -0
  371. package/src/lib/server/site-page-enricher.js +149 -0
  372. package/src/lib/server/site-page-enricher.js.map +1 -0
  373. package/src/lib/server/site-page-resolver.d.ts +26 -0
  374. package/src/lib/server/site-page-resolver.js +223 -0
  375. package/src/lib/server/site-page-resolver.js.map +1 -0
  376. package/src/lib/server/stock-hold.d.ts +127 -0
  377. package/src/lib/server/stock-hold.js +258 -0
  378. package/src/lib/server/stock-hold.js.map +1 -0
  379. package/src/lib/server/storefront-tax-record.d.ts +22 -0
  380. package/src/lib/server/storefront-tax-record.js +218 -0
  381. package/src/lib/server/storefront-tax-record.js.map +1 -0
  382. package/src/lib/server/storefront-tax.d.ts +197 -0
  383. package/src/lib/server/storefront-tax.js +245 -0
  384. package/src/lib/server/storefront-tax.js.map +1 -0
  385. package/src/lib/server/stream.d.ts +25 -0
  386. package/src/lib/server/stream.js +191 -0
  387. package/src/lib/server/stream.js.map +1 -0
  388. package/src/lib/server/subscription-portal.d.ts +24 -0
  389. package/src/lib/server/subscription-portal.js +91 -0
  390. package/src/lib/server/subscription-portal.js.map +1 -0
  391. package/src/lib/server/supplier-outbox.d.ts +190 -0
  392. package/src/lib/server/supplier-outbox.js +342 -0
  393. package/src/lib/server/supplier-outbox.js.map +1 -0
  394. package/src/lib/server/supplier-update.d.ts +23 -0
  395. package/src/lib/server/supplier-update.js +289 -0
  396. package/src/lib/server/supplier-update.js.map +1 -0
  397. package/src/lib/server/tax-profile.d.ts +29 -0
  398. package/src/lib/server/tax-profile.js +40 -0
  399. package/src/lib/server/tax-profile.js.map +1 -0
  400. package/src/lib/server.d.ts +32 -0
  401. package/src/lib/server.js +311 -0
  402. package/src/lib/server.js.map +1 -0
  403. package/src/lib/site.d.ts +27 -0
  404. package/src/lib/site.js +134 -0
  405. package/src/lib/site.js.map +1 -0
  406. package/src/lib/utils/escape-html.d.ts +41 -0
  407. package/src/lib/utils/escape-html.js +41 -0
  408. package/src/lib/utils/escape-html.js.map +1 -0
  409. package/src/lib/utils/generate-preset-id.d.ts +19 -0
  410. package/src/lib/utils/generate-preset-id.js +25 -0
  411. package/src/lib/utils/generate-preset-id.js.map +1 -0
  412. package/src/lib/utils/member-continue.d.ts +45 -0
  413. package/src/lib/utils/member-continue.js +49 -0
  414. package/src/lib/utils/member-continue.js.map +1 -0
  415. package/src/lib/utils/use-storefront-purchase-event.d.ts +60 -0
  416. package/src/lib/utils/use-storefront-purchase-event.js +142 -0
  417. package/src/lib/utils/use-storefront-purchase-event.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/product-grid.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\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiMagnify, mdiViewGridOutline } from '@aglyn/shared-data-mdi'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport CardActionArea from '@mui/material/CardActionArea'\nimport CardContent from '@mui/material/CardContent'\nimport CardMedia from '@mui/material/CardMedia'\nimport Chip from '@mui/material/Chip'\nimport InputAdornment from '@mui/material/InputAdornment'\nimport MenuItem from '@mui/material/MenuItem'\nimport Skeleton from '@mui/material/Skeleton'\nimport Slider from '@mui/material/Slider'\nimport SvgIcon from '@mui/material/SvgIcon'\nimport TextField from '@mui/material/TextField'\nimport Typography from '@mui/material/Typography'\nimport { forwardRef, useCallback, useEffect, useRef, useState } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'product-grid'\n\nexport interface ProductGridProps {\n /** Filter source; 'all' lists the whole active catalog. */\n source?: 'all' | 'collection' | 'category' | 'tag'\n /** Collection id when source = collection (rename-safe, AGL-343). */\n collectionId?: string\n /** Legacy collection slug; used only when no collectionId is set.\n * Blank follows the /collections/{slug} URL (AGL-298). */\n collectionSlug?: string\n /** Faceted controls above the grid: tags, availability, sort. */\n showFilters?: boolean\n /** Debounced visitor search box above the grid (server-side, AGL-561). */\n showSearch?: boolean\n /** Category filter chips from the host's categories (AGL-561). */\n showCategories?: boolean\n /** Sort select: newest, name, price low→high / high→low (AGL-561). */\n showSort?: boolean\n /** Physical / digital / services filter chips (AGL-561). */\n showTypeFilter?: boolean\n /** Price range slider bounded by the catalog's prices (AGL-564). */\n showPriceFilter?: boolean\n /** Products per page; shows a Load more button while more remain. */\n pageSize?: number\n /** Category id when source = category (rename-safe, AGL-343). */\n categoryId?: string\n /** Legacy category slug; used only when no categoryId is set. */\n categorySlug?: string\n /** Tag when source = tag. */\n tag?: string\n sort?: 'name' | 'price-asc' | 'price-desc' | 'newest'\n /** Grid columns on desktop (1-6); mobile always stacks to 2/1. */\n columns?: number\n maxItems?: number\n /** Empty-state copy when nothing matches. */\n emptyText?: string\n}\n\ninterface CatalogItem {\n id: string\n name: string\n slug: string\n priceUsd: number\n maxPriceUsd: number\n compareAtPriceUsd?: number\n imageUrl?: string\n soldOut: boolean\n tags?: string[]\n}\n\ninterface CatalogCategory {\n id: string\n name: string\n slug: string\n}\n\n/** Price facet from the catalog handler, in cents (AGL-564). */\ninterface CatalogPriceBounds {\n minCents: number\n maxCents: number\n}\n\n/**\n * This grid's first page, resolved server-side by the commerce site-page\n * enricher (AGL-659). Same shape the catalog endpoint returns, because both\n * go through `queryPublicCatalog`.\n */\ninterface CatalogSeed {\n items?: CatalogItem[]\n categories?: CatalogCategory[]\n priceBounds?: CatalogPriceBounds\n nextOffset?: number\n}\n\nconst SAMPLE_ITEMS: CatalogItem[] = [\n { id: 's1', name: 'Sample product', slug: '#', priceUsd: 29, maxPriceUsd: 29, soldOut: false },\n { id: 's2', name: 'Another product', slug: '#', priceUsd: 49, maxPriceUsd: 59, compareAtPriceUsd: 79, soldOut: false },\n { id: 's3', name: 'Third product', slug: '#', priceUsd: 12, maxPriceUsd: 12, soldOut: true },\n]\n\n/** Inert chips shown on the besigner canvas when categories are on. */\nconst SAMPLE_CATEGORIES: CatalogCategory[] = [\n { id: 'sc1', name: 'Apparel', slug: 'apparel' },\n { id: 'sc2', name: 'Accessories', slug: 'accessories' },\n]\n\n/** Inert slider bounds on the canvas, matching the sample cards. */\nconst SAMPLE_PRICE_BOUNDS: CatalogPriceBounds = {\n minCents: 1200,\n maxCents: 4900,\n}\n\nconst TYPE_OPTIONS = [\n { value: 'physical', label: 'Physical' },\n { value: 'digital', label: 'Digital' },\n { value: 'service', label: 'Services' },\n] as const\n\nconst SORT_OPTIONS = [\n { value: 'newest', label: 'Newest' },\n { value: 'name', label: 'Name' },\n { value: 'price-asc', label: 'Price: low to high' },\n { value: 'price-desc', label: 'Price: high to low' },\n] as const\n\nfunction collectionSlugFromLocation(): string {\n if (typeof window === 'undefined') return ''\n const match = window.location.pathname.match(/\\/collections\\/([^/?#]+)/)\n return match ? decodeURIComponent(match[1]) : ''\n}\n\nfunction priceLabel(item: CatalogItem): string {\n return item.priceUsd === item.maxPriceUsd\n ? `$${item.priceUsd}`\n : `From $${item.priceUsd}`\n}\n\n/**\n * Product grid / PLP block (AGL-291): active catalog items from the\n * public listing API, filterable by collection/category/tag, designable\n * in besigner with sample cards (no SiteContext = inert canvas, same\n * convention as the mui Product block). Cards navigate to\n * `/products/{slug}` (PDP routes, AGL-292). Catalog UX (AGL-561):\n * optional debounced search, category chips, type chips, a sort\n * select, and Load more paging — all resolved server-side by the\n * catalog handler so large catalogs stay cheap.\n */\nconst ProductGrid = forwardRef<HTMLDivElement, ProductGridProps>(\n (props, ref) => {\n const {\n source,\n collectionId,\n collectionSlug: collectionSlugProp,\n categoryId,\n categorySlug,\n tag,\n sort: sortProp,\n columns,\n maxItems,\n emptyText,\n showFilters,\n showSearch,\n showCategories,\n showSort,\n showTypeFilter,\n showPriceFilter,\n pageSize,\n ...rest\n } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const site = Aglyn.useSite()\n const { hostId } = site\n // Server-rendered first page (AGL-659). The site-page enricher ran this\n // grid's own query on the server and keyed the result by node id — two\n // grids on a page have different queries, so an unkeyed seed would put\n // the wrong products in one of them. Absent in the besigner and preview,\n // where there is no pageData at all and the effect below still fetches.\n const nodeId = Aglyn.useNodeId()\n const seed = (\n site.pageData as\n | { commerce?: { grids?: Record<string, CatalogSeed> } }\n | undefined\n )?.commerce?.grids?.[nodeId]\n\n const [items, setItems] = useState<CatalogItem[] | null>(\n seed?.items ?? null,\n )\n const [sort, setSort] = useState(sortProp)\n const [inStockOnly, setInStockOnly] = useState(false)\n const [activeTag, setActiveTag] = useState('')\n // Catalog UX state (AGL-561): the search box debounces into\n // `query`; a chip pick overrides any pinned category ('*' = All);\n // paging appends via `nextOffset` from the catalog handler.\n const [searchInput, setSearchInput] = useState('')\n const [query, setQuery] = useState('')\n const [activeCategoryId, setActiveCategoryId] = useState('')\n const [activeType, setActiveType] = useState('')\n const [categories, setCategories] = useState<CatalogCategory[]>(\n seed?.categories ?? [],\n )\n // Price filter (AGL-564): the slider drags into `priceInput` (whole\n // dollars) and debounces into `priceFilter`, which drives the query;\n // null = untouched (no price params sent). Bounds come from the\n // handler's price facets.\n const [priceBounds, setPriceBounds] = useState<CatalogPriceBounds | null>(\n seed?.priceBounds ?? null,\n )\n const [priceInput, setPriceInput] = useState<number[] | null>(null)\n const [priceFilter, setPriceFilter] = useState<number[] | null>(null)\n const [nextOffset, setNextOffset] = useState<number | null>(\n seed?.nextOffset ?? null,\n )\n const [loadingMore, setLoadingMore] = useState(false)\n const fetchSeq = useRef(0)\n const collectionSlug =\n source === 'collection'\n ? collectionSlugProp || collectionSlugFromLocation()\n : collectionSlugProp\n const pageLimit =\n pageSize && Number(pageSize) > 0 ? Math.floor(Number(pageSize)) : 0\n const pinnedCategoryId = source === 'category' ? categoryId ?? '' : ''\n\n // Debounce keystrokes so large catalogs aren't fetched per letter.\n useEffect(() => {\n const timer = setTimeout(() => setQuery(searchInput.trim()), 300)\n return () => clearTimeout(timer)\n }, [searchInput])\n\n // Debounce slider drags the same way (AGL-564): one fetch per\n // settled range, not one per pixel of thumb movement.\n useEffect(() => {\n const timer = setTimeout(() => setPriceFilter(priceInput), 300)\n return () => clearTimeout(timer)\n }, [priceInput])\n\n const loadPage = useCallback(\n async (offset: number): Promise<void> => {\n if (!hostId) return\n const seq = ++fetchSeq.current\n const params = new URLSearchParams({ hostId })\n // Ids first (rename-safe, AGL-343); slugs remain as the legacy path.\n if (source === 'collection') {\n if (collectionId) params.set('collectionId', collectionId)\n else if (collectionSlug) params.set('collection', collectionSlug)\n }\n const effectiveCategoryId =\n activeCategoryId === '*' ? '' : activeCategoryId || pinnedCategoryId\n if (effectiveCategoryId) {\n params.set('categoryId', effectiveCategoryId)\n } else if (!activeCategoryId && source === 'category' && categorySlug) {\n params.set('category', categorySlug)\n }\n if (source === 'tag' && tag) params.set('tag', tag)\n if (query) params.set('q', query)\n if (activeType) params.set('type', activeType)\n // Slider dollars → API cents (AGL-564).\n if (priceFilter) {\n params.set('minPriceCents', String(priceFilter[0] * 100))\n params.set('maxPriceCents', String(priceFilter[1] * 100))\n }\n if (sort) params.set('sort', sort)\n const limit = pageLimit || maxItems\n if (limit) params.set('limit', String(limit))\n if (offset) params.set('offset', String(offset))\n if ((showCategories || showPriceFilter) && offset === 0) {\n params.set('facets', '1')\n }\n try {\n const response = await fetch(\n `/api/commerce/catalog?${params.toString()}`,\n )\n const payload = await response.json()\n if (seq !== fetchSeq.current) return\n const pageItems: CatalogItem[] = payload?.items ?? []\n setItems((prev) =>\n offset && prev ? [...prev, ...pageItems] : pageItems,\n )\n setNextOffset(\n typeof payload?.nextOffset === 'number' ? payload.nextOffset : null,\n )\n if (Array.isArray(payload?.categories)) {\n setCategories(payload.categories)\n }\n const bounds = payload?.priceBounds\n if (\n typeof bounds?.minCents === 'number' &&\n typeof bounds?.maxCents === 'number'\n ) {\n setPriceBounds(bounds)\n }\n } catch {\n if (seq !== fetchSeq.current) return\n if (!offset) setItems([])\n setNextOffset(null)\n }\n },\n [\n hostId,\n source,\n collectionId,\n collectionSlug,\n categorySlug,\n tag,\n sort,\n maxItems,\n query,\n activeCategoryId,\n activeType,\n priceFilter,\n pageLimit,\n pinnedCategoryId,\n showCategories,\n showPriceFilter,\n ],\n )\n\n // A seeded grid already holds exactly what `loadPage(0)` would return,\n // so the first pass skips the fetch (AGL-659) — every later run, after\n // a filter or sort change, goes to the API as before.\n const seededRef = useRef(Boolean(seed))\n useEffect(() => {\n if (!hostId) return\n if (seededRef.current) {\n seededRef.current = false\n return\n }\n void loadPage(0)\n // Invalidate any in-flight request on dep change or unmount.\n return () => {\n fetchSeq.current++\n }\n }, [hostId, loadPage])\n\n const desktopColumns = Math.min(6, Math.max(1, columns ?? 3))\n const gridSx = {\n display: 'grid',\n gap: 2,\n gridTemplateColumns: {\n xs: 'repeat(1, 1fr)',\n sm: 'repeat(2, 1fr)',\n md: `repeat(${desktopColumns}, 1fr)`,\n },\n }\n let visible = hostId ? items : SAMPLE_ITEMS\n if (visible && showFilters) {\n if (inStockOnly) visible = visible.filter((item) => !item.soldOut)\n if (activeTag) {\n visible = visible.filter((item) =>\n (item.tags ?? []).includes(activeTag),\n )\n }\n }\n const facetTags = showFilters\n ? [...new Set((items ?? []).flatMap((item) => item.tags ?? []))].slice(\n 0,\n 12,\n )\n : []\n\n if (hostId && items === null) {\n return (\n // MERGE, never replace (AGL-1450). The skeleton branch replaced the\n // node's sx outright, so an authored grid flashed unstyled for as\n // long as the first fetch took and then snapped into place.\n <Box ref={ref} {...rest} sx={[gridSx, ...nodeSx]}>\n {Array.from({ length: desktopColumns }, (_item, index) => (\n <Card key={index} variant=\"outlined\">\n <Skeleton variant=\"rectangular\" height={160} />\n <CardContent>\n <Skeleton width=\"70%\" />\n <Skeleton width=\"30%\" />\n </CardContent>\n </Card>\n ))}\n </Box>\n )\n }\n\n // Catalog controls (AGL-561): search on top, category/type chips\n // under it with the sort select right-aligned — the layout every\n // mainstream commerce PLP uses. Server-side; sample data inert.\n const chipCategories = categories.length\n ? categories\n : !hostId && showCategories\n ? SAMPLE_CATEGORIES\n : []\n const selectedCategoryId =\n activeCategoryId === '*' ? '' : activeCategoryId || pinnedCategoryId\n const hasCatalogControls = Boolean(\n showSearch || showCategories || showSort || showTypeFilter ||\n showPriceFilter,\n )\n // Price slider bounds (AGL-564), widened to whole dollars so both\n // ends stay reachable; sample bounds keep the canvas designable.\n const sliderBounds = hostId ? priceBounds : SAMPLE_PRICE_BOUNDS\n const sliderMin = sliderBounds ? Math.floor(sliderBounds.minCents / 100) : 0\n const sliderMax = sliderBounds ? Math.ceil(sliderBounds.maxCents / 100) : 0\n const showSlider = Boolean(showPriceFilter && sliderMin < sliderMax)\n const controls = hasCatalogControls ? (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, mb: 2 }}>\n {showSearch ? (\n <TextField\n value={searchInput}\n onChange={(event) => setSearchInput(event.target.value)}\n placeholder=\"Search products…\"\n size=\"small\"\n fullWidth\n slotProps={{\n input: {\n startAdornment: (\n <InputAdornment position=\"start\">\n <SvgIcon fontSize=\"small\" color=\"disabled\">\n <path d={mdiMagnify.path} />\n </SvgIcon>\n </InputAdornment>\n ),\n },\n htmlInput: { 'aria-label': 'Search products', type: 'search' },\n }}\n />\n ) : null}\n {showCategories || showTypeFilter || showSort ? (\n <Box\n sx={{\n display: 'flex',\n gap: 1,\n flexWrap: 'wrap',\n alignItems: 'center',\n }}\n >\n {showCategories && chipCategories.length ? (\n <>\n <Chip\n label=\"All\"\n size=\"small\"\n variant={selectedCategoryId ? 'outlined' : 'filled'}\n color={selectedCategoryId ? 'default' : 'primary'}\n onClick={() => setActiveCategoryId('*')}\n />\n {chipCategories.map((category) => (\n <Chip\n key={category.id}\n label={category.name}\n size=\"small\"\n variant={\n selectedCategoryId === category.id ? 'filled' : 'outlined'\n }\n color={\n selectedCategoryId === category.id\n ? 'secondary'\n : 'default'\n }\n onClick={() =>\n setActiveCategoryId((prev) =>\n (prev || pinnedCategoryId) === category.id\n ? '*'\n : category.id,\n )\n }\n />\n ))}\n </>\n ) : null}\n {showTypeFilter\n ? TYPE_OPTIONS.map((option) => (\n <Chip\n key={option.value}\n label={option.label}\n size=\"small\"\n variant={activeType === option.value ? 'filled' : 'outlined'}\n color={\n activeType === option.value ? 'secondary' : 'default'\n }\n onClick={() =>\n setActiveType((prev) =>\n prev === option.value ? '' : option.value,\n )\n }\n />\n ))\n : null}\n {showSort ? (\n <>\n <Box sx={{ flex: 1 }} />\n <TextField\n select\n size=\"small\"\n value={\n SORT_OPTIONS.some((option) => option.value === sort)\n ? sort\n : 'name'\n }\n onChange={(event) =>\n setSort(event.target.value as ProductGridProps['sort'])\n }\n sx={{ minWidth: 180 }}\n slotProps={{\n htmlInput: { 'aria-label': 'Sort products' },\n }}\n >\n {SORT_OPTIONS.map((option) => (\n <MenuItem key={option.value} value={option.value}>\n {option.label}\n </MenuItem>\n ))}\n </TextField>\n </>\n ) : null}\n </Box>\n ) : null}\n {showSlider ? (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1.5,\n maxWidth: 360,\n px: 1,\n }}\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ whiteSpace: 'nowrap' }}\n >\n {`$${sliderMin}`}\n </Typography>\n <Slider\n size=\"small\"\n value={priceInput ?? [sliderMin, sliderMax]}\n min={sliderMin}\n max={sliderMax}\n step={1}\n disableSwap\n disabled={!hostId}\n onChange={(_event, value) =>\n setPriceInput(Array.isArray(value) ? value : [value, value])\n }\n valueLabelDisplay=\"auto\"\n valueLabelFormat={(value) => `$${value}`}\n getAriaLabel={(index) =>\n index === 0 ? 'Minimum price' : 'Maximum price'\n }\n />\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ whiteSpace: 'nowrap' }}\n >\n {`$${sliderMax}`}\n </Typography>\n </Box>\n ) : null}\n </Box>\n ) : null\n\n if (visible && visible.length === 0 && !hasCatalogControls) {\n return (\n <Box ref={ref} {...rest} sx={[{ p: 3, textAlign: 'center' }, ...nodeSx]}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {emptyText || 'No products here yet — check back soon.'}\n </Typography>\n </Box>\n )\n }\n // With controls visible the empty state renders inline, so a\n // no-result search still leaves the box available to clear.\n const emptyState = (\n <Box sx={{ p: 3, textAlign: 'center' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {query || activeType || selectedCategoryId || priceFilter\n ? 'No products match — try clearing a filter.'\n : emptyText || 'No products here yet — check back soon.'}\n </Typography>\n </Box>\n )\n const loadMore =\n hostId && pageLimit && nextOffset != null ? (\n <Box sx={{ display: 'flex', justifyContent: 'center', mt: 3 }}>\n <Button\n variant=\"outlined\"\n disabled={loadingMore}\n onClick={async () => {\n if (nextOffset == null || loadingMore) return\n setLoadingMore(true)\n await loadPage(nextOffset)\n setLoadingMore(false)\n }}\n >\n {loadingMore ? 'Loading…' : 'Load more'}\n </Button>\n </Box>\n ) : null\n\n const grid = (\n <Box sx={gridSx}>\n {(visible ?? []).map((item) => {\n // AGL-1726: resolved BEFORE the guard, so a stored value that is\n // truthy but resolves to nothing renders the placeholder rather\n // than an `<img>` with no `src`.\n const imageUrl = Aglyn.siteRelativeMediaSrc(item.imageUrl, { hostId })\n return (\n <Card key={item.id} variant=\"outlined\">\n <CardActionArea\n href={hostId ? `/products/${item.slug}` : undefined}\n disabled={!hostId}\n >\n {imageUrl ? (\n <CardMedia\n component=\"img\"\n image={imageUrl}\n alt={item.name}\n sx={{ height: 160, objectFit: 'cover' }}\n // Deferred (AGL-2486), and this is the worst offender of\n // the set: a grid renders one image PER PRODUCT, all of\n // them previously unhinted, so a storefront section below\n // the fold opened N eager default-priority fetches that\n // outranked everything above it.\n {...Aglyn.DEFERRED_IMAGE_ATTRIBUTES}\n />\n ) : (\n <Box sx={{ height: 160, bgcolor: 'action.hover' }} />\n )}\n <CardContent>\n <Typography variant=\"subtitle2\" noWrap>\n {item.name}\n </Typography>\n <Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {priceLabel(item)}\n </Typography>\n {item.compareAtPriceUsd ? (\n <Typography\n variant=\"caption\"\n color=\"text.disabled\"\n sx={{ textDecoration: 'line-through' }}\n >\n {`$${item.compareAtPriceUsd}`}\n </Typography>\n ) : null}\n {item.soldOut ? (\n <Chip label=\"Sold out\" size=\"small\" variant=\"outlined\" />\n ) : null}\n </Box>\n </CardContent>\n </CardActionArea>\n </Card>\n )\n })}\n </Box>\n )\n\n const body = visible && visible.length === 0 ? emptyState : grid\n if (!showFilters) {\n return (\n <Box ref={ref} {...rest}>\n {controls}\n {body}\n {loadMore}\n </Box>\n )\n }\n return (\n <Box ref={ref} {...rest}>\n {controls}\n <Box\n sx={{\n display: 'flex',\n gap: 1,\n flexWrap: 'wrap',\n alignItems: 'center',\n mb: 2,\n }}\n >\n <Chip\n label=\"In stock\"\n size=\"small\"\n variant={inStockOnly ? 'filled' : 'outlined'}\n color={inStockOnly ? 'primary' : 'default'}\n onClick={() => setInStockOnly((prev) => !prev)}\n />\n {facetTags.map((facetTag) => (\n <Chip\n key={facetTag}\n label={facetTag}\n size=\"small\"\n variant={activeTag === facetTag ? 'filled' : 'outlined'}\n color={activeTag === facetTag ? 'primary' : 'default'}\n onClick={() =>\n setActiveTag((prev) => (prev === facetTag ? '' : facetTag))\n }\n />\n ))}\n <Box sx={{ flex: 1 }} />\n <Chip\n label={\n sort === 'price-asc'\n ? 'Price ↑'\n : sort === 'price-desc'\n ? 'Price ↓'\n : 'A–Z'\n }\n size=\"small\"\n variant=\"outlined\"\n onClick={() =>\n setSort((prev) =>\n prev === 'price-asc'\n ? 'price-desc'\n : prev === 'price-desc'\n ? 'name'\n : 'price-asc',\n )\n }\n />\n </Box>\n {body}\n {loadMore}\n </Box>\n )\n },\n)\nProductGrid.displayName = 'AglynProductGrid'\n\nexport const schema: Aglyn.ComponentSchema<ProductGridProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Product grid',\n description:\n 'Your catalog as a grid, with optional search, category chips, sort and paging.',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiViewGridOutline.path, sx: { color: '#2e7d32' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'source',\n label: 'Show',\n description: 'Which products to list.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { label: 'All products', value: 'all' },\n { label: 'A collection', value: 'collection' },\n { label: 'A category', value: 'category' },\n { label: 'A tag', value: 'tag' },\n ],\n },\n {\n name: 'collectionId',\n label: 'Collection',\n description:\n 'Pick the collection — stored by id, so renaming it never breaks ' +\n 'this grid. Leave empty on collection template screens to follow ' +\n 'the /collections/{slug} URL.',\n component: Aglyn.FieldComponentType.COLLECTION_SELECT,\n },\n {\n name: 'collectionSlug',\n label: 'Collection slug (legacy)',\n description: 'Used only when no collection is picked above.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'categoryId',\n label: 'Category',\n description:\n 'Pick the category — stored by id, rename-safe.',\n component: Aglyn.FieldComponentType.CATEGORY_SELECT,\n },\n {\n name: 'categorySlug',\n label: 'Category slug (legacy)',\n description: 'Used only when no category is picked above.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'tag',\n label: 'Tag',\n description: 'Products tagged with this value.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'sort',\n label: 'Sort',\n description: 'Listing order.',\n component: Aglyn.FieldComponentType.SELECT,\n options: [\n { label: 'Name', value: 'name' },\n { label: 'Price (low → high)', value: 'price-asc' },\n { label: 'Price (high → low)', value: 'price-desc' },\n { label: 'Newest', value: 'newest' },\n ],\n },\n {\n name: 'columns',\n label: 'Columns',\n description: 'Desktop columns (1-6).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n {\n name: 'maxItems',\n label: 'Max items',\n description: 'Cap the number of cards.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n {\n name: 'emptyText',\n label: 'Empty text',\n description: 'Copy when nothing matches.',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n {\n name: 'showFilters',\n label: 'Show filters',\n description: 'Tag chips, in-stock toggle, and price sort above the grid.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n name: 'showSearch',\n label: 'Search box',\n description:\n 'Visitor search box above the grid — matches product names, ' +\n 'descriptions, and tags (server-side).',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n name: 'showCategories',\n label: 'Category chips',\n description:\n 'Filter chips built from your product categories, with an All chip.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n name: 'showSort',\n label: 'Sort select',\n description:\n 'Visitor sort: newest, name, price low→high, price high→low.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n name: 'showTypeFilter',\n label: 'Type filter',\n description: 'Physical / digital / services chips.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n name: 'showPriceFilter',\n label: 'Price filter',\n description:\n 'Price range slider between your lowest and highest product prices.',\n component: Aglyn.FieldComponentType.CHECKBOX,\n },\n {\n name: 'pageSize',\n label: 'Page size',\n description:\n 'Products per page with a Load more button; blank loads once ' +\n '(capped by Max items).',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n type: 'number',\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Product grid',\n pluginId: BUNDLE_ID,\n description: 'Responsive grid of catalog products',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiViewGridOutline.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: { source: 'all', sort: 'name', columns: 3 },\n },\n },\n {\n // Full shop page (AGL-561): the grid with every catalog control on\n // — search, category chips, sort, and Load more paging.\n $id: generatePresetId(ID, 'shop'),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Shop catalog',\n pluginId: BUNDLE_ID,\n description: 'Product grid with search, category chips, sort, and paging',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiViewGridOutline.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {\n source: 'all',\n sort: 'newest',\n columns: 3,\n showSearch: true,\n showCategories: true,\n showSort: true,\n pageSize: 12,\n },\n },\n },\n]\n\nexport default ProductGrid\n"],"names":["Aglyn","mdiMagnify","mdiViewGridOutline","Box","Button","Card","CardActionArea","CardContent","CardMedia","Chip","InputAdornment","MenuItem","Skeleton","Slider","SvgIcon","TextField","Typography","forwardRef","useCallback","useEffect","useRef","useState","BUNDLE_ID","generatePresetId","ID","SAMPLE_ITEMS","id","name","slug","priceUsd","maxPriceUsd","soldOut","compareAtPriceUsd","SAMPLE_CATEGORIES","SAMPLE_PRICE_BOUNDS","minCents","maxCents","TYPE_OPTIONS","value","label","SORT_OPTIONS","collectionSlugFromLocation","window","match","location","pathname","decodeURIComponent","priceLabel","item","ProductGrid","props","ref","site","source","collectionId","collectionSlug","collectionSlugProp","categoryId","categorySlug","tag","sort","sortProp","columns","maxItems","emptyText","showFilters","showSearch","showCategories","showSort","showTypeFilter","showPriceFilter","pageSize","rest","nodeSx","Array","isArray","useSite","hostId","nodeId","useNodeId","seed","pageData","commerce","grids","items","setItems","setSort","inStockOnly","setInStockOnly","activeTag","setActiveTag","searchInput","setSearchInput","query","setQuery","activeCategoryId","setActiveCategoryId","activeType","setActiveType","categories","setCategories","priceBounds","setPriceBounds","priceInput","setPriceInput","priceFilter","setPriceFilter","nextOffset","setNextOffset","loadingMore","setLoadingMore","fetchSeq","pageLimit","Number","Math","floor","pinnedCategoryId","timer","setTimeout","trim","clearTimeout","loadPage","offset","seq","current","params","URLSearchParams","set","effectiveCategoryId","String","limit","response","fetch","toString","payload","json","pageItems","prev","bounds","seededRef","Boolean","desktopColumns","min","max","gridSx","display","gap","gridTemplateColumns","xs","sm","md","visible","filter","tags","includes","facetTags","Set","flatMap","slice","sx","from","length","_item","index","variant","height","width","chipCategories","selectedCategoryId","hasCatalogControls","sliderBounds","sliderMin","sliderMax","ceil","showSlider","controls","flexDirection","mb","onChange","event","target","placeholder","size","fullWidth","slotProps","input","startAdornment","position","fontSize","color","path","d","htmlInput","type","flexWrap","alignItems","onClick","map","category","option","flex","select","some","minWidth","maxWidth","px","whiteSpace","step","disableSwap","disabled","_event","valueLabelDisplay","valueLabelFormat","getAriaLabel","p","textAlign","emptyState","loadMore","justifyContent","mt","grid","imageUrl","siteRelativeMediaSrc","href","undefined","component","image","alt","objectFit","DEFERRED_IMAGE_ATTRIBUTES","bgcolor","noWrap","textDecoration","body","facetTag","displayName","schema","$id","pluginId","description","ComponentCategory","COMMERCE","icon","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","FieldComponentType","SELECT","options","COLLECTION_SELECT","TEXT_FIELD","CATEGORY_SELECT","CHECKBOX","presets","NodeType","PRESET","data","componentId"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import * as Aglyn from '@aglyn/aglyn';
18
+ export declare const ID: Aglyn.ComponentId;
19
+ export interface ProductReviewsProps {
20
+ /** Product id; blank resolves from the /products/{slug} page product. */
21
+ productId?: string;
22
+ heading?: string;
23
+ }
24
+ /**
25
+ * Product reviews block (AGL-324): approved reviews with verified-buyer
26
+ * badges, seller replies, an aggregate summary (emitted as JSON-LD
27
+ * AggregateRating), and a submit form feeding the moderation queue.
28
+ */
29
+ declare const ProductReviews: import("react").ForwardRefExoticComponent<ProductReviewsProps & import("react").RefAttributes<HTMLDivElement>>;
30
+ export declare const schema: Aglyn.ComponentSchema<ProductReviewsProps>;
31
+ export declare const presets: Aglyn.PresetSchema[];
32
+ export default ProductReviews;
@@ -0,0 +1,349 @@
1
+ import { _ as _extends } from "@swc/helpers/_/_extends";
2
+ import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
3
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ /**
5
+ * @license
6
+ * Copyright 2026 Aglyn LLC
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ import * as Aglyn from "@aglyn/aglyn";
20
+ import { mdiStarOutline } from "@aglyn/shared-data-mdi";
21
+ import Alert from "@mui/material/Alert";
22
+ import Box from "@mui/material/Box";
23
+ import Button from "@mui/material/Button";
24
+ import Chip from "@mui/material/Chip";
25
+ import Divider from "@mui/material/Divider";
26
+ import Rating from "@mui/material/Rating";
27
+ import TextField from "@mui/material/TextField";
28
+ import Typography from "@mui/material/Typography";
29
+ import { forwardRef, useEffect, useState } from "react";
30
+ import { BUNDLE_ID } from "../constants/bundle-common.js";
31
+ import { generatePresetId } from "../utils/generate-preset-id.js";
32
+ // Component ids are persisted in screen documents; never rename.
33
+ export const ID = 'product-reviews';
34
+ async function resolveProductIdFromSlug(hostId) {
35
+ var _ref;
36
+ var _payload_product;
37
+ const match = window.location.pathname.match(/\/products\/([^/?#]+)/);
38
+ if (!match) return '';
39
+ const response = await fetch(`/api/commerce/product?hostId=${encodeURIComponent(hostId)}` + `&slug=${encodeURIComponent(decodeURIComponent(match[1]))}`).catch(()=>null);
40
+ if (!(response == null ? void 0 : response.ok)) return '';
41
+ const payload = await response.json().catch(()=>({}));
42
+ return String((_ref = payload == null ? void 0 : (_payload_product = payload.product) == null ? void 0 : _payload_product.id) != null ? _ref : '');
43
+ }
44
+ /**
45
+ * Product reviews block (AGL-324): approved reviews with verified-buyer
46
+ * badges, seller replies, an aggregate summary (emitted as JSON-LD
47
+ * AggregateRating), and a submit form feeding the moderation queue.
48
+ */ const ProductReviews = /*#__PURE__*/ forwardRef((props, ref)=>{
49
+ const { productId: productIdProp, heading } = props, rest = _object_without_properties_loose(props, [
50
+ "productId",
51
+ "heading"
52
+ ]);
53
+ // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).
54
+ const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [
55
+ props['sx']
56
+ ];
57
+ const { hostId } = Aglyn.useSite();
58
+ const siteFetch = Aglyn.useSiteFetch();
59
+ const [productId, setProductId] = useState(productIdProp != null ? productIdProp : '');
60
+ const [reviews, setReviews] = useState(null);
61
+ const [aggregate, setAggregate] = useState({
62
+ count: 0,
63
+ average: 0
64
+ });
65
+ const [form, setForm] = useState({
66
+ rating: 5,
67
+ body: '',
68
+ authorName: '',
69
+ authorEmail: ''
70
+ });
71
+ const [state, setState] = useState('idle');
72
+ useEffect(()=>{
73
+ if (!hostId) return;
74
+ let active = true;
75
+ void (async ()=>{
76
+ var _ref, _ref1;
77
+ const resolved = productIdProp || await resolveProductIdFromSlug(hostId);
78
+ if (!active || !resolved) return;
79
+ setProductId(resolved);
80
+ const response = await fetch(`/api/commerce/reviews?hostId=${encodeURIComponent(hostId)}` + `&productId=${encodeURIComponent(resolved)}`).catch(()=>null);
81
+ if (!active || !(response == null ? void 0 : response.ok)) return;
82
+ const payload = await response.json().catch(()=>({}));
83
+ setReviews((_ref = payload == null ? void 0 : payload.reviews) != null ? _ref : []);
84
+ setAggregate((_ref1 = payload == null ? void 0 : payload.aggregate) != null ? _ref1 : {
85
+ count: 0,
86
+ average: 0
87
+ });
88
+ })();
89
+ return ()=>{
90
+ active = false;
91
+ };
92
+ }, [
93
+ hostId,
94
+ productIdProp
95
+ ]);
96
+ const handleSubmit = async ()=>{
97
+ if (!hostId || !productId || state === 'busy') return;
98
+ setState('busy');
99
+ try {
100
+ const response = await siteFetch('/api/commerce/reviews', {
101
+ method: 'POST',
102
+ headers: {
103
+ 'Content-Type': 'application/json'
104
+ },
105
+ body: JSON.stringify(_extends({
106
+ hostId,
107
+ productId
108
+ }, form))
109
+ });
110
+ setState(response.ok ? 'done' : 'error');
111
+ } catch (unused) {
112
+ setState('error');
113
+ }
114
+ };
115
+ if (!hostId) {
116
+ return /*#__PURE__*/ _jsx(Box, _extends({
117
+ ref: ref
118
+ }, rest, {
119
+ sx: [
120
+ {
121
+ p: 3,
122
+ border: '1px dashed',
123
+ borderColor: 'divider',
124
+ borderRadius: 1,
125
+ color: 'text.secondary',
126
+ fontSize: 13,
127
+ fontFamily: 'system-ui, sans-serif'
128
+ },
129
+ ...nodeSx
130
+ ],
131
+ children: '★★★★★ Product reviews render here'
132
+ }));
133
+ }
134
+ return /*#__PURE__*/ _jsxs(Box, _extends({
135
+ ref: ref
136
+ }, rest, {
137
+ sx: [
138
+ {
139
+ display: 'flex',
140
+ flexDirection: 'column',
141
+ gap: 1.5
142
+ },
143
+ ...nodeSx
144
+ ],
145
+ children: [
146
+ /*#__PURE__*/ _jsxs(Typography, {
147
+ variant: "h6",
148
+ children: [
149
+ heading || 'Reviews',
150
+ aggregate.count > 0 ? ` (${aggregate.average} ★ · ${aggregate.count})` : ''
151
+ ]
152
+ }),
153
+ (reviews != null ? reviews : []).map((review)=>/*#__PURE__*/ _jsxs(Box, {
154
+ children: [
155
+ /*#__PURE__*/ _jsxs(Box, {
156
+ sx: {
157
+ display: 'flex',
158
+ gap: 1,
159
+ alignItems: 'center'
160
+ },
161
+ children: [
162
+ /*#__PURE__*/ _jsx(Rating, {
163
+ value: review.rating,
164
+ size: "small",
165
+ readOnly: true
166
+ }),
167
+ /*#__PURE__*/ _jsx(Typography, {
168
+ variant: "body2",
169
+ sx: {
170
+ fontWeight: 600
171
+ },
172
+ children: review.authorName
173
+ }),
174
+ review.verified ? /*#__PURE__*/ _jsx(Chip, {
175
+ label: "Verified buyer",
176
+ size: "small",
177
+ variant: "outlined",
178
+ color: "success"
179
+ }) : null
180
+ ]
181
+ }),
182
+ /*#__PURE__*/ _jsx(Typography, {
183
+ variant: "body2",
184
+ sx: {
185
+ mt: 0.5
186
+ },
187
+ children: review.body
188
+ }),
189
+ review.reply ? /*#__PURE__*/ _jsx(Typography, {
190
+ variant: "caption",
191
+ color: "text.secondary",
192
+ sx: {
193
+ display: 'block',
194
+ pl: 2,
195
+ mt: 0.5,
196
+ borderLeft: 2,
197
+ borderColor: 'divider'
198
+ },
199
+ children: `Seller: ${review.reply}`
200
+ }) : null,
201
+ /*#__PURE__*/ _jsx(Divider, {
202
+ sx: {
203
+ mt: 1.5
204
+ }
205
+ })
206
+ ]
207
+ }, review.id)),
208
+ reviews && reviews.length === 0 ? /*#__PURE__*/ _jsx(Typography, {
209
+ variant: "body2",
210
+ color: "text.secondary",
211
+ children: 'No reviews yet — be the first.'
212
+ }) : null,
213
+ state === 'done' ? /*#__PURE__*/ _jsx(Alert, {
214
+ severity: "success",
215
+ children: 'Thanks — your review is awaiting moderation.'
216
+ }) : /*#__PURE__*/ _jsxs(Box, {
217
+ sx: {
218
+ display: 'flex',
219
+ flexDirection: 'column',
220
+ gap: 1,
221
+ maxWidth: 480
222
+ },
223
+ children: [
224
+ /*#__PURE__*/ _jsx(Typography, {
225
+ variant: "subtitle2",
226
+ children: 'Write a review'
227
+ }),
228
+ /*#__PURE__*/ _jsx(Rating, {
229
+ value: form.rating,
230
+ onChange: (_event, value)=>setForm((prev)=>_extends({}, prev, {
231
+ rating: value != null ? value : 5
232
+ }))
233
+ }),
234
+ /*#__PURE__*/ _jsx(TextField, {
235
+ placeholder: "What did you think?",
236
+ value: form.body,
237
+ onChange: (event)=>setForm((prev)=>_extends({}, prev, {
238
+ body: event.target.value
239
+ })),
240
+ size: "small",
241
+ multiline: true,
242
+ minRows: 2
243
+ }),
244
+ /*#__PURE__*/ _jsxs(Box, {
245
+ sx: {
246
+ display: 'flex',
247
+ gap: 1
248
+ },
249
+ children: [
250
+ /*#__PURE__*/ _jsx(TextField, {
251
+ placeholder: "Name",
252
+ value: form.authorName,
253
+ onChange: (event)=>setForm((prev)=>_extends({}, prev, {
254
+ authorName: event.target.value
255
+ })),
256
+ size: "small",
257
+ sx: {
258
+ flex: 1
259
+ }
260
+ }),
261
+ /*#__PURE__*/ _jsx(TextField, {
262
+ placeholder: "Email (verifies your purchase)",
263
+ type: "email",
264
+ value: form.authorEmail,
265
+ onChange: (event)=>setForm((prev)=>_extends({}, prev, {
266
+ authorEmail: event.target.value
267
+ })),
268
+ size: "small",
269
+ sx: {
270
+ flex: 1.4
271
+ }
272
+ })
273
+ ]
274
+ }),
275
+ state === 'error' ? /*#__PURE__*/ _jsx(Alert, {
276
+ severity: "error",
277
+ children: 'Could not submit — check the fields.'
278
+ }) : null,
279
+ /*#__PURE__*/ _jsx(Button, {
280
+ variant: "outlined",
281
+ size: "small",
282
+ disabled: state === 'busy' || !form.body.trim() || !form.authorEmail.trim(),
283
+ onClick: handleSubmit,
284
+ sx: {
285
+ alignSelf: 'flex-start'
286
+ },
287
+ children: 'Submit review'
288
+ })
289
+ ]
290
+ })
291
+ ]
292
+ }));
293
+ });
294
+ ProductReviews.displayName = 'AglynProductReviews';
295
+ export const schema = {
296
+ $id: ID,
297
+ pluginId: BUNDLE_ID,
298
+ displayName: 'Product reviews',
299
+ description: 'Approved reviews with verified-buyer badges, and a form to add one.',
300
+ category: Aglyn.ComponentCategory.COMMERCE,
301
+ icon: {
302
+ path: mdiStarOutline.path,
303
+ sx: {
304
+ color: '#2e7d32'
305
+ }
306
+ },
307
+ flags: {
308
+ selfClosing: Aglyn.FEATURE_FLAG.ENABLED
309
+ },
310
+ attributes: [
311
+ {
312
+ name: 'productId',
313
+ label: 'Product id',
314
+ description: 'Whose reviews these are. Blank reads the product from the URL, ' + 'which is what you want on a product template; naming one pins the ' + 'block to that product wherever it is placed.',
315
+ component: Aglyn.FieldComponentType.PRODUCT_SELECT
316
+ },
317
+ {
318
+ name: 'heading',
319
+ label: 'Heading',
320
+ description: 'Defaults to "Reviews".',
321
+ component: Aglyn.FieldComponentType.TEXT_FIELD
322
+ }
323
+ ]
324
+ };
325
+ export const presets = [
326
+ {
327
+ $id: generatePresetId(ID),
328
+ type: Aglyn.NodeType.PRESET,
329
+ displayName: 'Product reviews',
330
+ pluginId: BUNDLE_ID,
331
+ description: 'Verified-buyer reviews with a submit form',
332
+ category: Aglyn.ComponentCategory.COMMERCE,
333
+ icon: {
334
+ path: mdiStarOutline.path,
335
+ sx: {
336
+ color: '#2e7d32'
337
+ }
338
+ },
339
+ data: {
340
+ $id: null,
341
+ componentId: ID,
342
+ pluginId: BUNDLE_ID,
343
+ props: {}
344
+ }
345
+ }
346
+ ];
347
+ export default ProductReviews;
348
+
349
+ //# sourceMappingURL=product-reviews.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/components/product-reviews.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\nimport * as Aglyn from '@aglyn/aglyn'\nimport { mdiStarOutline } from '@aglyn/shared-data-mdi'\nimport Alert from '@mui/material/Alert'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Chip from '@mui/material/Chip'\nimport Divider from '@mui/material/Divider'\nimport Rating from '@mui/material/Rating'\nimport TextField from '@mui/material/TextField'\nimport Typography from '@mui/material/Typography'\nimport { forwardRef, useEffect, useState } from 'react'\nimport { BUNDLE_ID } from '../constants/bundle-common'\nimport { generatePresetId } from '../utils/generate-preset-id'\n\n// Component ids are persisted in screen documents; never rename.\nexport const ID: Aglyn.ComponentId = 'product-reviews'\n\nexport interface ProductReviewsProps {\n /** Product id; blank resolves from the /products/{slug} page product. */\n productId?: string\n heading?: string\n}\n\ninterface ReviewView {\n id: string\n rating: number\n body: string\n authorName: string\n verified: boolean\n reply?: string | null\n createdAtMs: number\n}\n\nasync function resolveProductIdFromSlug(hostId: string): Promise<string> {\n const match = window.location.pathname.match(/\\/products\\/([^/?#]+)/)\n if (!match) return ''\n const response = await fetch(\n `/api/commerce/product?hostId=${encodeURIComponent(hostId)}` +\n `&slug=${encodeURIComponent(decodeURIComponent(match[1]))}`,\n ).catch(() => null)\n if (!response?.ok) return ''\n const payload = await response.json().catch(() => ({}))\n return String(payload?.product?.id ?? '')\n}\n\n/**\n * Product reviews block (AGL-324): approved reviews with verified-buyer\n * badges, seller replies, an aggregate summary (emitted as JSON-LD\n * AggregateRating), and a submit form feeding the moderation queue.\n */\nconst ProductReviews = forwardRef<HTMLDivElement, ProductReviewsProps>(\n (props, ref) => {\n const { productId: productIdProp, heading, ...rest } = props\n // Node styles ride the renderer-merged sx; recompose (stack.ts pattern).\n const nodeSx = Array.isArray(props['sx']) ? props['sx'] : [props['sx']]\n const { hostId } = Aglyn.useSite()\n const siteFetch = Aglyn.useSiteFetch()\n const [productId, setProductId] = useState(productIdProp ?? '')\n const [reviews, setReviews] = useState<ReviewView[] | null>(null)\n const [aggregate, setAggregate] = useState({ count: 0, average: 0 })\n const [form, setForm] = useState({\n rating: 5,\n body: '',\n authorName: '',\n authorEmail: '',\n })\n const [state, setState] = useState<'idle' | 'busy' | 'done' | 'error'>(\n 'idle',\n )\n\n useEffect(() => {\n if (!hostId) return\n let active = true\n void (async () => {\n const resolved =\n productIdProp || (await resolveProductIdFromSlug(hostId))\n if (!active || !resolved) return\n setProductId(resolved)\n const response = await fetch(\n `/api/commerce/reviews?hostId=${encodeURIComponent(hostId)}` +\n `&productId=${encodeURIComponent(resolved)}`,\n ).catch(() => null)\n if (!active || !response?.ok) return\n const payload = await response.json().catch(() => ({}))\n setReviews(payload?.reviews ?? [])\n setAggregate(payload?.aggregate ?? { count: 0, average: 0 })\n })()\n return () => {\n active = false\n }\n }, [hostId, productIdProp])\n\n const handleSubmit = async () => {\n if (!hostId || !productId || state === 'busy') return\n setState('busy')\n try {\n const response = await siteFetch('/api/commerce/reviews', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ hostId, productId, ...form }),\n })\n setState(response.ok ? 'done' : 'error')\n } catch {\n setState('error')\n }\n }\n\n if (!hostId) {\n return (\n <Box\n ref={ref}\n {...rest}\n sx={[\n {\n p: 3,\n border: '1px dashed',\n borderColor: 'divider',\n borderRadius: 1,\n color: 'text.secondary',\n fontSize: 13,\n fontFamily: 'system-ui, sans-serif',\n },\n ...nodeSx,\n ]}\n >\n {'★★★★★ Product reviews render here'}\n </Box>\n )\n }\n\n return (\n <Box ref={ref} {...rest} sx={[{ display: 'flex', flexDirection: 'column', gap: 1.5 }, ...nodeSx]}>\n {/* No JSON-LD here any more (AGL-686). This block used to emit a\n free-standing `AggregateRating` node, which schema.org ignores —\n a rating has to be a PROPERTY of the Product it rates. The PDP's\n server-rendered Product node now carries `aggregateRating`,\n built from the same `readProductReviews` reader this block's API\n uses, so the structured data and the visible stars cannot\n disagree. It also removes the one call site that was primed to\n become stored XSS the moment a reviewer name went into it. */}\n <Typography variant=\"h6\">\n {heading || 'Reviews'}\n {aggregate.count > 0 ? ` (${aggregate.average} ★ · ${aggregate.count})` : ''}\n </Typography>\n {(reviews ?? []).map((review) => (\n <Box key={review.id}>\n <Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>\n <Rating value={review.rating} size=\"small\" readOnly />\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>\n {review.authorName}\n </Typography>\n {review.verified ? (\n <Chip label=\"Verified buyer\" size=\"small\" variant=\"outlined\" color=\"success\" />\n ) : null}\n </Box>\n <Typography variant=\"body2\" sx={{ mt: 0.5 }}>\n {review.body}\n </Typography>\n {review.reply ? (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', pl: 2, mt: 0.5, borderLeft: 2, borderColor: 'divider' }}\n >\n {`Seller: ${review.reply}`}\n </Typography>\n ) : null}\n <Divider sx={{ mt: 1.5 }} />\n </Box>\n ))}\n {reviews && reviews.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No reviews yet — be the first.'}\n </Typography>\n ) : null}\n {state === 'done' ? (\n <Alert severity=\"success\">\n {'Thanks — your review is awaiting moderation.'}\n </Alert>\n ) : (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1, maxWidth: 480 }}>\n <Typography variant=\"subtitle2\">{'Write a review'}</Typography>\n <Rating\n value={form.rating}\n onChange={(_event, value) =>\n setForm((prev) => ({ ...prev, rating: value ?? 5 }))\n }\n />\n <TextField\n placeholder=\"What did you think?\"\n value={form.body}\n onChange={(event) =>\n setForm((prev) => ({ ...prev, body: event.target.value }))\n }\n size=\"small\"\n multiline\n minRows={2}\n />\n <Box sx={{ display: 'flex', gap: 1 }}>\n <TextField\n placeholder=\"Name\"\n value={form.authorName}\n onChange={(event) =>\n setForm((prev) => ({ ...prev, authorName: event.target.value }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <TextField\n placeholder=\"Email (verifies your purchase)\"\n type=\"email\"\n value={form.authorEmail}\n onChange={(event) =>\n setForm((prev) => ({ ...prev, authorEmail: event.target.value }))\n }\n size=\"small\"\n sx={{ flex: 1.4 }}\n />\n </Box>\n {state === 'error' ? (\n <Alert severity=\"error\">{'Could not submit — check the fields.'}</Alert>\n ) : null}\n <Button\n variant=\"outlined\"\n size=\"small\"\n disabled={state === 'busy' || !form.body.trim() || !form.authorEmail.trim()}\n onClick={handleSubmit}\n sx={{ alignSelf: 'flex-start' }}\n >\n {'Submit review'}\n </Button>\n </Box>\n )}\n </Box>\n )\n },\n)\nProductReviews.displayName = 'AglynProductReviews'\n\nexport const schema: Aglyn.ComponentSchema<ProductReviewsProps> = {\n $id: ID,\n pluginId: BUNDLE_ID,\n displayName: 'Product reviews',\n description:\n 'Approved reviews with verified-buyer badges, and a form to add one.',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiStarOutline.path, sx: { color: '#2e7d32' } },\n flags: { selfClosing: Aglyn.FEATURE_FLAG.ENABLED },\n attributes: [\n {\n name: 'productId',\n label: 'Product id',\n description:\n 'Whose reviews these are. Blank reads the product from the URL, ' +\n 'which is what you want on a product template; naming one pins the ' +\n 'block to that product wherever it is placed.',\n component: Aglyn.FieldComponentType.PRODUCT_SELECT,\n },\n {\n name: 'heading',\n label: 'Heading',\n description: 'Defaults to \"Reviews\".',\n component: Aglyn.FieldComponentType.TEXT_FIELD,\n },\n ],\n}\n\nexport const presets: Aglyn.PresetSchema[] = [\n {\n $id: generatePresetId(ID),\n type: Aglyn.NodeType.PRESET,\n displayName: 'Product reviews',\n pluginId: BUNDLE_ID,\n description: 'Verified-buyer reviews with a submit form',\n category: Aglyn.ComponentCategory.COMMERCE,\n icon: { path: mdiStarOutline.path, sx: { color: '#2e7d32' } },\n data: {\n $id: null,\n componentId: ID,\n pluginId: BUNDLE_ID,\n props: {},\n },\n },\n]\n\nexport default ProductReviews\n"],"names":["Aglyn","mdiStarOutline","Alert","Box","Button","Chip","Divider","Rating","TextField","Typography","forwardRef","useEffect","useState","BUNDLE_ID","generatePresetId","ID","resolveProductIdFromSlug","hostId","payload","match","window","location","pathname","response","fetch","encodeURIComponent","decodeURIComponent","catch","ok","json","String","product","id","ProductReviews","props","ref","productId","productIdProp","heading","rest","nodeSx","Array","isArray","useSite","siteFetch","useSiteFetch","setProductId","reviews","setReviews","aggregate","setAggregate","count","average","form","setForm","rating","body","authorName","authorEmail","state","setState","active","resolved","handleSubmit","method","headers","JSON","stringify","sx","p","border","borderColor","borderRadius","color","fontSize","fontFamily","display","flexDirection","gap","variant","map","review","alignItems","value","size","readOnly","fontWeight","verified","label","mt","reply","pl","borderLeft","length","severity","maxWidth","onChange","_event","prev","placeholder","event","target","multiline","minRows","flex","type","disabled","trim","onClick","alignSelf","displayName","schema","$id","pluginId","description","category","ComponentCategory","COMMERCE","icon","path","flags","selfClosing","FEATURE_FLAG","ENABLED","attributes","name","component","FieldComponentType","PRODUCT_SELECT","TEXT_FIELD","presets","NodeType","PRESET","data","componentId"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import * as Aglyn from '@aglyn/aglyn';
18
+ export declare const ID: Aglyn.ComponentId;
19
+ export interface RelatedProductsProps {
20
+ /** Anchor product id; blank follows the /products/{slug} page. */
21
+ productId?: string;
22
+ heading?: string;
23
+ maxItems?: number;
24
+ }
25
+ /**
26
+ * Related products / upsell strip (AGL-325): the product's manual list,
27
+ * else "frequently bought together" from recent orders, else tag and
28
+ * category neighbors — resolved server-side, rendered as cards.
29
+ */
30
+ declare const RelatedProducts: import("react").ForwardRefExoticComponent<RelatedProductsProps & import("react").RefAttributes<HTMLDivElement>>;
31
+ export declare const schema: Aglyn.ComponentSchema<RelatedProductsProps>;
32
+ export declare const presets: Aglyn.PresetSchema[];
33
+ export default RelatedProducts;