@vandenberghinc/volt 1.1.2

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 (451) hide show
  1. package/.vrepo +28 -0
  2. package/.vscode/tasks.json +87 -0
  3. package/README.md +67 -0
  4. package/backend/dist/cjs/blacklist.d.ts +10 -0
  5. package/backend/dist/cjs/blacklist.js +53 -0
  6. package/backend/dist/cjs/cli.d.ts +2 -0
  7. package/backend/dist/cjs/cli.js +263 -0
  8. package/backend/dist/cjs/database.d.ts +364 -0
  9. package/backend/dist/cjs/database.js +1962 -0
  10. package/backend/dist/cjs/endpoint.d.ts +57 -0
  11. package/backend/dist/cjs/endpoint.js +425 -0
  12. package/backend/dist/cjs/file_watcher.d.ts +44 -0
  13. package/backend/dist/cjs/file_watcher.js +348 -0
  14. package/backend/dist/cjs/frontend.d.ts +13 -0
  15. package/backend/dist/cjs/frontend.js +30 -0
  16. package/backend/dist/cjs/image_endpoint.d.ts +24 -0
  17. package/backend/dist/cjs/image_endpoint.js +210 -0
  18. package/backend/dist/cjs/logger.d.ts +5 -0
  19. package/backend/dist/cjs/logger.js +16 -0
  20. package/backend/dist/cjs/meta.d.ts +50 -0
  21. package/backend/dist/cjs/meta.js +153 -0
  22. package/backend/dist/cjs/mutex.d.ts +24 -0
  23. package/backend/dist/cjs/mutex.js +52 -0
  24. package/backend/dist/cjs/package.json +1 -0
  25. package/backend/dist/cjs/payments/paddle.d.ts +161 -0
  26. package/backend/dist/cjs/payments/paddle.js +2301 -0
  27. package/backend/dist/cjs/plugins/browser.d.ts +36 -0
  28. package/backend/dist/cjs/plugins/browser.js +183 -0
  29. package/backend/dist/cjs/plugins/communication.d.ts +70 -0
  30. package/backend/dist/cjs/plugins/communication.js +177 -0
  31. package/backend/dist/cjs/plugins/css.d.ts +10 -0
  32. package/backend/dist/cjs/plugins/css.js +71 -0
  33. package/backend/dist/cjs/plugins/mail.d.ts +277 -0
  34. package/backend/dist/cjs/plugins/mail.js +1419 -0
  35. package/backend/dist/cjs/plugins/pdf.d.ts +757 -0
  36. package/backend/dist/cjs/plugins/pdf.js +1694 -0
  37. package/backend/dist/cjs/plugins/thread_monitor.d.ts +18 -0
  38. package/backend/dist/cjs/plugins/thread_monitor.js +127 -0
  39. package/backend/dist/cjs/plugins/ts/compiler.d.ts +132 -0
  40. package/backend/dist/cjs/plugins/ts/compiler.js +944 -0
  41. package/backend/dist/cjs/plugins/ts/preprocessing.d.ts +14 -0
  42. package/backend/dist/cjs/plugins/ts/preprocessing.js +762 -0
  43. package/backend/dist/cjs/rate_limit.d.ts +65 -0
  44. package/backend/dist/cjs/rate_limit.js +463 -0
  45. package/backend/dist/cjs/request.deprc.d.ts +48 -0
  46. package/backend/dist/cjs/request.deprc.js +572 -0
  47. package/backend/dist/cjs/response.deprc.d.ts +55 -0
  48. package/backend/dist/cjs/response.deprc.js +275 -0
  49. package/backend/dist/cjs/server.d.ts +311 -0
  50. package/backend/dist/cjs/server.js +3475 -0
  51. package/backend/dist/cjs/splash_screen.d.ts +35 -0
  52. package/backend/dist/cjs/splash_screen.js +152 -0
  53. package/backend/dist/cjs/status.d.ts +60 -0
  54. package/backend/dist/cjs/status.js +199 -0
  55. package/backend/dist/cjs/stream.d.ts +75 -0
  56. package/backend/dist/cjs/stream.js +954 -0
  57. package/backend/dist/cjs/users.d.ts +111 -0
  58. package/backend/dist/cjs/users.js +1945 -0
  59. package/backend/dist/cjs/utils.d.ts +27 -0
  60. package/backend/dist/cjs/utils.js +329 -0
  61. package/backend/dist/cjs/view.d.ts +52 -0
  62. package/backend/dist/cjs/view.js +568 -0
  63. package/backend/dist/cjs/vinc.d.ts +2 -0
  64. package/backend/dist/cjs/vinc.dev.d.ts +2 -0
  65. package/backend/dist/cjs/vinc.dev.js +42 -0
  66. package/backend/dist/cjs/vinc.js +42 -0
  67. package/backend/dist/cjs/volt.d.ts +15 -0
  68. package/backend/dist/cjs/volt.js +64 -0
  69. package/backend/dist/css/adyen.css +92 -0
  70. package/backend/dist/css/volt.css +65 -0
  71. package/backend/dist/esm/blacklist.d.ts +10 -0
  72. package/backend/dist/esm/blacklist.js +49 -0
  73. package/backend/dist/esm/cli.d.ts +2 -0
  74. package/backend/dist/esm/cli.js +228 -0
  75. package/backend/dist/esm/database.d.ts +364 -0
  76. package/backend/dist/esm/database.js +1957 -0
  77. package/backend/dist/esm/endpoint.d.ts +57 -0
  78. package/backend/dist/esm/endpoint.js +421 -0
  79. package/backend/dist/esm/file_watcher.d.ts +44 -0
  80. package/backend/dist/esm/file_watcher.js +313 -0
  81. package/backend/dist/esm/frontend.d.ts +13 -0
  82. package/backend/dist/esm/frontend.js +27 -0
  83. package/backend/dist/esm/image_endpoint.d.ts +24 -0
  84. package/backend/dist/esm/image_endpoint.js +206 -0
  85. package/backend/dist/esm/logger.d.ts +5 -0
  86. package/backend/dist/esm/logger.js +13 -0
  87. package/backend/dist/esm/meta.d.ts +50 -0
  88. package/backend/dist/esm/meta.js +149 -0
  89. package/backend/dist/esm/mutex.d.ts +24 -0
  90. package/backend/dist/esm/mutex.js +48 -0
  91. package/backend/dist/esm/payments/paddle.d.ts +161 -0
  92. package/backend/dist/esm/payments/paddle.js +2261 -0
  93. package/backend/dist/esm/plugins/browser.d.ts +36 -0
  94. package/backend/dist/esm/plugins/browser.js +176 -0
  95. package/backend/dist/esm/plugins/communication.d.ts +70 -0
  96. package/backend/dist/esm/plugins/communication.js +169 -0
  97. package/backend/dist/esm/plugins/css.d.ts +10 -0
  98. package/backend/dist/esm/plugins/css.js +64 -0
  99. package/backend/dist/esm/plugins/mail.d.ts +277 -0
  100. package/backend/dist/esm/plugins/mail.js +1403 -0
  101. package/backend/dist/esm/plugins/pdf.d.ts +757 -0
  102. package/backend/dist/esm/plugins/pdf.js +1694 -0
  103. package/backend/dist/esm/plugins/thread_monitor.d.ts +18 -0
  104. package/backend/dist/esm/plugins/thread_monitor.js +120 -0
  105. package/backend/dist/esm/plugins/ts/compiler.d.ts +132 -0
  106. package/backend/dist/esm/plugins/ts/compiler.js +907 -0
  107. package/backend/dist/esm/plugins/ts/preprocessing.d.ts +14 -0
  108. package/backend/dist/esm/plugins/ts/preprocessing.js +724 -0
  109. package/backend/dist/esm/rate_limit.d.ts +65 -0
  110. package/backend/dist/esm/rate_limit.js +425 -0
  111. package/backend/dist/esm/request.deprc.d.ts +48 -0
  112. package/backend/dist/esm/request.deprc.js +572 -0
  113. package/backend/dist/esm/response.deprc.d.ts +55 -0
  114. package/backend/dist/esm/response.deprc.js +275 -0
  115. package/backend/dist/esm/server.d.ts +311 -0
  116. package/backend/dist/esm/server.js +3435 -0
  117. package/backend/dist/esm/splash_screen.d.ts +35 -0
  118. package/backend/dist/esm/splash_screen.js +148 -0
  119. package/backend/dist/esm/status.d.ts +60 -0
  120. package/backend/dist/esm/status.js +196 -0
  121. package/backend/dist/esm/stream.d.ts +75 -0
  122. package/backend/dist/esm/stream.js +947 -0
  123. package/backend/dist/esm/users.d.ts +111 -0
  124. package/backend/dist/esm/users.js +1908 -0
  125. package/backend/dist/esm/utils.d.ts +27 -0
  126. package/backend/dist/esm/utils.js +324 -0
  127. package/backend/dist/esm/view.d.ts +52 -0
  128. package/backend/dist/esm/view.js +561 -0
  129. package/backend/dist/esm/vinc.d.ts +2 -0
  130. package/backend/dist/esm/vinc.dev.d.ts +2 -0
  131. package/backend/dist/esm/vinc.dev.js +6 -0
  132. package/backend/dist/esm/vinc.js +6 -0
  133. package/backend/dist/esm/volt.d.ts +15 -0
  134. package/backend/dist/esm/volt.js +23 -0
  135. package/backend/dist/esm-dev/blacklist.d.ts +10 -0
  136. package/backend/dist/esm-dev/blacklist.js +49 -0
  137. package/backend/dist/esm-dev/cli.d.ts +2 -0
  138. package/backend/dist/esm-dev/cli.js +228 -0
  139. package/backend/dist/esm-dev/database.d.ts +364 -0
  140. package/backend/dist/esm-dev/database.js +1957 -0
  141. package/backend/dist/esm-dev/endpoint.d.ts +57 -0
  142. package/backend/dist/esm-dev/endpoint.js +421 -0
  143. package/backend/dist/esm-dev/file_watcher.d.ts +44 -0
  144. package/backend/dist/esm-dev/file_watcher.js +313 -0
  145. package/backend/dist/esm-dev/frontend.d.ts +13 -0
  146. package/backend/dist/esm-dev/frontend.js +27 -0
  147. package/backend/dist/esm-dev/image_endpoint.d.ts +24 -0
  148. package/backend/dist/esm-dev/image_endpoint.js +206 -0
  149. package/backend/dist/esm-dev/logger.d.ts +5 -0
  150. package/backend/dist/esm-dev/logger.js +13 -0
  151. package/backend/dist/esm-dev/meta.d.ts +50 -0
  152. package/backend/dist/esm-dev/meta.js +149 -0
  153. package/backend/dist/esm-dev/mutex.d.ts +24 -0
  154. package/backend/dist/esm-dev/mutex.js +48 -0
  155. package/backend/dist/esm-dev/payments/paddle.d.ts +161 -0
  156. package/backend/dist/esm-dev/payments/paddle.js +2261 -0
  157. package/backend/dist/esm-dev/plugins/browser.d.ts +36 -0
  158. package/backend/dist/esm-dev/plugins/browser.js +176 -0
  159. package/backend/dist/esm-dev/plugins/communication.d.ts +70 -0
  160. package/backend/dist/esm-dev/plugins/communication.js +169 -0
  161. package/backend/dist/esm-dev/plugins/css.d.ts +10 -0
  162. package/backend/dist/esm-dev/plugins/css.js +64 -0
  163. package/backend/dist/esm-dev/plugins/mail.d.ts +277 -0
  164. package/backend/dist/esm-dev/plugins/mail.js +1403 -0
  165. package/backend/dist/esm-dev/plugins/pdf.d.ts +757 -0
  166. package/backend/dist/esm-dev/plugins/pdf.js +1694 -0
  167. package/backend/dist/esm-dev/plugins/thread_monitor.d.ts +18 -0
  168. package/backend/dist/esm-dev/plugins/thread_monitor.js +120 -0
  169. package/backend/dist/esm-dev/plugins/ts/compiler.d.ts +132 -0
  170. package/backend/dist/esm-dev/plugins/ts/compiler.js +907 -0
  171. package/backend/dist/esm-dev/plugins/ts/preprocessing.d.ts +14 -0
  172. package/backend/dist/esm-dev/plugins/ts/preprocessing.js +724 -0
  173. package/backend/dist/esm-dev/rate_limit.d.ts +65 -0
  174. package/backend/dist/esm-dev/rate_limit.js +425 -0
  175. package/backend/dist/esm-dev/request.deprc.d.ts +48 -0
  176. package/backend/dist/esm-dev/request.deprc.js +572 -0
  177. package/backend/dist/esm-dev/response.deprc.d.ts +55 -0
  178. package/backend/dist/esm-dev/response.deprc.js +275 -0
  179. package/backend/dist/esm-dev/server.d.ts +311 -0
  180. package/backend/dist/esm-dev/server.js +3435 -0
  181. package/backend/dist/esm-dev/splash_screen.d.ts +35 -0
  182. package/backend/dist/esm-dev/splash_screen.js +148 -0
  183. package/backend/dist/esm-dev/status.d.ts +60 -0
  184. package/backend/dist/esm-dev/status.js +196 -0
  185. package/backend/dist/esm-dev/stream.d.ts +75 -0
  186. package/backend/dist/esm-dev/stream.js +947 -0
  187. package/backend/dist/esm-dev/users.d.ts +111 -0
  188. package/backend/dist/esm-dev/users.js +1908 -0
  189. package/backend/dist/esm-dev/utils.d.ts +27 -0
  190. package/backend/dist/esm-dev/utils.js +324 -0
  191. package/backend/dist/esm-dev/view.d.ts +52 -0
  192. package/backend/dist/esm-dev/view.js +561 -0
  193. package/backend/dist/esm-dev/vinc.d.ts +2 -0
  194. package/backend/dist/esm-dev/vinc.dev.d.ts +2 -0
  195. package/backend/dist/esm-dev/vinc.dev.js +6 -0
  196. package/backend/dist/esm-dev/vinc.js +6 -0
  197. package/backend/dist/esm-dev/volt.d.ts +15 -0
  198. package/backend/dist/esm-dev/volt.js +23 -0
  199. package/backend/src/blacklist.ts +69 -0
  200. package/backend/src/cli.js +245 -0
  201. package/backend/src/database.ts +2241 -0
  202. package/backend/src/endpoint.ts +494 -0
  203. package/backend/src/file_watcher.ts +359 -0
  204. package/backend/src/frontend.ts +35 -0
  205. package/backend/src/globals.d.ts +8 -0
  206. package/backend/src/image_endpoint.ts +258 -0
  207. package/backend/src/logger.ts +18 -0
  208. package/backend/src/meta.ts +202 -0
  209. package/backend/src/mutex.ts +51 -0
  210. package/backend/src/payments/paddle.ts +2659 -0
  211. package/backend/src/plugins/browser.ts +188 -0
  212. package/backend/src/plugins/communication.ts +204 -0
  213. package/backend/src/plugins/css.ts +84 -0
  214. package/backend/src/plugins/fonts/Menlo-Bold.ttf +0 -0
  215. package/backend/src/plugins/fonts/Menlo-Regular.ttf +0 -0
  216. package/backend/src/plugins/mail.ts +1720 -0
  217. package/backend/src/plugins/pdf.js +1932 -0
  218. package/backend/src/plugins/thread_monitor.ts +164 -0
  219. package/backend/src/plugins/ts/compiler.ts +1242 -0
  220. package/backend/src/plugins/ts/preprocessing.ts +812 -0
  221. package/backend/src/rate_limit.ts +503 -0
  222. package/backend/src/request.deprc.js +626 -0
  223. package/backend/src/response.deprc.js +354 -0
  224. package/backend/src/server.ts +4149 -0
  225. package/backend/src/splash_screen.ts +192 -0
  226. package/backend/src/status.ts +199 -0
  227. package/backend/src/stream.ts +1070 -0
  228. package/backend/src/users.ts +2077 -0
  229. package/backend/src/utils.ts +359 -0
  230. package/backend/src/view.ts +655 -0
  231. package/backend/src/vinc.dev.js +6 -0
  232. package/backend/src/vinc.ts +6 -0
  233. package/backend/src/volt.js +25 -0
  234. package/backend/tsconfig.cjs.json +29 -0
  235. package/backend/tsconfig.esm.dev.json +34 -0
  236. package/backend/tsconfig.esm.json +30 -0
  237. package/backend/tsconfig.json +2 -0
  238. package/frontend/compile.js +436 -0
  239. package/frontend/dist/elements/base.d.ts +9891 -0
  240. package/frontend/dist/elements/base.js +8818 -0
  241. package/frontend/dist/elements/module.d.ts +16 -0
  242. package/frontend/dist/elements/module.js +178 -0
  243. package/frontend/dist/modules/array.d.ts +37 -0
  244. package/frontend/dist/modules/array.js +284 -0
  245. package/frontend/dist/modules/auth.d.ts +45 -0
  246. package/frontend/dist/modules/auth.js +138 -0
  247. package/frontend/dist/modules/colors.d.ts +26 -0
  248. package/frontend/dist/modules/colors.js +340 -0
  249. package/frontend/dist/modules/compression.d.ts +6 -0
  250. package/frontend/dist/modules/compression.js +999 -0
  251. package/frontend/dist/modules/cookies.d.ts +17 -0
  252. package/frontend/dist/modules/cookies.js +166 -0
  253. package/frontend/dist/modules/date.d.ts +142 -0
  254. package/frontend/dist/modules/date.js +493 -0
  255. package/frontend/dist/modules/events.d.ts +7 -0
  256. package/frontend/dist/modules/events.js +90 -0
  257. package/frontend/dist/modules/google.d.ts +10 -0
  258. package/frontend/dist/modules/google.js +53 -0
  259. package/frontend/dist/modules/meta.d.ts +9 -0
  260. package/frontend/dist/modules/meta.js +45 -0
  261. package/frontend/dist/modules/mutex.d.ts +8 -0
  262. package/frontend/dist/modules/mutex.js +52 -0
  263. package/frontend/dist/modules/number.d.ts +12 -0
  264. package/frontend/dist/modules/number.js +8 -0
  265. package/frontend/dist/modules/object.d.ts +50 -0
  266. package/frontend/dist/modules/object.js +147 -0
  267. package/frontend/dist/modules/paddle.d.ts +1403 -0
  268. package/frontend/dist/modules/paddle.js +2641 -0
  269. package/frontend/dist/modules/scheme.d.ts +207 -0
  270. package/frontend/dist/modules/scheme.js +649 -0
  271. package/frontend/dist/modules/settings.d.ts +3 -0
  272. package/frontend/dist/modules/settings.js +4 -0
  273. package/frontend/dist/modules/statics.d.ts +4 -0
  274. package/frontend/dist/modules/statics.js +45 -0
  275. package/frontend/dist/modules/string.d.ts +163 -0
  276. package/frontend/dist/modules/string.js +291 -0
  277. package/frontend/dist/modules/support.d.ts +18 -0
  278. package/frontend/dist/modules/support.js +102 -0
  279. package/frontend/dist/modules/themes.d.ts +8 -0
  280. package/frontend/dist/modules/themes.js +17 -0
  281. package/frontend/dist/modules/user.d.ts +58 -0
  282. package/frontend/dist/modules/user.js +279 -0
  283. package/frontend/dist/modules/utils.d.ts +58 -0
  284. package/frontend/dist/modules/utils.js +1159 -0
  285. package/frontend/dist/types/gradient.d.ts +12 -0
  286. package/frontend/dist/types/gradient.js +79 -0
  287. package/frontend/dist/ui/border_button.d.ts +177 -0
  288. package/frontend/dist/ui/border_button.js +235 -0
  289. package/frontend/dist/ui/button.d.ts +42 -0
  290. package/frontend/dist/ui/button.js +114 -0
  291. package/frontend/dist/ui/canvas.d.ts +56 -0
  292. package/frontend/dist/ui/canvas.js +411 -0
  293. package/frontend/dist/ui/checkbox.d.ts +72 -0
  294. package/frontend/dist/ui/checkbox.js +277 -0
  295. package/frontend/dist/ui/code.d.ts +232 -0
  296. package/frontend/dist/ui/code.js +977 -0
  297. package/frontend/dist/ui/color.d.ts +1 -0
  298. package/frontend/dist/ui/color.js +110 -0
  299. package/frontend/dist/ui/context_menu.d.ts +30 -0
  300. package/frontend/dist/ui/context_menu.js +211 -0
  301. package/frontend/dist/ui/css.d.ts +10 -0
  302. package/frontend/dist/ui/css.js +44 -0
  303. package/frontend/dist/ui/divider.d.ts +18 -0
  304. package/frontend/dist/ui/divider.js +82 -0
  305. package/frontend/dist/ui/dropdown.d.ts +115 -0
  306. package/frontend/dist/ui/dropdown.js +446 -0
  307. package/frontend/dist/ui/for_each.d.ts +38 -0
  308. package/frontend/dist/ui/for_each.js +97 -0
  309. package/frontend/dist/ui/form.d.ts +25 -0
  310. package/frontend/dist/ui/form.js +227 -0
  311. package/frontend/dist/ui/frame_modes.d.ts +28 -0
  312. package/frontend/dist/ui/frame_modes.js +116 -0
  313. package/frontend/dist/ui/google_map.d.ts +31 -0
  314. package/frontend/dist/ui/google_map.js +111 -0
  315. package/frontend/dist/ui/gradient.d.ts +24 -0
  316. package/frontend/dist/ui/gradient.js +115 -0
  317. package/frontend/dist/ui/image.d.ts +138 -0
  318. package/frontend/dist/ui/image.js +570 -0
  319. package/frontend/dist/ui/input.d.ts +316 -0
  320. package/frontend/dist/ui/input.js +1187 -0
  321. package/frontend/dist/ui/link.d.ts +39 -0
  322. package/frontend/dist/ui/link.js +146 -0
  323. package/frontend/dist/ui/list.d.ts +33 -0
  324. package/frontend/dist/ui/list.js +161 -0
  325. package/frontend/dist/ui/loader_button.d.ts +108 -0
  326. package/frontend/dist/ui/loader_button.js +207 -0
  327. package/frontend/dist/ui/loaders.d.ts +60 -0
  328. package/frontend/dist/ui/loaders.js +150 -0
  329. package/frontend/dist/ui/popup.d.ts +84 -0
  330. package/frontend/dist/ui/popup.js +331 -0
  331. package/frontend/dist/ui/pseudo.d.ts +16 -0
  332. package/frontend/dist/ui/pseudo.js +81 -0
  333. package/frontend/dist/ui/scroller.d.ts +131 -0
  334. package/frontend/dist/ui/scroller.js +1251 -0
  335. package/frontend/dist/ui/slider.d.ts +35 -0
  336. package/frontend/dist/ui/slider.js +203 -0
  337. package/frontend/dist/ui/spacer.d.ts +20 -0
  338. package/frontend/dist/ui/spacer.js +83 -0
  339. package/frontend/dist/ui/span.d.ts +11 -0
  340. package/frontend/dist/ui/span.js +75 -0
  341. package/frontend/dist/ui/stack.d.ts +123 -0
  342. package/frontend/dist/ui/stack.js +344 -0
  343. package/frontend/dist/ui/steps.d.ts +72 -0
  344. package/frontend/dist/ui/steps.js +306 -0
  345. package/frontend/dist/ui/style.d.ts +12 -0
  346. package/frontend/dist/ui/style.js +78 -0
  347. package/frontend/dist/ui/switch.d.ts +44 -0
  348. package/frontend/dist/ui/switch.js +280 -0
  349. package/frontend/dist/ui/table.d.ts +118 -0
  350. package/frontend/dist/ui/table.js +411 -0
  351. package/frontend/dist/ui/tabs.d.ts +85 -0
  352. package/frontend/dist/ui/tabs.js +392 -0
  353. package/frontend/dist/ui/text.d.ts +19 -0
  354. package/frontend/dist/ui/text.js +88 -0
  355. package/frontend/dist/ui/theme.d.ts +25 -0
  356. package/frontend/dist/ui/theme.js +237 -0
  357. package/frontend/dist/ui/title.d.ts +36 -0
  358. package/frontend/dist/ui/title.js +127 -0
  359. package/frontend/dist/ui/ui.d.ts +38 -0
  360. package/frontend/dist/ui/ui.js +41 -0
  361. package/frontend/dist/ui/view.d.ts +25 -0
  362. package/frontend/dist/ui/view.js +93 -0
  363. package/frontend/dist/volt.d.ts +22 -0
  364. package/frontend/dist/volt.js +27 -0
  365. package/frontend/exports.json +1340 -0
  366. package/frontend/src/css/adyen.css +92 -0
  367. package/frontend/src/css/volt.css +65 -0
  368. package/frontend/src/elements/base.ts +16790 -0
  369. package/frontend/src/elements/module.ts +184 -0
  370. package/frontend/src/elements/types.d.ts +155 -0
  371. package/frontend/src/modules/array.ts +366 -0
  372. package/frontend/src/modules/auth.ts +188 -0
  373. package/frontend/src/modules/colors.ts +449 -0
  374. package/frontend/src/modules/compression.ts +67 -0
  375. package/frontend/src/modules/cookies.ts +182 -0
  376. package/frontend/src/modules/date.js +535 -0
  377. package/frontend/src/modules/date.ts +583 -0
  378. package/frontend/src/modules/events.ts +96 -0
  379. package/frontend/src/modules/google.ts +60 -0
  380. package/frontend/src/modules/meta.ts +59 -0
  381. package/frontend/src/modules/mutex.ts +59 -0
  382. package/frontend/src/modules/number.ts +20 -0
  383. package/frontend/src/modules/object.ts +212 -0
  384. package/frontend/src/modules/paddle.ts +2990 -0
  385. package/frontend/src/modules/scheme.ts +740 -0
  386. package/frontend/src/modules/settings.ts +5 -0
  387. package/frontend/src/modules/statics.ts +47 -0
  388. package/frontend/src/modules/string.ts +500 -0
  389. package/frontend/src/modules/support.ts +118 -0
  390. package/frontend/src/modules/themes.ts +24 -0
  391. package/frontend/src/modules/user.ts +321 -0
  392. package/frontend/src/modules/utils.ts +1260 -0
  393. package/frontend/src/static/admin/admin.png +0 -0
  394. package/frontend/src/static/admin/password.webp +0 -0
  395. package/frontend/src/static/icons/copy.webp +0 -0
  396. package/frontend/src/static/payments/arrow.long.webp +0 -0
  397. package/frontend/src/static/payments/arrow.long2.webp +0 -0
  398. package/frontend/src/static/payments/cancelled.webp +0 -0
  399. package/frontend/src/static/payments/check.sign.webp +0 -0
  400. package/frontend/src/static/payments/check.webp +0 -0
  401. package/frontend/src/static/payments/close.webp +0 -0
  402. package/frontend/src/static/payments/error.webp +0 -0
  403. package/frontend/src/static/payments/exclamation.webp +0 -0
  404. package/frontend/src/static/payments/minus.webp +0 -0
  405. package/frontend/src/static/payments/party.webp +0 -0
  406. package/frontend/src/static/payments/plus.webp +0 -0
  407. package/frontend/src/static/payments/shopping_cart.webp +0 -0
  408. package/frontend/src/static/payments/trash.webp +0 -0
  409. package/frontend/src/types/global.d.ts +4 -0
  410. package/frontend/src/types/gradient.ts +87 -0
  411. package/frontend/src/ui/any_element.d.ts +5 -0
  412. package/frontend/src/ui/border_button.ts +320 -0
  413. package/frontend/src/ui/button.ts +62 -0
  414. package/frontend/src/ui/canvas.ts +431 -0
  415. package/frontend/src/ui/checkbox.ts +284 -0
  416. package/frontend/src/ui/code.ts +1049 -0
  417. package/frontend/src/ui/color.ts +117 -0
  418. package/frontend/src/ui/context_menu.ts +194 -0
  419. package/frontend/src/ui/css.ts +57 -0
  420. package/frontend/src/ui/divider.ts +28 -0
  421. package/frontend/src/ui/dropdown.ts +503 -0
  422. package/frontend/src/ui/for_each.ts +71 -0
  423. package/frontend/src/ui/form.ts +208 -0
  424. package/frontend/src/ui/frame_modes.ts +140 -0
  425. package/frontend/src/ui/google_map.ts +70 -0
  426. package/frontend/src/ui/gradient.ts +73 -0
  427. package/frontend/src/ui/image.ts +587 -0
  428. package/frontend/src/ui/input.ts +1284 -0
  429. package/frontend/src/ui/link.ts +77 -0
  430. package/frontend/src/ui/list.ts +88 -0
  431. package/frontend/src/ui/loader_button.ts +192 -0
  432. package/frontend/src/ui/loaders.ts +126 -0
  433. package/frontend/src/ui/popup.ts +370 -0
  434. package/frontend/src/ui/pseudo.ts +33 -0
  435. package/frontend/src/ui/scroller.ts +1324 -0
  436. package/frontend/src/ui/slider.ts +215 -0
  437. package/frontend/src/ui/spacer.ts +29 -0
  438. package/frontend/src/ui/span.ts +23 -0
  439. package/frontend/src/ui/stack.ts +238 -0
  440. package/frontend/src/ui/steps.ts +334 -0
  441. package/frontend/src/ui/style.ts +26 -0
  442. package/frontend/src/ui/switch.ts +286 -0
  443. package/frontend/src/ui/table.ts +323 -0
  444. package/frontend/src/ui/tabs.ts +441 -0
  445. package/frontend/src/ui/text.ts +38 -0
  446. package/frontend/src/ui/theme.ts +279 -0
  447. package/frontend/src/ui/title.ts +64 -0
  448. package/frontend/src/ui/ui.ts +47 -0
  449. package/frontend/src/ui/view.ts +44 -0
  450. package/frontend/src/volt.ts +31 -0
  451. package/package.json +58 -0
@@ -0,0 +1,2990 @@
1
+ /*
2
+ * @author: Daan van den Bergh
3
+ * @copyright: © 2022 - 2024 Daan van den Bergh.
4
+ */
5
+
6
+ // Imports.
7
+ import { Utils } from "./utils.js";
8
+ import { User } from "./user.js";
9
+ import { HStack, HStackElement, NullHStack, VStack, VStackElement, } from "../ui/stack"
10
+ import { Text } from "../ui/text"
11
+ import { Title } from "../ui/title"
12
+ import { ForEach } from "../ui/for_each"
13
+ import { Image, ImageMask } from "../ui/image"
14
+ import { RingLoader } from "../ui/loaders"
15
+ import { BorderButton } from "../ui/border_button"
16
+ import { LoaderButton, LoaderButtonElement } from "../ui/loader_button"
17
+ import { Divider } from "../ui/divider"
18
+ import { Input, ExtendedSelect, ExtendedInput, ExtendedInputElement, ExtendedSelectElement } from "../ui/input"
19
+ import { Spacer } from "../ui/spacer"
20
+ import { Link } from "../ui/link"
21
+ import { CheckBox } from "../ui/checkbox"
22
+ import { Form } from "../ui/form"
23
+ import { Popup, PopupElement } from "../ui/popup"
24
+
25
+ // Declare global variables or external libraries if necessary.
26
+ // @todo import paddle here not using scripts
27
+ declare const Paddle: any;
28
+
29
+ // ---------------------------------------------------------
30
+ // Payments Object.
31
+
32
+ const Payments = {
33
+ // ---------------------------------------------------------
34
+ // Private Properties.
35
+
36
+ client_key: "{{PADDLE_CLIENT_KEY}}",
37
+ // @ts-ignore
38
+ sandbox: "{{PADDLE_SANDBOX}}" === "true",
39
+ // @ts-ignore
40
+ tax_inclusive: "{{PADDLE_INCLUSIVE_TAX}}" === "true",
41
+ countries: {
42
+ "AD": { name: "🇦🇩 Andorra", calling_code: "+376" },
43
+ "AE": { name: "🇦🇪 United Arab Emirates", calling_code: "+971" },
44
+ "AF": { name: "🇦🇫 Afghanistan", calling_code: "+93" },
45
+ "AG": { name: "🇦🇬 Antigua and Barbuda", calling_code: "+1-268" },
46
+ "AI": { name: "🇦🇮 Anguilla", calling_code: "+1-264" },
47
+ "AL": { name: "🇦🇱 Albania", calling_code: "+355" },
48
+ "AM": { name: "🇦🇲 Armenia", calling_code: "+374" },
49
+ "AO": { name: "🇦🇴 Angola", calling_code: "+244" },
50
+ "AQ": { name: "🇦🇶 Antarctica", calling_code: "+672" },
51
+ "AR": { name: "🇦🇷 Argentina", calling_code: "+54" },
52
+ "AS": { name: "🇦🇸 American Samoa", calling_code: "+1-684" },
53
+ "AT": { name: "🇦🇹 Austria", calling_code: "+43" },
54
+ "AU": { name: "🇦🇺 Australia", calling_code: "+61" },
55
+ "AW": { name: "🇦🇼 Aruba", calling_code: "+297" },
56
+ "AX": { name: "🇦🇽 Åland Islands", calling_code: "+358-18" },
57
+ "AZ": { name: "🇦🇿 Azerbaijan", calling_code: "+994" },
58
+ "BA": { name: "🇧🇦 Bosnia and Herzegovina", calling_code: "+387" },
59
+ "BB": { name: "🇧🇧 Barbados", calling_code: "+1-246" },
60
+ "BD": { name: "🇧🇩 Bangladesh", calling_code: "+880" },
61
+ "BE": { name: "🇧🇪 Belgium", calling_code: "+32" },
62
+ "BF": { name: "🇧🇫 Burkina Faso", calling_code: "+226" },
63
+ "BG": { name: "🇧🇬 Bulgaria", calling_code: "+359" },
64
+ "BH": { name: "🇧🇭 Bahrain", calling_code: "+973" },
65
+ "BI": { name: "🇧🇮 Burundi", calling_code: "+257" },
66
+ "BJ": { name: "🇧🇯 Benin", calling_code: "+229" },
67
+ "BL": { name: "🇧🇱 Saint Barthélemy", calling_code: "+590" },
68
+ "BM": { name: "🇧🇲 Bermuda", calling_code: "+1-441" },
69
+ "BN": { name: "🇧🇳 Brunei", calling_code: "+673" },
70
+ "BO": { name: "🇧🇴 Bolivia", calling_code: "+591" },
71
+ "BQ": { name: "🇧🇶 Caribbean Netherlands", calling_code: "+599" },
72
+ "BR": { name: "🇧🇷 Brazil", calling_code: "+55" },
73
+ "BS": { name: "🇧🇸 Bahamas", calling_code: "+1-242" },
74
+ "BT": { name: "🇧🇹 Bhutan", calling_code: "+975" },
75
+ "BV": { name: "🇧🇻 Bouvet Island", calling_code: "+47" },
76
+ "BW": { name: "🇧🇼 Botswana", calling_code: "+267" },
77
+ "BY": { name: "🇧🇾 Belarus", calling_code: "+375" },
78
+ "BZ": { name: "🇧🇿 Belize", calling_code: "+501" },
79
+ "CA": { name: "🇨🇦 Canada", calling_code: "+1" },
80
+ "CC": { name: "🇨🇨 Cocos (Keeling) Islands", calling_code: "+61" },
81
+ "CD": { name: "🇨🇩 Congo (DRC)", calling_code: "+243" },
82
+ "CF": { name: "🇨🇫 Central African Republic", calling_code: "+236" },
83
+ "CG": { name: "🇨🇬 Congo (Republic)", calling_code: "+242" },
84
+ "CH": { name: "🇨🇭 Switzerland", calling_code: "+41" },
85
+ "CI": { name: "🇨🇮 Côte d'Ivoire", calling_code: "+225" },
86
+ "CK": { name: "🇨🇰 Cook Islands", calling_code: "+682" },
87
+ "CL": { name: "🇨🇱 Chile", calling_code: "+56" },
88
+ "CM": { name: "🇨🇲 Cameroon", calling_code: "+237" },
89
+ "CN": { name: "🇨🇳 China", calling_code: "+86" },
90
+ "CO": { name: "🇨🇴 Colombia", calling_code: "+57" },
91
+ "CR": { name: "🇨🇷 Costa Rica", calling_code: "+506" },
92
+ "CU": { name: "🇨🇺 Cuba", calling_code: "+53" },
93
+ "CV": { name: "🇨🇻 Cape Verde", calling_code: "+238" },
94
+ "CW": { name: "🇨🇼 Curaçao", calling_code: "+599" },
95
+ "CX": { name: "🇨🇽 Christmas Island", calling_code: "+61" },
96
+ "CY": { name: "🇨🇾 Cyprus", calling_code: "+357" },
97
+ "CZ": { name: "🇨🇿 Czech Republic", calling_code: "+420" },
98
+ "DE": { name: "🇩🇪 Germany", calling_code: "+49" },
99
+ "DJ": { name: "🇩🇯 Djibouti", calling_code: "+253" },
100
+ "DK": { name: "🇩🇰 Denmark", calling_code: "+45" },
101
+ "DM": { name: "🇩🇲 Dominica", calling_code: "+1-767" },
102
+ "DO": { name: "🇩🇴 Dominican Republic", calling_code: "+1-809" },
103
+ "DZ": { name: "🇩🇿 Algeria", calling_code: "+213" },
104
+ "EC": { name: "🇪🇨 Ecuador", calling_code: "+593" },
105
+ "EE": { name: "🇪🇪 Estonia", calling_code: "+372" },
106
+ "EG": { name: "🇪🇬 Egypt", calling_code: "+20" },
107
+ "EH": { name: "🇪🇭 Western Sahara", calling_code: "+212" },
108
+ "ER": { name: "🇪🇷 Eritrea", calling_code: "+291" },
109
+ "ES": { name: "🇪🇸 Spain", calling_code: "+34" },
110
+ "ET": { name: "🇪🇹 Ethiopia", calling_code: "+251" },
111
+ "FI": { name: "🇫🇮 Finland", calling_code: "+358" },
112
+ "FJ": { name: "🇫🇯 Fiji", calling_code: "+679" },
113
+ "FK": { name: "🇫🇰 Falkland Islands (Malvinas)", calling_code: "+500" },
114
+ "FM": { name: "🇫🇲 Micronesia", calling_code: "+691" },
115
+ "FO": { name: "🇫🇴 Faroe Islands", calling_code: "+298" },
116
+ "FR": { name: "🇫🇷 France", calling_code: "+33" },
117
+ "GA": { name: "🇬🇦 Gabon", calling_code: "+241" },
118
+ "GB": { name: "🇬🇧 United Kingdom", calling_code: "+44" },
119
+ "GD": { name: "🇬🇩 Grenada", calling_code: "+1-473" },
120
+ "GE": { name: "🇬🇪 Georgia", calling_code: "+995" },
121
+ "GF": { name: "🇬🇫 French Guiana", calling_code: "+594" },
122
+ "GG": { name: "🇬🇬 Guernsey", calling_code: "+44" },
123
+ "GH": { name: "🇬🇭 Ghana", calling_code: "+233" },
124
+ "GI": { name: "🇬🇮 Gibraltar", calling_code: "+350" },
125
+ "GL": { name: "🇬🇱 Greenland", calling_code: "+299" },
126
+ "GM": { name: "🇬🇲 Gambia", calling_code: "+220" },
127
+ "GN": { name: "🇬🇳 Guinea", calling_code: "+224" },
128
+ "GP": { name: "🇬🇵 Guadeloupe", calling_code: "+590" },
129
+ "GQ": { name: "🇬🇶 Equatorial Guinea", calling_code: "+240" },
130
+ "GR": { name: "🇬🇷 Greece", calling_code: "+30" },
131
+ "GS": { name: "🇬🇸 South Georgia and the South Sandwich Islands", calling_code: "+500" },
132
+ "GT": { name: "🇬🇹 Guatemala", calling_code: "+502" },
133
+ "GU": { name: "🇬🇺 Guam", calling_code: "+1-671" },
134
+ "GW": { name: "🇬🇼 Guinea-Bissau", calling_code: "+245" },
135
+ "GY": { name: "🇬🇾 Guyana", calling_code: "+592" },
136
+ "HK": { name: "🇭🇰 Hong Kong", calling_code: "+852" },
137
+ "HM": { name: "🇭🇲 Heard Island and McDonald Islands", calling_code: "+672" },
138
+ "HN": { name: "🇭🇳 Honduras", calling_code: "+504" },
139
+ "HR": { name: "🇭🇷 Croatia", calling_code: "+385" },
140
+ "HT": { name: "🇭🇹 Haiti", calling_code: "+509" },
141
+ "HU": { name: "🇭🇺 Hungary", calling_code: "+36" },
142
+ "ID": { name: "🇮🇩 Indonesia", calling_code: "+62" },
143
+ "IE": { name: "🇮🇪 Ireland", calling_code: "+353" },
144
+ "IL": { name: "🇮🇱 Israel", calling_code: "+972" },
145
+ "IM": { name: "🇮🇲 Isle of Man", calling_code: "+44" },
146
+ "IN": { name: "🇮🇳 India", calling_code: "+91" },
147
+ "IO": { name: "🇮🇴 British Indian Ocean Territory", calling_code: "+246" },
148
+ "IQ": { name: "🇮🇶 Iraq", calling_code: "+964" },
149
+ "IR": { name: "🇮🇷 Iran", calling_code: "+98" },
150
+ "IS": { name: "🇮🇸 Iceland", calling_code: "+354" },
151
+ "IT": { name: "🇮🇹 Italy", calling_code: "+39" },
152
+ "JE": { name: "🇯🇪 Jersey", calling_code: "+44" },
153
+ "JM": { name: "🇯🇲 Jamaica", calling_code: "+1-876" },
154
+ "JO": { name: "🇯🇴 Jordan", calling_code: "+962" },
155
+ "JP": { name: "🇯🇵 Japan", calling_code: "+81" },
156
+ "KE": { name: "🇰🇪 Kenya", calling_code: "+254" },
157
+ "KG": { name: "🇰🇬 Kyrgyzstan", calling_code: "+996" },
158
+ "KH": { name: "🇰🇭 Cambodia", calling_code: "+855" },
159
+ "KI": { name: "🇰🇮 Kiribati", calling_code: "+686" },
160
+ "KM": { name: "🇰🇲 Comoros", calling_code: "+269" },
161
+ "KN": { name: "🇰🇳 Saint Kitts and Nevis", calling_code: "+1-869" },
162
+ "KP": { name: "🇰🇵 North Korea", calling_code: "+850" },
163
+ "KR": { name: "🇰🇷 South Korea", calling_code: "+82" },
164
+ "KW": { name: "🇰🇼 Kuwait", calling_code: "+965" },
165
+ "KY": { name: "🇰🇾 Cayman Islands", calling_code: "+1-345" },
166
+ "KZ": { name: "🇰🇿 Kazakhstan", calling_code: "+7" },
167
+ "LA": { name: "🇱🇦 Laos", calling_code: "+856" },
168
+ "LB": { name: "🇱🇧 Lebanon", calling_code: "+961" },
169
+ "LC": { name: "🇱🇨 Saint Lucia", calling_code: "+1-758" },
170
+ "LI": { name: "🇱🇮 Liechtenstein", calling_code: "+423" },
171
+ "LK": { name: "🇱🇰 Sri Lanka", calling_code: "+94" },
172
+ "LR": { name: "🇱🇷 Liberia", calling_code: "+231" },
173
+ "LS": { name: "🇱🇸 Lesotho", calling_code: "+266" },
174
+ "LT": { name: "🇱🇹 Lithuania", calling_code: "+370" },
175
+ "LU": { name: "🇱🇺 Luxembourg", calling_code: "+352" },
176
+ "LV": { name: "🇱🇻 Latvia", calling_code: "+371" },
177
+ "LY": { name: "🇱🇾 Libya", calling_code: "+218" },
178
+ "MA": { name: "🇲🇦 Morocco", calling_code: "+212" },
179
+ "MC": { name: "🇲🇨 Monaco", calling_code: "+377" },
180
+ "MD": { name: "🇲🇩 Moldova", calling_code: "+373" },
181
+ "ME": { name: "🇲🇪 Montenegro", calling_code: "+382" },
182
+ "MF": { name: "🇲🇫 Saint Martin", calling_code: "+590" },
183
+ "MG": { name: "🇲🇬 Madagascar", calling_code: "+261" },
184
+ "MH": { name: "🇲🇭 Marshall Islands", calling_code: "+692" },
185
+ "MK": { name: "🇲🇰 North Macedonia", calling_code: "+389" },
186
+ "ML": { name: "🇲🇱 Mali", calling_code: "+223" },
187
+ "MM": { name: "🇲🇲 Myanmar (Burma)", calling_code: "+95" },
188
+ "MN": { name: "🇲🇳 Mongolia", calling_code: "+976" },
189
+ "MO": { name: "🇲🇴 Macao", calling_code: "+853" },
190
+ "MP": { name: "🇲🇵 Northern Mariana Islands", calling_code: "+1-670" },
191
+ "MQ": { name: "🇲🇶 Martinique", calling_code: "+596" },
192
+ "MR": { name: "🇲🇷 Mauritania", calling_code: "+222" },
193
+ "MS": { name: "🇲🇸 Montserrat", calling_code: "+1-664" },
194
+ "MT": { name: "🇲🇹 Malta", calling_code: "+356" },
195
+ "MU": { name: "🇲🇺 Mauritius", calling_code: "+230" },
196
+ "MV": { name: "🇲🇻 Maldives", calling_code: "+960" },
197
+ "MW": { name: "🇲🇼 Malawi", calling_code: "+265" },
198
+ "MX": { name: "🇲🇽 Mexico", calling_code: "+52" },
199
+ "MY": { name: "🇲🇾 Malaysia", calling_code: "+60" },
200
+ "MZ": { name: "🇲🇿 Mozambique", calling_code: "+258" },
201
+ "NA": { name: "🇳🇦 Namibia", calling_code: "+264" },
202
+ "NC": { name: "🇳🇨 New Caledonia", calling_code: "+687" },
203
+ "NE": { name: "🇳🇪 Niger", calling_code: "+227" },
204
+ "NF": { name: "🇳🇫 Norfolk Island", calling_code: "+672" },
205
+ "NG": { name: "🇳🇬 Nigeria", calling_code: "+234" },
206
+ "NI": { name: "🇳🇮 Nicaragua", calling_code: "+505" },
207
+ "NL": { name: "🇳🇱 Netherlands", calling_code: "+31" },
208
+ "NO": { name: "🇳🇴 Norway", calling_code: "+47" },
209
+ "NP": { name: "🇳🇵 Nepal", calling_code: "+977" },
210
+ "NR": { name: "🇳🇷 Nauru", calling_code: "+674" },
211
+ "NU": { name: "🇳🇺 Niue", calling_code: "+683" },
212
+ "NZ": { name: "🇳🇿 New Zealand", calling_code: "+64" },
213
+ "OM": { name: "🇴🇲 Oman", calling_code: "+968" },
214
+ "PA": { name: "🇵🇦 Panama", calling_code: "+507" },
215
+ "PE": { name: "🇵🇪 Peru", calling_code: "+51" },
216
+ "PF": { name: "🇵🇫 French Polynesia", calling_code: "+689" },
217
+ "PG": { name: "🇵🇬 Papua New Guinea", calling_code: "+675" },
218
+ "PH": { name: "🇵🇭 Philippines", calling_code: "+63" },
219
+ "PK": { name: "🇵🇰 Pakistan", calling_code: "+92" },
220
+ "PL": { name: "🇵🇱 Poland", calling_code: "+48" },
221
+ "PM": { name: "🇵🇲 Saint Pierre and Miquelon", calling_code: "+508" },
222
+ "PN": { name: "🇵🇳 Pitcairn Islands", calling_code: "+64" },
223
+ "PR": { name: "🇵🇷 Puerto Rico", calling_code: "+1-787" },
224
+ "PS": { name: "🇵🇸 Palestine", calling_code: "+970" },
225
+ "PT": { name: "🇵🇹 Portugal", calling_code: "+351" },
226
+ "PW": { name: "🇵🇼 Palau", calling_code: "+680" },
227
+ "PY": { name: "🇵🇾 Paraguay", calling_code: "+595" },
228
+ "QA": { name: "🇶🇦 Qatar", calling_code: "+974" },
229
+ "RE": { name: "🇷🇪 Réunion", calling_code: "+262" },
230
+ "RO": { name: "🇷🇴 Romania", calling_code: "+40" },
231
+ "RS": { name: "🇷🇸 Serbia", calling_code: "+381" },
232
+ "RU": { name: "🇷🇺 Russia", calling_code: "+7" },
233
+ "RW": { name: "🇷🇼 Rwanda", calling_code: "+250" },
234
+ "SA": { name: "🇸🇦 Saudi Arabia", calling_code: "+966" },
235
+ "SB": { name: "🇸🇧 Solomon Islands", calling_code: "+677" },
236
+ "SC": { name: "🇸🇨 Seychelles", calling_code: "+248" },
237
+ "SD": { name: "🇸🇩 Sudan", calling_code: "+249" },
238
+ "SE": { name: "🇸🇪 Sweden", calling_code: "+46" },
239
+ "SG": { name: "🇸🇬 Singapore", calling_code: "+65" },
240
+ "SH": { name: "🇸🇭 Saint Helena, Ascension and Tristan da Cunha", calling_code: "+290" },
241
+ "SI": { name: "🇸🇮 Slovenia", calling_code: "+386" },
242
+ "SJ": { name: "🇸🇯 Svalbard and Jan Mayen", calling_code: "+47" },
243
+ "SK": { name: "🇸🇰 Slovakia", calling_code: "+421" },
244
+ "SL": { name: "🇸🇱 Sierra Leone", calling_code: "+232" },
245
+ "SM": { name: "🇸🇲 San Marino", calling_code: "+378" },
246
+ "SN": { name: "🇸🇳 Senegal", calling_code: "+221" },
247
+ "SO": { name: "🇸🇴 Somalia", calling_code: "+252" },
248
+ "SR": { name: "🇸🇷 Suriname", calling_code: "+597" },
249
+ "SS": { name: "🇸🇸 South Sudan", calling_code: "+211" },
250
+ "ST": { name: "🇸🇹 São Tomé and Príncipe", calling_code: "+239" },
251
+ "SV": { name: "🇸🇻 El Salvador", calling_code: "+503" },
252
+ "SX": { name: "🇸🇽 Sint Maarten", calling_code: "+1-721" },
253
+ "SY": { name: "🇸🇾 Syria", calling_code: "+963" },
254
+ "SZ": { name: "🇸🇿 Eswatini", calling_code: "+268" },
255
+ "TC": { name: "🇹🇨 Turks and Caicos Islands", calling_code: "+1-649" },
256
+ "TD": { name: "🇹🇩 Chad", calling_code: "+235" },
257
+ "TF": { name: "🇹🇫 French Southern and Antarctic Lands", calling_code: "+262" },
258
+ "TG": { name: "🇹🇬 Togo", calling_code: "+228" },
259
+ "TH": { name: "🇹🇭 Thailand", calling_code: "+66" },
260
+ "TJ": { name: "🇹🇯 Tajikistan", calling_code: "+992" },
261
+ "TK": { name: "🇹🇰 Tokelau", calling_code: "+690" },
262
+ "TL": { name: "🇹🇱 Timor-Leste", calling_code: "+670" },
263
+ "TM": { name: "🇹🇲 Turkmenistan", calling_code: "+993" },
264
+ "TN": { name: "🇹🇳 Tunisia", calling_code: "+216" },
265
+ "TO": { name: "🇹🇴 Tonga", calling_code: "+676" },
266
+ "TR": { name: "🇹🇷 Turkey", calling_code: "+90" },
267
+ "TT": { name: "🇹🇹 Trinidad and Tobago", calling_code: "+1-868" },
268
+ "TV": { name: "🇹🇻 Tuvalu", calling_code: "+688" },
269
+ "TW": { name: "🇹🇼 Taiwan", calling_code: "+886" },
270
+ "TZ": { name: "🇹🇿 Tanzania", calling_code: "+255" },
271
+ "UA": { name: "🇺🇦 Ukraine", calling_code: "+380" },
272
+ "UG": { name: "🇺🇬 Uganda", calling_code: "+256" },
273
+ "UM": { name: "🇺🇲 U.S. Minor Outlying Islands", calling_code: "+1" },
274
+ "US": { name: "🇺🇸 United States", calling_code: "+1" },
275
+ "UY": { name: "🇺🇾 Uruguay", calling_code: "+598" },
276
+ "UZ": { name: "🇺🇿 Uzbekistan", calling_code: "+998" },
277
+ "VA": { name: "🇻🇦 Vatican City", calling_code: "+379" },
278
+ "VC": { name: "🇻🇨 Saint Vincent and the Grenadines", calling_code: "+1-784" },
279
+ "VE": { name: "🇻🇪 Venezuela", calling_code: "+58" },
280
+ "VG": { name: "🇻🇬 British Virgin Islands", calling_code: "+1-284" },
281
+ "VI": { name: "🇻🇮 U.S. Virgin Islands", calling_code: "+1-340" },
282
+ "VN": { name: "🇻🇳 Vietnam", calling_code: "+84" },
283
+ "VU": { name: "🇻🇺 Vanuatu", calling_code: "+678" },
284
+ "WF": { name: "🇼🇫 Wallis and Futuna", calling_code: "+681" },
285
+ "WS": { name: "🇼🇸 Samoa", calling_code: "+685" },
286
+ "YE": { name: "🇾🇪 Yemen", calling_code: "+967" },
287
+ "YT": { name: "🇾🇹 Mayotte", calling_code: "+262" },
288
+ "ZA": { name: "🇿🇦 South Africa", calling_code: "+27" },
289
+ "ZM": { name: "🇿🇲 Zambia", calling_code: "+260" },
290
+ "ZW": { name: "🇿🇼 Zimbabwe", calling_code: "+263" }
291
+ },
292
+
293
+ _paddle_initialized: false,
294
+ _payment_element: undefined as any, // Replace 'any' with the actual type if known.
295
+ _sign_in_redirect: undefined as string | undefined | null,
296
+ _step: 0 as number,
297
+ _steps_element: undefined as any,
298
+ _steps_container: undefined as any,
299
+ _overview_container: undefined as any,
300
+ _order_container: undefined as any,
301
+ _billing_container: undefined as any,
302
+ _payment_container: undefined as any,
303
+ _processing_container: undefined as any,
304
+ _checkout_button: undefined as any,
305
+ _prev_step_button: undefined as any,
306
+ _style: undefined as any,
307
+ _currency_symbol: undefined as string | undefined,
308
+ _render_payment_element_reject: undefined as undefined | Function,
309
+ _render_payment_element_resolve: undefined as undefined | Function,
310
+ _refunds_element: undefined as any,
311
+ _refunds_container: undefined as any,
312
+ _processing_element: undefined as any,
313
+ _theme: undefined as any,
314
+ _products: undefined as any,
315
+ _days_refundable: 30, // **Added Property**
316
+
317
+ on_error: (data: string | Error) => {},
318
+
319
+ // Additional properties that might be inferred from function bodies:
320
+ _refund_policy: undefined as string | undefined, // Used in commented code
321
+ _cancellation_policy: undefined as string | undefined, // Used in commented code
322
+
323
+ // cart: {
324
+ // items: [] as any[], // Replace 'any' with the actual item type.
325
+ // refresh: function() { /* Implement refresh logic */ },
326
+ // save: function() { /* Implement save logic */ },
327
+ // add: async function(productId: string, quantity: number) { /* Implement add logic */ },
328
+ // remove: async function(productId: string, quantity: number | "all") { /* Implement remove logic */ },
329
+ // },
330
+
331
+ _billing_element: undefined as any, // Replace 'any' with the actual type if known.
332
+ _billing_details: undefined as any, // Replace 'any' with the actual type if known.
333
+
334
+ _overview_subtotal: undefined as any, // Replace 'any' with the actual type if known.
335
+ _overview_total: undefined as any, // Replace 'any' with the actual type if known.
336
+ _overview_subtotal_tax: undefined as any, // Replace 'any' with the actual type if known.
337
+ _overview_tax_container: undefined as any, // Replace 'any' with the actual type if known.
338
+ _overview_incl_excl_tax: undefined as any, // Replace 'any' with the actual type if known.
339
+ _overview_element: undefined as any, // Replace 'any' with the actual type if known.
340
+ _order_element: undefined as any, // Replace 'any' with the actual type if known.
341
+
342
+ // ---------------------------------------------------------
343
+ // Private Methods.
344
+
345
+ /**
346
+ * Initialize Paddle with the provided client key and set up event callbacks.
347
+ */
348
+ _initialize_paddle: function(): void {
349
+ if (this._paddle_initialized !== true) {
350
+ if (this.sandbox) {
351
+ Paddle.Environment.set("sandbox");
352
+ }
353
+ Paddle.Setup({
354
+ token: this.client_key,
355
+ eventCallback: (data: any) => {
356
+ if (data.name === "checkout.loaded") {
357
+ (this._render_payment_element_resolve as Function)();
358
+ }
359
+ else if (data.name === "checkout.completed") {
360
+ this._show_processing("success");
361
+ }
362
+ else if (data.name === "checkout.payment.initiated") {
363
+ // Uncomment and implement if needed.
364
+ // this._show_processing("processing");
365
+ }
366
+ else if (data.name === "checkout.payment.failed") {
367
+ this._show_processing("error");
368
+ }
369
+ else if (data.type === "checkout.error") {
370
+ if (data.error?.detail) {
371
+ console.error(data);
372
+ this.on_error(data.error.detail);
373
+ } else {
374
+ console.error(data);
375
+ this.on_error(new Error("Unknown error"));
376
+ }
377
+ (this._render_payment_element_reject as Function)(data.detail.split("|")[0]);
378
+ }
379
+ else if (data.type === "checkout.warning") {
380
+ if (this.sandbox) {
381
+ console.log("Checkout warning:", data);
382
+ }
383
+ }
384
+ else {
385
+ // Handle other events if necessary.
386
+ // Uncomment for debugging.
387
+ // if (this.sandbox) {
388
+ // console.log("Event", data);
389
+ // }
390
+ }
391
+ }
392
+ });
393
+ this._paddle_initialized = true;
394
+ }
395
+ },
396
+
397
+ /**
398
+ * Reset the payment element by removing it if it exists.
399
+ */
400
+ _reset: function(): void {
401
+ if (this._payment_element !== undefined) {
402
+ this._payment_element.remove();
403
+ }
404
+ this._payment_element = undefined;
405
+ },
406
+
407
+ /**
408
+ * Initialize the order by verifying authentication and making a POST request.
409
+ */
410
+ _init_order: async function (): Promise<void> {
411
+ try {
412
+ if (this._sign_in_redirect != null && !User.is_authenticated()) {
413
+ Utils.redirect(this._sign_in_redirect);
414
+ }
415
+ const response = await Utils.request({
416
+ method: "POST",
417
+ url: "/volt/payments/init",
418
+ data: {
419
+ items: this.cart.items,
420
+ }
421
+ });
422
+ // Handle response if necessary.
423
+ } catch (err: any) {
424
+ if (typeof err === "object" && err.error != null) {
425
+ err = err.error;
426
+ }
427
+ throw new Error(err);
428
+ }
429
+ },
430
+
431
+ /**
432
+ * Set the current step in the payment process.
433
+ */
434
+ _set_step: async function (): Promise<void | null> {
435
+ // Switch step.
436
+ switch (this._step) {
437
+
438
+ // Order.
439
+ case 0: {
440
+ // Select the current step.
441
+ this._steps_element.select(this._step);
442
+
443
+ // Show and hide relevant containers.
444
+ this._overview_container.show();
445
+ this._order_container.show();
446
+ this._billing_container.hide();
447
+ this._payment_container.hide();
448
+ this._processing_container.hide();
449
+ this._checkout_button.nodes.text.text("Next");
450
+ // this._policy_checkbox.hide();
451
+ this._prev_step_button.hide();
452
+ break;
453
+ }
454
+
455
+ // Address.
456
+ case 1: {
457
+ // Minimum duration for the loader.
458
+ const min_duration = new Promise(resolve => setTimeout(resolve, 350));
459
+
460
+ // Verify the order.
461
+ try {
462
+ await this._init_order();
463
+ } catch (err) {
464
+ --this._step;
465
+ console.error(err);
466
+ this.on_error(err as Error);
467
+ return null;
468
+ }
469
+
470
+ // Render billing element.
471
+ this._render_billing_element();
472
+
473
+ // Await minimum duration.
474
+ await min_duration;
475
+
476
+ // Select the current step.
477
+ this._steps_element.select(this._step);
478
+
479
+ // Show and hide relevant containers.
480
+ this._overview_container.show();
481
+ this._order_container.hide();
482
+ this._billing_container.show();
483
+ this._payment_container.hide();
484
+ this._processing_container.hide();
485
+ this._checkout_button.nodes.text.text("Next");
486
+ // this._policy_checkbox.hide();
487
+ this._prev_step_button.show();
488
+ break;
489
+ }
490
+
491
+ // Payment.
492
+ case 2: {
493
+ // Check if the billing details are entered correctly.
494
+ try {
495
+ this._billing_details = this._billing_element.data();
496
+ this._billing_details.phone_number = this._billing_details.phone_country_code + this._billing_details.phone_number;
497
+ delete this._billing_details.phone_country_code;
498
+ } catch (error) {
499
+ --this._step;
500
+ console.error(error);
501
+ this.on_error(error as Error);
502
+ return null;
503
+ }
504
+
505
+ // Render payment element.
506
+ try {
507
+ await this._render_payment_element();
508
+ } catch (error) {
509
+ --this._step;
510
+ console.error(error);
511
+ this.on_error(error as Error);
512
+ return null;
513
+ }
514
+
515
+ // Select the current step.
516
+ this._steps_element.select(this._step);
517
+
518
+ // Show and hide relevant containers.
519
+ this._overview_container.hide();
520
+ this._order_container.hide();
521
+ this._billing_container.hide();
522
+ this._payment_container.show();
523
+ this._processing_container.hide();
524
+ this._checkout_button.nodes.text.text("Checkout");
525
+ // this._policy_checkbox.show();
526
+ this._prev_step_button.show();
527
+ break;
528
+ }
529
+ }
530
+ },
531
+
532
+ /**
533
+ * Navigate to the next step in the payment process.
534
+ */
535
+ _next: async function (): Promise<void | null> {
536
+ if (this._step < 3) {
537
+ ++this._step;
538
+ return this._set_step();
539
+ } else if (this._step === 3) {
540
+ return this._set_step();
541
+ }
542
+ },
543
+
544
+ /**
545
+ * Navigate to the previous step in the payment process.
546
+ */
547
+ _prev: async function (): Promise<void | null> {
548
+ if (this._step > 0) {
549
+ --this._step;
550
+ return this._set_step();
551
+ }
552
+ },
553
+
554
+ /**
555
+ * Render the steps element in the UI.
556
+ */
557
+ _render_steps_element: function (): void {
558
+ // Shortcuts.
559
+ const style = this._style;
560
+
561
+ // The previous step button.
562
+ this._prev_step_button = HStack(
563
+ ImageMask("/volt_static/payments/arrow.long.webp")
564
+ .frame(15, 15)
565
+ .mask_color(this._style.fg_1)
566
+ .transition_mask("background 300ms ease-in-out")
567
+ .transform("rotate(180deg)")
568
+ .margin_right(10),
569
+ Text("Previous Step")
570
+ .color(this._style.fg_1)
571
+ .transition("color 300ms ease-in-out")
572
+ .padding(0)
573
+ .margin(0)
574
+ .font_size(14)
575
+ )
576
+ .hide()
577
+ .on_mouse_over_out(
578
+ (e: any) => {
579
+ e.child(0).color(this._style.fg);
580
+ e.child(1).color(this._style.fg);
581
+ },
582
+ (e: any) => {
583
+ e.child(0).color(this._style.fg_1);
584
+ e.child(1).color(this._style.fg_1);
585
+ },
586
+ )
587
+ .on_click(() => {
588
+ this._prev()
589
+ .catch((err: any) => console.error(err));
590
+ })
591
+ .center_vertical();
592
+
593
+ // The steps element.
594
+ this._steps_element = HStack(
595
+ ForEach(
596
+ ["Order Details", "Billing Details", "Payment Details", "Processing Details"],
597
+ (item: string, index: number) => {
598
+ const stack = HStack(
599
+ VStack((index + 1).toString())
600
+ .font_size(11)
601
+ .padding(0)
602
+ .margin(0)
603
+ .color(index === 0 ? this._style.selected.fg : this._style.fg_1)
604
+ .frame(17.5, 17.5)
605
+ .background(index === 0 ? this._style.selected.bg : this._style.bg_1)
606
+ .transition("color 300ms ease-in-out, background 300ms ease-in-out")
607
+ .border_radius("50%")
608
+ .margin_right(15)
609
+ .flex_shrink(0)
610
+ .center()
611
+ .center_vertical()
612
+ .border(1, this._style.divider_bg),
613
+ Text(item)
614
+ .color(index === 0 ? this._style.fg : this._style.fg_1)
615
+ .transition("color 300ms ease-in-out")
616
+ .padding(0)
617
+ .font_size(14)
618
+ .line_height(16)
619
+ )
620
+ .center_vertical()
621
+ .margin_right(25);
622
+ return stack;
623
+ }
624
+ ),
625
+ Spacer().min_frame(10, 1),
626
+ this._prev_step_button,
627
+ )
628
+ .overflow_x("scroll")
629
+ .class("hide_scrollbar")
630
+ .extend(
631
+ {
632
+ selected_index: 0,
633
+ /**
634
+ * Select the current step index and update UI accordingly.
635
+ * @param index - The index of the step to select.
636
+ */
637
+ select(index) {
638
+ let e = this.child(this.selected_index);
639
+ e.child(0)
640
+ .color(style.fg_1)
641
+ .background(style.bg_1);
642
+ e.child(1)
643
+ .color(style.fg_1);
644
+
645
+ this.selected_index = index;
646
+
647
+ e = this.child(this.selected_index);
648
+ e.child(0)
649
+ .color(style.selected.fg)
650
+ .background(style.selected.bg);
651
+ e.child(1)
652
+ .color(style.fg);
653
+
654
+ return this;
655
+ },
656
+
657
+ } as HStackElement & {
658
+ selected_index: number
659
+ select(index: number);
660
+ }
661
+ );
662
+
663
+ // Append the steps element to the steps container.
664
+ this._steps_container.append(this._steps_element);
665
+ },
666
+
667
+ /**
668
+ * Render the overview element in the UI.
669
+ */
670
+ _render_overview_element: function (): void {
671
+ // The subtotal price from the overview.
672
+ this._overview_subtotal = Text(`${this._currency_symbol == null ? "$" : this._currency_symbol} 0.00`)
673
+ .color(this._style.fg)
674
+ .font_size(this._style.font_size)
675
+ .flex_shrink(0)
676
+ .margin(0)
677
+ .padding(0);
678
+
679
+ // The total price from the overview.
680
+ this._overview_total = Text(`${this._currency_symbol == null ? "$" : this._currency_symbol} 0.00`)
681
+ .font_weight("bold")
682
+ .color(this._style.fg)
683
+ .font_size(this._style.font_size)
684
+ .flex_shrink(0)
685
+ .margin(0)
686
+ .padding(0);
687
+
688
+ // The subtotal VAT price from the overview.
689
+ this._overview_subtotal_tax = Text(`${this._currency_symbol == null ? "$" : this._currency_symbol} 0.00`)
690
+ .color(this._style.fg)
691
+ .font_size(this._style.font_size)
692
+ .flex_shrink(0)
693
+ .margin(0)
694
+ .padding(0);
695
+
696
+ // The tax stack.
697
+ this._overview_tax_container = HStack(
698
+ Text("Tax:")
699
+ .color(this._style.fg)
700
+ .font_size(this._style.font_size)
701
+ .stretch(true)
702
+ .flex_shrink(0)
703
+ .margin(0, 5, 0, 0)
704
+ .padding(0)
705
+ .wrap(false)
706
+ .overflow("hidden")
707
+ .text_overflow("ellipsis"),
708
+ this._overview_subtotal_tax,
709
+ )
710
+ .margin_top(5);
711
+
712
+ // The incl/excl tax text.
713
+ this._overview_incl_excl_tax = Text(this.tax_inclusive ? "incl. tax" : "excl. tax")
714
+ .color(this._style.fg_2)
715
+ .font_size(this._style.font_size - 6)
716
+ .margin(2.5, 0, 0, 0)
717
+ .padding(0)
718
+ .flex_shrink(0)
719
+ .text_trailing();
720
+
721
+ // The checkout button.
722
+ this._checkout_button = LoaderButton("Next")
723
+ .color(this._style.button.fg)
724
+ .background(this._style.button.bg)
725
+ .border_radius(this._style.button.border_radius)
726
+ .border(this._style.button.border_inset ? `${this._style.button.border_width} inset ${this._style.button.border_color}` : `${this._style.button.border_width} solid ${this._style.button.border_color}`)
727
+ .hover_brightness(...this._style.button.hover_brightness as [any, any])
728
+ .nodes.loader
729
+ .background(this._style.button.fg)
730
+ .update()
731
+ .parent<LoaderButtonElement>()
732
+ .on_click(async () => {
733
+ this._checkout_button.show_loader();
734
+ Payments._next()
735
+ .then(() => {
736
+ this._checkout_button.hide_loader();
737
+ })
738
+ .catch((err: any) => {
739
+ console.error(err);
740
+ this._checkout_button.hide_loader();
741
+ });
742
+ });
743
+
744
+ // Accept agreements (currently commented out).
745
+ // this._policy_checkbox = CheckBox({
746
+ // text: "I agree to the Terms and Conditions and the " +
747
+ // Link("Refund", this._refund_policy) +
748
+ // " and " +
749
+ // Link("Cancellation", this._cancellation_policy) +
750
+ // " policy. I agree that my payment method may be used for recurring subscriptions.",
751
+ // required: true
752
+ // }) // @todo check text.
753
+ // .color(this._style.fg_2)
754
+ // .border_color(this._style.divider_bg)
755
+ // .font_size(this._style.font_size - 6)
756
+ // .focus_color(this._style.theme_fg)
757
+ // .missing_color(this._style.missing_fg)
758
+ // .inner_bg(this._style.bg)
759
+ // .margin_bottom(15)
760
+ // .hide();
761
+
762
+ // The overview element.
763
+ this._overview_element = VStack(
764
+ Title("Overview")
765
+ .color(this._style.fg)
766
+ .width("fit-content")
767
+ .font_size(this._style.font_size - 2)
768
+ .flex_shrink(0)
769
+ .margin(0, 0, 15, 0)
770
+ .letter_spacing("1px")
771
+ .text_transform("uppercase")
772
+ .ellipsis_overflow(true),
773
+
774
+ HStack(
775
+ Text("Subtotal:")
776
+ .color(this._style.fg)
777
+ .font_size(this._style.font_size)
778
+ .stretch(true)
779
+ .flex_shrink(0)
780
+ .margin(0, 5, 0, 0)
781
+ .padding(0)
782
+ .wrap(false)
783
+ .overflow("hidden")
784
+ .text_overflow("ellipsis"),
785
+ this._overview_subtotal,
786
+ ),
787
+ // Uncomment and define Shipping if needed.
788
+ // HStack(
789
+ // Text("Shipping:")
790
+ // .color(this._style.fg_1)
791
+ // .font_size(this._style.font_size)
792
+ // .stretch(true)
793
+ // .flex_shrink(0)
794
+ // .margin(0, 5, 0, 0)
795
+ // .padding(0)
796
+ // .wrap(false)
797
+ // .overflow("hidden")
798
+ // .text_overflow("ellipsis"),
799
+ // Text("free")
800
+ // .color(this._style.fg_1)
801
+ // .font_size(this._style.font_size)
802
+ // .flex_shrink(0)
803
+ // .margin(0)
804
+ // .padding(0)
805
+ // .wrap(false)
806
+ // .overflow("hidden")
807
+ // .text_overflow("ellipsis"),
808
+ // )
809
+ // .margin_top(5),
810
+ this._overview_tax_container,
811
+ Divider()
812
+ .margin(20, 0, 20, 0)
813
+ .background(this._style.divider_bg),
814
+ HStack(
815
+ Text("Total:")
816
+ .font_weight("bold")
817
+ .color(this._style.fg)
818
+ .font_size(this._style.font_size)
819
+ .stretch(true)
820
+ .flex_shrink(0)
821
+ .margin(0, 5, 0, 0)
822
+ .padding(0)
823
+ .wrap(false)
824
+ .overflow("hidden")
825
+ .text_overflow("ellipsis"),
826
+ VStack(
827
+ this._overview_total,
828
+ this._overview_incl_excl_tax,
829
+ ),
830
+ )
831
+ .margin_bottom(25),
832
+ // this._policy_checkbox,
833
+ this._checkout_button,
834
+ )
835
+ .extend({
836
+ total: 0,
837
+ tax: 0,
838
+ /**
839
+ * Handle unknown tax scenarios by updating the UI accordingly.
840
+ */
841
+ unknown_tax: () => {
842
+ this._overview_incl_excl_tax.text(this.tax_inclusive ? "incl. tax" : "excl. tax");
843
+ this._overview_tax_container.hide();
844
+ this._overview_element.tax = 0;
845
+ this._overview_total.text(`${this._currency_symbol} ${this._overview_element.total.toFixed(2)}`);
846
+ },
847
+ /**
848
+ * Calculate tax based on the provided country code.
849
+ * @param country - The country code to calculate tax for.
850
+ */
851
+ calc_tax: async (country: string) => {
852
+ this._initialize_paddle();
853
+ try {
854
+ const result = await Paddle.PricePreview({
855
+ items: this.cart.items.map((item: any) => {
856
+ return { priceId: item.product.price_id, quantity: item.quantity };
857
+ }),
858
+ address: { countryCode: country },
859
+ });
860
+ this._overview_element.tax = 0;
861
+ result.data.details.lineItems.forEach((item: any) => {
862
+ this._overview_element.tax += parseInt(item.totals.tax) / 100;
863
+ });
864
+ this._overview_tax_container.show();
865
+ this._overview_incl_excl_tax.text("incl. tax");
866
+ this._overview_subtotal_tax.text(`${this._currency_symbol} ${this._overview_element.tax.toFixed(2)}`);
867
+ this._overview_total.text(`${this._currency_symbol} ${(this._overview_element.total + this._overview_element.tax).toFixed(2)}`);
868
+ } catch (error: any) {
869
+ if (error?.error?.detail) {
870
+ this.on_error(error.error.detail);
871
+ console.error(error);
872
+ } else {
873
+ console.error(error);
874
+ }
875
+ this._overview_element.unknown_tax();
876
+ }
877
+ },
878
+ });
879
+
880
+ // Append the overview element to the overview container.
881
+ this._overview_container.append(this._overview_element);
882
+ },
883
+
884
+ /**
885
+ * Render the order element in the UI.
886
+ */
887
+ _render_order_element: function (): void {
888
+ // Render.
889
+ interface Extension extends VStackElement {
890
+ refresh(this: Extension): Extension;
891
+ }
892
+ this._order_element = VStack()
893
+ .extend({
894
+ /**
895
+ * Refresh the order element by updating the cart and UI elements.
896
+ */
897
+ refresh(this) {
898
+
899
+ // Refresh the cart.
900
+ Payments.cart.refresh();
901
+
902
+ // Shortcuts.
903
+ const style = Payments._style;
904
+ const cart = Payments.cart;
905
+ const cart_items = Payments.cart.items;
906
+
907
+ // Shopping cart view.
908
+ let currency_symbol: string | null = null;
909
+ let subtotal = 0;
910
+ cart_items.forEach((item: any) => {
911
+ if (currency_symbol === null) {
912
+ currency_symbol = Payments.get_currency_symbol(item.product.currency);
913
+ }
914
+ subtotal += item.product.price * item.quantity;
915
+ });
916
+ if (currency_symbol === null) {
917
+ currency_symbol = "$";
918
+ }
919
+ Payments._currency_symbol = currency_symbol;
920
+
921
+ // Set the overview prices.
922
+ Payments._overview_subtotal.text(`${currency_symbol} ${subtotal.toFixed(2)}`);
923
+ Payments._overview_element.total = subtotal;
924
+ Payments._overview_element.unknown_tax();
925
+
926
+ // Add the products.
927
+ this.remove_children();
928
+ if (cart_items.length === 0) {
929
+ this.height(160);
930
+ this.append(
931
+ VStack(
932
+ Title("Empty Shopping Cart")
933
+ .color(style.fg_1)
934
+ .font_size(style.font_size - 2)
935
+ .flex_shrink(0)
936
+ .letter_spacing("1px")
937
+ .text_transform("uppercase")
938
+ .ellipsis_overflow(true)
939
+ .margin(0)
940
+ .padding(0)
941
+ .assign_to_parent_as("title_e"),
942
+ Text(`Your shopping cart is empty.`)
943
+ .color(style.fg_2)
944
+ .font_size(style.font_size - 2)
945
+ .line_height(style.font_size)
946
+ .margin(5, 0, 0, 0)
947
+ .padding(0)
948
+ .assign_to_parent_as("text_e")
949
+ .white_space("pre")
950
+ .line_height("1.4em")
951
+ .center(),
952
+ ImageMask("/volt_static/payments/shopping_cart.webp")
953
+ .frame(35, 35)
954
+ .margin_top(20)
955
+ .mask_color(style.theme_fg),
956
+ )
957
+ .frame("100%", "100%")
958
+ .center()
959
+ .center_vertical()
960
+ );
961
+ } else {
962
+ // Uncomment and adjust height if necessary.
963
+ // this.height("100%");
964
+ this.append(
965
+ Title("Order Details")
966
+ .color(style.fg)
967
+ .width("fit-content")
968
+ .font_size(style.font_size - 2)
969
+ .flex_shrink(0)
970
+ .margin(0, 0, 0, 0)
971
+ .letter_spacing("1px")
972
+ .text_transform("uppercase")
973
+ .ellipsis_overflow(true),
974
+
975
+ Divider()
976
+ .background(style.divider_bg)
977
+ .margin(10, 0, 20, 0),
978
+
979
+ ForEach(cart_items, (item: any, index: number) => {
980
+ let focus = false, mouse_over = false;
981
+ const quantity_input = Input("Quantity")
982
+ .value(item.quantity)
983
+ .font_size(16)
984
+ .color(style.fg_1)
985
+ .font_size(style.font_size - 2)
986
+ .border(1, style.divider_bg)
987
+ // .padding(12.5, 10, 12.5, 10)
988
+ .padding(2.5, 7.5)
989
+ .margin_right(25)
990
+ .flex_shrink(0)
991
+ .width(`calc(${item.quantity.toString().length}ch + 17.5px)`) // add padding.
992
+ .background(style.bg_1)
993
+ .display("inline")
994
+ .transition("color 300ms ease-in-out")
995
+ .center()
996
+ .on_input((_, event: any) => {
997
+ const value = quantity_input.value();
998
+ quantity_input.width(`calc(${value.length}ch + 17.5px)`); // add padding.
999
+ clearTimeout((quantity_input as any)._timeout);
1000
+ (quantity_input as any)._timeout = setTimeout(() => {
1001
+ const quantity = parseInt(value);
1002
+ if (isNaN(quantity)) {
1003
+ console.error(`Specified quantity "${value}" is not a number.`);
1004
+ Payments.on_error(new Error(`Specified quantity "${value}" is not a number.`));
1005
+ quantity_input.value(item.quantity.toString());
1006
+ return null;
1007
+ }
1008
+ item.quantity = quantity;
1009
+ cart.save();
1010
+ this.refresh();
1011
+ }, 500);
1012
+ })
1013
+ .on_mouse_over_out(
1014
+ (e: any) => {
1015
+ e.color(style.fg);
1016
+ mouse_over = true;
1017
+ e.mask_color(style.fg);
1018
+ },
1019
+ (e: any) => {
1020
+ mouse_over = false;
1021
+ if (!mouse_over && !focus) {
1022
+ e.color(style.fg_1);
1023
+ }
1024
+ },
1025
+ )
1026
+ .on_focus((e: any) => {
1027
+ e.color(style.fg);
1028
+ focus = true;
1029
+ })
1030
+ .on_blur((e: any) => {
1031
+ focus = false;
1032
+ if (!mouse_over && !focus) {
1033
+ e.color(style.fg_1);
1034
+ }
1035
+ });
1036
+
1037
+ let per_item = " per item" + (Payments.tax_inclusive ? " incl. tax" : " excl. tax") + ",";
1038
+ let renews_every: string | null = null;
1039
+ if (item.product.interval) {
1040
+ if (item.product.frequency === 1) {
1041
+ renews_every = `renews ${item.product.interval}ly.`;
1042
+ } else {
1043
+ renews_every = `renews every ${item.product.frequency} ${item.product.interval}s.`;
1044
+ }
1045
+ }
1046
+ let trial_text: string | null = null;
1047
+ if (item.product.trial) {
1048
+ if (item.product.trial.frequency === 1) {
1049
+ trial_text = `${item.product.trial.frequency} ${item.product.trial.interval} free`;
1050
+ } else {
1051
+ trial_text = `${item.product.trial.frequency} ${item.product.trial.interval}s free`;
1052
+ }
1053
+ }
1054
+ const stack = HStack(
1055
+ item.product.icon == null ? null :
1056
+ ImageMask(item.product.icon)
1057
+ .frame(30, 30)
1058
+ .flex_shrink(0)
1059
+ .margin(0, 25, 0, 0),
1060
+ VStack(
1061
+ Title(item.product.name)
1062
+ .color(style.fg)
1063
+ .font_size(style.font_size)
1064
+ .margin(0, 10, 0, 0)
1065
+ .padding(0)
1066
+ .wrap(false)
1067
+ .overflow("hidden")
1068
+ .text_overflow("ellipsis"),
1069
+ Text(item.product.description)
1070
+ .color(style.fg_1)
1071
+ .font_size(style.font_size - 2)
1072
+ .line_height(style.font_size)
1073
+ .margin(10, 10, 0, 0)
1074
+ .wrap(true)
1075
+ .padding(0),
1076
+ HStack(
1077
+ Text("Quantity:")
1078
+ .color(style.fg_1)
1079
+ .font_size(style.font_size - 2)
1080
+ // .line_height(style.font_size)
1081
+ .margin(0, 10, 2, 0)
1082
+ .padding(0)
1083
+ .flex_shrink(0),
1084
+ quantity_input,
1085
+ ImageMask("/volt_static/payments/minus.webp")
1086
+ .frame(20, 20)
1087
+ .padding(5)
1088
+ .margin_right(5)
1089
+ .mask_color(style.fg_1)
1090
+ .background(style.bg_1)
1091
+ .border(1, style.divider_bg)
1092
+ .border_radius("50%")
1093
+ .flex_shrink(0)
1094
+ .transition_mask("background 300ms ease-in-out")
1095
+ .on_mouse_over_out(
1096
+ (e: any) => e.mask_color(style.fg),
1097
+ (e: any) => e.mask_color(style.fg_1)
1098
+ )
1099
+ .on_click(async () => {
1100
+ if (item.quantity === 1) {
1101
+ await cart.remove(item.product.id, "all");
1102
+ this.refresh();
1103
+ } else {
1104
+ await cart.remove(item.product.id, 1);
1105
+ this.refresh();
1106
+ }
1107
+ }),
1108
+ ImageMask("/volt_static/payments/plus.webp")
1109
+ .frame(20, 20)
1110
+ .padding(5)
1111
+ .margin_right(5)
1112
+ .mask_color(style.fg_1)
1113
+ .background(style.bg_1)
1114
+ .border(1, style.divider_bg)
1115
+ .border_radius("50%")
1116
+ .flex_shrink(0)
1117
+ .transition_mask("background 300ms ease-in-out")
1118
+ .on_mouse_over_out(
1119
+ (e: any) => e.mask_color(style.fg),
1120
+ (e: any) => e.mask_color(style.fg_1)
1121
+ )
1122
+ .on_click(async () => {
1123
+ await cart.add(item.product.id, 1);
1124
+ this.refresh();
1125
+ }),
1126
+ ImageMask("/volt_static/payments/trash.webp")
1127
+ .frame(20, 20)
1128
+ .padding(5)
1129
+ .margin_right(5)
1130
+ .mask_color(style.fg_1)
1131
+ .background(style.bg_1)
1132
+ .border(1, style.divider_bg)
1133
+ .border_radius("50%")
1134
+ .flex_shrink(0)
1135
+ .transition_mask("background 300ms ease-in-out")
1136
+ .on_mouse_over_out(
1137
+ (e: any) => e.mask_color(style.fg),
1138
+ (e: any) => e.mask_color(style.fg_1)
1139
+ )
1140
+ .on_click(async () => {
1141
+ await cart.remove(item.product.id, "all");
1142
+ this.refresh();
1143
+ }),
1144
+ )
1145
+ .center_vertical()
1146
+ .wrap(true)
1147
+ .margin_top(17.5),
1148
+ )
1149
+ .stretch(true),
1150
+ VStack(
1151
+ Title(trial_text ? trial_text : `${currency_symbol} ${(item.product.price * item.quantity).toFixed(2)}`)
1152
+ .color(style.fg)
1153
+ .font_size(style.font_size)
1154
+ .margin(0)
1155
+ .padding(0)
1156
+ .flex_shrink(0)
1157
+ .wrap(false)
1158
+ .overflow("hidden")
1159
+ .text_overflow("ellipsis"),
1160
+ Text(`${trial_text ? "Then " : ""}${currency_symbol} ${item.product.price} ${per_item}`)
1161
+ .color(style.fg_1)
1162
+ .font_size(style.font_size - 6)
1163
+ .margin(5, 0, 0, 0)
1164
+ .padding(0)
1165
+ .flex_shrink(0),
1166
+ renews_every == null ? null : Text(renews_every)
1167
+ .color(style.fg_1)
1168
+ .font_size(style.font_size - 6)
1169
+ .margin(2.5, 0, 0, 0)
1170
+ .padding(0)
1171
+ .flex_shrink(0),
1172
+ )
1173
+ )
1174
+ .overflow_x("scroll")
1175
+ .class("hide_scrollbar")
1176
+ .width("100%")
1177
+ .media(
1178
+ "width >= 800px",
1179
+ (e: any) => {
1180
+ e.wrap(false);
1181
+ e.child(2).min_width("none")
1182
+ .margin(0);
1183
+ },
1184
+ (e: any) => {
1185
+ e.wrap(true);
1186
+ e.child(2)
1187
+ .min_width("100%")
1188
+ .margin(15, 0, 0, 55);
1189
+ },
1190
+ );
1191
+ return [
1192
+ stack,
1193
+ index === cart_items.length - 1 ? null : Divider()
1194
+ .background(style.divider_bg)
1195
+ .margin(20, 0, 20, 0)
1196
+ ];
1197
+ })
1198
+ );
1199
+ }
1200
+ return this;
1201
+ }
1202
+ } as Extension);
1203
+
1204
+ // Append the order element to the order container.
1205
+ this._order_container.append(this._order_element.refresh());
1206
+ },
1207
+
1208
+ // Render the refunds element.
1209
+ _render_refunds_element: function(): void {
1210
+ // Render.
1211
+ const style = this._style;
1212
+ this._refunds_element = VStack()
1213
+ .extend({
1214
+ /**
1215
+ * Refresh the refunds element by fetching and displaying refundable, refunding, and refunded payments.
1216
+ */
1217
+ async refresh(this: VStackElement) {
1218
+ // Reset.
1219
+ this.inner_html("");
1220
+
1221
+ // Create containers.
1222
+ let payments = await Payments.get_refundable_payments({
1223
+ days: Payments._days_refundable,
1224
+ });
1225
+ const refundable_container = VStack()
1226
+ .extend({
1227
+ title: "Refundable Payments",
1228
+ payments: payments,
1229
+ is_refundable: true,
1230
+ });
1231
+ payments = await Payments.get_refunding_payments();
1232
+ const refunding_container = VStack()
1233
+ .hide()
1234
+ .extend({
1235
+ title: "Processing Refunds",
1236
+ payments: payments,
1237
+ is_refunding: true,
1238
+ });
1239
+ payments = await Payments.get_refunded_payments();
1240
+ const refunded_container = VStack()
1241
+ .hide()
1242
+ .extend({
1243
+ title: "Refunded Payments",
1244
+ payments: payments,
1245
+ is_refunded: true,
1246
+ });
1247
+
1248
+ // Option bar.
1249
+ const option_bar = HStack(
1250
+ Text("Refundable")
1251
+ .font_size(style.font_size)
1252
+ .color(style.fg_1)
1253
+ .background(style.bg_1)
1254
+ .padding(8, 6)
1255
+ .margin(0)
1256
+ .stretch(true)
1257
+ .text_center()
1258
+ .transition("color 350ms ease, background 350ms ease")
1259
+ .on_mouse_over((e: any) => {
1260
+ if (e.background() === "transparent") {
1261
+ e.color(style.fg);
1262
+ }
1263
+ })
1264
+ .on_mouse_out((e: any) => {
1265
+ if (e.background() === "transparent") {
1266
+ e.color(style.fg_1);
1267
+ }
1268
+ })
1269
+ .on_click((e: any) => {
1270
+ e.color(Payments._style.fg_1);
1271
+ e.background(Payments._style.bg_1);
1272
+ [e.parentElement.child(1), e.parentElement.child(2)].forEach((child: any) => {
1273
+ child.color(Payments._style.fg_1);
1274
+ child.background("none");
1275
+ });
1276
+
1277
+ refundable_container.show();
1278
+ refunding_container.hide();
1279
+ refunded_container.hide();
1280
+ }),
1281
+ Text("Processing")
1282
+ .font_size(style.font_size)
1283
+ .color(style.fg_1)
1284
+ .background("transparent")
1285
+ .padding(8, 6)
1286
+ .margin(0)
1287
+ .stretch(true)
1288
+ .text_center()
1289
+ .transition("color 350ms ease, background 350ms ease")
1290
+ .on_mouse_over((e: any) => {
1291
+ if (e.background() === "transparent") {
1292
+ e.color(style.fg);
1293
+ }
1294
+ })
1295
+ .on_mouse_out((e: any) => {
1296
+ if (e.background() === "transparent") {
1297
+ e.color(style.fg_1);
1298
+ }
1299
+ })
1300
+ .on_click((e: any) => {
1301
+ e.color(Payments._style.fg_1);
1302
+ e.background(Payments._style.bg_1);
1303
+ [e.parentElement.child(0), e.parentElement.child(2)].forEach((child: any) => {
1304
+ child.color(Payments._style.fg_1);
1305
+ child.background("none");
1306
+ });
1307
+
1308
+ refundable_container.hide();
1309
+ refunding_container.show();
1310
+ refunded_container.hide();
1311
+ }),
1312
+ Text("Refunded")
1313
+ .font_size(style.font_size)
1314
+ .color(style.fg_1)
1315
+ .background("transparent")
1316
+ .padding(8, 6)
1317
+ .margin(0)
1318
+ .stretch(true)
1319
+ .text_center()
1320
+ .transition("color 350ms ease, background 350ms ease")
1321
+ .on_mouse_over((e: any) => {
1322
+ if (e.background() === "transparent") {
1323
+ e.color(style.fg);
1324
+ }
1325
+ })
1326
+ .on_mouse_out((e: any) => {
1327
+ if (e.background() === "transparent") {
1328
+ e.color(style.fg_1);
1329
+ }
1330
+ })
1331
+ .on_click((e: any) => {
1332
+ e.color(Payments._style.fg_1);
1333
+ e.background(Payments._style.bg_1);
1334
+ [e.parentElement.child(0), e.parentElement.child(1)].forEach((child: any) => {
1335
+ child.color(Payments._style.fg_1);
1336
+ child.background("none");
1337
+ });
1338
+
1339
+ refundable_container.hide();
1340
+ refunding_container.hide();
1341
+ refunded_container.show();
1342
+ }),
1343
+ )
1344
+ .overflow("hidden")
1345
+ .border(1, style.divider_bg)
1346
+ .border_radius(style.border_radius)
1347
+ .margin_bottom(30)
1348
+ .flex_shrink(0);
1349
+
1350
+ // Assign to parent.
1351
+ const refundable_option = option_bar.child(0);
1352
+ const refunding_option = option_bar.child(1);
1353
+ const refunded_option = option_bar.child(2);
1354
+
1355
+ // Add elements.
1356
+ this.append(
1357
+ option_bar,
1358
+ refundable_container,
1359
+ refunding_container,
1360
+ refunded_container,
1361
+ );
1362
+
1363
+ // Separate payments.
1364
+ let currency_symbol: string | null = null;
1365
+ await Promise.all([refundable_container, refunding_container, refunded_container].map(async (container: any) => {
1366
+ if (container.payments.length === 0) {
1367
+ container.append(
1368
+ VStack(
1369
+ Title("No Payments")
1370
+ .color(style.fg)
1371
+ .font_size(style.font_size - 2)
1372
+ .flex_shrink(0)
1373
+ .letter_spacing("1px")
1374
+ .text_transform("uppercase")
1375
+ .ellipsis_overflow(true)
1376
+ .margin(0)
1377
+ .padding(0)
1378
+ .assign_to_parent_as("title_e"),
1379
+ Text(`There are no ${container.title.toLowerCase()}.`)
1380
+ .color(style.fg_1)
1381
+ .font_size(style.font_size - 2)
1382
+ .line_height(style.font_size)
1383
+ .margin(5, 0, 0, 0)
1384
+ .padding(0)
1385
+ .assign_to_parent_as("text_e")
1386
+ .white_space("pre")
1387
+ .line_height("1.4em")
1388
+ .center(),
1389
+ Image("/volt_static/payments/check.webp")
1390
+ .frame(30, 30)
1391
+ .margin_top(15)
1392
+ .assign_to_parent_as("success_image_e"),
1393
+ )
1394
+ .min_height(160)
1395
+ .frame("100%", "100%")
1396
+ .center()
1397
+ .center_vertical()
1398
+ );
1399
+ } else {
1400
+ await Promise.all(container.payments.map(async (payment: any) => {
1401
+ await Promise.all(payment.line_items.map(async (item: any) => {
1402
+ item.product = await Payments.get_product(item.product);
1403
+ }));
1404
+ }));
1405
+ container.append(
1406
+ Title(container.title)
1407
+ .color(style.fg)
1408
+ .width("fit-content")
1409
+ .font_size(style.font_size - 2)
1410
+ .flex_shrink(0)
1411
+ .margin(0, 0, 0, 0)
1412
+ .letter_spacing("1px")
1413
+ .text_transform("uppercase")
1414
+ .ellipsis_overflow(true),
1415
+
1416
+ Divider()
1417
+ .background(style.divider_bg)
1418
+ .margin(10, 0, 20, 0),
1419
+
1420
+ ForEach(container.payments, (payment: any, index: number) => {
1421
+ // Line items.
1422
+ const items = VStack(
1423
+ ForEach(payment.line_items, (item: any, index: number) => {
1424
+ if (currency_symbol == null) {
1425
+ currency_symbol = Payments.get_currency_symbol(item.product.currency);
1426
+ }
1427
+ return [
1428
+ HStack(
1429
+ item.product.icon == null ? null :
1430
+ Image(item.product.icon)
1431
+ .frame(25, 25)
1432
+ .flex_shrink(0)
1433
+ .margin(0, 20, 0, 0),
1434
+ VStack(
1435
+ Title(item.product.name)
1436
+ .color(style.fg)
1437
+ .font_size(style.font_size - 2)
1438
+ .line_height(style.font_size)
1439
+ .margin(0, 10, 0, 0)
1440
+ .padding(0)
1441
+ .font_weight("bold")
1442
+ .ellipsis_overflow(true),
1443
+ Text(item.product.description)
1444
+ .color(style.fg_1)
1445
+ .font_size(style.font_size - 4)
1446
+ .line_height(style.font_size - 2)
1447
+ .margin(5, 0, 0, 0)
1448
+ .wrap(true)
1449
+ .padding(0),
1450
+ )
1451
+ .stretch(true),
1452
+ VStack(
1453
+ Text(`${currency_symbol} ${(item.total).toFixed(2)}`)
1454
+ .color(style.fg_1)
1455
+ .font_size(style.font_size - 4)
1456
+ .line_height(style.font_size - 2)
1457
+ .margin(0)
1458
+ .padding(0)
1459
+ .flex_shrink(0)
1460
+ .ellipsis_overflow(true),
1461
+ )
1462
+ ),
1463
+ index === payment.line_items.length - 1 ? null : Divider()
1464
+ .background(style.divider_bg)
1465
+ .margin(15, 0, 15, 0),
1466
+ ];
1467
+ }),
1468
+ )
1469
+ .background(style.bg_1)
1470
+ .border_radius(style.border_radius)
1471
+ .border(1, style.divider_bg)
1472
+ .padding(20);
1473
+
1474
+ // Payment.
1475
+ const stack = VStack(
1476
+ HStack(
1477
+ Title("Payment")
1478
+ .color(style.fg)
1479
+ .font_size(style.font_size)
1480
+ .margin(0, 10, 0, 0)
1481
+ .padding(0)
1482
+ .wrap(false)
1483
+ .overflow("hidden")
1484
+ .text_overflow("ellipsis")
1485
+ .stretch(true),
1486
+ !container.is_refundable ? null : BorderButton("Refund")
1487
+ .font_size(style.font_size - 4)
1488
+ .padding(7.5, 10)
1489
+ .margin(0, 5, 0, 0)
1490
+ .color(style.button.bg)
1491
+ .border_radius(style.button.border_radius)
1492
+ .border_color(style.button.bg)
1493
+ .hover_brightness(...style.button.hover_brightness as [any, any])
1494
+ .font_weight("bold")
1495
+ .on_click(() => {
1496
+ document.body.appendChild(
1497
+ Popup({
1498
+ title: "Request Refund",
1499
+ text: `You are about to request a refund for payment <span style='border-radius: 7px; background: ${style.bg_1}; padding: 1px 4px; font-size: 0.9em;'>${payment.id}</span>, do you wish to proceed?`,
1500
+ no: "No",
1501
+ yes: "Yes",
1502
+ image: "/volt_static/payments/error.webp",
1503
+ blur: 5,
1504
+ animation_duration: 300,
1505
+ on_yes: async () => {
1506
+ try {
1507
+ await Payments.create_refund(payment);
1508
+ } catch(err) {
1509
+ console.error(err);
1510
+ Payments.on_error(err as Error);
1511
+ return null;
1512
+ }
1513
+ (this as any).refresh().then(() => {
1514
+ refunding_option.click();
1515
+ });
1516
+ },
1517
+ })
1518
+ .font(window.getComputedStyle(Payments._refunds_container).font)
1519
+ .widget
1520
+ .background(style.bg)
1521
+ .color(style.fg_1)
1522
+ .border_bottom("4px solid #E8454E")
1523
+ // .leading()
1524
+ .parent<PopupElement>()
1525
+ .title
1526
+ .color(style.fg)
1527
+ // .width("fit-content")
1528
+ .font_size(style.font_size + 2)
1529
+ .flex_shrink(0)
1530
+ .margin(0, 0, 0, 10)
1531
+ // .letter_spacing("1px")
1532
+ // .text_transform("uppercase")
1533
+ // .ellipsis_overflow(true)
1534
+ // .color(style.fg_1)
1535
+ .center()
1536
+ .parent<PopupElement>()
1537
+ .text
1538
+ .color(style.fg_1)
1539
+ .font_size(style.font_size)
1540
+ .margin_left(10)
1541
+ .center()
1542
+ .parent<PopupElement>()
1543
+ .image
1544
+ .padding(10)
1545
+ .mask_color(style.bg)
1546
+ .border_radius("50%")
1547
+ .background("#E8454E")
1548
+ .frame(40, 40)
1549
+ .box_shadow('0 0 0 4px #E8454E50')
1550
+ .parent<PopupElement>()
1551
+ .no_button
1552
+ .padding(10, 0)
1553
+ .font_size(style.font_size)
1554
+ .background(style.bg_1)
1555
+ .color(style.fg_1)
1556
+ .border(1, style.divider_bg)
1557
+ .hover_brightness(...style.button.hover_brightness as [any, any])
1558
+ .box_shadow('0px 0px 5px #00000030')
1559
+ .parent<PopupElement>()
1560
+ .yes_button
1561
+ .padding(10, 0)
1562
+ .font_size(style.font_size)
1563
+ .background("#E8454E")
1564
+ .color(style.fg_1)
1565
+ .border(1, style.divider_bg)
1566
+ .hover_brightness(...style.button.hover_brightness as [any, any])
1567
+ .box_shadow('0px 0px 5px #00000030')
1568
+ .parent<PopupElement>()
1569
+ );
1570
+ }),
1571
+ !container.is_refunding ? null : RingLoader()
1572
+ .frame(20, 20)
1573
+ .background(style.theme_fg)
1574
+ .margin(0, 5, 0, 0)
1575
+ .update(),
1576
+ !container.is_refunded ? null : Image("/volt_static/payments/check.webp")
1577
+ .frame(20, 20)
1578
+ .margin(0, 5, 0, 0),
1579
+ )
1580
+ .min_height(30),
1581
+ Text("")
1582
+ .inner_html(`Purchased at ${Utils.unix_to_date(payment.timestamp/1000)} <span style='font-size: 0.8em'>${payment.id}<span>.`)
1583
+ .color(style.fg_1)
1584
+ .font_size(style.font_size - 6)
1585
+ .line_height(style.font_size - 4)
1586
+ .margin(-5, 0, 10, 0)
1587
+ .wrap(true)
1588
+ .padding(0)
1589
+ .white_space("pre")
1590
+ .line_height("1.4em")
1591
+ .center(),
1592
+ items
1593
+ )
1594
+ .width("100%");
1595
+
1596
+ // Elements.
1597
+ return [
1598
+ stack,
1599
+ index === container.payments.length - 1 ? null : Divider()
1600
+ .background(style.divider_bg)
1601
+ .margin(20, 0, 20, 0),
1602
+ ];
1603
+ })
1604
+ );
1605
+ }
1606
+ }));
1607
+ return this;
1608
+ }
1609
+ });
1610
+
1611
+ // Append.
1612
+ this._refunds_element.refresh();
1613
+ this._refunds_container.append(this._refunds_element);
1614
+ },
1615
+
1616
+ // Render the address element.
1617
+ _render_billing_element: function(): void {
1618
+ if (this._billing_element !== undefined) { return ; }
1619
+
1620
+ // Utils.
1621
+ const CreateInput = (args: any) => {
1622
+ return ExtendedInput(args)
1623
+ .color(this._style.fg)
1624
+ .font_size(this._style.font_size)
1625
+ .missing_color(this._style.missing_fg)
1626
+ .focus_color(this._style.theme_fg)
1627
+ .border_color(this._style.divider_bg)
1628
+ .border_radius(this._style.border_radius)
1629
+ .input
1630
+ .color(this._style.fg_1)
1631
+ .parent<ExtendedInputElement>();
1632
+ }
1633
+ const CreateSelect = (args: any) => {
1634
+ return ExtendedSelect(args)
1635
+ .background(this._style.bg)
1636
+ .color(this._style.fg)
1637
+ .font_size(this._style.font_size)
1638
+ .missing_color(this._style.missing_fg)
1639
+ .focus_color(this._style.theme_fg)
1640
+ .border_color(this._style.divider_bg)
1641
+ .border_radius(this._style.border_radius)
1642
+ .dropdown_height(150)
1643
+ .background("transparent")
1644
+ .dropdown
1645
+ .background(this._style.bg_1)
1646
+ .background_blur(20)
1647
+ .parent<ExtendedSelectElement>()
1648
+ .input
1649
+ .white_space("pre")
1650
+ // .border_radius(0)
1651
+ .color(this._style.fg_1)
1652
+ .parent<ExtendedSelectElement>();
1653
+ }
1654
+
1655
+ // Create element.
1656
+ const input_spacing = 15;
1657
+ let country_code: any;
1658
+ this._billing_element = Form(
1659
+
1660
+ Title("Billing Details")
1661
+ .color(this._style.fg)
1662
+ .width("fit-content")
1663
+ .font_size(this._style.font_size - 2)
1664
+ .flex_shrink(0)
1665
+ .margin(0, 0, 0, 0)
1666
+ .letter_spacing("1px")
1667
+ .text_transform("uppercase")
1668
+ .ellipsis_overflow(true),
1669
+
1670
+ Divider()
1671
+ .background(this._style.divider_bg)
1672
+ .margin(10, 0, 10, 0),
1673
+
1674
+ HStack(
1675
+ Text("Personal")
1676
+ .font_size(this._style.font_size)
1677
+ .color(this._style.fg)
1678
+ .background(this._style.bg_1)
1679
+ .padding(8, 6)
1680
+ .margin(0)
1681
+ .stretch(true)
1682
+ .text_center()
1683
+ .transition("color 350ms ease, background 350ms ease")
1684
+ .on_mouse_over((e: any) => {
1685
+ if (e.background() === "transparent") {
1686
+ e.color(this._style.fg);
1687
+ }
1688
+ })
1689
+ .on_mouse_out((e: any) => {
1690
+ if (e.background() === "transparent") {
1691
+ e.color(this._style.fg_1);
1692
+ }
1693
+ })
1694
+ .on_click((e: any) => {
1695
+
1696
+ e.color(this._style.fg_1);
1697
+ e.background(this._style.bg_1)
1698
+ const other = e.parentElement.child(1);
1699
+ other.color(this._style.fg_1);
1700
+ other.background("none");
1701
+
1702
+ this._billing_element.name_input.show();
1703
+ this._billing_element.name_input.required(true);
1704
+ this._billing_element.business_input.hide();
1705
+ this._billing_element.business_input.required(false);
1706
+ this._billing_element.vat_id_input.hide();
1707
+ this._billing_element.vat_id_input.required(false);
1708
+ }),
1709
+ Text("Business")
1710
+ .font_size(this._style.font_size)
1711
+ .color(this._style.fg_1)
1712
+ .background("transparent")
1713
+ .padding(8, 6)
1714
+ .margin(0)
1715
+ .stretch(true)
1716
+ .text_center()
1717
+ .transition("color 350ms ease, background 350ms ease")
1718
+ .on_mouse_over((e: any) => {
1719
+ if (e.background() === "transparent") {
1720
+ e.color(this._style.fg);
1721
+ }
1722
+ })
1723
+ .on_mouse_out((e: any) => {
1724
+ if (e.background() === "transparent") {
1725
+ e.color(this._style.fg_1);
1726
+ }
1727
+ })
1728
+ .on_click((e: any) => {
1729
+
1730
+ e.color(this._style.fg_1);
1731
+ e.background(this._style.bg_1)
1732
+ const other = e.parentElement.child(0);
1733
+ other.color(this._style.fg_1);
1734
+ other.background("transparent");
1735
+
1736
+ this._billing_element.name_input.hide();
1737
+ this._billing_element.name_input.required(false);
1738
+ this._billing_element.business_input.show();
1739
+ this._billing_element.business_input.required(true);
1740
+ this._billing_element.vat_id_input.show();
1741
+ this._billing_element.vat_id_input.required(true);
1742
+ }),
1743
+ )
1744
+ .overflow("hidden")
1745
+ .border(1, this._style.divider_bg)
1746
+ .border_radius(this._style.border_radius)
1747
+ .margin_top(10)
1748
+ .margin_bottom(10)
1749
+ .flex_shrink(0),
1750
+
1751
+ CreateInput({
1752
+ label: "Full Name",
1753
+ placeholder: "John Doe",
1754
+ })
1755
+ .value(User.first_name() === undefined ? "" : (User.first_name() + " " + User.last_name()))
1756
+ .margin_top(input_spacing)
1757
+ .required(true)
1758
+ .id("name")
1759
+ .assign_to_parent_as("name_input"),
1760
+
1761
+ CreateInput({
1762
+ label: "Business Name",
1763
+ placeholder: "Company Inc.",
1764
+ })
1765
+ .margin_top(input_spacing)
1766
+ .required(false)
1767
+ .id("business")
1768
+ .hide()
1769
+ .assign_to_parent_as("business_input"),
1770
+
1771
+ CreateInput({
1772
+ label: "VAT ID",
1773
+ placeholder: "VAT ID",
1774
+ })
1775
+ .margin_top(input_spacing)
1776
+ .required(false)
1777
+ .id("vat_id")
1778
+ .hide()
1779
+ .assign_to_parent_as("vat_id_input"),
1780
+
1781
+ CreateInput({
1782
+ label: "Email",
1783
+ placeholder: "my@email.com",
1784
+ })
1785
+ .value(User.email() ?? "")
1786
+ .margin_top(input_spacing)
1787
+ .required(true)
1788
+ .id("email"),
1789
+
1790
+ CreateInput({
1791
+ label: "Street",
1792
+ placeholder: "123 Park Avenue",
1793
+ })
1794
+ .margin_top(input_spacing)
1795
+ .required(true)
1796
+ .id("street"),
1797
+
1798
+ CreateInput({
1799
+ label: "House Number",
1800
+ placeholder: "Suite 405",
1801
+ })
1802
+ .margin_top(input_spacing)
1803
+ .required(true)
1804
+ .id("house_number"),
1805
+
1806
+ CreateInput({
1807
+ label: "Postal Code",
1808
+ placeholder: "10001",
1809
+ })
1810
+ .margin_top(input_spacing)
1811
+ .required(true)
1812
+ .id("postal_code"),
1813
+
1814
+ CreateInput({
1815
+ label: "City",
1816
+ placeholder: "New York",
1817
+ })
1818
+ .margin_top(input_spacing)
1819
+ .required(true)
1820
+ .id("city"),
1821
+
1822
+ CreateInput({
1823
+ label: "Province",
1824
+ placeholder: "New York",
1825
+ })
1826
+ .margin_top(input_spacing)
1827
+ .required(true)
1828
+ .id("province"),
1829
+
1830
+ CreateSelect({
1831
+ label: "Country",
1832
+ placeholder: "United States",
1833
+ items: Object.fromEntries(Object.entries(Payments.countries).map(([key, value]) => [key, value.name])),
1834
+ })
1835
+ .on_change((_: any, country: string) => {
1836
+ this._overview_element.calc_tax(country);
1837
+ country_code.value(Payments.countries[country].calling_code);
1838
+ })
1839
+ .margin_top(input_spacing)
1840
+ .required(true)
1841
+ .id("country"),
1842
+
1843
+ HStack(
1844
+ country_code = CreateInput({
1845
+ label: "Country Code",
1846
+ placeholder: "+1",
1847
+ type: "tel",
1848
+ })
1849
+ .max_width("fit-content")
1850
+ .margin_top(input_spacing)
1851
+ .margin_right(input_spacing)
1852
+ .required(true)
1853
+ .input
1854
+ .readonly(true)
1855
+ .parent<ExtendedInputElement>()
1856
+ .id("phone_country_code"),
1857
+
1858
+ CreateInput({
1859
+ label: "Phone Number",
1860
+ placeholder: "1234567890",
1861
+ type: "tel",
1862
+ })
1863
+ .margin_top(input_spacing)
1864
+ .stretch(true)
1865
+ .required(true)
1866
+ .id("phone_number"),
1867
+ )
1868
+ .width("100%")
1869
+ );
1870
+
1871
+ // Append.
1872
+ this._billing_container.append(this._billing_element);
1873
+ },
1874
+
1875
+ // Render the payment element.
1876
+ _render_payment_element: async function(): Promise<void> {
1877
+ return new Promise((resolve, reject) => {
1878
+ this._render_payment_element_resolve = resolve;
1879
+ this._render_payment_element_reject = reject;
1880
+
1881
+ // Already rendered.
1882
+ if (this._payment_element !== undefined) {
1883
+ return resolve();
1884
+ }
1885
+
1886
+ // Checks.
1887
+ if (this.client_key == null) {
1888
+ return reject(new Error(`No client key has been assigned to "Payments.client_key".`));
1889
+ }
1890
+ if (this.cart.items.length === 0) {
1891
+ return reject(new Error("Shopping cart is empty."));
1892
+ }
1893
+
1894
+ // Check subscription or one time payment.
1895
+ let is_subscription = false;
1896
+ this.cart.items.forEach((item: any) => {
1897
+ if (item.is_subscription === true) {
1898
+ is_subscription = true;
1899
+ return false;
1900
+ }
1901
+ });
1902
+
1903
+ // Initialize paddle.
1904
+ this._initialize_paddle();
1905
+
1906
+ // Create element.
1907
+ this._payment_element = VStack()
1908
+ .class("checkout-container");
1909
+
1910
+ // Append.
1911
+ this._payment_container.append(this._payment_element);
1912
+
1913
+ // Initialize.
1914
+ let custom_data: any = {
1915
+ customer_name: this._billing_details.name,
1916
+ };
1917
+ if (User.is_authenticated()) {
1918
+ custom_data.uid = User.uid();
1919
+ }
1920
+ try {
1921
+ let business: any = undefined;
1922
+ if (this._billing_details.business !== "") {
1923
+ business = {
1924
+ name: this._billing_details.business,
1925
+ taxIdentifier: this._billing_details.vat_id === "" ? undefined : this._billing_details.vat_id,
1926
+ };
1927
+ }
1928
+ Paddle.Checkout.open({
1929
+ settings: {
1930
+ displayMode: "inline",
1931
+ theme: this._theme,
1932
+ locale: "en",
1933
+ frameTarget: "checkout-container",
1934
+ frameInitialHeight: "450",
1935
+ frameStyle: "width: 100%; min-width: 312px; background-color: transparent; border: none;",
1936
+ // successUrl: this.return_url,
1937
+ // successUrl: "http://test.vandenberghinc.com/checkout?payment_status=success",
1938
+ },
1939
+ items: this.cart.items.map((item: any) => { return { priceId: item.product.price_id, quantity: item.quantity }; }),
1940
+ customer: {
1941
+ email: this._billing_details.email,
1942
+ address: {
1943
+ countryCode: this._billing_details.country,
1944
+ postalCode: this._billing_details.postal_code,
1945
+ region: this._billing_details.province,
1946
+ city: this._billing_details.city,
1947
+ firstLine: `${this._billing_details.street} ${this._billing_details.house_number}`,
1948
+ },
1949
+ business,
1950
+ },
1951
+ customData: custom_data,
1952
+ });
1953
+ } catch (err: any) {
1954
+ return reject(err);
1955
+ }
1956
+
1957
+ // const iframe = this._payment_element.children[0];
1958
+ // iframe.onload = () => {
1959
+ // console.log("ON LOAD");
1960
+ // let doc = iframe.contentDocument || iframe.contentWindow.document;
1961
+ // let elementInsideIframe = doc.getElementById('cardNumber');
1962
+ // elementInsideIframe.style.background = 'red'; // Example of editing an element
1963
+ // }
1964
+
1965
+ });
1966
+ },
1967
+
1968
+ // Render the processing element.
1969
+ _render_processing_element: function(): void {
1970
+
1971
+ // Already defined.
1972
+ if (this._processing_element !== undefined) {
1973
+ this._processing_element.set_processing();
1974
+ return ;
1975
+ }
1976
+
1977
+ // Create element.
1978
+ this._processing_element = VStack(
1979
+ Title("Processing")
1980
+ .color(this._style.fg)
1981
+ .font_size(this._style.font_size - 2)
1982
+ .flex_shrink(0)
1983
+ .letter_spacing("1px")
1984
+ .text_transform("uppercase")
1985
+ .ellipsis_overflow(true)
1986
+ .margin(0)
1987
+ .padding(0)
1988
+ .assign_to_parent_as("title_e"),
1989
+ Text("Processing your payment, please wait.")
1990
+ .color(this._style.fg_1)
1991
+ .font_size(this._style.font_size - 2)
1992
+ .line_height(this._style.font_size)
1993
+ .margin(5, 0, 0, 0)
1994
+ .padding(0)
1995
+ .assign_to_parent_as("text_e")
1996
+ .white_space("pre")
1997
+ .line_height("1.4em")
1998
+ .center(),
1999
+ ImageMask("/volt_static/payments/error.webp")
2000
+ .hide()
2001
+ .frame(40, 40)
2002
+ .padding(5)
2003
+ .mask_color(this._style.missing_fg)
2004
+ .margin_top(15)
2005
+ .assign_to_parent_as("error_image_e"),
2006
+ Image("/volt_static/payments/party.webp")
2007
+ .hide()
2008
+ .frame(40, 40)
2009
+ .margin_top(15)
2010
+ .assign_to_parent_as("success_image_e"),
2011
+ RingLoader()
2012
+ .background(this._style.theme_fg)
2013
+ .frame(40, 40)
2014
+ .update()
2015
+ .margin_top(15)
2016
+ .assign_to_parent_as("loader_e"),
2017
+ )
2018
+ .padding(15, 0)
2019
+ .center()
2020
+ .center_vertical()
2021
+ .extend({
2022
+ timestamp: Date.now(),
2023
+ /**
2024
+ * Set the processing element to display an error message.
2025
+ * @param message - The error message to display.
2026
+ */
2027
+ set_error(this: any, message: string = "The payment has failed, please check your information and try again.\n If the problem persists, contact support for assistance.") {
2028
+ this.loader_e.hide();
2029
+ this.error_image_e.src("/volt_static/payments/error.webp");
2030
+ this.error_image_e.show();
2031
+ this.success_image_e.hide();
2032
+ this.title_e.text("Error");
2033
+ this.text_e.text(message);
2034
+ },
2035
+ /**
2036
+ * Set the processing element to display a cancelled message.
2037
+ * @param message - The cancellation message to display.
2038
+ */
2039
+ set_cancelled(this: any, message: string = "The payment has been cancelled.") {
2040
+ this.loader_e.hide();
2041
+ this.error_image_e.src("/volt_static/payments/cancelled.webp");
2042
+ this.error_image_e.show();
2043
+ this.success_image_e.hide();
2044
+ this.title_e.text("Cancelled");
2045
+ this.text_e.text(message);
2046
+ },
2047
+ /**
2048
+ * Set the processing element to display a success message.
2049
+ * @param message - The success message to display.
2050
+ */
2051
+ set_success(this: any, message: string = "The payment has succeeded and is currently processing.\n Thank you for your purchase!") {
2052
+ this.loader_e.hide();
2053
+ this.error_image_e.hide();
2054
+ this.success_image_e.show();
2055
+ this.title_e.text("Success");
2056
+ this.text_e.text(message);
2057
+ },
2058
+ /**
2059
+ * Set the processing element to display a processing message.
2060
+ * @param message - The processing message to display.
2061
+ */
2062
+ set_processing(this: any, message: string = "Processing your payment, please wait.") {
2063
+ this.loader_e.show();
2064
+ this.error_image_e.hide();
2065
+ this.success_image_e.hide();
2066
+ this.title_e.text("Processing");
2067
+ this.text_e.text(message);
2068
+ },
2069
+ });
2070
+
2071
+ // Append.
2072
+ this._processing_container.append(this._processing_element);
2073
+ },
2074
+
2075
+ // Show the processing container.
2076
+ _show_processing: async function(status: string | null = null): Promise<void> {
2077
+
2078
+ // Select step.
2079
+ this._step = 3;
2080
+ this._steps_element.select(this._step);
2081
+
2082
+ // Render the processing element.
2083
+ this._render_processing_element();
2084
+
2085
+ // Set elements.
2086
+ this._order_container.hide();
2087
+ this._billing_container.hide();
2088
+ this._payment_container.hide();
2089
+ this._processing_container.show();
2090
+ this._overview_container.hide();
2091
+ this._prev_step_button.hide();
2092
+
2093
+ // Update.
2094
+ if (status != null) {
2095
+ this._update_processing(status);
2096
+ }
2097
+
2098
+ },
2099
+
2100
+ // Update the processing container.
2101
+ _update_processing: async function(status: string): Promise<void> {
2102
+
2103
+ // Handle result code.
2104
+ switch (status) {
2105
+ case "success":
2106
+ this._processing_element.set_success();
2107
+ break;
2108
+ case "processing":
2109
+ this._processing_element.set_processing();
2110
+ break;
2111
+ case "cancelled":
2112
+ this._processing_element.set_cancelled();
2113
+ break;
2114
+ case "error":
2115
+ this._processing_element.set_error();
2116
+ break;
2117
+ default:
2118
+ console.error(`Unknown session result code "${status}".`);
2119
+ this._processing_element.set_error("An unknown error has occurred.");
2120
+ break;
2121
+ }
2122
+ },
2123
+
2124
+ // Initialize checkout page.
2125
+ style: function({
2126
+ theme = "light", // light or dark
2127
+ font_size = 16,
2128
+ border_radius = 10,
2129
+ bg = "#FFFFFF",
2130
+ bg_1 = "#00000099",
2131
+ divider_bg = "gray",
2132
+ fg = "#687282",
2133
+ fg_1 = "black",
2134
+ fg_2 = "#6D6E77",
2135
+ theme_fg = "#8EB8EB",
2136
+ missing_fg = "#E8454E",
2137
+ selected = {
2138
+ fg: null as null | string,
2139
+ bg: null as null | string,
2140
+ },
2141
+ button = {
2142
+ fg: null as null | string,
2143
+ bg: null as null | string,
2144
+ border_color: null as null | string,
2145
+ border_radius: 25 as null | number,
2146
+ border_width: 1 as null | number | string,
2147
+ border_inset: false,
2148
+ hover_brightness: [1.1, 1.2] as number[],
2149
+ },
2150
+ } = {}): void {
2151
+ // Set selected defaults.
2152
+ if (selected == null) {
2153
+ selected = { fg: null, bg: null };
2154
+ }
2155
+ selected.fg ??= fg;
2156
+ selected.bg ??= theme_fg;
2157
+
2158
+ // Set button defaults.
2159
+ if (button == null) {
2160
+ button = {
2161
+ fg: null,
2162
+ bg: null,
2163
+ border_radius: null,
2164
+ border_color: null,
2165
+ border_width: 1,
2166
+ hover_brightness: [1, 1],
2167
+ border_inset: false,
2168
+ };
2169
+ }
2170
+ button.fg ??= fg;
2171
+ button.bg ??= bg_1; // Corrected bg_2 to bg_1 as bg_2 is not defined
2172
+ button.border_radius ??= 25;
2173
+ button.border_color ??= fg;
2174
+ button.border_width ??= 1;
2175
+ button.border_inset ??= false;
2176
+ button.hover_brightness ??= [1.1, 1.2];
2177
+ if (typeof button.border_width === "number") { button.border_width = `${button.border_width}px`; }
2178
+
2179
+ // Save style.
2180
+ this._style = {};
2181
+ this._theme = theme;
2182
+ this._style.font_size = font_size;
2183
+ this._style.border_radius = border_radius;
2184
+ this._style.bg = bg;
2185
+ this._style.bg_1 = bg_1;
2186
+ this._style.divider_bg = divider_bg;
2187
+ this._style.fg = fg;
2188
+ this._style.fg_1 = fg_1;
2189
+ this._style.fg_2 = fg_2;
2190
+ this._style.theme_fg = theme_fg;
2191
+ this._style.missing_fg = missing_fg;
2192
+ this._style.selected = selected;
2193
+ this._style.button = button;
2194
+
2195
+ // Set CSS variables.
2196
+ Object.keys(this._style).forEach((key) => {
2197
+ if (typeof this._style[key] === "number") {
2198
+ document.documentElement.style.setProperty(`--vpayments_${key}`, `${this._style[key]}px`);
2199
+ } else {
2200
+ document.documentElement.style.setProperty(`--vpayments_${key}`, this._style[key]);
2201
+ }
2202
+ });
2203
+ document.documentElement.style.setProperty(`--vpayments_theme_fg_80`, `${this._style.theme_fg}80`);
2204
+ document.documentElement.style.setProperty(`--vpayments_missing_fg_80`, `${this._style.missing_fg}80`);
2205
+ },
2206
+
2207
+ // Initialize checkout page.
2208
+ create_checkout_dropin: function({
2209
+ steps_container,
2210
+ order_container,
2211
+ billing_container,
2212
+ payment_container,
2213
+ processing_container,
2214
+ overview_container,
2215
+ sign_in_redirect = null,
2216
+ on_error = (error: string | Error) => {},
2217
+ }: {
2218
+ steps_container: any,
2219
+ order_container: any,
2220
+ billing_container: any,
2221
+ payment_container: any,
2222
+ processing_container: any,
2223
+ overview_container: any,
2224
+ sign_in_redirect?: string | null,
2225
+ on_error?: (error: string | Error) => void,
2226
+ }): void {
2227
+
2228
+ // Check args.
2229
+ if (!(steps_container instanceof Node)) {
2230
+ throw new Error('The "steps_container" must be assigned with a container node.');
2231
+ }
2232
+ if (!(order_container instanceof Node)) {
2233
+ throw new Error('The "order_container" must be assigned with a container node.');
2234
+ }
2235
+ if (!(billing_container instanceof Node)) {
2236
+ throw new Error('The "billing_container" must be assigned with a container node.');
2237
+ }
2238
+ if (!(payment_container instanceof Node)) {
2239
+ throw new Error('The "payment_container" must be assigned with a container node.');
2240
+ }
2241
+ if (!(processing_container instanceof Node)) {
2242
+ throw new Error('The "processing_container" must be assigned with a container node.');
2243
+ }
2244
+ if (!(overview_container instanceof Node)) {
2245
+ throw new Error('The "overview_container" must be assigned with a container node.');
2246
+ }
2247
+
2248
+ // Args.
2249
+ this._steps_container = steps_container;
2250
+ this._order_container = order_container;
2251
+ // @ts-ignore
2252
+ this._billing_container = billing_container.hide();
2253
+ // @ts-ignore
2254
+ this._payment_container = payment_container.hide();
2255
+ // @ts-ignore
2256
+ this._processing_container = processing_container.hide();
2257
+ this._overview_container = overview_container;
2258
+
2259
+ // Settings.
2260
+ this._sign_in_redirect = sign_in_redirect;
2261
+
2262
+ // Events.
2263
+ this.on_error = on_error;
2264
+
2265
+ // Check style.
2266
+ if (this._style === undefined) {
2267
+ this.style();
2268
+ }
2269
+
2270
+ // Other attributes.
2271
+ this._step = 0;
2272
+
2273
+ // Render the steps element.
2274
+ this._render_steps_element();
2275
+
2276
+ // When the user was redirected the URL params are defined, if so only render the processing view.
2277
+ if (Utils.url_param("payment_status", null) != null) {
2278
+ this._show_processing(Utils.url_param("payment_status", null));
2279
+ }
2280
+ // No redirect.
2281
+ else {
2282
+ // Render the overview element.
2283
+ this._render_overview_element();
2284
+
2285
+ // Render the order element.
2286
+ // Must be rendered after the overview element is rendered.
2287
+ this._render_order_element();
2288
+ }
2289
+ },
2290
+
2291
+ // Initialize refund page.
2292
+ create_refunds_dropin: function({
2293
+ // The element containers.
2294
+ refunds_container,
2295
+
2296
+ // Refundable settings.
2297
+ days_refundable = 30,
2298
+
2299
+ // Events.
2300
+ on_error = (error: any) => {},
2301
+ }: {
2302
+ refunds_container: any,
2303
+ days_refundable?: number,
2304
+ on_error?: (error: any) => void,
2305
+ }): void {
2306
+
2307
+ // Check args.
2308
+ if (!(refunds_container instanceof Node)) {
2309
+ throw new Error('The "refunds_container" must be assigned with a container node.');
2310
+ }
2311
+
2312
+ // Args.
2313
+ this._refunds_container = refunds_container;
2314
+ this._days_refundable = days_refundable;
2315
+
2316
+ // Events.
2317
+ this.on_error = on_error;
2318
+
2319
+ // Check style.
2320
+ if (this._style === undefined) {
2321
+ this.style();
2322
+ }
2323
+
2324
+ // Other attributes.
2325
+ this._step = 0;
2326
+
2327
+ // Render the refunds element.
2328
+ this._render_refunds_element();
2329
+ },
2330
+
2331
+ // Backend API.
2332
+
2333
+ // Get the currency symbol for a product currency.
2334
+ // Returns `null` when the currency is not supported.
2335
+ /**
2336
+ * @docs:
2337
+ * @nav: Frontend
2338
+ * @chapter: Payments
2339
+ * @title: Get Currency Symbol
2340
+ * @description: Get the currency symbol for a product currency.
2341
+ * @type: string | null
2342
+ * @return: Returns the currency symbol when the currency is supported, otherwise `null`
2343
+ * @param:
2344
+ * @name: currency
2345
+ * @description: The currency from the product object.
2346
+ */
2347
+ get_currency_symbol: function(currency: string): string | null {
2348
+ switch (currency.toLowerCase()) {
2349
+ case "aed": return "د.إ";
2350
+ case "afn": return "Af";
2351
+ case "all": return "L";
2352
+ case "amd": return "֏";
2353
+ case "ang": return "ƒ";
2354
+ case "aoa": return "Kz";
2355
+ case "ars": return "$";
2356
+ case "aud": return "$";
2357
+ case "awg": return "ƒ";
2358
+ case "azn": return "₼";
2359
+ case "bam": return "KM";
2360
+ case "bbd": return "Bds$";
2361
+ case "bdt": return "৳";
2362
+ case "bgn": return "лв";
2363
+ case "bhd": return ".د.ب";
2364
+ case "bif": return "FBu";
2365
+ case "bmd": return "BD$";
2366
+ case "bnd": return "B$";
2367
+ case "bob": return "Bs";
2368
+ case "brl": return "R$";
2369
+ case "bsd": return "B$";
2370
+ case "btn": return "Nu.";
2371
+ case "bwp": return "P";
2372
+ case "byn": return "Br";
2373
+ case "bzd": return "BZ$";
2374
+ case "cad": return "$";
2375
+ case "cdf": return "FC";
2376
+ case "chf": return "Fr";
2377
+ case "clf": return "UF";
2378
+ case "clp": return "$";
2379
+ case "cny": return "¥";
2380
+ case "cop": return "$";
2381
+ case "crc": return "₡";
2382
+ case "cuc": return "CUC$";
2383
+ case "cup": return "CUP$";
2384
+ case "cve": return "$";
2385
+ case "czk": return "Kč";
2386
+ case "djf": return "Fdj";
2387
+ case "dkk": return "kr";
2388
+ case "dop": return "RD$";
2389
+ case "dzd": return "دج";
2390
+ case "egp": return "E£";
2391
+ case "ern": return "Nfk";
2392
+ case "etb": return "Br";
2393
+ case "eur": return "€";
2394
+ case "fjd": return "FJ$";
2395
+ case "fkp": return "£";
2396
+ case "fok": return "F$";
2397
+ case "gbp": return "£";
2398
+ case "gel": return "₾";
2399
+ case "ghc": return "₵";
2400
+ case "gip": return "£";
2401
+ case "gmd": return "D";
2402
+ case "gnf": return "FG";
2403
+ case "gtq": return "Q";
2404
+ case "gyd": return "GY$";
2405
+ case "hkd": return "HK$";
2406
+ case "hnl": return "L";
2407
+ case "hrk": return "kn";
2408
+ case "htg": return "G";
2409
+ case "huf": return "Ft";
2410
+ case "idr": return "Rp";
2411
+ case "ils": return "₪";
2412
+ case "inr": return "₹";
2413
+ case "iqd": return "د.ع";
2414
+ case "irr": return "﷼";
2415
+ case "isk": return "kr";
2416
+ case "jmd": return "J$";
2417
+ case "jod": return "JD";
2418
+ case "jpy": return "¥";
2419
+ case "kes": return "Ksh";
2420
+ case "kgs": return "с";
2421
+ case "khr": return "៛";
2422
+ case "kmf": return "CF";
2423
+ case "kpw": return "₩";
2424
+ case "krw": return "₩";
2425
+ case "kwd": return "KD";
2426
+ case "kyd": return "CI$";
2427
+ case "kzt": return "₸";
2428
+ case "lak": return "₭";
2429
+ case "lbp": return "L£";
2430
+ case "lkr": return "Rs";
2431
+ case "lrd": return "L$";
2432
+ case "lsl": return "L";
2433
+ case "lyd": return "ل.د";
2434
+ case "mad": return "د.م.";
2435
+ case "mdl": return "L";
2436
+ case "mnt": return "₮";
2437
+ case "mop": return "MOP$";
2438
+ case "mur": return "Rs";
2439
+ case "mvr": return "Rf";
2440
+ case "mwk": return "MK";
2441
+ case "mxn": return "$";
2442
+ case "myr": return "RM";
2443
+ case "mzn": return "MTn";
2444
+ case "nad": return "N$";
2445
+ case "ngn": return "₦";
2446
+ case "nio": return "C$";
2447
+ case "nok": return "kr";
2448
+ case "npr": return "रू";
2449
+ case "nzd": return "$";
2450
+ case "omr": return "ر.ع.";
2451
+ case "pab": return "B/.";
2452
+ case "pen": return "S/.";
2453
+ case "pgk": return "K";
2454
+ case "php": return "₱";
2455
+ case "pkr": return "Rs";
2456
+ case "pln": return "zł";
2457
+ case "pyg": return "₲";
2458
+ case "qar": return "ر.ق";
2459
+ case "ron": return "lei";
2460
+ case "rsd": return "din.";
2461
+ case "rub": return "₽";
2462
+ case "rwf": return "FRw";
2463
+ case "sar": return "ر.س";
2464
+ case "sbd": return "SI$";
2465
+ case "scr": return "Sr";
2466
+ case "sdg": return "ج.س.";
2467
+ case "sek": return "kr";
2468
+ case "sgd": return "S$";
2469
+ case "shp": return "£";
2470
+ case "sll": return "Le";
2471
+ case "sos": return "S";
2472
+ case "srd": return "SRD$";
2473
+ case "ssp": return "£";
2474
+ case "std": return "Db";
2475
+ case "syp": return "S£";
2476
+ case "szl": return "L";
2477
+ case "thb": return "฿";
2478
+ case "tjs": return "ЅМ";
2479
+ case "tmt": return "m";
2480
+ case "tnd": return "د.ت";
2481
+ case "top": return "T$";
2482
+ case "try": return "₺";
2483
+ case "ttd": return "TT$";
2484
+ case "twd": return "NT$";
2485
+ case "tzs": return "TSh";
2486
+ case "uah": return "₴";
2487
+ case "ugx": return "USh";
2488
+ case "usd": return "$";
2489
+ case "uyu": return "$U";
2490
+ case "uzs": return "лв";
2491
+ case "ves": return "Bs.S.";
2492
+ case "vnd": return "₫";
2493
+ case "vuv": return "VT";
2494
+ case "wst": return "WS$";
2495
+ case "xaf": return "FCFA";
2496
+ case "xcd": return "EC$";
2497
+ case "xof": return "CFA";
2498
+ case "xpf": return "CFP";
2499
+ case "yer": return "﷼";
2500
+ case "zar": return "R";
2501
+ case "zmw": return "ZK";
2502
+ }
2503
+ return null;
2504
+ },
2505
+
2506
+ // Fetch the payment products.
2507
+ /**
2508
+ * @docs:
2509
+ * @nav: Frontend
2510
+ * @chapter: Payments
2511
+ * @title: Payment Products
2512
+ * @description: Get the backend defined payment products asynchronously.
2513
+ * @type: array[object]
2514
+ * @return: Returns the backend defined payment products.
2515
+ */
2516
+ get_products: async function(): Promise<any[]> {
2517
+ return new Promise((resolve, reject) => {
2518
+ if (this._products !== undefined) {
2519
+ return resolve(this._products);
2520
+ }
2521
+ Utils.request({
2522
+ method: "GET",
2523
+ url: "/volt/payments/products",
2524
+ })
2525
+ .then((products: any[]) => {
2526
+ this._products = products;
2527
+ resolve(this._products);
2528
+ })
2529
+ .catch((err: any) => {
2530
+ reject(err);
2531
+ });
2532
+ });
2533
+ },
2534
+
2535
+ // Fetch a payment product by id.
2536
+ /**
2537
+ * @docs:
2538
+ * @nav: Frontend
2539
+ * @chapter: Payments
2540
+ * @title: Get Payment Product
2541
+ * @description: Get the backend defined payment product by id asynchronously.
2542
+ * @type: object
2543
+ * @return: Returns the backend defined payment product.
2544
+ * @param:
2545
+ * @name: id
2546
+ * @required: true
2547
+ * @type: string
2548
+ * @desc: The id of the payment product.
2549
+ */
2550
+ get_product: async function(id: string): Promise<any> {
2551
+ return new Promise(async (resolve, reject) => {
2552
+ const products = await this.get_products();
2553
+ let product: any = null;
2554
+ for (const p of products) {
2555
+ if (p.id === id) {
2556
+ product = p;
2557
+ break;
2558
+ }
2559
+ if (p.is_subscription) {
2560
+ for (const plan of p.plans) {
2561
+ if (plan.id === id) {
2562
+ product = plan;
2563
+ break;
2564
+ }
2565
+ }
2566
+ if (product) break;
2567
+ }
2568
+ }
2569
+ if (product == null) {
2570
+ return reject(new Error(`Product "${id}" does not exist.`));
2571
+ }
2572
+ resolve(product);
2573
+ });
2574
+ },
2575
+
2576
+ // Fetch a payment object by id.
2577
+ /**
2578
+ * @docs:
2579
+ * @nav: Frontend
2580
+ * @chapter: Payments
2581
+ * @title: Get Payment.
2582
+ * @desc: Get a payment by id.
2583
+ * @param:
2584
+ * @name: id
2585
+ * @required: true
2586
+ * @type: string
2587
+ * @desc: The id of the payment.
2588
+ */
2589
+ get_payment: async function(id: string): Promise<any> {
2590
+ return Utils.request({
2591
+ method: "GET",
2592
+ url: "/volt/payments/payment",
2593
+ data: {
2594
+ id: id,
2595
+ }
2596
+ });
2597
+ },
2598
+
2599
+ // Get all payments.
2600
+ /**
2601
+ * @docs:
2602
+ * @nav: Frontend
2603
+ * @chapter: Payments
2604
+ * @title: Get Refunded Payments.
2605
+ * @desc:
2606
+ * Get all payments of the authenticated user
2607
+ *
2608
+ * All failed payments are no longer stored in the database.
2609
+ * @param:
2610
+ * @name: days
2611
+ * @type: number
2612
+ * @desc: Retrieve payments from the last amount of days.
2613
+ * @param:
2614
+ * @name: limit
2615
+ * @type: number
2616
+ * @desc: Limit the amount of response payment objects.
2617
+ * @param:
2618
+ * @name: status
2619
+ * @type: string
2620
+ * @desc: Filter the payments by status. Be aware that the line items of a payment also have a status with possible values of `open`, `cancelled`, `refunding` or `refunded.`
2621
+ * @enum:
2622
+ * @value: "open"
2623
+ * @desc: Payments that are still open and unpaid.
2624
+ * @enum:
2625
+ * @value: "paid"
2626
+ * @desc: Payments that are paid.
2627
+ */
2628
+ get_payments: async function({
2629
+ days = 30,
2630
+ limit = null,
2631
+ status = null,
2632
+ } = {}): Promise<any> {
2633
+ return Utils.request({
2634
+ method: "GET",
2635
+ url: "/volt/payments/payments",
2636
+ data: {
2637
+ days,
2638
+ limit,
2639
+ status,
2640
+ }
2641
+ });
2642
+ },
2643
+
2644
+ // Get refundable payments.
2645
+ /**
2646
+ * @docs:
2647
+ * @nav: Frontend
2648
+ * @chapter: Payments
2649
+ * @title: Get Refundable Payments.
2650
+ * @desc: Get all payments that are refundable for the authenticated user.
2651
+ * @param:
2652
+ * @name: days
2653
+ * @type: number
2654
+ * @desc: Retrieve payments from the last amount of days.
2655
+ * @param:
2656
+ * @name: limit
2657
+ * @type: number
2658
+ * @desc: Limit the amount of response payment objects.
2659
+ */
2660
+ get_refundable_payments: async function({
2661
+ days = 30,
2662
+ limit = null,
2663
+ } = {}): Promise<any> {
2664
+ return Utils.request({
2665
+ method: "GET",
2666
+ url: "/volt/payments/payments/refundable",
2667
+ data: {
2668
+ days,
2669
+ limit,
2670
+ }
2671
+ });
2672
+ },
2673
+
2674
+ // Get refunded payments.
2675
+ /**
2676
+ * @docs:
2677
+ * @nav: Frontend
2678
+ * @chapter: Payments
2679
+ * @title: Get Refunded Payments.
2680
+ * @desc: Get all successfully refunded payments of the authenticated user.
2681
+ * @param:
2682
+ * @name: days
2683
+ * @type: number
2684
+ * @desc: Retrieve payments from the last amount of days.
2685
+ * @param:
2686
+ * @name: limit
2687
+ * @type: number
2688
+ * @desc: Limit the amount of response payment objects.
2689
+ */
2690
+ get_refunded_payments: async function({
2691
+ days = 30,
2692
+ limit = null,
2693
+ } = {}): Promise<any> {
2694
+ return Utils.request({
2695
+ method: "GET",
2696
+ url: "/volt/payments/payments/refunded",
2697
+ data: {
2698
+ days,
2699
+ limit,
2700
+ }
2701
+ });
2702
+ },
2703
+
2704
+ // Get refunding payments.
2705
+ /**
2706
+ * @docs:
2707
+ * @nav: Frontend
2708
+ * @chapter: Payments
2709
+ * @title: Get Refunding Payments.
2710
+ * @desc: Get all payments that are currently in the refunding process of the authenticated user.
2711
+ * @param:
2712
+ * @name: days
2713
+ * @type: number
2714
+ * @desc: Retrieve payments from the last amount of days.
2715
+ * @param:
2716
+ * @name: limit
2717
+ * @type: number
2718
+ * @desc: Limit the amount of response payment objects.
2719
+ */
2720
+ get_refunding_payments: async function({
2721
+ days = null,
2722
+ limit = null,
2723
+ } = {}): Promise<any> {
2724
+ return Utils.request({
2725
+ method: "GET",
2726
+ url: "/volt/payments/payments/refunding",
2727
+ data: {
2728
+ days,
2729
+ limit,
2730
+ }
2731
+ });
2732
+ },
2733
+
2734
+ // Create refund.
2735
+ /**
2736
+ * @docs:
2737
+ * @nav: Frontend
2738
+ * @chapter: Payments
2739
+ * @title: Refund Payment.
2740
+ * @desc: Refund a payment based on the payment id for the authenticated user.
2741
+ * @warning: Refunding a subscription will also cancel all other subscriptions that were created by the same payment request.
2742
+ * @param:
2743
+ * @name: payment
2744
+ * @required: true
2745
+ * @type: number | string
2746
+ * @desc: The id of the payment object or the payment object itself.
2747
+ * @param:
2748
+ * @name: line_items
2749
+ * @required: true
2750
+ * @type: array[object]
2751
+ * @desc: The line items to refund, these must be retrieved from the original payment line items otherwise it may cause undefined behaviour. When undefined the entire payment will be refunded.
2752
+ * @param:
2753
+ * @name: reason
2754
+ * @type: string
2755
+ * @desc: The refund reason.
2756
+ */
2757
+ create_refund: async function(payment: number | string, line_items: any[] | null = null, reason: string = "refund"): Promise<any> {
2758
+ return Utils.request({
2759
+ method: "POST",
2760
+ url: "/volt/payments/refund",
2761
+ data: {
2762
+ payment,
2763
+ line_items,
2764
+ reason,
2765
+ }
2766
+ });
2767
+ },
2768
+
2769
+ // Cancel subscription.
2770
+ /**
2771
+ * @docs:
2772
+ * @nav: Frontend
2773
+ * @chapter: Payments
2774
+ * @title: Cancel Subscription.
2775
+ * @desc: Cancel a subscription based on the product id.
2776
+ * @warning: Cancelling a subscription will also cancel all other subscriptions that were created by the same payment request.
2777
+ * @param:
2778
+ * @name: product
2779
+ * @required: true
2780
+ * @type: string
2781
+ * @desc: The product id.
2782
+ */
2783
+ cancel_subscription: async function(product: string): Promise<any> {
2784
+ return Utils.request({
2785
+ method: "DELETE",
2786
+ url: "/volt/payments/subscription",
2787
+ data: {
2788
+ product,
2789
+ }
2790
+ });
2791
+ },
2792
+
2793
+ // Is subscribed.
2794
+ /**
2795
+ * @docs:
2796
+ * @nav: Frontend
2797
+ * @chapter: Payments
2798
+ * @title: Is Subscribed.
2799
+ * @desc: Check if the authenticated user is subscribed to a product plan.
2800
+ * @param:
2801
+ * @name: product
2802
+ * @required: true
2803
+ * @type: string
2804
+ * @desc: The product id.
2805
+ */
2806
+ is_subscribed: async function(product: string): Promise<any> {
2807
+ return Utils.request({
2808
+ method: "GET",
2809
+ url: "/volt/payments/subscribed",
2810
+ data: {
2811
+ product,
2812
+ }
2813
+ });
2814
+ },
2815
+
2816
+ // Get active subscriptions.
2817
+ /**
2818
+ * @docs:
2819
+ * @nav: Frontend
2820
+ * @chapter: Payments
2821
+ * @title: Get active subscriptions
2822
+ * @desc: Get the active subscriptions of the authenticated user.
2823
+ */
2824
+ get_active_subscriptions: async function(): Promise<any> {
2825
+ return Utils.request({
2826
+ method: "GET",
2827
+ url: "/volt/payments/active_subscriptions",
2828
+ });
2829
+ },
2830
+
2831
+ // Shopping cart.
2832
+
2833
+ // The shopping cart object.
2834
+ cart: {
2835
+ items: [] as any[],
2836
+
2837
+ // Refresh the shopping cart.
2838
+ /**
2839
+ * @docs:
2840
+ * @nav: Frontend
2841
+ * @chapter: Payments
2842
+ * @title: Refresh Cart
2843
+ * @description:
2844
+ * Refresh the shopping cart.
2845
+ *
2846
+ * The current cart items are accessible as `Payments.cart.items`.
2847
+ */
2848
+ refresh: function(): void {
2849
+ // Load from local storage.
2850
+ try {
2851
+ this.items = JSON.parse(localStorage.getItem("volt_shopping_cart") as string) || [];
2852
+ } catch(err) {
2853
+ this.items = [];
2854
+ }
2855
+
2856
+ // Reset the charge objects.
2857
+ Payments._reset();
2858
+ },
2859
+
2860
+ // Save the shopping cart.
2861
+ /**
2862
+ * @docs:
2863
+ * @nav: Frontend
2864
+ * @chapter: Payments
2865
+ * @title: Save Cart
2866
+ * @description:
2867
+ * Save the shopping cart in the local storage.
2868
+ *
2869
+ * The current cart items are accessible as `Payments.cart.items`.
2870
+ */
2871
+ save: function(): void {
2872
+ // Save to local storage.
2873
+ localStorage.setItem("volt_shopping_cart", JSON.stringify(this.items));
2874
+
2875
+ // Reset the charge objects.
2876
+ Payments._reset();
2877
+ },
2878
+
2879
+ // Add a product to the shopping cart.
2880
+ /**
2881
+ * @docs:
2882
+ * @nav: Frontend
2883
+ * @chapter: Payments
2884
+ * @title: Add to Cart
2885
+ * @description:
2886
+ * Add a product to the shopping cart.
2887
+ *
2888
+ * When the product was already added to the shopping cart only the quantity will be incremented.
2889
+ *
2890
+ * An error will be thrown if the product id does not exist.
2891
+ *
2892
+ * The current cart items are accessible as `Payments.cart.items`.
2893
+ * @param:
2894
+ * @name: id
2895
+ * @description: The product's id.
2896
+ * @type: string
2897
+ * @param:
2898
+ * @name: quantity
2899
+ * @description: The quantity to add.
2900
+ * @type: number
2901
+ */
2902
+ add: async function(id: string, quantity: number = 1): Promise<void> {
2903
+ this.refresh(); // Update in case another window has updated the cart.
2904
+ const found = this.items.some((item: any) => {
2905
+ if (item.product.id === id) {
2906
+ item.quantity += quantity;
2907
+ return true;
2908
+ }
2909
+ return false;
2910
+ });
2911
+ if (!found) {
2912
+ try {
2913
+ const product = await Payments.get_product(id);
2914
+ this.items.push({
2915
+ product: product,
2916
+ quantity: quantity,
2917
+ });
2918
+ } catch (error: any) {
2919
+ console.error(error);
2920
+ Payments.on_error(error as Error);
2921
+ throw new Error(`Failed to add product with id "${id}" to the cart.`);
2922
+ }
2923
+ }
2924
+ this.save();
2925
+ },
2926
+
2927
+ // Remove a product from the shopping cart.
2928
+ /**
2929
+ * @docs:
2930
+ * @nav: Frontend
2931
+ * @chapter: Payments
2932
+ * @title: Remove from Cart
2933
+ * @description:
2934
+ * Remove a product from the shopping cart.
2935
+ *
2936
+ * Does not throw an error when the product was not added to the shopping cart.
2937
+ *
2938
+ * The current cart items are accessible as `Payments.cart.items`.
2939
+ * @param:
2940
+ * @name: id
2941
+ * @description: The product's id.
2942
+ * @type: string
2943
+ * @param:
2944
+ * @name: quantity
2945
+ * @description: The quantity to remove. When the quantity value is "all", the entire product will be removed from the shopping cart.
2946
+ * @type: number | "all"
2947
+ */
2948
+ remove: async function(id: string, quantity: number | "all" = 1): Promise<void> {
2949
+ this.refresh(); // Update in case another window has updated the cart.
2950
+ let new_cart: any[] = [];
2951
+ this.items.forEach((item: any) => {
2952
+ if (item.product.id === id) {
2953
+ if (quantity === "all") {
2954
+ item.quantity = 0;
2955
+ } else {
2956
+ item.quantity -= quantity;
2957
+ }
2958
+ }
2959
+ if (item.quantity > 0) {
2960
+ new_cart.push(item);
2961
+ }
2962
+ });
2963
+ this.items = new_cart;
2964
+ this.save();
2965
+ },
2966
+
2967
+ // Clear the shopping cart.
2968
+ /**
2969
+ * @docs:
2970
+ * @nav: Frontend
2971
+ * @chapter: Payments
2972
+ * @title: Clear Cart
2973
+ * @description:
2974
+ * Clear the shopping cart.
2975
+ *
2976
+ * Will automatically be called if `Payments.confirm_charge()` finishes without any errors.
2977
+ *
2978
+ * The current cart items are accessible as `Payments.cart.items`.
2979
+ */
2980
+ clear: async function(): Promise<void> {
2981
+ this.items = [];
2982
+ this.save();
2983
+ }
2984
+ },
2985
+
2986
+
2987
+ };
2988
+
2989
+ // Exports.
2990
+ export { Payments };