@carlonicora/nextjs-jsonapi 1.0.4 → 1.0.5

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 (282) hide show
  1. package/dist/{AbstractService-BKlpJA61.d.mts → AbstractService-B2n_JdiC.d.mts} +1 -1
  2. package/dist/{AbstractService-D9eSVKNa.d.ts → AbstractService-DtQTYovo.d.ts} +1 -1
  3. package/dist/{content.interface-Dg2lt_An.d.mts → AuthComponent-CPLvEerw.d.mts} +11 -15
  4. package/dist/{content.interface-BhyAiOFq.d.ts → AuthComponent-m6Qp4Hz6.d.ts} +11 -15
  5. package/dist/{BlockNoteEditor-UVO3VZZE.mjs → BlockNoteEditor-BLVXQPXV.mjs} +14 -18
  6. package/dist/{BlockNoteEditor-UVO3VZZE.mjs.map → BlockNoteEditor-BLVXQPXV.mjs.map} +1 -1
  7. package/dist/{BlockNoteEditor-VFWG6LXI.js → BlockNoteEditor-ZTDHULFT.js} +15 -19
  8. package/dist/BlockNoteEditor-ZTDHULFT.js.map +1 -0
  9. package/dist/JsonApiRequest-O7BGUMFO.mjs +23 -0
  10. package/dist/JsonApiRequest-VARLNKAF.js +23 -0
  11. package/dist/JsonApiRequest-VARLNKAF.js.map +1 -0
  12. package/dist/chunk-2LM6LCJW.mjs +1 -0
  13. package/dist/chunk-3APORDYP.mjs +7783 -0
  14. package/dist/chunk-3APORDYP.mjs.map +1 -0
  15. package/dist/{chunk-TMVHSY3Y.js → chunk-5ZEADNNP.js} +36 -17
  16. package/dist/chunk-5ZEADNNP.js.map +1 -0
  17. package/dist/{chunk-ECDTZBYO.mjs → chunk-74F6BBHH.mjs} +21 -2
  18. package/dist/chunk-74F6BBHH.mjs.map +1 -0
  19. package/dist/{chunk-GYWPEPOH.mjs → chunk-7C5RAEBO.mjs} +72 -68
  20. package/dist/chunk-7C5RAEBO.mjs.map +1 -0
  21. package/dist/chunk-A5DDIABK.js +1 -0
  22. package/dist/{chunk-TEGF6ZWG.js → chunk-AGAJMJ4T.js} +47 -9
  23. package/dist/chunk-AGAJMJ4T.js.map +1 -0
  24. package/dist/{chunk-CXQOWQSY.js → chunk-AYHKQWHH.js} +15 -2
  25. package/dist/chunk-AYHKQWHH.js.map +1 -0
  26. package/dist/{chunk-I2REI7OA.js → chunk-HMHGLXWC.js} +33 -15
  27. package/dist/chunk-HMHGLXWC.js.map +1 -0
  28. package/dist/chunk-IWFGEPAA.mjs +1 -0
  29. package/dist/chunk-JC3WJK65.js +1 -0
  30. package/dist/{chunk-L6EQEAXU.mjs → chunk-PYF2U6WG.mjs} +25 -7
  31. package/dist/chunk-PYF2U6WG.mjs.map +1 -0
  32. package/dist/{chunk-YDVTFM7X.mjs → chunk-RBIVEH2K.mjs} +42 -4
  33. package/dist/chunk-RBIVEH2K.mjs.map +1 -0
  34. package/dist/{chunk-V2JJPI7N.js → chunk-RZO2LOW4.js} +237 -233
  35. package/dist/chunk-RZO2LOW4.js.map +1 -0
  36. package/dist/{chunk-X4BIHJ2B.mjs → chunk-SM63SZCP.mjs} +15 -2
  37. package/dist/chunk-SM63SZCP.mjs.map +1 -0
  38. package/dist/chunk-WEC4YMOS.js +7783 -0
  39. package/dist/chunk-WEC4YMOS.js.map +1 -0
  40. package/dist/client/index.d.mts +21 -2
  41. package/dist/client/index.d.ts +21 -2
  42. package/dist/client/index.js +18 -245
  43. package/dist/client/index.js.map +1 -1
  44. package/dist/client/index.mjs +28 -255
  45. package/dist/client/index.mjs.map +1 -1
  46. package/dist/components/index.d.mts +293 -8
  47. package/dist/components/index.d.ts +293 -8
  48. package/dist/components/index.js +78 -2323
  49. package/dist/components/index.js.map +1 -1
  50. package/dist/components/index.mjs +172 -2417
  51. package/dist/components/index.mjs.map +1 -1
  52. package/dist/{config-hXufftVS.d.ts → config-BmnK65TD.d.mts} +1 -0
  53. package/dist/{config-hXufftVS.d.mts → config-BmnK65TD.d.ts} +1 -0
  54. package/dist/config-DQeAo9Kf.d.mts +49 -0
  55. package/dist/config-DQeAo9Kf.d.ts +49 -0
  56. package/dist/contexts/index.d.mts +109 -21
  57. package/dist/contexts/index.d.ts +109 -21
  58. package/dist/contexts/index.js +39 -7
  59. package/dist/contexts/index.js.map +1 -1
  60. package/dist/contexts/index.mjs +40 -8
  61. package/dist/core/index.d.mts +3 -4
  62. package/dist/core/index.d.ts +3 -4
  63. package/dist/core/index.js +3 -7
  64. package/dist/core/index.js.map +1 -1
  65. package/dist/core/index.mjs +4 -8
  66. package/dist/{d3.link.interface-QMdB22bC.d.mts → d3.link.interface-ClC4Irqp.d.mts} +2 -1
  67. package/dist/{d3.link.interface-QMdB22bC.d.ts → d3.link.interface-ClC4Irqp.d.ts} +2 -1
  68. package/dist/features/index.d.mts +17 -86
  69. package/dist/features/index.d.ts +17 -86
  70. package/dist/features/index.js +7 -16
  71. package/dist/features/index.js.map +1 -1
  72. package/dist/features/index.mjs +10 -19
  73. package/dist/hooks/index.d.mts +18 -43
  74. package/dist/hooks/index.d.ts +18 -43
  75. package/dist/hooks/index.js +20 -7
  76. package/dist/hooks/index.js.map +1 -1
  77. package/dist/hooks/index.mjs +19 -6
  78. package/dist/index.d.mts +10 -6
  79. package/dist/index.d.ts +10 -6
  80. package/dist/index.js +13 -10
  81. package/dist/index.js.map +1 -1
  82. package/dist/index.mjs +22 -19
  83. package/dist/interfaces/index.d.mts +2 -1
  84. package/dist/interfaces/index.d.ts +2 -1
  85. package/dist/notification.interface-BBgMUdLR.d.mts +14 -0
  86. package/dist/notification.interface-gyvT-Z2F.d.ts +14 -0
  87. package/dist/permissions/index.d.mts +2 -3
  88. package/dist/permissions/index.d.ts +2 -3
  89. package/dist/server/index.d.mts +38 -18
  90. package/dist/server/index.d.ts +38 -18
  91. package/dist/server/index.js +70 -2
  92. package/dist/server/index.js.map +1 -1
  93. package/dist/server/index.mjs +68 -0
  94. package/dist/server/index.mjs.map +1 -1
  95. package/dist/types-BUAlgqqh.d.ts +39 -0
  96. package/dist/{types-DluCaP1I.d.ts → types-Bl61ob-7.d.mts} +19 -2
  97. package/dist/{types-lQVA8d_P.d.mts → types-Bl61ob-7.d.ts} +19 -2
  98. package/dist/types-iVdVY7ba.d.mts +39 -0
  99. package/dist/useSocket-Cn7fB_B1.d.mts +25 -0
  100. package/dist/useSocket-DzMKRKCA.d.ts +25 -0
  101. package/dist/user.fields-CbdObSmS.d.mts +18 -0
  102. package/dist/user.fields-CbdObSmS.d.ts +18 -0
  103. package/dist/utils/index.d.mts +1 -2
  104. package/dist/utils/index.d.ts +1 -2
  105. package/package.json +5 -3
  106. package/src/client/index.ts +13 -0
  107. package/src/components/forms/index.ts +1 -0
  108. package/src/components/index.ts +5 -0
  109. package/src/components/tables/ContentListTable.tsx +1 -0
  110. package/src/contexts/CommonContext.tsx +52 -0
  111. package/src/contexts/SharedContext.tsx +2 -0
  112. package/src/contexts/SocketContext.tsx +65 -0
  113. package/src/contexts/index.ts +6 -1
  114. package/src/features/auth/components/containers/AuthContainer.tsx +32 -0
  115. package/src/features/auth/components/containers/index.ts +1 -0
  116. package/src/features/auth/components/details/LandingComponent.tsx +39 -0
  117. package/src/features/auth/components/details/index.ts +1 -0
  118. package/src/features/auth/components/forms/AcceptInvitation.tsx +136 -0
  119. package/src/features/auth/components/forms/ActivateAccount.tsx +75 -0
  120. package/src/features/auth/components/forms/Cookies.tsx +32 -0
  121. package/src/features/auth/components/forms/ForgotPassword.tsx +108 -0
  122. package/src/features/auth/components/forms/Login.tsx +118 -0
  123. package/src/features/auth/components/forms/Logout.tsx +19 -0
  124. package/src/features/auth/components/forms/RefreshUser.tsx +39 -0
  125. package/src/features/auth/components/forms/Register.tsx +150 -0
  126. package/src/features/auth/components/forms/ResetPassword.tsx +126 -0
  127. package/src/features/auth/components/forms/index.ts +9 -0
  128. package/src/features/auth/components/index.ts +3 -0
  129. package/src/features/auth/contexts/AuthContext.tsx +77 -0
  130. package/src/features/auth/contexts/index.ts +1 -0
  131. package/src/features/auth/enums/AuthComponent.ts +9 -0
  132. package/src/features/auth/enums/index.ts +1 -0
  133. package/src/features/auth/index.ts +2 -1
  134. package/src/features/auth/utils/AuthCookies.ts +134 -0
  135. package/src/features/auth/utils/index.ts +1 -0
  136. package/src/features/company/components/containers/AdminCompanyContainer.tsx +26 -0
  137. package/src/features/company/components/containers/CompanyContainer.tsx +17 -0
  138. package/src/features/company/components/containers/index.ts +2 -0
  139. package/src/features/company/components/details/CompanyDetails.tsx +26 -0
  140. package/src/features/company/components/details/index.ts +1 -0
  141. package/src/features/company/components/forms/CompanyConfigurationEditor.tsx +151 -0
  142. package/src/features/company/components/forms/CompanyConfigurationSecurityForm.tsx +97 -0
  143. package/src/features/company/components/forms/CompanyDeleter.tsx +121 -0
  144. package/src/features/company/components/forms/CompanyEditor.tsx +245 -0
  145. package/src/features/company/components/forms/CompanyLicense.tsx +213 -0
  146. package/src/features/company/components/forms/index.ts +5 -0
  147. package/src/features/company/components/index.ts +4 -0
  148. package/src/features/company/components/lists/CompaniesList.tsx +31 -0
  149. package/src/features/company/components/lists/index.ts +1 -0
  150. package/src/features/company/contexts/CompanyContext.tsx +99 -0
  151. package/src/features/company/contexts/index.ts +0 -0
  152. package/src/features/company/hooks/index.ts +1 -0
  153. package/src/features/company/hooks/useCompanyTableStructure.tsx +82 -0
  154. package/src/features/feature/components/forms/FormFeatures.tsx +141 -140
  155. package/src/features/feature/components/forms/index.ts +1 -0
  156. package/src/features/feature/components/index.ts +1 -1
  157. package/src/features/feature/index.ts +1 -2
  158. package/src/features/module/index.ts +1 -1
  159. package/src/features/notification/components/common/NotificationErrorBoundary.tsx +51 -0
  160. package/src/features/notification/components/common/index.ts +1 -0
  161. package/src/features/notification/components/containers/NotificationsListContainer.tsx +44 -0
  162. package/src/features/notification/components/containers/index.ts +1 -0
  163. package/src/features/notification/components/index.ts +5 -0
  164. package/src/features/notification/components/lists/NotificationsList.tsx +129 -0
  165. package/src/features/notification/components/lists/index.ts +1 -0
  166. package/src/features/notification/components/modals/NotificationModal.tsx +220 -0
  167. package/src/features/notification/components/modals/index.ts +1 -0
  168. package/src/features/notification/components/notifications/Notification.tsx +120 -0
  169. package/src/features/notification/components/notifications/PushNotificationProvider.tsx +9 -0
  170. package/src/features/notification/components/notifications/index.ts +2 -0
  171. package/src/features/notification/contexts/NotificationContext.tsx +187 -0
  172. package/src/features/notification/contexts/index.ts +1 -0
  173. package/src/features/notification/index.ts +1 -1
  174. package/src/features/push/index.ts +1 -1
  175. package/src/features/role/components/containers/RoleContainer.tsx +18 -0
  176. package/src/features/role/components/containers/index.ts +1 -0
  177. package/src/features/role/components/details/RoleDetails.tsx +21 -0
  178. package/src/features/role/components/details/index.ts +1 -0
  179. package/src/features/role/components/forms/FormRoles.tsx +82 -0
  180. package/src/features/role/components/forms/RemoveUserFromRole.tsx +108 -0
  181. package/src/features/role/components/forms/UserRoleAdd.tsx +128 -0
  182. package/src/features/role/components/forms/index.ts +3 -0
  183. package/src/features/role/components/index.ts +4 -0
  184. package/src/features/role/components/lists/RolesList.tsx +27 -0
  185. package/src/features/role/components/lists/UserRolesList.tsx +31 -0
  186. package/src/features/role/components/lists/index.ts +2 -0
  187. package/src/features/role/contexts/RoleContext.tsx +84 -0
  188. package/src/features/role/contexts/index.ts +1 -0
  189. package/src/features/role/hooks/index.ts +1 -0
  190. package/src/features/role/hooks/useRoleTableStructure.tsx +72 -0
  191. package/src/features/s3/index.ts +1 -1
  192. package/src/features/user/components/containers/UserContainer.tsx +23 -0
  193. package/src/features/user/components/containers/UserIndexContainer.tsx +12 -0
  194. package/src/features/user/components/containers/UsersListContainer.tsx +36 -0
  195. package/src/features/user/components/containers/index.ts +3 -0
  196. package/src/features/user/components/details/UserDetails.tsx +74 -0
  197. package/src/features/user/components/details/UserIndexDetails.tsx +28 -0
  198. package/src/features/user/components/details/index.ts +2 -0
  199. package/src/features/user/components/forms/RoleUserAdd.tsx +93 -0
  200. package/src/features/user/components/forms/UserAvatarEditor.tsx +78 -0
  201. package/src/features/user/components/forms/UserDeleter.tsx +49 -0
  202. package/src/features/user/components/forms/UserEditor.tsx +319 -0
  203. package/src/features/user/components/forms/UserMultiSelect.tsx +218 -0
  204. package/src/features/user/components/forms/UserReactivator.tsx +79 -0
  205. package/src/features/user/components/forms/UserResentInvitationEmail.tsx +88 -0
  206. package/src/features/user/components/forms/UserSelector.tsx +185 -0
  207. package/src/features/user/components/forms/index.ts +8 -0
  208. package/src/features/user/components/index.ts +3 -0
  209. package/src/features/user/components/lists/AdminUsersList.tsx +41 -0
  210. package/src/features/user/components/lists/CompanyUsersList.tsx +44 -0
  211. package/src/features/user/components/lists/RelevantUsersList.tsx +30 -0
  212. package/src/features/user/components/lists/RoleUsersList.tsx +31 -0
  213. package/src/features/user/components/lists/UserListInAdd.tsx +53 -0
  214. package/src/features/user/components/lists/UsersList.tsx +30 -0
  215. package/src/features/user/components/lists/UsersListByContentIds.tsx +30 -0
  216. package/src/features/user/components/lists/index.ts +7 -0
  217. package/src/features/user/components/widgets/UserAvatarList.tsx +31 -0
  218. package/src/features/user/components/widgets/UserSearchPopover.tsx +89 -0
  219. package/src/features/user/contexts/UserContext.tsx +106 -0
  220. package/src/features/user/contexts/index.ts +1 -0
  221. package/src/features/user/hooks/index.ts +2 -0
  222. package/src/features/user/hooks/useUserSearch.ts +53 -0
  223. package/src/features/user/hooks/useUserTableStructure.tsx +115 -0
  224. package/src/features/user/index.ts +0 -1
  225. package/src/hooks/index.ts +4 -0
  226. package/src/hooks/useCustomD3Graph.tsx +2 -0
  227. package/src/hooks/useNotificationSync.ts +20 -0
  228. package/src/hooks/usePageTracker.ts +69 -0
  229. package/src/hooks/usePushNotifications.ts +82 -0
  230. package/src/hooks/useSocket.ts +201 -0
  231. package/src/hooks/useTableGenerator.ts +6 -2
  232. package/src/i18n/config.ts +1 -0
  233. package/src/index.ts +4 -0
  234. package/src/interfaces/d3.link.interface.ts +2 -1
  235. package/src/server/ServerSession.ts +103 -0
  236. package/src/server/index.ts +2 -1
  237. package/src/unified/JsonApiRequest.ts +23 -0
  238. package/dist/ApiRequestDataTypeInterface-CUKFDBx2.d.mts +0 -20
  239. package/dist/ApiRequestDataTypeInterface-CUKFDBx2.d.ts +0 -20
  240. package/dist/BlockNoteEditor-VFWG6LXI.js.map +0 -1
  241. package/dist/JsonApiRequest-S3ICLM7B.mjs +0 -20
  242. package/dist/JsonApiRequest-ZZLSP26T.js +0 -20
  243. package/dist/JsonApiRequest-ZZLSP26T.js.map +0 -1
  244. package/dist/chunk-366S2JCC.mjs +0 -31
  245. package/dist/chunk-366S2JCC.mjs.map +0 -1
  246. package/dist/chunk-5W6AKZE6.mjs +0 -131
  247. package/dist/chunk-5W6AKZE6.mjs.map +0 -1
  248. package/dist/chunk-A3J3AAYM.mjs +0 -97
  249. package/dist/chunk-A3J3AAYM.mjs.map +0 -1
  250. package/dist/chunk-AWONBQQP.js +0 -97
  251. package/dist/chunk-AWONBQQP.js.map +0 -1
  252. package/dist/chunk-CXQOWQSY.js.map +0 -1
  253. package/dist/chunk-DKKMWBP4.mjs +0 -1
  254. package/dist/chunk-DKKMWBP4.mjs.map +0 -1
  255. package/dist/chunk-DO2HLAZO.js +0 -48
  256. package/dist/chunk-DO2HLAZO.js.map +0 -1
  257. package/dist/chunk-DZXDB3K2.mjs +0 -17
  258. package/dist/chunk-DZXDB3K2.mjs.map +0 -1
  259. package/dist/chunk-ECDTZBYO.mjs.map +0 -1
  260. package/dist/chunk-FY4SXJGU.js +0 -806
  261. package/dist/chunk-FY4SXJGU.js.map +0 -1
  262. package/dist/chunk-GYWPEPOH.mjs.map +0 -1
  263. package/dist/chunk-H6FMOA6B.js +0 -1
  264. package/dist/chunk-H6FMOA6B.js.map +0 -1
  265. package/dist/chunk-I2REI7OA.js.map +0 -1
  266. package/dist/chunk-J4Q36PMP.js +0 -31
  267. package/dist/chunk-J4Q36PMP.js.map +0 -1
  268. package/dist/chunk-L6EQEAXU.mjs.map +0 -1
  269. package/dist/chunk-MFO27OHB.mjs +0 -48
  270. package/dist/chunk-MFO27OHB.mjs.map +0 -1
  271. package/dist/chunk-RAF7PNLG.js +0 -131
  272. package/dist/chunk-RAF7PNLG.js.map +0 -1
  273. package/dist/chunk-RUR22SVM.js +0 -17
  274. package/dist/chunk-RUR22SVM.js.map +0 -1
  275. package/dist/chunk-TEGF6ZWG.js.map +0 -1
  276. package/dist/chunk-TMVHSY3Y.js.map +0 -1
  277. package/dist/chunk-V2JJPI7N.js.map +0 -1
  278. package/dist/chunk-WWWMJZEF.mjs +0 -806
  279. package/dist/chunk-WWWMJZEF.mjs.map +0 -1
  280. package/dist/chunk-X4BIHJ2B.mjs.map +0 -1
  281. package/dist/chunk-YDVTFM7X.mjs.map +0 -1
  282. /package/dist/{JsonApiRequest-S3ICLM7B.mjs.map → JsonApiRequest-O7BGUMFO.mjs.map} +0 -0
@@ -0,0 +1,69 @@
1
+ "use client";
2
+
3
+ import { useAtom } from "jotai";
4
+ import { usePathname } from "next/navigation";
5
+ import { useEffect } from "react";
6
+ import { RecentPage, recentPagesAtom } from "../atoms";
7
+ import { getTrackablePages } from "../unified/JsonApiRequest";
8
+
9
+ // Routes to exclude from tracking
10
+ const EXCLUDED_ROUTES = ["/", "/login", "/register", "/forgot-password", "/reset-password", "/activate"];
11
+
12
+ export function usePageTracker() {
13
+ const pathname = usePathname();
14
+ const [recentPages, setRecentPages] = useAtom(recentPagesAtom);
15
+
16
+ useEffect(() => {
17
+ if (!pathname) return;
18
+
19
+ // Exclude certain routes
20
+ if (EXCLUDED_ROUTES.some((route) => pathname === route || pathname.endsWith(route))) {
21
+ return;
22
+ }
23
+
24
+ // Extract page information from pathname (already locale-free from next-intl)
25
+ const pathParts = pathname.split("/").filter(Boolean);
26
+
27
+ if (pathParts.length === 0) return;
28
+
29
+ // Try to find the module based on the route
30
+ const moduleName = pathParts[0];
31
+ const entityId = pathParts.length > 1 ? pathParts[1] : null;
32
+
33
+ // Only track pages with entity IDs (detail pages)
34
+ if (!entityId) return;
35
+
36
+ // Find the module from configured trackable pages
37
+ const trackablePages = getTrackablePages();
38
+ const foundModule = trackablePages.find((mod) => mod.pageUrl === `/${moduleName}`);
39
+
40
+ if (!foundModule) return;
41
+
42
+ // Only use base path (module/id), ignoring any sub-paths
43
+ const baseUrl = `/${moduleName}/${entityId}`;
44
+
45
+ let pageTitle = foundModule.name;
46
+ if (typeof document !== "undefined") {
47
+ const titleParts = document.title.split("]");
48
+ if (titleParts[1]) {
49
+ const cleanTitle = titleParts[1].split("|")[0]?.trim();
50
+ pageTitle = cleanTitle || foundModule.name;
51
+ }
52
+ }
53
+
54
+ const newPage: RecentPage = {
55
+ url: baseUrl,
56
+ title: pageTitle,
57
+ moduleType: foundModule.name,
58
+ timestamp: Date.now(),
59
+ };
60
+
61
+ setRecentPages((prev) => {
62
+ // Remove if already exists (to move to top)
63
+ const filtered = prev.filter((page) => page.url !== newPage.url);
64
+
65
+ // Add to beginning and limit to 10
66
+ return [newPage, ...filtered].slice(0, 10);
67
+ });
68
+ }, [pathname, setRecentPages]);
69
+ }
@@ -0,0 +1,82 @@
1
+ "use client";
2
+
3
+ import { useEffect } from "react";
4
+ import { useCurrentUserContext } from "../contexts";
5
+ import { PushService, UserInterface } from "../features";
6
+ import { getRoleId } from "../roles";
7
+ import { getAppUrl } from "../unified/JsonApiRequest";
8
+
9
+ function urlBase64ToUint8Array(base64String: string): Uint8Array {
10
+ const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
11
+ const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
12
+ const rawData = window.atob(base64);
13
+ const outputArray = new Uint8Array(rawData.length);
14
+ for (let i = 0; i < rawData.length; i++) {
15
+ outputArray[i] = rawData.charCodeAt(i);
16
+ }
17
+ return outputArray;
18
+ }
19
+
20
+ export default function usePushNotifications(): void {
21
+ const { currentUser, hasRole } = useCurrentUserContext<UserInterface>();
22
+
23
+ useEffect(() => {
24
+ const register = async () => {
25
+ if ("serviceWorker" in navigator && "PushManager" in window) {
26
+ try {
27
+ // Check if we've already processed push notifications for this user in this session
28
+ const sessionKey = `push_registered_${currentUser?.id}`;
29
+ const lastRegisteredSubscription = sessionStorage.getItem(sessionKey);
30
+
31
+ const registration = await navigator.serviceWorker.register(`${getAppUrl()}/sw.js`);
32
+
33
+ // Check current permission status first
34
+ let permission = Notification.permission;
35
+
36
+ // Only request permission if it's not already determined
37
+ if (permission === "default") {
38
+ permission = await Notification.requestPermission();
39
+ }
40
+
41
+ if (permission !== "granted") {
42
+ return; // User denied permission, this is not an error
43
+ }
44
+
45
+ const vapidPublicKey = (process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY || "").trim();
46
+ const convertedKey = urlBase64ToUint8Array(vapidPublicKey);
47
+
48
+ await navigator.serviceWorker.ready;
49
+
50
+ let subscription = await registration.pushManager.getSubscription();
51
+ if (!subscription) {
52
+ const appServerKey = new Uint8Array(Array.from(convertedKey));
53
+
54
+ subscription = await registration.pushManager.subscribe({
55
+ userVisibleOnly: true,
56
+ applicationServerKey: appServerKey,
57
+ });
58
+ }
59
+
60
+ const plainSubscription = {
61
+ endpoint: subscription.endpoint,
62
+ keys: subscription.toJSON().keys,
63
+ };
64
+
65
+ // Create a simple hash to detect subscription changes
66
+ const subscriptionHash = btoa(JSON.stringify(plainSubscription));
67
+
68
+ // Only call the API if subscription has changed or this is the first registration
69
+ if (lastRegisteredSubscription !== subscriptionHash) {
70
+ await PushService.register({ data: plainSubscription });
71
+ // Store the current subscription hash to avoid duplicate registrations
72
+ sessionStorage.setItem(sessionKey, subscriptionHash);
73
+ }
74
+ } catch (error) {
75
+ console.error("Error during service worker registration or push subscription:", error);
76
+ }
77
+ }
78
+ };
79
+
80
+ if (currentUser && !hasRole(getRoleId().Administrator)) register();
81
+ }, [currentUser]);
82
+ }
@@ -0,0 +1,201 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef, useState } from "react";
4
+ import io from "socket.io-client";
5
+ import { Modules, rehydrate } from "../core";
6
+ import { NotificationInterface } from "../features";
7
+
8
+ type Socket = ReturnType<typeof io>;
9
+
10
+ interface UseSocketOptions {
11
+ token: string;
12
+ }
13
+
14
+ interface SocketLike {
15
+ emit: (event: string, ...args: any[]) => void;
16
+ on: (event: string, callback: (...args: any[]) => void) => void;
17
+ off: (event: string, callback?: (...args: any[]) => void) => void;
18
+ connected: boolean;
19
+ }
20
+
21
+ interface UseSocketReturn {
22
+ socket: SocketLike | null;
23
+ isConnected: boolean;
24
+ messages: any[];
25
+ socketNotifications: NotificationInterface[];
26
+ sendMessage: (event: string, data: any) => void;
27
+ removeMessage: (index: number) => void;
28
+ removeSocketNotification: (index: number) => void;
29
+ clearMessages: () => void;
30
+ clearSocketNotifications: () => void;
31
+ }
32
+
33
+ export function useSocket({ token }: UseSocketOptions): UseSocketReturn {
34
+ const errorCount = useRef(0);
35
+ const shouldConnect = useRef(true);
36
+ const hookInstanceId = useRef(Math.random().toString(36).substring(2, 11));
37
+
38
+ const [socket, setSocket] = useState<Socket | null>(null);
39
+ const [isConnected, setIsConnected] = useState<boolean>(false);
40
+ const [messages, setMessages] = useState<any[]>([]);
41
+ const [socketNotifications, setSocketNotifications] = useState<NotificationInterface[]>([]);
42
+
43
+ const socketRef = useRef<Socket | null>(null);
44
+
45
+ useEffect(() => {
46
+ if (!token) return;
47
+
48
+ const globalSocketKey = `__socket_${process.env.NEXT_PUBLIC_API_URL?.replace(/[^a-zA-Z0-9]/g, "_")}`;
49
+
50
+ if (typeof window !== "undefined") {
51
+ const allSocketKeys = Object.keys(window).filter((key) => key.startsWith("__socket_"));
52
+
53
+ const existingSocket = (window as any)[globalSocketKey];
54
+ if (existingSocket) {
55
+ if (existingSocket.connected) {
56
+ // CRITICAL: Clear existing listeners to prevent accumulation
57
+ existingSocket.removeAllListeners();
58
+
59
+ socketRef.current = existingSocket;
60
+ setSocket(existingSocket);
61
+ setIsConnected(existingSocket.connected);
62
+ } else {
63
+ existingSocket.disconnect();
64
+ delete (window as any)[globalSocketKey];
65
+ }
66
+ }
67
+ }
68
+
69
+ let currentSocket: any;
70
+ const isReusing = socketRef.current && socketRef.current.connected;
71
+
72
+ if (isReusing) {
73
+ currentSocket = socketRef.current;
74
+ } else {
75
+ // React StrictMode protection: Prevent double-mounting issues
76
+ if (!shouldConnect.current) {
77
+ return;
78
+ }
79
+ shouldConnect.current = false;
80
+
81
+ try {
82
+ currentSocket = io(process.env.NEXT_PUBLIC_API_URL as string, {
83
+ auth: { token },
84
+ transports: ["websocket"],
85
+ timeout: 20000,
86
+ });
87
+
88
+ if (typeof window !== "undefined") {
89
+ if (currentSocket.id && currentSocket.id !== "undefined") {
90
+ (window as any)[globalSocketKey] = currentSocket;
91
+ }
92
+ }
93
+
94
+ socketRef.current = currentSocket;
95
+ setSocket(currentSocket);
96
+ } catch (error) {
97
+ return () => {}; // Return empty cleanup function on error
98
+ }
99
+ }
100
+
101
+ const handleConnect = () => {
102
+ setIsConnected(true);
103
+ };
104
+
105
+ const handleDisconnect = () => {
106
+ setIsConnected(false);
107
+ };
108
+
109
+ const handleMessage = (data: any) => {
110
+ setMessages((prevMessages) => {
111
+ const newMessages = [...prevMessages, data];
112
+ return newMessages;
113
+ });
114
+ };
115
+
116
+ const handleNotification = (data: any) => {
117
+ const notification = rehydrate(Modules.Notification, data) as NotificationInterface;
118
+ if (notification) {
119
+ setSocketNotifications((prev) => {
120
+ const newNotifications = [...prev, notification];
121
+ return newNotifications;
122
+ });
123
+ }
124
+ };
125
+
126
+ // Attach event listeners
127
+ if (currentSocket) {
128
+ currentSocket.on("connect", handleConnect);
129
+ currentSocket.on("disconnect", handleDisconnect);
130
+ currentSocket.on("message", handleMessage);
131
+ currentSocket.on("notification", handleNotification);
132
+ }
133
+
134
+ return () => {
135
+ shouldConnect.current = true;
136
+
137
+ // In development, preserve socket in window for HMR but remove listeners
138
+ if (currentSocket) {
139
+ if (process.env.NODE_ENV === "development") {
140
+ currentSocket.off("connect", handleConnect);
141
+ currentSocket.off("disconnect", handleDisconnect);
142
+ currentSocket.off("message", handleMessage);
143
+ currentSocket.off("notification", handleNotification);
144
+ } else {
145
+ currentSocket.off("connect", handleConnect);
146
+ currentSocket.off("disconnect", handleDisconnect);
147
+ currentSocket.off("message", handleMessage);
148
+ currentSocket.off("notification", handleNotification);
149
+
150
+ currentSocket.disconnect();
151
+
152
+ if (typeof window !== "undefined") {
153
+ delete (window as any)[globalSocketKey];
154
+ }
155
+ }
156
+ }
157
+ };
158
+ }, [token]);
159
+
160
+ const sendMessage = (event: string, data: any) => {
161
+ if (socketRef.current && isConnected) {
162
+ socketRef.current.emit(event, data);
163
+ }
164
+ };
165
+
166
+ const removeMessage = (index: number) => {
167
+ setMessages((prevMessages) => {
168
+ const newMessages = [...prevMessages];
169
+ newMessages.splice(index, 1);
170
+ return newMessages;
171
+ });
172
+ };
173
+
174
+ const removeSocketNotification = (index: number) => {
175
+ setSocketNotifications((prevNotifications) => {
176
+ const newNotifications = [...prevNotifications];
177
+ newNotifications.splice(index, 1);
178
+ return newNotifications;
179
+ });
180
+ };
181
+
182
+ const clearMessages = () => {
183
+ setMessages([]);
184
+ };
185
+
186
+ const clearSocketNotifications = () => {
187
+ setSocketNotifications([]);
188
+ };
189
+
190
+ return {
191
+ socket,
192
+ isConnected,
193
+ messages,
194
+ socketNotifications,
195
+ sendMessage,
196
+ removeMessage,
197
+ removeSocketNotification,
198
+ clearMessages,
199
+ clearSocketNotifications,
200
+ };
201
+ }
@@ -4,8 +4,12 @@ import { UseTableStructureHook, UseTableStructureHookParams, UseTableStructureHo
4
4
  import { ModuleWithPermissions } from "../permissions";
5
5
  import { tableGeneratorRegistry } from "./TableGeneratorRegistry";
6
6
 
7
- export function registerTableGenerator<T, U>(type: ModuleWithPermissions, hook: UseTableStructureHook<T, U>): void {
8
- tableGeneratorRegistry.register(type.name, hook);
7
+ export function registerTableGenerator<T, U>(
8
+ type: string | ModuleWithPermissions,
9
+ hook: UseTableStructureHook<T, U>,
10
+ ): void {
11
+ const name = typeof type === "string" ? type : type.name;
12
+ tableGeneratorRegistry.register(name, hook);
9
13
  }
10
14
 
11
15
  export function useTableGenerator<T, U>(
@@ -23,6 +23,7 @@ export interface I18nConfig {
23
23
  useLocale?: UseLocaleHook;
24
24
  useDateFnsLocale?: UseDateFnsLocaleHook;
25
25
  Link: LinkComponent;
26
+ usePathname: () => string;
26
27
  }
27
28
 
28
29
  // Private storage
package/src/index.ts CHANGED
@@ -14,3 +14,7 @@ export type { I18nConfig } from "./i18n";
14
14
  // Roles configuration
15
15
  export { configureRoles, getRoleId, isRolesConfigured } from "./roles";
16
16
  export type { RoleIdConfig } from "./roles";
17
+
18
+ // Auth configuration
19
+ export { configureAuth, getTokenHandler } from "./features/auth/config";
20
+ export type { TokenHandler, TokenParams } from "./features/auth/config";
@@ -1,6 +1,7 @@
1
+ import type { SimulationLinkDatum } from "d3";
1
2
  import { D3Node } from "./d3.node.interface";
2
3
 
3
- export interface D3Link extends d3.SimulationLinkDatum<D3Node> {
4
+ export interface D3Link extends SimulationLinkDatum<D3Node> {
4
5
  source: string | D3Node;
5
6
  target: string | D3Node;
6
7
  relationshipType?: string;
@@ -0,0 +1,103 @@
1
+ import { cookies } from "next/headers";
2
+ import { redirect } from "next/navigation";
3
+ import zlib from "zlib";
4
+ import { Action, checkPermissionsFromServer, ModuleWithPermissions } from "../permissions";
5
+
6
+ export class ServerSession {
7
+ static async isLogged() {
8
+ const cookieStore = await cookies();
9
+ const token = cookieStore.get("token");
10
+
11
+ if (!token || !token.value) return false;
12
+ return true;
13
+ }
14
+
15
+ static async isLicenseActive(): Promise<boolean> {
16
+ const cookieStore = await cookies();
17
+ const licenseExpirationDate = cookieStore.get("licenseExpirationDate")?.value;
18
+
19
+ if (!licenseExpirationDate) return false;
20
+
21
+ const now = new Date();
22
+ return new Date(licenseExpirationDate) > now;
23
+ }
24
+
25
+ static async companyId() {
26
+ const cookieStore = await cookies();
27
+ return cookieStore.get("companyId")?.value ?? "";
28
+ }
29
+
30
+ static async userId() {
31
+ const cookieStore = await cookies();
32
+ return cookieStore.get("userId")?.value ?? "";
33
+ }
34
+
35
+ static async checkPermission<M extends ModuleWithPermissions>(params: { module: M; action: Action; data?: any }) {
36
+ if (!(await this.hasPermissionToModule(params))) redirect(`/401`);
37
+ }
38
+
39
+ static async hasRole(roleId: string): Promise<boolean> {
40
+ const cookieStore = await cookies();
41
+ const roles = cookieStore.get("roles")?.value;
42
+
43
+ if (!roles || !roles.includes(roleId)) return false;
44
+
45
+ return true;
46
+ }
47
+
48
+ static async hasFeature(featureId: string): Promise<boolean> {
49
+ const cookieStore = await cookies();
50
+ const features = cookieStore.get("features")?.value;
51
+
52
+ if (!features || !features.includes(featureId)) return false;
53
+
54
+ return true;
55
+ }
56
+
57
+ static async hasPermissionToModule<M extends ModuleWithPermissions>(params: {
58
+ module: M;
59
+ action: Action;
60
+ data?: any;
61
+ }): Promise<boolean> {
62
+ const cookieStore = await cookies();
63
+
64
+ if (params.module.feature) {
65
+ const features = cookieStore.get("features")?.value;
66
+
67
+ if (features && !features.includes(params.module.feature)) return false;
68
+ }
69
+
70
+ const rawModules = cookieStore.get("modules")?.value;
71
+ if (!rawModules) return false;
72
+
73
+ const modules: {
74
+ id: string;
75
+ permissions: {
76
+ create: boolean | string;
77
+ read: boolean | string;
78
+ update: boolean | string;
79
+ delete: boolean | string;
80
+ };
81
+ }[] = JSON.parse(zlib.gunzipSync(Buffer.from(rawModules, "base64")).toString());
82
+
83
+ const selectedModule = modules.find((module) => module.id === params.module.moduleId);
84
+
85
+ return checkPermissionsFromServer({
86
+ module: params.module,
87
+ action: params.action,
88
+ data: params.data,
89
+ userId: await this.userId(),
90
+ selectedModule: selectedModule,
91
+ });
92
+
93
+ // if (!selectedModule) return false;
94
+
95
+ // if (!selectedModule.permissions[params.action]) return false;
96
+ // if (typeof selectedModule.permissions[params.action] === "boolean")
97
+ // return selectedModule.permissions[params.action] as boolean;
98
+
99
+ // if (!params.data) return false;
100
+
101
+ // return params.data[selectedModule.permissions[params.action] as string] === this.userId;
102
+ }
103
+ }
@@ -1,3 +1,4 @@
1
+ export * from "./cache";
1
2
  export * from "./request";
3
+ export * from "./ServerSession";
2
4
  export * from "./token";
3
- export * from "./cache";
@@ -3,6 +3,7 @@ import { ApiRequestDataTypeInterface } from "../core/interfaces/ApiRequestDataTy
3
3
  import { ApiResponseInterface } from "../core/interfaces/ApiResponseInterface";
4
4
  import { JsonApiDataFactory } from "../core/factories/JsonApiDataFactory";
5
5
  import { translateResponse } from "../core/utils/translateResponse";
6
+ import { ModuleWithPermissions } from "../permissions/types";
6
7
 
7
8
  // Type definitions for dynamically imported functions (avoiding typeof import to prevent bundling)
8
9
  type DirectFetchFn = (params: {
@@ -39,6 +40,8 @@ let _getServerToken: GetTokenFn;
39
40
  // Config storage for non-React contexts
40
41
  let _staticConfig: {
41
42
  apiUrl: string;
43
+ appUrl?: string;
44
+ trackablePages?: ModuleWithPermissions[];
42
45
  bootstrapper?: () => void;
43
46
  additionalHeaders?: Record<string, string>;
44
47
  } | null = null;
@@ -49,6 +52,8 @@ let _staticConfig: {
49
52
  */
50
53
  export function configureJsonApi(config: {
51
54
  apiUrl: string;
55
+ appUrl?: string;
56
+ trackablePages?: ModuleWithPermissions[];
52
57
  bootstrapper?: () => void;
53
58
  additionalHeaders?: Record<string, string>;
54
59
  }): void {
@@ -136,6 +141,24 @@ function getApiUrl(): string {
136
141
  return envUrl;
137
142
  }
138
143
 
144
+ export function getAppUrl(): string {
145
+ if (_staticConfig?.appUrl) {
146
+ return _staticConfig.appUrl;
147
+ }
148
+ // Fallback to environment variable
149
+ const envUrl = process.env.NEXT_PUBLIC_ADDRESS;
150
+ if (!envUrl) {
151
+ throw new Error(
152
+ "App URL not configured. Use configureJsonApi({ appUrl }) or set NEXT_PUBLIC_ADDRESS environment variable.",
153
+ );
154
+ }
155
+ return envUrl.trim().replace(/\/+$/, "");
156
+ }
157
+
158
+ export function getTrackablePages(): ModuleWithPermissions[] {
159
+ return _staticConfig?.trackablePages ?? [];
160
+ }
161
+
139
162
  function runBootstrapper(): void {
140
163
  if (_staticConfig?.bootstrapper) {
141
164
  _staticConfig.bootstrapper();
@@ -1,20 +0,0 @@
1
- type GetterKeys<T> = {
2
- [K in keyof T]: T[K] extends () => any ? never : K;
3
- }[keyof T];
4
- type FieldSelector<T> = {
5
- type: string;
6
- fields: ReadonlyArray<GetterKeys<T>>;
7
- };
8
- declare function createJsonApiInclusion<T>(dataType: string, fields: ReadonlyArray<GetterKeys<T>>): FieldSelector<T>;
9
-
10
- type ApiRequestDataTypeInterface = {
11
- name: string;
12
- cache?: string;
13
- inclusions?: Record<string, {
14
- types?: string[];
15
- fields?: FieldSelector<any>[];
16
- }>;
17
- model: new () => any;
18
- };
19
-
20
- export { type ApiRequestDataTypeInterface as A, type FieldSelector as F, type GetterKeys as G, createJsonApiInclusion as c };
@@ -1,20 +0,0 @@
1
- type GetterKeys<T> = {
2
- [K in keyof T]: T[K] extends () => any ? never : K;
3
- }[keyof T];
4
- type FieldSelector<T> = {
5
- type: string;
6
- fields: ReadonlyArray<GetterKeys<T>>;
7
- };
8
- declare function createJsonApiInclusion<T>(dataType: string, fields: ReadonlyArray<GetterKeys<T>>): FieldSelector<T>;
9
-
10
- type ApiRequestDataTypeInterface = {
11
- name: string;
12
- cache?: string;
13
- inclusions?: Record<string, {
14
- types?: string[];
15
- fields?: FieldSelector<any>[];
16
- }>;
17
- model: new () => any;
18
- };
19
-
20
- export { type ApiRequestDataTypeInterface as A, type FieldSelector as F, type GetterKeys as G, createJsonApiInclusion as c };
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/BlockNoteEditor-VFWG6LXI.js","../src/components/editors/BlockNoteEditor.tsx","../src/components/editors/BlockNoteEditorFormattingToolbar.tsx"],"names":["jsxs","jsx"],"mappings":"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","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/BlockNoteEditor-VFWG6LXI.js","sourcesContent":[null,"\"use client\";\n\nimport { BlockNoteSchema, defaultInlineContentSpecs, PartialBlock } from \"@blocknote/core\";\nimport { createReactInlineContentSpec, useCreateBlockNote } from \"@blocknote/react\";\nimport { BlockNoteView } from \"@blocknote/shadcn\";\nimport \"@blocknote/shadcn/style.css\";\nimport { CheckIcon, XIcon } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useCurrentUserContext } from \"../../contexts\";\nimport { S3Interface, S3Service, UserInterface } from \"../../features\";\nimport { Button } from \"../../shadcnui\";\nimport { BlockNoteDiffUtil, BlockNoteWordDiffRendererUtil, cn } from \"../../utils\";\nimport { errorToast } from \"../errors\";\nimport { BlockNoteEditorFormattingToolbar } from \"./BlockNoteEditorFormattingToolbar\";\n\nexport type BlockNoteEditorProps = {\n id: string;\n type: string;\n initialContent?: PartialBlock[];\n onChange?: (content: any, isEmpty: boolean, hasUnresolvedDiff: boolean) => void;\n size?: \"sm\" | \"md\";\n className?: string;\n markdownContent?: string;\n diffContent?: PartialBlock[];\n placeholder?: string;\n bordered?: boolean;\n};\n\nconst createDiffActionsInlineContentSpec = (\n handleAcceptChange: (diffId: string) => void,\n handleRejectChange: (diffId: string) => void,\n) => {\n return createReactInlineContentSpec(\n {\n type: \"diffActions\",\n propSchema: {\n diffIds: {\n default: \"\",\n },\n },\n content: \"none\",\n },\n {\n render: (props) => {\n const diffIds = props.inlineContent.props.diffIds;\n\n return (\n <span className=\"diff-actions-container mx-2 inline-flex items-center gap-1 align-middle\">\n <Button\n title=\"Accept change\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n diffIds.split(\",\").forEach((id: string) => handleAcceptChange(id.trim()));\n }}\n >\n <CheckIcon className=\"h-3 w-3 text-green-600\" />\n </Button>\n <Button\n title=\"Reject change\"\n className=\"mx-2 p-0\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n diffIds.split(\",\").forEach((id: string) => handleRejectChange(id.trim()));\n }}\n >\n <XIcon className=\"h-3 w-3 text-red-600\" />\n </Button>\n </span>\n );\n },\n },\n );\n};\n\nexport default function BlockNoteEditor({\n id,\n type,\n initialContent,\n onChange,\n size,\n className,\n markdownContent,\n diffContent,\n placeholder,\n bordered,\n}: BlockNoteEditorProps): React.JSX.Element {\n const t = useTranslations();\n const { company } = useCurrentUserContext<UserInterface>();\n\n const [acceptedChanges, setAcceptedChanges] = useState<Set<string>>(new Set());\n const [rejectedChanges, setRejectedChanges] = useState<Set<string>>(new Set());\n\n const editorRef = useRef<HTMLDivElement>(null);\n\n const handleAcceptChange = useCallback((diffId: string) => {\n setAcceptedChanges((prev) => new Set([...prev, diffId]));\n setRejectedChanges((prev) => {\n const newSet = new Set(prev);\n newSet.delete(diffId);\n return newSet;\n });\n }, []);\n\n const handleRejectChange = useCallback((diffId: string) => {\n setRejectedChanges((prev) => new Set([...prev, diffId]));\n setAcceptedChanges((prev) => {\n const newSet = new Set(prev);\n newSet.delete(diffId);\n return newSet;\n });\n }, []);\n\n const DiffActionsInlineContent = useMemo(\n () => createDiffActionsInlineContentSpec(handleAcceptChange, handleRejectChange),\n [handleAcceptChange, handleRejectChange],\n );\n\n const schema = useMemo(\n () =>\n BlockNoteSchema.create({\n inlineContentSpecs: {\n ...defaultInlineContentSpecs,\n diffActions: DiffActionsInlineContent,\n },\n } as any),\n [DiffActionsInlineContent],\n );\n\n const uploadImage = useCallback(\n async (file: File): Promise<string> => {\n if (!company) {\n errorToast({\n title: t(`generic.errors.upload`),\n error: t(`generic.errors.upload_description`),\n });\n throw new Error(t(`generic.errors.upload`));\n }\n\n const fileType = file.type;\n const key = `companies/${company.id}/${type}/${id}/${file.name}`;\n\n const s3: S3Interface = await S3Service.getPreSignedUrl({\n key: key,\n contentType: fileType,\n isPublic: true,\n });\n\n await fetch(s3.url, {\n method: \"PUT\",\n headers: s3.headers,\n body: file,\n });\n\n const signedImage: S3Interface = await S3Service.getSignedUrl({\n key: key,\n isPublic: true,\n });\n\n return signedImage.url;\n },\n [company, id, t],\n );\n\n // Utility: Remove trailing empty blocks for read-only display\n const removeTrailingEmptyBlocks = useCallback(\n (blocks: PartialBlock[]): PartialBlock[] => {\n if (!blocks || blocks.length === 0) return blocks;\n\n // Only remove trailing empty blocks in read-only mode\n if (onChange !== undefined) return blocks;\n\n const result = [...blocks];\n\n // Remove trailing empty paragraph blocks, but keep at least one block\n while (result.length > 1) {\n const lastBlock = result[result.length - 1];\n\n // Check if it's an empty paragraph\n const isEmptyParagraph =\n lastBlock.type === \"paragraph\" &&\n (!lastBlock.content ||\n lastBlock.content.length === 0 ||\n (Array.isArray(lastBlock.content) && lastBlock.content.every((c: any) => !c.text || c.text.trim() === \"\")));\n\n if (isEmptyParagraph) {\n result.pop();\n } else {\n break;\n }\n }\n\n return result;\n },\n [onChange],\n );\n\n const processedContent = useMemo(() => {\n if (diffContent && initialContent) {\n try {\n const diffResult = BlockNoteDiffUtil.diff(initialContent, diffContent);\n const renderedDiff = BlockNoteWordDiffRendererUtil.renderWordDiffs(\n diffResult.blocks,\n handleAcceptChange,\n handleRejectChange,\n acceptedChanges,\n rejectedChanges,\n );\n return removeTrailingEmptyBlocks(renderedDiff);\n } catch (error) {\n return initialContent && Array.isArray(initialContent) && initialContent.length > 0\n ? removeTrailingEmptyBlocks(initialContent)\n : [];\n }\n }\n\n if (!initialContent) {\n return [];\n }\n\n if (!Array.isArray(initialContent)) {\n return [];\n }\n\n return initialContent.length > 0 ? removeTrailingEmptyBlocks(initialContent) : [];\n }, [\n initialContent,\n diffContent,\n handleAcceptChange,\n handleRejectChange,\n acceptedChanges,\n rejectedChanges,\n removeTrailingEmptyBlocks,\n ]);\n\n const validatedInitialContent = useMemo(() => {\n if (processedContent && Array.isArray(processedContent) && processedContent.length > 0) {\n const validatedContent = processedContent.filter((block) => {\n if (!block || typeof block !== \"object\") return false;\n if (!(block as any).type) return false;\n return true;\n });\n return validatedContent.length > 0 ? (validatedContent as PartialBlock[]) : undefined;\n }\n return undefined;\n }, [processedContent]);\n\n const editor = useCreateBlockNote(\n useMemo(\n () => ({\n placeholders: {\n emptyDocument: placeholder || t(`generic.blocknote.placeholder`),\n },\n schema,\n initialContent: validatedInitialContent,\n uploadFile: uploadImage,\n }),\n [placeholder, t, schema, validatedInitialContent, uploadImage],\n ),\n );\n\n const handleChange = useCallback(async () => {\n if (!onChange) return;\n const newBlocks = editor.document;\n\n const markdownFromBlocks = (await editor.blocksToMarkdownLossy(editor.document)).trim();\n\n function hasUnresolvedDiffsRecursive(block: any): boolean {\n if (!block || typeof block !== \"object\") return false;\n let diffId = undefined;\n if (block.props && block.props.diffId) diffId = block.props.diffId;\n if (!diffId && block.attrs && block.attrs.diffId) diffId = block.attrs.diffId;\n if (diffId && !acceptedChanges.has(diffId) && !rejectedChanges.has(diffId)) {\n return true;\n }\n\n if (block.content) {\n const contentArr = Array.isArray(block.content) ? block.content : [block.content];\n for (const inline of contentArr) {\n if (inline && typeof inline === \"object\") {\n if (inline.type === \"diffActions\" && inline.props && inline.props.diffIds) {\n const ids =\n typeof inline.props.diffIds === \"string\" ? inline.props.diffIds.split(\",\") : inline.props.diffIds;\n for (const id of ids) {\n const trimmed = (id || \"\").toString().trim();\n if (trimmed && !acceptedChanges.has(trimmed) && !rejectedChanges.has(trimmed)) {\n return true;\n }\n }\n }\n if (inline.props && inline.props.diffId) {\n const diffIdInline = inline.props.diffId;\n if (diffIdInline && !acceptedChanges.has(diffIdInline) && !rejectedChanges.has(diffIdInline)) {\n return true;\n }\n }\n if (inline.children && Array.isArray(inline.children)) {\n for (const child of inline.children) {\n if (hasUnresolvedDiffsRecursive(child)) return true;\n }\n }\n }\n }\n }\n if (Array.isArray(block.children)) {\n for (const child of block.children) {\n if (hasUnresolvedDiffsRecursive(child)) return true;\n }\n }\n return false;\n }\n\n let hasUnresolvedDiff = false;\n if (Array.isArray(newBlocks)) {\n hasUnresolvedDiff = newBlocks.some((block: any) => hasUnresolvedDiffsRecursive(block));\n }\n\n onChange(newBlocks, !markdownFromBlocks.length, hasUnresolvedDiff);\n }, [editor, onChange, id, acceptedChanges, rejectedChanges]);\n\n // Utility: deep equality for arrays of blocks\n const areBlocksEqual = (a: any[], b: any[]): boolean => {\n return JSON.stringify(a) === JSON.stringify(b);\n };\n\n // Only initialize from markdownContent once per value, and only if different\n const hasInitializedFromMarkdown = useRef<string | null>(null);\n useEffect(() => {\n const updateContent = async (markdown: string) => {\n const blocks = await editor.tryParseMarkdownToBlocks(markdown);\n if (!areBlocksEqual(blocks, editor.document)) {\n editor.replaceBlocks(editor.document, blocks);\n }\n };\n\n if (markdownContent && hasInitializedFromMarkdown.current !== markdownContent) {\n hasInitializedFromMarkdown.current = markdownContent;\n updateContent(markdownContent).then(() => handleChange());\n }\n }, [markdownContent, editor]);\n\n // Update editor content when diff content changes, but only if different\n // Prevent unnecessary replaceBlocks calls that reset scroll/cursor.\n const previousContentHashRef = useRef<string | null>(null);\n useEffect(() => {\n if (!processedContent || !editor) return;\n const hash = JSON.stringify(processedContent);\n if (previousContentHashRef.current === hash) return; // no changes\n const currentHash = JSON.stringify(editor.document);\n if (currentHash === hash) {\n previousContentHashRef.current = hash;\n return; // already in sync\n }\n editor.replaceBlocks(editor.document, processedContent as PartialBlock[]);\n previousContentHashRef.current = hash;\n }, [processedContent, editor]);\n\n // Handle audio received from whisper transcription\n const handleAudioReceived = useCallback(\n (message: string) => {\n try {\n // Ensure the editor has focus\n const editorElement = editorRef.current?.querySelector('[contenteditable=\"true\"]') as HTMLElement;\n if (editorElement && document.activeElement !== editorElement) {\n editorElement.focus();\n }\n\n // Insert the transcribed text at the current cursor position\n editor.insertInlineContent(message);\n } catch (error) {\n console.error(\"Error inserting transcribed text:\", error);\n // Fallback: try to insert at the end of the document\n try {\n const blocks = editor.document;\n if (blocks.length > 0) {\n const lastBlock = blocks[blocks.length - 1];\n editor.setTextCursorPosition(lastBlock.id, \"end\");\n editor.insertInlineContent(message);\n }\n } catch (fallbackError) {\n console.error(\"Fallback insertion also failed:\", fallbackError);\n }\n }\n },\n [editor],\n );\n\n return (\n <div ref={editorRef} className={cn(bordered ? \"rounded-md border\" : \"\", \"w-full\")}>\n <BlockNoteView\n editor={editor}\n onChange={handleChange}\n editable={onChange !== undefined}\n formattingToolbar={false}\n theme=\"light\"\n className={cn(`BlockNoteView ${onChange ? \"min-h-96 p-4\" : \"\"}`, className, size === \"sm\" && \"small\")}\n >\n <BlockNoteEditorFormattingToolbar />\n </BlockNoteView>\n </div>\n );\n}\n","\"use client\";\n\nimport {\n BasicTextStyleButton,\n BlockTypeSelect,\n CreateLinkButton,\n FileCaptionButton,\n FileReplaceButton,\n FormattingToolbar,\n FormattingToolbarController,\n TextAlignButton,\n} from \"@blocknote/react\";\n\nexport function BlockNoteEditorFormattingToolbar() {\n return (\n <FormattingToolbarController\n formattingToolbar={() => (\n <FormattingToolbar>\n <BlockTypeSelect key={\"blockTypeSelect\"} />\n\n <FileCaptionButton key={\"fileCaptionButton\"} />\n <FileReplaceButton key={\"replaceFileButton\"} />\n\n <BasicTextStyleButton basicTextStyle={\"bold\"} key={\"boldStyleButton\"} />\n <BasicTextStyleButton basicTextStyle={\"italic\"} key={\"italicStyleButton\"} />\n <BasicTextStyleButton basicTextStyle={\"underline\"} key={\"underlineStyleButton\"} />\n <BasicTextStyleButton basicTextStyle={\"strike\"} key={\"strikeStyleButton\"} />\n\n <TextAlignButton textAlignment={\"left\"} key={\"textAlignLeftButton\"} />\n <TextAlignButton textAlignment={\"center\"} key={\"textAlignCenterButton\"} />\n <TextAlignButton textAlignment={\"right\"} key={\"textAlignRightButton\"} />\n\n <CreateLinkButton key={\"createLinkButton\"} />\n </FormattingToolbar>\n )}\n />\n );\n}\n"]}
@@ -1,20 +0,0 @@
1
- import {
2
- JsonApiDelete,
3
- JsonApiGet,
4
- JsonApiPatch,
5
- JsonApiPost,
6
- JsonApiPut,
7
- configureJsonApi
8
- } from "./chunk-ECDTZBYO.mjs";
9
- import "./chunk-YDVTFM7X.mjs";
10
- import "./chunk-MFO27OHB.mjs";
11
- import "./chunk-PAWJFY3S.mjs";
12
- export {
13
- JsonApiDelete,
14
- JsonApiGet,
15
- JsonApiPatch,
16
- JsonApiPost,
17
- JsonApiPut,
18
- configureJsonApi
19
- };
20
- //# sourceMappingURL=JsonApiRequest-S3ICLM7B.mjs.map