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,137 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import React from 'react'
3
+ import { EmailItem } from 'nextjs-cms/core/types'
4
+ import useModal from '@/hooks/useModal'
5
+ import { useToast } from '@/components/ui/use-toast'
6
+ import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
7
+ import { Button } from '@/components/ui/button'
8
+ import ProgressBar from '@/components/ProgressBar'
9
+ import EmailQuotaForm from '@/components/EmailQuotaForm'
10
+ import EmailPasswordForm from '@/components/EmailPasswordForm'
11
+ import { trpc } from '@/app/_trpc/client'
12
+
13
+ export default function EmailCard({ email, action }: { email: EmailItem; action: any }) {
14
+ const { setModal, modal, modalResponse, setModalResponse } = useModal()
15
+ const { toast } = useToast()
16
+
17
+ const deleteMutation = trpc.cpanel.deleteEmail.useMutation({
18
+ onError: (error) => {
19
+ setModalResponse({
20
+ message: error.message,
21
+ messageColor: 'text-red-900',
22
+ borderColor: 'border-red-600',
23
+ bgColor: 'bg-red-200',
24
+ })
25
+ },
26
+ onSuccess: (data) => {
27
+ action()
28
+ setModal(null)
29
+ setModalResponse(null)
30
+ toast({
31
+ variant: 'success',
32
+ title: getString('deleteEmailAccount'),
33
+ description: data.message,
34
+ })
35
+ },
36
+ })
37
+ const deleteEmail = async () => {
38
+ deleteMutation.mutate(email.user)
39
+ }
40
+
41
+ return (
42
+ <Card className='border border-gray-400 shadow-sm'>
43
+ <CardHeader>
44
+ <CardTitle>
45
+ <div className='flex flex-row items-center'>
46
+ <div className='flex flex-col break-all'>
47
+ <div className='text-sm font-medium text-foreground'>
48
+ <div className='me-2 font-bold'>{email.email}</div>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </CardTitle>
53
+ </CardHeader>
54
+ <CardContent>
55
+ {email.humandiskused} / {email.humandiskquota !== 'None' ? email.humandiskquota : email.diskquota}
56
+ <ProgressBar variant='determinate' value={parseInt(email.diskusedpercent)} />
57
+ </CardContent>
58
+ <CardFooter className='flex flex-wrap gap-1'>
59
+ <Button
60
+ size='sm'
61
+ variant='default'
62
+ onClick={() => {
63
+ setModal({
64
+ title: getString('emailQuota'),
65
+ body: (
66
+ <div className='p-4'>
67
+ <EmailQuotaForm email={email.user} action={() => action()} />
68
+ </div>
69
+ ),
70
+ headerColor: 'bg-sky-700',
71
+ titleColor: 'text-white',
72
+ lang: 'en',
73
+ })
74
+ }}
75
+ >
76
+ {getString('quota')}
77
+ </Button>
78
+ <Button
79
+ size='sm'
80
+ variant='default'
81
+ onClick={() => {
82
+ setModal({
83
+ title: getString('change_password'),
84
+ body: (
85
+ <div className='p-4'>
86
+ <EmailPasswordForm email={email.user} action={() => action()} />
87
+ </div>
88
+ ),
89
+ headerColor: 'bg-sky-700',
90
+ titleColor: 'text-white',
91
+ lang: 'en',
92
+ })
93
+ }}
94
+ >
95
+ {getString('password')}
96
+ </Button>
97
+ <Button
98
+ size='sm'
99
+ variant='destructive'
100
+ onClick={() => {
101
+ setModal({
102
+ title: getString('delete'),
103
+ body: (
104
+ <div className='p-4'>
105
+ <div className='flex flex-col gap-4'>
106
+ <div>{getString('deleteEmailText')}</div>
107
+ <div className='flex gap-2'>
108
+ <button
109
+ className='rounded bg-green-600 px-2 py-1 text-white'
110
+ onClick={deleteEmail}
111
+ >
112
+ Yes
113
+ </button>
114
+ <button
115
+ className='rounded bg-red-800 px-2 py-1 text-white'
116
+ onClick={() => {
117
+ setModal(null)
118
+ }}
119
+ >
120
+ No
121
+ </button>
122
+ </div>
123
+ </div>
124
+ </div>
125
+ ),
126
+ headerColor: 'bg-red-700',
127
+ titleColor: 'text-white',
128
+ lang: 'en',
129
+ })
130
+ }}
131
+ >
132
+ {getString('delete')}
133
+ </Button>
134
+ </CardFooter>
135
+ </Card>
136
+ )
137
+ }
@@ -0,0 +1,84 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import React from 'react'
3
+ import useModal from '@/hooks/useModal'
4
+ import { useToast } from '@/components/ui/use-toast'
5
+ import InfoCard from '@/components/InfoCard'
6
+ import { trpc } from '@/app/_trpc/client'
7
+
8
+ export default function EmailPasswordForm({ email, action }: { email: string; action: any }) {
9
+ const { setModal, modal, modalResponse, setModalResponse } = useModal()
10
+
11
+ const { toast } = useToast()
12
+ const quotaMutation = trpc.cpanel.passwordChange.useMutation({
13
+ onError: (error) => {
14
+ setModal({
15
+ title: getString('error'),
16
+ body: (
17
+ <div className='p-4'>
18
+ <InfoCard result={{ key: 'danger', title: error.message, status: false }} />
19
+ </div>
20
+ ),
21
+ headerColor: 'bg-red-700',
22
+ titleColor: 'text-white',
23
+ lang: 'en',
24
+ })
25
+ },
26
+ onSuccess: (data) => {
27
+ action()
28
+ setModal(null)
29
+ setModalResponse(null)
30
+ toast({
31
+ variant: 'success',
32
+ title: getString('success'),
33
+ })
34
+ },
35
+ })
36
+ const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
37
+ e.preventDefault()
38
+ quotaMutation.mutate({
39
+ email,
40
+ password: e.currentTarget.password.value,
41
+ passwordConfirm: e.currentTarget.passwordConfirm.value,
42
+ })
43
+ }
44
+
45
+ return (
46
+ <form onSubmit={handleSubmit} className='flex flex-col gap-2'>
47
+ <div>
48
+ <label htmlFor='password' className='block text-sm font-medium leading-6 text-foreground'>
49
+ {getString('new_password')}
50
+ </label>
51
+ <div className=''>
52
+ <input
53
+ id='password'
54
+ name='password'
55
+ type='text'
56
+ autoComplete='password'
57
+ required
58
+ 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'
59
+ />
60
+ </div>
61
+ </div>
62
+ <div>
63
+ <label htmlFor='passwordConfirm' className='block text-sm font-medium leading-6 text-foreground'>
64
+ {getString('confirm_new_password')}
65
+ </label>
66
+ <div className=''>
67
+ <input
68
+ id='passwordConfirm'
69
+ name='passwordConfirm'
70
+ type='text'
71
+ autoComplete='passwordConfirm'
72
+ required
73
+ 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'
74
+ />
75
+ </div>
76
+ </div>
77
+ <div className='mt-4'>
78
+ <button className='rounded bg-blue-700 px-2 py-1 font-bold text-white'>
79
+ {getString('change_password')}
80
+ </button>
81
+ </div>
82
+ </form>
83
+ )
84
+ }
@@ -0,0 +1,72 @@
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 EmailQuotaForm({ email, action }: { email: string; action: any }) {
10
+ const { setModal, modal, modalResponse, setModalResponse } = useModal()
11
+ const { toast } = useToast()
12
+
13
+ const quotaMutation = trpc.cpanel.quotaChange.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
+ setModal(null)
30
+ setModalResponse(null)
31
+ toast({
32
+ variant: 'success',
33
+ title: getString('success'),
34
+ })
35
+ },
36
+ })
37
+ const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
38
+ e.preventDefault()
39
+ quotaMutation.mutate({
40
+ email,
41
+ quota: e.currentTarget.quota.value,
42
+ })
43
+ }
44
+
45
+ return (
46
+ <form onSubmit={handleSubmit} className='flex flex-col gap-2'>
47
+ <div>
48
+ <label htmlFor='quota' className='block text-sm font-medium leading-6 text-foreground'>
49
+ {getString('emailQuota')}
50
+ </label>
51
+ <div className=''>
52
+ <input
53
+ id='quota'
54
+ name='quota'
55
+ type='number'
56
+ autoComplete='quota'
57
+ required
58
+ 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'
59
+ />
60
+ <Badge className='rounded-sm border-muted-foreground text-muted-foreground' variant='secondary'>
61
+ 0 = {getString('unlimited')}
62
+ </Badge>
63
+ </div>
64
+ </div>
65
+ <div className='mt-4'>
66
+ <button className='rounded bg-blue-700 px-2 py-1 font-bold text-white'>
67
+ {getString('update_quota')}
68
+ </button>
69
+ </div>
70
+ </form>
71
+ )
72
+ }
@@ -0,0 +1,48 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect } from 'react'
4
+ import { EmailItem } from 'nextjs-cms/core/types'
5
+ import getString from 'nextjs-cms/translations'
6
+ import ContainerBox from '@/components/ContainerBox'
7
+ import NewEmailForm from '@/components/NewEmailForm'
8
+ import EmailCard from '@/components/EmailCard'
9
+ import { trpc } from '@/app/_trpc/client'
10
+
11
+ const EmailsPage = () => {
12
+ const controller = new AbortController()
13
+
14
+ const { isLoading, isError, data, error, refetch } = trpc.cpanel.getEmails.useQuery()
15
+
16
+ useEffect(() => {
17
+ return () => {
18
+ controller.abort()
19
+ }
20
+ }, [])
21
+
22
+ return (
23
+ <div className='bg-white dark:bg-slate-900'>
24
+ <div className='bg-gradient-to-r from-sky-200 via-emerald-300 to-blue-600 p-8 font-extrabold text-foreground dark:from-blue-800 dark:via-amber-700 dark:to-rose-900'>
25
+ <h1 className='text-3xl'>{getString('email_accounts')}</h1>
26
+ </div>
27
+
28
+ <div className='flex flex-col gap-2 p-4'>
29
+ <ContainerBox title={getString('create_new_email_account')}>
30
+ <NewEmailForm action={() => refetch()} />
31
+ </ContainerBox>
32
+
33
+ {isLoading && <div>Loading...</div>}
34
+ {data && data.emails && data.emails.length > 0 && (
35
+ <ContainerBox title={getString('admins_list')}>
36
+ <div className='mt-2 grid w-full grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3'>
37
+ {data.emails.map((email: EmailItem) => (
38
+ <EmailCard key={email.user} action={() => refetch()} email={email} />
39
+ ))}
40
+ </div>
41
+ </ContainerBox>
42
+ )}
43
+ </div>
44
+ </div>
45
+ )
46
+ }
47
+
48
+ export default EmailsPage
@@ -0,0 +1,93 @@
1
+ import { PhotoGalleryItem } from 'nextjs-cms/core/types'
2
+ import getString from 'nextjs-cms/translations'
3
+ import { MinusIcon } from '@radix-ui/react-icons'
4
+ import ProtectedImage from '@/components/ProtectedImage'
5
+ import React from 'react'
6
+ import useModal from '@/hooks/useModal'
7
+ import { useToast } from '@/components/ui/use-toast'
8
+ import { trpc } from '@/app/_trpc/client'
9
+
10
+ const GalleryPhoto = ({ item, sectionName, action }: { item: PhotoGalleryItem; sectionName: string; action?: any }) => {
11
+ const { setModal, modal, modalResponse, setModalResponse } = useModal()
12
+ const deleteMutation = trpc.gallery.deletePhoto.useMutation({
13
+ onError: (error) => {
14
+ toast({
15
+ variant: 'destructive',
16
+ title: getString('delete_gallery_photo'),
17
+ description: error.message,
18
+ })
19
+ },
20
+
21
+ onSuccess: (data) => {
22
+ setModal(null)
23
+ setModalResponse(null)
24
+ toast({
25
+ variant: 'success',
26
+ title: getString('gallery_photo_deleted'),
27
+ })
28
+ action()
29
+ },
30
+ })
31
+ const { toast } = useToast()
32
+ const handlePhotoDelete = async () => {
33
+ deleteMutation.mutate({
34
+ sectionName: sectionName,
35
+ photoName: item.photo,
36
+ referenceId: item.referenceId,
37
+ })
38
+ }
39
+ return (
40
+ <div className='relative'>
41
+ {/* Delete Button */}
42
+ <button
43
+ type='button'
44
+ className='absolute -end-2 -top-2 z-10 h-6 w-6 rounded-full bg-red-500 p-1'
45
+ onClick={() => {
46
+ setModal({
47
+ title: getString('delete_gallery_photo'),
48
+ body: (
49
+ <div className='p-4'>
50
+ <div className='flex flex-col gap-4'>
51
+ <div>{getString('delete_gallery_photo_text')}</div>
52
+ <div className='flex gap-2'>
53
+ <button
54
+ className='rounded bg-green-600 px-2 py-1 text-white'
55
+ onClick={handlePhotoDelete}
56
+ >
57
+ Yes
58
+ </button>
59
+ <button
60
+ className='rounded bg-red-800 px-2 py-1 text-white'
61
+ onClick={() => {
62
+ setModal(null)
63
+ }}
64
+ >
65
+ No
66
+ </button>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ ),
71
+ headerColor: 'bg-red-700',
72
+ titleColor: 'text-white',
73
+ lang: 'en',
74
+ })
75
+ }}
76
+ >
77
+ <MinusIcon className='text-white' />
78
+ </button>
79
+ <ProtectedImage
80
+ section={sectionName}
81
+ photo={item.photo}
82
+ isThumb={true}
83
+ alt={item.photo}
84
+ height={150}
85
+ width={150}
86
+ // fill={true}
87
+ className='mb-4 rounded p-1 ring ring-gray-400'
88
+ />
89
+ </div>
90
+ )
91
+ }
92
+
93
+ export default GalleryPhoto
@@ -0,0 +1,94 @@
1
+ 'use client'
2
+
3
+ import Link from 'next/link'
4
+ import React from 'react'
5
+ import { CheckCircle, OctagonIcon, TriangleIcon } from 'lucide-react'
6
+
7
+ type result = {
8
+ key: string
9
+ title: string
10
+ status?: boolean
11
+ icon?: boolean
12
+ action?: {
13
+ text: string
14
+ link: string
15
+ }
16
+ }
17
+
18
+ export default function InfoCard({ result, className }: { result: result; className?: string }) {
19
+ let bgColor
20
+ let iconBgColor
21
+ let textColor
22
+ let buttonColor
23
+ switch (result.key) {
24
+ case 'success':
25
+ bgColor = 'bg-green-100'
26
+ iconBgColor = 'bg-green-200'
27
+ textColor = 'text-green-800'
28
+ buttonColor = 'bg-green-500 hover:bg-green-400'
29
+
30
+ break
31
+ case 'danger':
32
+ bgColor = 'bg-rose-100'
33
+ iconBgColor = 'bg-rose-200'
34
+ textColor = 'text-red-800'
35
+ buttonColor = 'bg-rose-600 hover:bg-red-500'
36
+
37
+ break
38
+ case 'warning':
39
+ bgColor = 'bg-orange-100'
40
+ iconBgColor = 'bg-orange-200'
41
+ textColor = 'text-orange-800'
42
+ buttonColor = 'bg-orange-500 hover:bg-orange-400'
43
+ break
44
+ case 'info':
45
+ bgColor = 'bg-sky-100'
46
+ iconBgColor = 'bg-sky-200'
47
+ textColor = 'text-blue-900'
48
+ buttonColor = 'bg-blue-500 hover:bg-blue-400'
49
+ break
50
+ default:
51
+ break
52
+ }
53
+ return (
54
+ <div className={className}>
55
+ <div className='col-span-full relative w-full overflow-hidden rounded-lg bg-white text-left border border-sky-700 transition-all'>
56
+ <div className=''>
57
+ <div className=''>
58
+ <div className={`w-full ${bgColor}`}>
59
+ <div className={`flex items-center text-md font-semibold ${textColor} py-1 px-2`}>
60
+ {result.icon && (
61
+ <div
62
+ className={` flex h-10 w-10 p-1 shrink-0 items-center justify-center rounded-full ${iconBgColor}`}
63
+ >
64
+ {result.key === 'success' ? (
65
+ <CheckCircle />
66
+ ) : result.key === 'danger' ? (
67
+ <OctagonIcon />
68
+ ) : result.key === 'warning' ? (
69
+ <TriangleIcon />
70
+ ) : (
71
+ <OctagonIcon />
72
+ )}
73
+ </div>
74
+ )}
75
+ <div className='ps-2 py-2'>
76
+ <div dangerouslySetInnerHTML={{ __html: result.title }}></div>
77
+ {result.action && (
78
+ <Link
79
+ href={result.action.link}
80
+ type='link'
81
+ className={`justify-center text-sm font-bold ms-2 text-blue-600`}
82
+ >
83
+ {result.action.text}
84
+ </Link>
85
+ )}
86
+ </div>
87
+ </div>
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ )
94
+ }