@carlonicora/nextjs-jsonapi 1.24.1 → 1.24.3

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 (66) hide show
  1. package/dist/{BlockNoteEditor-UCHRVVVZ.js → BlockNoteEditor-OFSTXGZX.js} +6 -6
  2. package/dist/{BlockNoteEditor-UCHRVVVZ.js.map → BlockNoteEditor-OFSTXGZX.js.map} +1 -1
  3. package/dist/{BlockNoteEditor-ZYZZ6B45.mjs → BlockNoteEditor-TJNLCNIP.mjs} +2 -2
  4. package/dist/billing/index.js +300 -303
  5. package/dist/billing/index.js.map +1 -1
  6. package/dist/billing/index.mjs +5 -8
  7. package/dist/billing/index.mjs.map +1 -1
  8. package/dist/{chunk-ILKUML3Z.js → chunk-EJALOG7L.js} +4002 -3923
  9. package/dist/chunk-EJALOG7L.js.map +1 -0
  10. package/dist/{chunk-CU4RXSNY.mjs → chunk-H5JZ5E7M.mjs} +4336 -4257
  11. package/dist/chunk-H5JZ5E7M.mjs.map +1 -0
  12. package/dist/client/index.js +2 -2
  13. package/dist/client/index.mjs +1 -1
  14. package/dist/components/index.d.mts +69 -34
  15. package/dist/components/index.d.ts +69 -34
  16. package/dist/components/index.js +20 -2
  17. package/dist/components/index.js.map +1 -1
  18. package/dist/components/index.mjs +35 -17
  19. package/dist/contexts/index.js +2 -2
  20. package/dist/contexts/index.mjs +1 -1
  21. package/dist/scripts/generate-web-module/templates/components/editor.template.js +11 -13
  22. package/dist/scripts/generate-web-module/templates/components/editor.template.js.map +1 -1
  23. package/dist/scripts/generate-web-module/templates/components/multi-selector.template.d.ts.map +1 -1
  24. package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js +13 -26
  25. package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js.map +1 -1
  26. package/dist/scripts/generate-web-module/templates/components/selector.template.d.ts.map +1 -1
  27. package/dist/scripts/generate-web-module/templates/components/selector.template.js +59 -76
  28. package/dist/scripts/generate-web-module/templates/components/selector.template.js.map +1 -1
  29. package/dist/scripts/generate-web-module/transformers/field-mapper.d.ts.map +1 -1
  30. package/dist/scripts/generate-web-module/transformers/field-mapper.js +10 -12
  31. package/dist/scripts/generate-web-module/transformers/field-mapper.js.map +1 -1
  32. package/package.json +2 -2
  33. package/scripts/generate-web-module/templates/components/editor.template.ts +11 -13
  34. package/scripts/generate-web-module/templates/components/multi-selector.template.ts +13 -26
  35. package/scripts/generate-web-module/templates/components/selector.template.ts +59 -76
  36. package/scripts/generate-web-module/transformers/field-mapper.ts +10 -12
  37. package/src/components/forms/FormCheckbox.tsx +18 -24
  38. package/src/components/forms/FormDate.tsx +103 -116
  39. package/src/components/forms/FormDateTime.tsx +122 -130
  40. package/src/components/forms/FormFieldWrapper.tsx +54 -0
  41. package/src/components/forms/FormInput.tsx +58 -46
  42. package/src/components/forms/FormPassword.tsx +17 -24
  43. package/src/components/forms/FormPlaceAutocomplete.tsx +50 -75
  44. package/src/components/forms/FormSelect.tsx +29 -35
  45. package/src/components/forms/FormSlider.tsx +23 -27
  46. package/src/components/forms/FormSwitch.tsx +12 -14
  47. package/src/components/forms/FormTextarea.tsx +12 -19
  48. package/src/components/forms/__tests__/FormInput.test.tsx +4 -2
  49. package/src/components/forms/index.ts +1 -1
  50. package/src/components/pages/PageContentContainer.tsx +2 -1
  51. package/src/features/billing/stripe-price/components/forms/PriceEditor.tsx +9 -13
  52. package/src/features/company/components/forms/CompanyConfigurationSecurityForm.tsx +19 -33
  53. package/src/features/feature/components/forms/FormFeatures.tsx +3 -4
  54. package/src/features/role/components/forms/FormRoles.tsx +40 -51
  55. package/src/features/user/components/forms/UserMultiSelect.tsx +12 -29
  56. package/src/features/user/components/forms/UserSelector.tsx +79 -91
  57. package/src/hooks/__tests__/useDataListRetriever.test.ts +10 -1
  58. package/src/shadcnui/index.ts +2 -0
  59. package/src/shadcnui/ui/field.tsx +3 -3
  60. package/src/shadcnui/ui/form.tsx +17 -134
  61. package/src/shadcnui/ui/input-group.tsx +4 -4
  62. package/src/shadcnui/ui/resizable.tsx +8 -8
  63. package/dist/chunk-CU4RXSNY.mjs.map +0 -1
  64. package/dist/chunk-ILKUML3Z.js.map +0 -1
  65. package/src/components/forms/FormContainerGeneric.tsx +0 -39
  66. /package/dist/{BlockNoteEditor-ZYZZ6B45.mjs.map → BlockNoteEditor-TJNLCNIP.mjs.map} +0 -0
@@ -6,11 +6,6 @@ import { useI18nDateFnsLocale, useI18nLocale, useI18nTranslations } from "../../
6
6
  import {
7
7
  Button,
8
8
  Calendar,
9
- FormControl,
10
- FormField,
11
- FormItem,
12
- FormLabel,
13
- FormMessage,
14
9
  Label,
15
10
  Popover,
16
11
  PopoverContent,
@@ -22,6 +17,7 @@ import {
22
17
  SelectValue,
23
18
  } from "../../shadcnui";
24
19
  import { cn } from "../../utils";
20
+ import { FormFieldWrapper } from "./FormFieldWrapper";
25
21
 
26
22
  export function FormDateTime({
27
23
  form,
@@ -96,138 +92,134 @@ export function FormDateTime({
96
92
 
97
93
  return (
98
94
  <div className="flex w-full flex-col">
99
- <FormField
100
- control={form.control}
95
+ <FormFieldWrapper
96
+ form={form}
101
97
  name={id}
102
- render={({ field }) => (
103
- <FormItem className={`${name ? "mb-5" : "mb-1"} w-full`}>
104
- {name && <FormLabel>{name}</FormLabel>}
105
- <FormControl>
106
- <div className="relative flex flex-row">
107
- <Popover open={open} onOpenChange={setOpen} modal={true}>
108
- <div className="flex w-full flex-row items-center justify-between">
109
- <PopoverTrigger
110
- render={
111
- <Button
112
- variant={"outline"}
113
- className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
114
- />
115
- }
116
- >
117
- {field.value ? formatDateTime(field.value) : <span>{t(`generic.pick_date_time`)}</span>}
118
- <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
119
- </PopoverTrigger>
120
- {field.value && allowEmpty !== false && (
121
- <CircleXIcon
122
- className="text-muted hover:text-destructive ml-2 h-6 w-6 cursor-pointer"
123
- onClick={() => {
124
- if (onChange) onChange(undefined);
125
- form.setValue(id, "");
126
- }}
127
- />
128
- )}
129
- </div>
130
- <PopoverContent className="w-auto p-4" align="start">
131
- <div className="flex flex-col space-y-4">
132
- <Calendar
133
- mode="single"
134
- selected={field.value}
135
- onSelect={(date) => {
136
- if (date) {
137
- // Preserve the current time when selecting a new date
138
- const newDate = new Date(date);
139
- if (field.value) {
140
- const currentDate = new Date(field.value);
141
- newDate.setHours(currentDate.getHours(), currentDate.getMinutes());
142
- } else {
143
- newDate.setHours(selectedHours, selectedMinutes);
144
- }
145
- form.setValue(id, newDate);
146
- if (onChange) onChange(newDate);
98
+ label={name}
99
+ >
100
+ {(field) => (
101
+ <div className="relative flex flex-row">
102
+ <Popover open={open} onOpenChange={setOpen} modal={true}>
103
+ <div className="flex w-full flex-row items-center justify-between">
104
+ <PopoverTrigger
105
+ render={
106
+ <Button
107
+ variant={"outline"}
108
+ className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
109
+ />
110
+ }
111
+ >
112
+ {field.value ? formatDateTime(field.value) : <span>{t(`generic.pick_date_time`)}</span>}
113
+ <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
114
+ </PopoverTrigger>
115
+ {field.value && allowEmpty !== false && (
116
+ <CircleXIcon
117
+ className="text-muted hover:text-destructive ml-2 h-6 w-6 cursor-pointer"
118
+ onClick={() => {
119
+ if (onChange) onChange(undefined);
120
+ form.setValue(id, "");
121
+ }}
122
+ />
123
+ )}
124
+ </div>
125
+ <PopoverContent className="w-auto p-4" align="start">
126
+ <div className="flex flex-col space-y-4">
127
+ <Calendar
128
+ mode="single"
129
+ selected={field.value}
130
+ onSelect={(date) => {
131
+ if (date) {
132
+ // Preserve the current time when selecting a new date
133
+ const newDate = new Date(date);
134
+ if (field.value) {
135
+ const currentDate = new Date(field.value);
136
+ newDate.setHours(currentDate.getHours(), currentDate.getMinutes());
137
+ } else {
138
+ newDate.setHours(selectedHours, selectedMinutes);
139
+ }
140
+ form.setValue(id, newDate);
141
+ if (onChange) onChange(newDate);
147
142
 
148
- // Update time state values
149
- setSelectedHours(newDate.getHours());
150
- setSelectedMinutes(roundToNearestFiveMinutes(newDate.getMinutes()));
151
- }
143
+ // Update time state values
144
+ setSelectedHours(newDate.getHours());
145
+ setSelectedMinutes(roundToNearestFiveMinutes(newDate.getMinutes()));
146
+ }
147
+ }}
148
+ disabled={(date) => (minDate && date < minDate ? true : false)}
149
+ locale={dateFnsLocale}
150
+ />
151
+ <div className="flex flex-row items-end justify-center space-x-4">
152
+ <div className="flex flex-col space-y-2">
153
+ <Label htmlFor="hours-select">{t(`generic.hours`)}</Label>
154
+ <Select
155
+ value={String(field.value ? new Date(field.value).getHours() : selectedHours)}
156
+ onValueChange={(value) => {
157
+ if (!value) return;
158
+ const hours = parseInt(value);
159
+ setSelectedHours(hours);
160
+ handleTimeChange(
161
+ hours,
162
+ field.value
163
+ ? roundToNearestFiveMinutes(new Date(field.value).getMinutes())
164
+ : selectedMinutes,
165
+ );
152
166
  }}
153
- disabled={(date) => (minDate && date < minDate ? true : false)}
154
- locale={dateFnsLocale}
155
- />
156
- <div className="flex flex-row items-end justify-center space-x-4">
157
- <div className="flex flex-col space-y-2">
158
- <Label htmlFor="hours-select">{t(`generic.hours`)}</Label>
159
- <Select
160
- value={String(field.value ? new Date(field.value).getHours() : selectedHours)}
161
- onValueChange={(value) => {
162
- if (!value) return;
163
- const hours = parseInt(value);
164
- setSelectedHours(hours);
165
- handleTimeChange(
166
- hours,
167
- field.value
168
- ? roundToNearestFiveMinutes(new Date(field.value).getMinutes())
169
- : selectedMinutes,
170
- );
171
- }}
172
- >
173
- <SelectTrigger id="hours-select" className="w-[70px]">
174
- <SelectValue />
175
- </SelectTrigger>
176
- <SelectContent>
177
- {hoursOptions.map((option) => (
178
- <SelectItem key={option.value} value={String(option.value)}>
179
- {option.label}
180
- </SelectItem>
181
- ))}
182
- </SelectContent>
183
- </Select>
184
- </div>
185
- <div className="mb-[9px] text-xl">:</div>
186
- <div className="flex flex-col space-y-2">
187
- <Label htmlFor="minutes-select">{t(`generic.minutes`)}</Label>
188
- <Select
189
- value={String(
190
- field.value
191
- ? roundToNearestFiveMinutes(new Date(field.value).getMinutes())
192
- : selectedMinutes,
193
- )}
194
- onValueChange={(value) => {
195
- if (!value) return;
196
- const minutes = parseInt(value);
197
- setSelectedMinutes(minutes);
198
- handleTimeChange(field.value ? new Date(field.value).getHours() : selectedHours, minutes);
199
- }}
200
- >
201
- <SelectTrigger id="minutes-select" className="w-[70px]">
202
- <SelectValue />
203
- </SelectTrigger>
204
- <SelectContent>
205
- {minutesOptions.map((option) => (
206
- <SelectItem key={option.value} value={String(option.value)}>
207
- {option.label}
208
- </SelectItem>
209
- ))}
210
- </SelectContent>
211
- </Select>
212
- </div>
213
- </div>
214
- <Button
215
- className="mt-2"
216
- onClick={() => {
217
- setOpen(false);
167
+ >
168
+ <SelectTrigger id="hours-select" className="w-[70px]">
169
+ <SelectValue />
170
+ </SelectTrigger>
171
+ <SelectContent>
172
+ {hoursOptions.map((option) => (
173
+ <SelectItem key={option.value} value={String(option.value)}>
174
+ {option.label}
175
+ </SelectItem>
176
+ ))}
177
+ </SelectContent>
178
+ </Select>
179
+ </div>
180
+ <div className="mb-[9px] text-xl">:</div>
181
+ <div className="flex flex-col space-y-2">
182
+ <Label htmlFor="minutes-select">{t(`generic.minutes`)}</Label>
183
+ <Select
184
+ value={String(
185
+ field.value
186
+ ? roundToNearestFiveMinutes(new Date(field.value).getMinutes())
187
+ : selectedMinutes,
188
+ )}
189
+ onValueChange={(value) => {
190
+ if (!value) return;
191
+ const minutes = parseInt(value);
192
+ setSelectedMinutes(minutes);
193
+ handleTimeChange(field.value ? new Date(field.value).getHours() : selectedHours, minutes);
218
194
  }}
219
195
  >
220
- {t(`generic.buttons.select_date`)}
221
- </Button>
196
+ <SelectTrigger id="minutes-select" className="w-[70px]">
197
+ <SelectValue />
198
+ </SelectTrigger>
199
+ <SelectContent>
200
+ {minutesOptions.map((option) => (
201
+ <SelectItem key={option.value} value={String(option.value)}>
202
+ {option.label}
203
+ </SelectItem>
204
+ ))}
205
+ </SelectContent>
206
+ </Select>
222
207
  </div>
223
- </PopoverContent>
224
- </Popover>
225
- </div>
226
- </FormControl>
227
- <FormMessage />
228
- </FormItem>
208
+ </div>
209
+ <Button
210
+ className="mt-2"
211
+ onClick={() => {
212
+ setOpen(false);
213
+ }}
214
+ >
215
+ {t(`generic.buttons.select_date`)}
216
+ </Button>
217
+ </div>
218
+ </PopoverContent>
219
+ </Popover>
220
+ </div>
229
221
  )}
230
- />
222
+ </FormFieldWrapper>
231
223
  </div>
232
224
  );
233
225
  }
@@ -0,0 +1,54 @@
1
+ "use client";
2
+
3
+ import { ReactNode } from "react";
4
+ import {
5
+ Controller,
6
+ ControllerFieldState,
7
+ ControllerRenderProps,
8
+ FieldValues,
9
+ Path,
10
+ UseFormReturn,
11
+ } from "react-hook-form";
12
+ import { Field, FieldDescription, FieldError, FieldLabel } from "../../shadcnui";
13
+
14
+ type FormFieldWrapperProps<T extends FieldValues> = {
15
+ form: UseFormReturn<T>;
16
+ name: Path<T>;
17
+ label?: string;
18
+ description?: string;
19
+ isRequired?: boolean;
20
+ orientation?: "vertical" | "horizontal" | "responsive";
21
+ children: (field: ControllerRenderProps<T, Path<T>>, fieldState: ControllerFieldState) => ReactNode;
22
+ testId?: string;
23
+ };
24
+
25
+ export function FormFieldWrapper<T extends FieldValues>({
26
+ form,
27
+ name,
28
+ label,
29
+ description,
30
+ isRequired,
31
+ orientation = "vertical",
32
+ children,
33
+ testId,
34
+ }: FormFieldWrapperProps<T>) {
35
+ return (
36
+ <Controller
37
+ control={form.control}
38
+ name={name}
39
+ render={({ field, fieldState }) => (
40
+ <Field orientation={orientation} data-invalid={!!fieldState.error} data-testid={testId}>
41
+ {label && (
42
+ <FieldLabel>
43
+ {label}
44
+ {isRequired && <span className="text-destructive ml-1 font-semibold">*</span>}
45
+ </FieldLabel>
46
+ )}
47
+ {children(field, fieldState)}
48
+ {description && <FieldDescription>{description}</FieldDescription>}
49
+ {fieldState.error && <FieldError>{fieldState.error.message}</FieldError>}
50
+ </Field>
51
+ )}
52
+ />
53
+ );
54
+ }
@@ -2,7 +2,14 @@
2
2
 
3
3
  import { useTranslations } from "next-intl";
4
4
  import React from "react";
5
- import { FormControl, FormField, FormItem, FormLabel, FormMessage, Input } from "../../shadcnui";
5
+ import {
6
+ Input,
7
+ InputGroup,
8
+ InputGroupAddon,
9
+ InputGroupInput,
10
+ InputGroupText,
11
+ } from "../../shadcnui";
12
+ import { FormFieldWrapper } from "./FormFieldWrapper";
6
13
 
7
14
  export function FormInput({
8
15
  form,
@@ -35,10 +42,13 @@ export function FormInput({
35
42
 
36
43
  return (
37
44
  <div className="flex w-full flex-col">
38
- <FormField
39
- control={form.control}
45
+ <FormFieldWrapper
46
+ form={form}
40
47
  name={id}
41
- render={({ field }) => {
48
+ label={name}
49
+ isRequired={isRequired}
50
+ >
51
+ {(field) => {
42
52
  const handleBlur = async (e: React.FocusEvent<HTMLInputElement>) => {
43
53
  let value = e.target.value;
44
54
 
@@ -62,49 +72,51 @@ export function FormInput({
62
72
  field.onBlur();
63
73
  };
64
74
 
65
- return (
66
- <FormItem className={`${name ? "mb-5" : "mb-1"}`}>
67
- {name && (
68
- <FormLabel className="flex items-center">
69
- {name}
70
- {isRequired && <span className="text-destructive ml-2 font-semibold">*</span>}
71
- </FormLabel>
72
- )}
73
- <FormControl>
74
- <div className="relative">
75
- {type === "currency" && (
76
- <span className="text-muted-foreground absolute top-0 left-0 pt-2 pl-3">€</span>
77
- )}
78
- <Input
79
- data-testid={testId}
80
- {...field}
81
- autoFocus={autoFocus === true}
82
- type={
83
- type === "number" || type === "currency" ? "number" : type === "password" ? "password" : "text"
84
- }
85
- className={`w-full ${type === "number" || type === "currency" ? "text-end" : ""}`}
86
- disabled={disabled === true || form.formState.isSubmitting}
87
- placeholder={placeholder || ""}
88
- onBlur={handleBlur}
89
- onKeyDown={onKeyDown}
90
- onChange={(e) => {
91
- if (type === "number" || type === "currency") {
92
- const value = e.target.value.replace(/[^0-9]/g, "");
93
- field.onChange(+value);
94
- if (onChange) onChange(+value);
95
- } else {
96
- field.onChange(e.target.value);
97
- if (onChange) onChange(e.target.value);
98
- }
99
- }}
100
- />
101
- </div>
102
- </FormControl>
103
- <FormMessage data-testid={testId ? `${testId}-error` : undefined} />
104
- </FormItem>
105
- );
75
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
76
+ if (type === "number" || type === "currency") {
77
+ const value = e.target.value.replace(/[^0-9]/g, "");
78
+ field.onChange(+value);
79
+ if (onChange) onChange(+value);
80
+ } else {
81
+ field.onChange(e.target.value);
82
+ if (onChange) onChange(e.target.value);
83
+ }
84
+ };
85
+
86
+ const inputProps = {
87
+ ...field,
88
+ autoFocus: autoFocus === true,
89
+ type:
90
+ type === "number" || type === "currency"
91
+ ? "number"
92
+ : type === "password"
93
+ ? "password"
94
+ : "text",
95
+ className: `w-full ${type === "number" || type === "currency" ? "text-end" : ""}`,
96
+ disabled: disabled === true || form.formState.isSubmitting,
97
+ placeholder: placeholder || "",
98
+ onBlur: handleBlur,
99
+ onKeyDown,
100
+ onChange: handleChange,
101
+ "data-testid": testId,
102
+ };
103
+
104
+ // Use InputGroup for currency type to show Euro symbol
105
+ if (type === "currency") {
106
+ return (
107
+ <InputGroup>
108
+ <InputGroupAddon>
109
+ <InputGroupText>{"\u20AC"}</InputGroupText>
110
+ </InputGroupAddon>
111
+ <InputGroupInput {...inputProps} />
112
+ </InputGroup>
113
+ );
114
+ }
115
+
116
+ // Regular input for other types
117
+ return <Input {...inputProps} />;
106
118
  }}
107
- />
119
+ </FormFieldWrapper>
108
120
  </div>
109
121
  );
110
122
  }
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { FormControl, FormField, FormItem, FormLabel, FormMessage } from "../../shadcnui";
3
+ import { FormFieldWrapper } from "./FormFieldWrapper";
4
4
  import { PasswordInput } from "./PasswordInput";
5
5
 
6
6
  export function FormPassword({
@@ -24,31 +24,24 @@ export function FormPassword({
24
24
  }) {
25
25
  return (
26
26
  <div className="flex w-full flex-col">
27
- <FormField
28
- control={form.control}
27
+ <FormFieldWrapper
28
+ form={form}
29
29
  name={id}
30
- render={({ field }) => (
31
- <FormItem className={`${name ? "mb-5" : "mb-1"}`}>
32
- {name && (
33
- <FormLabel>
34
- {name}
35
- {isRequired && <span className="text-destructive ml-2 font-semibold">*</span>}
36
- </FormLabel>
37
- )}
38
- <FormControl>
39
- <PasswordInput
40
- {...field}
41
- className={`w-full`}
42
- disabled={disabled === true || form.formState.isSubmitting}
43
- placeholder={placeholder ? placeholder : ""}
44
- onBlur={onBlur}
45
- data-testid={testId}
46
- />
47
- </FormControl>
48
- <FormMessage data-testid={testId ? `${testId}-error` : undefined} />
49
- </FormItem>
30
+ label={name}
31
+ isRequired={isRequired}
32
+ testId={testId}
33
+ >
34
+ {(field) => (
35
+ <PasswordInput
36
+ {...field}
37
+ className="w-full"
38
+ disabled={disabled === true || form.formState.isSubmitting}
39
+ placeholder={placeholder ? placeholder : ""}
40
+ onBlur={onBlur}
41
+ data-testid={testId}
42
+ />
50
43
  )}
51
- />
44
+ </FormFieldWrapper>
52
45
  </div>
53
46
  );
54
47
  }