create-nextjs-cms 0.5.8

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 -0
  2. package/README.md +71 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +395 -0
  6. package/dist/lib/utils.d.ts +11 -0
  7. package/dist/lib/utils.d.ts.map +1 -0
  8. package/dist/lib/utils.js +48 -0
  9. package/package.json +44 -0
  10. package/templates/default/.env +24 -0
  11. package/templates/default/.env.development +8 -0
  12. package/templates/default/.eslintrc.json +5 -0
  13. package/templates/default/.prettierignore +7 -0
  14. package/templates/default/.prettierrc.json +19 -0
  15. package/templates/default/CHANGELOG.md +77 -0
  16. package/templates/default/README.md +45 -0
  17. package/templates/default/app/(auth)/auth/login/LoginPage.tsx +175 -0
  18. package/templates/default/app/(auth)/auth/login/page.tsx +12 -0
  19. package/templates/default/app/(rootLayout)/admins/page.tsx +5 -0
  20. package/templates/default/app/(rootLayout)/advanced/page.tsx +5 -0
  21. package/templates/default/app/(rootLayout)/analytics/page.tsx +7 -0
  22. package/templates/default/app/(rootLayout)/browse/[section]/[page]/page.tsx +7 -0
  23. package/templates/default/app/(rootLayout)/categorized/[section]/page.tsx +7 -0
  24. package/templates/default/app/(rootLayout)/dashboard/page.tsx +7 -0
  25. package/templates/default/app/(rootLayout)/edit/[section]/[itemId]/page.tsx +7 -0
  26. package/templates/default/app/(rootLayout)/emails/page.tsx +6 -0
  27. package/templates/default/app/(rootLayout)/layout.tsx +5 -0
  28. package/templates/default/app/(rootLayout)/loading.tsx +10 -0
  29. package/templates/default/app/(rootLayout)/log/page.tsx +7 -0
  30. package/templates/default/app/(rootLayout)/new/[section]/page.tsx +7 -0
  31. package/templates/default/app/(rootLayout)/page.tsx +9 -0
  32. package/templates/default/app/(rootLayout)/section/[section]/page.tsx +7 -0
  33. package/templates/default/app/(rootLayout)/settings/page.tsx +7 -0
  34. package/templates/default/app/_trpc/client.ts +4 -0
  35. package/templates/default/app/api/auth/csrf/route.ts +25 -0
  36. package/templates/default/app/api/auth/refresh/route.ts +10 -0
  37. package/templates/default/app/api/auth/route.ts +23 -0
  38. package/templates/default/app/api/auth/session/route.ts +20 -0
  39. package/templates/default/app/api/editor/photo/route.ts +42 -0
  40. package/templates/default/app/api/photo/route.ts +27 -0
  41. package/templates/default/app/api/placeholder/route.ts +7 -0
  42. package/templates/default/app/api/submit/section/item/[slug]/route.ts +63 -0
  43. package/templates/default/app/api/submit/section/item/route.ts +53 -0
  44. package/templates/default/app/api/submit/section/simple/route.ts +54 -0
  45. package/templates/default/app/api/trpc/[trpc]/route.ts +33 -0
  46. package/templates/default/app/api/video/route.ts +174 -0
  47. package/templates/default/app/dictionaries.ts +14 -0
  48. package/templates/default/app/layout.tsx +28 -0
  49. package/templates/default/app/providers.tsx +151 -0
  50. package/templates/default/cli.ts +4 -0
  51. package/templates/default/components/AdminCard.tsx +163 -0
  52. package/templates/default/components/AdminEditPage.tsx +123 -0
  53. package/templates/default/components/AdminPrivilegeCard.tsx +184 -0
  54. package/templates/default/components/AdminsPage.tsx +43 -0
  55. package/templates/default/components/AdvancedSettingsPage.tsx +167 -0
  56. package/templates/default/components/AnalyticsPage.tsx +127 -0
  57. package/templates/default/components/BarChartBox.tsx +43 -0
  58. package/templates/default/components/BrowsePage.tsx +119 -0
  59. package/templates/default/components/CategorizedSectionPage.tsx +36 -0
  60. package/templates/default/components/CategoryDeleteConfirmPage.tsx +129 -0
  61. package/templates/default/components/CategorySectionSelectInput.tsx +139 -0
  62. package/templates/default/components/ConditionalFields.tsx +49 -0
  63. package/templates/default/components/ContainerBox.tsx +24 -0
  64. package/templates/default/components/DashboardPage.tsx +187 -0
  65. package/templates/default/components/DashboardPageAlt.tsx +43 -0
  66. package/templates/default/components/DefaultNavItems.tsx +3 -0
  67. package/templates/default/components/Dropzone.tsx +153 -0
  68. package/templates/default/components/EmailCard.tsx +137 -0
  69. package/templates/default/components/EmailPasswordForm.tsx +84 -0
  70. package/templates/default/components/EmailQuotaForm.tsx +72 -0
  71. package/templates/default/components/EmailsPage.tsx +48 -0
  72. package/templates/default/components/GalleryPhoto.tsx +93 -0
  73. package/templates/default/components/InfoCard.tsx +94 -0
  74. package/templates/default/components/ItemEditPage.tsx +217 -0
  75. package/templates/default/components/Layout.tsx +70 -0
  76. package/templates/default/components/LoadingSpinners.tsx +67 -0
  77. package/templates/default/components/LogPage.tsx +17 -0
  78. package/templates/default/components/Modal.tsx +99 -0
  79. package/templates/default/components/Navbar.tsx +29 -0
  80. package/templates/default/components/NavbarAlt.tsx +182 -0
  81. package/templates/default/components/NewAdminForm.tsx +172 -0
  82. package/templates/default/components/NewEmailForm.tsx +131 -0
  83. package/templates/default/components/NewPage.tsx +206 -0
  84. package/templates/default/components/NewVariantComponent.tsx +228 -0
  85. package/templates/default/components/PhotoGallery.tsx +35 -0
  86. package/templates/default/components/PieChartBox.tsx +101 -0
  87. package/templates/default/components/ProgressBar.tsx +24 -0
  88. package/templates/default/components/ProtectedDocument.tsx +78 -0
  89. package/templates/default/components/ProtectedImage.tsx +143 -0
  90. package/templates/default/components/ProtectedVideo.tsx +76 -0
  91. package/templates/default/components/SectionItemCard.tsx +143 -0
  92. package/templates/default/components/SectionItemStatusBadge.tsx +16 -0
  93. package/templates/default/components/SectionPage.tsx +124 -0
  94. package/templates/default/components/SelectBox.tsx +99 -0
  95. package/templates/default/components/SelectInputButtons.tsx +124 -0
  96. package/templates/default/components/SettingsPage.tsx +238 -0
  97. package/templates/default/components/Sidebar.tsx +209 -0
  98. package/templates/default/components/SidebarDropdownItem.tsx +74 -0
  99. package/templates/default/components/SidebarItem.tsx +19 -0
  100. package/templates/default/components/TempPage.tsx +12 -0
  101. package/templates/default/components/ThemeProvider.tsx +8 -0
  102. package/templates/default/components/TooltipComponent.tsx +27 -0
  103. package/templates/default/components/VariantCard.tsx +123 -0
  104. package/templates/default/components/VariantEditPage.tsx +229 -0
  105. package/templates/default/components/analytics/BounceRate.tsx +69 -0
  106. package/templates/default/components/analytics/LivePageViews.tsx +54 -0
  107. package/templates/default/components/analytics/LiveUsersCount.tsx +32 -0
  108. package/templates/default/components/analytics/MonthlyPageViews.tsx +41 -0
  109. package/templates/default/components/analytics/TopCountries.tsx +51 -0
  110. package/templates/default/components/analytics/TopDevices.tsx +45 -0
  111. package/templates/default/components/analytics/TopMediums.tsx +57 -0
  112. package/templates/default/components/analytics/TopSources.tsx +44 -0
  113. package/templates/default/components/analytics/TotalPageViews.tsx +40 -0
  114. package/templates/default/components/analytics/TotalSessions.tsx +40 -0
  115. package/templates/default/components/analytics/TotalUniqueUsers.tsx +40 -0
  116. package/templates/default/components/custom/RightHomeRoomVariantCard.tsx +137 -0
  117. package/templates/default/components/dndKit/Draggable.tsx +21 -0
  118. package/templates/default/components/dndKit/Droppable.tsx +20 -0
  119. package/templates/default/components/dndKit/SortableItem.tsx +18 -0
  120. package/templates/default/components/form/DateRangeFormInput.tsx +55 -0
  121. package/templates/default/components/form/Form.tsx +298 -0
  122. package/templates/default/components/form/FormInputElement.tsx +68 -0
  123. package/templates/default/components/form/FormInputs.tsx +108 -0
  124. package/templates/default/components/form/helpers/util.ts +20 -0
  125. package/templates/default/components/form/inputs/CheckboxFormInput.tsx +33 -0
  126. package/templates/default/components/form/inputs/ColorFormInput.tsx +44 -0
  127. package/templates/default/components/form/inputs/DateFormInput.tsx +107 -0
  128. package/templates/default/components/form/inputs/DocumentFormInput.tsx +124 -0
  129. package/templates/default/components/form/inputs/MapFormInput.tsx +139 -0
  130. package/templates/default/components/form/inputs/MultipleSelectFormInput.tsx +150 -0
  131. package/templates/default/components/form/inputs/NumberFormInput.tsx +42 -0
  132. package/templates/default/components/form/inputs/PasswordFormInput.tsx +47 -0
  133. package/templates/default/components/form/inputs/PhotoFormInput.tsx +218 -0
  134. package/templates/default/components/form/inputs/RichTextFormInput.tsx +133 -0
  135. package/templates/default/components/form/inputs/SelectFormInput.tsx +164 -0
  136. package/templates/default/components/form/inputs/TagsFormInput.tsx +63 -0
  137. package/templates/default/components/form/inputs/TextFormInput.tsx +48 -0
  138. package/templates/default/components/form/inputs/TextareaFormInput.tsx +47 -0
  139. package/templates/default/components/form/inputs/VideoFormInput.tsx +117 -0
  140. package/templates/default/components/pagination/Pagination.tsx +36 -0
  141. package/templates/default/components/pagination/PaginationButtons.tsx +145 -0
  142. package/templates/default/components/ui/accordion.tsx +57 -0
  143. package/templates/default/components/ui/alert.tsx +46 -0
  144. package/templates/default/components/ui/badge.tsx +33 -0
  145. package/templates/default/components/ui/button.tsx +57 -0
  146. package/templates/default/components/ui/calendar.tsx +68 -0
  147. package/templates/default/components/ui/card.tsx +76 -0
  148. package/templates/default/components/ui/checkbox.tsx +29 -0
  149. package/templates/default/components/ui/dropdown-menu.tsx +205 -0
  150. package/templates/default/components/ui/input.tsx +25 -0
  151. package/templates/default/components/ui/label.tsx +26 -0
  152. package/templates/default/components/ui/popover.tsx +31 -0
  153. package/templates/default/components/ui/scroll-area.tsx +42 -0
  154. package/templates/default/components/ui/select.tsx +164 -0
  155. package/templates/default/components/ui/sheet.tsx +107 -0
  156. package/templates/default/components/ui/switch.tsx +29 -0
  157. package/templates/default/components/ui/table.tsx +120 -0
  158. package/templates/default/components/ui/tabs.tsx +55 -0
  159. package/templates/default/components/ui/toast.tsx +113 -0
  160. package/templates/default/components/ui/toaster.tsx +35 -0
  161. package/templates/default/components/ui/tooltip.tsx +30 -0
  162. package/templates/default/components/ui/use-toast.ts +188 -0
  163. package/templates/default/components.json +16 -0
  164. package/templates/default/context/ModalProvider.tsx +53 -0
  165. package/templates/default/drizzle.config.ts +4 -0
  166. package/templates/default/dynamic-schemas/schema.ts +373 -0
  167. package/templates/default/env/env.js +130 -0
  168. package/templates/default/envConfig.ts +4 -0
  169. package/templates/default/hooks/useModal.ts +8 -0
  170. package/templates/default/lib/apiHelpers.ts +106 -0
  171. package/templates/default/lz.config.ts +40 -0
  172. package/templates/default/middleware.ts +33 -0
  173. package/templates/default/next.config.ts +46 -0
  174. package/templates/default/package.json +134 -0
  175. package/templates/default/postcss.config.js +6 -0
  176. package/templates/default/postinstall.js +14 -0
  177. package/templates/default/public/blank_avatar.png +0 -0
  178. package/templates/default/public/favicon.ico +0 -0
  179. package/templates/default/public/img/placeholder.svg +1 -0
  180. package/templates/default/public/lazemni_logo.png +0 -0
  181. package/templates/default/public/next.svg +1 -0
  182. package/templates/default/public/vercel.svg +1 -0
  183. package/templates/default/section-tests.ts +92 -0
  184. package/templates/default/styles/globals.css +88 -0
  185. package/templates/default/tailwind.config.js +95 -0
  186. package/templates/default/test.ts +77 -0
  187. package/templates/default/tsconfig.json +44 -0
@@ -0,0 +1,45 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import { BarChartDataItem } from 'nextjs-cms/core/types'
3
+ import { Badge } from '@/components/ui/badge'
4
+ import { formatNumber } from 'nextjs-cms/utils'
5
+ import ContainerBox from '@/components/ContainerBox'
6
+ import React from 'react'
7
+ import { useAxiosPrivate } from 'nextjs-cms/auth/hooks'
8
+ import { useQuery } from '@tanstack/react-query'
9
+ import { getAnalytics } from '@/lib/apiHelpers'
10
+ import LoadingSpinners from '@/components/LoadingSpinners'
11
+
12
+ export const TopDevices = ({ fromDate, toDate }: { fromDate: Date | string | null; toDate: Date | string | null }) => {
13
+ const axiosPrivate = useAxiosPrivate()
14
+ const controller = new AbortController()
15
+
16
+ const { isLoading, isError, data, error } = useQuery({
17
+ queryKey: ['analyticsPage', 'topDevices', fromDate, toDate],
18
+ queryFn: () =>
19
+ getAnalytics({
20
+ requestType: 'topDevices',
21
+ axiosPrivate,
22
+ controller,
23
+ fromDate,
24
+ toDate,
25
+ }),
26
+ })
27
+
28
+ return (
29
+ <ContainerBox title={getString('devices')}>
30
+ <div className='w-full'>
31
+ <h1 className='font-bold border-b pb-1 my-1'>{getString('topDevices')}</h1>
32
+ {isLoading && <LoadingSpinners single={true} />}
33
+ {data?.topDevices?.length > 0 &&
34
+ data.topDevices.map((device: BarChartDataItem, index: number) => (
35
+ <div key={`${index}-${device.name}`} className='w-full text-sm flex justify-between'>
36
+ <span className='font-bold text-foreground'>{device.name}:</span>
37
+ <Badge variant='outline' className='ms-2'>
38
+ {formatNumber(device.value)}
39
+ </Badge>
40
+ </div>
41
+ ))}
42
+ </div>
43
+ </ContainerBox>
44
+ )
45
+ }
@@ -0,0 +1,57 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import { BarChartDataItem } from 'nextjs-cms/core/types'
3
+ import { Badge } from '@/components/ui/badge'
4
+ import { formatNumber } from 'nextjs-cms/utils'
5
+ import ContainerBox from '@/components/ContainerBox'
6
+ import React, { useEffect } from 'react'
7
+ import { useAxiosPrivate } from 'nextjs-cms/auth/hooks'
8
+ import { useQuery } from '@tanstack/react-query'
9
+ import { getAnalytics } from '@/lib/apiHelpers'
10
+ import LoadingSpinners from '@/components/LoadingSpinners'
11
+
12
+ export const TopMediums = ({ fromDate, toDate }: { fromDate: Date | string | null; toDate: Date | string | null }) => {
13
+ const axiosPrivate = useAxiosPrivate()
14
+ let controller = new AbortController()
15
+
16
+ const { isLoading, isError, data, error } = useQuery({
17
+ queryKey: ['analyticsPage', 'topMediums', fromDate, toDate],
18
+ queryFn: () => {
19
+ // Abort the previous request
20
+ controller.abort()
21
+
22
+ // Create a new AbortController for the new request
23
+ controller = new AbortController()
24
+ return getAnalytics({
25
+ requestType: 'topMediums',
26
+ axiosPrivate,
27
+ controller,
28
+ fromDate,
29
+ toDate,
30
+ })
31
+ },
32
+ })
33
+
34
+ useEffect(() => {
35
+ return () => {
36
+ controller.abort()
37
+ }
38
+ }, [])
39
+
40
+ return (
41
+ <ContainerBox title={getString('mediums')}>
42
+ <div className='w-full mb-6'>
43
+ <h1 className='font-bold border-b pb-1 my-1'>{getString('topMediums')}</h1>
44
+ {isLoading && <LoadingSpinners single={true} />}
45
+ {data?.topMediums?.length > 0 &&
46
+ data.topMediums.map((medium: BarChartDataItem, index: number) => (
47
+ <div key={`${index}-${medium.name}`} className='w-full text-sm flex justify-between'>
48
+ <span className='font-bold text-foreground'>{medium.name}:</span>
49
+ <Badge variant='outline' className='ms-2'>
50
+ {formatNumber(medium.value)}
51
+ </Badge>
52
+ </div>
53
+ ))}
54
+ </div>
55
+ </ContainerBox>
56
+ )
57
+ }
@@ -0,0 +1,44 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import { BarChartDataItem } from 'nextjs-cms/core/types'
3
+ import { Badge } from '@/components/ui/badge'
4
+ import { formatNumber } from 'nextjs-cms/utils'
5
+ import ContainerBox from '@/components/ContainerBox'
6
+ import React from 'react'
7
+ import { useAxiosPrivate } from 'nextjs-cms/auth/hooks'
8
+ import { useQuery } from '@tanstack/react-query'
9
+ import { getAnalytics } from '@/lib/apiHelpers'
10
+ import LoadingSpinners from '@/components/LoadingSpinners'
11
+
12
+ export const TopSources = ({ fromDate, toDate }: { fromDate: Date | string | null; toDate: Date | string | null }) => {
13
+ const axiosPrivate = useAxiosPrivate()
14
+ const controller = new AbortController()
15
+
16
+ const { isLoading, isError, data, error } = useQuery({
17
+ queryKey: ['analyticsPage', 'topSources', fromDate, toDate],
18
+ queryFn: () =>
19
+ getAnalytics({
20
+ requestType: 'topSources',
21
+ axiosPrivate,
22
+ controller,
23
+ fromDate,
24
+ toDate,
25
+ }),
26
+ })
27
+ return (
28
+ <ContainerBox title={getString('sources')}>
29
+ <div className='w-full mb-6'>
30
+ <h1 className='font-bold border-b pb-1 my-1'>{getString('topSources')}</h1>
31
+ {isLoading && <LoadingSpinners single={true} />}
32
+ {data?.topSources?.length > 0 &&
33
+ data.topSources.map((source: BarChartDataItem, index: number) => (
34
+ <div key={`${index}-${source.name}`} className='w-full text-sm flex justify-between'>
35
+ <span className='font-bold text-foreground'>{source.name}:</span>
36
+ <Badge variant='outline' className='ms-2'>
37
+ {formatNumber(source.value)}
38
+ </Badge>
39
+ </div>
40
+ ))}
41
+ </div>
42
+ </ContainerBox>
43
+ )
44
+ }
@@ -0,0 +1,40 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import { formatNumber } from 'nextjs-cms/utils'
3
+ import ContainerBox from '@/components/ContainerBox'
4
+ import React from 'react'
5
+ import { useAxiosPrivate } from 'nextjs-cms/auth/hooks'
6
+ import { useQuery } from '@tanstack/react-query'
7
+ import { getAnalytics } from '@/lib/apiHelpers'
8
+ import LoadingSpinners from '@/components/LoadingSpinners'
9
+
10
+ export const TotalPageViews = ({
11
+ fromDate,
12
+ toDate,
13
+ }: {
14
+ fromDate: Date | string | null
15
+ toDate: Date | string | null
16
+ }) => {
17
+ const axiosPrivate = useAxiosPrivate()
18
+ const controller = new AbortController()
19
+
20
+ const { isLoading, isError, data, error } = useQuery({
21
+ queryKey: ['analyticsPage', 'statistics', fromDate, toDate],
22
+ queryFn: () =>
23
+ getAnalytics({
24
+ requestType: 'statistics',
25
+ axiosPrivate,
26
+ controller,
27
+ fromDate,
28
+ toDate,
29
+ }),
30
+ })
31
+ return (
32
+ <ContainerBox title={getString('totalPageViews')}>
33
+ {isLoading ? (
34
+ <LoadingSpinners single={true} />
35
+ ) : (
36
+ <div className='text-4xl'>{formatNumber(data?.totalPageViews)}</div>
37
+ )}
38
+ </ContainerBox>
39
+ )
40
+ }
@@ -0,0 +1,40 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import { formatNumber } from 'nextjs-cms/utils'
3
+ import ContainerBox from '@/components/ContainerBox'
4
+ import React from 'react'
5
+ import { useAxiosPrivate } from 'nextjs-cms/auth/hooks'
6
+ import { useQuery } from '@tanstack/react-query'
7
+ import { getAnalytics } from '@/lib/apiHelpers'
8
+ import LoadingSpinners from '@/components/LoadingSpinners'
9
+
10
+ export const TotalSessions = ({
11
+ fromDate,
12
+ toDate,
13
+ }: {
14
+ fromDate: Date | string | null
15
+ toDate: Date | string | null
16
+ }) => {
17
+ const axiosPrivate = useAxiosPrivate()
18
+ const controller = new AbortController()
19
+
20
+ const { isLoading, isError, data, error } = useQuery({
21
+ queryKey: ['analyticsPage', 'statistics', fromDate, toDate],
22
+ queryFn: () =>
23
+ getAnalytics({
24
+ requestType: 'statistics',
25
+ axiosPrivate,
26
+ controller,
27
+ fromDate,
28
+ toDate,
29
+ }),
30
+ })
31
+ return (
32
+ <ContainerBox title={getString('totalSessions')}>
33
+ {isLoading ? (
34
+ <LoadingSpinners single={true} />
35
+ ) : (
36
+ <div className='text-4xl'>{formatNumber(data?.totalSessions)}</div>
37
+ )}
38
+ </ContainerBox>
39
+ )
40
+ }
@@ -0,0 +1,40 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import { formatNumber } from 'nextjs-cms/utils'
3
+ import ContainerBox from '@/components/ContainerBox'
4
+ import React from 'react'
5
+ import { useAxiosPrivate } from 'nextjs-cms/auth/hooks'
6
+ import { useQuery } from '@tanstack/react-query'
7
+ import { getAnalytics } from '@/lib/apiHelpers'
8
+ import LoadingSpinners from '@/components/LoadingSpinners'
9
+
10
+ export const TotalUniqueUsers = ({
11
+ fromDate,
12
+ toDate,
13
+ }: {
14
+ fromDate: Date | string | null
15
+ toDate: Date | string | null
16
+ }) => {
17
+ const axiosPrivate = useAxiosPrivate()
18
+ const controller = new AbortController()
19
+
20
+ const { isLoading, isError, data, error } = useQuery({
21
+ queryKey: ['analyticsPage', 'statistics', fromDate, toDate],
22
+ queryFn: () =>
23
+ getAnalytics({
24
+ requestType: 'statistics',
25
+ axiosPrivate,
26
+ controller,
27
+ fromDate,
28
+ toDate,
29
+ }),
30
+ })
31
+ return (
32
+ <ContainerBox title={getString('totalUniqueUsers')}>
33
+ {isLoading ? (
34
+ <LoadingSpinners single={true} />
35
+ ) : (
36
+ <div className='text-4xl'>{formatNumber(data?.totalUniqueUsers)}</div>
37
+ )}
38
+ </ContainerBox>
39
+ )
40
+ }
@@ -0,0 +1,137 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import ContainerBox from '@/components/ContainerBox'
3
+ import React from 'react'
4
+ import { Variant } from 'nextjs-cms/core/types'
5
+ import useModal from '@/hooks/useModal'
6
+ import { useAxiosPrivate } from 'nextjs-cms/auth/hooks'
7
+ import { handleVariantDeletion } from '@/lib/apiHelpers'
8
+ import { useToast } from '@/components/ui/use-toast'
9
+ import { Button } from '@/components/ui/button'
10
+ import VariantEditPage from '@/components/VariantEditPage'
11
+
12
+ const RightHomeRoomVariantCard = ({
13
+ variant,
14
+ variantItem,
15
+ sectionItemId,
16
+ action,
17
+ }: {
18
+ variant: Variant
19
+ variantItem: any
20
+ sectionItemId: string
21
+ action: any
22
+ }) => {
23
+ const { setModal, modal, modalResponse, setModalResponse } = useModal()
24
+ const axiosPrivate = useAxiosPrivate()
25
+ const controller = new AbortController()
26
+ const { toast } = useToast()
27
+
28
+ const handleDelete = async () => {
29
+ const response = await handleVariantDeletion(variant.variant_name, variantItem.id, axiosPrivate, controller)
30
+ if (response.error) {
31
+ toast({
32
+ variant: 'destructive',
33
+ title: getString('delete_admin'),
34
+ description: response.error.message,
35
+ })
36
+ } else if (response.code === 200) {
37
+ action ? action() : null
38
+ setModal(null)
39
+ setModalResponse(null)
40
+ toast({
41
+ variant: 'success',
42
+ title: getString('itemDeletedSuccessfully'),
43
+ description: response.message,
44
+ })
45
+ }
46
+ }
47
+ return (
48
+ <ContainerBox title={variantItem.display_name} key={variantItem.id}>
49
+ <div className='flex flex-col gap-4'>
50
+ <div className='flex flex-col gap-1'>
51
+ <div className='flex justify-between'>
52
+ <span className='font-bold'>Size From:</span>
53
+ <span>{variantItem.size_from}</span>
54
+ </div>
55
+ <div className='flex justify-between'>
56
+ <span className='font-bold'>Size To:</span>
57
+ <span>{variantItem.size_to}</span>
58
+ </div>
59
+ <div className='flex justify-between'>
60
+ <span className='font-bold'>Price:</span>
61
+ <span>{variantItem.price}</span>
62
+ </div>
63
+ </div>
64
+ <div className='flex flex-row gap-2'>
65
+ <Button
66
+ size='sm'
67
+ type='button'
68
+ variant='default'
69
+ onClick={() => {
70
+ setModal({
71
+ size: 'lg',
72
+ title: getString('edit'),
73
+ body: (
74
+ <div className='p-4'>
75
+ <VariantEditPage
76
+ section={variant.section_name}
77
+ variant={variant.variant_name}
78
+ sectionItemId={sectionItemId}
79
+ itemId={variantItem.id}
80
+ action={action}
81
+ />
82
+ </div>
83
+ ),
84
+ headerColor: 'bg-sky-700',
85
+ titleColor: 'text-white',
86
+ lang: 'en',
87
+ })
88
+ }}
89
+ >
90
+ {getString('edit')}
91
+ </Button>
92
+ {/* Delete Button */}
93
+ <Button
94
+ size='sm'
95
+ type='button'
96
+ variant='destructive'
97
+ onClick={() => {
98
+ setModal({
99
+ title: getString('delete'),
100
+ body: (
101
+ <div className='p-4'>
102
+ <div className='flex flex-col gap-4'>
103
+ <div>{getString('deleteItemText')}</div>
104
+ <div className='flex gap-2'>
105
+ <button
106
+ className='rounded bg-green-600 px-2 py-1 text-white'
107
+ onClick={handleDelete}
108
+ >
109
+ Yes
110
+ </button>
111
+ <button
112
+ className='rounded bg-red-800 px-2 py-1 text-white'
113
+ onClick={() => {
114
+ setModal(null)
115
+ }}
116
+ >
117
+ No
118
+ </button>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ ),
123
+ headerColor: 'bg-red-700',
124
+ titleColor: 'text-white',
125
+ lang: 'en',
126
+ })
127
+ }}
128
+ >
129
+ {getString('delete')}
130
+ </Button>
131
+ </div>
132
+ </div>
133
+ </ContainerBox>
134
+ )
135
+ }
136
+
137
+ export default RightHomeRoomVariantCard
@@ -0,0 +1,21 @@
1
+ import React from 'react'
2
+ import { useDraggable } from '@dnd-kit/core'
3
+
4
+ function Draggable({ draggableId, children }: { draggableId: string | number; children: React.ReactNode }) {
5
+ const { attributes, listeners, setNodeRef, transform } = useDraggable({
6
+ id: draggableId,
7
+ })
8
+ const style = transform
9
+ ? {
10
+ transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
11
+ }
12
+ : undefined
13
+
14
+ return (
15
+ <div ref={setNodeRef} className='float-start' style={style} {...listeners} {...attributes}>
16
+ {children}
17
+ </div>
18
+ )
19
+ }
20
+
21
+ export default Draggable
@@ -0,0 +1,20 @@
1
+ import React from 'react'
2
+ import { useDroppable } from '@dnd-kit/core'
3
+
4
+ function Droppable({ droppableId, children }: { droppableId: string | number; children: React.ReactNode }) {
5
+ const { isOver, setNodeRef } = useDroppable({
6
+ id: droppableId,
7
+ })
8
+
9
+ const style = {
10
+ color: isOver ? 'green' : undefined,
11
+ }
12
+
13
+ return (
14
+ <div ref={setNodeRef} style={style}>
15
+ {children}
16
+ </div>
17
+ )
18
+ }
19
+
20
+ export default Droppable
@@ -0,0 +1,18 @@
1
+ import React from 'react'
2
+ import { useSortable } from '@dnd-kit/sortable'
3
+ import { CSS } from '@dnd-kit/utilities'
4
+
5
+ export default function SortableItem({ id, children }: { id: string | number; children: React.ReactNode }) {
6
+ const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: id })
7
+
8
+ const style = {
9
+ transform: CSS.Transform.toString(transform),
10
+ transition,
11
+ }
12
+
13
+ return (
14
+ <div ref={setNodeRef} style={style} {...attributes} {...listeners}>
15
+ {children}
16
+ </div>
17
+ )
18
+ }
@@ -0,0 +1,55 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { addDays, format } from 'date-fns'
5
+ import { DateRange } from 'react-day-picker'
6
+
7
+ import { cn } from 'nextjs-cms/utils'
8
+ import { Button } from '@/components/ui/button'
9
+ import { Calendar } from '@/components/ui/calendar'
10
+ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
11
+ import { CalendarIcon } from '@radix-ui/react-icons'
12
+
13
+ export function DatePickerWithRange({ className }: React.HTMLAttributes<HTMLDivElement>) {
14
+ const [date, setDate] = React.useState<DateRange | undefined>({
15
+ from: new Date(2020, 0, 20),
16
+ to: addDays(new Date(2023, 0, 20), 20),
17
+ })
18
+
19
+ return (
20
+ <div className={cn('grid gap-2', className)}>
21
+ <Popover>
22
+ <PopoverTrigger asChild>
23
+ <Button
24
+ id='date'
25
+ variant={'outline'}
26
+ className={cn('justify-start text-left font-normal', !date && 'text-muted-foreground')}
27
+ >
28
+ <CalendarIcon className='mr-2 h-4 w-4' />
29
+ {date?.from ? (
30
+ date.to ? (
31
+ <>
32
+ {format(date.from, 'LLL dd, y')} - {format(date.to, 'LLL dd, y')}
33
+ </>
34
+ ) : (
35
+ format(date.from, 'LLL dd, y')
36
+ )
37
+ ) : (
38
+ <span>Pick a date</span>
39
+ )}
40
+ </Button>
41
+ </PopoverTrigger>
42
+ <PopoverContent className='w-auto p-0' align='start'>
43
+ <Calendar
44
+ initialFocus
45
+ mode='range'
46
+ defaultMonth={date?.from}
47
+ selected={date}
48
+ onSelect={setDate}
49
+ numberOfMonths={2}
50
+ />
51
+ </PopoverContent>
52
+ </Popover>
53
+ </div>
54
+ )
55
+ }