@carlonicora/nextjs-jsonapi 1.0.3 → 1.0.4

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 (261) hide show
  1. package/package.json +2 -1
  2. package/src/atoms/index.ts +1 -0
  3. package/src/atoms/recentPagesAtom.ts +10 -0
  4. package/src/client/context/JsonApiContext.ts +61 -0
  5. package/src/client/context/JsonApiProvider.tsx +27 -0
  6. package/src/client/context/index.ts +2 -0
  7. package/src/client/hooks/index.ts +3 -0
  8. package/src/client/hooks/useJsonApiGet.ts +188 -0
  9. package/src/client/hooks/useJsonApiMutation.ts +193 -0
  10. package/src/client/hooks/useRehydration.ts +47 -0
  11. package/src/client/index.ts +11 -0
  12. package/src/client/request.ts +97 -0
  13. package/src/client/token.ts +10 -0
  14. package/src/components/containers/PageContainer.tsx +15 -0
  15. package/src/components/containers/ReactMarkdownContainer.tsx +119 -0
  16. package/src/components/containers/TabsContainer.tsx +93 -0
  17. package/src/components/containers/index.ts +3 -0
  18. package/src/components/contents/AttributeElement.tsx +20 -0
  19. package/src/components/contents/index.ts +1 -0
  20. package/src/components/details/AllowedUsersDetails.tsx +23 -0
  21. package/src/components/details/index.ts +1 -0
  22. package/src/components/editors/BlockNoteDiffInlineContent.tsx +152 -0
  23. package/src/components/editors/BlockNoteEditor.tsx +404 -0
  24. package/src/components/editors/BlockNoteEditorContainer.tsx +13 -0
  25. package/src/components/editors/BlockNoteEditorFormattingToolbar.tsx +38 -0
  26. package/src/components/editors/index.ts +1 -0
  27. package/src/components/errors/ErrorDetails.tsx +41 -0
  28. package/src/components/errors/errorToast.ts +9 -0
  29. package/src/components/errors/index.ts +2 -0
  30. package/src/components/forms/CommonAssociationForm.tsx +162 -0
  31. package/src/components/forms/CommonDeleter.tsx +94 -0
  32. package/src/components/forms/CommonEditorButtons.tsx +30 -0
  33. package/src/components/forms/CommonEditorHeader.tsx +35 -0
  34. package/src/components/forms/CommonEditorTrigger.tsx +26 -0
  35. package/src/components/forms/DatePickerPopover.tsx +219 -0
  36. package/src/components/forms/DateRangeSelector.tsx +110 -0
  37. package/src/components/forms/FileUploader.tsx +324 -0
  38. package/src/components/forms/FormCheckbox.tsx +66 -0
  39. package/src/components/forms/FormContainerGeneric.tsx +39 -0
  40. package/src/components/forms/FormDate.tsx +247 -0
  41. package/src/components/forms/FormDateTime.tsx +231 -0
  42. package/src/components/forms/FormInput.tsx +110 -0
  43. package/src/components/forms/FormPassword.tsx +54 -0
  44. package/src/components/forms/FormPlaceAutocomplete.tsx +286 -0
  45. package/src/components/forms/FormSelect.tsx +72 -0
  46. package/src/components/forms/FormSlider.tsx +51 -0
  47. package/src/components/forms/FormSwitch.tsx +25 -0
  48. package/src/components/forms/FormTextarea.tsx +44 -0
  49. package/src/components/forms/MultiFileUploader.tsx +107 -0
  50. package/src/components/forms/PasswordInput.tsx +47 -0
  51. package/src/components/forms/index.ts +21 -0
  52. package/src/components/index.ts +11 -0
  53. package/src/components/navigations/Breadcrumb.tsx +83 -0
  54. package/src/components/navigations/ContentTitle.tsx +39 -0
  55. package/src/components/navigations/Header.tsx +27 -0
  56. package/src/components/navigations/ModeToggleSwitch.tsx +25 -0
  57. package/src/components/navigations/PageSection.tsx +64 -0
  58. package/src/components/navigations/RecentPagesNavigator.tsx +52 -0
  59. package/src/components/navigations/index.ts +6 -0
  60. package/src/components/pages/PageContainerContentDetails.tsx +76 -0
  61. package/src/components/pages/PageContentContainer.tsx +31 -0
  62. package/src/components/pages/index.ts +2 -0
  63. package/src/components/tables/ContentListTable.tsx +165 -0
  64. package/src/components/tables/ContentTableSearch.tsx +105 -0
  65. package/src/components/tables/cells/cell.component.tsx +18 -0
  66. package/src/components/tables/cells/cell.date.tsx +16 -0
  67. package/src/components/tables/cells/cell.id.tsx +27 -0
  68. package/src/components/tables/cells/cell.link.tsx +18 -0
  69. package/src/components/tables/cells/cell.text.tsx +12 -0
  70. package/src/components/tables/cells/cell.url.tsx +13 -0
  71. package/src/components/tables/cells/index.ts +5 -0
  72. package/src/components/tables/index.ts +3 -0
  73. package/src/contexts/SharedContext.tsx +35 -0
  74. package/src/contexts/index.ts +2 -0
  75. package/src/core/abstracts/AbstractApiData.ts +138 -0
  76. package/src/core/abstracts/AbstractService.ts +263 -0
  77. package/src/core/abstracts/index.ts +2 -0
  78. package/src/core/endpoint/EndpointCreator.ts +97 -0
  79. package/src/core/endpoint/index.ts +1 -0
  80. package/src/core/factories/JsonApiDataFactory.ts +12 -0
  81. package/src/core/factories/RehydrationFactory.ts +30 -0
  82. package/src/core/factories/index.ts +2 -0
  83. package/src/core/fields/FieldSelector.ts +15 -0
  84. package/src/core/fields/index.ts +1 -0
  85. package/src/core/index.ts +20 -0
  86. package/src/core/interfaces/ApiData.ts +8 -0
  87. package/src/core/interfaces/ApiDataInterface.ts +15 -0
  88. package/src/core/interfaces/ApiRequestDataTypeInterface.ts +14 -0
  89. package/src/core/interfaces/ApiResponseInterface.ts +17 -0
  90. package/src/core/interfaces/JsonApiHydratedDataInterface.ts +5 -0
  91. package/src/core/interfaces/index.ts +5 -0
  92. package/src/core/registry/DataClassRegistry.ts +51 -0
  93. package/src/core/registry/ModuleRegistrar.ts +43 -0
  94. package/src/core/registry/ModuleRegistry.ts +64 -0
  95. package/src/core/registry/index.ts +3 -0
  96. package/src/core/utils/index.ts +2 -0
  97. package/src/core/utils/rehydrate.ts +24 -0
  98. package/src/core/utils/translateResponse.ts +125 -0
  99. package/src/features/auth/auth.module.ts +9 -0
  100. package/src/features/auth/config.ts +57 -0
  101. package/src/features/auth/data/auth.interface.ts +31 -0
  102. package/src/features/auth/data/auth.service.ts +159 -0
  103. package/src/features/auth/data/auth.ts +54 -0
  104. package/src/features/auth/data/index.ts +3 -0
  105. package/src/features/auth/index.ts +3 -0
  106. package/src/features/company/company.module.ts +10 -0
  107. package/src/features/company/data/company.fields.ts +6 -0
  108. package/src/features/company/data/company.interface.ts +28 -0
  109. package/src/features/company/data/company.service.ts +73 -0
  110. package/src/features/company/data/company.ts +104 -0
  111. package/src/features/company/data/index.ts +4 -0
  112. package/src/features/company/index.ts +2 -0
  113. package/src/features/content/content.module.ts +20 -0
  114. package/src/features/content/data/content.fields.ts +13 -0
  115. package/src/features/content/data/content.interface.ts +23 -0
  116. package/src/features/content/data/content.service.ts +75 -0
  117. package/src/features/content/data/content.ts +85 -0
  118. package/src/features/content/data/index.ts +4 -0
  119. package/src/features/content/index.ts +2 -0
  120. package/src/features/feature/components/forms/FormFeatures.tsx +149 -0
  121. package/src/features/feature/components/index.ts +1 -0
  122. package/src/features/feature/data/feature.interface.ts +9 -0
  123. package/src/features/feature/data/feature.service.ts +19 -0
  124. package/src/features/feature/data/feature.ts +33 -0
  125. package/src/features/feature/data/index.ts +3 -0
  126. package/src/features/feature/feature.module.ts +10 -0
  127. package/src/features/feature/index.ts +3 -0
  128. package/src/features/index.ts +12 -0
  129. package/src/features/module/data/index.ts +2 -0
  130. package/src/features/module/data/module.interface.ts +12 -0
  131. package/src/features/module/data/module.ts +42 -0
  132. package/src/features/module/index.ts +2 -0
  133. package/src/features/module/module.module.ts +10 -0
  134. package/src/features/notification/data/index.ts +4 -0
  135. package/src/features/notification/data/notification.fields.ts +8 -0
  136. package/src/features/notification/data/notification.interface.ts +14 -0
  137. package/src/features/notification/data/notification.service.ts +34 -0
  138. package/src/features/notification/data/notification.ts +51 -0
  139. package/src/features/notification/index.ts +2 -0
  140. package/src/features/notification/notification.module.ts +10 -0
  141. package/src/features/push/data/index.ts +3 -0
  142. package/src/features/push/data/push.interface.ts +8 -0
  143. package/src/features/push/data/push.service.ts +17 -0
  144. package/src/features/push/data/push.ts +18 -0
  145. package/src/features/push/index.ts +2 -0
  146. package/src/features/push/push.module.ts +10 -0
  147. package/src/features/role/data/index.ts +4 -0
  148. package/src/features/role/data/role.fields.ts +8 -0
  149. package/src/features/role/data/role.interface.ts +16 -0
  150. package/src/features/role/data/role.service.ts +117 -0
  151. package/src/features/role/data/role.ts +62 -0
  152. package/src/features/role/index.ts +2 -0
  153. package/src/features/role/role.module.ts +10 -0
  154. package/src/features/s3/data/index.ts +3 -0
  155. package/src/features/s3/data/s3.interface.ts +11 -0
  156. package/src/features/s3/data/s3.service.ts +30 -0
  157. package/src/features/s3/data/s3.ts +60 -0
  158. package/src/features/s3/index.ts +2 -0
  159. package/src/features/s3/s3.module.ts +10 -0
  160. package/src/features/search/index.ts +1 -0
  161. package/src/features/search/interfaces/index.ts +1 -0
  162. package/src/features/search/interfaces/search.result.interface.ts +3 -0
  163. package/src/features/user/author.module.ts +10 -0
  164. package/src/features/user/components/index.ts +2 -0
  165. package/src/features/user/components/lists/ContributorsList.tsx +41 -0
  166. package/src/features/user/components/lists/index.ts +1 -0
  167. package/src/features/user/components/widgets/UserAvatar.tsx +86 -0
  168. package/src/features/user/components/widgets/index.ts +1 -0
  169. package/src/features/user/contexts/CurrentUserContext.tsx +156 -0
  170. package/src/features/user/contexts/index.ts +1 -0
  171. package/src/features/user/data/index.ts +4 -0
  172. package/src/features/user/data/user.fields.ts +8 -0
  173. package/src/features/user/data/user.interface.ts +41 -0
  174. package/src/features/user/data/user.service.ts +246 -0
  175. package/src/features/user/data/user.ts +162 -0
  176. package/src/features/user/index.ts +4 -0
  177. package/src/features/user/user.module.ts +21 -0
  178. package/src/hooks/TableGeneratorRegistry.ts +53 -0
  179. package/src/hooks/index.ts +33 -0
  180. package/src/hooks/types.ts +35 -0
  181. package/src/hooks/url.rewriter.ts +22 -0
  182. package/src/hooks/useCustomD3Graph.tsx +705 -0
  183. package/src/hooks/useDataListRetriever.ts +349 -0
  184. package/src/hooks/useDebounce.ts +33 -0
  185. package/src/hooks/usePageUrlGenerator.ts +50 -0
  186. package/src/hooks/useTableGenerator.ts +16 -0
  187. package/src/i18n/config.ts +73 -0
  188. package/src/i18n/index.ts +18 -0
  189. package/src/index.ts +16 -0
  190. package/src/interfaces/breadcrumb.item.data.interface.ts +4 -0
  191. package/src/interfaces/d3.link.interface.ts +7 -0
  192. package/src/interfaces/d3.node.interface.ts +12 -0
  193. package/src/interfaces/index.ts +3 -0
  194. package/src/permissions/check.ts +127 -0
  195. package/src/permissions/index.ts +2 -0
  196. package/src/permissions/types.ts +109 -0
  197. package/src/roles/config.ts +46 -0
  198. package/src/roles/index.ts +1 -0
  199. package/src/server/cache.ts +28 -0
  200. package/src/server/index.ts +3 -0
  201. package/src/server/request.ts +113 -0
  202. package/src/server/token.ts +10 -0
  203. package/src/shadcnui/custom/kanban.tsx +1001 -0
  204. package/src/shadcnui/custom/link.tsx +18 -0
  205. package/src/shadcnui/custom/multi-select.tsx +382 -0
  206. package/src/shadcnui/index.ts +49 -0
  207. package/src/shadcnui/ui/accordion.tsx +52 -0
  208. package/src/shadcnui/ui/alert-dialog.tsx +141 -0
  209. package/src/shadcnui/ui/alert.tsx +43 -0
  210. package/src/shadcnui/ui/avatar.tsx +50 -0
  211. package/src/shadcnui/ui/badge.tsx +40 -0
  212. package/src/shadcnui/ui/breadcrumb.tsx +115 -0
  213. package/src/shadcnui/ui/button.tsx +51 -0
  214. package/src/shadcnui/ui/calendar.tsx +73 -0
  215. package/src/shadcnui/ui/card.tsx +43 -0
  216. package/src/shadcnui/ui/carousel.tsx +225 -0
  217. package/src/shadcnui/ui/chart.tsx +320 -0
  218. package/src/shadcnui/ui/checkbox.tsx +29 -0
  219. package/src/shadcnui/ui/collapsible.tsx +11 -0
  220. package/src/shadcnui/ui/command.tsx +155 -0
  221. package/src/shadcnui/ui/context-menu.tsx +179 -0
  222. package/src/shadcnui/ui/dialog.tsx +96 -0
  223. package/src/shadcnui/ui/drawer.tsx +89 -0
  224. package/src/shadcnui/ui/dropdown-menu.tsx +205 -0
  225. package/src/shadcnui/ui/form.tsx +138 -0
  226. package/src/shadcnui/ui/hover-card.tsx +29 -0
  227. package/src/shadcnui/ui/input.tsx +21 -0
  228. package/src/shadcnui/ui/label.tsx +26 -0
  229. package/src/shadcnui/ui/navigation-menu.tsx +168 -0
  230. package/src/shadcnui/ui/popover.tsx +33 -0
  231. package/src/shadcnui/ui/progress.tsx +25 -0
  232. package/src/shadcnui/ui/radio-group.tsx +37 -0
  233. package/src/shadcnui/ui/resizable.tsx +47 -0
  234. package/src/shadcnui/ui/scroll-area.tsx +40 -0
  235. package/src/shadcnui/ui/select.tsx +164 -0
  236. package/src/shadcnui/ui/separator.tsx +28 -0
  237. package/src/shadcnui/ui/sheet.tsx +139 -0
  238. package/src/shadcnui/ui/sidebar.tsx +677 -0
  239. package/src/shadcnui/ui/skeleton.tsx +13 -0
  240. package/src/shadcnui/ui/slider.tsx +25 -0
  241. package/src/shadcnui/ui/sonner.tsx +25 -0
  242. package/src/shadcnui/ui/switch.tsx +31 -0
  243. package/src/shadcnui/ui/table.tsx +120 -0
  244. package/src/shadcnui/ui/tabs.tsx +55 -0
  245. package/src/shadcnui/ui/textarea.tsx +24 -0
  246. package/src/shadcnui/ui/toggle.tsx +39 -0
  247. package/src/shadcnui/ui/tooltip.tsx +61 -0
  248. package/src/unified/JsonApiRequest.ts +325 -0
  249. package/src/unified/index.ts +1 -0
  250. package/src/utils/blocknote-diff.util.ts +815 -0
  251. package/src/utils/blocknote-word-diff-renderer.util.ts +413 -0
  252. package/src/utils/cn.ts +6 -0
  253. package/src/utils/compose-refs.ts +61 -0
  254. package/src/utils/date-formatter.ts +53 -0
  255. package/src/utils/exists.ts +7 -0
  256. package/src/utils/index.ts +15 -0
  257. package/src/utils/schemas/entity.object.schema.ts +8 -0
  258. package/src/utils/schemas/index.ts +2 -0
  259. package/src/utils/schemas/user.object.schema.ts +9 -0
  260. package/src/utils/table-options.ts +67 -0
  261. package/src/utils/use-mobile.tsx +21 -0
@@ -0,0 +1,41 @@
1
+ "use client";
2
+
3
+ import { Modules } from "../../../../core";
4
+ import { usePageUrlGenerator } from "../../../../hooks";
5
+ import { Link } from "../../../../shadcnui";
6
+ import { ContentInterface } from "../../../content";
7
+ import { UserInterface } from "../../data";
8
+ import { UserAvatar } from "../widgets";
9
+
10
+ type ContributorsListProps = {
11
+ content: ContentInterface;
12
+ };
13
+
14
+ export function ContributorsList({ content }: ContributorsListProps) {
15
+ const generateUrl = usePageUrlGenerator();
16
+
17
+ return (
18
+ <div className="flex flex-row items-center">
19
+ <Link
20
+ key={content.author.id}
21
+ href={generateUrl({ page: Modules.User, id: content.author.id })}
22
+ onClick={(e) => e.stopPropagation()}
23
+ >
24
+ <UserAvatar user={content.author} className="mr-1 h-6 w-6" />
25
+ </Link>
26
+ <div className="flex flex-row-reverse justify-end -space-x-1 space-x-reverse">
27
+ {content.editors
28
+ .filter((editor: UserInterface) => editor.id !== content.author.id)
29
+ .map((editor: UserInterface) => (
30
+ <Link
31
+ key={editor.id}
32
+ href={generateUrl({ page: Modules.User, id: editor.id })}
33
+ onClick={(e) => e.stopPropagation()}
34
+ >
35
+ <UserAvatar user={editor} className="h-5 w-5" />
36
+ </Link>
37
+ ))}
38
+ </div>
39
+ </div>
40
+ );
41
+ }
@@ -0,0 +1 @@
1
+ export * from "./ContributorsList";
@@ -0,0 +1,86 @@
1
+ "use client";
2
+
3
+ import { Modules } from "../../../../core";
4
+ import { usePageUrlGenerator } from "../../../../hooks";
5
+ import {
6
+ Avatar,
7
+ AvatarFallback,
8
+ AvatarImage,
9
+ Link,
10
+ Tooltip,
11
+ TooltipContent,
12
+ TooltipTrigger,
13
+ } from "../../../../shadcnui";
14
+ import { cn } from "../../../../utils";
15
+ import { UserInterface } from "../../data";
16
+
17
+ type UserAvatarProps = {
18
+ user: UserInterface;
19
+ className?: string;
20
+ showFull?: boolean;
21
+ showLink?: boolean;
22
+ };
23
+
24
+ export function UserAvatar({ user, className, showFull, showLink }: UserAvatarProps) {
25
+ const generateUrl = usePageUrlGenerator();
26
+
27
+ const getInitial = (param?: string) => {
28
+ if (!param) return "";
29
+ return param[0].toUpperCase();
30
+ };
31
+
32
+ const getInitials = (name: string) => {
33
+ const words = name.split(" ");
34
+ const initials =
35
+ words.length > 1 ? getInitial(words[0][0]) + getInitial(words[words.length - 1][0]) : getInitial(words[0][0]);
36
+
37
+ return initials ?? "";
38
+ };
39
+
40
+ const getAvatar = () => {
41
+ return (
42
+ <div className="*:ring-border *:ring-1">
43
+ <Avatar className={`h-6 w-6 ${className}`}>
44
+ <AvatarImage className="object-cover" src={user?.avatar} />
45
+ <AvatarFallback>{getInitials(user.name)}</AvatarFallback>
46
+ </Avatar>
47
+ </div>
48
+ );
49
+ };
50
+
51
+ return (
52
+ <Tooltip>
53
+ <TooltipTrigger asChild>
54
+ {showLink === false ? (
55
+ // If showLink is explicitly false, never show a link
56
+ showFull ? (
57
+ <div className={cn(`mb-2 flex w-full flex-row items-center justify-start gap-x-2 text-sm`, className)}>
58
+ {getAvatar()}
59
+ {user.name}
60
+ </div>
61
+ ) : (
62
+ getAvatar()
63
+ )
64
+ ) : showFull ? (
65
+ <Link
66
+ href={generateUrl({ page: Modules.User, id: user.id })}
67
+ className={cn(`mb-2 flex w-full flex-row items-center justify-start gap-x-2 text-sm`, className)}
68
+ onClick={(e) => e.stopPropagation()}
69
+ >
70
+ <div className="flex w-full flex-row items-center gap-x-2">
71
+ {getAvatar()}
72
+ {user.name}
73
+ </div>
74
+ </Link>
75
+ ) : showLink ? (
76
+ <Link href={generateUrl({ page: Modules.User, id: user.id })} className={className}>
77
+ {getAvatar()}
78
+ </Link>
79
+ ) : (
80
+ getAvatar()
81
+ )}
82
+ </TooltipTrigger>
83
+ <TooltipContent>{user.name}</TooltipContent>
84
+ </Tooltip>
85
+ );
86
+ }
@@ -0,0 +1 @@
1
+ export * from "./UserAvatar";
@@ -0,0 +1,156 @@
1
+ "use client";
2
+
3
+ import { getCookie } from "cookies-next";
4
+ import { useAtom } from "jotai";
5
+ import { atomWithStorage } from "jotai/utils";
6
+ import { usePathname } from "next/navigation";
7
+ import React, { createContext, useContext, useEffect } from "react";
8
+ import { Modules, rehydrate } from "../../../core";
9
+ import { Action, checkPermissions, ModuleWithPermissions } from "../../../permissions";
10
+ import { getRoleId } from "../../../roles";
11
+ import { CompanyInterface } from "../../company";
12
+ import { FeatureInterface } from "../../feature";
13
+ import { RoleInterface } from "../../role";
14
+ import { UserInterface } from "../data";
15
+
16
+ export interface CurrentUserContextType<T extends UserInterface = UserInterface> {
17
+ currentUser: T | null;
18
+ company: CompanyInterface | null;
19
+ setUser: (user?: T) => void;
20
+ hasPermissionToModule: <M extends ModuleWithPermissions>(params: {
21
+ module: M;
22
+ action: Action;
23
+ data?: any;
24
+ }) => boolean;
25
+ hasPermissionToModules: <M extends ModuleWithPermissions>(params: {
26
+ modules: M[];
27
+ action: Action;
28
+ data?: any;
29
+ }) => boolean;
30
+ hasPermissionToPath: (path: string) => boolean;
31
+ hasAccesToFeature: (featureIdentifier: string) => boolean;
32
+ matchUrlToModule: (prarms?: { path: string }) => ModuleWithPermissions | undefined;
33
+ hasRole: (roleId: string) => boolean;
34
+ }
35
+
36
+ const userAtom = atomWithStorage("user", null);
37
+
38
+ const CurrentUserContext = createContext<CurrentUserContextType | undefined>(undefined);
39
+
40
+ export const CurrentUserProvider = ({ children }: { children: React.ReactNode }) => {
41
+ const path = usePathname();
42
+
43
+ const [dehydratedUser, setDehydratedUser] = useAtom(userAtom);
44
+
45
+ useEffect(() => {
46
+ const token = getCookie("token");
47
+ if (!token && dehydratedUser) setDehydratedUser(null);
48
+ }, [dehydratedUser, setDehydratedUser]);
49
+
50
+ const matchUrlToModule = (params?: { path: string }): ModuleWithPermissions | undefined => {
51
+ const moduleKeys = Object.getOwnPropertyNames(Modules).filter(
52
+ (key) => key !== "prototype" && key !== "_factory" && key !== "length" && key !== "name",
53
+ );
54
+
55
+ const matchedModuleKey = moduleKeys.find((key) => {
56
+ const descriptor = Object.getOwnPropertyDescriptor(Modules, key);
57
+
58
+ if (!descriptor?.get) return false;
59
+
60
+ const selectedModule = descriptor.get.call(Modules);
61
+
62
+ return path.toLowerCase().startsWith(selectedModule.pageUrl?.toLowerCase());
63
+ });
64
+
65
+ if (!matchedModuleKey) return undefined;
66
+
67
+ const descriptor = Object.getOwnPropertyDescriptor(Modules, matchedModuleKey);
68
+ return descriptor?.get?.call(Modules);
69
+ };
70
+
71
+ const currentUser = dehydratedUser ? rehydrate<UserInterface>(Modules.User, dehydratedUser) : null;
72
+
73
+ const company = currentUser?.company ?? null;
74
+
75
+ const setUser = (user?: UserInterface): void => {
76
+ if (user) setDehydratedUser(user.dehydrate() as any);
77
+ else setDehydratedUser(null);
78
+ };
79
+
80
+ const hasRole = (roleId: string): boolean => {
81
+ if (!currentUser) return false;
82
+
83
+ return !!currentUser.roles?.some((userRole: RoleInterface) => userRole.id === roleId);
84
+ };
85
+
86
+ const hasAccesToFeature = (featureIdentifier: string): boolean => {
87
+ if (hasRole(getRoleId().Administrator)) return true;
88
+ if (!company) return false;
89
+
90
+ return company.features.some((feature: FeatureInterface) => feature.id === featureIdentifier);
91
+ };
92
+
93
+ function hasPermissionToModule<M extends ModuleWithPermissions>(params: {
94
+ module: M;
95
+ action: Action;
96
+ data?: M extends ModuleWithPermissions ? any : never;
97
+ }): boolean {
98
+ if (!currentUser) return false;
99
+
100
+ if (!!params.module.feature && !hasAccesToFeature(params.module.feature)) return false;
101
+
102
+ return checkPermissions({ module: params.module, action: params.action, data: params.data, user: currentUser });
103
+ }
104
+
105
+ function hasPermissionToModules<M extends ModuleWithPermissions>(params: {
106
+ modules: M[];
107
+ action: Action;
108
+ data?: M extends ModuleWithPermissions ? any : never;
109
+ }): boolean {
110
+ if (!currentUser) return false;
111
+
112
+ if (!params.modules.every((module) => !module.feature || hasAccesToFeature(module.feature))) return false;
113
+
114
+ return params.modules.every((module) =>
115
+ checkPermissions({ module: module, action: params.action, data: params.data, user: currentUser }),
116
+ );
117
+ }
118
+
119
+ function hasPermissionToPath(path: string): boolean {
120
+ if (!currentUser) return false;
121
+ if (path === "#" || path === "/") return true;
122
+
123
+ const selectedModule = matchUrlToModule({ path: path });
124
+ if (!selectedModule) return true;
125
+
126
+ const response = hasPermissionToModule({ module: selectedModule, action: Action.Read });
127
+
128
+ return response;
129
+ }
130
+
131
+ return (
132
+ <CurrentUserContext.Provider
133
+ value={{
134
+ currentUser: currentUser,
135
+ company: company,
136
+ setUser: setUser,
137
+ hasPermissionToModule: hasPermissionToModule,
138
+ hasPermissionToModules: hasPermissionToModules,
139
+ hasPermissionToPath: hasPermissionToPath,
140
+ hasAccesToFeature: hasAccesToFeature,
141
+ matchUrlToModule: matchUrlToModule,
142
+ hasRole: hasRole,
143
+ }}
144
+ >
145
+ {children}
146
+ </CurrentUserContext.Provider>
147
+ );
148
+ };
149
+
150
+ export function useCurrentUserContext<T extends UserInterface = UserInterface>(): CurrentUserContextType<T> {
151
+ const context = useContext(CurrentUserContext);
152
+ if (context === undefined) {
153
+ throw new Error("useCurrentUserContext must be used within a UserProvider");
154
+ }
155
+ return context as unknown as CurrentUserContextType<T>;
156
+ }
@@ -0,0 +1 @@
1
+ export * from "./CurrentUserContext";
@@ -0,0 +1,4 @@
1
+ export * from "./user";
2
+ export * from "./user.fields";
3
+ export * from "./user.interface";
4
+ export * from "./user.service";
@@ -0,0 +1,8 @@
1
+ export enum UserFields {
2
+ userId = "userId",
3
+ name = "name",
4
+ email = "email",
5
+ relevance = "relevance",
6
+ createdAt = "createdAt",
7
+ updatedAt = "updatedAt",
8
+ }
@@ -0,0 +1,41 @@
1
+ import { CompanyInterface } from "../../company/data/company.interface";
2
+ import { ModuleInterface } from "../../module/data/module.interface";
3
+ import { RoleInterface } from "../../role/data/role.interface";
4
+ import { ApiDataInterface } from "../../../core";
5
+
6
+ export type UserInput = {
7
+ id: string;
8
+ email?: string | undefined | null;
9
+ name?: string;
10
+ title?: string;
11
+ bio?: string;
12
+ password?: string | undefined;
13
+ roleIds?: string[];
14
+ sendInvitationEmail?: boolean;
15
+ companyId?: string;
16
+ adminCreated?: boolean;
17
+ avatar?: string;
18
+ phone?: string;
19
+ rate?: number;
20
+ };
21
+
22
+ export interface UserInterface extends ApiDataInterface {
23
+ get email(): string;
24
+ get name(): string;
25
+ get title(): string;
26
+ get bio(): string;
27
+ get avatar(): string | undefined;
28
+ get avatarUrl(): string | undefined;
29
+ get phone(): string | undefined;
30
+ get rate(): number | undefined;
31
+
32
+ get isActivated(): boolean;
33
+ get isDeleted(): boolean;
34
+ get lastLogin(): Date | undefined;
35
+
36
+ get relevance(): number | undefined;
37
+
38
+ get roles(): RoleInterface[];
39
+ get company(): CompanyInterface | undefined;
40
+ get modules(): ModuleInterface[];
41
+ }
@@ -0,0 +1,246 @@
1
+ import { AbstractService, EndpointCreator, HttpMethod, Modules, NextRef, PreviousRef } from "../../../core";
2
+ import { UserInput, UserInterface } from "./user.interface";
3
+
4
+ export class UserService extends AbstractService {
5
+ static async findFullUser(): Promise<UserInterface> {
6
+ const endpoint = new EndpointCreator({ endpoint: Modules.User, id: "me", childEndpoint: "full" });
7
+
8
+ return this.callApi<UserInterface>({
9
+ type: Modules.User,
10
+ method: HttpMethod.GET,
11
+ endpoint: endpoint.generate(),
12
+ });
13
+ }
14
+
15
+ static async findById(params: { userId: string }): Promise<UserInterface> {
16
+ return this.callApi<UserInterface>({
17
+ type: Modules.User,
18
+ method: HttpMethod.GET,
19
+ endpoint: new EndpointCreator({ endpoint: Modules.User, id: params.userId }).generate(),
20
+ });
21
+ }
22
+
23
+ static async findByEmail(params: { email: string }): Promise<UserInterface> {
24
+ const endpoint = new EndpointCreator({ endpoint: Modules.User, id: "email", childEndpoint: params.email });
25
+
26
+ return this.callApi<UserInterface>({ type: Modules.User, method: HttpMethod.GET, endpoint: endpoint.generate() });
27
+ }
28
+
29
+ static async findMany(params: {
30
+ roleId?: string;
31
+ search?: string;
32
+ fetchAll?: boolean;
33
+ includeDeleted?: boolean;
34
+ next?: NextRef;
35
+ prev?: PreviousRef;
36
+ }): Promise<UserInterface[]> {
37
+ const endpoint = new EndpointCreator({ endpoint: Modules.User });
38
+
39
+ if (params.roleId) endpoint.addAdditionalParam("roleId", params.roleId);
40
+
41
+ if (params.includeDeleted) endpoint.addAdditionalParam("includeDeleted", "true");
42
+ if (params.fetchAll) endpoint.addAdditionalParam("fetchAll", "true");
43
+ if (params.search) endpoint.addAdditionalParam("search", params.search);
44
+
45
+ return this.callApi({
46
+ type: Modules.User,
47
+ method: HttpMethod.GET,
48
+ endpoint: endpoint.generate(),
49
+ next: params.next,
50
+ });
51
+ }
52
+
53
+ static async findManyByContentIds(params: {
54
+ contentIds: string[];
55
+ search?: string;
56
+ next?: NextRef;
57
+ prev?: PreviousRef;
58
+ }): Promise<UserInterface[]> {
59
+ const endpoint = new EndpointCreator({ endpoint: Modules.User });
60
+
61
+ endpoint.addAdditionalParam("contentIds", params.contentIds.map((id) => id).join(","));
62
+ endpoint.addAdditionalParam("includeDeleted", "true");
63
+ endpoint.addAdditionalParam("fetchAll", "true");
64
+ if (params.search) endpoint.addAdditionalParam("search", params.search);
65
+
66
+ return this.callApi({
67
+ type: Modules.User,
68
+ method: HttpMethod.GET,
69
+ endpoint: endpoint.generate(),
70
+ next: params.next,
71
+ });
72
+ }
73
+
74
+ static async findRelevant(params: { id: string; next?: NextRef; prev?: PreviousRef }): Promise<UserInterface[]> {
75
+ const endpoint: EndpointCreator = new EndpointCreator({
76
+ endpoint: Modules.Content,
77
+ id: params.id,
78
+ childEndpoint: "user-relevance",
79
+ });
80
+
81
+ if (Modules.User.inclusions?.lists?.fields) endpoint.limitToFields(Modules.User.inclusions.lists.fields);
82
+ if (Modules.User.inclusions?.lists?.types) endpoint.limitToType(Modules.User.inclusions.lists.types);
83
+
84
+ return this.callApi<UserInterface[]>({
85
+ type: Modules.User,
86
+ method: HttpMethod.GET,
87
+ endpoint: endpoint.generate(),
88
+ next: params.next,
89
+ });
90
+ }
91
+
92
+ static async findManyForAmin(params: {
93
+ companyId?: string;
94
+ search?: string;
95
+ next?: NextRef;
96
+ prev?: PreviousRef;
97
+ }): Promise<UserInterface[]> {
98
+ if (!params.companyId) return [];
99
+
100
+ const endpoint = new EndpointCreator({
101
+ endpoint: Modules.Company,
102
+ id: params.companyId,
103
+ childEndpoint: Modules.User,
104
+ });
105
+
106
+ if (params.search) endpoint.addAdditionalParam("search", params.search);
107
+
108
+ return this.callApi({
109
+ type: Modules.User,
110
+ method: HttpMethod.GET,
111
+ endpoint: endpoint.generate(),
112
+ next: params.next,
113
+ previous: params.prev,
114
+ });
115
+ }
116
+
117
+ static async findAllUsers(params: {
118
+ companyId: string;
119
+ search?: string;
120
+ limitToRoles?: string[];
121
+ isDeleted?: boolean;
122
+ next?: NextRef;
123
+ prev?: PreviousRef;
124
+ }): Promise<UserInterface[]> {
125
+ const endpoint = new EndpointCreator({
126
+ endpoint: Modules.Company,
127
+ id: params.companyId,
128
+ childEndpoint: Modules.User,
129
+ });
130
+
131
+ if (params.search) endpoint.addAdditionalParam("search", params.search);
132
+ if (params.isDeleted) endpoint.addAdditionalParam("isDeleted", "true");
133
+ if (params.limitToRoles && params.limitToRoles.length > 0)
134
+ endpoint.addAdditionalParam("limitToRoles", params.limitToRoles.join(","));
135
+
136
+ return this.callApi({
137
+ type: Modules.User,
138
+ method: HttpMethod.GET,
139
+ endpoint: endpoint.generate(),
140
+ next: params.next,
141
+ });
142
+ }
143
+
144
+ static async findAllUsersByRole(params: {
145
+ roleId: string;
146
+ search?: string;
147
+ next?: NextRef;
148
+ prev?: PreviousRef;
149
+ }): Promise<UserInterface[]> {
150
+ const endpoint = new EndpointCreator({ endpoint: Modules.Role, id: params.roleId, childEndpoint: Modules.User });
151
+
152
+ if (params.search) endpoint.addAdditionalParam("search", params.search);
153
+
154
+ return this.callApi({
155
+ type: Modules.User,
156
+ method: HttpMethod.GET,
157
+ endpoint: endpoint.generate(),
158
+ next: params.next,
159
+ });
160
+ }
161
+
162
+ static async findAllUsersNotInRole(params: {
163
+ roleId: string;
164
+ search?: string;
165
+ next?: NextRef;
166
+ prev?: PreviousRef;
167
+ }): Promise<UserInterface[]> {
168
+ const endpoint = new EndpointCreator({
169
+ endpoint: Modules.Role,
170
+ id: params.roleId,
171
+ childEndpoint: Modules.User,
172
+ }).addAdditionalParam("notInRole", "true");
173
+
174
+ if (params.search) endpoint.addAdditionalParam("search", params.search);
175
+
176
+ return this.callApi({
177
+ type: Modules.User,
178
+ method: HttpMethod.GET,
179
+ endpoint: endpoint.generate(),
180
+ next: params.next,
181
+ });
182
+ }
183
+
184
+ static async create(params: UserInput): Promise<UserInterface> {
185
+ return this.callApi({
186
+ type: Modules.User,
187
+ method: HttpMethod.POST,
188
+ endpoint: new EndpointCreator({ endpoint: Modules.User }).generate(),
189
+ companyId: params.companyId,
190
+ input: params,
191
+ });
192
+ }
193
+
194
+ static async reactivate(params: { userId: string }): Promise<UserInterface> {
195
+ return this.callApi({
196
+ type: Modules.User,
197
+ method: HttpMethod.PATCH,
198
+ endpoint: new EndpointCreator({ endpoint: Modules.User, id: params.userId }).generate(),
199
+ });
200
+ }
201
+
202
+ static async sendInvitation(params: { userId: string; companyId?: string }): Promise<void> {
203
+ const endpoint = new EndpointCreator({
204
+ endpoint: Modules.User,
205
+ id: params.userId,
206
+ childEndpoint: "send-invitation-email",
207
+ });
208
+
209
+ if (params.companyId) endpoint.addAdditionalParam("companyId", params.companyId);
210
+
211
+ this.callApi({
212
+ type: Modules.User,
213
+ method: HttpMethod.POST,
214
+ endpoint: endpoint.generate(),
215
+ });
216
+ }
217
+
218
+ static async update(params: UserInput): Promise<UserInterface> {
219
+ return this.callApi({
220
+ type: Modules.User,
221
+ method: HttpMethod.PUT,
222
+ endpoint: new EndpointCreator({ endpoint: Modules.User, id: params.id }).generate(),
223
+ companyId: params.companyId,
224
+ input: params,
225
+ });
226
+ }
227
+
228
+ static async patchRate(params: UserInput): Promise<UserInterface> {
229
+ return this.callApi({
230
+ type: Modules.User,
231
+ method: HttpMethod.PATCH,
232
+ endpoint: new EndpointCreator({ endpoint: Modules.User, id: params.id, childEndpoint: "rates" }).generate(),
233
+ companyId: params.companyId,
234
+ input: params,
235
+ });
236
+ }
237
+
238
+ static async delete(params: { userId: string; companyId: string }): Promise<void> {
239
+ await this.callApi({
240
+ type: Modules.User,
241
+ method: HttpMethod.DELETE,
242
+ endpoint: new EndpointCreator({ endpoint: Modules.User, id: params.userId }).generate(),
243
+ companyId: params.companyId,
244
+ });
245
+ }
246
+ }