@carlonicora/nextjs-jsonapi 1.65.1 → 1.67.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 (93) hide show
  1. package/dist/{AuthComponent-B4rNZRYE.d.ts → AuthComponent-DL1D3y7f.d.ts} +1 -1
  2. package/dist/{AuthComponent-nzabiz68.d.mts → AuthComponent-NwQ_ZXsv.d.mts} +1 -1
  3. package/dist/{BlockNoteEditor-QGNV6E4X.js → BlockNoteEditor-QHWPE3BJ.js} +14 -14
  4. package/dist/{BlockNoteEditor-QGNV6E4X.js.map → BlockNoteEditor-QHWPE3BJ.js.map} +1 -1
  5. package/dist/{BlockNoteEditor-CZOW7J5K.mjs → BlockNoteEditor-TIX3GDVZ.mjs} +4 -4
  6. package/dist/{auth.interface-C1WjZ0fM.d.ts → auth.interface-BX_1qZZJ.d.ts} +1 -1
  7. package/dist/{auth.interface-fBFqIrw4.d.mts → auth.interface-yeLelxdI.d.mts} +1 -1
  8. package/dist/billing/index.js +346 -346
  9. package/dist/billing/index.mjs +3 -3
  10. package/dist/{chunk-CDCGQFIA.js → chunk-3BWYWS3A.js} +2118 -1659
  11. package/dist/chunk-3BWYWS3A.js.map +1 -0
  12. package/dist/{chunk-LRXJT656.js → chunk-CJY63D6U.js} +72 -5
  13. package/dist/chunk-CJY63D6U.js.map +1 -0
  14. package/dist/{chunk-RA4RYKYB.js → chunk-KFIQTY4O.js} +11 -11
  15. package/dist/{chunk-RA4RYKYB.js.map → chunk-KFIQTY4O.js.map} +1 -1
  16. package/dist/{chunk-G7PGWMFO.mjs → chunk-RIG2BEXJ.mjs} +72 -5
  17. package/dist/{chunk-G7PGWMFO.mjs.map → chunk-RIG2BEXJ.mjs.map} +1 -1
  18. package/dist/{chunk-ESGUCYJS.mjs → chunk-WWP32QYC.mjs} +3534 -3075
  19. package/dist/chunk-WWP32QYC.mjs.map +1 -0
  20. package/dist/{chunk-5KMKI23S.mjs → chunk-ZYAAJMZZ.mjs} +2 -2
  21. package/dist/client/index.d.mts +6 -6
  22. package/dist/client/index.d.ts +6 -6
  23. package/dist/client/index.js +4 -4
  24. package/dist/client/index.mjs +3 -3
  25. package/dist/components/index.d.mts +69 -12
  26. package/dist/components/index.d.ts +69 -12
  27. package/dist/components/index.js +18 -4
  28. package/dist/components/index.js.map +1 -1
  29. package/dist/components/index.mjs +19 -5
  30. package/dist/{config-DZWAFB7H.d.ts → config-CyCAWW-d.d.ts} +1 -1
  31. package/dist/{config-ndRJIQsP.d.mts → config-D-mqttuF.d.mts} +1 -1
  32. package/dist/{content.interface-B5ySfiOE.d.mts → content.interface-8T5-G84c.d.mts} +1 -1
  33. package/dist/{content.interface-mmz0uMwm.d.ts → content.interface-D-xdYxjt.d.ts} +1 -1
  34. package/dist/contexts/index.d.mts +3 -3
  35. package/dist/contexts/index.d.ts +3 -3
  36. package/dist/contexts/index.js +4 -4
  37. package/dist/contexts/index.mjs +3 -3
  38. package/dist/core/index.d.mts +29 -9
  39. package/dist/core/index.d.ts +29 -9
  40. package/dist/core/index.js +2 -2
  41. package/dist/core/index.mjs +1 -1
  42. package/dist/index.d.mts +8 -8
  43. package/dist/index.d.ts +8 -8
  44. package/dist/index.js +3 -3
  45. package/dist/index.mjs +2 -2
  46. package/dist/{notification.interface-DG7cq9oG.d.mts → notification.interface-C6UcmJqu.d.mts} +20 -0
  47. package/dist/{notification.interface-COKHDQeE.d.ts → notification.interface-ItBxq2au.d.ts} +20 -0
  48. package/dist/{s3.service-ppn9iGJU.d.ts → s3.service-Cg5TmbU_.d.ts} +6 -3
  49. package/dist/{s3.service-BoRPFx82.d.mts → s3.service-DLf_a0xS.d.mts} +6 -3
  50. package/dist/server/index.d.mts +4 -4
  51. package/dist/server/index.d.ts +4 -4
  52. package/dist/server/index.js +3 -3
  53. package/dist/server/index.mjs +1 -1
  54. package/dist/{useRbacState-DhuYYr0S.d.mts → useRbacState-Btk1gkQg.d.mts} +1 -1
  55. package/dist/{useRbacState-NnzNL2ED.d.ts → useRbacState-CUj0hp8t.d.ts} +1 -1
  56. package/dist/{useSocket-bsV-K4qR.d.ts → useSocket-BSUN9s3p.d.ts} +1 -1
  57. package/dist/{useSocket-CtfuR5wD.d.mts → useSocket-DKI92Fbg.d.mts} +1 -1
  58. package/package.json +2 -1
  59. package/src/components/EditableAvatar.tsx +175 -0
  60. package/src/components/containers/RoundPageContainer.tsx +1 -1
  61. package/src/components/fiscal/FiscalDataDisplay.tsx +26 -0
  62. package/src/components/fiscal/ItalianFiscalData.tsx +120 -0
  63. package/src/components/fiscal/ItalianFiscalDataDisplay.tsx +24 -0
  64. package/src/components/fiscal/index.ts +4 -0
  65. package/src/components/index.ts +3 -0
  66. package/src/components/navigations/RecentPagesNavigator.tsx +3 -3
  67. package/src/features/company/components/details/CompanyContent.tsx +105 -0
  68. package/src/features/company/components/details/CompanyDetails.tsx +2 -19
  69. package/src/features/company/components/details/index.ts +1 -0
  70. package/src/features/company/components/forms/CompanyConfigurationEditor.tsx +38 -70
  71. package/src/features/company/components/forms/CompanyEditor.tsx +212 -172
  72. package/src/features/company/data/company.interface.ts +20 -0
  73. package/src/features/company/data/company.ts +73 -0
  74. package/src/features/role/components/forms/FormRoles.tsx +5 -4
  75. package/src/features/user/components/containers/AllUsersListContainer.tsx +36 -0
  76. package/src/features/user/components/containers/UserContainer.tsx +10 -13
  77. package/src/features/user/components/containers/UsersListContainer.tsx +15 -24
  78. package/src/features/user/components/containers/index.ts +1 -0
  79. package/src/features/user/components/details/UserContent.tsx +92 -0
  80. package/src/features/user/components/details/index.ts +1 -1
  81. package/src/features/user/components/forms/UserEditor.tsx +233 -233
  82. package/src/features/user/components/lists/CompanyUsersList.tsx +3 -1
  83. package/src/features/user/contexts/UserContext.tsx +1 -6
  84. package/src/features/user/data/user.service.ts +9 -0
  85. package/src/features/user/data/user.ts +3 -4
  86. package/src/utils/fiscal-utils.ts +7 -0
  87. package/src/utils/italian-validators.ts +79 -0
  88. package/dist/chunk-CDCGQFIA.js.map +0 -1
  89. package/dist/chunk-ESGUCYJS.mjs.map +0 -1
  90. package/dist/chunk-LRXJT656.js.map +0 -1
  91. package/src/features/user/components/details/UserDetails.tsx +0 -74
  92. /package/dist/{BlockNoteEditor-CZOW7J5K.mjs.map → BlockNoteEditor-TIX3GDVZ.mjs.map} +0 -0
  93. /package/dist/{chunk-5KMKI23S.mjs.map → chunk-ZYAAJMZZ.mjs.map} +0 -0
@@ -18,6 +18,17 @@ export class Company extends AbstractApiData implements CompanyInterface {
18
18
  private _features?: FeatureInterface[];
19
19
  private _modules?: ModuleInterface[];
20
20
 
21
+ private _legal_address?: string;
22
+ private _street_number?: string;
23
+ private _street?: string;
24
+ private _city?: string;
25
+ private _province?: string;
26
+ private _region?: string;
27
+ private _postcode?: string;
28
+ private _country?: string;
29
+ private _country_code?: string;
30
+ private _fiscal_data?: string;
31
+
21
32
  get name(): string {
22
33
  if (this._name === undefined) throw new Error("Name is not defined");
23
34
  return this._name;
@@ -59,6 +70,46 @@ export class Company extends AbstractApiData implements CompanyInterface {
59
70
  return this._configurations;
60
71
  }
61
72
 
73
+ get legal_address(): string | undefined {
74
+ return this._legal_address;
75
+ }
76
+
77
+ get street_number(): string | undefined {
78
+ return this._street_number;
79
+ }
80
+
81
+ get street(): string | undefined {
82
+ return this._street;
83
+ }
84
+
85
+ get city(): string | undefined {
86
+ return this._city;
87
+ }
88
+
89
+ get province(): string | undefined {
90
+ return this._province;
91
+ }
92
+
93
+ get region(): string | undefined {
94
+ return this._region;
95
+ }
96
+
97
+ get postcode(): string | undefined {
98
+ return this._postcode;
99
+ }
100
+
101
+ get country(): string | undefined {
102
+ return this._country;
103
+ }
104
+
105
+ get country_code(): string | undefined {
106
+ return this._country_code;
107
+ }
108
+
109
+ get fiscal_data(): string | undefined {
110
+ return this._fiscal_data;
111
+ }
112
+
62
113
  rehydrate(data: JsonApiHydratedDataInterface): this {
63
114
  super.rehydrate(data);
64
115
 
@@ -73,6 +124,17 @@ export class Company extends AbstractApiData implements CompanyInterface {
73
124
  this._availableMonthlyTokens = data.jsonApi.attributes.availableMonthlyTokens ?? 0;
74
125
  this._availableExtraTokens = data.jsonApi.attributes.availableExtraTokens ?? 0;
75
126
 
127
+ this._legal_address = data.jsonApi.attributes.legal_address;
128
+ this._street_number = data.jsonApi.attributes.street_number;
129
+ this._street = data.jsonApi.attributes.street;
130
+ this._city = data.jsonApi.attributes.city;
131
+ this._province = data.jsonApi.attributes.province;
132
+ this._region = data.jsonApi.attributes.region;
133
+ this._postcode = data.jsonApi.attributes.postcode;
134
+ this._country = data.jsonApi.attributes.country;
135
+ this._country_code = data.jsonApi.attributes.country_code;
136
+ this._fiscal_data = data.jsonApi.attributes.fiscal_data;
137
+
76
138
  this._features = this._readIncluded<FeatureInterface>(data, "features", Modules.Feature) as FeatureInterface[];
77
139
  this._modules = this._readIncluded<ModuleInterface>(data, "modules", Modules.Module) as ModuleInterface[];
78
140
 
@@ -100,6 +162,17 @@ export class Company extends AbstractApiData implements CompanyInterface {
100
162
  if (data.availableExtraTokens !== undefined)
101
163
  response.data.attributes.availableExtraTokens = data.availableExtraTokens;
102
164
 
165
+ if (data.legal_address !== undefined) response.data.attributes.legal_address = data.legal_address;
166
+ if (data.street_number !== undefined) response.data.attributes.street_number = data.street_number;
167
+ if (data.street !== undefined) response.data.attributes.street = data.street;
168
+ if (data.city !== undefined) response.data.attributes.city = data.city;
169
+ if (data.province !== undefined) response.data.attributes.province = data.province;
170
+ if (data.region !== undefined) response.data.attributes.region = data.region;
171
+ if (data.postcode !== undefined) response.data.attributes.postcode = data.postcode;
172
+ if (data.country !== undefined) response.data.attributes.country = data.country;
173
+ if (data.country_code !== undefined) response.data.attributes.country_code = data.country_code;
174
+ if (data.fiscal_data !== undefined) response.data.attributes.fiscal_data = data.fiscal_data;
175
+
103
176
  if (data.featureIds && data.featureIds.length > 0) {
104
177
  response.data.relationships.features = {
105
178
  data: data.featureIds.map((featureId) => ({
@@ -22,7 +22,7 @@ export function FormRoles({ form, id, name, roles }: FormRolesProps) {
22
22
  <div className="flex w-full flex-col">
23
23
  <FormFieldWrapper form={form} name={id} label={name}>
24
24
  {(field) => (
25
- <div>
25
+ <div className="flex w-full flex-col gap-y-1">
26
26
  {roles
27
27
  .filter((role: RoleInterface) => role.isSelectable)
28
28
  .sort((a: RoleInterface, b: RoleInterface) => a.name.localeCompare(b.name))
@@ -30,9 +30,10 @@ export function FormRoles({ form, id, name, roles }: FormRolesProps) {
30
30
  if (role.requiredFeature && !hasAccesToFeature(role.requiredFeature.id)) return null;
31
31
 
32
32
  return (
33
- <div key={role.id}>
33
+ <div key={role.id} className="flex w-full items-center">
34
34
  <Checkbox
35
- defaultChecked={(field.value as string[]).some((roleId: string) => roleId === role.id)}
35
+ id={`role-${role.id}`}
36
+ checked={(field.value as string[]).some((roleId: string) => roleId === role.id)}
36
37
  onCheckedChange={(checked) => {
37
38
  if (checked) {
38
39
  form.setValue(id, [...(field.value as string[]), role.id]);
@@ -46,7 +47,7 @@ export function FormRoles({ form, id, name, roles }: FormRolesProps) {
46
47
  />
47
48
  <Tooltip>
48
49
  <TooltipTrigger>
49
- <FieldLabel className="ml-3 font-normal">
50
+ <FieldLabel htmlFor={`role-${role.id}`} className="ml-3 cursor-pointer font-normal">
50
51
  {t(`role.roles`, { role: role.id.replaceAll(`-`, ``) })}
51
52
  </FieldLabel>
52
53
  </TooltipTrigger>
@@ -0,0 +1,36 @@
1
+ "use client";
2
+
3
+ import { useTranslations } from "next-intl";
4
+ import { CompanyUsersList, Tab, TabsContainer } from "../../../../components";
5
+ import { Modules } from "../../../../core";
6
+ import { Action } from "../../../../permissions";
7
+ import { useCurrentUserContext } from "../../contexts";
8
+ import { UserInterface } from "../../data";
9
+
10
+ function AllUsersListContainerInternal() {
11
+ const { hasPermissionToModule } = useCurrentUserContext<UserInterface>();
12
+ const t = useTranslations();
13
+
14
+ if (!hasPermissionToModule({ module: Modules.User, action: Action.Delete })) return <CompanyUsersList />;
15
+
16
+ const tabs: Tab[] = [
17
+ {
18
+ label: t(`entities.users`, { count: 2 }),
19
+ content: <CompanyUsersList />,
20
+ modules: [Modules.Company],
21
+ action: Action.Read,
22
+ },
23
+ {
24
+ label: t(`user.deleted`),
25
+ content: <CompanyUsersList isDeleted={true} />,
26
+ modules: [Modules.Company],
27
+ action: Action.Update,
28
+ },
29
+ ];
30
+
31
+ return <TabsContainer tabs={tabs} />;
32
+ }
33
+
34
+ export function AllUsersListContainer() {
35
+ return <AllUsersListContainerInternal />;
36
+ }
@@ -1,23 +1,20 @@
1
1
  "use client";
2
2
 
3
- import { useTranslations } from "next-intl";
3
+ import { RoundPageContainer, Tab } from "@/components";
4
+ import { Modules } from "@/core";
4
5
  import { useUserContext } from "../../contexts";
5
- import { UserDetails } from "../details";
6
+ import { UserContent } from "../details";
6
7
 
7
8
  export function UserContainer() {
8
9
  const { user } = useUserContext();
9
10
  if (!user) return null;
10
11
 
11
- const _t = useTranslations();
12
+ const tabs: Tab[] = [
13
+ {
14
+ label: "Details",
15
+ content: <UserContent user={user} />,
16
+ },
17
+ ];
12
18
 
13
- return (
14
- <div className="flex w-full gap-x-4">
15
- <div className="w-2xl flex h-[calc(100vh-theme(spacing.20))] flex-col justify-between border-r pr-4">
16
- <div className="flex h-full overflow-y-auto">
17
- <UserDetails user={user} />
18
- </div>
19
- </div>
20
- <div className="flex w-full flex-col gap-y-4"></div>
21
- </div>
22
- );
19
+ return <RoundPageContainer module={Modules.User} tabs={tabs} />;
23
20
  }
@@ -1,36 +1,27 @@
1
1
  "use client";
2
2
 
3
- import { useTranslations } from "next-intl";
4
- import { CompanyUsersList, Tab, TabsContainer } from "../../../../components";
3
+ import { CompanyUsersList, RoundPageContainer } from "../../../../components";
5
4
  import { Modules } from "../../../../core";
6
5
  import { Action } from "../../../../permissions";
7
6
  import { useCurrentUserContext } from "../../contexts";
8
7
  import { UserInterface } from "../../data";
9
8
 
10
- function UsersListContainerInternal() {
11
- const { hasPermissionToModule } = useCurrentUserContext<UserInterface>();
12
- const t = useTranslations();
9
+ type UsersListContainerProps = {
10
+ fullWidth?: boolean;
11
+ };
13
12
 
14
- if (!hasPermissionToModule({ module: Modules.User, action: Action.Delete })) return <CompanyUsersList />;
13
+ function UsersListContainerInternal({ fullWidth }: UsersListContainerProps) {
14
+ return (
15
+ <RoundPageContainer module={Modules.User} fullWidth={fullWidth}>
16
+ <CompanyUsersList fullWidth={fullWidth} />
17
+ </RoundPageContainer>
18
+ );
19
+ }
15
20
 
16
- const tabs: Tab[] = [
17
- {
18
- label: t(`entities.users`, { count: 2 }),
19
- content: <CompanyUsersList />,
20
- modules: [Modules.Company],
21
- action: Action.Read,
22
- },
23
- {
24
- label: t(`user.deleted`),
25
- content: <CompanyUsersList isDeleted={true} />,
26
- modules: [Modules.Company],
27
- action: Action.Update,
28
- },
29
- ];
21
+ export function UsersListContainer({ fullWidth }: UsersListContainerProps) {
22
+ const { hasPermissionToModule } = useCurrentUserContext<UserInterface>();
30
23
 
31
- return <TabsContainer tabs={tabs} />;
32
- }
24
+ if (!hasPermissionToModule({ module: Modules.User, action: Action.Read })) return null;
33
25
 
34
- export function UsersListContainer() {
35
- return <UsersListContainerInternal />;
26
+ return <UsersListContainerInternal fullWidth={fullWidth} />;
36
27
  }
@@ -1,3 +1,4 @@
1
+ export * from "./AllUsersListContainer";
1
2
  export * from "./UserContainer";
2
3
  export * from "./UserIndexContainer";
3
4
  export * from "./UsersListContainer";
@@ -0,0 +1,92 @@
1
+ "use client";
2
+
3
+ import { useTranslations } from "next-intl";
4
+ import { AttributeElement } from "../../../../components/contents";
5
+ import { EditableAvatar } from "../../../../components/EditableAvatar";
6
+ import { getInitials } from "../../../../utils/getInitials";
7
+ import { Modules } from "../../../../core";
8
+ import { usePageUrlGenerator } from "../../../../hooks";
9
+ import { Badge, Link } from "../../../../shadcnui";
10
+ import { RoleInterface } from "../../../role";
11
+ import { UserInterface } from "../../data";
12
+ import { UserService } from "../../data/user.service";
13
+ import { useUserContext } from "../../contexts";
14
+ import { BriefcaseIcon, MailIcon, PhoneIcon } from "lucide-react";
15
+
16
+ type UserContentProps = {
17
+ user: UserInterface;
18
+ };
19
+
20
+ export function UserContent({ user }: UserContentProps) {
21
+ const t = useTranslations();
22
+ const generateUrl = usePageUrlGenerator();
23
+ const { setUser } = useUserContext();
24
+
25
+ const hasBio = !!user.bio;
26
+
27
+ return (
28
+ <div className="flex flex-col gap-y-8">
29
+ {/* Hero Section */}
30
+ <div className="flex items-start gap-x-6">
31
+ <EditableAvatar
32
+ entityId={user.id}
33
+ module={Modules.User}
34
+ image={user.avatar}
35
+ fallback={getInitials(user.name)}
36
+ alt={user.name}
37
+ patchImage={async (imageKey) => {
38
+ const updated = await UserService.patch({ id: user.id, avatar: imageKey });
39
+ setUser(updated);
40
+ }}
41
+ className="h-24 w-24"
42
+ fallbackClassName="text-2xl"
43
+ />
44
+ <div className="flex flex-col gap-y-2">
45
+ {user.roles && user.roles.length > 0 && (
46
+ <div className="flex flex-wrap gap-2">
47
+ {user.roles.map((role: RoleInterface) => (
48
+ <Link key={role.id} href={generateUrl({ page: Modules.Role, id: role.id })}>
49
+ <Badge variant="default">{t(`role.roles`, { role: role.id.replaceAll(`-`, ``) })}</Badge>
50
+ </Link>
51
+ ))}
52
+ </div>
53
+ )}
54
+ {user.isDeleted ? (
55
+ <div>
56
+ <Badge variant="destructive">{t(`user.errors.deleted`)}</Badge>
57
+ </div>
58
+ ) : (
59
+ <>
60
+ {!user.isActivated && (
61
+ <div>
62
+ <Badge variant="destructive">{t(`user.errors.inactive`)}</Badge>
63
+ </div>
64
+ )}
65
+ </>
66
+ )}
67
+ {user.title && (
68
+ <div className="text-muted-foreground flex items-center gap-x-2 text-sm">
69
+ <BriefcaseIcon className="h-4 w-4 shrink-0" />
70
+ {user.title}
71
+ </div>
72
+ )}
73
+ {user.email && (
74
+ <div className="text-muted-foreground flex items-center gap-x-2 text-sm">
75
+ <MailIcon className="h-4 w-4 shrink-0" />
76
+ {user.email}
77
+ </div>
78
+ )}
79
+ {user.phone && (
80
+ <div className="text-muted-foreground flex items-center gap-x-2 text-sm">
81
+ <PhoneIcon className="h-4 w-4 shrink-0" />
82
+ {user.phone}
83
+ </div>
84
+ )}
85
+ </div>
86
+ </div>
87
+
88
+ {/* Bio Section */}
89
+ {hasBio && <AttributeElement title={t(`user.fields.bio.label`)} value={user.bio} />}
90
+ </div>
91
+ );
92
+ }
@@ -1,3 +1,3 @@
1
- export * from "./UserDetails";
1
+ export * from "./UserContent";
2
2
  export * from "./UserIndexDetails";
3
3
  export * from "./UserStandaloneDetails";