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,182 @@
1
+ import React from 'react'
2
+ import classNames from 'classnames'
3
+ import { MoonIcon, SunIcon, BellIcon, HamburgerMenuIcon } from '@radix-ui/react-icons'
4
+ import { useTheme } from 'next-themes'
5
+ import Link from 'next/link'
6
+ import getString from 'nextjs-cms/translations'
7
+ import ProtectedImage from '@/components/ProtectedImage'
8
+ import Image from 'next/image'
9
+ import { LogOut, Settings } from 'lucide-react'
10
+
11
+ import {
12
+ DropdownMenu,
13
+ DropdownMenuContent,
14
+ DropdownMenuGroup,
15
+ DropdownMenuItem,
16
+ DropdownMenuLabel,
17
+ DropdownMenuSeparator,
18
+ DropdownMenuShortcut,
19
+ DropdownMenuTrigger,
20
+ } from '@/components/ui/dropdown-menu'
21
+ import { useToast } from '@/components/ui/use-toast'
22
+ import { logout, useSession } from 'nextjs-cms/auth/react'
23
+ type Props = {
24
+ /**
25
+ * Allows the parent component to modify the state when the
26
+ * menu button is clicked.
27
+ */
28
+ onMenuButtonClick(): void
29
+ }
30
+
31
+ export default function Navbar(props: Props) {
32
+ const { theme, setTheme } = useTheme()
33
+ const session = useSession()
34
+ const { toast } = useToast()
35
+ const handleLogout = async (e: React.MouseEvent<HTMLDivElement>) => {
36
+ e.preventDefault()
37
+ e.stopPropagation()
38
+ try {
39
+ await logout()
40
+ } catch (error: any) {
41
+ toast({
42
+ variant: 'destructive',
43
+ title: getString('logoutError'),
44
+ description: error.message,
45
+ })
46
+ }
47
+ }
48
+
49
+ return (
50
+ <>
51
+ <nav
52
+ className={classNames({
53
+ 'sticky top-0 h-[65px] bg-white text-zinc-500 drop-shadow dark:bg-slate-800': true, // colors
54
+ 'top-0 z-10 w-full px-4 shadow-sm md:w-full': true, //positioning & styling
55
+ })}
56
+ >
57
+ <div className='mx-auto px-0 lg:px-2'>
58
+ <div className='flex h-16 items-center justify-between'>
59
+ <div className='flex items-center'>
60
+ <div className='flex-shrink-0'>
61
+ <div className='flex md:hidden'>
62
+ {/* Mobile menu button */}
63
+ <button
64
+ onClick={props.onMenuButtonClick}
65
+ className='relative inline-flex items-center justify-center rounded-md border border-foreground p-2 text-foreground hover:text-foreground/90 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800'
66
+ >
67
+ <span className='absolute -inset-0.5' />
68
+ <span className='sr-only'>Open main menu</span>
69
+ <HamburgerMenuIcon className='block h-6 w-6' aria-hidden='true' />
70
+ </button>
71
+ </div>
72
+ </div>
73
+
74
+ {/*<div className=''>
75
+ <div className='flex items-baseline space-x-4'>
76
+ <input
77
+ type='text'
78
+ className='h-full w-full border-0 bg-transparent text-amber-500 outline-0 ring-0'
79
+ placeholder='Search...'
80
+ />
81
+ </div>
82
+ </div>*/}
83
+ </div>
84
+ <div className=''>
85
+ <div className='ml-4 flex items-center md:ml-6'>
86
+ <div className='flex flex-row items-center gap-3'>
87
+ <DropdownMenu>
88
+ <DropdownMenuTrigger
89
+ asChild
90
+ className='cursor-pointer text-foreground hover:text-foreground/90'
91
+ >
92
+ <BellIcon className='h-6 w-6' />
93
+ </DropdownMenuTrigger>
94
+ <DropdownMenuContent className='mt-2 w-[300px]'>
95
+ <DropdownMenuLabel>{getString('notifications')}</DropdownMenuLabel>
96
+ <DropdownMenuSeparator />
97
+ <DropdownMenuGroup></DropdownMenuGroup>
98
+ <DropdownMenuSeparator />
99
+
100
+ <Link href='/log'>
101
+ <DropdownMenuItem className='cursor-pointer'>
102
+ <span>{getString('seeAll')}</span>
103
+ </DropdownMenuItem>
104
+ </Link>
105
+ </DropdownMenuContent>
106
+ </DropdownMenu>
107
+ <button
108
+ onClick={() => {
109
+ setTheme(theme === 'dark' ? 'light' : 'dark')
110
+ }}
111
+ type='button'
112
+ className='relative rounded-full p-1 text-foreground hover:text-foreground/90 focus:outline-none'
113
+ >
114
+ <span className='absolute -inset-1.5' />
115
+ <span className='sr-only'>Theme</span>
116
+ {theme === 'dark' ? (
117
+ <SunIcon className='h-6 w-6' aria-hidden='true' />
118
+ ) : (
119
+ <MoonIcon className='h-6 w-6' aria-hidden='true' />
120
+ )}
121
+ </button>
122
+ {/* Profile dropdown */}
123
+ <DropdownMenu>
124
+ <DropdownMenuTrigger
125
+ asChild
126
+ className='relative ms-2 flex max-w-xs cursor-pointer items-center rounded-full bg-gray-800 text-sm hover:ring focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800'
127
+ >
128
+ <div>
129
+ <span className='absolute -inset-1.5' />
130
+ <span className='sr-only'>Open user menu</span>
131
+ {session?.data?.user.image ? (
132
+ <ProtectedImage
133
+ section={'admins'}
134
+ photo={session.data.user.image}
135
+ isThumb={true}
136
+ alt={session.data.user.name}
137
+ width={40}
138
+ height={40}
139
+ // fill={true}
140
+ className='rounded-full'
141
+ />
142
+ ) : (
143
+ <Image
144
+ src='/blank_avatar.png'
145
+ height={36}
146
+ width={36}
147
+ alt='profile image'
148
+ className='rounded-full ring-2 ring-inset ring-amber-300'
149
+ />
150
+ )}
151
+ </div>
152
+ </DropdownMenuTrigger>
153
+ <DropdownMenuContent className='w-56'>
154
+ <DropdownMenuLabel>{session.data?.user.name}</DropdownMenuLabel>
155
+ <DropdownMenuSeparator />
156
+ <DropdownMenuGroup>
157
+ <Link href='/settings'>
158
+ <DropdownMenuItem className='cursor-pointer'>
159
+ <Settings className='mr-2 h-4 w-4' />
160
+ <span>{getString('accountSettings')}</span>
161
+ <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
162
+ </DropdownMenuItem>
163
+ </Link>
164
+ </DropdownMenuGroup>
165
+ <DropdownMenuSeparator />
166
+
167
+ <DropdownMenuItem className='cursor-pointer' onClick={handleLogout}>
168
+ <LogOut className='mr-2 h-4 w-4' />
169
+ <span>{getString('logout')}</span>
170
+ <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
171
+ </DropdownMenuItem>
172
+ </DropdownMenuContent>
173
+ </DropdownMenu>
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </div>
178
+ </div>
179
+ </nav>
180
+ </>
181
+ )
182
+ }
@@ -0,0 +1,172 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import React from 'react'
3
+ import useModal from '@/hooks/useModal'
4
+ import InfoCard from '@/components/InfoCard'
5
+ import { useToast } from '@/components/ui/use-toast'
6
+ import { trpc } from '@/app/_trpc/client'
7
+ import AdminRoleCard from '@/components/AdminPrivilegeCard'
8
+ import { Button } from '@/components/ui/button'
9
+ import { RouterOutputs } from 'nextjs-cms/api'
10
+
11
+ export default function NewAdminForm({
12
+ privileges,
13
+ action,
14
+ }: {
15
+ privileges: RouterOutputs['admins']['list']['privileges']
16
+ action: any
17
+ }) {
18
+ const { setModal, modal, modalResponse, setModalResponse } = useModal()
19
+ const { toast } = useToast()
20
+ const formRef = React.useRef<HTMLFormElement>(null)
21
+ const [allChecked, setAllChecked] = React.useState<boolean | 'edited' | null>(null)
22
+ const usernameRef = React.useRef<HTMLInputElement>(null)
23
+ const passwordRef = React.useRef<HTMLInputElement>(null)
24
+
25
+ const mutation = trpc.admins.create.useMutation({
26
+ onError: (error) => {
27
+ setModal({
28
+ title: getString('create_new_admin'),
29
+ body: (
30
+ <div className='p-4'>
31
+ <InfoCard result={{ key: 'danger', title: error.message, status: false }} />
32
+ </div>
33
+ ),
34
+ headerColor: 'bg-red-700',
35
+ titleColor: 'text-white',
36
+ lang: 'en',
37
+ })
38
+ },
39
+
40
+ onSuccess: (data) => {
41
+ setModal(null)
42
+ setModalResponse(null)
43
+ setAllChecked(false)
44
+ action()
45
+
46
+ /**
47
+ * Empty the form
48
+ */
49
+ if (formRef.current) {
50
+ formRef.current.reset()
51
+ }
52
+
53
+ /**
54
+ * Show a success toast
55
+ */
56
+ toast({
57
+ variant: 'success',
58
+ title: getString('create_new_admin'),
59
+ description: getString('itemCreatedSuccessfully'),
60
+ })
61
+ },
62
+ })
63
+
64
+ const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
65
+ e.preventDefault()
66
+
67
+ /**
68
+ * Check username and password
69
+ */
70
+ if (!usernameRef.current?.value || !passwordRef.current?.value) {
71
+ setModal({
72
+ title: getString('create_new_admin'),
73
+ body: <div className='p-4'>{getString('usernamePasswordRequired')}</div>,
74
+ headerColor: 'bg-red-700',
75
+ titleColor: 'text-white',
76
+ lang: 'en',
77
+ })
78
+ return
79
+ }
80
+
81
+ const data = new FormData(e.currentTarget)
82
+ const values = Object.fromEntries(data.entries())
83
+ values.form_type = 'new'
84
+
85
+ // Convert the privileges to an array of objects
86
+ const privileges = Object.entries(values).filter(([key]) => key.includes('privileges'))
87
+ const privilegesArray = privileges.map(([key, value]) => JSON.parse(value as string))
88
+
89
+ mutation.mutate({
90
+ username: usernameRef.current.value,
91
+ password: passwordRef.current.value,
92
+ privileges: privilegesArray,
93
+ })
94
+ }
95
+
96
+ return (
97
+ <form ref={formRef} onSubmit={handleSubmit} className='flex flex-col gap-2'>
98
+ <div>
99
+ <label htmlFor='email' className='block text-sm font-medium leading-6 text-foreground'>
100
+ {getString('username')}
101
+ </label>
102
+ <div className=''>
103
+ <input
104
+ ref={usernameRef}
105
+ id='username'
106
+ name='username'
107
+ type='text'
108
+ // required
109
+ className='block w-full rounded-md border-0 bg-input p-3 text-foreground shadow-sm outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
110
+ />
111
+ </div>
112
+ </div>
113
+
114
+ <div>
115
+ <label htmlFor='password' className='block text-sm font-medium leading-6 text-foreground'>
116
+ {getString('password')}
117
+ </label>
118
+ <div className=''>
119
+ <input
120
+ ref={passwordRef}
121
+ id='password'
122
+ name='password'
123
+ type='text'
124
+ // required
125
+ className='block w-full rounded-md border-0 bg-input p-3 text-foreground shadow-sm outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
126
+ />
127
+ </div>
128
+ </div>
129
+ {privileges && privileges.length > 0 && (
130
+ <>
131
+ <div className='mt-5 w-full font-semibold'>{getString('admin_privileges')}</div>
132
+ <div className='flex'>
133
+ <Button
134
+ className='border border-foreground'
135
+ type='button'
136
+ variant={allChecked === true ? 'default' : 'secondary'}
137
+ onClick={(event) => {
138
+ event.preventDefault()
139
+ event.stopPropagation()
140
+ if (allChecked === true) {
141
+ setAllChecked(false)
142
+ } else {
143
+ setAllChecked(true)
144
+ }
145
+ }}
146
+ >
147
+ {allChecked === true ? getString('removeAll') : getString('checkAll')}
148
+ </Button>
149
+ </div>
150
+ <div className='mt-2 grid w-full grid-cols-1 gap-2 md-sidebar:grid-cols-2 lg-sidebar:grid-cols-3 xl-sidebar:grid-cols-4 2xl-sidebar:grid-cols-5'>
151
+ {privileges.map((privilege, index: number) => {
152
+ return (
153
+ <AdminRoleCard
154
+ key={index}
155
+ privilege={privilege}
156
+ allChecked={allChecked}
157
+ setAllChecked={setAllChecked}
158
+ />
159
+ )
160
+ })}
161
+ </div>
162
+ </>
163
+ )}
164
+
165
+ <div className='mt-4'>
166
+ <button type='submit' className='rounded bg-blue-700 px-2 py-1 font-bold text-white'>
167
+ {getString('submit_new_admin')}
168
+ </button>
169
+ </div>
170
+ </form>
171
+ )
172
+ }
@@ -0,0 +1,131 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import React from 'react'
3
+ import useModal from '@/hooks/useModal'
4
+ import { Badge } from '@/components/ui/badge'
5
+ import { useToast } from '@/components/ui/use-toast'
6
+ import InfoCard from '@/components/InfoCard'
7
+ import { trpc } from '@/app/_trpc/client'
8
+
9
+ export default function NewEmailForm({ action }: { action: any }) {
10
+ const { setModal, modal, modalResponse, setModalResponse } = useModal()
11
+ const formRef = React.useRef<HTMLFormElement>(null)
12
+ const { toast } = useToast()
13
+ const newEmailMutation = trpc.cpanel.createEmail.useMutation({
14
+ onError: (error) => {
15
+ setModal({
16
+ title: getString('error'),
17
+ body: (
18
+ <div className='p-4'>
19
+ <InfoCard result={{ key: 'danger', title: error.message, status: false }} />
20
+ </div>
21
+ ),
22
+ headerColor: 'bg-red-700',
23
+ titleColor: 'text-white',
24
+ lang: 'en',
25
+ })
26
+ },
27
+ onSuccess: (data) => {
28
+ action()
29
+ toast({
30
+ variant: 'success',
31
+ title: getString('success'),
32
+ description: data.message,
33
+ })
34
+
35
+ // Empty the form
36
+ if (formRef.current) {
37
+ formRef.current.reset()
38
+ }
39
+ },
40
+ })
41
+ const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
42
+ e.preventDefault()
43
+ newEmailMutation.mutate({
44
+ email: e.currentTarget.username.value,
45
+ password: e.currentTarget.password.value,
46
+ quota: e.currentTarget.quota.value,
47
+ })
48
+
49
+ /*const data = new FormData(e.currentTarget)
50
+ const values = Object.fromEntries(data.entries())
51
+ values.operationType = 'newEmail'
52
+ const response = await handleEmailSubmission(values, axiosPrivate, controller)
53
+ if (response.error) {
54
+ setModal({
55
+ title: getString('error'),
56
+ body: (
57
+ <div className='p-4'>
58
+ <InfoCard result={{ key: 'danger', title: response.error.message, status: false }} />
59
+ </div>
60
+ ),
61
+ headerColor: 'bg-red-700',
62
+ titleColor: 'text-white',
63
+ lang: 'en',
64
+ })
65
+ } else if (response.code === 200) {
66
+ action()
67
+ toast({
68
+ variant: 'success',
69
+ title: getString('success'),
70
+ description: response.message,
71
+ })
72
+ }*/
73
+ }
74
+
75
+ return (
76
+ <form ref={formRef} onSubmit={handleSubmit} className='flex flex-col gap-2'>
77
+ <div>
78
+ <label htmlFor='username' className='block text-sm font-medium leading-6 text-foreground'>
79
+ {getString('email')}
80
+ </label>
81
+ <div className=''>
82
+ <input
83
+ id='username'
84
+ name='username'
85
+ type='text'
86
+ autoComplete='username'
87
+ required
88
+ className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-sm outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
89
+ />
90
+ </div>
91
+ </div>
92
+
93
+ <div>
94
+ <label htmlFor='password' className='block text-sm font-medium leading-6 text-foreground'>
95
+ {getString('password')}
96
+ </label>
97
+ <div className=''>
98
+ <input
99
+ id='password'
100
+ name='password'
101
+ type='text'
102
+ autoComplete='password'
103
+ required
104
+ className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-sm outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
105
+ />
106
+ </div>
107
+ </div>
108
+ <div>
109
+ <label htmlFor='quota' className='block text-sm font-medium leading-6 text-foreground'>
110
+ {getString('emailQuota')}
111
+ </label>
112
+ <div className=''>
113
+ <input
114
+ id='quota'
115
+ name='quota'
116
+ type='number'
117
+ autoComplete='quota'
118
+ required
119
+ className='block rounded-md border-0 bg-input p-2.5 text-foreground shadow-sm outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
120
+ />
121
+ <Badge className='rounded-sm border-muted-foreground text-muted-foreground' variant='secondary'>
122
+ 0 = {getString('unlimited')}
123
+ </Badge>
124
+ </div>
125
+ </div>
126
+ <div className='mt-4'>
127
+ <button className='rounded bg-blue-700 px-2 py-1 font-bold text-white'>{getString('create')}</button>
128
+ </div>
129
+ </form>
130
+ )
131
+ }