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
d389de98
Commit
d389de98
authored
Feb 01, 2025
by
Wellton Quirino
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add new modules and areas
parent
1e2e278b
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
541 additions
and
73 deletions
+541
-73
package-lock.json
package-lock.json
+39
-4
package.json
package.json
+3
-1
accounts.ts
src/api/accounts.ts
+17
-0
areas.ts
src/api/areas.ts
+9
-8
login.ts
src/api/login.ts
+20
-0
modules.ts
src/api/modules.ts
+38
-0
page.tsx
src/app/(home)/page.tsx
+7
-0
page.tsx
src/app/admin/area/page.tsx
+21
-4
page.tsx
src/app/admin/curso/[id]/page.tsx
+14
-0
form-modules.tsx
src/app/admin/curso/components/form-modules.tsx
+34
-0
page.tsx
src/app/admin/curso/page.tsx
+112
-24
page.tsx
src/app/admin/page.tsx
+10
-1
page.tsx
src/app/contato/page.tsx
+20
-2
layout.tsx
src/app/layout.tsx
+18
-15
page.tsx
src/app/login/page.tsx
+51
-8
input-file.tsx
src/components/input-file.tsx
+1
-0
inputs.tsx
src/components/mui/inputs.tsx
+11
-5
search-filter.tsx
src/components/search-filter.tsx
+5
-0
auth-context.tsx
src/contexts/auth-context.tsx
+77
-0
axios.ts
src/lib/axios.ts
+34
-1
No files found.
package-lock.json
View file @
d389de98
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
"dependencies"
:
{
"dependencies"
:
{
"@emotion/react"
:
"^11.13.0"
,
"@emotion/react"
:
"^11.13.0"
,
"@emotion/styled"
:
"^11.13.0"
,
"@emotion/styled"
:
"^11.13.0"
,
"@hookform/resolvers"
:
"^3.
9
.0"
,
"@hookform/resolvers"
:
"^3.
10
.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-alert-dialog"
:
"^1.1.2"
,
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
"lucide-react"
:
"^0.383.0"
,
"lucide-react"
:
"^0.383.0"
,
"next"
:
"14.2.3"
,
"next"
:
"14.2.3"
,
"next-themes"
:
"^0.3.0"
,
"next-themes"
:
"^0.3.0"
,
"nookies"
:
"^2.5.2"
,
"react"
:
"^18"
,
"react"
:
"^18"
,
"react-day-picker"
:
"^8.10.1"
,
"react-day-picker"
:
"^8.10.1"
,
"react-dom"
:
"^18"
,
"react-dom"
:
"^18"
,
...
@@ -44,6 +45,7 @@
...
@@ -44,6 +45,7 @@
},
},
"devDependencies"
:
{
"devDependencies"
:
{
"@rocketseat/eslint-config"
:
"^2.2.2"
,
"@rocketseat/eslint-config"
:
"^2.2.2"
,
"@types/cookie"
:
"^0.6.0"
,
"@types/node"
:
"^20"
,
"@types/node"
:
"^20"
,
"@types/react"
:
"^18"
,
"@types/react"
:
"^18"
,
"@types/react-dom"
:
"^18"
,
"@types/react-dom"
:
"^18"
,
...
@@ -543,9 +545,10 @@
...
@@ -543,9 +545,10 @@
"integrity"
:
"sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww=="
"integrity"
:
"sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww=="
},
},
"node_modules/@hookform/resolvers"
:
{
"node_modules/@hookform/resolvers"
:
{
"version"
:
"3.9.0"
,
"version"
:
"3.10.0"
,
"resolved"
:
"https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.0.tgz"
,
"resolved"
:
"https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.10.0.tgz"
,
"integrity"
:
"sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg=="
,
"integrity"
:
"sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag=="
,
"license"
:
"MIT"
,
"peerDependencies"
:
{
"peerDependencies"
:
{
"react-hook-form"
:
"^7.0.0"
"react-hook-form"
:
"^7.0.0"
}
}
...
@@ -2273,6 +2276,13 @@
...
@@ -2273,6 +2276,13 @@
"react"
:
"^18 || ^19"
"react"
:
"^18 || ^19"
}
}
},
},
"node_modules/@types/cookie"
:
{
"version"
:
"0.6.0"
,
"resolved"
:
"https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz"
,
"integrity"
:
"sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
,
"dev"
:
true
,
"license"
:
"MIT"
},
"node_modules/@types/json-schema"
:
{
"node_modules/@types/json-schema"
:
{
"version"
:
"7.0.15"
,
"version"
:
"7.0.15"
,
"resolved"
:
"https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
,
"resolved"
:
"https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
,
...
@@ -3162,6 +3172,15 @@
...
@@ -3162,6 +3172,15 @@
"resolved"
:
"https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz"
,
"resolved"
:
"https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz"
,
"integrity"
:
"sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
"integrity"
:
"sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
},
"node_modules/cookie"
:
{
"version"
:
"0.4.2"
,
"resolved"
:
"https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz"
,
"integrity"
:
"sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
,
"license"
:
"MIT"
,
"engines"
:
{
"node"
:
">= 0.6"
}
},
"node_modules/cosmiconfig"
:
{
"node_modules/cosmiconfig"
:
{
"version"
:
"7.1.0"
,
"version"
:
"7.1.0"
,
"resolved"
:
"https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz"
,
"resolved"
:
"https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz"
,
...
@@ -5571,6 +5590,16 @@
...
@@ -5571,6 +5590,16 @@
"node"
:
"^10 || ^12 || >=14"
"node"
:
"^10 || ^12 || >=14"
}
}
},
},
"node_modules/nookies"
:
{
"version"
:
"2.5.2"
,
"resolved"
:
"https://registry.npmjs.org/nookies/-/nookies-2.5.2.tgz"
,
"integrity"
:
"sha512-x0TRSaosAEonNKyCrShoUaJ5rrT5KHRNZ5DwPCuizjgrnkpE5DRf3VL7AyyQin4htict92X1EQ7ejDbaHDVdYA=="
,
"license"
:
"MIT"
,
"dependencies"
:
{
"cookie"
:
"^0.4.1"
,
"set-cookie-parser"
:
"^2.4.6"
}
},
"node_modules/normalize-path"
:
{
"node_modules/normalize-path"
:
{
"version"
:
"3.0.0"
,
"version"
:
"3.0.0"
,
"resolved"
:
"https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
,
"resolved"
:
"https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
,
...
@@ -6480,6 +6509,12 @@
...
@@ -6480,6 +6509,12 @@
"node"
:
">=10"
"node"
:
">=10"
}
}
},
},
"node_modules/set-cookie-parser"
:
{
"version"
:
"2.7.1"
,
"resolved"
:
"https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz"
,
"integrity"
:
"sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="
,
"license"
:
"MIT"
},
"node_modules/set-function-length"
:
{
"node_modules/set-function-length"
:
{
"version"
:
"1.2.2"
,
"version"
:
"1.2.2"
,
"resolved"
:
"https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz"
,
"resolved"
:
"https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz"
,
...
...
package.json
View file @
d389de98
...
@@ -11,7 +11,7 @@
...
@@ -11,7 +11,7 @@
"dependencies"
:
{
"dependencies"
:
{
"
@emotion/react
"
:
"
^11.13.0
"
,
"
@emotion/react
"
:
"
^11.13.0
"
,
"
@emotion/styled
"
:
"
^11.13.0
"
,
"
@emotion/styled
"
:
"
^11.13.0
"
,
"
@hookform/resolvers
"
:
"
^3.
9
.0
"
,
"
@hookform/resolvers
"
:
"
^3.
10
.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-alert-dialog
"
:
"
^1.1.2
"
,
...
@@ -33,6 +33,7 @@
...
@@ -33,6 +33,7 @@
"
lucide-react
"
:
"
^0.383.0
"
,
"
lucide-react
"
:
"
^0.383.0
"
,
"
next
"
:
"
14.2.3
"
,
"
next
"
:
"
14.2.3
"
,
"
next-themes
"
:
"
^0.3.0
"
,
"
next-themes
"
:
"
^0.3.0
"
,
"
nookies
"
:
"
^2.5.2
"
,
"
react
"
:
"
^18
"
,
"
react
"
:
"
^18
"
,
"
react-day-picker
"
:
"
^8.10.1
"
,
"
react-day-picker
"
:
"
^8.10.1
"
,
"
react-dom
"
:
"
^18
"
,
"
react-dom
"
:
"
^18
"
,
...
@@ -45,6 +46,7 @@
...
@@ -45,6 +46,7 @@
},
},
"devDependencies"
:
{
"devDependencies"
:
{
"
@rocketseat/eslint-config
"
:
"
^2.2.2
"
,
"
@rocketseat/eslint-config
"
:
"
^2.2.2
"
,
"
@types/cookie
"
:
"
^0.6.0
"
,
"
@types/node
"
:
"
^20
"
,
"
@types/node
"
:
"
^20
"
,
"
@types/react
"
:
"
^18
"
,
"
@types/react
"
:
"
^18
"
,
"
@types/react-dom
"
:
"
^18
"
,
"
@types/react-dom
"
:
"
^18
"
,
...
...
src/api/accounts.ts
0 → 100644
View file @
d389de98
import
{
api
}
from
'@/lib/axios'
export
type
AccountsProps
=
{
id
:
string
name
:
string
email
:
string
}
export
async
function
getAccounts
()
{
const
accounts
=
await
api
.
get
<
AccountsProps
[]
>
(
'/accounts'
)
return
accounts
}
export
async
function
getAccountsId
(
id
:
string
)
{
const
account
=
await
api
.
get
<
AccountsProps
>
(
`/accounts/
${
id
}
`
)
return
account
}
src/api/areas.ts
View file @
d389de98
import
{
api
}
from
'@/lib/axios'
import
{
api
}
from
'@/lib/axios'
interface
FileBanner
{
//
interface FileBanner {
name
:
string
//
name: string
}
//
}
export
type
AreasProps
=
{
export
type
AreasProps
=
{
id
:
string
id
?
:
string
name
:
string
name
:
string
desktopBanner
?:
{
[
key
:
string
]:
FileBanner
}
desktopBanner
:
string
mobileBanner
?:
{
[
key
:
string
]:
FileBanner
}
mobileBanner
:
string
// desktopBanner?: { [key: string]: FileBanner }
// mobileBanner?: { [key: string]: FileBanner }
}
}
export
async
function
createAreas
({
export
async
function
createAreas
({
...
@@ -47,8 +49,7 @@ export async function getAreasId(id: string) {
...
@@ -47,8 +49,7 @@ export async function getAreasId(id: string) {
return
area
return
area
}
}
export
async
function
deleteArea
(
id
:
string
)
{
export
async
function
deleteArea
(
id
:
string
)
{
const
area
=
await
api
.
delete
(
`/areas/
${
id
}
`
)
const
area
=
await
api
.
delete
(
`/areas/
${
id
}
`
)
return
area
return
area
}
}
\ No newline at end of file
src/api/login.ts
0 → 100644
View file @
d389de98
import
{
api
}
from
'@/lib/axios'
export
type
SignInProps
=
{
email
:
string
password
:
string
}
export
type
SignInResponse
=
{
access_token
:
string
user
:
{
id
:
string
name
:
string
email
:
string
}
}
export
async
function
login
(
data
:
SignInProps
)
{
const
token
=
await
api
.
post
<
SignInResponse
>
(
'/login'
,
data
)
return
token
}
src/api/modules.ts
0 → 100644
View file @
d389de98
import
{
api
}
from
'@/lib/axios'
export
type
ModulesProps
=
{
id
:
string
name
:
string
description
:
string
}
export
async
function
createModules
({
name
,
description
}:
ModulesProps
)
{
const
modules
=
await
api
.
post
<
ModulesProps
>
(
'/modules'
,
{
name
,
description
,
})
return
modules
}
export
async
function
editModule
({
id
,
name
,
description
}:
ModulesProps
)
{
const
modules
=
await
api
.
patch
<
ModulesProps
[]
>
(
`/modules/
${
id
}
`
,
{
name
,
description
,
})
return
modules
}
export
async
function
getModules
()
{
const
modules
=
await
api
.
get
<
ModulesProps
[]
>
(
'/modules'
)
return
modules
}
export
async
function
getModulesId
(
id
:
string
)
{
const
modules
=
await
api
.
get
<
ModulesProps
>
(
`/modules/
${
id
}
`
)
return
modules
}
export
async
function
deleteModule
(
id
:
string
)
{
const
modules
=
await
api
.
delete
(
`/modules/
${
id
}
`
)
return
modules
}
src/app/(home)/page.tsx
View file @
d389de98
'use client'
import
{
Search
}
from
'lucide-react'
import
{
Search
}
from
'lucide-react'
import
Link
from
'next/link'
import
Link
from
'next/link'
...
@@ -12,8 +14,11 @@ import { SignUp } from '@/components/sign-up'
...
@@ -12,8 +14,11 @@ import { SignUp } from '@/components/sign-up'
import
{
SkeletonSerachParams
}
from
'@/components/skeleton-serach-params'
import
{
SkeletonSerachParams
}
from
'@/components/skeleton-serach-params'
import
{
Button
}
from
'@/components/ui/button'
import
{
Button
}
from
'@/components/ui/button'
import
{
Suspense
}
from
'react'
import
{
Suspense
}
from
'react'
import
{
useForm
}
from
'react-hook-form'
export
default
function
Home
()
{
export
default
function
Home
()
{
const
{
register
}
=
useForm
()
return
(
return
(
<>
<>
<
div
className=
"absolute h-[200px] w-full bg-gradient-to-b from-gray-900 from-5% z-10"
/>
<
div
className=
"absolute h-[200px] w-full bg-gradient-to-b from-gray-900 from-5% z-10"
/>
...
@@ -31,6 +36,8 @@ export default function Home() {
...
@@ -31,6 +36,8 @@ export default function Home() {
type=
"text"
type=
"text"
className=
"w-full"
className=
"w-full"
themeColor=
"#fafafa"
themeColor=
"#fafafa"
name=
"learned-today"
register=
{
register
}
/>
/>
<
Search
size=
{
24
}
/>
<
Search
size=
{
24
}
/>
</
div
>
</
div
>
...
...
src/app/admin/area/page.tsx
View file @
d389de98
...
@@ -16,8 +16,8 @@ export default function Area() {
...
@@ -16,8 +16,8 @@ export default function Area() {
const
router
=
useRouter
()
const
router
=
useRouter
()
const
data
=
watch
()
const
data
=
watch
()
const
valueDesktopBanner
=
data
?.
desktopBanner
?.[
'0'
]?.
name
const
valueMobileBanner
=
data
?.
mobileBanner
?.[
'0'
]?.
name
const
valueMobileBanner
=
data
?.
mobileBanner
?.[
'0'
]?.
name
const
valueDesktopBanner
=
data
?.
desktopBanner
?.[
'0'
]?.
name
const
queryClient
=
useQueryClient
()
const
queryClient
=
useQueryClient
()
...
@@ -31,7 +31,24 @@ export default function Area() {
...
@@ -31,7 +31,24 @@ export default function Area() {
})
})
function
onSubmit
(
data
:
AreasProps
)
{
function
onSubmit
(
data
:
AreasProps
)
{
mutation
.
mutate
(
data
)
// console.log('🚀 ~ onSubmit ~ data:', data)
// const fileMobile = data.mobileBanner?.[0]
// const fileDesktop = data.desktopBanner?.[0]
// const formData = new FormData()
// formData.append('mobileBanner', fileMobile, fileMobile?.name)
// formData.append('desktopBanner', fileDesktop, fileDesktop?.name)
// console.log('🚀 ~ onSubmit ~ formData:', formData)
const
dataArea
=
{
...
data
,
mobileBanner
:
'/Users/wellton/Documents/www/sevenpro-frontend/public/images/banners/negocios-mobile.jpg'
,
desktopBanner
:
'/Users/wellton/Documents/www/sevenpro-frontend/public/images/banners/negocios.jpg'
,
}
console
.
log
(
'🚀 ~ onSubmit ~ data:'
,
dataArea
)
mutation
.
mutate
(
dataArea
)
}
}
return
(
return
(
...
@@ -58,7 +75,7 @@ export default function Area() {
...
@@ -58,7 +75,7 @@ export default function Area() {
<
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: 1512 x 300
</
span
>
<
span
className=
"mt-4"
>
Dimensões recomendadas: 1512 x 300
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
, .jpeg
</
span
>
<
InputFile
<
InputFile
id=
"desktopBanner"
id=
"desktopBanner"
...
@@ -70,7 +87,7 @@ export default function Area() {
...
@@ -70,7 +87,7 @@ export default function Area() {
<
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: 390 x 300
</
span
>
<
span
className=
"mt-4"
>
Dimensões recomendadas: 390 x 300
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
</
span
>
<
span
>
Formatos aceitos: .png, .jpg
, .jpeg
</
span
>
<
InputFile
<
InputFile
id=
"mobileBanner"
id=
"mobileBanner"
values=
{
valueMobileBanner
}
values=
{
valueMobileBanner
}
...
...
src/app/admin/curso/[id]/page.tsx
View file @
d389de98
...
@@ -16,6 +16,7 @@ import { MenuItem } from '@mui/material'
...
@@ -16,6 +16,7 @@ import { MenuItem } from '@mui/material'
import
{
format
}
from
'date-fns'
import
{
format
}
from
'date-fns'
import
{
CalendarIcon
,
PlusIcon
,
Trash
}
from
'lucide-react'
import
{
CalendarIcon
,
PlusIcon
,
Trash
}
from
'lucide-react'
import
{
useState
}
from
'react'
import
{
useState
}
from
'react'
import
{
useForm
}
from
'react-hook-form'
const
options
=
[
const
options
=
[
{
label
:
'The Godfather'
,
value
:
1
},
{
label
:
'The Godfather'
,
value
:
1
},
...
@@ -24,6 +25,7 @@ const options = [
...
@@ -24,6 +25,7 @@ const options = [
export
default
function
EditCourse
()
{
export
default
function
EditCourse
()
{
const
[
date
,
setDate
]
=
useState
<
Date
>
()
const
[
date
,
setDate
]
=
useState
<
Date
>
()
const
{
register
}
=
useForm
()
return
(
return
(
<
section
className=
"container py-10"
>
<
section
className=
"container py-10"
>
...
@@ -55,6 +57,8 @@ export default function EditCourse() {
...
@@ -55,6 +57,8 @@ export default function EditCourse() {
variant=
"standard"
variant=
"standard"
type=
"text"
type=
"text"
themeColor=
"#26AAA7"
themeColor=
"#26AAA7"
name=
"name-course"
register=
{
register
}
/>
/>
<
InputMui
<
InputMui
...
@@ -63,6 +67,8 @@ export default function EditCourse() {
...
@@ -63,6 +67,8 @@ export default function EditCourse() {
label=
"Área"
label=
"Área"
select
select
themeColor=
"#26AAA7"
themeColor=
"#26AAA7"
name=
"area"
register=
{
register
}
>
>
{
options
.
map
((
option
)
=>
(
{
options
.
map
((
option
)
=>
(
<
MenuItem
key=
{
option
.
value
}
value=
{
option
.
value
}
>
<
MenuItem
key=
{
option
.
value
}
value=
{
option
.
value
}
>
...
@@ -78,6 +84,8 @@ export default function EditCourse() {
...
@@ -78,6 +84,8 @@ export default function EditCourse() {
multiline
multiline
rows=
{
4
}
rows=
{
4
}
themeColor=
"#26AAA7"
themeColor=
"#26AAA7"
name=
"description-course"
register=
{
register
}
/>
/>
<
InputMui
<
InputMui
...
@@ -85,6 +93,8 @@ export default function EditCourse() {
...
@@ -85,6 +93,8 @@ export default function EditCourse() {
variant=
"standard"
variant=
"standard"
type=
"text"
type=
"text"
themeColor=
"#26AAA7"
themeColor=
"#26AAA7"
name=
"teachers"
register=
{
register
}
/>
/>
<
div
className=
"flex justify-between flex-wrap gap-6"
>
<
div
className=
"flex justify-between flex-wrap gap-6"
>
...
@@ -207,6 +217,8 @@ export default function EditCourse() {
...
@@ -207,6 +217,8 @@ export default function EditCourse() {
variant=
"standard"
variant=
"standard"
type=
"text"
type=
"text"
themeColor=
"#26AAA7"
themeColor=
"#26AAA7"
name=
"title"
register=
{
register
}
/>
/>
<
InputMui
<
InputMui
...
@@ -216,6 +228,8 @@ export default function EditCourse() {
...
@@ -216,6 +228,8 @@ export default function EditCourse() {
multiline
multiline
rows=
{
4
}
rows=
{
4
}
themeColor=
"#26AAA7"
themeColor=
"#26AAA7"
name=
"description"
register=
{
register
}
/>
/>
</
div
>
</
div
>
...
...
src/app/admin/curso/components/form-modules.tsx
0 → 100644
View file @
d389de98
import
{
StyledInputs
}
from
'@/components/mui/styled-inputs'
import
{
TextField
}
from
'@mui/material'
import
{
useForm
}
from
'react-hook-form'
type
FormModulesProps
=
{
index
?:
number
remove
?:
(
index
:
number
|
number
[])
=>
void
}
export
function
FormNewModules
({
index
,
remove
}:
FormModulesProps
)
{
const
{
register
}
=
useForm
()
return
(
<
div
className=
"flex flex-col p-4 gap-6 border border-gray-100"
>
<
TextField
label=
"Título"
variant=
"standard"
type=
"text"
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
{
...
register
(`
newModule
.
$
{
index
}
.
name
`)}
/>
<
TextField
label=
"Descrição"
variant=
"standard"
type=
"text"
multiline
rows=
{
4
}
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
{
...
register
(`
newModule
.
$
{
index
}
.
description
`)}
/>
</
div
>
)
}
src/app/admin/curso/page.tsx
View file @
d389de98
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
import
{
getAreas
}
from
'@/api/areas'
import
{
getAreas
}
from
'@/api/areas'
import
{
getAudiences
}
from
'@/api/audiences'
import
{
getAudiences
}
from
'@/api/audiences'
import
{
getCategories
}
from
'@/api/categories'
import
{
getCategories
}
from
'@/api/categories'
import
{
createModules
,
getModules
,
ModulesProps
}
from
'@/api/modules'
import
InputFile
from
'@/components/input-file'
import
InputFile
from
'@/components/input-file'
import
{
LoadingSpinIcon
}
from
'@/components/loading-spin-icon'
import
{
LoadingSpinIcon
}
from
'@/components/loading-spin-icon'
import
{
StyledInputs
}
from
'@/components/mui/styled-inputs'
import
{
StyledInputs
}
from
'@/components/mui/styled-inputs'
...
@@ -25,12 +26,14 @@ import {
...
@@ -25,12 +26,14 @@ import {
import
{
RadioGroup
,
RadioGroupItem
}
from
'@/components/ui/radio-group'
import
{
RadioGroup
,
RadioGroupItem
}
from
'@/components/ui/radio-group'
import
{
Separator
}
from
'@/components/ui/separator'
import
{
Separator
}
from
'@/components/ui/separator'
import
{
cn
}
from
'@/lib/utils'
import
{
cn
}
from
'@/lib/utils'
import
{
zodResolver
}
from
'@hookform/resolvers/zod'
import
{
Box
,
Chip
,
MenuItem
,
TextField
}
from
'@mui/material'
import
{
Box
,
Chip
,
MenuItem
,
TextField
}
from
'@mui/material'
import
{
use
Query
}
from
'@tanstack/react-query'
import
{
use
Mutation
,
useQuery
,
useQueryClient
}
from
'@tanstack/react-query'
import
{
format
}
from
'date-fns'
import
{
format
}
from
'date-fns'
import
{
CalendarIcon
,
PlusIcon
}
from
'lucide-react'
import
{
CalendarIcon
,
PlusIcon
,
Trash2
}
from
'lucide-react'
import
{
useState
}
from
'react'
import
{
useState
}
from
'react'
import
{
Controller
,
useForm
}
from
'react-hook-form'
import
{
Controller
,
useForm
}
from
'react-hook-form'
import
{
toast
}
from
'sonner'
import
{
z
}
from
'zod'
import
{
z
}
from
'zod'
// type CoursesProps = {
// type CoursesProps = {
...
@@ -50,8 +53,8 @@ import { z } from 'zod'
...
@@ -50,8 +53,8 @@ import { z } from 'zod'
// }
// }
const
FormSchema
=
z
.
object
({
const
FormSchema
=
z
.
object
({
name
:
z
.
string
(),
name
:
z
.
string
()
.
trim
().
min
(
3
,
{
message
:
'Título obrigatório'
})
,
description
:
z
.
string
(),
description
:
z
.
string
()
.
trim
().
min
(
3
,
{
message
:
'Descrição obrigatória'
})
,
desktopBanner
:
z
.
string
(),
desktopBanner
:
z
.
string
(),
mobileBanner
:
z
.
string
(),
mobileBanner
:
z
.
string
(),
duration
:
z
.
number
(),
duration
:
z
.
number
(),
...
@@ -70,15 +73,18 @@ export default function Curso() {
...
@@ -70,15 +73,18 @@ export default function Curso() {
const
[
checkedEnd
,
setCheckedEnd
]
=
useState
<
boolean
>
(
false
)
const
[
checkedEnd
,
setCheckedEnd
]
=
useState
<
boolean
>
(
false
)
const
[
dateStart
,
setDateStart
]
=
useState
<
Date
>
()
const
[
dateStart
,
setDateStart
]
=
useState
<
Date
>
()
const
[
dateEnd
,
setDateEnd
]
=
useState
<
Date
>
()
const
[
dateEnd
,
setDateEnd
]
=
useState
<
Date
>
()
const
[
inputValue
,
setInputValue
]
=
useState
<
string
>
(
''
)
const
[
inputValue
,
setInputValue
]
=
useState
<
string
>
(
''
)
const
queryClient
=
useQueryClient
()
// const { form.register, watch, handleSubmit, control } = useForm<CoursesProps>()
// const { form.register, watch, handleSubmit, control } = useForm<CoursesProps>()
const
{
register
,
handleSubmit
,
reset
}
=
useForm
<
ModulesProps
>
()
const
form
=
useForm
<
z
.
infer
<
typeof
FormSchema
>>
({
const
form
=
useForm
<
z
.
infer
<
typeof
FormSchema
>>
({
//
resolver: zodResolver(FormSchema),
resolver
:
zodResolver
(
FormSchema
),
defaultValues
:
{
defaultValues
:
{
areaId
:
''
,
areaId
:
''
,
professors
:
[],
professors
:
[],
moduleIds
:
[],
},
},
})
})
const
values
=
form
.
watch
()
const
values
=
form
.
watch
()
...
@@ -90,6 +96,11 @@ export default function Curso() {
...
@@ -90,6 +96,11 @@ export default function Curso() {
queryFn
:
getAreas
,
queryFn
:
getAreas
,
})
})
const
{
data
:
modules
}
=
useQuery
({
queryKey
:
[
'modules'
],
queryFn
:
getModules
,
})
const
{
data
:
audiences
,
isLoading
:
audiencesLoading
}
=
useQuery
({
const
{
data
:
audiences
,
isLoading
:
audiencesLoading
}
=
useQuery
({
queryKey
:
[
'audiences'
],
queryKey
:
[
'audiences'
],
queryFn
:
getAudiences
,
queryFn
:
getAudiences
,
...
@@ -100,15 +111,6 @@ export default function Curso() {
...
@@ -100,15 +111,6 @@ export default function Curso() {
queryFn
:
getCategories
,
queryFn
:
getCategories
,
})
})
function
onSubmit
(
data
:
z
.
infer
<
typeof
FormSchema
>
)
{
const
body
=
{
...
data
,
startDate
:
dateStart
?.
toLocaleDateString
()
||
''
,
endDate
:
dateEnd
?.
toLocaleDateString
()
||
''
,
}
console
.
log
(
body
)
}
function
onCheckedStart
(
checkedStart
:
boolean
)
{
function
onCheckedStart
(
checkedStart
:
boolean
)
{
setCheckedStart
(
checkedStart
)
setCheckedStart
(
checkedStart
)
}
}
...
@@ -132,6 +134,55 @@ export default function Curso() {
...
@@ -132,6 +134,55 @@ export default function Curso() {
)
)
}
}
const
mutation
=
useMutation
({
mutationFn
:
createModules
,
onSuccess
:
()
=>
{
toast
.
success
(
'Módulo criado com sucesso!'
)
queryClient
.
invalidateQueries
({
queryKey
:
[
'modules'
]
})
},
})
async
function
addNewModuler
(
data
:
ModulesProps
)
{
const
response
=
await
mutation
.
mutateAsync
(
data
)
const
responseModuleId
=
response
.
data
.
id
form
.
setValue
(
'moduleIds'
,
[...
selectedIds
,
responseModuleId
])
reset
()
}
const
selectedIds
=
form
.
watch
(
'moduleIds'
)
||
[]
const
selectedModules
=
modules
?.
data
.
filter
((
module
)
=>
selectedIds
.
includes
(
module
.
id
),
)
const
handleSelect
=
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
selectedId
=
event
.
target
.
value
if
(
selectedId
&&
!
selectedIds
.
includes
(
selectedId
))
{
form
.
setValue
(
'moduleIds'
,
[...
selectedIds
,
selectedId
])
}
}
const
handleDeleteModule
=
(
idToRemove
:
string
)
=>
{
form
.
setValue
(
'moduleIds'
,
selectedIds
.
filter
((
id
)
=>
id
!==
idToRemove
),
)
}
function
onSubmit
(
data
:
z
.
infer
<
typeof
FormSchema
>
)
{
const
body
=
{
...
data
,
startDate
:
dateStart
?.
toLocaleDateString
()
||
''
,
endDate
:
dateEnd
?.
toLocaleDateString
()
||
''
,
}
console
.
log
(
body
)
}
console
.
log
(
'error: '
,
form
.
formState
.
errors
)
return
(
return
(
<
section
className=
"container py-10"
>
<
section
className=
"container py-10"
>
<
Form
{
...
form
}
>
<
Form
{
...
form
}
>
...
@@ -155,6 +206,9 @@ export default function Curso() {
...
@@ -155,6 +206,9 @@ export default function Curso() {
{
...
form
.
register
('
name
')}
{
...
form
.
register
('
name
')}
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
/>
/>
{
form
.
formState
.
errors
.
name
&&
(
<
p
>
{
form
.
formState
.
errors
.
name
.
message
}
</
p
>
)
}
<
TextField
<
TextField
type=
"text"
type=
"text"
...
@@ -185,14 +239,6 @@ export default function Curso() {
...
@@ -185,14 +239,6 @@ export default function Curso() {
{
...
form
.
register
('
description
')}
{
...
form
.
register
('
description
')}
/>
/>
{
/* <TextField
label="Nome dos(as) Professores(as):"
variant="standard"
type="text"
sx={StyledInputs({ color: '#26AAA7' })}
{...form.register('professors')}
/> */
}
<
Controller
<
Controller
control=
{
form
.
control
}
control=
{
form
.
control
}
name=
"professors"
name=
"professors"
...
@@ -274,6 +320,7 @@ export default function Curso() {
...
@@ -274,6 +320,7 @@ export default function Curso() {
<
PopoverTrigger
asChild
>
<
PopoverTrigger
asChild
>
<
Button
<
Button
variant=
{
'ghost'
}
variant=
{
'ghost'
}
type=
"button"
className=
{
cn
(
className=
{
cn
(
'lg:w-[450px] justify-start text-left font-normal border-b rounded-none pl-0 border-green-400'
,
'lg:w-[450px] justify-start text-left font-normal border-b rounded-none pl-0 border-green-400'
,
!
dateStart
&&
'text-muted-foreground'
,
!
dateStart
&&
'text-muted-foreground'
,
...
@@ -293,6 +340,7 @@ export default function Curso() {
...
@@ -293,6 +340,7 @@ export default function Curso() {
selected=
{
dateStart
}
selected=
{
dateStart
}
onSelect=
{
setDateStart
}
onSelect=
{
setDateStart
}
initialFocus
initialFocus
{
...
form
.
register
('
startDate
')}
/>
/>
</
PopoverContent
>
</
PopoverContent
>
</
Popover
>
</
Popover
>
...
@@ -316,6 +364,7 @@ export default function Curso() {
...
@@ -316,6 +364,7 @@ export default function Curso() {
<
PopoverTrigger
asChild
>
<
PopoverTrigger
asChild
>
<
Button
<
Button
variant=
{
'ghost'
}
variant=
{
'ghost'
}
type=
"button"
className=
{
cn
(
className=
{
cn
(
'lg:w-[450px] justify-start text-left font-normal border-b rounded-none pl-0 border-green-400'
,
'lg:w-[450px] justify-start text-left font-normal border-b rounded-none pl-0 border-green-400'
,
!
dateEnd
&&
'text-muted-foreground'
,
!
dateEnd
&&
'text-muted-foreground'
,
...
@@ -348,12 +397,47 @@ export default function Curso() {
...
@@ -348,12 +397,47 @@ export default function Curso() {
<
h6
className=
"text-xl text-purple-100 mb-4"
>
Módulos
</
h6
>
<
h6
className=
"text-xl text-purple-100 mb-4"
>
Módulos
</
h6
>
<
TextField
type=
"text"
variant=
"standard"
label=
"Selecione os módulos do curso"
select
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
defaultValue=
{
''
}
value=
""
onChange=
{
handleSelect
}
// {...form.register('moduleIds')}
>
<
MenuItem
value=
""
className=
"hidden"
>
Selecione os módulos
</
MenuItem
>
{
modules
?.
data
.
map
((
option
)
=>
(
<
MenuItem
key=
{
option
.
id
}
value=
{
option
.
id
}
>
{
option
.
name
}
</
MenuItem
>
))
}
</
TextField
>
{
selectedModules
?.
map
((
item
)
=>
(
<
div
key=
{
item
.
id
}
className=
"w-full flex justify-between bg-green-800/30 py-2 px-4 rounded-sm"
>
<
p
>
{
item
.
name
}
</
p
>
<
Trash2
className=
"cursor-pointer text-red-400 hover:text-red-100"
onClick=
{
()
=>
handleDeleteModule
(
item
.
id
)
}
/>
</
div
>
))
}
<
div
className=
"flex flex-col p-4 gap-6 border border-gray-100"
>
<
div
className=
"flex flex-col p-4 gap-6 border border-gray-100"
>
<
TextField
<
TextField
label=
"Título"
label=
"Título"
variant=
"standard"
variant=
"standard"
type=
"text"
type=
"text"
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
{
...
register
('
name
')}
/>
/>
<
TextField
<
TextField
...
@@ -363,16 +447,20 @@ export default function Curso() {
...
@@ -363,16 +447,20 @@ export default function Curso() {
multiline
multiline
rows=
{
4
}
rows=
{
4
}
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
sx=
{
StyledInputs
({
color
:
'#26AAA7'
})
}
{
...
register
('
description
')}
/>
/>
</
div
>
</
div
>
<
Button
<
Button
variant=
"third"
variant=
"third"
type=
"button"
className=
"uppercase w-52 flex items-center gap-2 !mt-8"
className=
"uppercase w-52 flex items-center gap-2 !mt-8"
onClick=
{
handleSubmit
(
addNewModuler
)
}
>
>
<
PlusIcon
size=
{
20
}
/>
<
span
>
Adicionar
Módulo
</
span
>
<
PlusIcon
size=
{
20
}
/>
<
span
>
Criar novo
Módulo
</
span
>
</
Button
>
</
Button
>
</
div
>
</
div
>
<
div
className=
"w-[380px] pl-6 flex flex-col gap-4"
>
<
div
className=
"w-[380px] pl-6 flex flex-col gap-4"
>
<
h6
className=
"text-xl text-purple-100 mb-4"
>
<
h6
className=
"text-xl text-purple-100 mb-4"
>
Qual o público alvo?
Qual o público alvo?
...
...
src/app/admin/page.tsx
View file @
d389de98
...
@@ -4,10 +4,13 @@ import { getAreas } from '@/api/areas'
...
@@ -4,10 +4,13 @@ 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
{
AuthContext
}
from
'@/contexts/auth-context'
import
{
CoursesCard
}
from
'@/utils/courses-array'
import
{
CoursesCard
}
from
'@/utils/courses-array'
import
{
useQuery
}
from
'@tanstack/react-query'
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'
import
{
useContext
}
from
'react'
import
{
useForm
}
from
'react-hook-form'
// const areas = [
// const areas = [
// {
// {
...
@@ -46,6 +49,10 @@ const banners = [
...
@@ -46,6 +49,10 @@ const banners = [
]
]
export
default
function
Admin
()
{
export
default
function
Admin
()
{
const
{
register
}
=
useForm
()
const
{
user
}
=
useContext
(
AuthContext
)
console
.
log
(
'🚀 ~ Admin ~ user:'
,
user
)
const
{
const
{
data
:
areas
,
data
:
areas
,
error
,
error
,
...
@@ -63,7 +70,7 @@ export default function Admin() {
...
@@ -63,7 +70,7 @@ export default function Admin() {
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,
{
user
?.
name
}
!
</
h1
>
<
div
className=
"flex h-auto mb-20"
>
<
div
className=
"flex h-auto mb-20"
>
<
aside
className=
"mt-10 w-[348px]"
>
<
aside
className=
"mt-10 w-[348px]"
>
<
h2
className=
"text-purple-50 text-2xl"
>
Áreas
</
h2
>
<
h2
className=
"text-purple-50 text-2xl"
>
Áreas
</
h2
>
...
@@ -116,6 +123,8 @@ export default function Admin() {
...
@@ -116,6 +123,8 @@ export default function Admin() {
variant=
"standard"
variant=
"standard"
className=
"w-full"
className=
"w-full"
themeColor=
"#fafafa"
themeColor=
"#fafafa"
name=
"search"
register=
{
register
}
/>
/>
<
Search
size=
{
24
}
className=
"-ml-6"
/>
<
Search
size=
{
24
}
className=
"-ml-6"
/>
</
div
>
</
div
>
...
...
src/app/contato/page.tsx
View file @
d389de98
...
@@ -2,6 +2,7 @@ import { InputMui } from '@/components/mui/inputs'
...
@@ -2,6 +2,7 @@ import { InputMui } from '@/components/mui/inputs'
import
{
Button
}
from
'@/components/ui/button'
import
{
Button
}
from
'@/components/ui/button'
import
{
MenuItem
}
from
'@mui/material'
import
{
MenuItem
}
from
'@mui/material'
import
{
Clock4
,
Mail
,
Smartphone
}
from
'lucide-react'
import
{
Clock4
,
Mail
,
Smartphone
}
from
'lucide-react'
import
{
useForm
}
from
'react-hook-form'
const
matters
=
[
const
matters
=
[
{
{
...
@@ -23,6 +24,8 @@ const matters = [
...
@@ -23,6 +24,8 @@ const matters = [
]
]
export
default
function
Contact
()
{
export
default
function
Contact
()
{
const
{
register
}
=
useForm
()
return
(
return
(
<
main
className=
"container flex flex-col justify-center items-center py-20"
>
<
main
className=
"container flex flex-col justify-center items-center py-20"
>
<
h1
className=
"text-center font-normal md:font-extrabold text-green-800 text-2xl md:text-4xl"
>
<
h1
className=
"text-center font-normal md:font-extrabold text-green-800 text-2xl md:text-4xl"
>
...
@@ -53,16 +56,31 @@ export default function Contact() {
...
@@ -53,16 +56,31 @@ export default function Contact() {
Envie uma mensagem
Envie uma mensagem
</
h2
>
</
h2
>
<
form
action=
""
className=
"mt-6 flex flex-col gap-6"
>
<
form
action=
""
className=
"mt-6 flex flex-col gap-6"
>
<
InputMui
type=
"text"
variant=
"outlined"
label=
"Nome completo"
/>
<
InputMui
type=
"text"
variant=
"outlined"
label=
"Nome completo"
name=
"full-name"
register=
{
register
}
/>
<
InputMui
<
InputMui
type=
"text"
type=
"text"
variant=
"outlined"
variant=
"outlined"
label=
"Mensagem"
label=
"Mensagem"
multiline
multiline
rows=
{
4
}
rows=
{
4
}
name=
"message"
register=
{
register
}
/>
/>
<
InputMui
type=
"text"
variant=
"outlined"
label=
"Assunto"
select
>
<
InputMui
type=
"text"
variant=
"outlined"
label=
"Assunto"
select
name=
"subject"
register=
{
register
}
>
{
matters
.
map
((
option
)
=>
(
{
matters
.
map
((
option
)
=>
(
<
MenuItem
key=
{
option
.
value
}
value=
{
option
.
value
}
>
<
MenuItem
key=
{
option
.
value
}
value=
{
option
.
value
}
>
{
option
.
label
}
{
option
.
label
}
...
...
src/app/layout.tsx
View file @
d389de98
...
@@ -7,6 +7,7 @@ import type { Metadata } from 'next'
...
@@ -7,6 +7,7 @@ import type { Metadata } from 'next'
import
{
Poppins
}
from
'next/font/google'
import
{
Poppins
}
from
'next/font/google'
import
{
Toaster
}
from
'sonner'
import
{
Toaster
}
from
'sonner'
import
{
AuthProvider
}
from
'@/contexts/auth-context'
import
ReactQueryProvider
from
'@/providers/react-query'
import
ReactQueryProvider
from
'@/providers/react-query'
const
poppins
=
Poppins
({
subsets
:
[
'latin'
],
weight
:
[
'300'
,
'400'
,
'800'
]
})
const
poppins
=
Poppins
({
subsets
:
[
'latin'
],
weight
:
[
'300'
,
'400'
,
'800'
]
})
...
@@ -24,21 +25,23 @@ export default function RootLayout({
...
@@ -24,21 +25,23 @@ export default function RootLayout({
return
(
return
(
<
html
lang=
"pt-BR"
>
<
html
lang=
"pt-BR"
>
<
body
className=
{
`antialiased ${poppins.className}`
}
>
<
body
className=
{
`antialiased ${poppins.className}`
}
>
<
ThemeProvider
<
AuthProvider
>
attribute=
"class"
<
ThemeProvider
defaultTheme=
"dark"
attribute=
"class"
enableSystem
defaultTheme=
"dark"
disableTransitionOnChange
enableSystem
>
disableTransitionOnChange
<
StyledEngineProvider
injectFirst
>
>
<
ReactQueryProvider
>
<
StyledEngineProvider
injectFirst
>
<
Toaster
richColors
/>
<
ReactQueryProvider
>
<
Header
/>
<
Toaster
richColors
/>
{
children
}
<
Header
/>
<
Footer
/>
{
children
}
</
ReactQueryProvider
>
<
Footer
/>
</
StyledEngineProvider
>
</
ReactQueryProvider
>
</
ThemeProvider
>
</
StyledEngineProvider
>
</
ThemeProvider
>
</
AuthProvider
>
</
body
>
</
body
>
</
html
>
</
html
>
)
)
...
...
src/app/login/page.tsx
View file @
d389de98
'use client'
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
{
Checkbox
}
from
'@/components/ui/checkbox
'
import
{
AuthContext
}
from
'@/contexts/auth-context
'
import
Image
from
'next/image'
import
Image
from
'next/image'
import
Link
from
'next/link'
import
Link
from
'next/link'
// import { useRouter } from 'next/router'
import
{
AxiosError
}
from
'axios'
import
{
useContext
}
from
'react'
import
{
useForm
}
from
'react-hook-form'
import
{
toast
}
from
'sonner'
import
globo
from
'../../../public/images/globo.svg'
import
globo
from
'../../../public/images/globo.svg'
type
FormLogin
=
{
email
:
string
password
:
string
}
export
default
function
Login
()
{
export
default
function
Login
()
{
const
{
handleSubmit
,
register
}
=
useForm
<
FormLogin
>
()
const
{
signIn
}
=
useContext
(
AuthContext
)
// const router = useRouter()
const
onSubmit
=
async
(
data
:
FormLogin
)
=>
{
try
{
await
signIn
(
data
)
// router.push('/admin')
}
catch
(
error
)
{
if
(
error
instanceof
AxiosError
)
{
const
{
message
}
=
error
.
response
?.
data
toast
.
error
(
`
${
message
}
`
)
}
console
.
log
(
'🚀 ~ onSubmit ~ error aqui:'
,
error
)
}
}
return
(
return
(
<
main
>
<
main
>
<
section
className=
" container flex flex-col justify-center items-center space-y-10 h-[723px]"
>
<
section
className=
" container flex flex-col justify-center items-center space-y-10 h-[723px]"
>
...
@@ -20,15 +50,27 @@ export default function Login() {
...
@@ -20,15 +50,27 @@ export default function Login() {
Acesso exclusivo para usuários cadastrados.
Acesso exclusivo para usuários cadastrados.
</
h2
>
</
h2
>
<
form
<
form
//
onSubmit={handleSubmit(onSubmit)}
onSubmit=
{
handleSubmit
(
onSubmit
)
}
className=
"w-full md:w-[600px] flex flex-col gap-8 order-4"
className=
"w-full md:w-[600px] flex flex-col gap-8 order-4"
>
>
<
div
className=
"flex flex-col space-y-6"
>
<
div
className=
"flex flex-col space-y-6"
>
<
div
className=
"flex flex-col space-y-4"
>
<
div
className=
"flex flex-col space-y-4"
>
<
InputMui
label=
"E-mail"
variant=
"outlined"
type=
"email"
/>
<
InputMui
<
InputMui
label=
"Senha"
variant=
"outlined"
type=
"password"
/>
label=
"E-mail"
variant=
"outlined"
type=
"email"
name=
"email"
register=
{
register
}
/>
<
InputMui
label=
"Senha"
variant=
"outlined"
type=
"password"
name=
"password"
register=
{
register
}
/>
</
div
>
</
div
>
<
div
className=
"flex items-center space-x-2"
>
{
/*
<div className="flex items-center space-x-2">
<Checkbox id="remember" />
<Checkbox id="remember" />
<label
<label
htmlFor="remember"
htmlFor="remember"
...
@@ -36,9 +78,10 @@ export default function Login() {
...
@@ -36,9 +78,10 @@ export default function Login() {
>
>
Lembrar-me
Lembrar-me
</label>
</label>
</
div
>
</div> */
}
<
Button
className=
"rounded-sm"
asChild
>
<
Button
className=
"rounded-sm"
type=
"submit"
>
<
Link
href=
"/admin"
>
Entrar
</
Link
>
{
/* <Link href="/admin">Entrar</Link> */
}
Entrar
</
Button
>
</
Button
>
<
Button
<
Button
variant=
{
'link'
}
variant=
{
'link'
}
...
...
src/components/input-file.tsx
View file @
d389de98
...
@@ -17,6 +17,7 @@ const InputFile = forwardRef<HTMLInputElement, InputFileProps>(
...
@@ -17,6 +17,7 @@ const InputFile = forwardRef<HTMLInputElement, InputFileProps>(
<
input
<
input
id=
{
id
}
id=
{
id
}
type=
"file"
type=
"file"
accept=
"image/png, image/jpeg, image/jpg"
className=
"hidden"
className=
"hidden"
ref=
{
ref
}
ref=
{
ref
}
{
...
inputProps
}
{
...
inputProps
}
...
...
src/components/mui/inputs.tsx
View file @
d389de98
...
@@ -3,21 +3,26 @@
...
@@ -3,21 +3,26 @@
import
{
useThemeClient
}
from
'@/hooks/useThemeClient'
import
{
useThemeClient
}
from
'@/hooks/useThemeClient'
import
{
TextField
,
TextFieldProps
}
from
'@mui/material'
import
{
TextField
,
TextFieldProps
}
from
'@mui/material'
import
{
ReactNode
}
from
'react'
import
{
ReactNode
}
from
'react'
import
{
FieldValues
,
Path
,
UseFormRegister
}
from
'react-hook-form'
type
InputMuiProps
=
TextFieldProps
&
{
type
InputMuiProps
<
T
extends
FieldValues
>
=
TextFieldProps
&
{
label
:
string
label
:
string
variant
:
'standard'
|
'filled'
|
'outlined'
variant
:
'standard'
|
'filled'
|
'outlined'
themeColor
?:
string
themeColor
?:
string
children
?:
ReactNode
children
?:
ReactNode
name
:
Path
<
T
>
register
:
UseFormRegister
<
T
>
}
}
export
function
InputMui
({
export
const
InputMui
=
<
T
extends
FieldValues
>
(
{
label
,
label
,
variant
,
variant
,
children
,
children
,
themeColor
=
'#fafafa'
,
themeColor
=
'#fafafa'
,
...
props
register
,
}:
InputMuiProps
)
{
name
,
...
rest
}
: InputMuiProps
<
T
>
) =
>
{
const
themeConfig
=
useThemeClient
()
const
themeConfig
=
useThemeClient
()
const
color
=
themeConfig
===
'dark'
?
themeColor
:
'#3C3C3C'
const
color
=
themeConfig
===
'dark'
?
themeColor
:
'#3C3C3C'
...
@@ -26,7 +31,8 @@ export function InputMui({
...
@@ -26,7 +31,8 @@ export function InputMui({
<
TextField
<
TextField
label=
{
label
}
label=
{
label
}
variant=
{
variant
}
variant=
{
variant
}
{
...
props
}
{
...
register
(
name
)}
{
...
rest
}
sx=
{
{
sx=
{
{
'& .MuiOutlinedInput-root'
:
{
'& .MuiOutlinedInput-root'
:
{
'& fieldset'
:
{
'& fieldset'
:
{
...
...
src/components/search-filter.tsx
View file @
d389de98
import
{
Search
}
from
'lucide-react'
import
{
Search
}
from
'lucide-react'
import
{
useForm
}
from
'react-hook-form'
import
{
InputMui
}
from
'./mui/inputs'
import
{
InputMui
}
from
'./mui/inputs'
import
{
Label
}
from
'./ui/label'
import
{
Label
}
from
'./ui/label'
import
{
import
{
...
@@ -11,6 +12,8 @@ import {
...
@@ -11,6 +12,8 @@ import {
}
from
'./ui/select'
}
from
'./ui/select'
export
default
function
SearchFilter
()
{
export
default
function
SearchFilter
()
{
const
{
register
}
=
useForm
()
return
(
return
(
<
div
className=
"container grid md:grid-cols-2 gap-8 items-end mb-8"
>
<
div
className=
"container grid md:grid-cols-2 gap-8 items-end mb-8"
>
<
div
className=
"flex items-center max-w-[712px] flex-1"
>
<
div
className=
"flex items-center max-w-[712px] flex-1"
>
...
@@ -19,6 +22,8 @@ export default function SearchFilter() {
...
@@ -19,6 +22,8 @@ export default function SearchFilter() {
variant=
"standard"
variant=
"standard"
type=
"text"
type=
"text"
className=
"w-full #fafafa"
className=
"w-full #fafafa"
name=
"learned-today"
register=
{
register
}
/>
/>
<
Search
size=
{
24
}
className=
"-ml-6"
/>
<
Search
size=
{
24
}
className=
"-ml-6"
/>
</
div
>
</
div
>
...
...
src/contexts/auth-context.tsx
0 → 100644
View file @
d389de98
'use client'
// import { useRouter } from 'next/router'
import
{
parseCookies
,
setCookie
}
from
'nookies'
import
{
createContext
,
useEffect
,
useState
}
from
'react'
import
{
getAccountsId
}
from
'@/api/accounts'
import
{
login
}
from
'@/api/login'
import
{
api
}
from
'@/lib/axios'
import
{
useRouter
}
from
'next/navigation'
type
User
=
{
id
:
string
name
:
string
email
:
string
}
|
null
type
SignInData
=
{
email
:
string
password
:
string
}
type
AuthContextType
=
{
isAuthenticated
:
boolean
user
:
User
signIn
:
(
data
:
SignInData
)
=>
Promise
<
void
>
}
export
const
AuthContext
=
createContext
({}
as
AuthContextType
)
export
function
AuthProvider
({
children
})
{
const
[
user
,
setUser
]
=
useState
<
User
|
null
>
(
null
)
const
router
=
useRouter
()
const
isAuthenticated
=
!!
user
useEffect
(()
=>
{
const
{
'sevenpro-token'
:
token
}
=
parseCookies
()
const
{
'sevenpro-user'
:
userCookie
}
=
parseCookies
()
if
(
token
&&
userCookie
)
{
const
{
id
}
=
JSON
.
parse
(
userCookie
)
getAccountsId
(
id
).
then
((
response
)
=>
{
setUser
(
response
.
data
)
})
}
},
[])
async
function
signIn
({
email
,
password
}:
SignInData
)
{
const
{
data
}
=
await
login
({
email
,
password
,
})
const
token
=
data
.
access_token
const
user
=
data
.
user
setCookie
(
undefined
,
'sevenpro-token'
,
token
,
{
maxAge
:
60
*
60
*
1
,
// 1 hour
})
setCookie
(
undefined
,
'sevenpro-user'
,
JSON
.
stringify
(
user
),
{
maxAge
:
60
*
60
*
1
,
// 1 hour
})
api
.
defaults
.
headers
.
Authorization
=
`Bearer
${
token
}
`
setUser
(
user
)
router
.
push
(
'/admin'
)
}
return
(
<
AuthContext
.
Provider
value=
{
{
user
,
isAuthenticated
,
signIn
}
}
>
{
children
}
</
AuthContext
.
Provider
>
)
}
src/lib/axios.ts
View file @
d389de98
import
axios
from
'axios'
import
axios
from
'axios'
// import Router from 'next/router'
import
{
destroyCookie
,
parseCookies
}
from
'nookies'
const
{
'sevenpro-token'
:
token
}
=
parseCookies
()
console
.
log
(
'🚀 ~ token:'
,
token
)
export
const
api
=
axios
.
create
({
export
const
api
=
axios
.
create
({
baseURL
:
'http://localhost:3000'
,
baseURL
:
process
.
env
.
NEXT_PUBLIC_URL_API
,
})
})
if
(
token
)
{
api
.
defaults
.
headers
.
Authorization
=
`Bearer
${
token
}
`
}
// api.interceptors.request.use(
// (config) => {
// return config
// },
// (error) => {
// return Promise.reject(error)
// },
// )
api
.
interceptors
.
response
.
use
(
(
response
)
=>
response
,
async
(
error
)
=>
{
if
(
error
.
response
&&
error
.
response
.
status
===
401
)
{
// Remove o token inválido
destroyCookie
(
null
,
'sevenpro-token'
)
// Redireciona para a página de login
// Router.push('/login')
}
return
Promise
.
reject
(
error
)
},
)
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