@cratis/showrunner.boxoffice.react 0.0.0-stage → 1.9.0

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 (329) hide show
  1. package/Banners/NoLicense.tsx +36 -0
  2. package/Banners/SuspensionBanner.tsx +54 -0
  3. package/Banners/TrialBanner.tsx +30 -0
  4. package/Banners/bannerModels.ts +117 -0
  5. package/Banners/index.ts +7 -0
  6. package/Entitlements/EntitlementsContext.ts +17 -0
  7. package/Entitlements/RequiresModule.tsx +68 -0
  8. package/Entitlements/entitlementModel.ts +175 -0
  9. package/Entitlements/index.ts +9 -0
  10. package/Entitlements/moduleFilter.ts +23 -0
  11. package/Entitlements/requiresModuleModel.ts +44 -0
  12. package/Entitlements/useEntitlements.ts +25 -0
  13. package/Labels/BoxOfficeLabels.ts +239 -0
  14. package/Labels/defaultBoxOfficeLabels.ts +119 -0
  15. package/Labels/format.ts +13 -0
  16. package/Labels/index.ts +7 -0
  17. package/Labels/resolveLabels.ts +36 -0
  18. package/Plan/PlanPage.tsx +24 -0
  19. package/Plan/PlanView.tsx +80 -0
  20. package/Plan/index.ts +6 -0
  21. package/Plan/planModels.ts +127 -0
  22. package/Portal/PortalButton.tsx +48 -0
  23. package/Portal/index.ts +5 -0
  24. package/Portal/portalLinks.ts +32 -0
  25. package/Provider/BoxOfficeContext.ts +67 -0
  26. package/Provider/BoxOfficeProvider.tsx +96 -0
  27. package/Provider/index.ts +5 -0
  28. package/README.md +71 -2
  29. package/Seats/AssignSeatDialog.tsx +73 -0
  30. package/Seats/SeatsPage.tsx +85 -0
  31. package/Seats/SeatsView.tsx +108 -0
  32. package/Seats/index.ts +7 -0
  33. package/Seats/seatModels.ts +97 -0
  34. package/Usage/UsagePage.tsx +26 -0
  35. package/Usage/UsageView.tsx +94 -0
  36. package/Usage/index.ts +6 -0
  37. package/Usage/usageModels.ts +92 -0
  38. package/dist/cjs/Banners/NoLicense.d.ts +2 -0
  39. package/dist/cjs/Banners/NoLicense.d.ts.map +1 -0
  40. package/dist/cjs/Banners/NoLicense.js +50 -0
  41. package/dist/cjs/Banners/NoLicense.js.map +1 -0
  42. package/dist/cjs/Banners/SuspensionBanner.d.ts +7 -0
  43. package/dist/cjs/Banners/SuspensionBanner.d.ts.map +1 -0
  44. package/dist/cjs/Banners/SuspensionBanner.js +62 -0
  45. package/dist/cjs/Banners/SuspensionBanner.js.map +1 -0
  46. package/dist/cjs/Banners/TrialBanner.d.ts +2 -0
  47. package/dist/cjs/Banners/TrialBanner.d.ts.map +1 -0
  48. package/dist/cjs/Banners/TrialBanner.js +38 -0
  49. package/dist/cjs/Banners/TrialBanner.js.map +1 -0
  50. package/dist/cjs/Banners/bannerModels.d.ts +19 -0
  51. package/dist/cjs/Banners/bannerModels.d.ts.map +1 -0
  52. package/dist/cjs/Banners/bannerModels.js +101 -0
  53. package/dist/cjs/Banners/bannerModels.js.map +1 -0
  54. package/dist/cjs/Banners/index.d.ts +5 -0
  55. package/dist/cjs/Banners/index.d.ts.map +1 -0
  56. package/dist/cjs/Entitlements/EntitlementsContext.d.ts +4 -0
  57. package/dist/cjs/Entitlements/EntitlementsContext.d.ts.map +1 -0
  58. package/dist/cjs/Entitlements/EntitlementsContext.js +19 -0
  59. package/dist/cjs/Entitlements/EntitlementsContext.js.map +1 -0
  60. package/dist/cjs/Entitlements/RequiresModule.d.ts +9 -0
  61. package/dist/cjs/Entitlements/RequiresModule.d.ts.map +1 -0
  62. package/dist/cjs/Entitlements/RequiresModule.js +68 -0
  63. package/dist/cjs/Entitlements/RequiresModule.js.map +1 -0
  64. package/dist/cjs/Entitlements/entitlementModel.d.ts +25 -0
  65. package/dist/cjs/Entitlements/entitlementModel.d.ts.map +1 -0
  66. package/dist/cjs/Entitlements/entitlementModel.js +93 -0
  67. package/dist/cjs/Entitlements/entitlementModel.js.map +1 -0
  68. package/dist/cjs/Entitlements/index.d.ts +7 -0
  69. package/dist/cjs/Entitlements/index.d.ts.map +1 -0
  70. package/dist/cjs/Entitlements/moduleFilter.d.ts +6 -0
  71. package/dist/cjs/Entitlements/moduleFilter.d.ts.map +1 -0
  72. package/dist/cjs/Entitlements/moduleFilter.js +16 -0
  73. package/dist/cjs/Entitlements/moduleFilter.js.map +1 -0
  74. package/dist/cjs/Entitlements/requiresModuleModel.d.ts +10 -0
  75. package/dist/cjs/Entitlements/requiresModuleModel.d.ts.map +1 -0
  76. package/dist/cjs/Entitlements/requiresModuleModel.js +32 -0
  77. package/dist/cjs/Entitlements/requiresModuleModel.js.map +1 -0
  78. package/dist/cjs/Entitlements/useEntitlements.d.ts +5 -0
  79. package/dist/cjs/Entitlements/useEntitlements.d.ts.map +1 -0
  80. package/dist/cjs/Entitlements/useEntitlements.js +26 -0
  81. package/dist/cjs/Entitlements/useEntitlements.js.map +1 -0
  82. package/dist/cjs/Labels/BoxOfficeLabels.d.ts +116 -0
  83. package/dist/cjs/Labels/BoxOfficeLabels.d.ts.map +1 -0
  84. package/dist/cjs/Labels/defaultBoxOfficeLabels.d.ts +3 -0
  85. package/dist/cjs/Labels/defaultBoxOfficeLabels.d.ts.map +1 -0
  86. package/dist/cjs/Labels/defaultBoxOfficeLabels.js +120 -0
  87. package/dist/cjs/Labels/defaultBoxOfficeLabels.js.map +1 -0
  88. package/dist/cjs/Labels/format.d.ts +2 -0
  89. package/dist/cjs/Labels/format.d.ts.map +1 -0
  90. package/dist/cjs/Labels/format.js +15 -0
  91. package/dist/cjs/Labels/format.js.map +1 -0
  92. package/dist/cjs/Labels/index.d.ts +5 -0
  93. package/dist/cjs/Labels/index.d.ts.map +1 -0
  94. package/dist/cjs/Labels/resolveLabels.d.ts +3 -0
  95. package/dist/cjs/Labels/resolveLabels.d.ts.map +1 -0
  96. package/dist/cjs/Labels/resolveLabels.js +35 -0
  97. package/dist/cjs/Labels/resolveLabels.js.map +1 -0
  98. package/dist/cjs/Plan/PlanPage.d.ts +2 -0
  99. package/dist/cjs/Plan/PlanPage.d.ts.map +1 -0
  100. package/dist/cjs/Plan/PlanPage.js +24 -0
  101. package/dist/cjs/Plan/PlanPage.js.map +1 -0
  102. package/dist/cjs/Plan/PlanView.d.ts +10 -0
  103. package/dist/cjs/Plan/PlanView.d.ts.map +1 -0
  104. package/dist/cjs/Plan/PlanView.js +123 -0
  105. package/dist/cjs/Plan/PlanView.js.map +1 -0
  106. package/dist/cjs/Plan/index.d.ts +4 -0
  107. package/dist/cjs/Plan/index.d.ts.map +1 -0
  108. package/dist/cjs/Plan/planModels.d.ts +24 -0
  109. package/dist/cjs/Plan/planModels.d.ts.map +1 -0
  110. package/dist/cjs/Plan/planModels.js +83 -0
  111. package/dist/cjs/Plan/planModels.js.map +1 -0
  112. package/dist/cjs/Portal/PortalButton.d.ts +10 -0
  113. package/dist/cjs/Portal/PortalButton.d.ts.map +1 -0
  114. package/dist/cjs/Portal/PortalButton.js +37 -0
  115. package/dist/cjs/Portal/PortalButton.js.map +1 -0
  116. package/dist/cjs/Portal/index.d.ts +3 -0
  117. package/dist/cjs/Portal/index.d.ts.map +1 -0
  118. package/dist/cjs/Portal/portalLinks.d.ts +6 -0
  119. package/dist/cjs/Portal/portalLinks.d.ts.map +1 -0
  120. package/dist/cjs/Portal/portalLinks.js +34 -0
  121. package/dist/cjs/Portal/portalLinks.js.map +1 -0
  122. package/dist/cjs/Provider/BoxOfficeContext.d.ts +16 -0
  123. package/dist/cjs/Provider/BoxOfficeContext.d.ts.map +1 -0
  124. package/dist/cjs/Provider/BoxOfficeContext.js +34 -0
  125. package/dist/cjs/Provider/BoxOfficeContext.js.map +1 -0
  126. package/dist/cjs/Provider/BoxOfficeProvider.d.ts +15 -0
  127. package/dist/cjs/Provider/BoxOfficeProvider.d.ts.map +1 -0
  128. package/dist/cjs/Provider/BoxOfficeProvider.js +72 -0
  129. package/dist/cjs/Provider/BoxOfficeProvider.js.map +1 -0
  130. package/dist/cjs/Provider/index.d.ts +3 -0
  131. package/dist/cjs/Provider/index.d.ts.map +1 -0
  132. package/dist/cjs/Seats/AssignSeatDialog.d.ts +9 -0
  133. package/dist/cjs/Seats/AssignSeatDialog.d.ts.map +1 -0
  134. package/dist/cjs/Seats/AssignSeatDialog.js +99 -0
  135. package/dist/cjs/Seats/AssignSeatDialog.js.map +1 -0
  136. package/dist/cjs/Seats/SeatsPage.d.ts +2 -0
  137. package/dist/cjs/Seats/SeatsPage.d.ts.map +1 -0
  138. package/dist/cjs/Seats/SeatsPage.js +87 -0
  139. package/dist/cjs/Seats/SeatsPage.js.map +1 -0
  140. package/dist/cjs/Seats/SeatsView.d.ts +14 -0
  141. package/dist/cjs/Seats/SeatsView.d.ts.map +1 -0
  142. package/dist/cjs/Seats/SeatsView.js +111 -0
  143. package/dist/cjs/Seats/SeatsView.js.map +1 -0
  144. package/dist/cjs/Seats/index.d.ts +5 -0
  145. package/dist/cjs/Seats/index.d.ts.map +1 -0
  146. package/dist/cjs/Seats/seatModels.d.ts +23 -0
  147. package/dist/cjs/Seats/seatModels.d.ts.map +1 -0
  148. package/dist/cjs/Seats/seatModels.js +65 -0
  149. package/dist/cjs/Seats/seatModels.js.map +1 -0
  150. package/dist/cjs/Usage/UsagePage.d.ts +2 -0
  151. package/dist/cjs/Usage/UsagePage.d.ts.map +1 -0
  152. package/dist/cjs/Usage/UsagePage.js +26 -0
  153. package/dist/cjs/Usage/UsagePage.js.map +1 -0
  154. package/dist/cjs/Usage/UsageView.d.ts +9 -0
  155. package/dist/cjs/Usage/UsageView.d.ts.map +1 -0
  156. package/dist/cjs/Usage/UsageView.js +108 -0
  157. package/dist/cjs/Usage/UsageView.js.map +1 -0
  158. package/dist/cjs/Usage/index.d.ts +4 -0
  159. package/dist/cjs/Usage/index.d.ts.map +1 -0
  160. package/dist/cjs/Usage/usageModels.d.ts +17 -0
  161. package/dist/cjs/Usage/usageModels.d.ts.map +1 -0
  162. package/dist/cjs/Usage/usageModels.js +57 -0
  163. package/dist/cjs/Usage/usageModels.js.map +1 -0
  164. package/dist/cjs/formatting.d.ts +5 -0
  165. package/dist/cjs/formatting.d.ts.map +1 -0
  166. package/dist/cjs/formatting.js +46 -0
  167. package/dist/cjs/formatting.js.map +1 -0
  168. package/dist/cjs/index.d.ts +10 -0
  169. package/dist/cjs/index.d.ts.map +1 -0
  170. package/dist/cjs/index.js +85 -0
  171. package/dist/cjs/index.js.map +1 -0
  172. package/dist/cjs/package.json +3 -0
  173. package/dist/esm/Banners/NoLicense.d.ts +2 -0
  174. package/dist/esm/Banners/NoLicense.d.ts.map +1 -0
  175. package/dist/esm/Banners/NoLicense.js +48 -0
  176. package/dist/esm/Banners/NoLicense.js.map +1 -0
  177. package/dist/esm/Banners/SuspensionBanner.d.ts +7 -0
  178. package/dist/esm/Banners/SuspensionBanner.d.ts.map +1 -0
  179. package/dist/esm/Banners/SuspensionBanner.js +59 -0
  180. package/dist/esm/Banners/SuspensionBanner.js.map +1 -0
  181. package/dist/esm/Banners/TrialBanner.d.ts +2 -0
  182. package/dist/esm/Banners/TrialBanner.d.ts.map +1 -0
  183. package/dist/esm/Banners/TrialBanner.js +36 -0
  184. package/dist/esm/Banners/TrialBanner.js.map +1 -0
  185. package/dist/esm/Banners/bannerModels.d.ts +19 -0
  186. package/dist/esm/Banners/bannerModels.d.ts.map +1 -0
  187. package/dist/esm/Banners/bannerModels.js +96 -0
  188. package/dist/esm/Banners/bannerModels.js.map +1 -0
  189. package/dist/esm/Banners/index.d.ts +5 -0
  190. package/dist/esm/Banners/index.d.ts.map +1 -0
  191. package/dist/esm/Banners/index.js +5 -0
  192. package/dist/esm/Banners/index.js.map +1 -0
  193. package/dist/esm/Entitlements/EntitlementsContext.d.ts +4 -0
  194. package/dist/esm/Entitlements/EntitlementsContext.d.ts.map +1 -0
  195. package/dist/esm/Entitlements/EntitlementsContext.js +16 -0
  196. package/dist/esm/Entitlements/EntitlementsContext.js.map +1 -0
  197. package/dist/esm/Entitlements/RequiresModule.d.ts +9 -0
  198. package/dist/esm/Entitlements/RequiresModule.d.ts.map +1 -0
  199. package/dist/esm/Entitlements/RequiresModule.js +66 -0
  200. package/dist/esm/Entitlements/RequiresModule.js.map +1 -0
  201. package/dist/esm/Entitlements/entitlementModel.d.ts +25 -0
  202. package/dist/esm/Entitlements/entitlementModel.d.ts.map +1 -0
  203. package/dist/esm/Entitlements/entitlementModel.js +89 -0
  204. package/dist/esm/Entitlements/entitlementModel.js.map +1 -0
  205. package/dist/esm/Entitlements/index.d.ts +7 -0
  206. package/dist/esm/Entitlements/index.d.ts.map +1 -0
  207. package/dist/esm/Entitlements/index.js +7 -0
  208. package/dist/esm/Entitlements/index.js.map +1 -0
  209. package/dist/esm/Entitlements/moduleFilter.d.ts +6 -0
  210. package/dist/esm/Entitlements/moduleFilter.d.ts.map +1 -0
  211. package/dist/esm/Entitlements/moduleFilter.js +14 -0
  212. package/dist/esm/Entitlements/moduleFilter.js.map +1 -0
  213. package/dist/esm/Entitlements/requiresModuleModel.d.ts +10 -0
  214. package/dist/esm/Entitlements/requiresModuleModel.d.ts.map +1 -0
  215. package/dist/esm/Entitlements/requiresModuleModel.js +30 -0
  216. package/dist/esm/Entitlements/requiresModuleModel.js.map +1 -0
  217. package/dist/esm/Entitlements/useEntitlements.d.ts +5 -0
  218. package/dist/esm/Entitlements/useEntitlements.d.ts.map +1 -0
  219. package/dist/esm/Entitlements/useEntitlements.js +23 -0
  220. package/dist/esm/Entitlements/useEntitlements.js.map +1 -0
  221. package/dist/esm/Labels/BoxOfficeLabels.d.ts +116 -0
  222. package/dist/esm/Labels/BoxOfficeLabels.d.ts.map +1 -0
  223. package/dist/esm/Labels/BoxOfficeLabels.js +2 -0
  224. package/dist/esm/Labels/BoxOfficeLabels.js.map +1 -0
  225. package/dist/esm/Labels/defaultBoxOfficeLabels.d.ts +3 -0
  226. package/dist/esm/Labels/defaultBoxOfficeLabels.d.ts.map +1 -0
  227. package/dist/esm/Labels/defaultBoxOfficeLabels.js +118 -0
  228. package/dist/esm/Labels/defaultBoxOfficeLabels.js.map +1 -0
  229. package/dist/esm/Labels/format.d.ts +2 -0
  230. package/dist/esm/Labels/format.d.ts.map +1 -0
  231. package/dist/esm/Labels/format.js +13 -0
  232. package/dist/esm/Labels/format.js.map +1 -0
  233. package/dist/esm/Labels/index.d.ts +5 -0
  234. package/dist/esm/Labels/index.d.ts.map +1 -0
  235. package/dist/esm/Labels/index.js +5 -0
  236. package/dist/esm/Labels/index.js.map +1 -0
  237. package/dist/esm/Labels/resolveLabels.d.ts +3 -0
  238. package/dist/esm/Labels/resolveLabels.d.ts.map +1 -0
  239. package/dist/esm/Labels/resolveLabels.js +33 -0
  240. package/dist/esm/Labels/resolveLabels.js.map +1 -0
  241. package/dist/esm/Plan/PlanPage.d.ts +2 -0
  242. package/dist/esm/Plan/PlanPage.d.ts.map +1 -0
  243. package/dist/esm/Plan/PlanPage.js +22 -0
  244. package/dist/esm/Plan/PlanPage.js.map +1 -0
  245. package/dist/esm/Plan/PlanView.d.ts +10 -0
  246. package/dist/esm/Plan/PlanView.d.ts.map +1 -0
  247. package/dist/esm/Plan/PlanView.js +121 -0
  248. package/dist/esm/Plan/PlanView.js.map +1 -0
  249. package/dist/esm/Plan/index.d.ts +4 -0
  250. package/dist/esm/Plan/index.d.ts.map +1 -0
  251. package/dist/esm/Plan/index.js +4 -0
  252. package/dist/esm/Plan/index.js.map +1 -0
  253. package/dist/esm/Plan/planModels.d.ts +24 -0
  254. package/dist/esm/Plan/planModels.d.ts.map +1 -0
  255. package/dist/esm/Plan/planModels.js +78 -0
  256. package/dist/esm/Plan/planModels.js.map +1 -0
  257. package/dist/esm/Portal/PortalButton.d.ts +10 -0
  258. package/dist/esm/Portal/PortalButton.d.ts.map +1 -0
  259. package/dist/esm/Portal/PortalButton.js +35 -0
  260. package/dist/esm/Portal/PortalButton.js.map +1 -0
  261. package/dist/esm/Portal/index.d.ts +3 -0
  262. package/dist/esm/Portal/index.d.ts.map +1 -0
  263. package/dist/esm/Portal/index.js +3 -0
  264. package/dist/esm/Portal/index.js.map +1 -0
  265. package/dist/esm/Portal/portalLinks.d.ts +6 -0
  266. package/dist/esm/Portal/portalLinks.d.ts.map +1 -0
  267. package/dist/esm/Portal/portalLinks.js +31 -0
  268. package/dist/esm/Portal/portalLinks.js.map +1 -0
  269. package/dist/esm/Provider/BoxOfficeContext.d.ts +16 -0
  270. package/dist/esm/Provider/BoxOfficeContext.d.ts.map +1 -0
  271. package/dist/esm/Provider/BoxOfficeContext.js +29 -0
  272. package/dist/esm/Provider/BoxOfficeContext.js.map +1 -0
  273. package/dist/esm/Provider/BoxOfficeProvider.d.ts +15 -0
  274. package/dist/esm/Provider/BoxOfficeProvider.d.ts.map +1 -0
  275. package/dist/esm/Provider/BoxOfficeProvider.js +70 -0
  276. package/dist/esm/Provider/BoxOfficeProvider.js.map +1 -0
  277. package/dist/esm/Provider/index.d.ts +3 -0
  278. package/dist/esm/Provider/index.d.ts.map +1 -0
  279. package/dist/esm/Provider/index.js +3 -0
  280. package/dist/esm/Provider/index.js.map +1 -0
  281. package/dist/esm/Seats/AssignSeatDialog.d.ts +9 -0
  282. package/dist/esm/Seats/AssignSeatDialog.d.ts.map +1 -0
  283. package/dist/esm/Seats/AssignSeatDialog.js +97 -0
  284. package/dist/esm/Seats/AssignSeatDialog.js.map +1 -0
  285. package/dist/esm/Seats/SeatsPage.d.ts +2 -0
  286. package/dist/esm/Seats/SeatsPage.d.ts.map +1 -0
  287. package/dist/esm/Seats/SeatsPage.js +85 -0
  288. package/dist/esm/Seats/SeatsPage.js.map +1 -0
  289. package/dist/esm/Seats/SeatsView.d.ts +14 -0
  290. package/dist/esm/Seats/SeatsView.d.ts.map +1 -0
  291. package/dist/esm/Seats/SeatsView.js +109 -0
  292. package/dist/esm/Seats/SeatsView.js.map +1 -0
  293. package/dist/esm/Seats/index.d.ts +5 -0
  294. package/dist/esm/Seats/index.d.ts.map +1 -0
  295. package/dist/esm/Seats/index.js +5 -0
  296. package/dist/esm/Seats/index.js.map +1 -0
  297. package/dist/esm/Seats/seatModels.d.ts +23 -0
  298. package/dist/esm/Seats/seatModels.d.ts.map +1 -0
  299. package/dist/esm/Seats/seatModels.js +59 -0
  300. package/dist/esm/Seats/seatModels.js.map +1 -0
  301. package/dist/esm/Usage/UsagePage.d.ts +2 -0
  302. package/dist/esm/Usage/UsagePage.d.ts.map +1 -0
  303. package/dist/esm/Usage/UsagePage.js +24 -0
  304. package/dist/esm/Usage/UsagePage.js.map +1 -0
  305. package/dist/esm/Usage/UsageView.d.ts +9 -0
  306. package/dist/esm/Usage/UsageView.d.ts.map +1 -0
  307. package/dist/esm/Usage/UsageView.js +106 -0
  308. package/dist/esm/Usage/UsageView.js.map +1 -0
  309. package/dist/esm/Usage/index.d.ts +4 -0
  310. package/dist/esm/Usage/index.d.ts.map +1 -0
  311. package/dist/esm/Usage/index.js +4 -0
  312. package/dist/esm/Usage/index.js.map +1 -0
  313. package/dist/esm/Usage/usageModels.d.ts +17 -0
  314. package/dist/esm/Usage/usageModels.d.ts.map +1 -0
  315. package/dist/esm/Usage/usageModels.js +53 -0
  316. package/dist/esm/Usage/usageModels.js.map +1 -0
  317. package/dist/esm/formatting.d.ts +5 -0
  318. package/dist/esm/formatting.d.ts.map +1 -0
  319. package/dist/esm/formatting.js +42 -0
  320. package/dist/esm/formatting.js.map +1 -0
  321. package/dist/esm/index.d.ts +10 -0
  322. package/dist/esm/index.d.ts.map +1 -0
  323. package/dist/esm/index.js +29 -0
  324. package/dist/esm/index.js.map +1 -0
  325. package/dist/esm/package.json +3 -0
  326. package/formatting.ts +41 -0
  327. package/index.ts +12 -0
  328. package/package.json +84 -4
  329. package/styles.css +166 -0
@@ -0,0 +1,48 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { Button, ButtonProps } from '@cratis/components/Common';
5
+ import { Guid } from '@cratis/fundamentals';
6
+ import { PortalIntent } from '@cratis/showrunner.boxoffice';
7
+ import { useState } from 'react';
8
+ import { useBoxOfficeContext } from '../Provider/BoxOfficeContext.js';
9
+ import { useEntitlementsContext } from '../Entitlements/EntitlementsContext.js';
10
+
11
+ /**
12
+ * Props for {@link PortalButton}.
13
+ */
14
+ export interface PortalButtonProps extends Pick<ButtonProps, 'variant' | 'tone' | 'size' | 'className' | 'icon'> {
15
+ /** What the user wants to do in the customer portal. */
16
+ intent: PortalIntent;
17
+
18
+ /** The text of the button. */
19
+ label: string;
20
+
21
+ /** The offer the user looked at, when they did. */
22
+ offer?: Guid;
23
+ }
24
+
25
+ /**
26
+ * A button that opens the operator's customer portal with a signed link, to buy, try or change plan. It is not shown
27
+ * when the product has no customer portal.
28
+ */
29
+ export const PortalButton = ({ intent, label, offer, variant = 'solid', ...rest }: PortalButtonProps) => {
30
+ const { openPortal } = useBoxOfficeContext();
31
+ const { canOpenPortal } = useEntitlementsContext();
32
+ const [isOpening, setIsOpening] = useState(false);
33
+
34
+ if (!canOpenPortal) {
35
+ return null;
36
+ }
37
+
38
+ const open = async () => {
39
+ setIsOpening(true);
40
+ try {
41
+ await openPortal(intent, offer);
42
+ } finally {
43
+ setIsOpening(false);
44
+ }
45
+ };
46
+
47
+ return <Button {...rest} variant={variant} label={label} loading={isOpening} onClick={() => void open()} />;
48
+ };
@@ -0,0 +1,5 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ export * from './portalLinks.js';
5
+ export * from './PortalButton.js';
@@ -0,0 +1,32 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { ArcConfiguration } from '@cratis/arc.react';
5
+ import { Guid } from '@cratis/fundamentals';
6
+ import { LinkToPortal, PortalIntent } from '@cratis/showrunner.boxoffice';
7
+
8
+ /**
9
+ * Asks the backend for a signed link that opens the customer portal for what the user wants to do there.
10
+ * @param arc The Arc configuration the application runs with.
11
+ * @param intent What the user wants to do.
12
+ * @param offer The offer the user looked at, when they did.
13
+ * @returns The link; undefined when the backend gave none.
14
+ */
15
+ export async function linkToPortal(arc: ArcConfiguration, intent: PortalIntent, offer?: Guid): Promise<string | undefined> {
16
+ const query = new LinkToPortal();
17
+ query.setMicroservice(arc.microservice);
18
+ query.setApiBasePath(arc.apiBasePath ?? '');
19
+ query.setOrigin(arc.origin ?? '');
20
+ query.setHttpHeadersCallback(arc.httpHeadersCallback ?? (() => ({})));
21
+
22
+ const result = await query.perform({ intent, offer });
23
+ return result.isSuccess && result.data?.url ? result.data.url : undefined;
24
+ }
25
+
26
+ /**
27
+ * Opens a link in a new tab, without letting the page it opens reach back to this one.
28
+ * @param url The link.
29
+ */
30
+ export function openInNewTab(url: string): void {
31
+ window.open(url, '_blank', 'noopener,noreferrer');
32
+ }
@@ -0,0 +1,67 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { Guid } from '@cratis/fundamentals';
5
+ import { PortalIntent, SeatStanding } from '@cratis/showrunner.boxoffice';
6
+ import { createContext, useContext } from 'react';
7
+ import { BoxOfficeLabels, resolveLabels } from '../Labels/index.js';
8
+
9
+ /**
10
+ * What {@link BoxOfficeProvider} gives the Box Office components.
11
+ */
12
+ export interface BoxOfficeContextValue {
13
+ /** Whether a {@link BoxOfficeProvider} provides the value; the defaults otherwise. */
14
+ readonly isProvided: boolean;
15
+
16
+ /** The labels to show. */
17
+ readonly labels: BoxOfficeLabels;
18
+
19
+ /** The locale to format dates and numbers for; the browser's when not given. */
20
+ readonly locale?: string;
21
+
22
+ /** Where the signed-in user stands with the tenant's seats; nothing while it loads. */
23
+ readonly seat?: SeatStanding;
24
+
25
+ /**
26
+ * Opens the customer portal for what the user wants to do there. Reports a failure with a toast.
27
+ * @param intent What the user wants to do.
28
+ * @param offer The offer the user looked at, when they did.
29
+ */
30
+ openPortal(intent: PortalIntent, offer?: Guid): Promise<void>;
31
+
32
+ /**
33
+ * Asks the backend again what the tenant may do, for after something changed it.
34
+ */
35
+ refresh(): void;
36
+ }
37
+
38
+ const noop = () => {
39
+ /* Without a BoxOfficeProvider there is nothing to refresh. */
40
+ };
41
+
42
+ /**
43
+ * The value without a {@link BoxOfficeProvider}: English labels, and no portal to open.
44
+ */
45
+ export const defaultBoxOfficeContextValue: BoxOfficeContextValue = {
46
+ isProvided: false,
47
+ labels: resolveLabels(),
48
+ openPortal: () => Promise.resolve(),
49
+ refresh: noop
50
+ };
51
+
52
+ /**
53
+ * The React context {@link BoxOfficeProvider} provides.
54
+ */
55
+ export const BoxOfficeContext = createContext<BoxOfficeContextValue>(defaultBoxOfficeContextValue);
56
+
57
+ /**
58
+ * Gets what {@link BoxOfficeProvider} provides, or the defaults outside one.
59
+ * @returns The {@link BoxOfficeContextValue}.
60
+ */
61
+ export const useBoxOfficeContext = (): BoxOfficeContextValue => useContext(BoxOfficeContext);
62
+
63
+ /**
64
+ * Gets the labels to show.
65
+ * @returns The {@link BoxOfficeLabels}.
66
+ */
67
+ export const useBoxOfficeLabels = (): BoxOfficeLabels => useContext(BoxOfficeContext).labels;
@@ -0,0 +1,96 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { ArcContext } from '@cratis/arc.react';
5
+ import { toast } from '@cratis/components/Notifications';
6
+ import { Guid } from '@cratis/fundamentals';
7
+ import { CurrentEntitlements, EntitlementSummary, Mine, PortalIntent, SeatStanding } from '@cratis/showrunner.boxoffice';
8
+ import { ReactNode, useContext, useMemo } from 'react';
9
+ import { entitlementsOf } from '../Entitlements/entitlementModel.js';
10
+ import { EntitlementsContext } from '../Entitlements/EntitlementsContext.js';
11
+ import { BoxOfficeLabelOverrides, resolveLabels } from '../Labels/index.js';
12
+ import { linkToPortal, openInNewTab } from '../Portal/portalLinks.js';
13
+ import { BoxOfficeContext, BoxOfficeContextValue } from './BoxOfficeContext.js';
14
+
15
+ /**
16
+ * Props for {@link BoxOfficeProvider}.
17
+ */
18
+ export interface BoxOfficeProviderProps {
19
+ /** The labels that replace the English defaults, for instance to localize them. */
20
+ labels?: BoxOfficeLabelOverrides;
21
+
22
+ /** The locale to format dates and numbers for; the browser's when not given. */
23
+ locale?: string;
24
+
25
+ /**
26
+ * The entitlements to use instead of asking the backend. For stories, specifications and previews; leave it out in
27
+ * the application.
28
+ */
29
+ entitlements?: EntitlementSummary;
30
+
31
+ /**
32
+ * Where the user stands with the tenant's seats, to use instead of asking the backend. For stories,
33
+ * specifications and previews; leave it out in the application.
34
+ */
35
+ seat?: SeatStanding;
36
+
37
+ /** Opens a link to the customer portal. Defaults to opening it in a new tab. */
38
+ openLink?: (url: string) => void;
39
+
40
+ /**
41
+ * Gets the link that opens the customer portal, instead of asking the backend for a signed one. For stories and
42
+ * specifications; leave it out in the application.
43
+ */
44
+ portalLink?: (intent: PortalIntent, offer?: Guid) => Promise<string | undefined>;
45
+
46
+ /** The application. */
47
+ children?: ReactNode;
48
+ }
49
+
50
+ /**
51
+ * Slots Box Office into an application: asks the backend what the signed-in user's tenant may do and where the user
52
+ * stands with its seats, and gives {@link useEntitlements}, {@link RequiresModule}, the banners and the pages what they
53
+ * need. Render it inside `<Arc>` and a `CratisComponentsProvider` with a toaster, once, around the shell.
54
+ */
55
+ export const BoxOfficeProvider = ({ labels, locale, entitlements: preloaded, seat: preloadedSeat, openLink = openInNewTab, portalLink, children }: BoxOfficeProviderProps) => {
56
+ const arc = useContext(ArcContext);
57
+ const resolvedLabels = useMemo(() => resolveLabels(labels), [labels]);
58
+ const [summaryResult, refreshSummary] = CurrentEntitlements.when(preloaded === undefined).use();
59
+ const [seatResult, refreshSeat] = Mine.when(preloadedSeat === undefined).use();
60
+
61
+ const summary = preloaded ?? (summaryResult.isSuccess && summaryResult.data?.modules ? summaryResult.data : undefined);
62
+ const seat = preloadedSeat ?? (seatResult.isSuccess && seatResult.data?.status !== undefined ? seatResult.data : undefined);
63
+ const entitlements = useMemo(() => entitlementsOf(summary), [summary]);
64
+
65
+ const value = useMemo<BoxOfficeContextValue>(() => ({
66
+ isProvided: true,
67
+ labels: resolvedLabels,
68
+ locale,
69
+ seat,
70
+ openPortal: async (intent: PortalIntent, offer?: Guid) => {
71
+ try {
72
+ const url = await (portalLink ? portalLink(intent, offer) : linkToPortal(arc, intent, offer));
73
+ if (url) {
74
+ openLink(url);
75
+ return;
76
+ }
77
+ } catch {
78
+ /* The toast below says what went wrong; the details are of no use to the user. */
79
+ }
80
+
81
+ toast.error({ title: resolvedLabels.common.portalFailed });
82
+ },
83
+ refresh: () => {
84
+ void refreshSummary();
85
+ void refreshSeat();
86
+ }
87
+ }), [resolvedLabels, locale, seat, arc, openLink, portalLink, refreshSummary, refreshSeat]);
88
+
89
+ return (
90
+ <BoxOfficeContext.Provider value={value}>
91
+ <EntitlementsContext.Provider value={entitlements}>
92
+ {children}
93
+ </EntitlementsContext.Provider>
94
+ </BoxOfficeContext.Provider>
95
+ );
96
+ };
@@ -0,0 +1,5 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ export * from './BoxOfficeContext.js';
5
+ export * from './BoxOfficeProvider.js';
package/README.md CHANGED
@@ -1,3 +1,72 @@
1
- # Temporary Holding Version
1
+ # Showrunner
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > Showrunner is a set of ready-made product parts for applications built on [Cratis](https://www.cratis.io) — drop-in backend and frontend packages, built as Arc and Chronicle vertical slices.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+ [![Build](https://github.com/Cratis/Showrunner/actions/workflows/build.yml/badge.svg)](https://github.com/Cratis/Showrunner/actions/workflows/build.yml)
7
+ [![Publish](https://github.com/Cratis/Showrunner/actions/workflows/publish.yml/badge.svg)](https://github.com/Cratis/Showrunner/actions/workflows/publish.yml)
8
+ [![Discord](https://img.shields.io/discord/1182595891576717413?label=Discord&logo=discord&logoColor=white)](https://discord.gg/kt4AMpV8WV)
9
+
10
+ ## Usher
11
+
12
+ **Usher** is the support part: it lets the users of an application report issues and hold support conversations with the people running it. It is a library an application hosts, not a service of its own — the backend package adds Usher's commands, queries and events to the host's Arc application and Chronicle event store, and the frontend packages give the host's React UI the generated proxies and components to drive them.
13
+
14
+ Usher is in its earliest stage: the packages are scaffolded and published, but carry no behavior yet. See [Documentation](./Documentation/index.md).
15
+
16
+ **Box Office** is the licensing part: trials, seats, modules, compute allowances and suspension, decided by the operator of a managed product and honored by the product. Its event contracts, its catalog of offers and prices, and a product's offering declaration and compute metering are in place; see [Documentation](./Documentation/BoxOffice/index.md).
17
+
18
+ **Marquee** is the announcements part: the people running a product write an announcement with an audience, a display and an exact window, and the product shows it to the people it reaches, as a banner or a dialog. Drop `<Marquee />` into the application shell and it brings its own queries and commands; see [Documentation](./Documentation/Marquee/index.md).
19
+
20
+ ## Packages
21
+
22
+ | Package | Registry | What it is |
23
+ | --- | --- | --- |
24
+ | `Cratis.Showrunner.BoxOffice.Catalog` | NuGet | Box Office's catalog — offers (seat plans, modules, compute packs), prices and the pricing arithmetic, published to products |
25
+ | `Cratis.Showrunner.BoxOffice.Offering` | NuGet | Box Office for a product — declares what the product sells (modules, meters, seat licensing) and measures its compute per tenant and day |
26
+ | `Cratis.Showrunner.BoxOffice.Contracts` | NuGet | Box Office's event contracts: what an operator decides about a tenant and what a product reports back |
27
+ | `Cratis.Showrunner.Usher.Contracts` | NuGet | Usher's event contracts, for hosts that react to what Usher records |
28
+ | `Cratis.Showrunner.Marquee.Contracts` | NuGet | Marquee's event contracts: the public events a product receives announcements through |
29
+ | `Cratis.Showrunner.Marquee.Authoring` | NuGet | Marquee's authoring backend — commands, query and outbox for writing announcements, built on Arc and Chronicle |
30
+ | `Cratis.Showrunner.Marquee` | NuGet | Marquee's backend for products — receives announcements once, shows each tenant what its audience matches and records acknowledgements |
31
+ | `Cratis.Showrunner.Usher` | NuGet | Usher's backend — Arc commands and queries over Chronicle |
32
+ | `@cratis/showrunner.marquee` | npm | The generated TypeScript proxies for Marquee's receiving commands and queries; no UI framework dependency |
33
+ | `@cratis/showrunner.marquee.authoring` | npm | The generated TypeScript proxies for Marquee's authoring commands and query; no UI framework dependency |
34
+ | `@cratis/showrunner.marquee.react` | npm | The Marquee drop-in React component: banners and dialogs for a product's announcements, built on `@cratis/arc.react` and `@cratis/components` |
35
+ | `@cratis/showrunner.usher` | npm | The generated TypeScript proxies for Usher's commands and queries; no UI framework dependency |
36
+ | `@cratis/showrunner.usher.react` | npm | React components for Usher, built on `@cratis/arc.react` and `@cratis/components` |
37
+
38
+ ## Building
39
+
40
+ Prerequisites: the .NET SDK from [`global.json`](./global.json) (10.0.400 or later) and Node.js 20 or later with Corepack enabled (`corepack enable`); Yarn itself is checked in under `.yarn/releases`.
41
+
42
+ ```shell
43
+ # Backend: Debug builds compile the inline specs and regenerate the TypeScript proxies
44
+ dotnet build Showrunner.slnx --configuration Debug
45
+ dotnet test Showrunner.slnx --configuration Debug --no-build
46
+
47
+ # Release is warnings-as-errors; clearing CratisProxiesOutputPath skips proxy generation
48
+ dotnet build Showrunner.slnx --configuration Release -p:CratisProxiesOutputPath=
49
+
50
+ # Frontend
51
+ yarn install
52
+ yarn lint:ci
53
+ yarn compile
54
+ yarn test
55
+ yarn build
56
+ ```
57
+
58
+ Specifications live beside the code they specify — `for_*/when_*/` folders compiled into Debug builds only for .NET, and Vitest specs in the same layout for TypeScript.
59
+
60
+ The end-to-end specifications in [`Integration`](./Integration) run Usher and a desk against a real Chronicle kernel in a container, so `dotnet test Showrunner.slnx` needs Docker. Set `USHER_CHRONICLE_IMAGE` to run them against another kernel image, and `USHER_INTEGRATION_LOG` to a file path to keep the application's log.
61
+
62
+ ## Releasing
63
+
64
+ Every pull request carries exactly one of the `major`, `minor`, `patch` or `no-release` labels. Merging a version-labelled pull request to `main` releases all four packages under one semantic version through [`cratis/release-action`](https://github.com/Cratis/release-action) — NuGet packages through NuGet trusted publishing and npm packages through npm trusted publishing with provenance. The packages are built and packed in jobs without publishing rights; separate jobs that run no build or install script hold the short-lived OIDC token and only push what was packed.
65
+
66
+ ## Part of the Cratis ecosystem
67
+
68
+ Showrunner is a [Cratis](https://www.cratis.io) project, built on event sourcing with [Chronicle](https://github.com/Cratis/Chronicle) and CQRS with [Arc](https://github.com/Cratis/Arc), with frontends on [`@cratis/components`](https://github.com/Cratis/Components). Join the community on [Discord](https://discord.gg/kt4AMpV8WV).
69
+
70
+ ## License
71
+
72
+ Showrunner is licensed under the [MIT License](LICENSE) and free to use.
@@ -0,0 +1,73 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { DialogResult } from '@cratis/arc.react/dialogs';
5
+ import { TextInput } from '@cratis/components/Common';
6
+ import { Dialog, DialogInitialFocus } from '@cratis/components/Dialogs';
7
+ import { useState } from 'react';
8
+ import { useBoxOfficeLabels } from '../Provider/BoxOfficeContext.js';
9
+ import { emptySeatPerson, isValidSeatPerson, SeatPersonInput } from './seatModels.js';
10
+
11
+ /**
12
+ * Props for {@link AssignSeatDialog}.
13
+ */
14
+ export interface AssignSeatDialogProps {
15
+ /** Whether the dialog is open. */
16
+ visible: boolean;
17
+
18
+ /** Whether the seat is being assigned. */
19
+ isBusy?: boolean;
20
+
21
+ /** Called when the user confirms, with the person to give a seat. */
22
+ onAssign: (person: SeatPersonInput) => void;
23
+
24
+ /** Called when the user closes the dialog. */
25
+ onClose: () => void;
26
+ }
27
+
28
+ /**
29
+ * Asks who to give a seat.
30
+ */
31
+ export const AssignSeatDialog = ({ visible, isBusy, onAssign, onClose }: AssignSeatDialogProps) => {
32
+ const labels = useBoxOfficeLabels();
33
+ const [person, setPerson] = useState<SeatPersonInput>(emptySeatPerson);
34
+ const change = (field: keyof SeatPersonInput) => (value: string) => setPerson(current => ({ ...current, [field]: value }));
35
+
36
+ return (
37
+ <Dialog
38
+ title={labels.seats.assignTitle}
39
+ visible={visible}
40
+ okLabel={labels.seats.assignConfirm}
41
+ cancelLabel={labels.common.cancel}
42
+ closeAriaLabel={labels.common.close}
43
+ initialFocus={DialogInitialFocus.Content}
44
+ isValid={isValidSeatPerson(person)}
45
+ isBusy={isBusy}
46
+ onConfirm={() => onAssign(person)}
47
+ onClose={result => {
48
+ if (result !== DialogResult.Ok) {
49
+ setPerson(emptySeatPerson);
50
+ onClose();
51
+ }
52
+ }}>
53
+ <form className='boxoffice-seat-form' onSubmit={event => event.preventDefault()}>
54
+ <label className='boxoffice-field'>
55
+ <span>{labels.seats.name}</span>
56
+ <TextInput value={person.name} onChange={change('name')} autoComplete='off' />
57
+ </label>
58
+ <label className='boxoffice-field'>
59
+ <span>{labels.seats.email}</span>
60
+ <TextInput type='email' value={person.email} onChange={change('email')} autoComplete='off' />
61
+ </label>
62
+ <label className='boxoffice-field'>
63
+ <span>{labels.seats.identityProvider}</span>
64
+ <TextInput value={person.identityProvider} onChange={change('identityProvider')} autoComplete='off' />
65
+ </label>
66
+ <label className='boxoffice-field'>
67
+ <span>{labels.seats.subject}</span>
68
+ <TextInput value={person.subject} onChange={change('subject')} autoComplete='off' />
69
+ </label>
70
+ </form>
71
+ </Dialog>
72
+ );
73
+ };
@@ -0,0 +1,85 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { DialogButtons, DialogResult, useConfirmationDialog } from '@cratis/arc.react/dialogs';
5
+ import { toastCommandResult } from '@cratis/components/Notifications';
6
+ import { AssignSeat, CurrentRoster, ReleaseSeat, SeatHolder, SeatHolding } from '@cratis/showrunner.boxoffice';
7
+ import { useState } from 'react';
8
+ import { useEntitlementsContext } from '../Entitlements/EntitlementsContext.js';
9
+ import { format } from '../Labels/index.js';
10
+ import { useBoxOfficeContext } from '../Provider/BoxOfficeContext.js';
11
+ import { AssignSeatDialog } from './AssignSeatDialog.js';
12
+ import { personOf, seatRows, seatSummary, SeatPersonInput } from './seatModels.js';
13
+ import { SeatsView } from './SeatsView.js';
14
+
15
+ /**
16
+ * The seats page: who holds the tenant's seats, with buttons to assign and release them. For the people who maintain
17
+ * the product; the backend refuses everyone else. Render it inside a {@link BoxOfficeProvider}, the `DialogComponents`
18
+ * registration and a `CratisComponentsProvider` with a toaster.
19
+ */
20
+ export const SeatsPage = () => {
21
+ const { labels, refresh } = useBoxOfficeContext();
22
+ const entitlements = useEntitlementsContext();
23
+ const [roster, performRoster] = CurrentRoster.use();
24
+ const [assignSeat] = AssignSeat.use();
25
+ const [releaseSeat] = ReleaseSeat.use();
26
+ const [confirm] = useConfirmationDialog();
27
+ const [isAssigning, setIsAssigning] = useState(false);
28
+ const [isBusy, setIsBusy] = useState(false);
29
+
30
+ const rows = seatRows(roster.isSuccess ? roster.data : undefined, entitlements.seats);
31
+ const changed = () => {
32
+ void performRoster();
33
+ refresh();
34
+ };
35
+
36
+ const assign = async (input: SeatPersonInput) => {
37
+ setIsBusy(true);
38
+ try {
39
+ assignSeat.holder = personOf(input);
40
+ if (toastCommandResult(await assignSeat.execute(), { successTitle: labels.seats.assignConfirm })) {
41
+ setIsAssigning(false);
42
+ changed();
43
+ }
44
+ } finally {
45
+ setIsBusy(false);
46
+ }
47
+ };
48
+
49
+ const release = async (holding: SeatHolding) => {
50
+ const answer = await confirm(
51
+ labels.seats.releaseTitle,
52
+ format(labels.seats.releaseMessage, { name: holding.holder.name }),
53
+ DialogButtons.YesNo);
54
+ if (answer !== DialogResult.Yes) {
55
+ return;
56
+ }
57
+
58
+ const holder = new SeatHolder();
59
+ holder.identityProvider = holding.holder.identityProvider;
60
+ holder.subject = holding.holder.identityProviderSubject;
61
+ releaseSeat.holder = holder;
62
+ if (toastCommandResult(await releaseSeat.execute(), { showSuccess: false })) {
63
+ changed();
64
+ }
65
+ };
66
+
67
+ return (
68
+ <>
69
+ <SeatsView
70
+ rows={rows}
71
+ summary={seatSummary(rows, entitlements.seats)}
72
+ isReadOnly={entitlements.isReadOnly}
73
+ isLoading={roster.isPerforming && !roster.isSuccess}
74
+ isUnauthorized={!roster.isAuthorized}
75
+ hasFailed={!roster.isPerforming && roster.isAuthorized && !roster.isSuccess}
76
+ onAssign={() => setIsAssigning(true)}
77
+ onRelease={holding => void release(holding)} />
78
+ <AssignSeatDialog
79
+ visible={isAssigning}
80
+ isBusy={isBusy}
81
+ onAssign={input => void assign(input)}
82
+ onClose={() => setIsAssigning(false)} />
83
+ </>
84
+ );
85
+ };
@@ -0,0 +1,108 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { Button } from '@cratis/components/Common';
5
+ import { Column, DataTableCore, DataTableStatus } from '@cratis/components/DataTables';
6
+ import { Message, Tag } from '@cratis/components/Display';
7
+ import { SeatHolding } from '@cratis/showrunner.boxoffice';
8
+ import { formatDay } from '../formatting.js';
9
+ import { format } from '../Labels/index.js';
10
+ import { useBoxOfficeContext } from '../Provider/BoxOfficeContext.js';
11
+ import { SeatRow, SeatSummary } from './seatModels.js';
12
+
13
+ /**
14
+ * Props for {@link SeatsView}.
15
+ */
16
+ export interface SeatsViewProps {
17
+ /** The seats, oldest first. */
18
+ rows: readonly SeatRow[];
19
+
20
+ /** What to summarize. */
21
+ summary: SeatSummary;
22
+
23
+ /** Whether the tenant is read-only, so seats cannot be changed. */
24
+ isReadOnly: boolean;
25
+
26
+ /** Whether the seats are still loading. */
27
+ isLoading?: boolean;
28
+
29
+ /** Whether the seats could not be loaded because the user may not see them. */
30
+ isUnauthorized?: boolean;
31
+
32
+ /** Whether the seats could not be loaded. */
33
+ hasFailed?: boolean;
34
+
35
+ /** Called when the user wants to assign a seat. */
36
+ onAssign: () => void;
37
+
38
+ /** Called when the user wants to release a seat. */
39
+ onRelease: (holding: SeatHolding) => void;
40
+ }
41
+
42
+ const statusOf = (isLoading?: boolean, isUnauthorized?: boolean, hasFailed?: boolean) => {
43
+ if (isUnauthorized) {
44
+ return DataTableStatus.Unauthorized;
45
+ }
46
+
47
+ if (hasFailed) {
48
+ return DataTableStatus.Failed;
49
+ }
50
+
51
+ return isLoading ? DataTableStatus.Loading : DataTableStatus.Ready;
52
+ };
53
+
54
+ /**
55
+ * The seats of the tenant: how many are used, who holds them, and buttons to assign and release.
56
+ */
57
+ export const SeatsView = ({ rows, summary, isReadOnly, isLoading, isUnauthorized, hasFailed, onAssign, onRelease }: SeatsViewProps) => {
58
+ const { labels, locale } = useBoxOfficeContext();
59
+
60
+ return (
61
+ <section className='boxoffice-seats' aria-labelledby='boxoffice-seats-title'>
62
+ <header className='boxoffice-page__header'>
63
+ <h2 id='boxoffice-seats-title' className='boxoffice-page__title'>{labels.seats.title}</h2>
64
+ <Button label={labels.seats.assign} disabled={isReadOnly || summary.capacity === 0} onClick={onAssign} />
65
+ </header>
66
+
67
+ <p className='boxoffice-seats__summary'>
68
+ {summary.capacity === 0
69
+ ? labels.seats.noCapacity
70
+ : format(labels.seats.summary, { held: summary.held, capacity: summary.capacity })}
71
+ </p>
72
+ {summary.over > 0 && <Message severity='warn'>{format(labels.seats.overCapacity, { over: summary.over })}</Message>}
73
+ {isReadOnly && <Message severity='info'>{labels.seats.readOnly}</Message>}
74
+
75
+ <DataTableCore<SeatRow>
76
+ data={[...rows]}
77
+ dataKey='holding.holder.identityProviderSubject'
78
+ status={statusOf(isLoading, isUnauthorized, hasFailed)}
79
+ emptyMessage={labels.seats.empty}
80
+ loadingMessage={labels.common.loading}
81
+ failureMessage={labels.common.failed}
82
+ unauthorizedMessage={labels.common.unauthorized}>
83
+ <Column<SeatRow> header={labels.seats.holderColumn} body={row => row.holding.holder.name} />
84
+ <Column<SeatRow> header={labels.seats.emailColumn} body={row => row.holding.holder.email} />
85
+ <Column<SeatRow> header={labels.seats.assignedColumn} body={row => formatDay(row.holding.assignedAt, locale)} />
86
+ <Column<SeatRow>
87
+ header={labels.seats.statusColumn}
88
+ body={row => (
89
+ <Tag
90
+ severity={row.coverage === 'licensed' ? 'success' : 'warn'}
91
+ value={row.coverage === 'licensed' ? labels.seats.licensed : labels.seats.overCapacityStatus} />
92
+ )} />
93
+ <Column<SeatRow>
94
+ header=''
95
+ body={row => (
96
+ <Button
97
+ variant='ghost'
98
+ tone='critical'
99
+ size='small'
100
+ label={labels.seats.releaseShort}
101
+ aria-label={format(labels.seats.release, { name: row.holding.holder.name })}
102
+ disabled={isReadOnly}
103
+ onClick={() => onRelease(row.holding)} />
104
+ )} />
105
+ </DataTableCore>
106
+ </section>
107
+ );
108
+ };
package/Seats/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ export * from './AssignSeatDialog.js';
5
+ export * from './seatModels.js';
6
+ export * from './SeatsPage.js';
7
+ export * from './SeatsView.js';