create-nextjs-cms 0.9.4 → 0.9.6

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 (187) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +71 -71
  3. package/dist/helpers/utils.js +16 -16
  4. package/dist/lib/section-creators.js +166 -166
  5. package/package.json +3 -3
  6. package/templates/default/.eslintrc.json +5 -5
  7. package/templates/default/.prettierignore +7 -7
  8. package/templates/default/.prettierrc.json +27 -27
  9. package/templates/default/CHANGELOG.md +140 -140
  10. package/templates/default/_gitignore +57 -57
  11. package/templates/default/app/(auth)/auth/login/LoginPage.tsx +192 -192
  12. package/templates/default/app/(auth)/auth/login/page.tsx +11 -11
  13. package/templates/default/app/(auth)/layout.tsx +81 -81
  14. package/templates/default/app/(rootLayout)/(plugins)/[...slug]/page.tsx +40 -40
  15. package/templates/default/app/(rootLayout)/(plugins)/[...slug]/plugin-server-registry.ts +16 -16
  16. package/templates/default/app/(rootLayout)/admins/page.tsx +10 -10
  17. package/templates/default/app/(rootLayout)/browse/[section]/[page]/page.tsx +22 -22
  18. package/templates/default/app/(rootLayout)/categorized/[section]/page.tsx +15 -15
  19. package/templates/default/app/(rootLayout)/dashboard/page.tsx +63 -63
  20. package/templates/default/app/(rootLayout)/edit/[section]/[itemId]/page.tsx +20 -20
  21. package/templates/default/app/(rootLayout)/layout.tsx +81 -81
  22. package/templates/default/app/(rootLayout)/loading.tsx +10 -10
  23. package/templates/default/app/(rootLayout)/log/page.tsx +7 -7
  24. package/templates/default/app/(rootLayout)/new/[section]/page.tsx +15 -15
  25. package/templates/default/app/(rootLayout)/section/[section]/page.tsx +19 -19
  26. package/templates/default/app/(rootLayout)/settings/page.tsx +13 -13
  27. package/templates/default/app/_trpc/client.ts +3 -3
  28. package/templates/default/app/api/auth/csrf/route.ts +25 -25
  29. package/templates/default/app/api/auth/refresh/route.ts +10 -10
  30. package/templates/default/app/api/auth/route.ts +49 -49
  31. package/templates/default/app/api/auth/session/route.ts +20 -20
  32. package/templates/default/app/api/document/route.ts +165 -165
  33. package/templates/default/app/api/editor/photo/route.ts +49 -49
  34. package/templates/default/app/api/photo/route.ts +27 -27
  35. package/templates/default/app/api/submit/section/item/[slug]/route.ts +95 -95
  36. package/templates/default/app/api/submit/section/item/route.ts +56 -56
  37. package/templates/default/app/api/submit/section/simple/route.ts +86 -86
  38. package/templates/default/app/api/trpc/[trpc]/route.ts +33 -33
  39. package/templates/default/app/api/video/route.ts +174 -174
  40. package/templates/default/app/globals.css +228 -228
  41. package/templates/default/app/providers.tsx +152 -152
  42. package/templates/default/cms.config.ts +58 -57
  43. package/templates/default/components/AdminCard.tsx +166 -166
  44. package/templates/default/components/AdminEditPage.tsx +124 -124
  45. package/templates/default/components/AdminPrivilegeCard.tsx +185 -185
  46. package/templates/default/components/AdminsPage.tsx +43 -43
  47. package/templates/default/components/AnalyticsPage.tsx +144 -128
  48. package/templates/default/components/BarChartBox.tsx +42 -42
  49. package/templates/default/components/BrowsePage.tsx +106 -106
  50. package/templates/default/components/CategorizedSectionPage.tsx +31 -31
  51. package/templates/default/components/CategoryDeleteConfirmPage.tsx +130 -130
  52. package/templates/default/components/CategorySectionSelectInput.tsx +140 -140
  53. package/templates/default/components/ConditionalFields.tsx +49 -49
  54. package/templates/default/components/ContainerBox.tsx +24 -24
  55. package/templates/default/components/DashboardPageAlt.tsx +45 -45
  56. package/templates/default/components/DefaultNavItems.tsx +3 -3
  57. package/templates/default/components/Dropzone.tsx +154 -154
  58. package/templates/default/components/ErrorComponent.tsx +16 -16
  59. package/templates/default/components/GalleryPhoto.tsx +93 -93
  60. package/templates/default/components/InfoCard.tsx +93 -93
  61. package/templates/default/components/ItemEditPage.tsx +294 -294
  62. package/templates/default/components/Layout.tsx +84 -84
  63. package/templates/default/components/LoadingSpinners.tsx +67 -67
  64. package/templates/default/components/LocaleSwitcher.tsx +89 -89
  65. package/templates/default/components/LogPage.tsx +107 -107
  66. package/templates/default/components/Modal.tsx +166 -166
  67. package/templates/default/components/Navbar.tsx +258 -258
  68. package/templates/default/components/NewAdminForm.tsx +173 -173
  69. package/templates/default/components/NewPage.tsx +206 -206
  70. package/templates/default/components/NewVariantComponent.tsx +229 -229
  71. package/templates/default/components/PhotoGallery.tsx +35 -35
  72. package/templates/default/components/PieChartBox.tsx +101 -101
  73. package/templates/default/components/ProgressBar.tsx +48 -48
  74. package/templates/default/components/ProtectedDocument.tsx +44 -44
  75. package/templates/default/components/ProtectedImage.tsx +143 -143
  76. package/templates/default/components/ProtectedVideo.tsx +76 -76
  77. package/templates/default/components/SectionIcon.tsx +8 -8
  78. package/templates/default/components/SectionItemCard.tsx +144 -144
  79. package/templates/default/components/SectionItemStatusBadge.tsx +17 -17
  80. package/templates/default/components/SectionPage.tsx +205 -205
  81. package/templates/default/components/SelectBox.tsx +98 -98
  82. package/templates/default/components/SelectInputButtons.tsx +125 -125
  83. package/templates/default/components/SettingsPage.tsx +232 -232
  84. package/templates/default/components/Sidebar.tsx +204 -204
  85. package/templates/default/components/SidebarDropdownItem.tsx +83 -83
  86. package/templates/default/components/SidebarItem.tsx +24 -24
  87. package/templates/default/components/ThemeProvider.tsx +8 -8
  88. package/templates/default/components/TooltipComponent.tsx +27 -27
  89. package/templates/default/components/VariantCard.tsx +124 -124
  90. package/templates/default/components/VariantEditPage.tsx +230 -230
  91. package/templates/default/components/analytics/BounceRate.tsx +70 -70
  92. package/templates/default/components/analytics/LivePageViews.tsx +55 -55
  93. package/templates/default/components/analytics/LiveUsersCount.tsx +33 -33
  94. package/templates/default/components/analytics/MonthlyPageViews.tsx +42 -42
  95. package/templates/default/components/analytics/TopCountries.tsx +52 -52
  96. package/templates/default/components/analytics/TopDevices.tsx +46 -46
  97. package/templates/default/components/analytics/TopMediums.tsx +58 -58
  98. package/templates/default/components/analytics/TopSources.tsx +45 -45
  99. package/templates/default/components/analytics/TotalPageViews.tsx +41 -41
  100. package/templates/default/components/analytics/TotalSessions.tsx +41 -41
  101. package/templates/default/components/analytics/TotalUniqueUsers.tsx +41 -41
  102. package/templates/default/components/custom/RightHomeRoomVariantCard.tsx +138 -138
  103. package/templates/default/components/dndKit/Draggable.tsx +21 -21
  104. package/templates/default/components/dndKit/Droppable.tsx +20 -20
  105. package/templates/default/components/dndKit/SortableItem.tsx +18 -18
  106. package/templates/default/components/form/Form.tsx +370 -360
  107. package/templates/default/components/form/FormInputElement.tsx +70 -70
  108. package/templates/default/components/form/FormInputs.tsx +120 -111
  109. package/templates/default/components/form/helpers/_section-hot-reload.js +1 -1
  110. package/templates/default/components/form/helpers/util.ts +17 -17
  111. package/templates/default/components/form/inputs/CheckboxFormInput.tsx +46 -46
  112. package/templates/default/components/form/inputs/ColorFormInput.tsx +44 -44
  113. package/templates/default/components/form/inputs/DateFormInput.tsx +156 -156
  114. package/templates/default/components/form/inputs/DateRangeFormInput.tsx +153 -0
  115. package/templates/default/components/form/inputs/DocumentFormInput.tsx +222 -222
  116. package/templates/default/components/form/inputs/MapFormInput.tsx +140 -140
  117. package/templates/default/components/form/inputs/MultipleSelectFormInput.tsx +85 -85
  118. package/templates/default/components/form/inputs/NumberFormInput.tsx +43 -43
  119. package/templates/default/components/form/inputs/PasswordFormInput.tsx +47 -47
  120. package/templates/default/components/form/inputs/PhotoFormInput.tsx +275 -275
  121. package/templates/default/components/form/inputs/RichTextFormInput.tsx +138 -138
  122. package/templates/default/components/form/inputs/SelectFormInput.tsx +175 -175
  123. package/templates/default/components/form/inputs/SlugFormInput.tsx +131 -131
  124. package/templates/default/components/form/inputs/TagsFormInput.tsx +261 -260
  125. package/templates/default/components/form/inputs/TextFormInput.tsx +51 -51
  126. package/templates/default/components/form/inputs/TextareaFormInput.tsx +50 -50
  127. package/templates/default/components/form/inputs/VideoFormInput.tsx +118 -118
  128. package/templates/default/components/multi-select.tsx +1146 -1146
  129. package/templates/default/components/pagination/Pagination.tsx +36 -36
  130. package/templates/default/components/pagination/PaginationButtons.tsx +147 -147
  131. package/templates/default/components/theme-toggle.tsx +39 -39
  132. package/templates/default/components/ui/accordion.tsx +53 -53
  133. package/templates/default/components/ui/alert-dialog.tsx +157 -157
  134. package/templates/default/components/ui/alert.tsx +47 -47
  135. package/templates/default/components/ui/badge.tsx +38 -38
  136. package/templates/default/components/ui/button.tsx +62 -62
  137. package/templates/default/components/ui/calendar.tsx +166 -166
  138. package/templates/default/components/ui/card.tsx +43 -43
  139. package/templates/default/components/ui/checkbox.tsx +29 -29
  140. package/templates/default/components/ui/command.tsx +137 -137
  141. package/templates/default/components/ui/custom-alert-dialog.tsx +113 -113
  142. package/templates/default/components/ui/custom-dialog.tsx +123 -123
  143. package/templates/default/components/ui/dialog.tsx +123 -123
  144. package/templates/default/components/ui/direction.tsx +22 -22
  145. package/templates/default/components/ui/dropdown-menu.tsx +182 -182
  146. package/templates/default/components/ui/input-group.tsx +54 -54
  147. package/templates/default/components/ui/input.tsx +22 -22
  148. package/templates/default/components/ui/label.tsx +19 -19
  149. package/templates/default/components/ui/popover.tsx +42 -42
  150. package/templates/default/components/ui/progress.tsx +31 -31
  151. package/templates/default/components/ui/scroll-area.tsx +42 -42
  152. package/templates/default/components/ui/select.tsx +165 -165
  153. package/templates/default/components/ui/separator.tsx +28 -28
  154. package/templates/default/components/ui/sheet.tsx +103 -103
  155. package/templates/default/components/ui/spinner.tsx +16 -16
  156. package/templates/default/components/ui/switch.tsx +29 -29
  157. package/templates/default/components/ui/table.tsx +83 -83
  158. package/templates/default/components/ui/tabs.tsx +55 -55
  159. package/templates/default/components/ui/toast.tsx +113 -113
  160. package/templates/default/components/ui/toaster.tsx +35 -35
  161. package/templates/default/components/ui/tooltip.tsx +30 -30
  162. package/templates/default/components/ui/use-toast.ts +188 -188
  163. package/templates/default/components.json +21 -21
  164. package/templates/default/context/ModalProvider.tsx +53 -53
  165. package/templates/default/drizzle.config.ts +4 -4
  166. package/templates/default/env/env.js +130 -130
  167. package/templates/default/envConfig.ts +4 -4
  168. package/templates/default/hooks/useModal.ts +8 -8
  169. package/templates/default/lib/apiHelpers.ts +92 -92
  170. package/templates/default/lib/postinstall.js +14 -14
  171. package/templates/default/lib/utils.ts +6 -6
  172. package/templates/default/next-env.d.ts +6 -6
  173. package/templates/default/next.config.ts +23 -23
  174. package/templates/default/package.json +3 -3
  175. package/templates/default/postcss.config.mjs +6 -6
  176. package/templates/default/proxy.ts +32 -32
  177. package/templates/default/tsconfig.json +48 -48
  178. package/templates/default/app/(rootLayout)/dashboard-new/page.tsx +0 -7
  179. package/templates/default/components/DashboardNewPage.tsx +0 -253
  180. package/templates/default/components/DashboardPage.tsx +0 -188
  181. package/templates/default/components/EmailCard.tsx +0 -138
  182. package/templates/default/components/EmailPasswordForm.tsx +0 -85
  183. package/templates/default/components/EmailQuotaForm.tsx +0 -73
  184. package/templates/default/components/EmailsPage.tsx +0 -49
  185. package/templates/default/components/NewEmailForm.tsx +0 -132
  186. package/templates/default/components/form/DateRangeFormInput.tsx +0 -57
  187. package/templates/default/dynamic-schemas/schema.ts +0 -475
@@ -1,140 +1,140 @@
1
- import React, { useEffect } from 'react'
2
- import { APIProvider, Map, Marker } from '@vis.gl/react-google-maps'
3
- import ContainerBox from '@/components/ContainerBox'
4
- import { Button } from '@/components/ui/button'
5
- import TooltipComponent from '@/components/TooltipComponent'
6
- import { useI18n } from 'nextjs-cms/translations/client'
7
- import { MapFieldClientConfig } from 'nextjs-cms/core/fields'
8
- import { useController, useFormContext } from 'react-hook-form'
9
- import FormInputElement from '@/components/form/FormInputElement'
10
-
11
- export default function MapFormInput({ input }: { input: MapFieldClientConfig }) {
12
- const t = useI18n()
13
- const { control } = useFormContext()
14
- const {
15
- field,
16
- fieldState: { invalid, isTouched, isDirty, error },
17
- } = useController({
18
- name: input.name,
19
- control,
20
- defaultValue: input.value ?? undefined,
21
- })
22
-
23
- const [coords, setCoords] = React.useState<
24
- | {
25
- lat: number
26
- lng: number
27
- }
28
- | undefined
29
- >(() => {
30
- if (input.value?.lat && input.value?.lng) {
31
- return {
32
- lat: input.value.lat,
33
- lng: input.value.lng,
34
- }
35
- }
36
- })
37
-
38
- useEffect(() => {
39
- field.onChange(coords ? `${coords.lat},${coords.lng}` : undefined)
40
- }, [coords])
41
-
42
- return (
43
- <FormInputElement
44
- validationError={error}
45
- value={
46
- <span>
47
- {input.value?.lat}, {input.value?.lng}
48
- </span>
49
- }
50
- readonly={input.readonly}
51
- label={input.label}
52
- required={input.required}
53
- >
54
- <ContainerBox>
55
- <div className='relative h-[500px] w-full overflow-hidden rounded-xl outline-0'>
56
- <input
57
- type='hidden'
58
- value={coords ? `${coords.lat},${coords.lng}` : ''}
59
- disabled={field.disabled}
60
- name={field.name}
61
- onChange={field.onChange}
62
- onBlur={field.onBlur}
63
- ref={field.ref}
64
- />
65
- <APIProvider apiKey={process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY ?? ''}>
66
- <Map
67
- clickableIcons={false}
68
- zoomControl={true}
69
- onClick={(e) => {
70
- e.stop()
71
- setCoords(() => {
72
- if (e.detail.latLng) {
73
- return {
74
- lat: e.detail.latLng.lat,
75
- lng: e.detail.latLng.lng,
76
- }
77
- }
78
- })
79
- }}
80
- zoom={input.zoom}
81
- minZoom={input.minZoom}
82
- restriction={{
83
- latLngBounds: input.latLngBounds,
84
- strictBounds: true,
85
- }}
86
- center={input.value ? { lat: input.value.lat, lng: input.value.lng } : input.center}
87
- gestureHandling={'greedy'}
88
- disableDefaultUI={true}
89
- >
90
- {coords?.lat && coords?.lng ? (
91
- <Marker position={{ lat: coords.lat, lng: coords.lng }} />
92
- ) : null}
93
- </Map>
94
- </APIProvider>
95
- </div>
96
-
97
- <div className='my-2 flex flex-wrap gap-2'>
98
- <Button
99
- type='button'
100
- size={'sm'}
101
- disabled={!coords?.lat || !coords?.lng}
102
- variant='default'
103
- onClick={(e) => {
104
- e.preventDefault()
105
- e.stopPropagation()
106
- setCoords(undefined)
107
- }}
108
- >
109
- {t('removeMarker')}
110
- </Button>
111
- <TooltipComponent
112
- delayDuration={100}
113
- content={!(input.value?.lat && input.value?.lng) ? t('restoreMarkerTooltip') : null}
114
- >
115
- <Button
116
- type='button'
117
- size={'sm'}
118
- disabled={!(input.value?.lat && input.value?.lng)}
119
- variant='default'
120
- onClick={(e) => {
121
- e.preventDefault()
122
- e.stopPropagation()
123
- setCoords(() => {
124
- if (input.value?.lat && input.value?.lng) {
125
- return {
126
- lat: input.value.lat,
127
- lng: input.value.lng,
128
- }
129
- }
130
- })
131
- }}
132
- >
133
- {t('restoreMarker')}
134
- </Button>
135
- </TooltipComponent>
136
- </div>
137
- </ContainerBox>
138
- </FormInputElement>
139
- )
140
- }
1
+ import React, { useEffect } from 'react'
2
+ import { APIProvider, Map, Marker } from '@vis.gl/react-google-maps'
3
+ import ContainerBox from '@/components/ContainerBox'
4
+ import { Button } from '@/components/ui/button'
5
+ import TooltipComponent from '@/components/TooltipComponent'
6
+ import { useI18n } from 'nextjs-cms/translations/client'
7
+ import { MapFieldClientConfig } from 'nextjs-cms/core/fields'
8
+ import { useController, useFormContext } from 'react-hook-form'
9
+ import FormInputElement from '@/components/form/FormInputElement'
10
+
11
+ export default function MapFormInput({ input }: { input: MapFieldClientConfig }) {
12
+ const t = useI18n()
13
+ const { control } = useFormContext()
14
+ const {
15
+ field,
16
+ fieldState: { invalid, isTouched, isDirty, error },
17
+ } = useController({
18
+ name: input.name,
19
+ control,
20
+ defaultValue: input.value ?? undefined,
21
+ })
22
+
23
+ const [coords, setCoords] = React.useState<
24
+ | {
25
+ lat: number
26
+ lng: number
27
+ }
28
+ | undefined
29
+ >(() => {
30
+ if (input.value?.lat && input.value?.lng) {
31
+ return {
32
+ lat: input.value.lat,
33
+ lng: input.value.lng,
34
+ }
35
+ }
36
+ })
37
+
38
+ useEffect(() => {
39
+ field.onChange(coords ? `${coords.lat},${coords.lng}` : undefined)
40
+ }, [coords])
41
+
42
+ return (
43
+ <FormInputElement
44
+ validationError={error}
45
+ value={
46
+ <span>
47
+ {input.value?.lat}, {input.value?.lng}
48
+ </span>
49
+ }
50
+ readonly={input.readonly}
51
+ label={input.label}
52
+ required={input.required}
53
+ >
54
+ <ContainerBox>
55
+ <div className='relative h-[500px] w-full overflow-hidden rounded-xl outline-0'>
56
+ <input
57
+ type='hidden'
58
+ value={coords ? `${coords.lat},${coords.lng}` : ''}
59
+ disabled={field.disabled}
60
+ name={field.name}
61
+ onChange={field.onChange}
62
+ onBlur={field.onBlur}
63
+ ref={field.ref}
64
+ />
65
+ <APIProvider apiKey={process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY ?? ''}>
66
+ <Map
67
+ clickableIcons={false}
68
+ zoomControl={true}
69
+ onClick={(e) => {
70
+ e.stop()
71
+ setCoords(() => {
72
+ if (e.detail.latLng) {
73
+ return {
74
+ lat: e.detail.latLng.lat,
75
+ lng: e.detail.latLng.lng,
76
+ }
77
+ }
78
+ })
79
+ }}
80
+ zoom={input.zoom}
81
+ minZoom={input.minZoom}
82
+ restriction={{
83
+ latLngBounds: input.latLngBounds,
84
+ strictBounds: true,
85
+ }}
86
+ center={input.value ? { lat: input.value.lat, lng: input.value.lng } : input.center}
87
+ gestureHandling={'greedy'}
88
+ disableDefaultUI={true}
89
+ >
90
+ {coords?.lat && coords?.lng ? (
91
+ <Marker position={{ lat: coords.lat, lng: coords.lng }} />
92
+ ) : null}
93
+ </Map>
94
+ </APIProvider>
95
+ </div>
96
+
97
+ <div className='my-2 flex flex-wrap gap-2'>
98
+ <Button
99
+ type='button'
100
+ size={'sm'}
101
+ disabled={!coords?.lat || !coords?.lng}
102
+ variant='default'
103
+ onClick={(e) => {
104
+ e.preventDefault()
105
+ e.stopPropagation()
106
+ setCoords(undefined)
107
+ }}
108
+ >
109
+ {t('removeMarker')}
110
+ </Button>
111
+ <TooltipComponent
112
+ delayDuration={100}
113
+ content={!(input.value?.lat && input.value?.lng) ? t('restoreMarkerTooltip') : null}
114
+ >
115
+ <Button
116
+ type='button'
117
+ size={'sm'}
118
+ disabled={!(input.value?.lat && input.value?.lng)}
119
+ variant='default'
120
+ onClick={(e) => {
121
+ e.preventDefault()
122
+ e.stopPropagation()
123
+ setCoords(() => {
124
+ if (input.value?.lat && input.value?.lng) {
125
+ return {
126
+ lat: input.value.lat,
127
+ lng: input.value.lng,
128
+ }
129
+ }
130
+ })
131
+ }}
132
+ >
133
+ {t('restoreMarker')}
134
+ </Button>
135
+ </TooltipComponent>
136
+ </div>
137
+ </ContainerBox>
138
+ </FormInputElement>
139
+ )
140
+ }
@@ -1,85 +1,85 @@
1
- import FormInputElement from '@/components/form/FormInputElement'
2
- import { useEffect, useState } from 'react'
3
- import { SelectMultipleFieldClientConfig, SelectOption } from 'nextjs-cms/core/fields'
4
- import { useController, useFormContext } from 'react-hook-form'
5
- import { MultiSelect, MultiSelectOption } from '@/components/multi-select'
6
- import { useI18n } from 'nextjs-cms/translations/client'
7
-
8
- export default function MultipleSelectFormInput({ input }: { input: SelectMultipleFieldClientConfig }) {
9
- const t = useI18n()
10
- const { control } = useFormContext()
11
- const {
12
- field,
13
- fieldState: { invalid, isTouched, isDirty, error },
14
- } = useController({
15
- name: input.name,
16
- control,
17
- defaultValue: input.value,
18
- })
19
-
20
- const [value, setValue] = useState<SelectOption[] | undefined>([])
21
-
22
- // Convert SelectOption[] to MultiSelectOption[]
23
- const convertToMultiSelectOptions = (options: SelectOption[] | undefined): MultiSelectOption[] => {
24
- if (!options) return []
25
- return options.map((option) => ({
26
- label: option.label.toString(),
27
- value: option.value.toString(),
28
- }))
29
- }
30
-
31
- // Convert string[] to SelectOption[]
32
- const convertFromStringArray = (values: string[], options: SelectOption[] | undefined): SelectOption[] => {
33
- if (!options || !values) return []
34
- return values
35
- .map((value) => options.find((option) => option.value.toString() === value))
36
- .filter(Boolean) as SelectOption[]
37
- }
38
-
39
- // Convert SelectOption[] to string[]
40
- const convertToStringArray = (options: SelectOption[] | undefined): string[] => {
41
- if (!options) return []
42
- return options.map((option) => option.value.toString())
43
- }
44
-
45
- useEffect(() => {
46
- if (input.value && input.value?.length > 0) {
47
- setValue(input.value)
48
- }
49
- }, [input.value])
50
-
51
- const multiSelectOptions = convertToMultiSelectOptions(input.options)
52
- const currentValue = convertToStringArray(field.value || [])
53
-
54
- const handleValueChange = (newValues: string[]) => {
55
- const selectOptions = convertFromStringArray(newValues, input.options)
56
- field.onChange(selectOptions)
57
- setValue(selectOptions)
58
- }
59
-
60
- return (
61
- <FormInputElement validationError={error} label={input.label} required={input.required}>
62
- <input
63
- type='hidden'
64
- className='hidden'
65
- disabled={field.disabled}
66
- name={field.name}
67
- onBlur={field.onBlur}
68
- ref={field.ref}
69
- value={JSON.stringify(field.value)}
70
- />
71
-
72
- <MultiSelect
73
- hideSelectAll={true}
74
- variant='default'
75
- maxCount={100}
76
- options={multiSelectOptions}
77
- onValueChange={handleValueChange}
78
- defaultValue={currentValue}
79
- placeholder={t('selectOptions') as string}
80
- disabled={field.disabled}
81
- className='w-full py-3 ring-2 ring-gray-300'
82
- />
83
- </FormInputElement>
84
- )
85
- }
1
+ import FormInputElement from '@/components/form/FormInputElement'
2
+ import { useEffect, useState } from 'react'
3
+ import { SelectMultipleFieldClientConfig, SelectOption } from 'nextjs-cms/core/fields'
4
+ import { useController, useFormContext } from 'react-hook-form'
5
+ import { MultiSelect, MultiSelectOption } from '@/components/multi-select'
6
+ import { useI18n } from 'nextjs-cms/translations/client'
7
+
8
+ export default function MultipleSelectFormInput({ input }: { input: SelectMultipleFieldClientConfig }) {
9
+ const t = useI18n()
10
+ const { control } = useFormContext()
11
+ const {
12
+ field,
13
+ fieldState: { invalid, isTouched, isDirty, error },
14
+ } = useController({
15
+ name: input.name,
16
+ control,
17
+ defaultValue: input.value,
18
+ })
19
+
20
+ const [value, setValue] = useState<SelectOption[] | undefined>([])
21
+
22
+ // Convert SelectOption[] to MultiSelectOption[]
23
+ const convertToMultiSelectOptions = (options: SelectOption[] | undefined): MultiSelectOption[] => {
24
+ if (!options) return []
25
+ return options.map((option) => ({
26
+ label: option.label.toString(),
27
+ value: option.value.toString(),
28
+ }))
29
+ }
30
+
31
+ // Convert string[] to SelectOption[]
32
+ const convertFromStringArray = (values: string[], options: SelectOption[] | undefined): SelectOption[] => {
33
+ if (!options || !values) return []
34
+ return values
35
+ .map((value) => options.find((option) => option.value.toString() === value))
36
+ .filter(Boolean) as SelectOption[]
37
+ }
38
+
39
+ // Convert SelectOption[] to string[]
40
+ const convertToStringArray = (options: SelectOption[] | undefined): string[] => {
41
+ if (!options) return []
42
+ return options.map((option) => option.value.toString())
43
+ }
44
+
45
+ useEffect(() => {
46
+ if (input.value && input.value?.length > 0) {
47
+ setValue(input.value)
48
+ }
49
+ }, [input.value])
50
+
51
+ const multiSelectOptions = convertToMultiSelectOptions(input.options)
52
+ const currentValue = convertToStringArray(field.value || [])
53
+
54
+ const handleValueChange = (newValues: string[]) => {
55
+ const selectOptions = convertFromStringArray(newValues, input.options)
56
+ field.onChange(selectOptions)
57
+ setValue(selectOptions)
58
+ }
59
+
60
+ return (
61
+ <FormInputElement validationError={error} label={input.label} required={input.required}>
62
+ <input
63
+ type='hidden'
64
+ className='hidden'
65
+ disabled={field.disabled}
66
+ name={field.name}
67
+ onBlur={field.onBlur}
68
+ ref={field.ref}
69
+ value={JSON.stringify(field.value)}
70
+ />
71
+
72
+ <MultiSelect
73
+ hideSelectAll={true}
74
+ variant='default'
75
+ maxCount={100}
76
+ options={multiSelectOptions}
77
+ onValueChange={handleValueChange}
78
+ defaultValue={currentValue}
79
+ placeholder={t('selectOptions') as string}
80
+ disabled={field.disabled}
81
+ className='w-full py-3 ring-2 ring-gray-300'
82
+ />
83
+ </FormInputElement>
84
+ )
85
+ }
@@ -1,43 +1,43 @@
1
- import React from 'react'
2
- import FormInputElement from '@/components/form/FormInputElement'
3
- import type { NumberFieldClientConfig } from 'nextjs-cms/core/fields'
4
- import { useController, useFormContext } from 'react-hook-form'
5
- import { isNumber, toNumber } from 'lodash-es'
6
-
7
- export default function NumberFormInput({ input }: { input: NumberFieldClientConfig }) {
8
- const { control } = useFormContext()
9
- const {
10
- field,
11
- fieldState: { invalid, isTouched, isDirty, error },
12
- } = useController({
13
- name: input.name,
14
- control,
15
- defaultValue: isNumber(input.value) ? input.value : undefined,
16
- disabled: input.readonly,
17
- })
18
- return (
19
- <FormInputElement
20
- validationError={error}
21
- value={input.value}
22
- label={input.label}
23
- required={input.required}
24
- readonly={input.readonly}
25
- >
26
- <input
27
- type='number'
28
- placeholder={input.label}
29
- dir={input.rtl !== undefined ? (input.rtl ? 'rtl' : 'ltr') : undefined}
30
- readOnly={field.disabled}
31
- disabled={field.disabled}
32
- name={field.name}
33
- onChange={(event) =>
34
- event.target.value ? field.onChange(toNumber(event.target.value)) : field.onChange(NaN)
35
- }
36
- onBlur={field.onBlur}
37
- value={field.value ?? ''}
38
- ref={field.ref}
39
- className='w-full rounded bg-input p-3 text-foreground shadow-xs outline-0 ring-2 ring-gray-300 hover:ring-gray-400 focus:ring-blue-500'
40
- />
41
- </FormInputElement>
42
- )
43
- }
1
+ import React from 'react'
2
+ import FormInputElement from '@/components/form/FormInputElement'
3
+ import type { NumberFieldClientConfig } from 'nextjs-cms/core/fields'
4
+ import { useController, useFormContext } from 'react-hook-form'
5
+ import { isNumber, toNumber } from 'lodash-es'
6
+
7
+ export default function NumberFormInput({ input }: { input: NumberFieldClientConfig }) {
8
+ const { control } = useFormContext()
9
+ const {
10
+ field,
11
+ fieldState: { invalid, isTouched, isDirty, error },
12
+ } = useController({
13
+ name: input.name,
14
+ control,
15
+ defaultValue: isNumber(input.value) ? input.value : undefined,
16
+ disabled: input.readonly,
17
+ })
18
+ return (
19
+ <FormInputElement
20
+ validationError={error}
21
+ value={input.value}
22
+ label={input.label}
23
+ required={input.required}
24
+ readonly={input.readonly}
25
+ >
26
+ <input
27
+ type='number'
28
+ placeholder={input.label}
29
+ dir={input.rtl !== undefined ? (input.rtl ? 'rtl' : 'ltr') : undefined}
30
+ readOnly={field.disabled}
31
+ disabled={field.disabled}
32
+ name={field.name}
33
+ onChange={(event) =>
34
+ event.target.value ? field.onChange(toNumber(event.target.value)) : field.onChange(NaN)
35
+ }
36
+ onBlur={field.onBlur}
37
+ value={field.value ?? ''}
38
+ ref={field.ref}
39
+ className='w-full rounded bg-input p-3 text-foreground shadow-xs outline-0 ring-2 ring-gray-300 hover:ring-gray-400 focus:ring-blue-500'
40
+ />
41
+ </FormInputElement>
42
+ )
43
+ }
@@ -1,47 +1,47 @@
1
- import React from 'react'
2
- import FormInputElement from '@/components/form/FormInputElement'
3
- import { PasswordFieldClientConfig } from 'nextjs-cms/core/fields'
4
- import { useController, useFormContext } from 'react-hook-form'
5
-
6
- export default function PasswordFormInput({
7
- input,
8
- defaultValue,
9
- direction,
10
- }: {
11
- input: PasswordFieldClientConfig
12
- defaultValue?: string | null
13
- direction?: 'row' | 'col'
14
- }) {
15
- const { control } = useFormContext()
16
- const {
17
- field,
18
- fieldState: { invalid, isTouched, isDirty, error },
19
- } = useController({
20
- name: input.name,
21
- control,
22
- defaultValue: defaultValue ?? input.value ?? undefined,
23
- disabled: input.readonly,
24
- })
25
- return (
26
- <FormInputElement
27
- validationError={error}
28
- value={'********'}
29
- readonly={input.readonly}
30
- label={input.label}
31
- required={input.required}
32
- >
33
- <input
34
- placeholder={input.placeholder ? input.placeholder : input.label}
35
- type='password'
36
- readOnly={input.readonly}
37
- disabled={field.disabled}
38
- name={field.name}
39
- onChange={field.onChange}
40
- onBlur={field.onBlur}
41
- value={field.value}
42
- ref={field.ref}
43
- className='w-full rounded bg-input p-3 text-foreground shadow-xs outline-0 ring-2 ring-gray-300 hover:ring-gray-400 focus:ring-blue-500'
44
- />
45
- </FormInputElement>
46
- )
47
- }
1
+ import React from 'react'
2
+ import FormInputElement from '@/components/form/FormInputElement'
3
+ import { PasswordFieldClientConfig } from 'nextjs-cms/core/fields'
4
+ import { useController, useFormContext } from 'react-hook-form'
5
+
6
+ export default function PasswordFormInput({
7
+ input,
8
+ defaultValue,
9
+ direction,
10
+ }: {
11
+ input: PasswordFieldClientConfig
12
+ defaultValue?: string | null
13
+ direction?: 'row' | 'col'
14
+ }) {
15
+ const { control } = useFormContext()
16
+ const {
17
+ field,
18
+ fieldState: { invalid, isTouched, isDirty, error },
19
+ } = useController({
20
+ name: input.name,
21
+ control,
22
+ defaultValue: defaultValue ?? input.value ?? undefined,
23
+ disabled: input.readonly,
24
+ })
25
+ return (
26
+ <FormInputElement
27
+ validationError={error}
28
+ value={'********'}
29
+ readonly={input.readonly}
30
+ label={input.label}
31
+ required={input.required}
32
+ >
33
+ <input
34
+ placeholder={input.placeholder ? input.placeholder : input.label}
35
+ type='password'
36
+ readOnly={input.readonly}
37
+ disabled={field.disabled}
38
+ name={field.name}
39
+ onChange={field.onChange}
40
+ onBlur={field.onBlur}
41
+ value={field.value}
42
+ ref={field.ref}
43
+ className='w-full rounded bg-input p-3 text-foreground shadow-xs outline-0 ring-2 ring-gray-300 hover:ring-gray-400 focus:ring-blue-500'
44
+ />
45
+ </FormInputElement>
46
+ )
47
+ }