@carlonicora/nextjs-jsonapi 1.36.1 → 1.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/dist/{BlockNoteEditor-4MDHRUS2.js → BlockNoteEditor-74FHJO7E.js} +8 -8
  2. package/dist/{BlockNoteEditor-4MDHRUS2.js.map → BlockNoteEditor-74FHJO7E.js.map} +1 -1
  3. package/dist/{BlockNoteEditor-SZWO3MDO.mjs → BlockNoteEditor-GTWR6CPI.mjs} +4 -4
  4. package/dist/BlockNoteEditor-GTWR6CPI.mjs.map +1 -0
  5. package/dist/billing/index.d.mts +3 -3
  6. package/dist/billing/index.d.ts +3 -3
  7. package/dist/billing/index.js +365 -363
  8. package/dist/billing/index.js.map +1 -1
  9. package/dist/billing/index.mjs +80 -78
  10. package/dist/billing/index.mjs.map +1 -1
  11. package/dist/{chunk-E6PQQTWF.js → chunk-YVEK3SUS.js} +640 -1320
  12. package/dist/chunk-YVEK3SUS.js.map +1 -0
  13. package/dist/{chunk-I7DFEJFF.mjs → chunk-ZUUH4CQC.mjs} +737 -1417
  14. package/dist/chunk-ZUUH4CQC.mjs.map +1 -0
  15. package/dist/client/index.js +2 -2
  16. package/dist/client/index.mjs +1 -1
  17. package/dist/components/index.d.mts +23 -8
  18. package/dist/components/index.d.ts +23 -8
  19. package/dist/components/index.js +2 -2
  20. package/dist/components/index.mjs +1 -1
  21. package/dist/contexts/index.d.mts +1 -1
  22. package/dist/contexts/index.d.ts +1 -1
  23. package/dist/contexts/index.js +2 -2
  24. package/dist/contexts/index.mjs +1 -1
  25. package/dist/testing/index.js.map +1 -1
  26. package/dist/testing/index.mjs.map +1 -1
  27. package/package.json +2 -2
  28. package/src/client/context/JsonApiProvider.tsx +1 -5
  29. package/src/client/hooks/__tests__/useJsonApiGet.test.tsx +9 -9
  30. package/src/client/hooks/__tests__/useJsonApiMutation.test.tsx +11 -11
  31. package/src/client/hooks/__tests__/useRehydration.test.ts +13 -34
  32. package/src/components/editors/BlockNoteEditor.tsx +2 -2
  33. package/src/components/forms/CommonEditorTrigger.tsx +1 -1
  34. package/src/components/forms/FormCheckbox.tsx +2 -12
  35. package/src/components/forms/FormDate.tsx +1 -6
  36. package/src/components/forms/FormInput.tsx +1 -1
  37. package/src/components/forms/FormPassword.tsx +1 -7
  38. package/src/components/forms/FormSelect.tsx +2 -8
  39. package/src/components/forms/FormSlider.tsx +1 -5
  40. package/src/components/forms/FormSwitch.tsx +1 -5
  41. package/src/components/forms/GdprConsentCheckbox.tsx +2 -8
  42. package/src/components/forms/PasswordInput.tsx +28 -26
  43. package/src/components/forms/__tests__/FormCheckbox.test.tsx +16 -18
  44. package/src/components/forms/__tests__/FormDate.test.tsx +14 -30
  45. package/src/components/forms/__tests__/FormInput.test.tsx +21 -37
  46. package/src/components/forms/__tests__/FormSelect.test.tsx +15 -21
  47. package/src/components/tables/ContentListTable.tsx +1 -1
  48. package/src/components/tables/__tests__/ContentListTable.test.tsx +17 -89
  49. package/src/components/tables/cells/cell.component.tsx +1 -1
  50. package/src/contexts/HeaderChildrenContext.tsx +3 -1
  51. package/src/core/endpoint/__tests__/EndpointCreator.test.ts +2 -7
  52. package/src/core/factories/__tests__/JsonApiDataFactory.test.ts +3 -3
  53. package/src/core/factories/__tests__/RehydrationFactory.test.ts +4 -6
  54. package/src/core/registry/__tests__/DataClassRegistry.test.ts +5 -15
  55. package/src/core/registry/__tests__/ModuleRegistrar.test.ts +5 -15
  56. package/src/features/auth/components/GdprConsentSection.tsx +1 -6
  57. package/src/features/auth/components/details/LandingComponent.tsx +6 -1
  58. package/src/features/auth/components/forms/AcceptInvitation.tsx +1 -1
  59. package/src/features/auth/components/forms/ResetPassword.tsx +1 -1
  60. package/src/features/billing/components/cards/PaymentMethodSummaryCard.tsx +13 -18
  61. package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +7 -1
  62. package/src/features/billing/components/modals/BillingDetailModal.tsx +2 -13
  63. package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +8 -1
  64. package/src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx +2 -13
  65. package/src/features/billing/stripe-customer/components/forms/PaymentMethodForm.tsx +2 -12
  66. package/src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx +6 -1
  67. package/src/features/billing/stripe-price/components/lists/PricesList.tsx +13 -5
  68. package/src/features/billing/stripe-product/components/lists/ProductsList.tsx +5 -5
  69. package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +1 -3
  70. package/src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx +4 -1
  71. package/src/features/billing/stripe-subscription/components/forms/CancelSubscriptionDialog.tsx +1 -1
  72. package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +4 -1
  73. package/src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx +9 -2
  74. package/src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx +3 -1
  75. package/src/features/billing/stripe-subscription/components/wizards/SubscriptionWizard.tsx +1 -7
  76. package/src/features/billing/stripe-subscription/components/wizards/WizardProgressIndicator.tsx +2 -10
  77. package/src/features/billing/stripe-subscription/components/wizards/WizardStepPaymentMethod.tsx +3 -13
  78. package/src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx +5 -16
  79. package/src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx +1 -1
  80. package/src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx +1 -1
  81. package/src/features/company/components/details/CompanyDetails.tsx +2 -2
  82. package/src/features/company/components/forms/CompanyConfigurationSecurityForm.tsx +1 -1
  83. package/src/features/notification/components/containers/NotificationsListContainer.tsx +1 -1
  84. package/src/features/notification/components/modals/NotificationModal.tsx +6 -2
  85. package/src/features/notification/contexts/NotificationContext.tsx +1 -3
  86. package/src/features/oauth/components/OAuthClientCard.tsx +15 -17
  87. package/src/features/oauth/components/OAuthClientDetail.tsx +7 -19
  88. package/src/features/oauth/components/OAuthClientForm.tsx +4 -13
  89. package/src/features/oauth/components/OAuthClientSecretDisplay.tsx +4 -20
  90. package/src/features/oauth/components/OAuthRedirectUriInput.tsx +5 -12
  91. package/src/features/oauth/components/OAuthScopeSelector.tsx +17 -23
  92. package/src/features/oauth/components/consent/OAuthConsentActions.tsx +3 -16
  93. package/src/features/oauth/components/consent/OAuthConsentHeader.tsx +3 -12
  94. package/src/features/oauth/components/consent/OAuthConsentScreen.tsx +5 -20
  95. package/src/features/oauth/components/consent/OAuthScopeList.tsx +3 -18
  96. package/src/features/onboarding/contexts/OnboardingContext.tsx +3 -3
  97. package/src/features/role/components/forms/FormRoles.tsx +1 -7
  98. package/src/features/user/components/containers/UserContainer.tsx +1 -1
  99. package/src/features/user/components/details/UserDetails.tsx +1 -1
  100. package/src/features/user/components/forms/UserDeleter.tsx +1 -1
  101. package/src/features/user/components/forms/UserEditor.tsx +1 -1
  102. package/src/features/user/components/forms/UserMultiSelect.tsx +7 -7
  103. package/src/features/user/components/lists/UserListInAdd.tsx +2 -2
  104. package/src/features/user/components/lists/UsersList.tsx +7 -1
  105. package/src/features/user/contexts/CurrentUserContext.tsx +36 -33
  106. package/src/hooks/__tests__/useDataListRetriever.test.ts +15 -21
  107. package/src/hooks/__tests__/useDebounce.test.ts +2 -7
  108. package/src/hooks/useCustomD3Graph.tsx +2 -2
  109. package/src/shadcnui/custom/multi-select.tsx +28 -2
  110. package/src/shadcnui/ui/accordion.tsx +21 -23
  111. package/src/shadcnui/ui/alert-dialog.tsx +45 -62
  112. package/src/shadcnui/ui/alert.tsx +25 -41
  113. package/src/shadcnui/ui/avatar.tsx +23 -36
  114. package/src/shadcnui/ui/badge.tsx +13 -11
  115. package/src/shadcnui/ui/breadcrumb.tsx +21 -55
  116. package/src/shadcnui/ui/button.tsx +17 -18
  117. package/src/shadcnui/ui/calendar.tsx +44 -93
  118. package/src/shadcnui/ui/carousel.tsx +72 -100
  119. package/src/shadcnui/ui/chart.tsx +102 -161
  120. package/src/shadcnui/ui/checkbox.tsx +8 -9
  121. package/src/shadcnui/ui/combobox.tsx +52 -83
  122. package/src/shadcnui/ui/command.tsx +43 -77
  123. package/src/shadcnui/ui/context-menu.tsx +47 -86
  124. package/src/shadcnui/ui/dialog.tsx +34 -60
  125. package/src/shadcnui/ui/drawer.tsx +32 -53
  126. package/src/shadcnui/ui/dropdown-menu.tsx +48 -65
  127. package/src/shadcnui/ui/field.tsx +39 -48
  128. package/src/shadcnui/ui/hover-card.tsx +9 -14
  129. package/src/shadcnui/ui/input-group.tsx +44 -55
  130. package/src/shadcnui/ui/input-otp.tsx +22 -26
  131. package/src/shadcnui/ui/input.tsx +6 -6
  132. package/src/shadcnui/ui/label.tsx +6 -6
  133. package/src/shadcnui/ui/navigation-menu.tsx +36 -60
  134. package/src/shadcnui/ui/popover.tsx +15 -38
  135. package/src/shadcnui/ui/progress.tsx +12 -29
  136. package/src/shadcnui/ui/radio-group.tsx +9 -15
  137. package/src/shadcnui/ui/resizable.tsx +14 -24
  138. package/src/shadcnui/ui/scroll-area.tsx +12 -27
  139. package/src/shadcnui/ui/select.tsx +41 -65
  140. package/src/shadcnui/ui/separator.tsx +7 -11
  141. package/src/shadcnui/ui/sheet.tsx +30 -55
  142. package/src/shadcnui/ui/sidebar.tsx +141 -189
  143. package/src/shadcnui/ui/skeleton.tsx +3 -9
  144. package/src/shadcnui/ui/slider.tsx +11 -23
  145. package/src/shadcnui/ui/switch.tsx +8 -8
  146. package/src/shadcnui/ui/tabs.tsx +14 -21
  147. package/src/shadcnui/ui/textarea.tsx +5 -5
  148. package/src/shadcnui/ui/toggle.tsx +8 -14
  149. package/src/shadcnui/ui/tooltip.tsx +11 -23
  150. package/src/testing/providers/MockJsonApiProvider.tsx +1 -5
  151. package/src/testing/utils/renderWithProviders.tsx +6 -10
  152. package/dist/BlockNoteEditor-SZWO3MDO.mjs.map +0 -1
  153. package/dist/chunk-E6PQQTWF.js.map +0 -1
  154. package/dist/chunk-I7DFEJFF.mjs.map +0 -1
@@ -49,28 +49,29 @@ export function OAuthScopeSelector({
49
49
  onChange(value.filter((s) => s !== scope));
50
50
  }
51
51
  },
52
- [value, onChange]
52
+ [value, onChange],
53
53
  );
54
54
 
55
55
  // Group scopes by category (before the colon)
56
- const groupedScopes = availableScopes.reduce((acc, scope) => {
57
- const [category] = scope.scope.split(":");
58
- const groupName = category === scope.scope ? "General" : category;
56
+ const groupedScopes = availableScopes.reduce(
57
+ (acc, scope) => {
58
+ const [category] = scope.scope.split(":");
59
+ const groupName = category === scope.scope ? "General" : category;
59
60
 
60
- if (!acc[groupName]) {
61
- acc[groupName] = [];
62
- }
63
- acc[groupName].push(scope);
64
- return acc;
65
- }, {} as Record<string, OAuthScopeInfo[]>);
61
+ if (!acc[groupName]) {
62
+ acc[groupName] = [];
63
+ }
64
+ acc[groupName].push(scope);
65
+ return acc;
66
+ },
67
+ {} as Record<string, OAuthScopeInfo[]>,
68
+ );
66
69
 
67
70
  return (
68
71
  <div className="space-y-4">
69
72
  <div>
70
73
  <Label>{label} *</Label>
71
- <p className="text-sm text-muted-foreground">
72
- Select the permissions your application needs.
73
- </p>
74
+ <p className="text-sm text-muted-foreground">Select the permissions your application needs.</p>
74
75
  </div>
75
76
 
76
77
  <div className="space-y-4">
@@ -92,20 +93,13 @@ export function OAuthScopeSelector({
92
93
  <Checkbox
93
94
  id={`scope-${scopeInfo.scope}`}
94
95
  checked={isChecked}
95
- onCheckedChange={(checked) =>
96
- handleToggle(scopeInfo.scope, checked === true)
97
- }
96
+ onCheckedChange={(checked) => handleToggle(scopeInfo.scope, checked === true)}
98
97
  disabled={disabled}
99
98
  />
100
99
  <div className="flex-1">
101
- <Label
102
- htmlFor={`scope-${scopeInfo.scope}`}
103
- className="text-sm font-medium cursor-pointer"
104
- >
100
+ <Label htmlFor={`scope-${scopeInfo.scope}`} className="text-sm font-medium cursor-pointer">
105
101
  {scopeInfo.name}
106
- {isAdmin && (
107
- <span className="ml-2 text-xs text-destructive">(Dangerous)</span>
108
- )}
102
+ {isAdmin && <span className="ml-2 text-xs text-destructive">(Dangerous)</span>}
109
103
  </Label>
110
104
  <p className="text-xs text-muted-foreground">{scopeInfo.description}</p>
111
105
  </div>
@@ -14,26 +14,13 @@ export interface OAuthConsentActionsProps {
14
14
  /**
15
15
  * Action buttons for OAuth consent screen
16
16
  */
17
- export function OAuthConsentActions({
18
- onApprove,
19
- onDeny,
20
- isLoading = false,
21
- }: OAuthConsentActionsProps) {
17
+ export function OAuthConsentActions({ onApprove, onDeny, isLoading = false }: OAuthConsentActionsProps) {
22
18
  return (
23
19
  <div className="flex flex-col sm:flex-row gap-3">
24
- <Button
25
- variant="outline"
26
- onClick={onDeny}
27
- disabled={isLoading}
28
- className="flex-1"
29
- >
20
+ <Button variant="outline" onClick={onDeny} disabled={isLoading} className="flex-1">
30
21
  Deny
31
22
  </Button>
32
- <Button
33
- onClick={onApprove}
34
- disabled={isLoading}
35
- className="flex-1"
36
- >
23
+ <Button onClick={onApprove} disabled={isLoading} className="flex-1">
37
24
  {isLoading ? "Authorizing..." : "Authorize"}
38
25
  </Button>
39
26
  </div>
@@ -16,21 +16,13 @@ export interface OAuthConsentHeaderProps {
16
16
  * Header component for OAuth consent screen
17
17
  * Shows platform logo and requesting app information
18
18
  */
19
- export function OAuthConsentHeader({
20
- client,
21
- logoUrl,
22
- appName = "Only35",
23
- }: OAuthConsentHeaderProps) {
19
+ export function OAuthConsentHeader({ client, logoUrl, appName = "Only35" }: OAuthConsentHeaderProps) {
24
20
  return (
25
21
  <div className="text-center space-y-4">
26
22
  {/* Platform Logo */}
27
23
  <div className="flex justify-center">
28
24
  {logoUrl ? (
29
- <img
30
- src={logoUrl}
31
- alt={appName}
32
- className="h-12 w-auto"
33
- />
25
+ <img src={logoUrl} alt={appName} className="h-12 w-auto" />
34
26
  ) : (
35
27
  <div className="h-12 w-12 rounded-full bg-primary flex items-center justify-center">
36
28
  <Shield className="h-6 w-6 text-primary-foreground" />
@@ -42,8 +34,7 @@ export function OAuthConsentHeader({
42
34
  <div className="space-y-2">
43
35
  <h1 className="text-2xl font-bold">Authorize {client.name}</h1>
44
36
  <p className="text-muted-foreground">
45
- <span className="font-medium text-foreground">{client.name}</span>
46
- {" "}wants to access your {appName} account
37
+ <span className="font-medium text-foreground">{client.name}</span> wants to access your {appName} account
47
38
  </p>
48
39
  </div>
49
40
  </div>
@@ -1,14 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { ExternalLink, AlertTriangle, Loader2 } from "lucide-react";
4
- import {
5
- Card,
6
- CardContent,
7
- CardFooter,
8
- Separator,
9
- Alert,
10
- AlertDescription,
11
- } from "../../../../shadcnui";
4
+ import { Card, CardContent, CardFooter, Separator, Alert, AlertDescription } from "../../../../shadcnui";
12
5
  import { OAuthConsentHeader } from "./OAuthConsentHeader";
13
6
  import { OAuthScopeList } from "./OAuthScopeList";
14
7
  import { OAuthConsentActions } from "./OAuthConsentActions";
@@ -92,11 +85,7 @@ export function OAuthConsentScreen({
92
85
  <Card className="w-full max-w-md">
93
86
  <CardContent className="pt-6 space-y-6">
94
87
  {/* Header */}
95
- <OAuthConsentHeader
96
- client={client}
97
- logoUrl={logoUrl}
98
- appName={appName}
99
- />
88
+ <OAuthConsentHeader client={client} logoUrl={logoUrl} appName={appName} />
100
89
 
101
90
  <Separator />
102
91
 
@@ -115,11 +104,7 @@ export function OAuthConsentScreen({
115
104
  </div>
116
105
 
117
106
  {/* Actions */}
118
- <OAuthConsentActions
119
- onApprove={approve}
120
- onDeny={deny}
121
- isLoading={isSubmitting}
122
- />
107
+ <OAuthConsentActions onApprove={approve} onDeny={deny} isLoading={isSubmitting} />
123
108
  </CardContent>
124
109
 
125
110
  {/* Footer */}
@@ -128,8 +113,8 @@ export function OAuthConsentScreen({
128
113
  By authorizing, you agree to the app's{" "}
129
114
  <a href={termsUrl} className="underline hover:text-foreground" target="_blank" rel="noopener">
130
115
  Terms of Service
131
- </a>
132
- {" "}and{" "}
116
+ </a>{" "}
117
+ and{" "}
133
118
  <a href={privacyUrl} className="underline hover:text-foreground" target="_blank" rel="noopener">
134
119
  Privacy Policy
135
120
  </a>
@@ -1,16 +1,6 @@
1
1
  "use client";
2
2
 
3
- import {
4
- Eye,
5
- Pencil,
6
- Image,
7
- Upload,
8
- Film,
9
- FolderPlus,
10
- User,
11
- Shield,
12
- LucideIcon,
13
- } from "lucide-react";
3
+ import { Eye, Pencil, Image, Upload, Film, FolderPlus, User, Shield, LucideIcon } from "lucide-react";
14
4
  import { OAuthScopeInfo } from "../../interfaces/oauth.interface";
15
5
 
16
6
  export interface OAuthScopeListProps {
@@ -48,15 +38,10 @@ export function OAuthScopeList({ scopes }: OAuthScopeListProps) {
48
38
  const IconComponent = scope.icon ? SCOPE_ICONS[scope.icon] : Eye;
49
39
 
50
40
  return (
51
- <li
52
- key={scope.scope}
53
- className="flex items-start gap-3 p-3 rounded-lg bg-muted/50"
54
- >
41
+ <li key={scope.scope} className="flex items-start gap-3 p-3 rounded-lg bg-muted/50">
55
42
  <div className="flex-shrink-0 mt-0.5">
56
43
  <div className="h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center">
57
- {IconComponent && (
58
- <IconComponent className="h-4 w-4 text-primary" />
59
- )}
44
+ {IconComponent && <IconComponent className="h-4 w-4 text-primary" />}
60
45
  </div>
61
46
  </div>
62
47
  <div className="flex-1">
@@ -18,10 +18,10 @@ const OnboardingContext = createContext<OnboardingContextValue | null>(null);
18
18
  export function OnboardingProvider({
19
19
  children,
20
20
  tours = [],
21
- tourPaths = {},
21
+ tourPaths: _tourPaths = {},
22
22
  labels = DEFAULT_ONBOARDING_LABELS,
23
23
  renderCard,
24
- zIndex = 9999,
24
+ zIndex: _zIndex = 9999,
25
25
  }: OnboardingProviderProps) {
26
26
  const [isTourActive, setIsTourActive] = useState(false);
27
27
  const [activeTourId, setActiveTourId] = useState<string | null>(null);
@@ -35,7 +35,7 @@ export function OnboardingProvider({
35
35
  rootsRef.current.forEach((root) => {
36
36
  try {
37
37
  root.unmount();
38
- } catch (e) {
38
+ } catch (_e) {
39
39
  // Root may already be unmounted
40
40
  }
41
41
  });
@@ -2,13 +2,7 @@
2
2
 
3
3
  import { useTranslations } from "next-intl";
4
4
  import { FormFieldWrapper } from "../../../../components/forms";
5
- import {
6
- Checkbox,
7
- FieldLabel,
8
- Tooltip,
9
- TooltipContent,
10
- TooltipTrigger,
11
- } from "../../../../shadcnui";
5
+ import { Checkbox, FieldLabel, Tooltip, TooltipContent, TooltipTrigger } from "../../../../shadcnui";
12
6
  import { UserInterface } from "../../../user";
13
7
  import { useCurrentUserContext } from "../../../user/contexts";
14
8
  import { RoleInterface } from "../../data";
@@ -8,7 +8,7 @@ export function UserContainer() {
8
8
  const { user } = useUserContext();
9
9
  if (!user) return null;
10
10
 
11
- const t = useTranslations();
11
+ const _t = useTranslations();
12
12
 
13
13
  return (
14
14
  <div className="flex w-full gap-x-4">
@@ -26,7 +26,7 @@ export function UserDetails({ user }: UserDetailsProps) {
26
26
  roles = (
27
27
  <div className="mb-4 w-full">
28
28
  <div className="flex flex-wrap gap-2">
29
- {user.roles.map((role: RoleInterface, index: number) => (
29
+ {user.roles.map((role: RoleInterface, _index: number) => (
30
30
  <Link key={role.id} href={generateUrl({ page: Modules.Role, id: role.id })}>
31
31
  <Badge className="mr-2" variant={`default`}>
32
32
  {t(`role.roles`, { role: role.id.replaceAll(`-`, ``) })}
@@ -20,7 +20,7 @@ function UserDeleterInternal({ user, onDeleted, companyId }: UserDeleterProps) {
20
20
  const { currentUser, company } = useCurrentUserContext<UserInterface>();
21
21
  const generateUrl = usePageUrlGenerator();
22
22
  const router = useI18nRouter();
23
- const t = useTranslations();
23
+ const _t = useTranslations();
24
24
 
25
25
  let cId;
26
26
  if (currentUser?.roles.find((role) => role.id === getRoleId().Administrator) && companyId) {
@@ -106,7 +106,7 @@ function UserEditorInternal({ user, propagateChanges, adminCreated, trigger, onR
106
106
  errorToast({ title: t(`user.errors.email_exists`), error: "" });
107
107
  return;
108
108
  }
109
- } catch (error) {
109
+ } catch (_error) {
110
110
  // User does not exist, proceed
111
111
  }
112
112
  }
@@ -1,16 +1,12 @@
1
1
  "use client";
2
2
 
3
+ import { useTranslations } from "next-intl";
3
4
  import { useCallback, useEffect, useRef, useState } from "react";
4
5
  import { useWatch } from "react-hook-form";
5
6
  import { FormFieldWrapper } from "../../../../components/forms";
6
7
  import { Modules } from "../../../../core";
7
8
  import { DataListRetriever, useDataListRetriever, useDebounce } from "../../../../hooks";
8
- import {
9
- Avatar,
10
- AvatarFallback,
11
- AvatarImage,
12
- MultiSelect,
13
- } from "../../../../shadcnui";
9
+ import { Avatar, AvatarFallback, AvatarImage, MultiSelect } from "../../../../shadcnui";
14
10
  import { useCurrentUserContext } from "../../contexts";
15
11
  import { UserInterface } from "../../data";
16
12
  import { UserService } from "../../data/user.service";
@@ -59,10 +55,11 @@ export function UserMultiSelect({
59
55
  maxCount = 3,
60
56
  isRequired = false,
61
57
  }: UserMultiSelectProps) {
58
+ const t = useTranslations();
62
59
  const { company } = useCurrentUserContext<UserInterface>();
63
60
 
64
61
  const searchTermRef = useRef<string>("");
65
- const [searchTerm, setSearchTerm] = useState<string>("");
62
+ const [searchTerm, _setSearchTerm] = useState<string>("");
66
63
  const [isSearching, setIsSearching] = useState<boolean>(false);
67
64
  const [userOptions, setUserOptions] = useState<any[]>([]);
68
65
 
@@ -194,6 +191,9 @@ export function UserMultiSelect({
194
191
  placeholder={placeholder}
195
192
  maxCount={maxCount}
196
193
  animation={0}
194
+ loading={isSearching}
195
+ loadingText={t("ui.search.button")}
196
+ emptyText={t("ui.search.no_results", { type: t("entities.users", { count: 2 }) })}
197
197
  />
198
198
  )}
199
199
  </FormFieldWrapper>
@@ -28,11 +28,11 @@ export function UserListInAdd({ data, existingUsers, setSelectedUser, setLevelOp
28
28
  <CommandItem
29
29
  className="cursor-pointer hover:bg-muted data-selected:hover:bg-muted bg-transparent data-selected:bg-transparent"
30
30
  key={user.id}
31
- onClick={(e) => {
31
+ onClick={(_e) => {
32
32
  setSelectedUser(user);
33
33
  setLevelOpen?.(true);
34
34
  }}
35
- onSelect={(e) => {
35
+ onSelect={(_e) => {
36
36
  setSelectedUser(user);
37
37
  setLevelOpen?.(true);
38
38
  }}
@@ -16,7 +16,13 @@ type UsersListProps = {
16
16
  restrictToJoinRequests?: boolean;
17
17
  };
18
18
 
19
- export function UsersList({ data, optionComponents, removeFunction, hideOptions, showRelevance }: UsersListProps) {
19
+ export function UsersList({
20
+ data,
21
+ optionComponents: _optionComponents,
22
+ removeFunction: _removeFunction,
23
+ hideOptions: _hideOptions,
24
+ showRelevance: _showRelevance,
25
+ }: UsersListProps) {
20
26
  const t = useTranslations();
21
27
 
22
28
  return (
@@ -51,7 +51,7 @@ export const CurrentUserProvider = ({ children }: { children: React.ReactNode })
51
51
  if (!token && dehydratedUser) setDehydratedUser(null);
52
52
  }, [dehydratedUser, setDehydratedUser]);
53
53
 
54
- const matchUrlToModule = (params?: { path: string }): ModuleWithPermissions | undefined => {
54
+ const matchUrlToModule = (_params?: { path: string }): ModuleWithPermissions | undefined => {
55
55
  const moduleKeys = Object.getOwnPropertyNames(Modules).filter(
56
56
  (key) => key !== "prototype" && key !== "_factory" && key !== "length" && key !== "name",
57
57
  );
@@ -138,41 +138,44 @@ export const CurrentUserProvider = ({ children }: { children: React.ReactNode })
138
138
  // Function to refresh user data from the API
139
139
  // skipCookieUpdate: When true, only updates React state without calling the Server Action
140
140
  // This prevents page reloads when refresh is triggered by WebSocket events
141
- const refreshUser = useCallback(async (options?: { skipCookieUpdate?: boolean }): Promise<void> => {
142
- if (isRefreshing) {
143
- return;
144
- }
141
+ const refreshUser = useCallback(
142
+ async (options?: { skipCookieUpdate?: boolean }): Promise<void> => {
143
+ if (isRefreshing) {
144
+ return;
145
+ }
145
146
 
146
- setIsRefreshing(true);
147
- try {
148
- const fullUser = await UserService.findFullUser();
149
- if (fullUser) {
150
- const dehydrated = fullUser.dehydrate();
151
-
152
- setDehydratedUser(dehydrated as any);
153
- setUser(fullUser);
154
-
155
- // Update authentication cookies with fresh user data
156
- // Skip when triggered by WebSocket to prevent page reload (Server Actions modify cookies)
157
- if (!options?.skipCookieUpdate) {
158
- await getTokenHandler()?.updateToken({
159
- userId: fullUser.id,
160
- companyId: fullUser.company?.id,
161
- roles: fullUser.roles.map((role) => role.id),
162
- features: fullUser.company?.features?.map((feature) => feature.id) ?? [],
163
- modules: fullUser.modules.map((module) => ({
164
- id: module.id,
165
- permissions: module.permissions,
166
- })),
167
- });
147
+ setIsRefreshing(true);
148
+ try {
149
+ const fullUser = await UserService.findFullUser();
150
+ if (fullUser) {
151
+ const dehydrated = fullUser.dehydrate();
152
+
153
+ setDehydratedUser(dehydrated as any);
154
+ setUser(fullUser);
155
+
156
+ // Update authentication cookies with fresh user data
157
+ // Skip when triggered by WebSocket to prevent page reload (Server Actions modify cookies)
158
+ if (!options?.skipCookieUpdate) {
159
+ await getTokenHandler()?.updateToken({
160
+ userId: fullUser.id,
161
+ companyId: fullUser.company?.id,
162
+ roles: fullUser.roles.map((role) => role.id),
163
+ features: fullUser.company?.features?.map((feature) => feature.id) ?? [],
164
+ modules: fullUser.modules.map((module) => ({
165
+ id: module.id,
166
+ permissions: module.permissions,
167
+ })),
168
+ });
169
+ }
168
170
  }
171
+ } catch (error) {
172
+ console.error("Failed to refresh user data:", error);
173
+ } finally {
174
+ setIsRefreshing(false);
169
175
  }
170
- } catch (error) {
171
- console.error("Failed to refresh user data:", error);
172
- } finally {
173
- setIsRefreshing(false);
174
- }
175
- }, [isRefreshing, setDehydratedUser]);
176
+ },
177
+ [isRefreshing, setDehydratedUser],
178
+ );
176
179
 
177
180
  // WebSocket integration for real-time token updates
178
181
  const { socket, isConnected } = useSocketContext();
@@ -22,7 +22,7 @@ describe("useDataListRetriever", () => {
22
22
  useDataListRetriever({
23
23
  retriever,
24
24
  module: mockModule,
25
- })
25
+ }),
26
26
  );
27
27
 
28
28
  // Wait for async operations to settle
@@ -42,7 +42,7 @@ describe("useDataListRetriever", () => {
42
42
  retriever,
43
43
  module: mockModule,
44
44
  ready: false,
45
- })
45
+ }),
46
46
  );
47
47
 
48
48
  expect(result.current.ready).toBe(false);
@@ -63,7 +63,7 @@ describe("useDataListRetriever", () => {
63
63
  useDataListRetriever({
64
64
  retriever,
65
65
  module: mockModule,
66
- })
66
+ }),
67
67
  );
68
68
 
69
69
  await waitFor(() => {
@@ -82,7 +82,7 @@ describe("useDataListRetriever", () => {
82
82
  useDataListRetriever({
83
83
  retriever,
84
84
  module: mockModule,
85
- })
85
+ }),
86
86
  );
87
87
 
88
88
  await waitFor(() => {
@@ -96,16 +96,14 @@ describe("useDataListRetriever", () => {
96
96
 
97
97
  describe("search", () => {
98
98
  it("should search and call retriever with search term", async () => {
99
- const mockData = [
100
- createMockApiData({ type: "articles", id: "1", attributes: { title: "Search Result" } }),
101
- ];
99
+ const mockData = [createMockApiData({ type: "articles", id: "1", attributes: { title: "Search Result" } })];
102
100
  const retriever = vi.fn().mockResolvedValue(mockData);
103
101
 
104
102
  const { result } = renderHook(() =>
105
103
  useDataListRetriever({
106
104
  retriever,
107
105
  module: mockModule,
108
- })
106
+ }),
109
107
  );
110
108
 
111
109
  await waitFor(() => {
@@ -133,7 +131,7 @@ describe("useDataListRetriever", () => {
133
131
  useDataListRetriever({
134
132
  retriever,
135
133
  module: mockModule,
136
- })
134
+ }),
137
135
  );
138
136
 
139
137
  await waitFor(() => {
@@ -161,7 +159,7 @@ describe("useDataListRetriever", () => {
161
159
  useDataListRetriever({
162
160
  retriever,
163
161
  module: mockModule,
164
- })
162
+ }),
165
163
  );
166
164
 
167
165
  await waitFor(() => {
@@ -189,7 +187,7 @@ describe("useDataListRetriever", () => {
189
187
  retriever,
190
188
  module: mockModule,
191
189
  ready: false,
192
- })
190
+ }),
193
191
  );
194
192
 
195
193
  expect(result.current.ready).toBe(false);
@@ -209,16 +207,14 @@ describe("useDataListRetriever", () => {
209
207
 
210
208
  describe("element management", () => {
211
209
  it("should update element with setRefreshedElement", async () => {
212
- const mockData = [
213
- createMockApiData({ type: "articles", id: "1", attributes: { title: "Original" } }),
214
- ];
210
+ const mockData = [createMockApiData({ type: "articles", id: "1", attributes: { title: "Original" } })];
215
211
  const retriever = vi.fn().mockResolvedValue(mockData);
216
212
 
217
213
  const { result } = renderHook(() =>
218
214
  useDataListRetriever({
219
215
  retriever,
220
216
  module: mockModule,
221
- })
217
+ }),
222
218
  );
223
219
 
224
220
  await waitFor(() => {
@@ -250,7 +246,7 @@ describe("useDataListRetriever", () => {
250
246
  useDataListRetriever({
251
247
  retriever,
252
248
  module: mockModule,
253
- })
249
+ }),
254
250
  );
255
251
 
256
252
  await waitFor(() => {
@@ -276,7 +272,7 @@ describe("useDataListRetriever", () => {
276
272
  useDataListRetriever({
277
273
  retriever,
278
274
  module: mockModule,
279
- })
275
+ }),
280
276
  );
281
277
 
282
278
  await waitFor(() => {
@@ -288,9 +284,7 @@ describe("useDataListRetriever", () => {
288
284
  });
289
285
 
290
286
  await waitFor(() => {
291
- expect(retriever).toHaveBeenCalledWith(
292
- expect.objectContaining({ filter: "active" })
293
- );
287
+ expect(retriever).toHaveBeenCalledWith(expect.objectContaining({ filter: "active" }));
294
288
  });
295
289
  });
296
290
 
@@ -301,7 +295,7 @@ describe("useDataListRetriever", () => {
301
295
  useDataListRetriever({
302
296
  retriever,
303
297
  module: mockModule,
304
- })
298
+ }),
305
299
  );
306
300
 
307
301
  await waitFor(() => {
@@ -92,9 +92,7 @@ describe("useDebounce", () => {
92
92
 
93
93
  it("should pass multiple arguments to callback", () => {
94
94
  const callback = vi.fn();
95
- const { result } = renderHook(() =>
96
- useDebounce((a: string, b: number, c: boolean) => callback(a, b, c), 500)
97
- );
95
+ const { result } = renderHook(() => useDebounce((a: string, b: number, c: boolean) => callback(a, b, c), 500));
98
96
 
99
97
  act(() => {
100
98
  result.current("hello", 42, true);
@@ -111,10 +109,7 @@ describe("useDebounce", () => {
111
109
  const callback1 = vi.fn();
112
110
  const callback2 = vi.fn();
113
111
 
114
- const { result, rerender } = renderHook(
115
- ({ cb }) => useDebounce(cb, 500),
116
- { initialProps: { cb: callback1 } }
117
- );
112
+ const { result, rerender } = renderHook(({ cb }) => useDebounce(cb, 500), { initialProps: { cb: callback1 } });
118
113
 
119
114
  act(() => {
120
115
  result.current("test");
@@ -269,7 +269,7 @@ export function useCustomD3Graph(
269
269
  }
270
270
  });
271
271
 
272
- for (const [nodeId, node] of nodeHierarchy.entries()) {
272
+ for (const [_nodeId, node] of nodeHierarchy.entries()) {
273
273
  if (node.depth === 1 && node.angle !== undefined && node.x !== undefined && node.y !== undefined) {
274
274
  const childAngle = node.angle;
275
275
  const childX = node.x;
@@ -527,7 +527,7 @@ export function useCustomD3Graph(
527
527
  const Icon = d.icon as React.FC<{ size: number; color: string }>;
528
528
  const iconSvg = renderToStaticMarkup(<Icon size={nodeRadius / 2} color="white" />);
529
529
 
530
- const iconGroup = d3
530
+ const _iconGroup = d3
531
531
  .select(this)
532
532
  .append("g")
533
533
  .html(iconSvg)