@carlonicora/nextjs-jsonapi 1.24.2 → 1.25.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 (116) hide show
  1. package/dist/{BlockNoteEditor-7OSPCSFW.js → BlockNoteEditor-CKMTHP7C.js} +13 -13
  2. package/dist/{BlockNoteEditor-7OSPCSFW.js.map → BlockNoteEditor-CKMTHP7C.js.map} +1 -1
  3. package/dist/{BlockNoteEditor-63GKCJK3.mjs → BlockNoteEditor-EJQLNOLB.mjs} +3 -3
  4. package/dist/billing/index.js +345 -348
  5. package/dist/billing/index.js.map +1 -1
  6. package/dist/billing/index.mjs +6 -9
  7. package/dist/billing/index.mjs.map +1 -1
  8. package/dist/{chunk-UTPWUC6O.mjs → chunk-JNLXGGHE.mjs} +5790 -4519
  9. package/dist/chunk-JNLXGGHE.mjs.map +1 -0
  10. package/dist/{chunk-5U4NJJOF.mjs → chunk-LNBT2YPZ.mjs} +289 -2
  11. package/dist/chunk-LNBT2YPZ.mjs.map +1 -0
  12. package/dist/{chunk-NQVPCNRS.js → chunk-O3LLMGP7.js} +290 -3
  13. package/dist/chunk-O3LLMGP7.js.map +1 -0
  14. package/dist/{chunk-HIKTQMCR.js → chunk-YYZ2U4WU.js} +7332 -6061
  15. package/dist/chunk-YYZ2U4WU.js.map +1 -0
  16. package/dist/client/index.d.mts +96 -1
  17. package/dist/client/index.d.ts +96 -1
  18. package/dist/client/index.js +9 -3
  19. package/dist/client/index.js.map +1 -1
  20. package/dist/client/index.mjs +8 -2
  21. package/dist/components/index.d.mts +291 -32
  22. package/dist/components/index.d.ts +291 -32
  23. package/dist/components/index.js +43 -3
  24. package/dist/components/index.js.map +1 -1
  25. package/dist/components/index.mjs +58 -18
  26. package/dist/contexts/index.js +3 -3
  27. package/dist/contexts/index.mjs +2 -2
  28. package/dist/core/index.d.mts +108 -1
  29. package/dist/core/index.d.ts +108 -1
  30. package/dist/core/index.js +14 -2
  31. package/dist/core/index.js.map +1 -1
  32. package/dist/core/index.mjs +13 -1
  33. package/dist/index.d.mts +2 -1
  34. package/dist/index.d.ts +2 -1
  35. package/dist/index.js +14 -2
  36. package/dist/index.js.map +1 -1
  37. package/dist/index.mjs +13 -1
  38. package/dist/oauth.interface-DsZ5ecSX.d.mts +119 -0
  39. package/dist/oauth.interface-vL7za9Bz.d.ts +119 -0
  40. package/dist/scripts/generate-web-module/templates/components/editor.template.js +11 -13
  41. package/dist/scripts/generate-web-module/templates/components/editor.template.js.map +1 -1
  42. package/dist/scripts/generate-web-module/templates/components/multi-selector.template.d.ts.map +1 -1
  43. package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js +13 -26
  44. package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js.map +1 -1
  45. package/dist/scripts/generate-web-module/templates/components/selector.template.d.ts.map +1 -1
  46. package/dist/scripts/generate-web-module/templates/components/selector.template.js +59 -76
  47. package/dist/scripts/generate-web-module/templates/components/selector.template.js.map +1 -1
  48. package/dist/scripts/generate-web-module/transformers/field-mapper.d.ts.map +1 -1
  49. package/dist/scripts/generate-web-module/transformers/field-mapper.js +10 -12
  50. package/dist/scripts/generate-web-module/transformers/field-mapper.js.map +1 -1
  51. package/dist/server/index.js +3 -3
  52. package/dist/server/index.mjs +1 -1
  53. package/package.json +1 -1
  54. package/scripts/generate-web-module/templates/components/editor.template.ts +11 -13
  55. package/scripts/generate-web-module/templates/components/multi-selector.template.ts +13 -26
  56. package/scripts/generate-web-module/templates/components/selector.template.ts +59 -76
  57. package/scripts/generate-web-module/transformers/field-mapper.ts +10 -12
  58. package/src/client/index.ts +1 -0
  59. package/src/components/forms/FormCheckbox.tsx +18 -24
  60. package/src/components/forms/FormDate.tsx +103 -116
  61. package/src/components/forms/FormDateTime.tsx +122 -130
  62. package/src/components/forms/FormFieldWrapper.tsx +54 -0
  63. package/src/components/forms/FormInput.tsx +58 -46
  64. package/src/components/forms/FormPassword.tsx +17 -24
  65. package/src/components/forms/FormPlaceAutocomplete.tsx +50 -75
  66. package/src/components/forms/FormSelect.tsx +29 -35
  67. package/src/components/forms/FormSlider.tsx +23 -27
  68. package/src/components/forms/FormSwitch.tsx +12 -14
  69. package/src/components/forms/FormTextarea.tsx +12 -19
  70. package/src/components/forms/index.ts +1 -1
  71. package/src/components/index.ts +1 -0
  72. package/src/core/index.ts +3 -0
  73. package/src/core/registry/ModuleRegistry.ts +2 -0
  74. package/src/features/billing/stripe-price/components/forms/PriceEditor.tsx +9 -13
  75. package/src/features/company/components/forms/CompanyConfigurationSecurityForm.tsx +19 -33
  76. package/src/features/feature/components/forms/FormFeatures.tsx +3 -4
  77. package/src/features/index.ts +1 -0
  78. package/src/features/oauth/atoms/index.ts +1 -0
  79. package/src/features/oauth/atoms/oauth.atoms.ts +131 -0
  80. package/src/features/oauth/components/OAuthClientCard.tsx +105 -0
  81. package/src/features/oauth/components/OAuthClientDetail.tsx +269 -0
  82. package/src/features/oauth/components/OAuthClientForm.tsx +212 -0
  83. package/src/features/oauth/components/OAuthClientList.tsx +127 -0
  84. package/src/features/oauth/components/OAuthClientSecretDisplay.tsx +127 -0
  85. package/src/features/oauth/components/OAuthRedirectUriInput.tsx +152 -0
  86. package/src/features/oauth/components/OAuthScopeSelector.tsx +123 -0
  87. package/src/features/oauth/components/consent/OAuthConsentActions.tsx +41 -0
  88. package/src/features/oauth/components/consent/OAuthConsentHeader.tsx +51 -0
  89. package/src/features/oauth/components/consent/OAuthConsentScreen.tsx +142 -0
  90. package/src/features/oauth/components/consent/OAuthScopeList.tsx +72 -0
  91. package/src/features/oauth/components/consent/index.ts +4 -0
  92. package/src/features/oauth/components/index.ts +8 -0
  93. package/src/features/oauth/data/index.ts +2 -0
  94. package/src/features/oauth/data/oauth.service.ts +191 -0
  95. package/src/features/oauth/data/oauth.ts +87 -0
  96. package/src/features/oauth/hooks/index.ts +3 -0
  97. package/src/features/oauth/hooks/useOAuthClient.ts +161 -0
  98. package/src/features/oauth/hooks/useOAuthClients.ts +111 -0
  99. package/src/features/oauth/hooks/useOAuthConsent.ts +125 -0
  100. package/src/features/oauth/index.ts +6 -0
  101. package/src/features/oauth/interfaces/index.ts +1 -0
  102. package/src/features/oauth/interfaces/oauth.interface.ts +175 -0
  103. package/src/features/oauth/oauth.module.ts +9 -0
  104. package/src/features/role/components/forms/FormRoles.tsx +40 -51
  105. package/src/features/user/components/forms/UserMultiSelect.tsx +12 -29
  106. package/src/features/user/components/forms/UserSelector.tsx +79 -91
  107. package/src/shadcnui/index.ts +2 -0
  108. package/src/shadcnui/ui/field.tsx +3 -3
  109. package/src/shadcnui/ui/form.tsx +17 -134
  110. package/src/shadcnui/ui/input-group.tsx +4 -4
  111. package/dist/chunk-5U4NJJOF.mjs.map +0 -1
  112. package/dist/chunk-HIKTQMCR.js.map +0 -1
  113. package/dist/chunk-NQVPCNRS.js.map +0 -1
  114. package/dist/chunk-UTPWUC6O.mjs.map +0 -1
  115. package/src/components/forms/FormContainerGeneric.tsx +0 -39
  116. /package/dist/{BlockNoteEditor-63GKCJK3.mjs.map → BlockNoteEditor-EJQLNOLB.mjs.map} +0 -0
@@ -2,15 +2,12 @@
2
2
 
3
3
  import {
4
4
  Checkbox,
5
- FormControl,
6
- FormField,
7
- FormItem,
8
- FormLabel,
9
- FormMessage,
5
+ FieldLabel,
10
6
  Tooltip,
11
7
  TooltipContent,
12
8
  TooltipTrigger,
13
9
  } from "../../shadcnui";
10
+ import { FormFieldWrapper } from "./FormFieldWrapper";
14
11
 
15
12
  type FormCheckboxProps = {
16
13
  form: any;
@@ -24,14 +21,14 @@ type FormCheckboxProps = {
24
21
  export function FormCheckbox({ form, id, name, labelBefore, description, isRequired }: FormCheckboxProps) {
25
22
  const simpleLabel = () => {
26
23
  return (
27
- <FormLabel htmlFor={id} className={`font-normal ${labelBefore ? "" : "ml-3"}`}>
24
+ <FieldLabel htmlFor={id} className={`font-normal ${labelBefore ? "" : "ml-3"}`}>
28
25
  {name}
29
- </FormLabel>
26
+ </FieldLabel>
30
27
  );
31
28
  };
32
29
 
33
30
  const label = () => {
34
- if (description) return simpleLabel();
31
+ if (!description) return simpleLabel();
35
32
  else
36
33
  return (
37
34
  <Tooltip>
@@ -43,24 +40,21 @@ export function FormCheckbox({ form, id, name, labelBefore, description, isRequi
43
40
 
44
41
  return (
45
42
  <div className="flex w-full flex-col">
46
- <FormField
47
- control={form.control}
43
+ <FormFieldWrapper
44
+ form={form}
48
45
  name={id}
49
- render={({ field }) => (
50
- <FormItem className={`${name ? "mb-5" : "mb-1"}`}>
51
- <FormControl>
52
- <div className="flex gap-x-4">
53
- {labelBefore && label()}
54
- {labelBefore && isRequired && <span className="text-destructive ml-2 font-semibold">*</span>}
55
- <Checkbox id={id} defaultChecked={field.value} onCheckedChange={field.onChange} />
56
- {!labelBefore && label()}
57
- {!labelBefore && isRequired && <span className="text-destructive ml-2 font-semibold">*</span>}
58
- </div>
59
- </FormControl>
60
- <FormMessage />
61
- </FormItem>
46
+ orientation="horizontal"
47
+ >
48
+ {(field) => (
49
+ <div className="flex gap-x-4">
50
+ {labelBefore && label()}
51
+ {labelBefore && isRequired && <span className="text-destructive ml-2 font-semibold">*</span>}
52
+ <Checkbox id={id} defaultChecked={field.value} onCheckedChange={field.onChange} />
53
+ {!labelBefore && label()}
54
+ {!labelBefore && isRequired && <span className="text-destructive ml-2 font-semibold">*</span>}
55
+ </div>
62
56
  )}
63
- />
57
+ </FormFieldWrapper>
64
58
  </div>
65
59
  );
66
60
  }
@@ -6,12 +6,10 @@ import { useMemo, useState } from "react";
6
6
  import { useI18nDateFnsLocale, useI18nLocale } from "../../i18n";
7
7
  import {
8
8
  Calendar,
9
- FormControl,
10
- FormField,
11
- FormItem,
12
- FormLabel,
13
- FormMessage,
14
- Input,
9
+ InputGroup,
10
+ InputGroupAddon,
11
+ InputGroupButton,
12
+ InputGroupInput,
15
13
  Popover,
16
14
  PopoverContent,
17
15
  PopoverTrigger,
@@ -21,6 +19,7 @@ import {
21
19
  SelectTrigger,
22
20
  SelectValue,
23
21
  } from "../../shadcnui";
22
+ import { FormFieldWrapper } from "./FormFieldWrapper";
24
23
 
25
24
  export function FormDate({
26
25
  form,
@@ -130,119 +129,107 @@ export function FormDate({
130
129
 
131
130
  return (
132
131
  <div className="flex w-full flex-col">
133
- <FormField
134
- control={form.control}
132
+ <FormFieldWrapper
133
+ form={form}
135
134
  name={id}
136
- render={({ field }) => (
137
- <FormItem className={`${name ? "mb-5" : "mb-1"} w-full`}>
138
- {name && (
139
- <FormLabel className="dlex items-center">
140
- {name} {isRequired && <span className="text-destructive ml-2 font-semibold">*</span>}
141
- </FormLabel>
142
- )}
143
- <FormControl>
144
- <div className="relative">
145
- <Popover open={open} onOpenChange={setOpen} modal={true}>
146
- <div className="relative">
147
- <Input
148
- value={inputValue}
149
- onChange={(e) => handleInputChange(e.target.value, field)}
150
- placeholder={datePlaceholder}
151
- className="pr-16"
152
- />
153
- <div className="absolute right-1 top-1/2 flex -translate-y-1/2 items-center space-x-1">
154
- <PopoverTrigger
155
- render={<div />}
156
- nativeButton={false}
157
- className="hover:bg-muted flex h-8 w-8 cursor-pointer items-center justify-center rounded-md"
158
- >
159
- <CalendarIcon className="h-4 w-4 opacity-50" />
160
- </PopoverTrigger>
161
- {field.value && (
162
- <button
163
- type="button"
164
- className="hover:bg-muted flex h-8 w-8 items-center justify-center rounded-md"
165
- onClick={() => {
166
- field.onChange(undefined);
167
- setInputValue("");
168
- if (onChange) onChange(undefined);
169
- }}
170
- >
171
- <CircleXIcon className="h-4 w-4 opacity-50 hover:opacity-100" />
172
- </button>
173
- )}
174
- </div>
175
- </div>
176
- <PopoverContent className="w-auto p-0" align="start">
177
- <div className="p-3">
178
- {/* Year and Month Selectors */}
179
- <div className="mb-3 flex gap-2">
180
- <Select
181
- value={displayMonth.getMonth().toString()}
182
- onValueChange={(value) => {
183
- if (!value) return;
184
- const newMonth = parseInt(value);
185
- const newDate = new Date(displayMonth.getFullYear(), newMonth, 1);
186
- setDisplayMonth(newDate);
187
- }}
188
- >
189
- <SelectTrigger className="w-[130px]">
190
- <SelectValue />
191
- </SelectTrigger>
192
- <SelectContent>
193
- {monthNames.map((month, index) => (
194
- <SelectItem key={index} value={index.toString()}>
195
- {month}
196
- </SelectItem>
197
- ))}
198
- </SelectContent>
199
- </Select>
200
-
201
- <Select
202
- value={displayMonth.getFullYear().toString()}
203
- onValueChange={(value) => {
204
- if (!value) return;
205
- const newYear = parseInt(value);
206
- const newDate = new Date(newYear, displayMonth.getMonth(), 1);
207
- setDisplayMonth(newDate);
208
- }}
209
- >
210
- <SelectTrigger className="w-[80px]">
211
- <SelectValue />
212
- </SelectTrigger>
213
- <SelectContent>
214
- {yearOptions.reverse().map((year) => (
215
- <SelectItem key={year} value={year.toString()}>
216
- {year}
217
- </SelectItem>
218
- ))}
219
- </SelectContent>
220
- </Select>
221
- </div>
222
-
223
- {/* Calendar */}
224
- <Calendar
225
- mode="single"
226
- selected={field.value}
227
- onSelect={(e) => {
228
- handleCalendarSelect(e, field);
229
- setOpen(false);
230
- }}
231
- disabled={(date) => (minDate && date < minDate ? true : false)}
232
- locale={dateFnsLocale}
233
- weekStartsOn={1}
234
- month={displayMonth}
235
- onMonthChange={setDisplayMonth}
236
- />
237
- </div>
238
- </PopoverContent>
239
- </Popover>
135
+ label={name}
136
+ isRequired={isRequired}
137
+ >
138
+ {(field) => (
139
+ <Popover open={open} onOpenChange={setOpen} modal={true}>
140
+ <InputGroup>
141
+ <InputGroupInput
142
+ value={inputValue}
143
+ onChange={(e) => handleInputChange(e.target.value, field)}
144
+ placeholder={datePlaceholder}
145
+ />
146
+ <InputGroupAddon align="inline-end">
147
+ <PopoverTrigger render={<div />} nativeButton={false}>
148
+ <InputGroupButton variant="ghost" size="icon-xs">
149
+ <CalendarIcon className="h-4 w-4 opacity-50" />
150
+ </InputGroupButton>
151
+ </PopoverTrigger>
152
+ {field.value && (
153
+ <InputGroupButton
154
+ variant="ghost"
155
+ size="icon-xs"
156
+ onClick={() => {
157
+ field.onChange(undefined);
158
+ setInputValue("");
159
+ if (onChange) onChange(undefined);
160
+ }}
161
+ >
162
+ <CircleXIcon className="h-4 w-4 opacity-50 hover:opacity-100" />
163
+ </InputGroupButton>
164
+ )}
165
+ </InputGroupAddon>
166
+ </InputGroup>
167
+ <PopoverContent className="w-auto p-0" align="start">
168
+ <div className="p-3">
169
+ {/* Year and Month Selectors */}
170
+ <div className="mb-3 flex gap-2">
171
+ <Select
172
+ value={displayMonth.getMonth().toString()}
173
+ onValueChange={(value) => {
174
+ if (!value) return;
175
+ const newMonth = parseInt(value);
176
+ const newDate = new Date(displayMonth.getFullYear(), newMonth, 1);
177
+ setDisplayMonth(newDate);
178
+ }}
179
+ >
180
+ <SelectTrigger className="w-[130px]">
181
+ <SelectValue />
182
+ </SelectTrigger>
183
+ <SelectContent>
184
+ {monthNames.map((month, index) => (
185
+ <SelectItem key={index} value={index.toString()}>
186
+ {month}
187
+ </SelectItem>
188
+ ))}
189
+ </SelectContent>
190
+ </Select>
191
+
192
+ <Select
193
+ value={displayMonth.getFullYear().toString()}
194
+ onValueChange={(value) => {
195
+ if (!value) return;
196
+ const newYear = parseInt(value);
197
+ const newDate = new Date(newYear, displayMonth.getMonth(), 1);
198
+ setDisplayMonth(newDate);
199
+ }}
200
+ >
201
+ <SelectTrigger className="w-[80px]">
202
+ <SelectValue />
203
+ </SelectTrigger>
204
+ <SelectContent>
205
+ {yearOptions.reverse().map((year) => (
206
+ <SelectItem key={year} value={year.toString()}>
207
+ {year}
208
+ </SelectItem>
209
+ ))}
210
+ </SelectContent>
211
+ </Select>
212
+ </div>
213
+
214
+ {/* Calendar */}
215
+ <Calendar
216
+ mode="single"
217
+ selected={field.value}
218
+ onSelect={(e) => {
219
+ handleCalendarSelect(e, field);
220
+ setOpen(false);
221
+ }}
222
+ disabled={(date) => (minDate && date < minDate ? true : false)}
223
+ locale={dateFnsLocale}
224
+ weekStartsOn={1}
225
+ month={displayMonth}
226
+ onMonthChange={setDisplayMonth}
227
+ />
240
228
  </div>
241
- </FormControl>
242
- <FormMessage />
243
- </FormItem>
229
+ </PopoverContent>
230
+ </Popover>
244
231
  )}
245
- />
232
+ </FormFieldWrapper>
246
233
  </div>
247
234
  );
248
235
  }
@@ -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
  }