@carlonicora/nextjs-jsonapi 1.0.4 → 1.0.6

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 (283) hide show
  1. package/LICENSE +675 -0
  2. package/dist/{AbstractService-BKlpJA61.d.mts → AbstractService-B2n_JdiC.d.mts} +1 -1
  3. package/dist/{AbstractService-D9eSVKNa.d.ts → AbstractService-DtQTYovo.d.ts} +1 -1
  4. package/dist/{content.interface-Dg2lt_An.d.mts → AuthComponent-CPLvEerw.d.mts} +11 -15
  5. package/dist/{content.interface-BhyAiOFq.d.ts → AuthComponent-m6Qp4Hz6.d.ts} +11 -15
  6. package/dist/{BlockNoteEditor-UVO3VZZE.mjs → BlockNoteEditor-BLVXQPXV.mjs} +14 -18
  7. package/dist/{BlockNoteEditor-UVO3VZZE.mjs.map → BlockNoteEditor-BLVXQPXV.mjs.map} +1 -1
  8. package/dist/{BlockNoteEditor-VFWG6LXI.js → BlockNoteEditor-ZTDHULFT.js} +15 -19
  9. package/dist/BlockNoteEditor-ZTDHULFT.js.map +1 -0
  10. package/dist/JsonApiRequest-O7BGUMFO.mjs +23 -0
  11. package/dist/JsonApiRequest-VARLNKAF.js +23 -0
  12. package/dist/JsonApiRequest-VARLNKAF.js.map +1 -0
  13. package/dist/chunk-2LM6LCJW.mjs +1 -0
  14. package/dist/chunk-3APORDYP.mjs +7783 -0
  15. package/dist/chunk-3APORDYP.mjs.map +1 -0
  16. package/dist/{chunk-TMVHSY3Y.js → chunk-5ZEADNNP.js} +36 -17
  17. package/dist/chunk-5ZEADNNP.js.map +1 -0
  18. package/dist/{chunk-ECDTZBYO.mjs → chunk-74F6BBHH.mjs} +21 -2
  19. package/dist/chunk-74F6BBHH.mjs.map +1 -0
  20. package/dist/{chunk-GYWPEPOH.mjs → chunk-7C5RAEBO.mjs} +72 -68
  21. package/dist/chunk-7C5RAEBO.mjs.map +1 -0
  22. package/dist/chunk-A5DDIABK.js +1 -0
  23. package/dist/{chunk-TEGF6ZWG.js → chunk-AGAJMJ4T.js} +47 -9
  24. package/dist/chunk-AGAJMJ4T.js.map +1 -0
  25. package/dist/{chunk-CXQOWQSY.js → chunk-AYHKQWHH.js} +15 -2
  26. package/dist/chunk-AYHKQWHH.js.map +1 -0
  27. package/dist/{chunk-I2REI7OA.js → chunk-HMHGLXWC.js} +33 -15
  28. package/dist/chunk-HMHGLXWC.js.map +1 -0
  29. package/dist/chunk-IWFGEPAA.mjs +1 -0
  30. package/dist/chunk-JC3WJK65.js +1 -0
  31. package/dist/{chunk-L6EQEAXU.mjs → chunk-PYF2U6WG.mjs} +25 -7
  32. package/dist/chunk-PYF2U6WG.mjs.map +1 -0
  33. package/dist/{chunk-YDVTFM7X.mjs → chunk-RBIVEH2K.mjs} +42 -4
  34. package/dist/chunk-RBIVEH2K.mjs.map +1 -0
  35. package/dist/{chunk-V2JJPI7N.js → chunk-RZO2LOW4.js} +237 -233
  36. package/dist/chunk-RZO2LOW4.js.map +1 -0
  37. package/dist/{chunk-X4BIHJ2B.mjs → chunk-SM63SZCP.mjs} +15 -2
  38. package/dist/chunk-SM63SZCP.mjs.map +1 -0
  39. package/dist/chunk-WEC4YMOS.js +7783 -0
  40. package/dist/chunk-WEC4YMOS.js.map +1 -0
  41. package/dist/client/index.d.mts +21 -2
  42. package/dist/client/index.d.ts +21 -2
  43. package/dist/client/index.js +18 -245
  44. package/dist/client/index.js.map +1 -1
  45. package/dist/client/index.mjs +28 -255
  46. package/dist/client/index.mjs.map +1 -1
  47. package/dist/components/index.d.mts +293 -8
  48. package/dist/components/index.d.ts +293 -8
  49. package/dist/components/index.js +78 -2323
  50. package/dist/components/index.js.map +1 -1
  51. package/dist/components/index.mjs +172 -2417
  52. package/dist/components/index.mjs.map +1 -1
  53. package/dist/{config-hXufftVS.d.ts → config-BmnK65TD.d.mts} +1 -0
  54. package/dist/{config-hXufftVS.d.mts → config-BmnK65TD.d.ts} +1 -0
  55. package/dist/config-DQeAo9Kf.d.mts +49 -0
  56. package/dist/config-DQeAo9Kf.d.ts +49 -0
  57. package/dist/contexts/index.d.mts +109 -21
  58. package/dist/contexts/index.d.ts +109 -21
  59. package/dist/contexts/index.js +39 -7
  60. package/dist/contexts/index.js.map +1 -1
  61. package/dist/contexts/index.mjs +40 -8
  62. package/dist/core/index.d.mts +3 -4
  63. package/dist/core/index.d.ts +3 -4
  64. package/dist/core/index.js +3 -7
  65. package/dist/core/index.js.map +1 -1
  66. package/dist/core/index.mjs +4 -8
  67. package/dist/{d3.link.interface-QMdB22bC.d.mts → d3.link.interface-ClC4Irqp.d.mts} +2 -1
  68. package/dist/{d3.link.interface-QMdB22bC.d.ts → d3.link.interface-ClC4Irqp.d.ts} +2 -1
  69. package/dist/features/index.d.mts +17 -86
  70. package/dist/features/index.d.ts +17 -86
  71. package/dist/features/index.js +7 -16
  72. package/dist/features/index.js.map +1 -1
  73. package/dist/features/index.mjs +10 -19
  74. package/dist/hooks/index.d.mts +18 -43
  75. package/dist/hooks/index.d.ts +18 -43
  76. package/dist/hooks/index.js +20 -7
  77. package/dist/hooks/index.js.map +1 -1
  78. package/dist/hooks/index.mjs +19 -6
  79. package/dist/index.d.mts +10 -6
  80. package/dist/index.d.ts +10 -6
  81. package/dist/index.js +13 -10
  82. package/dist/index.js.map +1 -1
  83. package/dist/index.mjs +22 -19
  84. package/dist/interfaces/index.d.mts +2 -1
  85. package/dist/interfaces/index.d.ts +2 -1
  86. package/dist/notification.interface-BBgMUdLR.d.mts +14 -0
  87. package/dist/notification.interface-gyvT-Z2F.d.ts +14 -0
  88. package/dist/permissions/index.d.mts +2 -3
  89. package/dist/permissions/index.d.ts +2 -3
  90. package/dist/server/index.d.mts +38 -18
  91. package/dist/server/index.d.ts +38 -18
  92. package/dist/server/index.js +70 -2
  93. package/dist/server/index.js.map +1 -1
  94. package/dist/server/index.mjs +68 -0
  95. package/dist/server/index.mjs.map +1 -1
  96. package/dist/types-BUAlgqqh.d.ts +39 -0
  97. package/dist/{types-DluCaP1I.d.ts → types-Bl61ob-7.d.mts} +19 -2
  98. package/dist/{types-lQVA8d_P.d.mts → types-Bl61ob-7.d.ts} +19 -2
  99. package/dist/types-iVdVY7ba.d.mts +39 -0
  100. package/dist/useSocket-Cn7fB_B1.d.mts +25 -0
  101. package/dist/useSocket-DzMKRKCA.d.ts +25 -0
  102. package/dist/user.fields-CbdObSmS.d.mts +18 -0
  103. package/dist/user.fields-CbdObSmS.d.ts +18 -0
  104. package/dist/utils/index.d.mts +1 -2
  105. package/dist/utils/index.d.ts +1 -2
  106. package/package.json +5 -3
  107. package/src/client/index.ts +13 -0
  108. package/src/components/forms/index.ts +1 -0
  109. package/src/components/index.ts +5 -0
  110. package/src/components/tables/ContentListTable.tsx +1 -0
  111. package/src/contexts/CommonContext.tsx +52 -0
  112. package/src/contexts/SharedContext.tsx +2 -0
  113. package/src/contexts/SocketContext.tsx +65 -0
  114. package/src/contexts/index.ts +6 -1
  115. package/src/features/auth/components/containers/AuthContainer.tsx +32 -0
  116. package/src/features/auth/components/containers/index.ts +1 -0
  117. package/src/features/auth/components/details/LandingComponent.tsx +39 -0
  118. package/src/features/auth/components/details/index.ts +1 -0
  119. package/src/features/auth/components/forms/AcceptInvitation.tsx +136 -0
  120. package/src/features/auth/components/forms/ActivateAccount.tsx +75 -0
  121. package/src/features/auth/components/forms/Cookies.tsx +32 -0
  122. package/src/features/auth/components/forms/ForgotPassword.tsx +108 -0
  123. package/src/features/auth/components/forms/Login.tsx +118 -0
  124. package/src/features/auth/components/forms/Logout.tsx +19 -0
  125. package/src/features/auth/components/forms/RefreshUser.tsx +39 -0
  126. package/src/features/auth/components/forms/Register.tsx +150 -0
  127. package/src/features/auth/components/forms/ResetPassword.tsx +126 -0
  128. package/src/features/auth/components/forms/index.ts +9 -0
  129. package/src/features/auth/components/index.ts +3 -0
  130. package/src/features/auth/contexts/AuthContext.tsx +77 -0
  131. package/src/features/auth/contexts/index.ts +1 -0
  132. package/src/features/auth/enums/AuthComponent.ts +9 -0
  133. package/src/features/auth/enums/index.ts +1 -0
  134. package/src/features/auth/index.ts +2 -1
  135. package/src/features/auth/utils/AuthCookies.ts +134 -0
  136. package/src/features/auth/utils/index.ts +1 -0
  137. package/src/features/company/components/containers/AdminCompanyContainer.tsx +26 -0
  138. package/src/features/company/components/containers/CompanyContainer.tsx +17 -0
  139. package/src/features/company/components/containers/index.ts +2 -0
  140. package/src/features/company/components/details/CompanyDetails.tsx +26 -0
  141. package/src/features/company/components/details/index.ts +1 -0
  142. package/src/features/company/components/forms/CompanyConfigurationEditor.tsx +151 -0
  143. package/src/features/company/components/forms/CompanyConfigurationSecurityForm.tsx +97 -0
  144. package/src/features/company/components/forms/CompanyDeleter.tsx +121 -0
  145. package/src/features/company/components/forms/CompanyEditor.tsx +245 -0
  146. package/src/features/company/components/forms/CompanyLicense.tsx +213 -0
  147. package/src/features/company/components/forms/index.ts +5 -0
  148. package/src/features/company/components/index.ts +4 -0
  149. package/src/features/company/components/lists/CompaniesList.tsx +31 -0
  150. package/src/features/company/components/lists/index.ts +1 -0
  151. package/src/features/company/contexts/CompanyContext.tsx +99 -0
  152. package/src/features/company/contexts/index.ts +0 -0
  153. package/src/features/company/hooks/index.ts +1 -0
  154. package/src/features/company/hooks/useCompanyTableStructure.tsx +82 -0
  155. package/src/features/feature/components/forms/FormFeatures.tsx +141 -140
  156. package/src/features/feature/components/forms/index.ts +1 -0
  157. package/src/features/feature/components/index.ts +1 -1
  158. package/src/features/feature/index.ts +1 -2
  159. package/src/features/module/index.ts +1 -1
  160. package/src/features/notification/components/common/NotificationErrorBoundary.tsx +51 -0
  161. package/src/features/notification/components/common/index.ts +1 -0
  162. package/src/features/notification/components/containers/NotificationsListContainer.tsx +44 -0
  163. package/src/features/notification/components/containers/index.ts +1 -0
  164. package/src/features/notification/components/index.ts +5 -0
  165. package/src/features/notification/components/lists/NotificationsList.tsx +129 -0
  166. package/src/features/notification/components/lists/index.ts +1 -0
  167. package/src/features/notification/components/modals/NotificationModal.tsx +220 -0
  168. package/src/features/notification/components/modals/index.ts +1 -0
  169. package/src/features/notification/components/notifications/Notification.tsx +120 -0
  170. package/src/features/notification/components/notifications/PushNotificationProvider.tsx +9 -0
  171. package/src/features/notification/components/notifications/index.ts +2 -0
  172. package/src/features/notification/contexts/NotificationContext.tsx +187 -0
  173. package/src/features/notification/contexts/index.ts +1 -0
  174. package/src/features/notification/index.ts +1 -1
  175. package/src/features/push/index.ts +1 -1
  176. package/src/features/role/components/containers/RoleContainer.tsx +18 -0
  177. package/src/features/role/components/containers/index.ts +1 -0
  178. package/src/features/role/components/details/RoleDetails.tsx +21 -0
  179. package/src/features/role/components/details/index.ts +1 -0
  180. package/src/features/role/components/forms/FormRoles.tsx +82 -0
  181. package/src/features/role/components/forms/RemoveUserFromRole.tsx +108 -0
  182. package/src/features/role/components/forms/UserRoleAdd.tsx +128 -0
  183. package/src/features/role/components/forms/index.ts +3 -0
  184. package/src/features/role/components/index.ts +4 -0
  185. package/src/features/role/components/lists/RolesList.tsx +27 -0
  186. package/src/features/role/components/lists/UserRolesList.tsx +31 -0
  187. package/src/features/role/components/lists/index.ts +2 -0
  188. package/src/features/role/contexts/RoleContext.tsx +84 -0
  189. package/src/features/role/contexts/index.ts +1 -0
  190. package/src/features/role/hooks/index.ts +1 -0
  191. package/src/features/role/hooks/useRoleTableStructure.tsx +72 -0
  192. package/src/features/s3/index.ts +1 -1
  193. package/src/features/user/components/containers/UserContainer.tsx +23 -0
  194. package/src/features/user/components/containers/UserIndexContainer.tsx +12 -0
  195. package/src/features/user/components/containers/UsersListContainer.tsx +36 -0
  196. package/src/features/user/components/containers/index.ts +3 -0
  197. package/src/features/user/components/details/UserDetails.tsx +74 -0
  198. package/src/features/user/components/details/UserIndexDetails.tsx +28 -0
  199. package/src/features/user/components/details/index.ts +2 -0
  200. package/src/features/user/components/forms/RoleUserAdd.tsx +93 -0
  201. package/src/features/user/components/forms/UserAvatarEditor.tsx +78 -0
  202. package/src/features/user/components/forms/UserDeleter.tsx +49 -0
  203. package/src/features/user/components/forms/UserEditor.tsx +319 -0
  204. package/src/features/user/components/forms/UserMultiSelect.tsx +218 -0
  205. package/src/features/user/components/forms/UserReactivator.tsx +79 -0
  206. package/src/features/user/components/forms/UserResentInvitationEmail.tsx +88 -0
  207. package/src/features/user/components/forms/UserSelector.tsx +185 -0
  208. package/src/features/user/components/forms/index.ts +8 -0
  209. package/src/features/user/components/index.ts +3 -0
  210. package/src/features/user/components/lists/AdminUsersList.tsx +41 -0
  211. package/src/features/user/components/lists/CompanyUsersList.tsx +44 -0
  212. package/src/features/user/components/lists/RelevantUsersList.tsx +30 -0
  213. package/src/features/user/components/lists/RoleUsersList.tsx +31 -0
  214. package/src/features/user/components/lists/UserListInAdd.tsx +53 -0
  215. package/src/features/user/components/lists/UsersList.tsx +30 -0
  216. package/src/features/user/components/lists/UsersListByContentIds.tsx +30 -0
  217. package/src/features/user/components/lists/index.ts +7 -0
  218. package/src/features/user/components/widgets/UserAvatarList.tsx +31 -0
  219. package/src/features/user/components/widgets/UserSearchPopover.tsx +89 -0
  220. package/src/features/user/contexts/UserContext.tsx +106 -0
  221. package/src/features/user/contexts/index.ts +1 -0
  222. package/src/features/user/hooks/index.ts +2 -0
  223. package/src/features/user/hooks/useUserSearch.ts +53 -0
  224. package/src/features/user/hooks/useUserTableStructure.tsx +115 -0
  225. package/src/features/user/index.ts +0 -1
  226. package/src/hooks/index.ts +4 -0
  227. package/src/hooks/useCustomD3Graph.tsx +2 -0
  228. package/src/hooks/useNotificationSync.ts +20 -0
  229. package/src/hooks/usePageTracker.ts +69 -0
  230. package/src/hooks/usePushNotifications.ts +82 -0
  231. package/src/hooks/useSocket.ts +201 -0
  232. package/src/hooks/useTableGenerator.ts +6 -2
  233. package/src/i18n/config.ts +1 -0
  234. package/src/index.ts +4 -0
  235. package/src/interfaces/d3.link.interface.ts +2 -1
  236. package/src/server/ServerSession.ts +103 -0
  237. package/src/server/index.ts +2 -1
  238. package/src/unified/JsonApiRequest.ts +23 -0
  239. package/dist/ApiRequestDataTypeInterface-CUKFDBx2.d.mts +0 -20
  240. package/dist/ApiRequestDataTypeInterface-CUKFDBx2.d.ts +0 -20
  241. package/dist/BlockNoteEditor-VFWG6LXI.js.map +0 -1
  242. package/dist/JsonApiRequest-S3ICLM7B.mjs +0 -20
  243. package/dist/JsonApiRequest-ZZLSP26T.js +0 -20
  244. package/dist/JsonApiRequest-ZZLSP26T.js.map +0 -1
  245. package/dist/chunk-366S2JCC.mjs +0 -31
  246. package/dist/chunk-366S2JCC.mjs.map +0 -1
  247. package/dist/chunk-5W6AKZE6.mjs +0 -131
  248. package/dist/chunk-5W6AKZE6.mjs.map +0 -1
  249. package/dist/chunk-A3J3AAYM.mjs +0 -97
  250. package/dist/chunk-A3J3AAYM.mjs.map +0 -1
  251. package/dist/chunk-AWONBQQP.js +0 -97
  252. package/dist/chunk-AWONBQQP.js.map +0 -1
  253. package/dist/chunk-CXQOWQSY.js.map +0 -1
  254. package/dist/chunk-DKKMWBP4.mjs +0 -1
  255. package/dist/chunk-DKKMWBP4.mjs.map +0 -1
  256. package/dist/chunk-DO2HLAZO.js +0 -48
  257. package/dist/chunk-DO2HLAZO.js.map +0 -1
  258. package/dist/chunk-DZXDB3K2.mjs +0 -17
  259. package/dist/chunk-DZXDB3K2.mjs.map +0 -1
  260. package/dist/chunk-ECDTZBYO.mjs.map +0 -1
  261. package/dist/chunk-FY4SXJGU.js +0 -806
  262. package/dist/chunk-FY4SXJGU.js.map +0 -1
  263. package/dist/chunk-GYWPEPOH.mjs.map +0 -1
  264. package/dist/chunk-H6FMOA6B.js +0 -1
  265. package/dist/chunk-H6FMOA6B.js.map +0 -1
  266. package/dist/chunk-I2REI7OA.js.map +0 -1
  267. package/dist/chunk-J4Q36PMP.js +0 -31
  268. package/dist/chunk-J4Q36PMP.js.map +0 -1
  269. package/dist/chunk-L6EQEAXU.mjs.map +0 -1
  270. package/dist/chunk-MFO27OHB.mjs +0 -48
  271. package/dist/chunk-MFO27OHB.mjs.map +0 -1
  272. package/dist/chunk-RAF7PNLG.js +0 -131
  273. package/dist/chunk-RAF7PNLG.js.map +0 -1
  274. package/dist/chunk-RUR22SVM.js +0 -17
  275. package/dist/chunk-RUR22SVM.js.map +0 -1
  276. package/dist/chunk-TEGF6ZWG.js.map +0 -1
  277. package/dist/chunk-TMVHSY3Y.js.map +0 -1
  278. package/dist/chunk-V2JJPI7N.js.map +0 -1
  279. package/dist/chunk-WWWMJZEF.mjs +0 -806
  280. package/dist/chunk-WWWMJZEF.mjs.map +0 -1
  281. package/dist/chunk-X4BIHJ2B.mjs.map +0 -1
  282. package/dist/chunk-YDVTFM7X.mjs.map +0 -1
  283. /package/dist/{JsonApiRequest-S3ICLM7B.mjs.map → JsonApiRequest-O7BGUMFO.mjs.map} +0 -0
@@ -0,0 +1,97 @@
1
+ "use client";
2
+
3
+ import { useTranslations } from "next-intl";
4
+ import { UseFormReturn } from "react-hook-form";
5
+ import { Checkbox, FormControl, FormField, FormItem, FormLabel, FormMessage, Input } from "../../../../shadcnui";
6
+
7
+ type SecurityConfigurationFormProps = {
8
+ form: UseFormReturn<any>;
9
+ };
10
+
11
+ type Fields = {
12
+ fields: string[];
13
+ defaults: Record<string, any>;
14
+ };
15
+
16
+ const providerConfig: Fields = {
17
+ fields: ["isManagedKnowledge", "allowPublicBot"],
18
+ defaults: {},
19
+ };
20
+
21
+ export function CompanyConfigurationSecurityForm({ form }: SecurityConfigurationFormProps) {
22
+ const t = useTranslations();
23
+
24
+ const renderProviderFields = () => {
25
+ const config = providerConfig;
26
+ if (!config) return null;
27
+
28
+ return config.fields.map((currentField) => {
29
+ const isRequired = currentField === "";
30
+
31
+ let label = "";
32
+ let placeholder = "";
33
+ let type = "text";
34
+
35
+ switch (currentField) {
36
+ case "isManagedKnowledge":
37
+ label = "Limit Require structured knowledge management";
38
+ placeholder =
39
+ "Enforce single-nesting expertises, require expertise associations to content, and enable knowledge manager roles for better long-term organization.";
40
+ type = "checkbox";
41
+ break;
42
+ case "allowPublicBot":
43
+ label = "Allow Public Bot";
44
+ placeholder = "Enable this to allow the public to access public information.";
45
+ type = "checkbox";
46
+ break;
47
+ }
48
+
49
+ return (
50
+ <FormField
51
+ key={currentField}
52
+ control={form.control}
53
+ name={currentField}
54
+ render={({ field: formField }) =>
55
+ type === "checkbox" ? (
56
+ <FormItem className="flex items-start space-x-4">
57
+ <FormControl>
58
+ <Checkbox
59
+ id={currentField}
60
+ checked={formField.value}
61
+ onCheckedChange={(checked) => {
62
+ return checked ? formField.onChange(true) : formField.onChange(false);
63
+ }}
64
+ />
65
+ </FormControl>
66
+ <div className="grid gap-2">
67
+ <FormLabel htmlFor={currentField}>
68
+ {label} {isRequired && <span className="text-destructive">*</span>}
69
+ </FormLabel>
70
+ <p className="text-muted-foreground text-sm">{placeholder}</p>
71
+ </div>
72
+ <FormLabel></FormLabel>
73
+ <FormMessage />
74
+ </FormItem>
75
+ ) : (
76
+ <FormItem>
77
+ <FormLabel>
78
+ {label} {isRequired && <span className="text-destructive">*</span>}
79
+ </FormLabel>
80
+ <FormControl>
81
+ <Input type={type} placeholder={placeholder} {...formField} />
82
+ </FormControl>
83
+ <FormMessage />
84
+ </FormItem>
85
+ )
86
+ }
87
+ />
88
+ );
89
+ });
90
+ };
91
+
92
+ return (
93
+ <div className="space-y-4">
94
+ <div className="space-y-4 border-t pt-4">{renderProviderFields()}</div>
95
+ </div>
96
+ );
97
+ }
@@ -0,0 +1,121 @@
1
+ "use client";
2
+
3
+ import { LoaderCircleIcon, Trash2Icon } from "lucide-react";
4
+ import { useTranslations } from "next-intl";
5
+ import { useState } from "react";
6
+ import { errorToast } from "../../../../components";
7
+ import { Modules } from "../../../../core";
8
+ import { useI18nRouter } from "../../../../i18n";
9
+ import { Action } from "../../../../permissions";
10
+ import { getRoleId } from "../../../../roles";
11
+ import {
12
+ AlertDialog,
13
+ AlertDialogContent,
14
+ AlertDialogDescription,
15
+ AlertDialogHeader,
16
+ AlertDialogTitle,
17
+ AlertDialogTrigger,
18
+ Button,
19
+ Input,
20
+ Label,
21
+ } from "../../../../shadcnui";
22
+ import { UserInterface } from "../../../user";
23
+ import { useCurrentUserContext } from "../../../user/contexts";
24
+ import { CompanyInterface, CompanyService } from "../../data";
25
+
26
+ type CompanyDeleterProps = {
27
+ company: CompanyInterface;
28
+ };
29
+
30
+ function CompanyDeleterInternal({ company }: CompanyDeleterProps) {
31
+ const t = useTranslations();
32
+ const router = useI18nRouter();
33
+ const [open, setOpen] = useState<boolean>(false);
34
+ const [isDeleting, setIsDeleting] = useState<boolean>(false);
35
+ const [companyName, setCompanyName] = useState<string>("");
36
+
37
+ const handleDelete = async () => {
38
+ setIsDeleting(true);
39
+ try {
40
+ await CompanyService.delete({ companyId: company.id });
41
+ router.push("/");
42
+ } catch (error) {
43
+ errorToast({ title: t(`generic.errors.delete`), error: error });
44
+ }
45
+ setIsDeleting(false);
46
+ };
47
+
48
+ return (
49
+ <AlertDialog open={open} onOpenChange={setOpen}>
50
+ <AlertDialogTrigger asChild>
51
+ <Button size="sm" variant={"destructive"}>
52
+ <Trash2Icon className="mr-3 h-3.5 w-3.5" />
53
+ {t(`generic.buttons.delete`)}
54
+ </Button>
55
+ </AlertDialogTrigger>
56
+ <AlertDialogContent className={`flex max-h-[70vh] max-w-3xl flex-col overflow-y-auto`}>
57
+ <AlertDialogHeader>
58
+ <AlertDialogTitle>{t(`generic.delete.title`, { type: t(`types.companies`, { count: 1 }) })}</AlertDialogTitle>
59
+ <AlertDialogDescription>
60
+ {t(`generic.delete.subtitle`, { type: t(`types.companies`, { count: 1 }) })}
61
+ </AlertDialogDescription>
62
+ </AlertDialogHeader>
63
+ <div className="text-destructive p-4 text-sm">
64
+ {t(`generic.delete.description`, { type: t(`types.companies`, { count: 1 }) })}
65
+ </div>
66
+ <div className="flex w-full flex-col gap-y-2">
67
+ <div>{t(`generic.delete.confirmation`, { type: t(`types.companies`, { count: 1 }) })}</div>
68
+ <div className="flex w-full flex-col">
69
+ <Label className="flex items-center">
70
+ {t(`foundations.company.fields.name.label`)}
71
+ <span className="text-destructive ml-2 font-semibold">*</span>
72
+ </Label>
73
+ <Input
74
+ className={`w-full`}
75
+ placeholder={t(`foundations.company.fields.name.placeholder`)}
76
+ onChange={(e) => setCompanyName(e.target.value)}
77
+ />
78
+ </div>
79
+ </div>
80
+ <div className="flex justify-end">
81
+ <Button
82
+ className="mr-2"
83
+ variant={"outline"}
84
+ type={`button`}
85
+ onClick={() => setOpen(false)}
86
+ disabled={isDeleting}
87
+ >
88
+ {t(`generic.buttons.cancel`)}
89
+ </Button>
90
+ <Button
91
+ type="submit"
92
+ onClick={(e) => {
93
+ e.preventDefault();
94
+ handleDelete();
95
+ }}
96
+ variant={"destructive"}
97
+ disabled={company.name !== companyName || isDeleting}
98
+ >
99
+ {isDeleting ? (
100
+ <>
101
+ {t(`generic.buttons.is_deleting`)}
102
+ <LoaderCircleIcon className="animate-spin-slow h-5 w-5" />
103
+ </>
104
+ ) : (
105
+ t(`generic.buttons.delete`)
106
+ )}
107
+ </Button>
108
+ </div>
109
+ </AlertDialogContent>
110
+ </AlertDialog>
111
+ );
112
+ }
113
+
114
+ export function CompanyDeleter({ company }: CompanyDeleterProps) {
115
+ const { hasPermissionToModule, hasRole } = useCurrentUserContext<UserInterface>();
116
+
117
+ if (!hasRole(getRoleId().Administrator) && !hasPermissionToModule({ module: Modules.Company, action: Action.Delete }))
118
+ return null;
119
+
120
+ return <CompanyDeleterInternal company={company} />;
121
+ }
@@ -0,0 +1,245 @@
1
+ "use client";
2
+
3
+ import { zodResolver } from "@hookform/resolvers/zod";
4
+ import { setCookie } from "cookies-next";
5
+ import { UploadIcon } from "lucide-react";
6
+ import { useTranslations } from "next-intl";
7
+ import Image from "next/image";
8
+ import { useEffect, useState } from "react";
9
+ import { DropzoneOptions } from "react-dropzone";
10
+ import { SubmitHandler, useForm } from "react-hook-form";
11
+ import { v4 } from "uuid";
12
+ import { z } from "zod";
13
+ import {
14
+ CommonEditorButtons,
15
+ CommonEditorHeader,
16
+ CommonEditorTrigger,
17
+ errorToast,
18
+ FileInput,
19
+ FileUploader,
20
+ FormFeatures,
21
+ FormInput,
22
+ } from "../../../../components";
23
+ import { Modules } from "../../../../core";
24
+ import { usePageUrlGenerator } from "../../../../hooks";
25
+ import { useI18nRouter } from "../../../../i18n";
26
+ import { getRoleId } from "../../../../roles";
27
+ import { Dialog, DialogContent, Form, ScrollArea } from "../../../../shadcnui";
28
+ import { FeatureInterface, FeatureService } from "../../../feature";
29
+ import { S3Interface, S3Service } from "../../../s3";
30
+ import { UserInterface } from "../../../user";
31
+ import { useCurrentUserContext } from "../../../user/contexts";
32
+ import { CompanyInput, CompanyInterface, CompanyService } from "../../data";
33
+
34
+ type CompanyEditorProps = {
35
+ company?: CompanyInterface;
36
+ propagateChanges?: (company: CompanyInterface) => void;
37
+ onRevalidate?: (path: string) => Promise<void>;
38
+ };
39
+
40
+ function CompanyEditorInternal({ company, propagateChanges, onRevalidate }: CompanyEditorProps) {
41
+ const { hasRole } = useCurrentUserContext<UserInterface>();
42
+ const router = useI18nRouter();
43
+ const [open, setOpen] = useState<boolean>(false);
44
+ const [features, setFeatures] = useState<FeatureInterface[]>([]);
45
+ const [file, setFile] = useState<File | null>(null);
46
+ const [files, setFiles] = useState<File[] | null>(null);
47
+ const [contentType, setContentType] = useState<string | null>(null);
48
+ const t = useTranslations();
49
+ const generateUrl = usePageUrlGenerator();
50
+
51
+ const formSchema = z.object({
52
+ id: z.uuidv4(),
53
+ name: z.string().min(1, {
54
+ message: t(`foundations.company.fields.name.error`),
55
+ }),
56
+ featureIds: z.array(z.string()).optional(),
57
+ moduleIds: z.array(z.string()).optional(),
58
+ logo: z.string().optional(),
59
+ });
60
+
61
+ const form = useForm({
62
+ resolver: zodResolver(formSchema),
63
+ defaultValues: {
64
+ id: company?.id || v4(),
65
+ name: company?.name || "",
66
+ featureIds: company?.features.map((feature) => feature.id) || [],
67
+ moduleIds: company?.modules.map((module) => module.id) || [],
68
+ logo: company?.logo || "",
69
+ },
70
+ });
71
+
72
+ const onSubmit: SubmitHandler<z.infer<typeof formSchema>> = async (values: z.infer<typeof formSchema>) => {
73
+ if (values.logo && contentType) {
74
+ const s3: S3Interface = await S3Service.getPreSignedUrl({
75
+ key: values.logo,
76
+ contentType: contentType,
77
+ isPublic: true,
78
+ });
79
+
80
+ await fetch(s3.url, {
81
+ method: "PUT",
82
+ headers: s3.headers,
83
+ body: file,
84
+ });
85
+ }
86
+
87
+ const payload: CompanyInput = {
88
+ id: company?.id ?? v4(),
89
+ name: values.name,
90
+ logo: files && contentType ? values.logo : undefined,
91
+ featureIds: values.featureIds,
92
+ moduleIds: values.moduleIds,
93
+ };
94
+
95
+ try {
96
+ const updatedCompany = company ? await CompanyService.update(payload) : await CompanyService.create(payload);
97
+
98
+ if (onRevalidate) {
99
+ await onRevalidate(generateUrl({ page: Modules.Company, id: updatedCompany.id, language: `[locale]` }));
100
+ }
101
+ if (company && propagateChanges) {
102
+ setCookie("reloadData", "true", { path: "/" });
103
+ propagateChanges(updatedCompany);
104
+ setOpen(false);
105
+ } else {
106
+ router.push(`/administration/companies/${updatedCompany.id}`);
107
+ }
108
+ } catch (error) {
109
+ errorToast({
110
+ title: company ? t(`generic.errors.update`) : t(`generic.errors.create`),
111
+ error,
112
+ });
113
+ }
114
+ };
115
+
116
+ useEffect(() => {
117
+ async function fetchFeatures() {
118
+ const allfeatures = await FeatureService.findMany({});
119
+ if (hasRole(getRoleId().Administrator)) {
120
+ setFeatures(allfeatures);
121
+ } else {
122
+ setFeatures(allfeatures.filter((feature) => feature.isProduction));
123
+ }
124
+ }
125
+ if (
126
+ open &&
127
+ features.length === 0 &&
128
+ (hasRole(getRoleId().Administrator) ||
129
+ (hasRole(getRoleId().CompanyAdministrator) &&
130
+ process.env.NEXT_PUBLIC_PRIVATE_INSTALLATION?.toLowerCase() === "true"))
131
+ )
132
+ fetchFeatures();
133
+ }, [open, features]);
134
+
135
+ useEffect(() => {
136
+ if (file && company) {
137
+ const id = form.getValues("id");
138
+ const fileType = file.type;
139
+ let extension = "";
140
+
141
+ switch (fileType) {
142
+ default:
143
+ extension = file.type.split("/").pop() ?? "";
144
+ break;
145
+ }
146
+
147
+ const timestamp = new Date().toISOString().replace(/[-:T]/g, "").split(".")[0];
148
+
149
+ const fileUrl = `companies/${form.getValues("id")}/companies/${id}/${id}.${timestamp}.${extension}`;
150
+ form.setValue("logo", fileUrl);
151
+
152
+ setContentType(fileType);
153
+ } else {
154
+ setContentType(null);
155
+ }
156
+ }, [file]);
157
+
158
+ useEffect(() => {
159
+ if (files && files.length > 0) {
160
+ setFile(files[0]);
161
+ }
162
+ }, [files]);
163
+
164
+ const dropzone = {
165
+ multiple: false,
166
+ maxSize: 100 * 1024 * 1024,
167
+ preventDropOnDocument: false,
168
+ accept: {
169
+ "application/images": [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"],
170
+ },
171
+ } satisfies DropzoneOptions;
172
+
173
+ const canAccessFeatures =
174
+ hasRole(getRoleId().Administrator) ||
175
+ (hasRole(getRoleId().CompanyAdministrator) &&
176
+ process.env.NEXT_PUBLIC_PRIVATE_INSTALLATION?.toLowerCase() === "true");
177
+
178
+ const isAdministrator = hasRole(getRoleId().Administrator);
179
+
180
+ return (
181
+ <Dialog open={open} onOpenChange={setOpen}>
182
+ <CommonEditorTrigger isEdit={!!company} />
183
+ <DialogContent
184
+ className={`flex max-h-[70vh] w-full ${isAdministrator || canAccessFeatures ? `max-w-5xl` : `max-w-4xl`} flex-col overflow-y-auto`}
185
+ >
186
+ <CommonEditorHeader type={t(`types.companies`, { count: 1 })} name={company?.name} />
187
+ <Form {...form}>
188
+ <form onSubmit={form.handleSubmit(onSubmit)} className={`flex w-full flex-col gap-y-4`}>
189
+ <div className="flex w-full items-start justify-between gap-x-4">
190
+ <div className={`flex w-96 flex-col justify-start gap-y-4`}>
191
+ <FileUploader value={files} onValueChange={setFiles} dropzoneOptions={dropzone} className="w-full p-4">
192
+ <FileInput className="text-neutral-300 outline-dashed">
193
+ <div className="flex w-full flex-col items-center justify-center pt-3 pb-4">
194
+ <div className="flex w-full flex-col items-center justify-center pt-3 pb-4">
195
+ {file || company?.logo ? (
196
+ <Image
197
+ src={file ? URL.createObjectURL(file) : company?.logo || ""}
198
+ alt="Company Logo"
199
+ width={200}
200
+ height={200}
201
+ />
202
+ ) : (
203
+ <>
204
+ <UploadIcon className="my-4 h-8 w-8" />
205
+ <p className="mb-1 flex w-full text-center text-sm">
206
+ {t(`foundations.company.click_drag_logo`)}
207
+ </p>
208
+ </>
209
+ )}
210
+ </div>
211
+ </div>
212
+ </FileInput>
213
+ </FileUploader>
214
+ </div>
215
+ <div className={`flex w-full flex-col justify-start gap-y-4`}>
216
+ <FormInput
217
+ form={form}
218
+ id="name"
219
+ name={t(`foundations.company.fields.name.label`)}
220
+ placeholder={t(`foundations.company.fields.name.placeholder`)}
221
+ />
222
+ </div>
223
+ {canAccessFeatures && (
224
+ <div className={`flex w-96 flex-col justify-start gap-y-4`}>
225
+ <ScrollArea className="h-max">
226
+ <FormFeatures
227
+ form={form}
228
+ name={t(`foundations.company.features_and_modules`)}
229
+ features={features}
230
+ />
231
+ </ScrollArea>
232
+ </div>
233
+ )}
234
+ </div>
235
+ <CommonEditorButtons form={form} setOpen={setOpen} isEdit={!!company} />
236
+ </form>
237
+ </Form>
238
+ </DialogContent>
239
+ </Dialog>
240
+ );
241
+ }
242
+
243
+ export function CompanyEditor(props: CompanyEditorProps) {
244
+ return <CompanyEditorInternal {...props} />;
245
+ }
@@ -0,0 +1,213 @@
1
+ "use client";
2
+
3
+ import { zodResolver } from "@hookform/resolvers/zod";
4
+ import { deleteCookie } from "cookies-next";
5
+ import { ClipboardIcon } from "lucide-react";
6
+ import { useTranslations } from "next-intl";
7
+ import Image from "next/image";
8
+ import { SubmitHandler, useForm } from "react-hook-form";
9
+ import { toast } from "sonner";
10
+ import z from "zod";
11
+ import { errorToast, FormInput, FormTextarea } from "../../../../components";
12
+ import { Modules } from "../../../../core";
13
+ import { useI18nRouter, usePageUrlGenerator } from "../../../../hooks";
14
+ import { getRoleId } from "../../../../roles";
15
+ import {
16
+ Button,
17
+ Card,
18
+ CardContent,
19
+ CardDescription,
20
+ CardFooter,
21
+ CardHeader,
22
+ CardTitle,
23
+ Form,
24
+ Input,
25
+ Label,
26
+ Link,
27
+ } from "../../../../shadcnui";
28
+ import { UserInterface, UserService } from "../../../user";
29
+ import { useCurrentUserContext } from "../../../user/contexts";
30
+ import { CompanyInput, CompanyService } from "../../data";
31
+
32
+ type TokenPayload = {
33
+ userId: string;
34
+ companyId?: string;
35
+ licenseExpirationDate?: Date;
36
+ roles: string[];
37
+ features: string[];
38
+ modules: {
39
+ id: string;
40
+ permissions: {
41
+ create: boolean | string;
42
+ read: boolean | string;
43
+ update: boolean | string;
44
+ delete: boolean | string;
45
+ };
46
+ }[];
47
+ };
48
+
49
+ type CompanyLicenseProps = {
50
+ onRevalidate?: (path: string) => Promise<void>;
51
+ onUpdateToken?: (token: TokenPayload) => Promise<void>;
52
+ };
53
+
54
+ export default function CompanyLicense({ onRevalidate, onUpdateToken }: CompanyLicenseProps = {}) {
55
+ const { currentUser, setUser, hasRole } = useCurrentUserContext<UserInterface>();
56
+
57
+ const t = useTranslations();
58
+ const generateUrl = usePageUrlGenerator();
59
+ const router = useI18nRouter();
60
+
61
+ const copyToClipboard = (text: string) => {
62
+ navigator.clipboard.writeText(text);
63
+ toast("Copied to clipboard");
64
+ };
65
+
66
+ const formSchema = z.object({
67
+ license: z.string().min(1, {
68
+ message: `License is required`,
69
+ }),
70
+ privateKey: z.string().min(1, {
71
+ message: `Private key is required`,
72
+ }),
73
+ });
74
+
75
+ const defaultValues = {
76
+ license:
77
+ "09001678dca2f4a6d2d32bb984811278:3e93a432f6130579e543a511346c0d2c6ca7a97d49c7ff2d3e789ca7c7c8d79b864fd3406c8315e72aa5febf6232776dfaea51d72168ddcdd34a59ea1a05b3b3dd60ac3af6c3934203d19ea68642293aa5b79f012633b4ba2e4a474e9ceed6b6cda13d8dedc8e60ece61886843ee6edc1af6d2da5e07945033295507df6f87994f8347b5759b446aa20b1185d7b5c54c67509ae280e729913d0e68e95b5f090b0577a8a735f24fb7c1df8f6586886d840af4a43f9dc74d5d1f291058a45ace759176fa19fe5e164f5d8307981e8bcd166f346e97b676dd0242d1c30ec4fe744f22621fae603b1caaac25f198d2b29be0e0f2afc81a40edeb20242345e2feac8666027d0c30aa8dadbca742dd68ade46602545979f473b344021d27921553d5b284fd96a717b74573ca7e693723876357013e3c0d07a35d270a0e32654d2c244220e2492380279aa34a4744d145b89d06a8abef49cc2ef0dd0171e0eefcf16724decf53e545d10d9bfd8e0c4b03ca720b0fc63d8a20ca2c71d74cb0cf7e547637dbcc8d27257414b5b0b40eabe9eb53a4b5f61ca2250d5933a13565f785a89fc5e3e3c468acbeddf14627aa4109f32af641fc96513e52edc21849e81331cafc900ea85f58927d583aafe5a959af69ce5c967d0cd5d9050cf6601a615e8e3ccf32e6a04227f1f228d94f9bd24073c7b0ec2550f4efc69bddde745144dcb279864fb3e7e7d57d1e96d0701b55f0d6f3bd688880e4a78adb0974cba278cd34bc02753e8a736a4b3a4e48afdf206b9330fee4e29a3c28dec8457e0f44adc10735c1d1992b798e0dd710053ce98ff38b6ff59004079a5face769950401b49fdc13e4cd3324d7df2cf0f40593f51c117debbafd",
78
+ privateKey:
79
+ "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCKDXrjEXBcYx6p\nChtixITGiFqZeaurD3n2SeJl8QuniKlbl7ytC71gS9BzIG5Q/ENhAE41qa7FaHdN\nHLQ2anfAjS/wd/41wx9ilvQeN/IcDb5Dx3Qd07OMLdrgDvkhlUPSvt7Y5/yft1IX\nS8NaDrKoO4zjpVB9SeLYGyFXmfP0ciJ97AkWDfXp3l2WjwwxEQByo5uXOMzpEZla\nkqBFy7kkO3c/SJWqnuXbXrUVr7AjZ9zMCPP/NbvvOkGzovrOYHN5WO9Rg7m+wIFK\n+gTL2e3RnyjUUSoX5/NMZO9oyDNEaaWgIv6LOG72A2Xq55gpNQihjltZWd/o+xFb\nIRZzbmllAgMBAAECggEABrrvgcBo5OgkJ4OJoEAKZQ9is1a+KsG/ZWVmtyeQNOOx\ntfhox1rqKZaom+Q53JLfygvUxEL4dUFJh6Xdl0WLfwSjEKsY5pATqJ/JWOvLTtjQ\nrMc9fvLCLxRRNlkkhiGbw9twS8zLgRHT27Ti2jIbPZ5hmPuHOARxHa386yNjREh1\n14Vlhk+dvhmqtYt11AKWuU8nHuf92wCCetATUg/pfNQ1itf6XDlygUZTl4GkoJg/\nVrt1MnsrTKcGzP+gvpNH0aOuUbgtUWtBIKaSuGgY6lMMny6AApeJ+kXZR8cyPVSi\nYm/185AcxQDlPunoyl3QzvV41zJUccoMI576wFTUQQKBgQC8QQtNXjfcQvYDeVv8\ntWKAxgk+OE6/3ntLkbYxPw2H5IOikhb5OjNirzUzRs4CKjnGhx0zDzCi4TV2xwZf\nwDHpd9VEhEXmKBJe43RCQs0vb1jwz4ttRk9eoz1Oa4cNij3yH5F4oNu5ZnOSZWi/\n1c4mIsGjjTWzeOkJ6J+fCc6ztQKBgQC7u53nuvMubVhNW3FyuHaXuE+nUlNaw2gc\n9mhm17DY+MBf2YqdJOCY1B44WMIZe3k/75qXrZEYG4ikdlAGzrh7q3/8GMKCxk8P\n5y+YeKODdURM1SsUoOqAzga7s2vFxnChtWxk3KfXCzjKUoX/9zWX/zfIAl9VsVVC\nhrARyffM8QKBgC6pIJgIpmfd4QRzbC1y9/tbGqdlZX+BMaZFc5c5Pa1VIpuFAlS7\n7EiljNYs0psOxEtE6iPhu/hjQdEy+414IebwYNgewQSPIh6K2iIiVKFRRAZMKw7m\nwn1+kI+Db3IXtcrxsCjqFgwaLMM4h4IlCHfDXaOgOJNHgNuH4SiWUbmRAoGAUGD4\nLuugi1RN5nEslc3dGQDVOfLJtabMwPnPoZjgI0X+OAvQiY/sigLoHYADOx3ewD06\nl468/PFtA92UThXcbzbyyWFghtWZrFlzy3h7qiFfaPYsR9zOCvAredpMXpWkS9h9\n3IGNa0lmu1mx/fI+hCHGJGC/qNUQiDda04MCEkECgYAxDhQW7sRox+7Pn0TsRotN\nTv6AJggyTjBaF45fVy+28sn53f/9HE++Rxn8W5xQl+hEOywT95OcWB9b4CiZsp1P\nZyjkByeUuraVM1DoFh66UdXUvC2FECdyz4N3JyKHvV82GdrTPsQLVPCsGfzkj7V8\nX+iuQoeEbUvwnnrg3pbClQ==\n-----END PRIVATE KEY-----\n",
80
+ };
81
+
82
+ const form = useForm<z.infer<typeof formSchema>>({
83
+ resolver: zodResolver(formSchema),
84
+ defaultValues: defaultValues,
85
+ });
86
+
87
+ const onSubmit: SubmitHandler<z.infer<typeof formSchema>> = async (values: z.infer<typeof formSchema>) => {
88
+ if (!currentUser || !currentUser.company) {
89
+ errorToast({
90
+ title: t("generic.errors.error"),
91
+ error: new Error("User or company not found"),
92
+ });
93
+ return;
94
+ }
95
+
96
+ const payload: CompanyInput = {
97
+ id: currentUser.company.id,
98
+ license: values.license,
99
+ privateKey: values.privateKey,
100
+ };
101
+
102
+ try {
103
+ const updatedLicense = await CompanyService.activateLicense(payload);
104
+
105
+ const fullUser = await UserService.findFullUser();
106
+
107
+ if (fullUser) {
108
+ setUser(fullUser);
109
+ const token = {
110
+ userId: fullUser.id,
111
+ companyId: fullUser.company?.id,
112
+ licenseExpirationDate: fullUser.company?.licenseExpirationDate,
113
+ roles: fullUser.roles.map((role) => role.id),
114
+ features: fullUser.company?.features?.map((feature) => feature.id) ?? [],
115
+ modules: fullUser.modules.map((module) => {
116
+ return { id: module.id, permissions: module.permissions };
117
+ }),
118
+ };
119
+
120
+ if (onUpdateToken) {
121
+ await onUpdateToken(token);
122
+ }
123
+ deleteCookie("reloadData");
124
+ }
125
+
126
+ if (onRevalidate) {
127
+ await onRevalidate(generateUrl({ page: Modules.Company, id: updatedLicense.id, language: `[locale]` }));
128
+ }
129
+ router.push(generateUrl({ page: "/" }));
130
+ } catch (error) {
131
+ errorToast({
132
+ title: t(`generic.errors.update`),
133
+ error,
134
+ });
135
+ }
136
+ };
137
+
138
+ if (!currentUser || !currentUser.company) return null;
139
+
140
+ return (
141
+ <Form {...form}>
142
+ <form
143
+ onSubmit={form.handleSubmit(onSubmit)}
144
+ className="relative flex min-h-screen w-full flex-col items-center justify-center"
145
+ >
146
+ <div className="absolute top-4 left-4 z-0">
147
+ <Image
148
+ src={`/phlow-logo.webp`}
149
+ className="object-contain p-4"
150
+ height={300}
151
+ width={300}
152
+ alt={"Phlow"}
153
+ priority
154
+ />
155
+ </div>
156
+ <Card className="z-10 w-3xl">
157
+ {hasRole(getRoleId().CompanyAdministrator) ? (
158
+ <>
159
+ <CardHeader>
160
+ <CardTitle>Company License Required</CardTitle>
161
+ <CardDescription className={`flex w-full flex-col`}>
162
+ <div>You need to activate your license to use Phlow.</div>
163
+ <div>
164
+ <span>To obtain your license, please visit</span>
165
+ <Link href="https://phlow.com" target="_blank" className={`text-primary`}>
166
+ our website (https://phlow.com)
167
+ </Link>
168
+ <span>, register for an account and follow the instructions provided.</span>
169
+ </div>
170
+ <div>You will be required to provide the installation identifier provided below.</div>
171
+ <div>
172
+ Once you have activated your license, please paste your license and private key in the fields below.
173
+ </div>
174
+ </CardDescription>
175
+ </CardHeader>
176
+ <CardContent className="flex flex-col gap-y-4">
177
+ <div>
178
+ <Label>Installation Identifier</Label>
179
+ <div className="flex items-center">
180
+ <Input disabled value={currentUser.company.id} />
181
+ <ClipboardIcon
182
+ className="text-muted-foreground ml-2 cursor-pointer"
183
+ onClick={() => copyToClipboard(currentUser!.company!.id)}
184
+ />
185
+ </div>
186
+ </div>
187
+ <div>
188
+ <FormInput form={form} id="license" name={"license"} placeholder="Enter your license" />
189
+ </div>
190
+ <div>
191
+ <FormTextarea name="Private Key" form={form} id="privateKey" placeholder="Enter your private key" />
192
+ </div>
193
+ </CardContent>
194
+ <CardFooter className="flex justify-end">
195
+ <Button type="submit">Activate License</Button>
196
+ </CardFooter>
197
+ </>
198
+ ) : (
199
+ <>
200
+ <CardHeader>
201
+ <CardTitle>Company License Required</CardTitle>
202
+ <CardDescription className={`flex w-full flex-col`}>
203
+ The company license is either missing or expired.
204
+ </CardDescription>
205
+ </CardHeader>
206
+ <CardContent>Please contact your system administrator to resolve this issue.</CardContent>
207
+ </>
208
+ )}
209
+ </Card>
210
+ </form>
211
+ </Form>
212
+ );
213
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./CompanyConfigurationEditor";
2
+ export * from "./CompanyConfigurationSecurityForm";
3
+ export * from "./CompanyDeleter";
4
+ export * from "./CompanyEditor";
5
+ export * from "./CompanyLicense";
@@ -0,0 +1,4 @@
1
+ export * from "./containers";
2
+ export * from "./details";
3
+ export * from "./forms";
4
+ export * from "./lists";