create-nextjs-cms 0.5.92 → 0.5.94
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/package.json +3 -3
- package/templates/default/app/(auth)/auth/login/LoginPage.tsx +13 -12
- package/templates/default/app/(auth)/layout.tsx +56 -0
- package/templates/default/app/(rootLayout)/layout.tsx +58 -8
- package/templates/default/app/globals.css +1 -1
- package/templates/default/components/AdminCard.tsx +16 -15
- package/templates/default/components/AdminEditPage.tsx +8 -7
- package/templates/default/components/AdminPrivilegeCard.tsx +12 -11
- package/templates/default/components/AdminsPage.tsx +5 -4
- package/templates/default/components/AnalyticsPage.tsx +8 -7
- package/templates/default/components/BrowsePage.tsx +7 -6
- package/templates/default/components/CategoryDeleteConfirmPage.tsx +12 -11
- package/templates/default/components/CategorySectionSelectInput.tsx +3 -2
- package/templates/default/components/DashboardNewPage.tsx +40 -39
- package/templates/default/components/DashboardPage.tsx +34 -33
- package/templates/default/components/DashboardPageAlt.tsx +3 -1
- package/templates/default/components/Dropzone.tsx +8 -7
- package/templates/default/components/EmailCard.tsx +12 -11
- package/templates/default/components/EmailPasswordForm.tsx +7 -6
- package/templates/default/components/EmailQuotaForm.tsx +7 -6
- package/templates/default/components/EmailsPage.tsx +6 -5
- package/templates/default/components/GalleryPhoto.tsx +6 -5
- package/templates/default/components/ItemEditPage.tsx +5 -4
- package/templates/default/components/Layout.tsx +1 -1
- package/templates/default/components/LoadingSpinners.tsx +1 -1
- package/templates/default/components/LogPage.tsx +24 -9
- package/templates/default/components/Navbar.tsx +13 -12
- package/templates/default/components/NewAdminForm.tsx +12 -11
- package/templates/default/components/NewEmailForm.tsx +11 -10
- package/templates/default/components/NewPage.tsx +6 -5
- package/templates/default/components/NewVariantComponent.tsx +6 -5
- package/templates/default/components/PhotoGallery.tsx +4 -3
- package/templates/default/components/SectionItemCard.tsx +8 -8
- package/templates/default/components/SectionItemStatusBadge.tsx +3 -2
- package/templates/default/components/SectionPage.tsx +6 -5
- package/templates/default/components/SelectInputButtons.tsx +8 -7
- package/templates/default/components/SettingsPage.tsx +18 -17
- package/templates/default/components/Sidebar.tsx +23 -15
- package/templates/default/components/SidebarDropdownItem.tsx +11 -5
- package/templates/default/components/SidebarItem.tsx +1 -0
- package/templates/default/components/VariantCard.tsx +8 -8
- package/templates/default/components/VariantEditPage.tsx +5 -4
- package/templates/default/components/analytics/BounceRate.tsx +6 -5
- package/templates/default/components/analytics/LivePageViews.tsx +8 -7
- package/templates/default/components/analytics/LiveUsersCount.tsx +3 -2
- package/templates/default/components/analytics/MonthlyPageViews.tsx +3 -2
- package/templates/default/components/analytics/TopCountries.tsx +4 -3
- package/templates/default/components/analytics/TopDevices.tsx +4 -3
- package/templates/default/components/analytics/TopMediums.tsx +4 -3
- package/templates/default/components/analytics/TopSources.tsx +4 -3
- package/templates/default/components/analytics/TotalPageViews.tsx +3 -2
- package/templates/default/components/analytics/TotalSessions.tsx +3 -2
- package/templates/default/components/analytics/TotalUniqueUsers.tsx +3 -2
- package/templates/default/components/custom/RightHomeRoomVariantCard.tsx +9 -8
- package/templates/default/components/form/Form.tsx +5 -4
- package/templates/default/components/form/FormInputElement.tsx +3 -1
- package/templates/default/components/form/helpers/_section-hot-reload.js +1 -1
- package/templates/default/components/form/inputs/DateFormInput.tsx +3 -2
- package/templates/default/components/form/inputs/DocumentFormInput.tsx +16 -15
- package/templates/default/components/form/inputs/MapFormInput.tsx +5 -4
- package/templates/default/components/form/inputs/PhotoFormInput.tsx +16 -15
- package/templates/default/components/form/inputs/SelectFormInput.tsx +3 -2
- package/templates/default/components/form/inputs/TagsFormInput.tsx +3 -2
- package/templates/default/components/form/inputs/VideoFormInput.tsx +7 -6
- package/templates/default/components/pagination/PaginationButtons.tsx +8 -6
- package/templates/default/package.json +2 -2
- package/templates/default/app/layout.tsx +0 -40
|
@@ -2,7 +2,7 @@ import React, { CSSProperties, forwardRef, Ref, useEffect, useImperativeHandle,
|
|
|
2
2
|
import { DropEvent, FileRejection, useDropzone } from 'react-dropzone'
|
|
3
3
|
import { DropzoneFile } from 'nextjs-cms/core/types'
|
|
4
4
|
import ContainerBox from '@/components/ContainerBox'
|
|
5
|
-
import
|
|
5
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
6
6
|
import { MinusIcon } from '@radix-ui/react-icons'
|
|
7
7
|
import { useToast } from '@/components/ui/use-toast'
|
|
8
8
|
|
|
@@ -36,6 +36,7 @@ export interface DropzoneHandles {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function Dropzone(props: any, ref: Ref<DropzoneHandles>) {
|
|
39
|
+
const t = useI18n()
|
|
39
40
|
const acceptedFileTypes = {
|
|
40
41
|
'image/png': ['.png'],
|
|
41
42
|
'image/jpeg': ['.jpg', '.jpeg'],
|
|
@@ -62,17 +63,17 @@ function Dropzone(props: any, ref: Ref<DropzoneHandles>) {
|
|
|
62
63
|
onDropRejected: (rejectedFiles: FileRejection[], e: DropEvent) => {
|
|
63
64
|
toast({
|
|
64
65
|
variant: 'destructive',
|
|
65
|
-
title:
|
|
66
|
+
title: t('deleteGalleryPhoto'),
|
|
66
67
|
description: rejectedFiles[0]?.errors[0]?.message
|
|
67
68
|
? rejectedFiles[0].errors[0].message
|
|
68
|
-
:
|
|
69
|
+
: t('error'),
|
|
69
70
|
})
|
|
70
71
|
},
|
|
71
72
|
|
|
72
73
|
onError: (error: any) => {
|
|
73
74
|
toast({
|
|
74
75
|
variant: 'destructive',
|
|
75
|
-
title:
|
|
76
|
+
title: t('deleteGalleryPhoto'),
|
|
76
77
|
description: error.displayName,
|
|
77
78
|
})
|
|
78
79
|
},
|
|
@@ -131,16 +132,16 @@ function Dropzone(props: any, ref: Ref<DropzoneHandles>) {
|
|
|
131
132
|
}, [])
|
|
132
133
|
|
|
133
134
|
return (
|
|
134
|
-
<ContainerBox title={
|
|
135
|
+
<ContainerBox title={t('uploadPhotosToGallery')}>
|
|
135
136
|
<section className='container mt-4 rounded-2xl border-4 border-dashed border-gray-400 bg-accent py-8'>
|
|
136
137
|
<div {...getRootProps({ className: 'dropzone' })}>
|
|
137
138
|
<input {...getInputProps()} />
|
|
138
139
|
<div className='flex flex-col items-center justify-center'>
|
|
139
140
|
<div className='p-4 text-xl font-semibold text-card-foreground'>
|
|
140
|
-
{
|
|
141
|
+
{t('dropzoneText')}
|
|
141
142
|
</div>
|
|
142
143
|
<div className='text-muted-foreground'>
|
|
143
|
-
|
|
144
|
+
{t('accepts')}: {Object.values(acceptedFileTypes).flat().join(', ')}
|
|
144
145
|
</div>
|
|
145
146
|
</div>
|
|
146
147
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { EmailItem } from 'nextjs-cms/core/types'
|
|
4
4
|
import useModal from '@/hooks/useModal'
|
|
@@ -11,6 +11,7 @@ import EmailPasswordForm from '@/components/EmailPasswordForm'
|
|
|
11
11
|
import { trpc } from '@/app/_trpc/client'
|
|
12
12
|
|
|
13
13
|
export default function EmailCard({ email, action }: { email: EmailItem; action: any }) {
|
|
14
|
+
const t = useI18n()
|
|
14
15
|
const { setModal, modal, modalResponse, setModalResponse } = useModal()
|
|
15
16
|
const { toast } = useToast()
|
|
16
17
|
|
|
@@ -29,7 +30,7 @@ export default function EmailCard({ email, action }: { email: EmailItem; action:
|
|
|
29
30
|
setModalResponse(null)
|
|
30
31
|
toast({
|
|
31
32
|
variant: 'success',
|
|
32
|
-
title:
|
|
33
|
+
title: t('deleteEmailAccount'),
|
|
33
34
|
description: data.message,
|
|
34
35
|
})
|
|
35
36
|
},
|
|
@@ -61,7 +62,7 @@ export default function EmailCard({ email, action }: { email: EmailItem; action:
|
|
|
61
62
|
variant='default'
|
|
62
63
|
onClick={() => {
|
|
63
64
|
setModal({
|
|
64
|
-
title:
|
|
65
|
+
title: t('emailQuota'),
|
|
65
66
|
body: (
|
|
66
67
|
<div className='p-4'>
|
|
67
68
|
<EmailQuotaForm email={email.user} action={() => action()} />
|
|
@@ -73,14 +74,14 @@ export default function EmailCard({ email, action }: { email: EmailItem; action:
|
|
|
73
74
|
})
|
|
74
75
|
}}
|
|
75
76
|
>
|
|
76
|
-
{
|
|
77
|
+
{t('quota')}
|
|
77
78
|
</Button>
|
|
78
79
|
<Button
|
|
79
80
|
size='sm'
|
|
80
81
|
variant='default'
|
|
81
82
|
onClick={() => {
|
|
82
83
|
setModal({
|
|
83
|
-
title:
|
|
84
|
+
title: t('changePassword'),
|
|
84
85
|
body: (
|
|
85
86
|
<div className='p-4'>
|
|
86
87
|
<EmailPasswordForm email={email.user} action={() => action()} />
|
|
@@ -92,24 +93,24 @@ export default function EmailCard({ email, action }: { email: EmailItem; action:
|
|
|
92
93
|
})
|
|
93
94
|
}}
|
|
94
95
|
>
|
|
95
|
-
{
|
|
96
|
+
{t('password')}
|
|
96
97
|
</Button>
|
|
97
98
|
<Button
|
|
98
99
|
size='sm'
|
|
99
100
|
variant='destructive'
|
|
100
101
|
onClick={() => {
|
|
101
102
|
setModal({
|
|
102
|
-
title:
|
|
103
|
+
title: t('delete'),
|
|
103
104
|
body: (
|
|
104
105
|
<div className='p-4'>
|
|
105
106
|
<div className='flex flex-col gap-4'>
|
|
106
|
-
<div>{
|
|
107
|
+
<div>{t('deleteEmailText')}</div>
|
|
107
108
|
<div className='flex gap-2'>
|
|
108
109
|
<button
|
|
109
110
|
className='rounded bg-green-600 px-2 py-1 text-white'
|
|
110
111
|
onClick={deleteEmail}
|
|
111
112
|
>
|
|
112
|
-
|
|
113
|
+
{t('yes')}
|
|
113
114
|
</button>
|
|
114
115
|
<button
|
|
115
116
|
className='rounded bg-red-800 px-2 py-1 text-white'
|
|
@@ -117,7 +118,7 @@ export default function EmailCard({ email, action }: { email: EmailItem; action:
|
|
|
117
118
|
setModal(null)
|
|
118
119
|
}}
|
|
119
120
|
>
|
|
120
|
-
|
|
121
|
+
{t('no')}
|
|
121
122
|
</button>
|
|
122
123
|
</div>
|
|
123
124
|
</div>
|
|
@@ -129,7 +130,7 @@ export default function EmailCard({ email, action }: { email: EmailItem; action:
|
|
|
129
130
|
})
|
|
130
131
|
}}
|
|
131
132
|
>
|
|
132
|
-
{
|
|
133
|
+
{t('delete')}
|
|
133
134
|
</Button>
|
|
134
135
|
</CardFooter>
|
|
135
136
|
</Card>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import useModal from '@/hooks/useModal'
|
|
4
4
|
import { useToast } from '@/components/ui/use-toast'
|
|
@@ -6,13 +6,14 @@ import InfoCard from '@/components/InfoCard'
|
|
|
6
6
|
import { trpc } from '@/app/_trpc/client'
|
|
7
7
|
|
|
8
8
|
export default function EmailPasswordForm({ email, action }: { email: string; action: any }) {
|
|
9
|
+
const t = useI18n()
|
|
9
10
|
const { setModal, modal, modalResponse, setModalResponse } = useModal()
|
|
10
11
|
|
|
11
12
|
const { toast } = useToast()
|
|
12
13
|
const quotaMutation = trpc.cpanelEmails.passwordChange.useMutation({
|
|
13
14
|
onError: (error) => {
|
|
14
15
|
setModal({
|
|
15
|
-
title:
|
|
16
|
+
title: t('error'),
|
|
16
17
|
body: (
|
|
17
18
|
<div className='p-4'>
|
|
18
19
|
<InfoCard result={{ key: 'danger', title: error.message, status: false }} />
|
|
@@ -29,7 +30,7 @@ export default function EmailPasswordForm({ email, action }: { email: string; ac
|
|
|
29
30
|
setModalResponse(null)
|
|
30
31
|
toast({
|
|
31
32
|
variant: 'success',
|
|
32
|
-
title:
|
|
33
|
+
title: t('success'),
|
|
33
34
|
})
|
|
34
35
|
},
|
|
35
36
|
})
|
|
@@ -46,7 +47,7 @@ export default function EmailPasswordForm({ email, action }: { email: string; ac
|
|
|
46
47
|
<form onSubmit={handleSubmit} className='flex flex-col gap-2'>
|
|
47
48
|
<div>
|
|
48
49
|
<label htmlFor='password' className='block text-sm font-medium leading-6 text-foreground'>
|
|
49
|
-
{
|
|
50
|
+
{t('newPassword')}
|
|
50
51
|
</label>
|
|
51
52
|
<div className=''>
|
|
52
53
|
<input
|
|
@@ -61,7 +62,7 @@ export default function EmailPasswordForm({ email, action }: { email: string; ac
|
|
|
61
62
|
</div>
|
|
62
63
|
<div>
|
|
63
64
|
<label htmlFor='passwordConfirm' className='block text-sm font-medium leading-6 text-foreground'>
|
|
64
|
-
{
|
|
65
|
+
{t('confirmNewPassword')}
|
|
65
66
|
</label>
|
|
66
67
|
<div className=''>
|
|
67
68
|
<input
|
|
@@ -76,7 +77,7 @@ export default function EmailPasswordForm({ email, action }: { email: string; ac
|
|
|
76
77
|
</div>
|
|
77
78
|
<div className='mt-4'>
|
|
78
79
|
<button className='rounded bg-blue-700 px-2 py-1 font-bold text-white'>
|
|
79
|
-
{
|
|
80
|
+
{t('changePassword')}
|
|
80
81
|
</button>
|
|
81
82
|
</div>
|
|
82
83
|
</form>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import useModal from '@/hooks/useModal'
|
|
4
4
|
import { Badge } from '@/components/ui/badge'
|
|
@@ -7,13 +7,14 @@ import InfoCard from '@/components/InfoCard'
|
|
|
7
7
|
import { trpc } from '@/app/_trpc/client'
|
|
8
8
|
|
|
9
9
|
export default function EmailQuotaForm({ email, action }: { email: string; action: any }) {
|
|
10
|
+
const t = useI18n()
|
|
10
11
|
const { setModal, modal, modalResponse, setModalResponse } = useModal()
|
|
11
12
|
const { toast } = useToast()
|
|
12
13
|
|
|
13
14
|
const quotaMutation = trpc.cpanelEmails.quotaChange.useMutation({
|
|
14
15
|
onError: (error) => {
|
|
15
16
|
setModal({
|
|
16
|
-
title:
|
|
17
|
+
title: t('error'),
|
|
17
18
|
body: (
|
|
18
19
|
<div className='p-4'>
|
|
19
20
|
<InfoCard result={{ key: 'danger', title: error.message, status: false }} />
|
|
@@ -30,7 +31,7 @@ export default function EmailQuotaForm({ email, action }: { email: string; actio
|
|
|
30
31
|
setModalResponse(null)
|
|
31
32
|
toast({
|
|
32
33
|
variant: 'success',
|
|
33
|
-
title:
|
|
34
|
+
title: t('success'),
|
|
34
35
|
})
|
|
35
36
|
},
|
|
36
37
|
})
|
|
@@ -46,7 +47,7 @@ export default function EmailQuotaForm({ email, action }: { email: string; actio
|
|
|
46
47
|
<form onSubmit={handleSubmit} className='flex flex-col gap-2'>
|
|
47
48
|
<div>
|
|
48
49
|
<label htmlFor='quota' className='block text-sm font-medium leading-6 text-foreground'>
|
|
49
|
-
{
|
|
50
|
+
{t('emailQuota')}
|
|
50
51
|
</label>
|
|
51
52
|
<div className=''>
|
|
52
53
|
<input
|
|
@@ -58,13 +59,13 @@ export default function EmailQuotaForm({ email, action }: { email: string; actio
|
|
|
58
59
|
className='block rounded-md border-0 bg-input p-2.5 text-foreground shadow-xs 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
|
/>
|
|
60
61
|
<Badge className='rounded-sm border-muted-foreground text-muted-foreground' variant='secondary'>
|
|
61
|
-
0 = {
|
|
62
|
+
0 = {t('unlimited')}
|
|
62
63
|
</Badge>
|
|
63
64
|
</div>
|
|
64
65
|
</div>
|
|
65
66
|
<div className='mt-4'>
|
|
66
67
|
<button className='rounded bg-blue-700 px-2 py-1 font-bold text-white'>
|
|
67
|
-
{
|
|
68
|
+
{t('updateQuota')}
|
|
68
69
|
</button>
|
|
69
70
|
</div>
|
|
70
71
|
</form>
|
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect } from 'react'
|
|
4
4
|
import { EmailItem } from 'nextjs-cms/core/types'
|
|
5
|
-
import
|
|
5
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
6
6
|
import ContainerBox from '@/components/ContainerBox'
|
|
7
7
|
import NewEmailForm from '@/components/NewEmailForm'
|
|
8
8
|
import EmailCard from '@/components/EmailCard'
|
|
9
9
|
import { trpc } from '@/app/_trpc/client'
|
|
10
10
|
|
|
11
11
|
const EmailsPage = () => {
|
|
12
|
+
const t = useI18n()
|
|
12
13
|
const controller = new AbortController()
|
|
13
14
|
|
|
14
15
|
const { isLoading, isError, data, error, refetch } = trpc.cpanelEmails.getEmails.useQuery()
|
|
@@ -22,17 +23,17 @@ const EmailsPage = () => {
|
|
|
22
23
|
return (
|
|
23
24
|
<div className='bg-white dark:bg-slate-900'>
|
|
24
25
|
<div className='bg-linear-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'>{
|
|
26
|
+
<h1 className='text-3xl'>{t('emailAccounts')}</h1>
|
|
26
27
|
</div>
|
|
27
28
|
|
|
28
29
|
<div className='flex flex-col gap-2 p-4'>
|
|
29
|
-
<ContainerBox title={
|
|
30
|
+
<ContainerBox title={t('createNewEmailAccount')}>
|
|
30
31
|
<NewEmailForm action={() => refetch()} />
|
|
31
32
|
</ContainerBox>
|
|
32
33
|
|
|
33
|
-
{isLoading && <div>
|
|
34
|
+
{isLoading && <div>{t('loading')}</div>}
|
|
34
35
|
{data && data.emails && data.emails.length > 0 && (
|
|
35
|
-
<ContainerBox title={
|
|
36
|
+
<ContainerBox title={t('emailAccountsList')}>
|
|
36
37
|
<div className='mt-2 grid w-full grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3'>
|
|
37
38
|
{data.emails.map((email: EmailItem) => (
|
|
38
39
|
<EmailCard key={email.user} action={() => refetch()} email={email} />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PhotoGalleryItem } from 'nextjs-cms/core/types'
|
|
2
|
-
import
|
|
2
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
3
3
|
import { MinusIcon } from '@radix-ui/react-icons'
|
|
4
4
|
import ProtectedImage from '@/components/ProtectedImage'
|
|
5
5
|
import useModal from '@/hooks/useModal'
|
|
@@ -7,12 +7,13 @@ import { useToast } from '@/components/ui/use-toast'
|
|
|
7
7
|
import { trpc } from '@/app/_trpc/client'
|
|
8
8
|
|
|
9
9
|
const GalleryPhoto = ({ item, sectionName, action }: { item: PhotoGalleryItem; sectionName: string; action?: any }) => {
|
|
10
|
+
const t = useI18n()
|
|
10
11
|
const { setModal, setModalResponse } = useModal()
|
|
11
12
|
const deleteMutation = trpc.gallery.deletePhoto.useMutation({
|
|
12
13
|
onError: (error) => {
|
|
13
14
|
toast({
|
|
14
15
|
variant: 'destructive',
|
|
15
|
-
title:
|
|
16
|
+
title: t('deleteGalleryPhoto'),
|
|
16
17
|
description: error.message,
|
|
17
18
|
})
|
|
18
19
|
},
|
|
@@ -22,7 +23,7 @@ const GalleryPhoto = ({ item, sectionName, action }: { item: PhotoGalleryItem; s
|
|
|
22
23
|
setModalResponse(null)
|
|
23
24
|
toast({
|
|
24
25
|
variant: 'success',
|
|
25
|
-
title:
|
|
26
|
+
title: t('galleryPhotoDeleted'),
|
|
26
27
|
})
|
|
27
28
|
action()
|
|
28
29
|
},
|
|
@@ -43,11 +44,11 @@ const GalleryPhoto = ({ item, sectionName, action }: { item: PhotoGalleryItem; s
|
|
|
43
44
|
className='absolute -end-2 -top-2 z-10 h-6 w-6 rounded-full bg-red-500 p-1'
|
|
44
45
|
onClick={() => {
|
|
45
46
|
setModal({
|
|
46
|
-
title:
|
|
47
|
+
title: t('deleteGalleryPhoto'),
|
|
47
48
|
body: (
|
|
48
49
|
<div className='p-4'>
|
|
49
50
|
<div className='flex flex-col gap-4'>
|
|
50
|
-
<div>{
|
|
51
|
+
<div>{t('deleteGalleryPhotoText')}</div>
|
|
51
52
|
<div className='flex gap-2'>
|
|
52
53
|
<button
|
|
53
54
|
className='rounded bg-green-600 px-2 py-1 text-white'
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { useAxiosPrivate } from 'nextjs-cms/auth/hooks'
|
|
4
4
|
import { RefObject, useEffect, useRef, useState } from 'react'
|
|
5
5
|
import { SectionType } from 'nextjs-cms/core/types'
|
|
6
|
-
import
|
|
6
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
7
7
|
import useModal from '@/hooks/useModal'
|
|
8
8
|
import { AxiosError } from 'axios'
|
|
9
9
|
import InfoCard from '@/components/InfoCard'
|
|
@@ -31,6 +31,7 @@ export default function ItemEditPage({
|
|
|
31
31
|
}[]
|
|
32
32
|
action?: any
|
|
33
33
|
}) {
|
|
34
|
+
const t = useI18n()
|
|
34
35
|
const [response, setResponse] = useState<any>(null)
|
|
35
36
|
const [progress, setProgress] = useState(0)
|
|
36
37
|
const [progressVariant, setProgressVariant] = useState<'determinate' | 'query'>('determinate')
|
|
@@ -133,7 +134,7 @@ export default function ItemEditPage({
|
|
|
133
134
|
setModal(null)
|
|
134
135
|
toast({
|
|
135
136
|
variant: 'success',
|
|
136
|
-
description:
|
|
137
|
+
description: t('itemUpdatedSuccessfully'),
|
|
137
138
|
})
|
|
138
139
|
if (action) {
|
|
139
140
|
await action().then(() => {
|
|
@@ -149,7 +150,7 @@ export default function ItemEditPage({
|
|
|
149
150
|
setResponse(null)
|
|
150
151
|
toast({
|
|
151
152
|
variant: 'success',
|
|
152
|
-
description:
|
|
153
|
+
description: t('itemUpdatedSuccessfully'),
|
|
153
154
|
})
|
|
154
155
|
|
|
155
156
|
// Redirect to the edit page
|
|
@@ -193,7 +194,7 @@ export default function ItemEditPage({
|
|
|
193
194
|
<div className='absolute left-0 top-0 z-2 h-4 w-full bg-linear-to-r from-emerald-800 via-emerald-400 to-sky-600'></div>
|
|
194
195
|
<h1 className='pb-4 text-4xl'>{data.section?.title.section}</h1>
|
|
195
196
|
<span>
|
|
196
|
-
/{
|
|
197
|
+
/{t('edit')} {data.section?.title.singular}
|
|
197
198
|
</span>
|
|
198
199
|
</div>
|
|
199
200
|
<Form
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
4
4
|
import { trpc } from '@/app/_trpc/client'
|
|
5
5
|
import { Badge } from '@/components/ui/badge'
|
|
6
6
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
|
7
|
+
import ErrorComponent from '@/components/ErrorComponent'
|
|
8
|
+
import { Spinner } from '@/components/ui/spinner'
|
|
7
9
|
|
|
8
10
|
type LogMetadata = {
|
|
9
11
|
fields?: string[]
|
|
@@ -28,34 +30,47 @@ const parseMetadata = (metadata?: string | null): LogMetadata | null => {
|
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
export default function LogPage() {
|
|
31
|
-
const
|
|
33
|
+
const t = useI18n()
|
|
34
|
+
const { data, isLoading, isError, error } = trpc.logs.list.useQuery({
|
|
32
35
|
limit: 50,
|
|
33
36
|
offset: 0,
|
|
34
37
|
})
|
|
35
38
|
|
|
39
|
+
if (isLoading) {
|
|
40
|
+
return (
|
|
41
|
+
<div className='flex w-full items-center justify-center p-8'>
|
|
42
|
+
<Spinner className='size-8' />
|
|
43
|
+
</div>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (isError) {
|
|
48
|
+
return <ErrorComponent message={error?.message || t('noAccessToSection')} />
|
|
49
|
+
}
|
|
50
|
+
|
|
36
51
|
const logs = data?.items ?? []
|
|
37
52
|
return (
|
|
38
53
|
<div className='w-full'>
|
|
39
54
|
<div className='text-foreground bg-linear-to-r from-sky-200 via-emerald-300 to-blue-600 p-8 font-extrabold dark:from-blue-800 dark:via-amber-700 dark:to-rose-900'>
|
|
40
|
-
<h1 className='text-3xl'>{
|
|
55
|
+
<h1 className='text-3xl'>{t('logs')}</h1>
|
|
41
56
|
</div>
|
|
42
57
|
|
|
43
58
|
<div className='flex flex-col gap-4 p-4'>
|
|
44
59
|
<Table>
|
|
45
60
|
<TableHeader>
|
|
46
61
|
<TableRow>
|
|
47
|
-
<TableHead>{
|
|
48
|
-
<TableHead>{
|
|
49
|
-
<TableHead>{
|
|
50
|
-
<TableHead>{
|
|
51
|
-
<TableHead>{
|
|
62
|
+
<TableHead>{t('date')}</TableHead>
|
|
63
|
+
<TableHead>{t('action')}</TableHead>
|
|
64
|
+
<TableHead>{t('admin')}</TableHead>
|
|
65
|
+
<TableHead>{t('section')}</TableHead>
|
|
66
|
+
<TableHead>{t('details')}</TableHead>
|
|
52
67
|
</TableRow>
|
|
53
68
|
</TableHeader>
|
|
54
69
|
<TableBody>
|
|
55
70
|
{logs.length === 0 ? (
|
|
56
71
|
<TableRow>
|
|
57
72
|
<TableCell colSpan={5} className='text-muted-foreground text-center'>
|
|
58
|
-
{
|
|
73
|
+
{t('noData')}
|
|
59
74
|
</TableCell>
|
|
60
75
|
</TableRow>
|
|
61
76
|
) : (
|
|
@@ -3,7 +3,7 @@ import classNames from 'classnames'
|
|
|
3
3
|
import { MoonIcon, SunIcon, BellIcon, HamburgerMenuIcon } from '@radix-ui/react-icons'
|
|
4
4
|
import { useTheme } from 'next-themes'
|
|
5
5
|
import Link from 'next/link'
|
|
6
|
-
import
|
|
6
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
7
7
|
import { trpc } from '@/app/_trpc/client'
|
|
8
8
|
import ProtectedImage from '@/components/ProtectedImage'
|
|
9
9
|
import { Spinner } from '@/components/ui/spinner'
|
|
@@ -39,6 +39,7 @@ const formatTimestamp = (value?: Date | string | null) => {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export default function Navbar(props: Props) {
|
|
42
|
+
const t = useI18n()
|
|
42
43
|
const { theme, setTheme } = useTheme()
|
|
43
44
|
const session = useSession()
|
|
44
45
|
const { toast } = useToast()
|
|
@@ -67,7 +68,7 @@ export default function Navbar(props: Props) {
|
|
|
67
68
|
} catch (error: any) {
|
|
68
69
|
toast({
|
|
69
70
|
variant: 'destructive',
|
|
70
|
-
title:
|
|
71
|
+
title: t('logoutError'),
|
|
71
72
|
description: error.message,
|
|
72
73
|
})
|
|
73
74
|
}
|
|
@@ -109,7 +110,7 @@ export default function Navbar(props: Props) {
|
|
|
109
110
|
</div>*/}
|
|
110
111
|
</div>
|
|
111
112
|
<div className=''>
|
|
112
|
-
<div className='
|
|
113
|
+
<div className='ms-4 flex items-center md:ms-6'>
|
|
113
114
|
<div className='flex flex-row items-center gap-3'>
|
|
114
115
|
<DropdownMenu onOpenChange={handleNotificationsOpenChange}>
|
|
115
116
|
<DropdownMenuTrigger
|
|
@@ -125,20 +126,20 @@ export default function Navbar(props: Props) {
|
|
|
125
126
|
alignOffset={-20}
|
|
126
127
|
className='w-[400px] max-w-full ring-1 ring-sky-400/80 dark:ring-amber-900'
|
|
127
128
|
>
|
|
128
|
-
<DropdownMenuLabel>{
|
|
129
|
+
<DropdownMenuLabel>{t('notifications')}</DropdownMenuLabel>
|
|
129
130
|
<DropdownMenuSeparator />
|
|
130
131
|
<DropdownMenuGroup className='max-h-[320px] overflow-y-auto'>
|
|
131
132
|
{logsQuery.isFetching && logs.length === 0 ? (
|
|
132
133
|
<DropdownMenuItem disabled className='flex items-center gap-2'>
|
|
133
134
|
<Spinner className='size-3' />
|
|
134
|
-
<span>{
|
|
135
|
+
<span>{t('loading')}</span>
|
|
135
136
|
</DropdownMenuItem>
|
|
136
137
|
) : logsQuery.isError ? (
|
|
137
138
|
<DropdownMenuItem disabled>
|
|
138
|
-
{
|
|
139
|
+
{logsQuery.error?.message || t('noAccessToSection')}
|
|
139
140
|
</DropdownMenuItem>
|
|
140
141
|
) : logs.length === 0 ? (
|
|
141
|
-
<DropdownMenuItem disabled>{
|
|
142
|
+
<DropdownMenuItem disabled>{t('noData')}</DropdownMenuItem>
|
|
142
143
|
) : (
|
|
143
144
|
logs.map((log) => {
|
|
144
145
|
const actorLabel = log.actorUsername || log.actorId || ''
|
|
@@ -170,7 +171,7 @@ export default function Navbar(props: Props) {
|
|
|
170
171
|
|
|
171
172
|
<Link href='/log'>
|
|
172
173
|
<DropdownMenuItem className='cursor-pointer'>
|
|
173
|
-
<span>{
|
|
174
|
+
<span>{t('seeAll')}</span>
|
|
174
175
|
</DropdownMenuItem>
|
|
175
176
|
</Link>
|
|
176
177
|
</DropdownMenuContent>
|
|
@@ -219,8 +220,8 @@ export default function Navbar(props: Props) {
|
|
|
219
220
|
<DropdownMenuGroup>
|
|
220
221
|
<Link href='/settings'>
|
|
221
222
|
<DropdownMenuItem className='cursor-pointer'>
|
|
222
|
-
<Settings className='
|
|
223
|
-
<span>{
|
|
223
|
+
<Settings className='me-2 h-4 w-4' />
|
|
224
|
+
<span>{t('accountSettings')}</span>
|
|
224
225
|
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
|
225
226
|
</DropdownMenuItem>
|
|
226
227
|
</Link>
|
|
@@ -228,8 +229,8 @@ export default function Navbar(props: Props) {
|
|
|
228
229
|
<DropdownMenuSeparator />
|
|
229
230
|
|
|
230
231
|
<DropdownMenuItem className='cursor-pointer' onClick={handleLogout}>
|
|
231
|
-
<LogOut className='
|
|
232
|
-
<span>{
|
|
232
|
+
<LogOut className='me-2 h-4 w-4' />
|
|
233
|
+
<span>{t('logout')}</span>
|
|
233
234
|
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
|
234
235
|
</DropdownMenuItem>
|
|
235
236
|
</DropdownMenuContent>
|