Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
sevenpro-frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
FAP
sevenpro-frontend
Commits
4f7e1d0b
Commit
4f7e1d0b
authored
Oct 10, 2024
by
Wellton Quirino
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crud of areas
parent
9863ab2f
Changes
19
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
1094 additions
and
1284 deletions
+1094
-1284
package-lock.json
package-lock.json
+336
-1131
package.json
package.json
+4
-1
areas.ts
src/api/areas.ts
+54
-0
audiences.ts
src/api/audiences.ts
+11
-0
banners.ts
src/api/banners.ts
+13
-0
page.tsx
src/app/admin/area/[id]/page.tsx
+127
-52
page.tsx
src/app/admin/area/page.tsx
+73
-51
page.tsx
src/app/admin/curso/[id]/page.tsx
+2
-2
page.tsx
src/app/admin/curso/page.tsx
+2
-2
page.tsx
src/app/admin/page.tsx
+48
-29
layout.tsx
src/app/layout.tsx
+9
-3
breadcrumb-component.tsx
src/components/breadcrumb-component.tsx
+30
-0
input-file.tsx
src/components/input-file.tsx
+31
-0
modal-dialog.tsx
src/components/modal-dialog.tsx
+34
-0
alert-dialog.tsx
src/components/ui/alert-dialog.tsx
+141
-0
breadcrumb.tsx
src/components/ui/breadcrumb.tsx
+115
-0
input.tsx
src/components/ui/input.tsx
+41
-12
axios.ts
src/lib/axios.ts
+1
-1
react-query.tsx
src/providers/react-query.tsx
+22
-0
No files found.
package-lock.json
View file @
4f7e1d0b
This diff is collapsed.
Click to expand it.
package.json
View file @
4f7e1d0b
...
@@ -14,6 +14,7 @@
...
@@ -14,6 +14,7 @@
"
@hookform/resolvers
"
:
"
^3.9.0
"
,
"
@hookform/resolvers
"
:
"
^3.9.0
"
,
"
@mui/material
"
:
"
^5.16.4
"
,
"
@mui/material
"
:
"
^5.16.4
"
,
"
@radix-ui/react-accordion
"
:
"
^1.2.0
"
,
"
@radix-ui/react-accordion
"
:
"
^1.2.0
"
,
"
@radix-ui/react-alert-dialog
"
:
"
^1.1.2
"
,
"
@radix-ui/react-checkbox
"
:
"
^1.1.1
"
,
"
@radix-ui/react-checkbox
"
:
"
^1.1.1
"
,
"
@radix-ui/react-dialog
"
:
"
^1.0.5
"
,
"
@radix-ui/react-dialog
"
:
"
^1.0.5
"
,
"
@radix-ui/react-label
"
:
"
^2.1.0
"
,
"
@radix-ui/react-label
"
:
"
^2.1.0
"
,
...
@@ -21,7 +22,8 @@
...
@@ -21,7 +22,8 @@
"
@radix-ui/react-select
"
:
"
^2.1.1
"
,
"
@radix-ui/react-select
"
:
"
^2.1.1
"
,
"
@radix-ui/react-separator
"
:
"
^1.1.0
"
,
"
@radix-ui/react-separator
"
:
"
^1.1.0
"
,
"
@radix-ui/react-slot
"
:
"
^1.1.0
"
,
"
@radix-ui/react-slot
"
:
"
^1.1.0
"
,
"
axios
"
:
"
^1.7.2
"
,
"
@tanstack/react-query
"
:
"
^5.59.3
"
,
"
axios
"
:
"
^1.7.7
"
,
"
class-variance-authority
"
:
"
^0.7.0
"
,
"
class-variance-authority
"
:
"
^0.7.0
"
,
"
clsx
"
:
"
^2.1.1
"
,
"
clsx
"
:
"
^2.1.1
"
,
"
date-fns
"
:
"
^3.6.0
"
,
"
date-fns
"
:
"
^3.6.0
"
,
...
@@ -35,6 +37,7 @@
...
@@ -35,6 +37,7 @@
"
react-dom
"
:
"
^18
"
,
"
react-dom
"
:
"
^18
"
,
"
react-hook-form
"
:
"
^7.52.2
"
,
"
react-hook-form
"
:
"
^7.52.2
"
,
"
react-input-mask
"
:
"
^2.0.4
"
,
"
react-input-mask
"
:
"
^2.0.4
"
,
"
sonner
"
:
"
^1.5.0
"
,
"
tailwind-merge
"
:
"
^2.3.0
"
,
"
tailwind-merge
"
:
"
^2.3.0
"
,
"
tailwindcss-animate
"
:
"
^1.0.7
"
,
"
tailwindcss-animate
"
:
"
^1.0.7
"
,
"
zod
"
:
"
^3.23.8
"
"
zod
"
:
"
^3.23.8
"
...
...
src/api/areas.ts
0 → 100644
View file @
4f7e1d0b
import
{
api
}
from
'@/lib/axios'
interface
FileBanner
{
name
:
string
}
export
type
AreasProps
=
{
id
:
string
name
:
string
desktopBanner
?:
{
[
key
:
string
]:
FileBanner
}
mobileBanner
?:
{
[
key
:
string
]:
FileBanner
}
}
export
async
function
createAreas
({
name
,
desktopBanner
,
mobileBanner
,
}:
AreasProps
)
{
const
area
=
await
api
.
post
<
AreasProps
[]
>
(
'/areas'
,
{
name
,
desktopBanner
,
mobileBanner
,
})
return
area
}
export
async
function
editArea
({
id
,
name
,
desktopBanner
,
mobileBanner
,
}:
AreasProps
)
{
const
area
=
await
api
.
patch
<
AreasProps
[]
>
(
`/areas/
${
id
}
`
,
{
name
,
desktopBanner
,
mobileBanner
,
})
return
area
}
export
async
function
getAreas
()
{
const
areas
=
await
api
.
get
<
AreasProps
[]
>
(
'/areas'
)
return
areas
}
export
async
function
getAreasId
(
id
:
string
)
{
const
area
=
await
api
.
get
<
AreasProps
>
(
`/areas/
${
id
}
`
)
return
area
}
export
async
function
deleteArea
(
id
:
string
)
{
const
area
=
await
api
.
delete
(
`/areas/
${
id
}
`
)
return
area
}
\ No newline at end of file
src/api/audiences.ts
0 → 100644
View file @
4f7e1d0b
import
{
api
}
from
'@/lib/axios'
export
type
AudiencesProps
=
{
id
:
string
name
:
string
}
export
async
function
getAudiences
()
{
const
audiences
=
await
api
.
get
<
AudiencesProps
[]
>
(
'/audiences'
)
return
audiences
}
src/api/banners.ts
0 → 100644
View file @
4f7e1d0b
import
{
api
}
from
'@/lib/axios'
export
type
BannersProps
=
{
id
:
string
name
:
string
desktopBanner
?:
string
mobileBanner
?:
string
}
export
async
function
getBanners
()
{
const
banners
=
await
api
.
get
<
BannersProps
[]
>
(
'/banners'
)
return
banners
}
src/app/admin/area/[id]/page.tsx
View file @
4f7e1d0b
import
{
StyledInputs
}
from
'@/components/mui/styled-inputs'
'use client'
import
{
AreasProps
,
deleteArea
,
editArea
,
getAreasId
}
from
'@/api/areas'
import
BreadcrumbComponent
from
'@/components/breadcrumb-component'
import
InputFile
from
'@/components/input-file'
import
ModalDialog
from
'@/components/modal-dialog'
import
{
AlertDialog
,
AlertDialogTrigger
}
from
'@/components/ui/alert-dialog'
import
{
Button
}
from
'@/components/ui/button'
import
{
Button
}
from
'@/components/ui/button'
import
{
TextField
}
from
'@mui/material'
import
{
Input
}
from
'@/components/ui/input'
import
{
useMutation
,
useQuery
,
useQueryClient
}
from
'@tanstack/react-query'
import
{
Trash
}
from
'lucide-react'
import
{
Trash
}
from
'lucide-react'
import
{
useParams
,
useRouter
}
from
'next/navigation'
import
{
useForm
}
from
'react-hook-form'
import
{
toast
}
from
'sonner'
export
default
function
AreaId
()
{
export
default
function
AreaId
()
{
const
params
=
useParams
<
{
id
:
string
}
>
()
const
{
register
,
handleSubmit
,
watch
}
=
useForm
<
AreasProps
>
()
const
router
=
useRouter
()
const
data
=
watch
()
const
valueDesktopBanner
=
data
?.
desktopBanner
?.[
'0'
]?.
name
const
valueMobileBanner
=
data
?.
mobileBanner
?.[
'0'
]?.
name
const
queryClient
=
useQueryClient
()
const
{
data
:
area
,
isLoading
,
isPending
}
=
useQuery
({
queryKey
:
[
'area'
],
queryFn
:
()
=>
getAreasId
(
params
.
id
),
enabled
:
!!
params
.
id
,
})
const
mutationEdit
=
useMutation
({
mutationFn
:
editArea
,
onSuccess
:
()
=>
{
toast
.
success
(
'Área editada com sucesso!'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'areas'
]
})
router
.
push
(
'/admin'
)
},
})
const
mutationDelete
=
useMutation
({
mutationFn
:
deleteArea
,
onSuccess
:
()
=>
{
toast
.
success
(
'Área deletada com sucesso!'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'areas'
]
})
router
.
push
(
'/admin'
)
},
})
function
onSubmit
(
data
:
AreasProps
)
{
const
body
=
{
...
data
,
id
:
params
.
id
,
}
mutationEdit
.
mutate
(
body
)
}
function
handleDeleteArea
()
{
mutationDelete
.
mutate
(
params
.
id
)
}
if
(
isLoading
)
{
console
.
log
(
'isloading'
)
return
<
span
>
isLoading TEST...
</
span
>
}
if
(
isPending
)
{
console
.
log
(
'isPeding'
)
return
<
span
>
isPending TEST...
</
span
>
}
return
(
return
(
<
section
className=
"container py-10"
>
<
section
className=
"container py-20 space-y-10"
>
<
BreadcrumbComponent
/>
<
form
onSubmit=
{
handleSubmit
(
onSubmit
)
}
>
<
div
className=
"flex items-center gap-6"
>
<
div
className=
"flex items-center gap-6"
>
<
h1
className=
"text-green-700 text-3xl font-bold"
>
Editar Área
</
h1
>
<
h1
className=
"text-3xl font-bold"
>
Editar Área
</
h1
>
<
Button
variant=
"third"
className=
"uppercase"
>
<
Button
variant=
"secondary"
type=
'submit'
className=
"uppercase rounded-sm"
>
Salvar como rascunho
</
Button
>
<
Button
variant=
"secondary"
className=
"uppercase"
>
Salvar e publicar
Salvar e publicar
</
Button
>
</
Button
>
<
Button
<
AlertDialog
>
variant=
"ghost"
<>
className=
"uppercase flex items-center gap-2 text-orange-100 hover:text-orange-100"
<
AlertDialogTrigger
className=
"uppercase flex items-center gap-2 text-orange-100 border-none hover:bg-orange-100/10 hover:text-orange-100 h-10 px-5 rounded-sm"
type=
"button"
>
>
<
span
>
Apagar área
</
span
>
<
span
>
Apagar área
</
span
>
<
Trash
/>
<
Trash
/>
</
Button
>
</
AlertDialogTrigger
>
<
ModalDialog
title=
"Tem certeza que deseja deletar a área?"
description=
{
`Ao clicar em continue você irá deletar a área ${area?.data.name}`
}
handleClick=
{
handleDeleteArea
}
/>
</>
</
AlertDialog
>
</
div
>
</
div
>
<
div
className=
"w-full
"
>
<
div
className=
"w-full mt-16
"
>
<
TextField
<
Input
label=
"Nome da área"
label=
"Nome da área"
variant=
"standard"
className=
"border-green-400"
defaultValue=
{
area
?.
data
.
name
}
{
...
register
('
name
')}
type=
"text"
type=
"text"
className=
"flex"
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
/>
/>
<
div
className=
"flex justify-between flex-wrap gap
-6"
>
<
div
className=
"flex justify-between flex-wrap gap-6 py
-6"
>
<
div
className=
"flex flex-col flex-1 mt-6"
>
<
div
className=
"flex flex-col flex-1 mt-6"
>
<
h6
className=
"text-xl text-purple-100"
>
Banner Desktop
</
h6
>
<
h6
className=
"text-xl text-purple-100"
>
Banner Desktop
</
h6
>
<
span
className=
"mt-4"
>
Dimensões recomendadas:
</
span
>
<
span
className=
"mt-4"
>
Dimensões recomendadas: 1512 x 300
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
Button
<
InputFile
variant=
"third
"
id=
"desktopBanner
"
className=
"border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
values=
{
valueDesktopBanner
}
>
label=
"Adicionar banner"
Adicionar banner
{
...
register
('
desktopBanner
')}
</
Button
>
/
>
</
div
>
</
div
>
<
div
className=
"flex flex-col flex-1 mt-6"
>
<
div
className=
"flex flex-col flex-1 mt-6"
>
<
h6
className=
"text-xl text-purple-100"
>
Banner Mobile
</
h6
>
<
h6
className=
"text-xl text-purple-100"
>
Banner Mobile
</
h6
>
<
span
className=
"mt-4"
>
Dimensões recomendadas:
</
span
>
<
span
className=
"mt-4"
>
Dimensões recomendadas: 390 x 300
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
Button
<
InputFile
variant=
"third
"
id=
"mobileBanner
"
className=
"border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
values=
{
valueMobileBanner
}
>
label=
"Adicionar banner"
Adicionar banner
{
...
register
('
mobileBanner
')}
</
Button
>
/
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
</
form
>
</
section
>
</
section
>
)
)
}
}
src/app/admin/area/page.tsx
View file @
4f7e1d0b
'use client'
import
{
AreasProps
,
createAreas
}
from
'@/api/areas'
import
InputFile
from
'@/components/input-file'
import
{
StyledInputs
}
from
'@/components/mui/styled-inputs'
import
{
StyledInputs
}
from
'@/components/mui/styled-inputs'
import
{
Button
}
from
'@/components/ui/button'
import
{
Button
}
from
'@/components/ui/button'
import
{
TextField
}
from
'@mui/material'
import
{
TextField
}
from
'@mui/material'
import
{
Trash
}
from
'lucide-react'
import
{
useMutation
,
useQueryClient
}
from
'@tanstack/react-query'
import
{
useRouter
}
from
'next/navigation'
import
{
useForm
}
from
'react-hook-form'
import
{
toast
}
from
'sonner'
export
default
function
Area
()
{
export
default
function
Area
()
{
const
{
register
,
handleSubmit
,
watch
}
=
useForm
<
AreasProps
>
()
const
router
=
useRouter
()
const
data
=
watch
()
const
valueDesktopBanner
=
data
?.
desktopBanner
?.[
'0'
]?.
name
const
valueMobileBanner
=
data
?.
mobileBanner
?.[
'0'
]?.
name
const
queryClient
=
useQueryClient
()
const
mutation
=
useMutation
({
mutationFn
:
createAreas
,
onSuccess
:
()
=>
{
toast
.
success
(
'Área criada com sucesso!'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'areas'
]
})
router
.
push
(
'/admin'
)
},
})
function
onSubmit
(
data
:
AreasProps
)
{
mutation
.
mutate
(
data
)
}
return
(
return
(
<
section
className=
"container py-10"
>
<
section
className=
"container py-20 space-y-10"
>
<
form
onSubmit=
{
handleSubmit
(
onSubmit
)
}
>
<
div
className=
"flex items-center gap-6"
>
<
div
className=
"flex items-center gap-6"
>
<
h1
className=
"text-green-700 text-3xl font-bold"
>
Criar Área
</
h1
>
<
h1
className=
"text-3xl font-bold"
>
Criar Área
</
h1
>
<
Button
variant=
"third"
className=
"uppercase"
>
<
Button
variant=
"secondary"
className=
"uppercase rounded-sm"
>
Salvar como rascunho
</
Button
>
<
Button
variant=
"secondary"
className=
"uppercase"
>
Salvar e publicar
Salvar e publicar
</
Button
>
</
Button
>
<
Button
variant=
"ghost"
className=
"uppercase flex items-center gap-2 text-orange-100 hover:text-orange-100"
>
<
span
>
Apagar área
</
span
>
<
Trash
/>
</
Button
>
</
div
>
</
div
>
<
div
className=
"w-full
"
>
<
div
className=
"w-full mt-16
"
>
<
TextField
<
TextField
label=
"Nome da área"
label=
"Nome da área"
variant=
"standard"
variant=
"standard"
type=
"text"
type=
"text"
className=
"flex"
className=
"flex"
{
...
register
('
name
')}
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
/>
/>
<
div
className=
"flex justify-between flex-wrap gap
-6"
>
<
div
className=
"flex justify-between flex-wrap gap-6 py
-6"
>
<
div
className=
"flex flex-col flex-1 mt-6"
>
<
div
className=
"flex flex-col flex-1 mt-6"
>
<
h6
className=
"text-xl text-purple-100"
>
Banner Desktop
</
h6
>
<
h6
className=
"text-xl text-purple-100"
>
Banner Desktop
</
h6
>
<
span
className=
"mt-4"
>
Dimensões recomendadas:
</
span
>
<
span
className=
"mt-4"
>
Dimensões recomendadas: 1512 x 300
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
Button
<
InputFile
variant=
"third
"
id=
"desktopBanner
"
className=
"border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
values=
{
valueDesktopBanner
}
>
label=
"Adicionar banner"
Adicionar banner
{
...
register
('
desktopBanner
')}
</
Button
>
/
>
</
div
>
</
div
>
<
div
className=
"flex flex-col flex-1 mt-6"
>
<
div
className=
"flex flex-col flex-1 mt-6"
>
<
h6
className=
"text-xl text-purple-100"
>
Banner Mobile
</
h6
>
<
h6
className=
"text-xl text-purple-100"
>
Banner Mobile
</
h6
>
<
span
className=
"mt-4"
>
Dimensões recomendadas:
</
span
>
<
span
className=
"mt-4"
>
Dimensões recomendadas: 390 x 300
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
Button
<
InputFile
variant=
"third
"
id=
"mobileBanner
"
className=
"border border-dotted border-green-400 rounded-sm mt-6 mx-auto w-full"
values=
{
valueMobileBanner
}
>
label=
"Adicionar banner"
Adicionar banner
{
...
register
('
mobileBanner
')}
</
Button
>
/
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
</
form
>
</
section
>
</
section
>
)
)
}
}
src/app/admin/curso/[id]/page.tsx
View file @
4f7e1d0b
...
@@ -30,9 +30,9 @@ export default function EditCourse() {
...
@@ -30,9 +30,9 @@ export default function EditCourse() {
<
form
>
<
form
>
<
div
className=
"flex items-center gap-6"
>
<
div
className=
"flex items-center gap-6"
>
<
h1
className=
"text-green-700 text-3xl font-bold"
>
Editar curso
</
h1
>
<
h1
className=
"text-green-700 text-3xl font-bold"
>
Editar curso
</
h1
>
<
Button
variant=
"third"
className=
"uppercase"
>
{
/*
<Button variant="third" className="uppercase">
Salvar como rascunho
Salvar como rascunho
</
Button
>
</Button>
*/
}
<
Button
variant=
"secondary"
className=
"uppercase"
>
<
Button
variant=
"secondary"
className=
"uppercase"
>
Salvar e publicar
Salvar e publicar
</
Button
>
</
Button
>
...
...
src/app/admin/curso/page.tsx
View file @
4f7e1d0b
...
@@ -30,9 +30,9 @@ export default function Curso() {
...
@@ -30,9 +30,9 @@ export default function Curso() {
<
form
>
<
form
>
<
div
className=
"flex items-center gap-6"
>
<
div
className=
"flex items-center gap-6"
>
<
h1
className=
"text-green-700 text-3xl font-bold"
>
Criar curso
</
h1
>
<
h1
className=
"text-green-700 text-3xl font-bold"
>
Criar curso
</
h1
>
<
Button
variant=
"third"
className=
"uppercase"
>
{
/*
<Button variant="third" className="uppercase">
Salvar como rascunho
Salvar como rascunho
</
Button
>
</Button>
*/
}
<
Button
variant=
"secondary"
className=
"uppercase"
>
<
Button
variant=
"secondary"
className=
"uppercase"
>
Salvar e publicar
Salvar e publicar
</
Button
>
</
Button
>
...
...
src/app/admin/page.tsx
View file @
4f7e1d0b
'use client'
import
{
getAreas
}
from
'@/api/areas'
import
{
Card
}
from
'@/components/card'
import
{
Card
}
from
'@/components/card'
import
{
InputMui
}
from
'@/components/mui/inputs'
import
{
InputMui
}
from
'@/components/mui/inputs'
import
{
Button
}
from
'@/components/ui/button'
import
{
Button
}
from
'@/components/ui/button'
import
{
CoursesCard
}
from
'@/utils/courses-array'
import
{
CoursesCard
}
from
'@/utils/courses-array'
import
{
useQuery
}
from
'@tanstack/react-query'
import
{
Pencil
,
Search
}
from
'lucide-react'
import
{
Pencil
,
Search
}
from
'lucide-react'
import
Link
from
'next/link'
import
Link
from
'next/link'
const
areas
=
[
//
const areas = [
{
//
{
id
:
'1'
,
//
id: '1',
title
:
'Educação'
,
//
title: 'Educação',
},
//
},
{
//
{
id
:
'2'
,
//
id: '2',
title
:
'Negócios'
,
//
title: 'Negócios',
},
//
},
{
//
{
id
:
'3'
,
//
id: '3',
title
:
'Comunicação'
,
//
title: 'Comunicação',
},
//
},
{
//
{
id
:
'4'
,
//
id: '4',
title
:
'Saúde'
,
//
title: 'Saúde',
},
//
},
{
//
{
id
:
'5'
,
//
id: '5',
title
:
'Tecnologia'
,
//
title: 'Tecnologia',
},
//
},
{
//
{
id
:
'6'
,
//
id: '6',
title
:
'Teologia'
,
//
title: 'Teologia',
},
//
},
]
//
]
const
banners
=
[
const
banners
=
[
{
{
...
@@ -42,6 +46,21 @@ const banners = [
...
@@ -42,6 +46,21 @@ const banners = [
]
]
export
default
function
Admin
()
{
export
default
function
Admin
()
{
const
{
data
:
areas
,
error
,
isLoading
,
isError
,
}
=
useQuery
({
queryKey
:
[
'areas'
],
queryFn
:
getAreas
})
if
(
isLoading
)
{
return
<
span
>
Loading...
</
span
>
}
if
(
isError
)
{
return
<
span
>
Error:
{
error
.
message
}
</
span
>
}
return
(
return
(
<
section
className=
"container"
>
<
section
className=
"container"
>
<
h1
className=
"text-green-400 text-2xl"
>
Bem vindo, João da Silva,
</
h1
>
<
h1
className=
"text-green-400 text-2xl"
>
Bem vindo, João da Silva,
</
h1
>
...
@@ -55,13 +74,13 @@ export default function Admin() {
...
@@ -55,13 +74,13 @@ export default function Admin() {
<
nav
className=
"my-6"
>
<
nav
className=
"my-6"
>
<
ul
className=
"space-y-4"
>
<
ul
className=
"space-y-4"
>
{
areas
.
map
((
area
)
=>
(
{
areas
?.
data
.
map
((
area
)
=>
(
<
li
key=
{
area
.
title
}
className=
"border-b border-green-400"
>
<
li
key=
{
area
.
id
}
className=
"border-b border-green-400"
>
<
Link
<
Link
href=
{
`/admin/area/${area.id}`
}
href=
{
`/admin/area/${area.id}`
}
className=
"flex justify-between py-2 hover:bg-green-400/10"
className=
"flex justify-between py-2 hover:bg-green-400/10"
>
>
<
span
>
{
area
.
titl
e
}
</
span
>
<
span
>
{
area
.
nam
e
}
</
span
>
<
Pencil
className=
"text-green-400"
/>
<
Pencil
className=
"text-green-400"
/>
</
Link
>
</
Link
>
</
li
>
</
li
>
...
...
src/app/layout.tsx
View file @
4f7e1d0b
...
@@ -5,6 +5,9 @@ import '@/styles/globals.css'
...
@@ -5,6 +5,9 @@ import '@/styles/globals.css'
import
{
StyledEngineProvider
}
from
'@mui/material'
import
{
StyledEngineProvider
}
from
'@mui/material'
import
type
{
Metadata
}
from
'next'
import
type
{
Metadata
}
from
'next'
import
{
Poppins
}
from
'next/font/google'
import
{
Poppins
}
from
'next/font/google'
import
{
Toaster
}
from
'sonner'
import
ReactQueryProvider
from
'@/providers/react-query'
const
poppins
=
Poppins
({
subsets
:
[
'latin'
],
weight
:
[
'300'
,
'400'
,
'800'
]
})
const
poppins
=
Poppins
({
subsets
:
[
'latin'
],
weight
:
[
'300'
,
'400'
,
'800'
]
})
...
@@ -28,9 +31,12 @@ export default function RootLayout({
...
@@ -28,9 +31,12 @@ export default function RootLayout({
disableTransitionOnChange
disableTransitionOnChange
>
>
<
StyledEngineProvider
injectFirst
>
<
StyledEngineProvider
injectFirst
>
<
ReactQueryProvider
>
<
Toaster
richColors
/>
<
Header
/>
<
Header
/>
{
children
}
{
children
}
<
Footer
/>
<
Footer
/>
</
ReactQueryProvider
>
</
StyledEngineProvider
>
</
StyledEngineProvider
>
</
ThemeProvider
>
</
ThemeProvider
>
</
body
>
</
body
>
...
...
src/components/breadcrumb-component.tsx
0 → 100644
View file @
4f7e1d0b
import
{
Breadcrumb
,
BreadcrumbItem
,
BreadcrumbLink
,
BreadcrumbList
,
BreadcrumbPage
,
BreadcrumbSeparator
,
}
from
"@/components/ui/breadcrumb"
import
Link
from
"next/link"
export
default
function
BreadcrumbComponent
()
{
return
(
<
Breadcrumb
>
<
BreadcrumbList
>
<
BreadcrumbItem
>
<
BreadcrumbLink
asChild
>
<
Link
href=
"/admin"
>
Admin
</
Link
>
</
BreadcrumbLink
>
</
BreadcrumbItem
>
<
BreadcrumbSeparator
/>
<
BreadcrumbItem
>
<
BreadcrumbPage
>
Área
</
BreadcrumbPage
>
</
BreadcrumbItem
>
</
BreadcrumbList
>
</
Breadcrumb
>
)
}
src/components/input-file.tsx
0 → 100644
View file @
4f7e1d0b
import
{
forwardRef
}
from
'react'
interface
InputFileProps
extends
React
.
InputHTMLAttributes
<
HTMLInputElement
>
{
id
:
string
values
?:
string
label
:
string
}
const
InputFile
=
forwardRef
<
HTMLInputElement
,
InputFileProps
>
(
({
id
,
values
,
label
,
...
inputProps
},
ref
)
=>
{
return
(
<
label
htmlFor=
{
id
}
className=
"flex justify-center items-center border border-dotted rounded-sm border-green-400 bg-green-400/10 cursor-pointer hover:bg-green-400/5 text-green-400 text-sm h-10 mt-6"
>
{
values
||
label
}
<
input
id=
{
id
}
type=
"file"
className=
"hidden"
ref=
{
ref
}
{
...
inputProps
}
/>
</
label
>
)
},
)
InputFile
.
displayName
=
'InputFile'
export
default
InputFile
src/components/modal-dialog.tsx
0 → 100644
View file @
4f7e1d0b
import
{
AlertDialogAction
,
AlertDialogCancel
,
AlertDialogContent
,
AlertDialogDescription
,
AlertDialogFooter
,
AlertDialogHeader
,
AlertDialogTitle
,
}
from
'./ui/alert-dialog'
type
AlertDialogProps
=
{
title
:
string
description
:
string
handleClick
:
()
=>
void
}
export
default
function
ModalDialog
({
title
,
description
,
handleClick
,
}:
AlertDialogProps
)
{
return
(
<
AlertDialogContent
>
<
AlertDialogHeader
>
<
AlertDialogTitle
>
{
title
}
</
AlertDialogTitle
>
<
AlertDialogDescription
>
{
description
}
</
AlertDialogDescription
>
</
AlertDialogHeader
>
<
AlertDialogFooter
>
<
AlertDialogCancel
>
Cancelar
</
AlertDialogCancel
>
<
AlertDialogAction
onClick=
{
handleClick
}
>
Continue
</
AlertDialogAction
>
</
AlertDialogFooter
>
</
AlertDialogContent
>
)
}
src/components/ui/alert-dialog.tsx
0 → 100644
View file @
4f7e1d0b
"use client"
import
*
as
React
from
"react"
import
*
as
AlertDialogPrimitive
from
"@radix-ui/react-alert-dialog"
import
{
cn
}
from
"@/lib/utils"
import
{
buttonVariants
}
from
"@/components/ui/button"
const
AlertDialog
=
AlertDialogPrimitive
.
Root
const
AlertDialogTrigger
=
AlertDialogPrimitive
.
Trigger
const
AlertDialogPortal
=
AlertDialogPrimitive
.
Portal
const
AlertDialogOverlay
=
React
.
forwardRef
<
React
.
ElementRef
<
typeof
AlertDialogPrimitive
.
Overlay
>
,
React
.
ComponentPropsWithoutRef
<
typeof
AlertDialogPrimitive
.
Overlay
>
>
(({
className
,
...
props
},
ref
)
=>
(
<
AlertDialogPrimitive
.
Overlay
className=
{
cn
(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
,
className
)
}
{
...
props
}
ref=
{
ref
}
/>
))
AlertDialogOverlay
.
displayName
=
AlertDialogPrimitive
.
Overlay
.
displayName
const
AlertDialogContent
=
React
.
forwardRef
<
React
.
ElementRef
<
typeof
AlertDialogPrimitive
.
Content
>
,
React
.
ComponentPropsWithoutRef
<
typeof
AlertDialogPrimitive
.
Content
>
>
(({
className
,
...
props
},
ref
)
=>
(
<
AlertDialogPortal
>
<
AlertDialogOverlay
/>
<
AlertDialogPrimitive
.
Content
ref=
{
ref
}
className=
{
cn
(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg"
,
className
)
}
{
...
props
}
/>
</
AlertDialogPortal
>
))
AlertDialogContent
.
displayName
=
AlertDialogPrimitive
.
Content
.
displayName
const
AlertDialogHeader
=
({
className
,
...
props
}:
React
.
HTMLAttributes
<
HTMLDivElement
>
)
=>
(
<
div
className=
{
cn
(
"flex flex-col space-y-2 text-center sm:text-left"
,
className
)
}
{
...
props
}
/>
)
AlertDialogHeader
.
displayName
=
"AlertDialogHeader"
const
AlertDialogFooter
=
({
className
,
...
props
}:
React
.
HTMLAttributes
<
HTMLDivElement
>
)
=>
(
<
div
className=
{
cn
(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2"
,
className
)
}
{
...
props
}
/>
)
AlertDialogFooter
.
displayName
=
"AlertDialogFooter"
const
AlertDialogTitle
=
React
.
forwardRef
<
React
.
ElementRef
<
typeof
AlertDialogPrimitive
.
Title
>
,
React
.
ComponentPropsWithoutRef
<
typeof
AlertDialogPrimitive
.
Title
>
>
(({
className
,
...
props
},
ref
)
=>
(
<
AlertDialogPrimitive
.
Title
ref=
{
ref
}
className=
{
cn
(
"text-lg font-semibold"
,
className
)
}
{
...
props
}
/>
))
AlertDialogTitle
.
displayName
=
AlertDialogPrimitive
.
Title
.
displayName
const
AlertDialogDescription
=
React
.
forwardRef
<
React
.
ElementRef
<
typeof
AlertDialogPrimitive
.
Description
>
,
React
.
ComponentPropsWithoutRef
<
typeof
AlertDialogPrimitive
.
Description
>
>
(({
className
,
...
props
},
ref
)
=>
(
<
AlertDialogPrimitive
.
Description
ref=
{
ref
}
className=
{
cn
(
"text-sm text-muted-foreground"
,
className
)
}
{
...
props
}
/>
))
AlertDialogDescription
.
displayName
=
AlertDialogPrimitive
.
Description
.
displayName
const
AlertDialogAction
=
React
.
forwardRef
<
React
.
ElementRef
<
typeof
AlertDialogPrimitive
.
Action
>
,
React
.
ComponentPropsWithoutRef
<
typeof
AlertDialogPrimitive
.
Action
>
>
(({
className
,
...
props
},
ref
)
=>
(
<
AlertDialogPrimitive
.
Action
ref=
{
ref
}
className=
{
cn
(
buttonVariants
(),
className
)
}
{
...
props
}
/>
))
AlertDialogAction
.
displayName
=
AlertDialogPrimitive
.
Action
.
displayName
const
AlertDialogCancel
=
React
.
forwardRef
<
React
.
ElementRef
<
typeof
AlertDialogPrimitive
.
Cancel
>
,
React
.
ComponentPropsWithoutRef
<
typeof
AlertDialogPrimitive
.
Cancel
>
>
(({
className
,
...
props
},
ref
)
=>
(
<
AlertDialogPrimitive
.
Cancel
ref=
{
ref
}
className=
{
cn
(
buttonVariants
({
variant
:
"outline"
}),
"mt-2 sm:mt-0"
,
className
)
}
{
...
props
}
/>
))
AlertDialogCancel
.
displayName
=
AlertDialogPrimitive
.
Cancel
.
displayName
export
{
AlertDialog
,
AlertDialogPortal
,
AlertDialogOverlay
,
AlertDialogTrigger
,
AlertDialogContent
,
AlertDialogHeader
,
AlertDialogFooter
,
AlertDialogTitle
,
AlertDialogDescription
,
AlertDialogAction
,
AlertDialogCancel
,
}
src/components/ui/breadcrumb.tsx
0 → 100644
View file @
4f7e1d0b
import
*
as
React
from
"react"
import
{
Slot
}
from
"@radix-ui/react-slot"
import
{
ChevronRight
,
MoreHorizontal
}
from
"lucide-react"
import
{
cn
}
from
"@/lib/utils"
const
Breadcrumb
=
React
.
forwardRef
<
HTMLElement
,
React
.
ComponentPropsWithoutRef
<
"nav"
>
&
{
separator
?:
React
.
ReactNode
}
>
(({
...
props
},
ref
)
=>
<
nav
ref=
{
ref
}
aria
-
label=
"breadcrumb"
{
...
props
}
/>)
Breadcrumb
.
displayName
=
"Breadcrumb"
const
BreadcrumbList
=
React
.
forwardRef
<
HTMLOListElement
,
React
.
ComponentPropsWithoutRef
<
"ol"
>
>
(({
className
,
...
props
},
ref
)
=>
(
<
ol
ref=
{
ref
}
className=
{
cn
(
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5"
,
className
)
}
{
...
props
}
/>
))
BreadcrumbList
.
displayName
=
"BreadcrumbList"
const
BreadcrumbItem
=
React
.
forwardRef
<
HTMLLIElement
,
React
.
ComponentPropsWithoutRef
<
"li"
>
>
(({
className
,
...
props
},
ref
)
=>
(
<
li
ref=
{
ref
}
className=
{
cn
(
"inline-flex items-center gap-1.5"
,
className
)
}
{
...
props
}
/>
))
BreadcrumbItem
.
displayName
=
"BreadcrumbItem"
const
BreadcrumbLink
=
React
.
forwardRef
<
HTMLAnchorElement
,
React
.
ComponentPropsWithoutRef
<
"a"
>
&
{
asChild
?:
boolean
}
>
(({
asChild
,
className
,
...
props
},
ref
)
=>
{
const
Comp
=
asChild
?
Slot
:
"a"
return
(
<
Comp
ref=
{
ref
}
className=
{
cn
(
"transition-colors hover:text-foreground"
,
className
)
}
{
...
props
}
/>
)
})
BreadcrumbLink
.
displayName
=
"BreadcrumbLink"
const
BreadcrumbPage
=
React
.
forwardRef
<
HTMLSpanElement
,
React
.
ComponentPropsWithoutRef
<
"span"
>
>
(({
className
,
...
props
},
ref
)
=>
(
<
span
ref=
{
ref
}
role=
"link"
aria
-
disabled=
"true"
aria
-
current=
"page"
className=
{
cn
(
"font-normal text-foreground"
,
className
)
}
{
...
props
}
/>
))
BreadcrumbPage
.
displayName
=
"BreadcrumbPage"
const
BreadcrumbSeparator
=
({
children
,
className
,
...
props
}:
React
.
ComponentProps
<
"li"
>
)
=>
(
<
li
role=
"presentation"
aria
-
hidden=
"true"
className=
{
cn
(
"[&>svg]:size-3.5"
,
className
)
}
{
...
props
}
>
{
children
??
<
ChevronRight
/>
}
</
li
>
)
BreadcrumbSeparator
.
displayName
=
"BreadcrumbSeparator"
const
BreadcrumbEllipsis
=
({
className
,
...
props
}:
React
.
ComponentProps
<
"span"
>
)
=>
(
<
span
role=
"presentation"
aria
-
hidden=
"true"
className=
{
cn
(
"flex h-9 w-9 items-center justify-center"
,
className
)
}
{
...
props
}
>
<
MoreHorizontal
className=
"h-4 w-4"
/>
<
span
className=
"sr-only"
>
More
</
span
>
</
span
>
)
BreadcrumbEllipsis
.
displayName
=
"BreadcrumbElipssis"
export
{
Breadcrumb
,
BreadcrumbList
,
BreadcrumbItem
,
BreadcrumbLink
,
BreadcrumbPage
,
BreadcrumbSeparator
,
BreadcrumbEllipsis
,
}
src/components/ui/input.tsx
View file @
4f7e1d0b
import
{
cva
,
VariantProps
}
from
'class-variance-authority'
import
*
as
React
from
'react'
import
*
as
React
from
'react'
import
{
cn
}
from
'@/lib/utils'
import
{
cn
}
from
'@/lib/utils'
const
inputVariants
=
cva
(
'inline-flex items-center justify-center whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-ring focus-visible:border-b-2 disabled:pointer-events-none disabled:opacity-50 focus-visible:outline-none disabled:cursor-not-allowed'
,
{
variants
:
{
variant
:
{
default
:
'flex h-10 w-full border border-t-0 border-x-0 border-gray-300 px-2 py-2 text-md text-white bg-transparent file:bg-transparent file:text-sm file:font-medium placeholder:text-gray-300'
,
secondary
:
'text-gray-50 bg-gradient-to-r from-purple-100 to-purple-200 hover:bg-purple-200 hover:opacity-75'
,
file
:
'border border-dotted rounded-sm border-green-400 bg-green-400/10 cursor-pointer hover:bg-green-400/5 text-green-400 text-sm h-10'
,
destructive
:
'bg-destructive text-destructive-foreground hover:bg-destructive/90'
,
outline
:
'border border-input bg-background hover:bg-accent hover:text-accent-foreground'
,
ghost
:
'dark:hover:bg-white/10 dark:hover:text-gray-50 hover:bg-gray-900/10'
,
link
:
'text-primary underline-offset-4 hover:underline'
,
},
},
defaultVariants
:
{
variant
:
'default'
,
},
},
)
export
interface
InputProps
export
interface
InputProps
extends
React
.
InputHTMLAttributes
<
HTMLInputElement
>
{}
extends
React
.
InputHTMLAttributes
<
HTMLInputElement
>
,
VariantProps
<
typeof
inputVariants
>
{
label
?:
string
}
const
Input
=
React
.
forwardRef
<
HTMLInputElement
,
InputProps
>
(
const
Input
=
React
.
forwardRef
<
HTMLInputElement
,
InputProps
>
(
({
className
,
type
,
...
props
},
ref
)
=>
{
({
className
,
variant
,
type
,
label
,
...
props
},
ref
)
=>
{
return
(
return
(
<
label
>
<
span
className=
"text-sm text-gray-400"
>
{
label
}
</
span
>
<
input
<
input
type=
{
type
}
type=
{
type
}
className=
{
cn
(
className=
{
cn
(
inputVariants
({
variant
,
className
}))
}
'flex h-10 w-full border border-t-0 border-x-0 border-gray-300 px-2 py-2 text-md text-white ile:border-0 bg-transparent file:bg-transparent file:text-sm file:font-medium placeholder:text-gray-300 focus-visible:outline-none focus-visible:border-b-white focus-visible:border-b-2 disabled:cursor-not-allowed disabled:opacity-50'
,
className
,
)
}
ref=
{
ref
}
ref=
{
ref
}
{
...
props
}
{
...
props
}
/>
/>
</
label
>
)
)
},
},
)
)
Input
.
displayName
=
'Input'
Input
.
displayName
=
'Input'
export
{
Input
}
export
{
Input
,
inputVariants
}
src/lib/axios.ts
View file @
4f7e1d0b
import
axios
from
'axios'
import
axios
from
'axios'
export
const
api
=
axios
.
create
({
export
const
api
=
axios
.
create
({
baseURL
:
'
/api
'
,
baseURL
:
'
http://localhost:3000
'
,
})
})
src/providers/react-query.tsx
0 → 100644
View file @
4f7e1d0b
'use client'
import
{
QueryClient
,
QueryClientProvider
}
from
'@tanstack/react-query'
import
{
ReactNode
}
from
'react'
type
ReactQueryProps
=
{
children
:
ReactNode
}
const
queryClient
=
new
QueryClient
({
defaultOptions
:
{
queries
:
{
refetchOnWindowFocus
:
false
,
},
},
})
export
default
function
ReactQueryProvider
({
children
}:
ReactQueryProps
)
{
return
(
<
QueryClientProvider
client=
{
queryClient
}
>
{
children
}
</
QueryClientProvider
>
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment