@libreapps/commerce 7.5.1

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 (327) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/CHANGELOG.md +13 -0
  3. package/LICENSE.md +21 -0
  4. package/components/Icons.tsx +35 -0
  5. package/components/add-to-cart-widget.tsx +183 -0
  6. package/components/buy/buy-card.tsx +259 -0
  7. package/components/buy/carousel-buy-card.tsx +242 -0
  8. package/components/buy/multi-family/all-variants-carousel.tsx +261 -0
  9. package/components/buy/multi-family/family-carousel/index.tsx +77 -0
  10. package/components/buy/multi-family/family-carousel/slide.tsx +83 -0
  11. package/components/buy/multi-family/family-carousel/state.ts +87 -0
  12. package/components/buy/multi-family/index.ts +2 -0
  13. package/components/buy/single-family-selector.tsx +90 -0
  14. package/components/buy/title-and-byline.tsx +25 -0
  15. package/components/cart/cart-panel/cart-line-item.tsx +76 -0
  16. package/components/cart/cart-panel/index.tsx +154 -0
  17. package/components/cart/cart-panel/promo-code.tsx +109 -0
  18. package/components/cart/cart-panel/total-area.tsx +60 -0
  19. package/components/checkout/payment-step-form/card-icon-row.tsx +26 -0
  20. package/components/checkout/payment-step-form/card-icons/amex.tsx +32 -0
  21. package/components/checkout/payment-step-form/card-icons/diners-club.tsx +13 -0
  22. package/components/checkout/payment-step-form/card-icons/discover.tsx +25 -0
  23. package/components/checkout/payment-step-form/card-icons/jcb.tsx +26 -0
  24. package/components/checkout/payment-step-form/card-icons/mastercard.tsx +27 -0
  25. package/components/checkout/payment-step-form/card-icons/visa.tsx +25 -0
  26. package/components/checkout/payment-step-form/cc-button.tsx +17 -0
  27. package/components/checkout/payment-step-form/contact-form.tsx +50 -0
  28. package/components/checkout/payment-step-form/crypto-icons/btc.tsx +11 -0
  29. package/components/checkout/payment-step-form/crypto-icons/eth.tsx +20 -0
  30. package/components/checkout/payment-step-form/crypto-icons/usdt.tsx +13 -0
  31. package/components/checkout/payment-step-form/index.tsx +122 -0
  32. package/components/checkout/payment-step-form/methods/bank-transfer.tsx +79 -0
  33. package/components/checkout/payment-step-form/methods/card.tsx +232 -0
  34. package/components/checkout/payment-step-form/methods/crypto.tsx +227 -0
  35. package/components/checkout/payment-step-form/methods/index.ts +23 -0
  36. package/components/checkout/shipping-step-form.tsx +175 -0
  37. package/components/index.ts +11 -0
  38. package/components/item/product-card.tsx +48 -0
  39. package/components/item-selector/button.tsx +188 -0
  40. package/components/item-selector/carousel/index.tsx +197 -0
  41. package/components/item-selector/carousel/slider.tsx +40 -0
  42. package/components/item-selector/index.ts +5 -0
  43. package/components/item-selector/quantity-indicator.tsx +48 -0
  44. package/components/node-tabs/index.tsx +91 -0
  45. package/components/node-tabs/node-image.tsx +31 -0
  46. package/dist/components/Icons.d.ts +18 -0
  47. package/dist/components/Icons.js +19 -0
  48. package/dist/components/Icons.js.map +1 -0
  49. package/dist/components/add-to-cart-widget.d.ts +11 -0
  50. package/dist/components/add-to-cart-widget.js +85 -0
  51. package/dist/components/add-to-cart-widget.js.map +1 -0
  52. package/dist/components/buy/buy-card.d.ts +30 -0
  53. package/dist/components/buy/buy-card.js +109 -0
  54. package/dist/components/buy/buy-card.js.map +1 -0
  55. package/dist/components/buy/carousel-buy-card.d.ts +12 -0
  56. package/dist/components/buy/carousel-buy-card.js +94 -0
  57. package/dist/components/buy/carousel-buy-card.js.map +1 -0
  58. package/dist/components/buy/multi-family/all-variants-carousel.d.ts +4 -0
  59. package/dist/components/buy/multi-family/all-variants-carousel.js +115 -0
  60. package/dist/components/buy/multi-family/all-variants-carousel.js.map +1 -0
  61. package/dist/components/buy/multi-family/family-carousel/index.d.ts +4 -0
  62. package/dist/components/buy/multi-family/family-carousel/index.js +27 -0
  63. package/dist/components/buy/multi-family/family-carousel/index.js.map +1 -0
  64. package/dist/components/buy/multi-family/family-carousel/slide.d.ts +11 -0
  65. package/dist/components/buy/multi-family/family-carousel/slide.js +35 -0
  66. package/dist/components/buy/multi-family/family-carousel/slide.js.map +1 -0
  67. package/dist/components/buy/multi-family/family-carousel/state.d.ts +20 -0
  68. package/dist/components/buy/multi-family/family-carousel/state.js +59 -0
  69. package/dist/components/buy/multi-family/family-carousel/state.js.map +1 -0
  70. package/dist/components/buy/multi-family/index.d.ts +2 -0
  71. package/dist/components/buy/multi-family/index.js +3 -0
  72. package/dist/components/buy/multi-family/index.js.map +1 -0
  73. package/dist/components/buy/single-family-selector.d.ts +15 -0
  74. package/dist/components/buy/single-family-selector.js +28 -0
  75. package/dist/components/buy/single-family-selector.js.map +1 -0
  76. package/dist/components/buy/title-and-byline.d.ts +8 -0
  77. package/dist/components/buy/title-and-byline.js +7 -0
  78. package/dist/components/buy/title-and-byline.js.map +1 -0
  79. package/dist/components/cart/cart-panel/cart-line-item.d.ts +11 -0
  80. package/dist/components/cart/cart-panel/cart-line-item.js +25 -0
  81. package/dist/components/cart/cart-panel/cart-line-item.js.map +1 -0
  82. package/dist/components/cart/cart-panel/index.d.ts +19 -0
  83. package/dist/components/cart/cart-panel/index.js +65 -0
  84. package/dist/components/cart/cart-panel/index.js.map +1 -0
  85. package/dist/components/cart/cart-panel/promo-code.d.ts +4 -0
  86. package/dist/components/cart/cart-panel/promo-code.js +62 -0
  87. package/dist/components/cart/cart-panel/promo-code.js.map +1 -0
  88. package/dist/components/cart/cart-panel/total-area.d.ts +7 -0
  89. package/dist/components/cart/cart-panel/total-area.js +14 -0
  90. package/dist/components/cart/cart-panel/total-area.js.map +1 -0
  91. package/dist/components/checkout/payment-step-form/card-icon-row.d.ts +2 -0
  92. package/dist/components/checkout/payment-step-form/card-icon-row.js +14 -0
  93. package/dist/components/checkout/payment-step-form/card-icon-row.js.map +1 -0
  94. package/dist/components/checkout/payment-step-form/card-icons/amex.d.ts +4 -0
  95. package/dist/components/checkout/payment-step-form/card-icons/amex.js +6 -0
  96. package/dist/components/checkout/payment-step-form/card-icons/amex.js.map +1 -0
  97. package/dist/components/checkout/payment-step-form/card-icons/diners-club.d.ts +4 -0
  98. package/dist/components/checkout/payment-step-form/card-icons/diners-club.js +6 -0
  99. package/dist/components/checkout/payment-step-form/card-icons/diners-club.js.map +1 -0
  100. package/dist/components/checkout/payment-step-form/card-icons/discover.d.ts +4 -0
  101. package/dist/components/checkout/payment-step-form/card-icons/discover.js +6 -0
  102. package/dist/components/checkout/payment-step-form/card-icons/discover.js.map +1 -0
  103. package/dist/components/checkout/payment-step-form/card-icons/jcb.d.ts +4 -0
  104. package/dist/components/checkout/payment-step-form/card-icons/jcb.js +6 -0
  105. package/dist/components/checkout/payment-step-form/card-icons/jcb.js.map +1 -0
  106. package/dist/components/checkout/payment-step-form/card-icons/mastercard.d.ts +4 -0
  107. package/dist/components/checkout/payment-step-form/card-icons/mastercard.js +6 -0
  108. package/dist/components/checkout/payment-step-form/card-icons/mastercard.js.map +1 -0
  109. package/dist/components/checkout/payment-step-form/card-icons/visa.d.ts +4 -0
  110. package/dist/components/checkout/payment-step-form/card-icons/visa.js +6 -0
  111. package/dist/components/checkout/payment-step-form/card-icons/visa.js.map +1 -0
  112. package/dist/components/checkout/payment-step-form/cc-button.d.ts +3 -0
  113. package/dist/components/checkout/payment-step-form/cc-button.js +6 -0
  114. package/dist/components/checkout/payment-step-form/cc-button.js.map +1 -0
  115. package/dist/components/checkout/payment-step-form/contact-form.d.ts +5 -0
  116. package/dist/components/checkout/payment-step-form/contact-form.js +6 -0
  117. package/dist/components/checkout/payment-step-form/contact-form.js.map +1 -0
  118. package/dist/components/checkout/payment-step-form/crypto-icons/btc.d.ts +4 -0
  119. package/dist/components/checkout/payment-step-form/crypto-icons/btc.js +6 -0
  120. package/dist/components/checkout/payment-step-form/crypto-icons/btc.js.map +1 -0
  121. package/dist/components/checkout/payment-step-form/crypto-icons/eth.d.ts +4 -0
  122. package/dist/components/checkout/payment-step-form/crypto-icons/eth.js +6 -0
  123. package/dist/components/checkout/payment-step-form/crypto-icons/eth.js.map +1 -0
  124. package/dist/components/checkout/payment-step-form/crypto-icons/usdt.d.ts +4 -0
  125. package/dist/components/checkout/payment-step-form/crypto-icons/usdt.js +6 -0
  126. package/dist/components/checkout/payment-step-form/crypto-icons/usdt.js.map +1 -0
  127. package/dist/components/checkout/payment-step-form/index.d.ts +4 -0
  128. package/dist/components/checkout/payment-step-form/index.js +77 -0
  129. package/dist/components/checkout/payment-step-form/index.js.map +1 -0
  130. package/dist/components/checkout/payment-step-form/methods/bank-transfer.d.ts +4 -0
  131. package/dist/components/checkout/payment-step-form/methods/bank-transfer.js +24 -0
  132. package/dist/components/checkout/payment-step-form/methods/bank-transfer.js.map +1 -0
  133. package/dist/components/checkout/payment-step-form/methods/card.d.ts +4 -0
  134. package/dist/components/checkout/payment-step-form/methods/card.js +160 -0
  135. package/dist/components/checkout/payment-step-form/methods/card.js.map +1 -0
  136. package/dist/components/checkout/payment-step-form/methods/crypto.d.ts +9 -0
  137. package/dist/components/checkout/payment-step-form/methods/crypto.js +137 -0
  138. package/dist/components/checkout/payment-step-form/methods/crypto.js.map +1 -0
  139. package/dist/components/checkout/payment-step-form/methods/index.d.ts +6 -0
  140. package/dist/components/checkout/payment-step-form/methods/index.js +21 -0
  141. package/dist/components/checkout/payment-step-form/methods/index.js.map +1 -0
  142. package/dist/components/checkout/shipping-step-form.d.ts +3 -0
  143. package/dist/components/checkout/shipping-step-form.js +53 -0
  144. package/dist/components/checkout/shipping-step-form.js.map +1 -0
  145. package/dist/components/index.d.ts +8 -0
  146. package/dist/components/index.js +9 -0
  147. package/dist/components/index.js.map +1 -0
  148. package/dist/components/item/product-card.d.ts +7 -0
  149. package/dist/components/item/product-card.js +9 -0
  150. package/dist/components/item/product-card.js.map +1 -0
  151. package/dist/components/item-selector/button.d.ts +4 -0
  152. package/dist/components/item-selector/button.js +47 -0
  153. package/dist/components/item-selector/button.js.map +1 -0
  154. package/dist/components/item-selector/carousel/index.d.ts +12 -0
  155. package/dist/components/item-selector/carousel/index.js +74 -0
  156. package/dist/components/item-selector/carousel/index.js.map +1 -0
  157. package/dist/components/item-selector/carousel/slider.d.ts +8 -0
  158. package/dist/components/item-selector/carousel/slider.js +12 -0
  159. package/dist/components/item-selector/carousel/slider.js.map +1 -0
  160. package/dist/components/item-selector/index.d.ts +2 -0
  161. package/dist/components/item-selector/index.js +3 -0
  162. package/dist/components/item-selector/index.js.map +1 -0
  163. package/dist/components/item-selector/quantity-indicator.d.ts +9 -0
  164. package/dist/components/item-selector/quantity-indicator.js +16 -0
  165. package/dist/components/item-selector/quantity-indicator.js.map +1 -0
  166. package/dist/components/node-tabs/index.d.ts +14 -0
  167. package/dist/components/node-tabs/index.js +42 -0
  168. package/dist/components/node-tabs/index.js.map +1 -0
  169. package/dist/components/node-tabs/node-image.d.ts +6 -0
  170. package/dist/components/node-tabs/node-image.js +13 -0
  171. package/dist/components/node-tabs/node-image.js.map +1 -0
  172. package/dist/index.d.ts +5 -0
  173. package/dist/index.js +5 -0
  174. package/dist/index.js.map +1 -0
  175. package/dist/service/context.d.ts +8 -0
  176. package/dist/service/context.js +19 -0
  177. package/dist/service/context.js.map +1 -0
  178. package/dist/service/debug.d.ts +10 -0
  179. package/dist/service/debug.js +30 -0
  180. package/dist/service/debug.js.map +1 -0
  181. package/dist/service/impls/standalone/actual-line-item.d.ts +40 -0
  182. package/dist/service/impls/standalone/actual-line-item.js +84 -0
  183. package/dist/service/impls/standalone/actual-line-item.js.map +1 -0
  184. package/dist/service/impls/standalone/get-instance.d.ts +2 -0
  185. package/dist/service/impls/standalone/get-instance.js +39 -0
  186. package/dist/service/impls/standalone/get-instance.js.map +1 -0
  187. package/dist/service/impls/standalone/index.d.ts +67 -0
  188. package/dist/service/impls/standalone/index.js +416 -0
  189. package/dist/service/impls/standalone/index.js.map +1 -0
  190. package/dist/service/impls/standalone/order/firebase.d.ts +2 -0
  191. package/dist/service/impls/standalone/order/firebase.js +13 -0
  192. package/dist/service/impls/standalone/order/firebase.js.map +1 -0
  193. package/dist/service/impls/standalone/order/index.d.ts +24 -0
  194. package/dist/service/impls/standalone/order/index.js +61 -0
  195. package/dist/service/impls/standalone/order/index.js.map +1 -0
  196. package/dist/service/impls/standalone/persistence.d.ts +4 -0
  197. package/dist/service/impls/standalone/persistence.js +22 -0
  198. package/dist/service/impls/standalone/persistence.js.map +1 -0
  199. package/dist/service/path-utils.d.ts +7 -0
  200. package/dist/service/path-utils.js +16 -0
  201. package/dist/service/path-utils.js.map +1 -0
  202. package/dist/service/sep.d.ts +6 -0
  203. package/dist/service/sep.js +6 -0
  204. package/dist/service/sep.js.map +1 -0
  205. package/dist/types/category-node.d.ts +36 -0
  206. package/dist/types/category-node.js +2 -0
  207. package/dist/types/category-node.js.map +1 -0
  208. package/dist/types/checkout.d.ts +33 -0
  209. package/dist/types/checkout.js +2 -0
  210. package/dist/types/checkout.js.map +1 -0
  211. package/dist/types/commerce-config.d.ts +11 -0
  212. package/dist/types/commerce-config.js +2 -0
  213. package/dist/types/commerce-config.js.map +1 -0
  214. package/dist/types/commerce-service.d.ts +109 -0
  215. package/dist/types/commerce-service.js +2 -0
  216. package/dist/types/commerce-service.js.map +1 -0
  217. package/dist/types/family.d.ts +16 -0
  218. package/dist/types/family.js +2 -0
  219. package/dist/types/family.js.map +1 -0
  220. package/dist/types/index.d.ts +13 -0
  221. package/dist/types/index.js +8 -0
  222. package/dist/types/index.js.map +1 -0
  223. package/dist/types/item-selector.d.ts +72 -0
  224. package/dist/types/item-selector.js +2 -0
  225. package/dist/types/item-selector.js.map +1 -0
  226. package/dist/types/line-item.d.ts +14 -0
  227. package/dist/types/line-item.js +2 -0
  228. package/dist/types/line-item.js.map +1 -0
  229. package/dist/types/multi-family-selector-props.d.ts +16 -0
  230. package/dist/types/multi-family-selector-props.js +2 -0
  231. package/dist/types/multi-family-selector-props.js.map +1 -0
  232. package/dist/types/product.d.ts +15 -0
  233. package/dist/types/product.js +2 -0
  234. package/dist/types/product.js.map +1 -0
  235. package/dist/types/promo.d.ts +7 -0
  236. package/dist/types/promo.js +2 -0
  237. package/dist/types/promo.js.map +1 -0
  238. package/dist/types/selection-ui-specifier.d.ts +40 -0
  239. package/dist/types/selection-ui-specifier.js +2 -0
  240. package/dist/types/selection-ui-specifier.js.map +1 -0
  241. package/dist/types/string-mutator.d.ts +9 -0
  242. package/dist/types/string-mutator.js +2 -0
  243. package/dist/types/string-mutator.js.map +1 -0
  244. package/dist/types/token-separators.d.ts +6 -0
  245. package/dist/types/token-separators.js +2 -0
  246. package/dist/types/token-separators.js.map +1 -0
  247. package/dist/util/analytics.d.ts +9 -0
  248. package/dist/util/analytics.js +10 -0
  249. package/dist/util/analytics.js.map +1 -0
  250. package/dist/util/countries.d.ts +7 -0
  251. package/dist/util/countries.js +197 -0
  252. package/dist/util/countries.js.map +1 -0
  253. package/dist/util/error.d.ts +1 -0
  254. package/dist/util/error.js +22 -0
  255. package/dist/util/error.js.map +1 -0
  256. package/dist/util/index.d.ts +15 -0
  257. package/dist/util/index.js +54 -0
  258. package/dist/util/index.js.map +1 -0
  259. package/dist/util/item-selector-options-accessor.d.ts +3 -0
  260. package/dist/util/item-selector-options-accessor.js +27 -0
  261. package/dist/util/item-selector-options-accessor.js.map +1 -0
  262. package/dist/util/line-item-ref.d.ts +8 -0
  263. package/dist/util/line-item-ref.js +15 -0
  264. package/dist/util/line-item-ref.js.map +1 -0
  265. package/dist/util/multi-family-selector-options-accessor.d.ts +3 -0
  266. package/dist/util/multi-family-selector-options-accessor.js +11 -0
  267. package/dist/util/multi-family-selector-options-accessor.js.map +1 -0
  268. package/dist/util/obs-string-mutator.d.ts +8 -0
  269. package/dist/util/obs-string-mutator.js +15 -0
  270. package/dist/util/obs-string-mutator.js.map +1 -0
  271. package/dist/util/product-media-accessor.d.ts +29 -0
  272. package/dist/util/product-media-accessor.js +22 -0
  273. package/dist/util/product-media-accessor.js.map +1 -0
  274. package/dist/util/promo-codes.d.ts +3 -0
  275. package/dist/util/promo-codes.js +100 -0
  276. package/dist/util/promo-codes.js.map +1 -0
  277. package/dist/util/selection-ui-specifiers.d.ts +3 -0
  278. package/dist/util/selection-ui-specifiers.js +24 -0
  279. package/dist/util/selection-ui-specifiers.js.map +1 -0
  280. package/dist/util/square-payment.d.ts +7 -0
  281. package/dist/util/square-payment.js +37 -0
  282. package/dist/util/square-payment.js.map +1 -0
  283. package/dist/util/use-sync-sku-param-w-current-item.d.ts +2 -0
  284. package/dist/util/use-sync-sku-param-w-current-item.js +61 -0
  285. package/dist/util/use-sync-sku-param-w-current-item.js.map +1 -0
  286. package/index.ts +13 -0
  287. package/libreapps-ui.d.ts +108 -0
  288. package/package.json +67 -0
  289. package/service/context.tsx +45 -0
  290. package/service/debug.ts +41 -0
  291. package/service/impls/standalone/actual-line-item.ts +136 -0
  292. package/service/impls/standalone/get-instance.ts +64 -0
  293. package/service/impls/standalone/index.ts +579 -0
  294. package/service/impls/standalone/order/firebase.ts +14 -0
  295. package/service/impls/standalone/order/index.ts +129 -0
  296. package/service/impls/standalone/persistence.ts +33 -0
  297. package/service/path-utils.ts +26 -0
  298. package/service/sep.ts +7 -0
  299. package/tsconfig.json +17 -0
  300. package/types/README.md +2 -0
  301. package/types/category-node.ts +50 -0
  302. package/types/checkout.ts +47 -0
  303. package/types/commerce-config.ts +13 -0
  304. package/types/commerce-service.ts +128 -0
  305. package/types/family.ts +26 -0
  306. package/types/index.ts +15 -0
  307. package/types/item-selector.ts +97 -0
  308. package/types/line-item.ts +29 -0
  309. package/types/multi-family-selector-props.ts +20 -0
  310. package/types/product.ts +21 -0
  311. package/types/promo.ts +10 -0
  312. package/types/selection-ui-specifier.ts +52 -0
  313. package/types/string-mutator.ts +14 -0
  314. package/types/token-separators.ts +7 -0
  315. package/util/analytics.ts +21 -0
  316. package/util/countries.ts +196 -0
  317. package/util/error.ts +34 -0
  318. package/util/index.ts +71 -0
  319. package/util/item-selector-options-accessor.ts +35 -0
  320. package/util/line-item-ref.ts +23 -0
  321. package/util/multi-family-selector-options-accessor.ts +15 -0
  322. package/util/obs-string-mutator.ts +22 -0
  323. package/util/product-media-accessor.ts +58 -0
  324. package/util/promo-codes.ts +106 -0
  325. package/util/selection-ui-specifiers.ts +30 -0
  326. package/util/square-payment.ts +50 -0
  327. package/util/use-sync-sku-param-w-current-item.ts +88 -0
@@ -0,0 +1,129 @@
1
+ import {
2
+ getFirestore,
3
+ collection,
4
+ setDoc,
5
+ doc,
6
+ serverTimestamp,
7
+ type Firestore,
8
+ type FieldValue,
9
+ } from 'firebase/firestore'
10
+
11
+ import type { ActualLineItemSnapshot } from '../actual-line-item'
12
+
13
+ import firebaseApp from './firebase'
14
+
15
+ let dbInstance: Firestore | undefined = undefined
16
+
17
+ const getDBInstance = (name: string): Firestore => {
18
+ if (!dbInstance) {
19
+ dbInstance = getFirestore(firebaseApp, name)
20
+ }
21
+ return dbInstance
22
+ }
23
+
24
+ interface SavedOrder {
25
+ email: string
26
+ name: string
27
+ // TODO: add shippingInfo type
28
+ shippingInfo?: any
29
+ paymentInfo?: any
30
+ status: string
31
+ timestamp: FieldValue
32
+ items: ActualLineItemSnapshot[]
33
+ }
34
+
35
+ const createOrder = async (
36
+ email: string,
37
+ items: ActualLineItemSnapshot[],
38
+ options: {
39
+ dbName: string
40
+ ordersTable: string
41
+ },
42
+ name?: string
43
+ ): Promise<{
44
+ success: boolean,
45
+ error: any,
46
+ id?: string,
47
+ }> => {
48
+
49
+ let error: any | null = null
50
+ const ordersRef = collection(getDBInstance(options.dbName), options.ordersTable)
51
+ const orderId = `${email}-${new Date().toISOString()}`
52
+
53
+ try {
54
+ await setDoc(doc(ordersRef, orderId), {
55
+ email,
56
+ name: name ?? '',
57
+ status: 'open',
58
+ timestamp: serverTimestamp(),
59
+ items,
60
+ } satisfies SavedOrder)
61
+ return { success: !error, error, id: orderId }
62
+ }
63
+ catch (e) {
64
+ console.error('Error writing item document: ', e)
65
+ error = e
66
+ }
67
+
68
+ return { success: !error, error }
69
+ }
70
+
71
+ const updateOrderShippingInfo = async (
72
+ orderId: string,
73
+ shippingInfo: any,
74
+ options: {
75
+ dbName: string
76
+ ordersTable: string
77
+ }
78
+ ): Promise<{
79
+ success: boolean,
80
+ error: any
81
+ }> => {
82
+
83
+ let error: any | null = null
84
+ const ordersRef = collection(getDBInstance(options.dbName), options.ordersTable)
85
+
86
+ try {
87
+ await setDoc(doc(ordersRef, orderId), {
88
+ shippingInfo,
89
+ timestamp: serverTimestamp(),
90
+ }, { merge: true })
91
+ }
92
+ catch (e) {
93
+ console.error('Error writing item document: ', e)
94
+ error = e
95
+ }
96
+
97
+ return { success: !error, error }
98
+ }
99
+
100
+ const updateOrderPaymentInfo = async (
101
+ orderId: string,
102
+ paymentInfo: any,
103
+ options: {
104
+ dbName: string
105
+ ordersTable: string
106
+ }
107
+ ): Promise<{
108
+ success: boolean,
109
+ error: any
110
+ }> => {
111
+
112
+ let error: any | null = null
113
+ const ordersRef = collection(getDBInstance(options.dbName), options.ordersTable)
114
+
115
+ try {
116
+ await setDoc(doc(ordersRef, orderId), {
117
+ paymentInfo,
118
+ timestamp: serverTimestamp(),
119
+ }, { merge: true })
120
+ }
121
+ catch (e) {
122
+ console.error('Error writing item document: ', e)
123
+ error = e
124
+ }
125
+
126
+ return { success: !error, error }
127
+ }
128
+
129
+ export { createOrder, updateOrderShippingInfo, updateOrderPaymentInfo }
@@ -0,0 +1,33 @@
1
+ import { reaction } from 'mobx'
2
+ import { StandaloneService, type StandaloneServiceSnapshot } from './index'
3
+
4
+ const LS_KEY = 'lux-cart'
5
+
6
+ const readSnapshot = (key: string): StandaloneServiceSnapshot | undefined => {
7
+ const snapshotAsStr = localStorage.getItem(key)
8
+ return snapshotAsStr ? JSON.parse(snapshotAsStr) as StandaloneServiceSnapshot : undefined
9
+ }
10
+
11
+ const writeSnapshotsOnChange = (cmmc: StandaloneService, key: string): void => {
12
+
13
+ if (typeof window !== 'undefined') {
14
+ reaction(
15
+ () => (cmmc.cartTotal),
16
+ (total) => {
17
+ if (total > 0) {
18
+ const snapshot = cmmc.takeSnapshot()
19
+ localStorage.setItem(key, JSON.stringify(snapshot) )
20
+ }
21
+ else {
22
+ localStorage.removeItem(key)
23
+ }
24
+ }
25
+ )
26
+ }
27
+ }
28
+
29
+ export {
30
+ readSnapshot,
31
+ writeSnapshotsOnChange
32
+ }
33
+
@@ -0,0 +1,26 @@
1
+ import type { SelectedPaths } from '../types'
2
+ import sep from './sep'
3
+
4
+ export const getSelectedPaths = (
5
+ skuPath: string
6
+ ): { paths: SelectedPaths; level: number } => {
7
+
8
+ const toks = skuPath.split(sep.tok)
9
+ const level = toks.length - 1
10
+ const paths: SelectedPaths = {}
11
+ for (let l = 1; l <= level; l++ ) {
12
+ paths[l] = [toks[l]]
13
+ }
14
+ return {
15
+ paths,
16
+ level
17
+ }
18
+ }
19
+
20
+ export const getParentPath = (skuPath: string): string => (
21
+ skuPath.split(sep.tok).slice(0, -1).join(sep.tok)
22
+ )
23
+
24
+ export const lastToken = (skuPath: string): string => (
25
+ skuPath.split(sep.tok).pop()!
26
+ )
package/service/sep.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { TokenSeparators } from '../types'
2
+
3
+ export default {
4
+ tok: '-',
5
+ subTok: '_',
6
+ decimal: '.'
7
+ } satisfies TokenSeparators
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "extends": "../tsconfig.libreapps.base.json",
3
+ "include": [
4
+ "**/*.ts",
5
+ "**/*.tsx",
6
+ ],
7
+ "exclude": [
8
+ "node_modules",
9
+ "dist"
10
+ ],
11
+ "compilerOptions": {
12
+ "noEmit": false,
13
+ "declaration": true,
14
+ "skipLibCheck": true,
15
+ "strict": false
16
+ }
17
+ }
@@ -0,0 +1,2 @@
1
+ These are the types that the card ui expects and understands.
2
+ There should always be adaptors both ways from LibreApps commerceJs types.
@@ -0,0 +1,50 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ interface CategoryNode {
4
+ skuToken: string // a token in the sku
5
+ label: string;
6
+ /**
7
+ * Explicitly marks this node as a "last user-visible" / "outermost" Category.
8
+ * Normally, a node is "outermost" when it has no subnodes
9
+ * (and thus is a family with products -- "single-family")
10
+ * But if it *has* subnodes, and its subNodes are actually sibling families
11
+ * of a Category, it must be marked as "outermost" ("multi-family")
12
+ * */
13
+ outermost?: boolean;
14
+ img? : string | ReactNode // icon is required
15
+ imgAR? : number // helps with svgs
16
+
17
+ /**
18
+ * One word prompt that describes the 'meaning' of
19
+ * the subnodes.
20
+ * For example, if a node is 'Lux Credit',
21
+ * it's subNodesLabel might be 'Level', so some UI's
22
+ * might be configured to render 'Level: Black'
23
+ *
24
+ * or something like...
25
+ *
26
+ * <Tabs title={parentNode.label + ': ' + parentNode.subNodesLabel} values={families.map((f) => (f.shortName))} />
27
+ *
28
+ * ...which renders
29
+ *
30
+ * Lux Credit Levels:
31
+ * Black Elite Founder Sovereign
32
+ */
33
+ subNodesLabel?: string
34
+ subNodes?: CategoryNode[]
35
+ }
36
+
37
+ type CategoryNodeRole =
38
+ 'single-family' |
39
+ 'family-in-multi-family' |
40
+ 'multi-family' |
41
+ 'non-outermost'
42
+
43
+ // Which facets tokens are 'on' at each level
44
+ type SelectedPaths = Record<number, string[]>
45
+
46
+ export type {
47
+ CategoryNodeRole,
48
+ CategoryNode,
49
+ SelectedPaths
50
+ }
@@ -0,0 +1,47 @@
1
+ import type { ComponentType } from 'react'
2
+ import type { UseFormReturn } from 'react-hook-form'
3
+
4
+ type TransactionStatus = 'unpaid' | 'paid' | 'confirmed' | 'error'
5
+
6
+ interface CheckoutStepComponentProps {
7
+ onDone: () => void
8
+ orderId: string | undefined
9
+ setOrderId: (orderId: string | undefined) => void
10
+ }
11
+
12
+ interface CheckoutStep {
13
+ name: string
14
+ label?: string
15
+ Comp: ComponentType<CheckoutStepComponentProps>
16
+ }
17
+
18
+ type ContactFormType = UseFormReturn<{
19
+ name: string
20
+ email: string
21
+ }, any, {
22
+ name: string
23
+ email: string
24
+ }>
25
+
26
+ interface PaymentMethodComponentProps {
27
+ onDone: () => void
28
+ transactionStatus: TransactionStatus
29
+ setTransactionStatus: (status: TransactionStatus) => void
30
+ storePaymentInfo: (paymentInfo: any) => Promise<void>
31
+ contactForm: ContactFormType
32
+ }
33
+
34
+ interface PaymentMethodDesc {
35
+ value: string
36
+ label: string
37
+ Comp: ComponentType<PaymentMethodComponentProps>
38
+ }
39
+
40
+ export {
41
+ type TransactionStatus,
42
+ type CheckoutStepComponentProps,
43
+ type CheckoutStep,
44
+ type PaymentMethodComponentProps,
45
+ type PaymentMethodDesc,
46
+ type ContactFormType,
47
+ }
@@ -0,0 +1,13 @@
1
+ import type { ServiceOptions } from '..'
2
+ import type { CategoryNode } from './category-node'
3
+ import type { Family } from './family'
4
+ import type { SelectionUISpecifier } from './selection-ui-specifier'
5
+
6
+ interface CommerceConfig {
7
+ families: Family[]
8
+ rootNode: CategoryNode
9
+ options?: ServiceOptions
10
+ uiSpecifiers?: Record<string, SelectionUISpecifier>
11
+ }
12
+
13
+ export { type CommerceConfig as default }
@@ -0,0 +1,128 @@
1
+ import type { LineItem, ObsLineItemRef } from './line-item'
2
+ import type { CategoryNode, SelectedPaths, CategoryNodeRole } from './category-node'
3
+ import type { Family, ObsFamilyRef} from './family'
4
+ import type Promo from './promo'
5
+
6
+
7
+ interface CommerceService extends ObsLineItemRef, ObsFamilyRef {
8
+
9
+ /** Items in cart */
10
+ get cartItems(): LineItem[]
11
+ /** Total of all quantities of all items in cart */
12
+ get cartQuantity(): number
13
+ /** Total of all prices x quantities of items in cart */
14
+ get cartTotal(): number
15
+
16
+ /** cartItem whose quantity was modified most recently
17
+ * item: LineItem
18
+ * modified: number (timestamp)
19
+ * (undefined if cartEmpty)
20
+ */
21
+ get recentItem(): { item: LineItem, modified: number } | undefined
22
+ get promoAppliedCartTotal(): number
23
+
24
+ get cartEmpty(): boolean
25
+
26
+ get appliedPromo(): Promo | null
27
+ setAppliedPromo(promo: Promo | null): void
28
+ /** returns the price with promo applied, of undefined if no promo or promo does not apply */
29
+ itemPromoPrice(item: LineItem): number | undefined
30
+
31
+ getFamilySubtotal(familyId: string): number
32
+
33
+ createOrder(email: string, name?: string): Promise<string | undefined>
34
+ updateOrderShippingInfo(orderId: string, shippingInfo: any): Promise<void>
35
+ updateOrderPaymentInfo(orderId: string, paymentInfo: any): Promise<void>
36
+
37
+ /**
38
+ * Sets the tokens at each level supplied.
39
+ * If a level is selected as [], nothing will be selected.
40
+ * If a level is missing (undefined), everything at that level is selected
41
+ *
42
+ * This selects one or more Family's, and all the LineItem's in them.
43
+ *
44
+ * An empty value object selects all Family's and all LineItem's,
45
+ * */
46
+ selectPaths(value: SelectedPaths): Family[]
47
+ selectPath(skuPath: string): Family[]
48
+
49
+ /**
50
+ * With role as ...
51
+ *
52
+ * 'single-family':
53
+ * item: item with skuPath as SKU, otherwise undefined
54
+ * node: node at path (or item's parent node),
55
+ * family: node at path as family (or item's parent node as family),
56
+ * families: undefined
57
+ *
58
+ * 'family-in-multi-family':
59
+ * item: item with skuPath as SKU, otherwise undefined
60
+ * node: parent node of this family (or parent node of item's family)
61
+ * family: this family (or item's family)
62
+ * families: this family (or item's family) and siblings
63
+ *
64
+ * 'multi-family':
65
+ * item: undefined
66
+ * node: node at path
67
+ * family: undefined
68
+ * families: subnodes / families of this node
69
+ *
70
+ * 'non-outermost':
71
+ * item: undefined
72
+ * node: node at path
73
+ * family: undefined
74
+ * families: undefined
75
+ *
76
+ */
77
+ peek(skuPath: string): {
78
+ role: CategoryNodeRole
79
+ family: Family | undefined
80
+ families: Family[] | undefined
81
+ node: CategoryNode | undefined
82
+ item: LineItem | undefined
83
+ } | string // or error string
84
+
85
+ /** @deprecated
86
+ * Whether this path defines a Family, or if it has further levels
87
+ * */
88
+ getNodeAtPath(skuPath: string): CategoryNode | undefined
89
+
90
+ get selectedPaths(): SelectedPaths // returns a copy
91
+
92
+ get selectedItems(): LineItem[]
93
+ get selectedFamilies(): Family[]
94
+ get hasSelection(): boolean
95
+
96
+
97
+ /**
98
+ * Who are the subnodes selected at 'level'?
99
+ * If more than one value is selected at 'level',
100
+ * the returned CategoryNode[] may represent multiple sets.
101
+ * */
102
+ getSelectedNodesAtLevel(level: number): CategoryNode[] | undefined
103
+
104
+ /**
105
+ * For convenience, so widgets can share state.
106
+ * "current" is unrelated to what branches and items are
107
+ * "selected" (with CategoryNode's and paths)
108
+ *
109
+ * SEE ALSO: from ObsLineItemRef and ObsFamilyRef, there are also
110
+ * get item(): LineItem | undefined
111
+ * get family(): Family | undefined
112
+ *
113
+ * These simply delegate to these functions
114
+ * */
115
+ setCurrentItem(sku: string | undefined): boolean // valid sku and was set.
116
+ get currentItem(): LineItem | undefined
117
+ setCurrentFamily(id: string | undefined): boolean // valid id and was set.
118
+ get currentFamily(): Family | undefined
119
+
120
+ // utility
121
+ getFamilyById(id: string): Family | undefined
122
+ getItemBySku(sku: string): LineItem | undefined
123
+ }
124
+
125
+
126
+ export {
127
+ type CommerceService as default
128
+ }
@@ -0,0 +1,26 @@
1
+ import type { ImageDef } from '@libreapps/ui/types'
2
+ import type Product from './product'
3
+
4
+ interface Family {
5
+ id: string // LXB-AU-B
6
+ title: string // Minted Bar, Lux Elite Card
7
+ titleShort?: string // Elite
8
+ parentTitle?: string // Lux Gold, Lux Credit
9
+ byline?: string // literal text, or name of function on 'this' object that returns a string
10
+ desc?: string
11
+ img?: ImageDef,
12
+ // inbound to the service, they're Products
13
+ // when it's initialized, interally they become LineItems
14
+ // always ok to cast up to LineItem thereafter
15
+ products: Product[]
16
+ }
17
+
18
+
19
+ interface ObsFamilyRef {
20
+ get family(): Family | undefined
21
+ }
22
+
23
+ export {
24
+ type Family,
25
+ type ObsFamilyRef
26
+ }
package/types/index.ts ADDED
@@ -0,0 +1,15 @@
1
+
2
+ export type { default as CommerceService } from './commerce-service'
3
+ export type { default as CommerceConfig } from './commerce-config'
4
+ export type { default as MultiFamilySelectorProps } from './multi-family-selector-props'
5
+ export type { default as Product } from './product'
6
+ export type { default as Promo } from './promo'
7
+ export type { default as TokenSeparators } from './token-separators'
8
+
9
+ export * from './category-node'
10
+ export * from './checkout'
11
+ export * from './family'
12
+ export * from './item-selector'
13
+ export * from './line-item'
14
+ export * from './selection-ui-specifier'
15
+ export * from './string-mutator'
@@ -0,0 +1,97 @@
1
+ import type { LineItem, ObsLineItemRef } from './line-item'
2
+
3
+ interface ItemSelector {
4
+ items: LineItem[]
5
+ selectedItemRef: ObsLineItemRef
6
+ selectSku: (sku: string) => void
7
+ }
8
+
9
+ /** default: 'text' */
10
+ type ItemButton = 'text' | 'image-and-text' | 'image'
11
+
12
+ // NOTE: if a field is added here, it should also
13
+ // be added to util/item-selector-options-accessor.ts
14
+ type ItemSelectorOptions = {
15
+
16
+ /**
17
+ * default: short
18
+ * 'short': product.shortTitle if defined
19
+ * 'long': always us product.title, even if .shortTitle is defined
20
+ * 'none': do not show title AND BYLINE
21
+ *
22
+ * (NOTE: *not* the same as buttonType = 'none')
23
+ */
24
+ familyTitle?: 'none' | 'long' | 'short'
25
+
26
+ /** only if title shown
27
+ * default: false */
28
+ showFamilyByline?: boolean
29
+
30
+ /**
31
+ * Whether the item label includes the Family name.
32
+ * eg, 'Minted Bar, 1oz' vs '1oz'
33
+ * default: false.
34
+ */
35
+ showFamilyInOption?: boolean
36
+ /** default: true if it exists */
37
+ showByline?: boolean
38
+
39
+ /** default: true */
40
+ showPrice?: boolean
41
+
42
+ /**
43
+ * Show the current item quantity along with title and price.
44
+ * default: false
45
+ */
46
+ showQuantity?: boolean
47
+
48
+ buttonType?: ItemButton
49
+
50
+ /** (button selector only) default: false */
51
+ horizButtons?: boolean
52
+
53
+ /** (carousel selector only)
54
+ * affects sort. See below.
55
+ * default: false */
56
+ showSlider?: boolean
57
+
58
+ /** default true */
59
+ showButtonIfOnlyOne?: boolean
60
+
61
+ /**
62
+ * Sort by cost.
63
+ * If it's a carousel selector and 'showSlider' is true,
64
+ * defaults to 'asc', unless another value is explicitly specified.
65
+ * Otherwise, defaults to 'none'
66
+ * */
67
+ sort?: 'none' | 'asc' | 'desc'
68
+ }
69
+
70
+ interface _ItemSelectorCompProps {
71
+ clx?: string
72
+ itemClx?: string
73
+ soleItemClx?: string
74
+ /** type-specific props for ItemSelector's.
75
+ * eg, Carousel options.
76
+ */
77
+ ext?: any
78
+ /** List selectors will scroll.
79
+ * Used internally
80
+ * default: false */
81
+ scrollable? : boolean
82
+ options?: ItemSelectorOptions
83
+
84
+ mobile?: boolean
85
+ }
86
+
87
+ type ItemSelectorCompProps = Omit<_ItemSelectorCompProps, 'scrollable'>
88
+
89
+ interface ItemSelectorProps extends
90
+ ItemSelector, _ItemSelectorCompProps {}
91
+
92
+ export {
93
+ type ItemSelector,
94
+ type ItemSelectorCompProps,
95
+ type ItemSelectorOptions,
96
+ type ItemSelectorProps
97
+ }
@@ -0,0 +1,29 @@
1
+ import type Product from './product'
2
+
3
+ // Client code always
4
+ // has a LineItem, whether the Product
5
+ // is in the cart or not. Something is in the cart
6
+ // when its quantity > 0. That's the only difference.
7
+ // The ui, and as well as some Cart state, reacts to
8
+ // changes in this quantity.
9
+
10
+ // It could have more accurately been named
11
+ // 'QuantifiedProduct' but that sucked.
12
+ interface LineItem extends Product {
13
+
14
+ /** all observable */
15
+ get quantity(): number
16
+ get canDecrement(): boolean
17
+ get isInCart(): boolean
18
+
19
+ increment(): void
20
+ decrement(): void
21
+
22
+ get title(): string
23
+ }
24
+
25
+ interface ObsLineItemRef {
26
+ get item(): LineItem | undefined
27
+ }
28
+
29
+ export type { LineItem, ObsLineItemRef}
@@ -0,0 +1,20 @@
1
+ import type { Dimensions } from '@libreapps/ui/types'
2
+
3
+ import type { Family } from './family'
4
+ import type { ItemSelectorOptions } from './item-selector'
5
+ import type { MultiFamilySelectorOptions } from './selection-ui-specifier'
6
+ import type { CategoryNode } from './category-node'
7
+ import type { LineItem } from './line-item'
8
+
9
+ interface MultiFamilySelectorProps {
10
+ families: Family[]
11
+ parent: CategoryNode
12
+ clx?: string
13
+ itemClx?: string
14
+ itemOptions?: ItemSelectorOptions
15
+ selectorOptions?: MultiFamilySelectorOptions
16
+ mediaConstraint?: Dimensions
17
+ mobile?: boolean
18
+ }
19
+
20
+ export { type MultiFamilySelectorProps as default }
@@ -0,0 +1,21 @@
1
+ import type { ImageDef, MediaStackDef } from '@libreapps/ui/types'
2
+
3
+ interface Product extends MediaStackDef {
4
+ id: string // DB index // not a logical aspect of our domain. may not be necessary at all
5
+ sku: string // human visible on orders etc.
6
+ fullTitle?: string
7
+ optionLabel: string
8
+ optionLabelShort?: string
9
+ familyId: string // skuPath, eg LXB-AU-B
10
+ familyTitle: string
11
+ byline?: string
12
+ desc?: string
13
+ price: number
14
+ // image to by uses as an image button in a list of choices
15
+ // defaults to (MediaStackDef's) img
16
+ optionImg?: ImageDef
17
+ }
18
+
19
+ export {
20
+ type Product as default
21
+ }
package/types/promo.ts ADDED
@@ -0,0 +1,10 @@
1
+ interface Promo {
2
+ type: 'percent' | 'amount'
3
+ code: string
4
+ value: number,
5
+ skus?: string[]
6
+ }
7
+
8
+ export {
9
+ type Promo as default
10
+ }