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.
- package/LICENSE +21 -0
- package/README.md +71 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +395 -0
- package/dist/lib/utils.d.ts +11 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +48 -0
- package/package.json +44 -0
- package/templates/default/.env +24 -0
- package/templates/default/.env.development +8 -0
- package/templates/default/.eslintrc.json +5 -0
- package/templates/default/.prettierignore +7 -0
- package/templates/default/.prettierrc.json +19 -0
- package/templates/default/CHANGELOG.md +77 -0
- package/templates/default/README.md +45 -0
- package/templates/default/app/(auth)/auth/login/LoginPage.tsx +175 -0
- package/templates/default/app/(auth)/auth/login/page.tsx +12 -0
- package/templates/default/app/(rootLayout)/admins/page.tsx +5 -0
- package/templates/default/app/(rootLayout)/advanced/page.tsx +5 -0
- package/templates/default/app/(rootLayout)/analytics/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/browse/[section]/[page]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/categorized/[section]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/dashboard/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/edit/[section]/[itemId]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/emails/page.tsx +6 -0
- package/templates/default/app/(rootLayout)/layout.tsx +5 -0
- package/templates/default/app/(rootLayout)/loading.tsx +10 -0
- package/templates/default/app/(rootLayout)/log/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/new/[section]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/page.tsx +9 -0
- package/templates/default/app/(rootLayout)/section/[section]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/settings/page.tsx +7 -0
- package/templates/default/app/_trpc/client.ts +4 -0
- package/templates/default/app/api/auth/csrf/route.ts +25 -0
- package/templates/default/app/api/auth/refresh/route.ts +10 -0
- package/templates/default/app/api/auth/route.ts +23 -0
- package/templates/default/app/api/auth/session/route.ts +20 -0
- package/templates/default/app/api/editor/photo/route.ts +42 -0
- package/templates/default/app/api/photo/route.ts +27 -0
- package/templates/default/app/api/placeholder/route.ts +7 -0
- package/templates/default/app/api/submit/section/item/[slug]/route.ts +63 -0
- package/templates/default/app/api/submit/section/item/route.ts +53 -0
- package/templates/default/app/api/submit/section/simple/route.ts +54 -0
- package/templates/default/app/api/trpc/[trpc]/route.ts +33 -0
- package/templates/default/app/api/video/route.ts +174 -0
- package/templates/default/app/dictionaries.ts +14 -0
- package/templates/default/app/layout.tsx +28 -0
- package/templates/default/app/providers.tsx +151 -0
- package/templates/default/cli.ts +4 -0
- package/templates/default/components/AdminCard.tsx +163 -0
- package/templates/default/components/AdminEditPage.tsx +123 -0
- package/templates/default/components/AdminPrivilegeCard.tsx +184 -0
- package/templates/default/components/AdminsPage.tsx +43 -0
- package/templates/default/components/AdvancedSettingsPage.tsx +167 -0
- package/templates/default/components/AnalyticsPage.tsx +127 -0
- package/templates/default/components/BarChartBox.tsx +43 -0
- package/templates/default/components/BrowsePage.tsx +119 -0
- package/templates/default/components/CategorizedSectionPage.tsx +36 -0
- package/templates/default/components/CategoryDeleteConfirmPage.tsx +129 -0
- package/templates/default/components/CategorySectionSelectInput.tsx +139 -0
- package/templates/default/components/ConditionalFields.tsx +49 -0
- package/templates/default/components/ContainerBox.tsx +24 -0
- package/templates/default/components/DashboardPage.tsx +187 -0
- package/templates/default/components/DashboardPageAlt.tsx +43 -0
- package/templates/default/components/DefaultNavItems.tsx +3 -0
- package/templates/default/components/Dropzone.tsx +153 -0
- package/templates/default/components/EmailCard.tsx +137 -0
- package/templates/default/components/EmailPasswordForm.tsx +84 -0
- package/templates/default/components/EmailQuotaForm.tsx +72 -0
- package/templates/default/components/EmailsPage.tsx +48 -0
- package/templates/default/components/GalleryPhoto.tsx +93 -0
- package/templates/default/components/InfoCard.tsx +94 -0
- package/templates/default/components/ItemEditPage.tsx +217 -0
- package/templates/default/components/Layout.tsx +70 -0
- package/templates/default/components/LoadingSpinners.tsx +67 -0
- package/templates/default/components/LogPage.tsx +17 -0
- package/templates/default/components/Modal.tsx +99 -0
- package/templates/default/components/Navbar.tsx +29 -0
- package/templates/default/components/NavbarAlt.tsx +182 -0
- package/templates/default/components/NewAdminForm.tsx +172 -0
- package/templates/default/components/NewEmailForm.tsx +131 -0
- package/templates/default/components/NewPage.tsx +206 -0
- package/templates/default/components/NewVariantComponent.tsx +228 -0
- package/templates/default/components/PhotoGallery.tsx +35 -0
- package/templates/default/components/PieChartBox.tsx +101 -0
- package/templates/default/components/ProgressBar.tsx +24 -0
- package/templates/default/components/ProtectedDocument.tsx +78 -0
- package/templates/default/components/ProtectedImage.tsx +143 -0
- package/templates/default/components/ProtectedVideo.tsx +76 -0
- package/templates/default/components/SectionItemCard.tsx +143 -0
- package/templates/default/components/SectionItemStatusBadge.tsx +16 -0
- package/templates/default/components/SectionPage.tsx +124 -0
- package/templates/default/components/SelectBox.tsx +99 -0
- package/templates/default/components/SelectInputButtons.tsx +124 -0
- package/templates/default/components/SettingsPage.tsx +238 -0
- package/templates/default/components/Sidebar.tsx +209 -0
- package/templates/default/components/SidebarDropdownItem.tsx +74 -0
- package/templates/default/components/SidebarItem.tsx +19 -0
- package/templates/default/components/TempPage.tsx +12 -0
- package/templates/default/components/ThemeProvider.tsx +8 -0
- package/templates/default/components/TooltipComponent.tsx +27 -0
- package/templates/default/components/VariantCard.tsx +123 -0
- package/templates/default/components/VariantEditPage.tsx +229 -0
- package/templates/default/components/analytics/BounceRate.tsx +69 -0
- package/templates/default/components/analytics/LivePageViews.tsx +54 -0
- package/templates/default/components/analytics/LiveUsersCount.tsx +32 -0
- package/templates/default/components/analytics/MonthlyPageViews.tsx +41 -0
- package/templates/default/components/analytics/TopCountries.tsx +51 -0
- package/templates/default/components/analytics/TopDevices.tsx +45 -0
- package/templates/default/components/analytics/TopMediums.tsx +57 -0
- package/templates/default/components/analytics/TopSources.tsx +44 -0
- package/templates/default/components/analytics/TotalPageViews.tsx +40 -0
- package/templates/default/components/analytics/TotalSessions.tsx +40 -0
- package/templates/default/components/analytics/TotalUniqueUsers.tsx +40 -0
- package/templates/default/components/custom/RightHomeRoomVariantCard.tsx +137 -0
- package/templates/default/components/dndKit/Draggable.tsx +21 -0
- package/templates/default/components/dndKit/Droppable.tsx +20 -0
- package/templates/default/components/dndKit/SortableItem.tsx +18 -0
- package/templates/default/components/form/DateRangeFormInput.tsx +55 -0
- package/templates/default/components/form/Form.tsx +298 -0
- package/templates/default/components/form/FormInputElement.tsx +68 -0
- package/templates/default/components/form/FormInputs.tsx +108 -0
- package/templates/default/components/form/helpers/util.ts +20 -0
- package/templates/default/components/form/inputs/CheckboxFormInput.tsx +33 -0
- package/templates/default/components/form/inputs/ColorFormInput.tsx +44 -0
- package/templates/default/components/form/inputs/DateFormInput.tsx +107 -0
- package/templates/default/components/form/inputs/DocumentFormInput.tsx +124 -0
- package/templates/default/components/form/inputs/MapFormInput.tsx +139 -0
- package/templates/default/components/form/inputs/MultipleSelectFormInput.tsx +150 -0
- package/templates/default/components/form/inputs/NumberFormInput.tsx +42 -0
- package/templates/default/components/form/inputs/PasswordFormInput.tsx +47 -0
- package/templates/default/components/form/inputs/PhotoFormInput.tsx +218 -0
- package/templates/default/components/form/inputs/RichTextFormInput.tsx +133 -0
- package/templates/default/components/form/inputs/SelectFormInput.tsx +164 -0
- package/templates/default/components/form/inputs/TagsFormInput.tsx +63 -0
- package/templates/default/components/form/inputs/TextFormInput.tsx +48 -0
- package/templates/default/components/form/inputs/TextareaFormInput.tsx +47 -0
- package/templates/default/components/form/inputs/VideoFormInput.tsx +117 -0
- package/templates/default/components/pagination/Pagination.tsx +36 -0
- package/templates/default/components/pagination/PaginationButtons.tsx +145 -0
- package/templates/default/components/ui/accordion.tsx +57 -0
- package/templates/default/components/ui/alert.tsx +46 -0
- package/templates/default/components/ui/badge.tsx +33 -0
- package/templates/default/components/ui/button.tsx +57 -0
- package/templates/default/components/ui/calendar.tsx +68 -0
- package/templates/default/components/ui/card.tsx +76 -0
- package/templates/default/components/ui/checkbox.tsx +29 -0
- package/templates/default/components/ui/dropdown-menu.tsx +205 -0
- package/templates/default/components/ui/input.tsx +25 -0
- package/templates/default/components/ui/label.tsx +26 -0
- package/templates/default/components/ui/popover.tsx +31 -0
- package/templates/default/components/ui/scroll-area.tsx +42 -0
- package/templates/default/components/ui/select.tsx +164 -0
- package/templates/default/components/ui/sheet.tsx +107 -0
- package/templates/default/components/ui/switch.tsx +29 -0
- package/templates/default/components/ui/table.tsx +120 -0
- package/templates/default/components/ui/tabs.tsx +55 -0
- package/templates/default/components/ui/toast.tsx +113 -0
- package/templates/default/components/ui/toaster.tsx +35 -0
- package/templates/default/components/ui/tooltip.tsx +30 -0
- package/templates/default/components/ui/use-toast.ts +188 -0
- package/templates/default/components.json +16 -0
- package/templates/default/context/ModalProvider.tsx +53 -0
- package/templates/default/drizzle.config.ts +4 -0
- package/templates/default/dynamic-schemas/schema.ts +373 -0
- package/templates/default/env/env.js +130 -0
- package/templates/default/envConfig.ts +4 -0
- package/templates/default/hooks/useModal.ts +8 -0
- package/templates/default/lib/apiHelpers.ts +106 -0
- package/templates/default/lz.config.ts +40 -0
- package/templates/default/middleware.ts +33 -0
- package/templates/default/next.config.ts +46 -0
- package/templates/default/package.json +134 -0
- package/templates/default/postcss.config.js +6 -0
- package/templates/default/postinstall.js +14 -0
- package/templates/default/public/blank_avatar.png +0 -0
- package/templates/default/public/favicon.ico +0 -0
- package/templates/default/public/img/placeholder.svg +1 -0
- package/templates/default/public/lazemni_logo.png +0 -0
- package/templates/default/public/next.svg +1 -0
- package/templates/default/public/vercel.svg +1 -0
- package/templates/default/section-tests.ts +92 -0
- package/templates/default/styles/globals.css +88 -0
- package/templates/default/tailwind.config.js +95 -0
- package/templates/default/test.ts +77 -0
- 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
|
+
}
|