feat: implement category fetching and integrate into header menus
This commit is contained in:
parent
cfc864cb43
commit
25e136ba72
25
app/apis/common/get-categories.ts
Normal file
25
app/apis/common/get-categories.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
import { HttpServer, type THttpServer } from '~/libs/http-server'
|
||||
|
||||
const categorySchema = z.object({
|
||||
data: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
code: z.string(),
|
||||
name: z.string(),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
export type TCategorySchema = z.infer<typeof categorySchema>
|
||||
|
||||
export const getCategories = async (parameters?: THttpServer) => {
|
||||
try {
|
||||
const { data } = await HttpServer(parameters).get(`/api/category`)
|
||||
return categorySchema.parse(data)
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line unicorn/no-useless-promise-resolve-reject
|
||||
return Promise.reject(error)
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,18 @@
|
||||
import { useState } from 'react'
|
||||
import { Link } from 'react-router'
|
||||
|
||||
import type { TCategorySchema } from '~/apis/common/get-categories'
|
||||
import { CloseIcon } from '~/components/icons/close'
|
||||
import { MenuIcon } from '~/components/icons/menu'
|
||||
import { useNewsContext } from '~/contexts/news'
|
||||
import { HeaderSearch } from '~/layouts/news/header-search'
|
||||
|
||||
import { MENU } from './menu'
|
||||
type THeaderMenuMobile = {
|
||||
menu?: TCategorySchema['data']
|
||||
}
|
||||
|
||||
export default function HeaderMenuMobile() {
|
||||
export default function HeaderMenuMobile(properties: THeaderMenuMobile) {
|
||||
const { menu } = properties
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
||||
const { setIsLoginOpen } = useNewsContext()
|
||||
|
||||
@ -38,19 +42,19 @@ export default function HeaderMenuMobile() {
|
||||
|
||||
{/* List Menu */}
|
||||
<ul className="mx-10 mt-10 max-lg:space-y-3 lg:ml-14 lg:flex lg:gap-x-5">
|
||||
{MENU.map((item, index) => (
|
||||
{menu?.map((item, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className="px-3 max-lg:border-b max-lg:py-3"
|
||||
>
|
||||
<Link
|
||||
key={item.title}
|
||||
to={item.url}
|
||||
key={item.id}
|
||||
to={`/category/${item.code}`}
|
||||
className={
|
||||
'flex h-full items-center justify-center border-white px-[35px] sm:border-r'
|
||||
}
|
||||
>
|
||||
{item.title}
|
||||
{item.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
|
||||
@ -1,28 +1,31 @@
|
||||
import { Link } from 'react-router'
|
||||
import { Link, useRouteLoaderData } from 'react-router'
|
||||
|
||||
import HeaderMenuMobile from '~/layouts/news/header-menu-mobile'
|
||||
import type { loader } from '~/routes/_layout'
|
||||
|
||||
import { HeaderSearch } from './header-search'
|
||||
import { MENU } from './menu'
|
||||
|
||||
export const HeaderMenu = () => {
|
||||
const loaderData = useRouteLoaderData<typeof loader>('routes/_layout')
|
||||
const menu = loaderData?.categoriesData
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="hidden h-[60px] items-center justify-between bg-[#2E2F7C] text-xl font-medium text-white sm:flex">
|
||||
{MENU.map((item) => (
|
||||
{menu?.map((item) => (
|
||||
<Link
|
||||
key={item.title}
|
||||
to={item.url}
|
||||
key={item.id}
|
||||
to={`/category/${item.code}`}
|
||||
className={
|
||||
'flex h-full items-center justify-center border-r border-white px-[35px]'
|
||||
}
|
||||
>
|
||||
{item.title}
|
||||
{item.name}
|
||||
</Link>
|
||||
))}
|
||||
<HeaderSearch />
|
||||
</div>
|
||||
<HeaderMenuMobile />
|
||||
<HeaderMenuMobile menu={menu} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -18,37 +18,6 @@ type TFooterMenu = {
|
||||
items: TMenu[]
|
||||
}
|
||||
|
||||
export const MENU: TMenu[] = [
|
||||
{
|
||||
title: 'Spotlight',
|
||||
url: '/category/spotlight',
|
||||
},
|
||||
{
|
||||
title: 'Berita',
|
||||
url: '/category/berita',
|
||||
},
|
||||
{
|
||||
title: 'Kasus',
|
||||
url: '/category/kasus',
|
||||
},
|
||||
{
|
||||
title: 'Kajian',
|
||||
url: '/category/kajian',
|
||||
},
|
||||
{
|
||||
title: 'Lifestyle',
|
||||
url: '/category/lifestyle',
|
||||
},
|
||||
{
|
||||
title: 'Event',
|
||||
url: '/category/event',
|
||||
},
|
||||
{
|
||||
title: 'Travel',
|
||||
url: '/category/travel',
|
||||
},
|
||||
]
|
||||
|
||||
export const FOOTER_MENU: TFooterMenu[] = [
|
||||
{
|
||||
group: 'About Us',
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Outlet } from 'react-router'
|
||||
|
||||
import { getCategories } from '~/apis/common/get-categories'
|
||||
import { getSubscriptions } from '~/apis/common/get-subscriptions'
|
||||
import { NewsProvider } from '~/contexts/news'
|
||||
import { NewsDefaultLayout } from '~/layouts/news/default'
|
||||
@ -10,10 +11,12 @@ import type { Route } from './+types/_layout'
|
||||
export const loader = async ({ request }: Route.LoaderArgs) => {
|
||||
const { userToken } = await handleCookie(request)
|
||||
const { data: subscriptionsData } = await getSubscriptions()
|
||||
const { data: categoriesData } = await getCategories()
|
||||
|
||||
return {
|
||||
userToken,
|
||||
subscriptionsData,
|
||||
categoriesData,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user