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
f47a9145
Commit
f47a9145
authored
Mar 15, 2025
by
Wellton Quirino
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add filters in screens courses
parent
89d68af0
Changes
18
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
276 additions
and
143 deletions
+276
-143
audiences.ts
src/api/audiences.ts
+1
-1
categories.ts
src/api/categories.ts
+1
-1
courses.ts
src/api/courses.ts
+4
-0
page.tsx
src/app/admin/area/[id]/page.tsx
+0
-1
page.tsx
src/app/admin/curso/[id]/page.tsx
+0
-1
page.tsx
src/app/admin/curso/page.tsx
+0
-13
page.tsx
src/app/admin/page.tsx
+35
-10
page.tsx
src/app/curso/[courseId]/page.tsx
+46
-27
page.tsx
src/app/empresas/page.tsx
+1
-1
page.tsx
src/app/estudantes/page.tsx
+75
-17
page.tsx
src/app/profissionais/page.tsx
+1
-1
banner-category.tsx
src/components/banner-category.tsx
+16
-4
card-image.tsx
src/components/card/card-image.tsx
+1
-1
card-root.tsx
src/components/card/card-root.tsx
+6
-2
corousel-component.tsx
src/components/corousel-component.tsx
+1
-2
course-details.tsx
src/components/course-details.tsx
+24
-7
globals.css
src/styles/globals.css
+54
-54
formatDate.ts
src/utils/formatDate.ts
+10
-0
No files found.
src/api/audiences.ts
View file @
f47a9145
import
{
api
}
from
'@/lib/axios'
export
type
AudiencesProps
=
{
id
?
:
string
id
:
string
name
:
string
}
...
...
src/api/categories.ts
View file @
f47a9145
import
{
api
}
from
'@/lib/axios'
export
type
CategoriesProps
=
{
id
?
:
string
id
:
string
name
:
string
}
...
...
src/api/courses.ts
View file @
f47a9145
...
...
@@ -37,6 +37,10 @@ export type CoursesProps = {
areaId
:
string
audienceId
:
string
categoryId
:
string
area
?:
{
id
:
string
name
:
string
}
audience
?:
{
id
:
string
name
:
string
...
...
src/app/admin/area/[id]/page.tsx
View file @
f47a9145
...
...
@@ -19,7 +19,6 @@ import { toast } from 'sonner'
export
default
function
AreaId
()
{
const
[
desktopBanner
,
setDesktopBanner
]
=
useState
<
File
|
null
>
(
null
)
console
.
log
(
'🚀 ~ AreaId ~ desktopBanner:'
,
desktopBanner
)
const
[
mobileBanner
,
setMobileBanner
]
=
useState
<
File
|
null
>
(
null
)
const
params
=
useParams
<
{
id
:
string
}
>
()
...
...
src/app/admin/curso/[id]/page.tsx
View file @
f47a9145
...
...
@@ -86,7 +86,6 @@ export default function Curso() {
queryFn
:
()
=>
getCourseId
(
params
.
id
),
enabled
:
!!
params
.
id
,
})
console
.
log
(
'🚀 ~ Curso:'
,
course
)
const
formatDate
=
(
dateString
:
string
)
=>
{
const
date
=
parseISO
(
dateString
)
...
...
src/app/admin/curso/page.tsx
View file @
f47a9145
...
...
@@ -40,18 +40,6 @@ import { Controller, useForm } from 'react-hook-form'
import
{
toast
}
from
'sonner'
import
{
z
}
from
'zod'
// const ACCOUNT_ID = env.NEXT_PUBLIC_CLOUDFLARE_ACCESS_ACCOUNT_ID
// const ACCESS_KEY_ID = env.NEXT_PUBLIC_CLOUDFLARE_ACCESS_KEY_ID
// const SECRET_ACCESS_KEY = env.NEXT_PUBLIC_CLOUDFLARE_SECRET_ACCESS_KEY
// const MAX_FILE_SIZE = 5000000
// const ACCEPTED_IMAGE_TYPES = [
// 'image/jpeg',
// 'image/jpg',
// 'image/png',
// 'image/webp',
// ]
const
FormSchema
=
z
.
object
({
name
:
z
.
string
().
trim
().
min
(
3
,
{
message
:
'Título obrigatório'
}),
description
:
z
.
string
().
trim
().
min
(
3
,
{
message
:
'Descrição obrigatória'
}),
...
...
@@ -91,7 +79,6 @@ export default function Curso() {
},
})
const
values
=
form
.
watch
()
console
.
log
(
'🚀 ~ Curso ~ values:'
,
values
)
const
{
data
:
areas
}
=
useQuery
({
queryKey
:
[
'areas'
],
...
...
src/app/admin/page.tsx
View file @
f47a9145
...
...
@@ -12,18 +12,28 @@ import { AuthContext } from '@/contexts/auth-context'
import
{
useQuery
}
from
'@tanstack/react-query'
import
{
Pencil
,
Search
}
from
'lucide-react'
import
Link
from
'next/link'
import
{
useContext
}
from
'react'
import
{
useContext
,
useEffect
,
useState
}
from
'react'
import
{
useForm
}
from
'react-hook-form'
export
default
function
Admin
()
{
const
{
register
}
=
useForm
()
const
{
register
,
watch
}
=
useForm
()
const
{
user
}
=
useContext
(
AuthContext
)
const
search
=
watch
(
'search'
,
''
)
const
[
debouncedSearch
,
setDebouncedSearch
]
=
useState
(
''
)
useEffect
(()
=>
{
const
handler
=
setTimeout
(()
=>
{
setDebouncedSearch
(
search
)
},
500
)
return
()
=>
clearTimeout
(
handler
)
},
[
search
])
const
{
data
:
areas
,
error
,
isLoading
,
isError
,
isLoading
:
areasLoading
,
isError
:
areasIsError
,
}
=
useQuery
({
queryKey
:
[
'areas'
],
queryFn
:
getAreas
})
const
{
data
:
categories
}
=
useQuery
({
...
...
@@ -31,22 +41,34 @@ export default function Admin() {
queryFn
:
getCategories
,
})
const
{
data
:
audiences
}
=
useQuery
({
const
{
data
:
audiences
,
isLoading
:
audiencesLoading
,
isError
:
audiencesIsError
,
}
=
useQuery
({
queryKey
:
[
'audiences'
],
queryFn
:
getAudiences
,
})
const
{
data
:
courses
}
=
useQuery
({
const
{
data
:
courses
,
isLoading
:
coursesLoading
,
isError
:
coursesIsError
,
}
=
useQuery
({
queryKey
:
[
'courses'
],
queryFn
:
getCourses
,
})
if
(
isLoading
)
{
const
filteredCourses
=
courses
?.
data
.
filter
((
course
)
=>
course
.
name
.
toLowerCase
().
includes
(
debouncedSearch
.
toLowerCase
()),
)
if
(
areasLoading
||
coursesLoading
||
audiencesLoading
)
{
return
<
span
>
Loading...
</
span
>
}
if
(
i
sError
)
{
return
<
span
>
Error:
{
error
.
message
}
</
span
>
if
(
areasIsError
||
audiencesIsError
||
coursesI
sError
)
{
return
<
span
>
Error:
{
error
?
.
message
}
</
span
>
}
return
(
...
...
@@ -142,7 +164,7 @@ export default function Admin() {
<
p
className=
"text-yellow-100"
>
Não há curso cadastrado!
</
p
>
)
:
(
<
div
className=
"flex flex-wrap justify-around gap-4"
>
{
courses
?.
data
.
map
((
course
)
=>
(
{
filteredCourses
?
.
map
((
course
)
=>
(
<
Link
key=
{
course
.
id
}
className=
"lowercase scale-100 hover:scale-105 duration-300"
...
...
@@ -166,6 +188,9 @@ export default function Admin() {
</
div
>
</
Link
>
))
}
{
filteredCourses
?.
length
===
0
&&
(
<
p
className=
"text-yellow-100"
>
Nenhum curso encontrado!
</
p
>
)
}
</
div
>
)
}
</
div
>
...
...
src/app/curso/[courseId]/page.tsx
View file @
f47a9145
'use client'
import
Image
from
'next/image'
import
{
getCourseId
}
from
'@/api/courses'
import
{
BannerCategory
}
from
'@/components/banner-category'
import
{
CarouselComponent
}
from
'@/components/corousel-component'
import
{
CourseDetails
}
from
'@/components/course-details'
...
...
@@ -11,19 +14,35 @@ import {
}
from
'@/components/ui/accordion'
import
{
Button
}
from
'@/components/ui/button'
import
{
Separator
}
from
'@/components/ui/separator'
import
{
useQuery
}
from
'@tanstack/react-query'
import
{
useParams
}
from
'next/navigation'
import
imageCapa
from
'../../../../public/images/banner.png'
export
default
function
CoursePage
()
{
const
params
=
useParams
<
{
courseId
:
string
}
>
()
const
{
data
:
course
,
isLoading
}
=
useQuery
({
queryKey
:
[
'course'
,
params
.
courseId
],
queryFn
:
()
=>
getCourseId
(
params
.
courseId
),
enabled
:
!!
params
.
courseId
,
})
if
(
isLoading
)
{
return
<
p
>
Carregando...
</
p
>
}
return
(
<>
<
BannerCategory
/>
<
BannerCategory
data=
{
course
?.
data
.
area
.
name
}
/>
<
div
className=
"flex flex-col md:flex-row px-6 pt-20 gap-6"
>
<
div
className=
"flex flex-col gap-7"
>
<
h1
className=
"block md:hidden text-green-400 text-3xl font-thin"
>
História Contemporânea dos Estados Unidos
{
course
?.
data
.
name
}
</
h1
>
<
Image
src=
{
imageCapa
}
src=
{
course
?.
data
.
mobileBanner
||
imageCapa
}
width=
{
500
}
height=
{
500
}
className=
"min-w-[348px] h-[464px] object-cover rounded-lg"
alt=
"Imagem de capa do curso"
/>
...
...
@@ -33,43 +52,43 @@ export default function CoursePage() {
</
div
>
<
div
className=
"flex flex-col gap-6"
>
<
h1
className=
"hidden md:block text-green-400 text-4xl font-extrabold"
>
História Contemporânea dos Estados Unidos
{
course
?.
data
.
name
}
</
h1
>
<
div
className=
"flex flex-col-reverse lg:flex-row gap-6 w-full"
>
<
div
className=
"flex flex-col lg:w-1/2"
>
<
h3
className=
"font-bold"
>
O que você vai aprender
</
h3
>
<
p
>
Este curso levará você por uma jornada desde os tumultuados anos
de 1970 até os dias atuais, explorando os impactos decisivos dos
governos de Bush, Obama, Trump e Biden. Descubra os
momentos-chave que moldaram a história contemporânea dos Estados
Unidos, desde a resiliência diante de crises até as mudanças
geopolíticas e sociais. Vamos desvendar os bastidores dos
eventos que marcaram época, proporcionando uma compreensão
profunda e contextualizada da evolução norte-americana.
Prepare-se para uma experiência de aprendizado envolvente e
reveladora, onde o passado ilumina o presente, moldando o
futuro.
</
p
>
<
p
>
{
course
?.
data
.
description
}
</
p
>
<
h3
className=
"font-bold mt-6"
>
Com quem você vai aprender
</
h3
>
<
p
>
Professor João Silva
</
p
>
{
course
?.
data
.
professors
&&
course
?.
data
.
professors
.
length
>
0
&&
(
<
p
>
{
course
?.
data
.
professors
.
join
(
', '
)
}
</
p
>
)
}
</
div
>
<
div
className=
"lg:w-1/2"
>
<
CourseDetails
/>
<
CourseDetails
data=
{
course
?.
data
}
/>
</
div
>
</
div
>
<
Button
variant=
"secondary"
className=
"uppercase block md:hidden"
>
Quero este curso
</
Button
>
<
span
className=
"font-bold mt-4 block md:hidden"
>
Saiba mais:
</
span
>
<
Accordion
type=
"single"
collapsible
className=
"w-full"
>
<
AccordionItem
value=
"item-1"
>
<
AccordionTrigger
>
Módulos
</
AccordionTrigger
>
{
course
?.
data
.
modules
.
sort
((
a
,
b
)
=>
a
.
module
.
name
.
localeCompare
(
b
.
module
.
name
))
.
map
((
module
)
=>
(
<
Accordion
type=
"single"
collapsible
className=
"w-full"
key=
{
module
.
module
.
id
}
>
<
AccordionItem
value=
{
module
.
module
.
id
}
>
<
AccordionTrigger
>
{
module
.
module
.
name
}
</
AccordionTrigger
>
<
AccordionContent
>
Yes. It adheres to the WAI-ARIA design pattern.
{
module
.
module
.
description
}
</
AccordionContent
>
</
AccordionItem
>
</
Accordion
>
))
}
</
div
>
</
div
>
<
div
className=
"my-10 px-6"
>
...
...
src/app/empresas/page.tsx
View file @
f47a9145
...
...
@@ -22,7 +22,7 @@ export default function Companies() {
<
div
className=
"grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid-rows-3 lg:grid-rows-2 gap-4 md:gap-6 p-6"
>
{
CoursesCard
.
map
((
course
)
=>
(
<
div
className=
"flex justify-center"
key=
{
course
.
id
}
>
<
Card
.
Root
link=
{
`curso/${course.id}`
}
>
<
Card
.
Root
link=
{
`
/
curso/${course.id}`
}
>
<
Card
.
Image
image=
{
course
.
image
.
src
}
width=
{
273
}
height=
{
365
}
>
<
Card
.
Title
title=
{
course
.
title
}
/>
</
Card
.
Image
>
...
...
src/app/estudantes/page.tsx
View file @
f47a9145
'use client'
import
{
getCourses
}
from
'@/api/courses'
import
{
About
}
from
'@/components/about'
import
{
BannerCategory
}
from
'@/components/banner-category'
import
{
Card
}
from
'@/components/card'
...
...
@@ -7,11 +10,36 @@ import { PaginationComponent } from '@/components/pagination-component'
import
SearchFilter
from
'@/components/search-filter'
import
{
SignUp
}
from
'@/components/sign-up'
import
{
SkeletonSerachParams
}
from
'@/components/skeleton-serach-params'
import
{
CoursesCard
}
from
'@/utils/courses-array'
import
{
formatDate
}
from
'@/utils/formatDate'
import
{
useQuery
}
from
'@tanstack/react-query'
import
{
Calendar
,
Clock4
,
User
}
from
'lucide-react'
import
{
usePathname
,
useSearchParams
}
from
'next/navigation'
import
{
Suspense
}
from
'react'
export
default
function
Students
()
{
const
path
=
usePathname
()
const
searchParams
=
useSearchParams
()
const
category
=
searchParams
.
get
(
'area'
)
console
.
log
(
"🚀 ~ Students ~ category:"
,
category
)
const
{
data
:
courses
,
isLoading
:
coursesLoading
,
isError
:
coursesIsError
,
}
=
useQuery
({
queryKey
:
[
'courses'
],
queryFn
:
getCourses
,
})
const
filterCoursesAudience
=
courses
?.
data
.
filter
((
item
)
=>
path
.
toLowerCase
().
includes
(
item
?.
audience
?.
name
.
toLowerCase
()
as
string
)
)
console
.
log
(
"🚀 ~ Students ~ filterCoursesAudience:"
,
filterCoursesAudience
)
const
filterCoursesAudiencesAndArea
=
filterCoursesAudience
?.
filter
((
area
)
=>
category
?.
includes
(
area
?.
area
?.
name
.
toLowerCase
()
as
string
))
console
.
log
(
"🚀 ~ Students ~ filterCoursesAudiencesAndArea:"
,
filterCoursesAudiencesAndArea
)
return
(
<
main
>
<
Suspense
fallback=
{
<
SkeletonSerachParams
/>
}
>
...
...
@@ -20,24 +48,54 @@ export default function Students() {
</
Suspense
>
<
SearchFilter
/>
<
div
className=
"grid rounded-none grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid-rows-3 lg:grid-rows-2 gap-4 md:gap-6 p-6"
>
{
CoursesCard
.
map
((
course
)
=>
(
{
!
category
&&
filterCoursesAudience
&&
filterCoursesAudience
.
map
(
course
=>
(
<
div
className=
"flex justify-center"
key=
{
course
.
id
}
>
<
Card
.
Root
link=
{
`
curso/${course.id}`
}
>
<
Card
.
Image
image=
{
course
.
image
.
src
}
width=
{
273
}
height=
{
365
}
>
<
Card
.
Title
title=
{
course
.
titl
e
}
/>
<
Card
.
Root
link=
{
`/
curso/${course.id}`
}
>
<
Card
.
Image
image=
{
course
.
mobileBanner
as
string
}
width=
{
273
}
height=
{
365
}
>
<
Card
.
Title
title=
{
course
.
nam
e
}
/>
</
Card
.
Image
>
<
Card
.
Content
description=
{
course
.
hours
}
>
<
Card
.
Content
description=
{
`${course.workload} hrs / ${course.category?.name}`
}
>
<
Card
.
Icon
icon=
{
Clock4
}
/>
</
Card
.
Content
>
<
Card
.
Content
description=
{
course
.
category
}
>
<
Card
.
Content
description=
{
course
.
audience
?.
name
as
string
}
>
<
Card
.
Icon
icon=
{
User
}
/>
</
Card
.
Content
>
<
Card
.
Content
description=
{
course
.
calender
}
>
<
Card
.
Content
description=
{
formatDate
(
course
.
startDate
)
as
string
}
>
<
Card
.
Icon
icon=
{
Calendar
}
/>
</
Card
.
Content
>
</
Card
.
Root
>
</
div
>
))
}
{
category
&&
filterCoursesAudiencesAndArea
&&
filterCoursesAudiencesAndArea
.
map
((
course
)
=>
(
<
div
className=
"flex justify-center"
key=
{
course
.
id
}
>
<
Card
.
Root
link=
{
`/curso/${course.id}`
}
>
<
Card
.
Image
image=
{
course
.
mobileBanner
as
string
}
width=
{
273
}
height=
{
365
}
>
<
Card
.
Title
title=
{
course
.
name
}
/>
</
Card
.
Image
>
<
Card
.
Content
description=
{
`${course.workload} hrs / ${course.category?.name}`
}
>
<
Card
.
Icon
icon=
{
Clock4
}
/>
</
Card
.
Content
>
<
Card
.
Content
description=
{
course
.
audience
?.
name
as
string
}
>
<
Card
.
Icon
icon=
{
User
}
/>
</
Card
.
Content
>
<
Card
.
Content
description=
{
formatDate
(
course
.
startDate
)
as
string
}
>
<
Card
.
Icon
icon=
{
Calendar
}
/>
</
Card
.
Content
>
</
Card
.
Root
>
</
div
>
))
}
{
category
&&
filterCoursesAudiencesAndArea
?.
length
===
0
&&
(
<
p
>
Não há cursos para a área
{
category
}
com audiência
{
path
}
</
p
>
)
}
{
!
category
&&
filterCoursesAudience
?.
length
===
0
&&
(
<
p
>
Não há cursos para a audiência
{
path
}
</
p
>
)
}
</
div
>
<
div
className=
"my-6"
>
<
PaginationComponent
pageIndex=
{
0
}
totalCount=
{
105
}
perPage=
{
10
}
/>
...
...
src/app/profissionais/page.tsx
View file @
f47a9145
...
...
@@ -22,7 +22,7 @@ export default function Professionals() {
<
div
className=
"grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 grid-rows-3 lg:grid-rows-2 gap-4 md:gap-6 p-6"
>
{
CoursesCard
.
map
((
course
)
=>
(
<
div
className=
"flex justify-center"
key=
{
course
.
id
}
>
<
Card
.
Root
link=
{
`curso/${course.id}`
}
>
<
Card
.
Root
link=
{
`
/
curso/${course.id}`
}
>
<
Card
.
Image
image=
{
course
.
image
.
src
}
width=
{
273
}
height=
{
365
}
>
<
Card
.
Title
title=
{
course
.
title
}
/>
</
Card
.
Image
>
...
...
src/components/banner-category.tsx
View file @
f47a9145
...
...
@@ -7,16 +7,20 @@ import bannerStudants from '../../public/images/banners/students_banner.jpg'
import
{
getAreas
}
from
'@/api/areas'
import
{
useQuery
}
from
'@tanstack/react-query'
export
function
BannerCategory
()
{
export
function
BannerCategory
(
areaBanner
:
{
data
?:
string
|
undefined
}
)
{
const
searchParams
=
useSearchParams
()
const
category
=
searchParams
.
get
(
'area'
)
const
{
data
:
areas
}
=
useQuery
({
queryKey
:
[
'areas'
],
queryFn
:
getAreas
})
const
area
=
areas
?.
data
.
find
(
const
bannerImage
=
areas
?.
data
.
find
(
(
item
)
=>
item
.
name
.
toLowerCase
()
===
category
?.
toLowerCase
(),
)
const
bannerImageArea
=
areas
?.
data
.
find
(
(
item
)
=>
item
.
name
.
toLowerCase
()
===
areaBanner
?.
data
?.
toLowerCase
(),
)
return
(
<
div
className=
"h-[300px] flex items-center justify-end"
>
<
Image
...
...
@@ -24,7 +28,11 @@ export function BannerCategory() {
className=
"hidden md:flex w-full h-full object-cover"
width=
{
100
}
height=
{
100
}
src=
{
area
?.
desktopBanner
||
bannerStudants
}
src=
{
bannerImage
?.
desktopBanner
||
bannerImageArea
?.
desktopBanner
||
bannerStudants
}
unoptimized
/>
<
Image
...
...
@@ -32,7 +40,11 @@ export function BannerCategory() {
className=
"flex md:hidden w-full h-full object-cover"
width=
{
100
}
height=
{
100
}
src=
{
area
?.
mobileBanner
||
bannerStudants
}
src=
{
bannerImage
?.
mobileBanner
||
bannerImageArea
?.
mobileBanner
||
bannerStudants
}
unoptimized
/>
</
div
>
...
...
src/components/card/card-image.tsx
View file @
f47a9145
...
...
@@ -10,7 +10,7 @@ type CardImageProps = {
export
function
CardImage
({
children
,
image
,
width
,
height
}:
CardImageProps
)
{
return
(
<
div
className=
{
`relative w-[${width}px]
`
}
>
<
div
className=
{
`relative w-[${width}px]`
}
>
<
Image
src=
{
image
}
width=
{
width
}
...
...
src/components/card/card-root.tsx
View file @
f47a9145
'use client'
import
Link
from
'next/link'
import
{
ReactNode
}
from
'react'
...
...
@@ -9,10 +11,12 @@ type CardRootProps = {
export
function
CardRoot
({
children
,
link
}:
CardRootProps
)
{
return
(
<
Link
className=
"lowercase transform scale-95 hover:scale-100 transition-transform duration-300 drop-shadow"
className=
"lowercase transform scale-95 hover:scale-100 transition-transform duration-300 drop-shadow
"
href=
{
link
}
>
<
div
className=
{
`border border-gray-100 pl-0 rounded-lg max-w-[273px] `
}
>
<
div
className=
{
`border border-gray-100 pl-0 rounded-lg max-w-[273px] h-full`
}
>
{
children
}
</
div
>
</
Link
>
...
...
src/components/corousel-component.tsx
View file @
f47a9145
...
...
@@ -18,7 +18,6 @@ export function CarouselComponent() {
queryKey
:
[
'courses'
],
queryFn
:
getCourses
,
})
console
.
log
(
'🚀 ~ Admin ~ courses:'
,
courses
)
return
(
<
section
>
...
...
@@ -30,7 +29,7 @@ export function CarouselComponent() {
key=
{
course
.
id
}
className=
"sm:basis-1/2 md:basis-1/3 lg:basis-1/4 xl:basis-1/5 flex justify-center"
>
<
Card
.
Root
link=
{
`curso/${course.id}`
}
>
<
Card
.
Root
link=
{
`
/
curso/${course.id}`
}
>
<
Card
.
Image
image=
{
course
.
mobileBanner
||
''
}
width=
{
240
}
...
...
src/components/course-details.tsx
View file @
f47a9145
import
{
Calendar
,
Clock4
,
DollarSign
,
UserRound
}
from
'lucide-react'
import
{
CourseIdProps
}
from
'@/api/courses'
import
{
format
,
parseISO
}
from
'date-fns'
import
{
toZonedTime
}
from
'date-fns-tz'
import
{
Calendar
,
Clock4
,
UserRound
}
from
'lucide-react'
type
CourseProps
=
{
data
?:
CourseIdProps
}
export
function
CourseDetails
(
course
:
CourseProps
)
{
const
formatDate
=
(
dateString
:
string
|
undefined
)
=>
{
if
(
!
dateString
)
return
const
date
=
parseISO
(
dateString
)
const
utcDate
=
toZonedTime
(
date
,
'UTC'
)
return
format
(
utcDate
,
'dd/MM/yyyy'
)
}
export
function
CourseDetails
()
{
return
(
<
ul
className=
"flex flex-col gap-8"
>
<
li
className=
"flex items-center gap-4"
>
...
...
@@ -11,7 +26,9 @@ export function CourseDetails() {
</
div
>
<
div
className=
"flex flex-col gap-2"
>
<
span
className=
"font-thin"
>
Duração:
</
span
>
<
span
className=
"text-xl"
>
30 Hrs/Curso Rápido
</
span
>
<
span
className=
"text-xl"
>
{
course
.
data
?.
workload
.
toString
()
}
Hrs/
{
course
.
data
?.
category
.
name
}
</
span
>
</
div
>
</
li
>
<
li
className=
"flex items-center gap-4"
>
...
...
@@ -22,7 +39,7 @@ export function CourseDetails() {
</
div
>
<
div
className=
"flex flex-col gap-2"
>
<
span
className=
"font-thin"
>
Indicado para:
</
span
>
<
span
className=
"text-xl"
>
Estudantes
</
span
>
<
span
className=
"text-xl"
>
{
course
.
data
?.
audience
.
name
}
</
span
>
</
div
>
</
li
>
<
li
className=
"flex items-center gap-4"
>
...
...
@@ -33,10 +50,10 @@ export function CourseDetails() {
</
div
>
<
div
className=
"flex flex-col gap-2"
>
<
span
className=
"font-thin"
>
Início:
</
span
>
<
span
className=
"text-xl"
>
Imediato
</
span
>
<
span
className=
"text-xl"
>
{
formatDate
(
course
.
data
?.
startDate
)
}
</
span
>
</
div
>
</
li
>
<
li
className=
"flex items-center gap-4"
>
{
/*
<li className="flex items-center gap-4">
<div className="rounded-full w-[60px] h-[60px] flex items-center justify-center bg-gradient-to-r from-green-700 to-green-50">
<div className="rounded-full flex items-center justify-center w-[57px] h-[57px] dark:bg-gray-900 bg-gray-50">
<DollarSign size={35} />
...
...
@@ -46,7 +63,7 @@ export function CourseDetails() {
<span className="font-thin">Investimento:</span>
<span className="text-xl">R$200,00</span>
</div>
</
li
>
</li>
*/
}
</
ul
>
)
}
src/styles/globals.css
View file @
f47a9145
@tailwind
base
;
@tailwind
components
;
@tailwind
utilities
;
@tailwind
components
;
@tailwind
utilities
;
@layer
base
{
@layer
base
{
:root
{
--background
:
0
0%
100%
;
--foreground
:
0
,
0%
,
25%
;
...
...
@@ -64,13 +64,13 @@
--input
:
240
3.7%
15.9%
;
--ring
:
240
4.9%
83.9%
;
}
}
}
@layer
base
{
@layer
base
{
*
{
@apply
border-border;
}
body
{
@apply
bg-background
text-foreground;
}
}
\ No newline at end of file
}
src/utils/formatDate.ts
0 → 100644
View file @
f47a9145
import
{
format
,
parseISO
}
from
"date-fns"
import
{
toZonedTime
}
from
"date-fns-tz"
export
const
formatDate
=
(
dateString
:
string
|
undefined
)
=>
{
if
(
!
dateString
)
return
const
date
=
parseISO
(
dateString
)
const
utcDate
=
toZonedTime
(
date
,
'UTC'
)
return
format
(
utcDate
,
'dd/MM/yyyy'
)
}
\ No newline at end of file
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