Merge remote-tracking branch 'origin/master' into feature/slicing

This commit is contained in:
fredy.siswanto 2025-03-08 20:36:43 +07:00
commit 333fa32eda
10 changed files with 66 additions and 90 deletions

View File

@ -11,8 +11,6 @@ type TParameters = {
slug: string
} & THttpServer
export type TNewDetailResponse = z.infer<typeof dataResponseSchema>
export const getNewsBySlug = async (parameters: TParameters) => {
const { slug, accessToken } = parameters
try {

View File

@ -1,21 +0,0 @@
import { Link } from 'react-router'
type BreadcrumbProperty = {
slug: string
}
export const Breadcrumb = (property: BreadcrumbProperty) => {
const { slug } = property
return (
<div className="mb-5 flex items-center gap-2">
<Link to={'#'}>Blog</Link>
<div>{'>'}</div>
<Link
to={'#'}
className="text-ellipsis md:text-clip ..."
>
{slug.slice(0, 20) + '...'}
</Link>
</div>
)
}

View File

@ -25,16 +25,16 @@ export const Navbar = () => {
</Link>
<div className="flex items-center gap-x-8">
<Popover className="relative">
<PopoverButton className="flex w-3xs cursor-pointer items-center justify-between focus:outline-none">
<div className="flex items-center">
{staffData?.profile_picture === '' ? (
<ProfileIcon className="mr-3 h-8 w-8 rounded-full bg-[#C4C4C4]" />
) : (
<PopoverButton className="flex w-3xs cursor-pointer items-center justify-between rounded-xl p-2 ring-2 ring-[#707FDD]/10 hover:shadow focus:outline-none">
<div className="flex items-center space-x-3">
{staffData?.profile_picture ? (
<img
src={staffData?.profile_picture}
alt={staffData?.name}
className="mr-3 h-8 w-8 rounded-full bg-[#C4C4C4] object-cover"
className="h-8 w-8 rounded-full bg-[#C4C4C4] object-cover"
/>
) : (
<ProfileIcon className="h-8 w-8 rounded-full bg-[#C4C4C4]" />
)}
<span className="text-xs">{staffData?.name}</span>

View File

@ -71,7 +71,7 @@ export const TagsPage = () => {
className="text-md h-[42px] rounded-md"
size="lg"
>
Buat Tags
Buat Tag
</Button>
</div>
@ -80,7 +80,7 @@ export const TagsPage = () => {
columns={dataColumns}
options={dataOptions}
slots={dataSlot}
title="Daftar Katgeori"
title="Daftar Tags"
/>
</div>
)

View File

@ -1,39 +0,0 @@
import type { TNewsDetail } from '~/types/news'
export const CONTENT: TNewsDetail = {
title: 'Hotman Paris Membuka Perpustakaan di tengah Diskotik',
content: ` <section>
<h1>Introduction</h1>
</secti>
<section>
<p>Mi tincidunt elit, id quisque ligula ac diam, amet. Vel etiam suspendisse morbi eleifend faucibus eget vestibulum felis. Dictum quis montes, sit sit. Tellus aliquam enim urna, etiam. Mauris posuere vulputate arcu amet, vitae nisi, tellus tincidunt. At feugiat sapien varius id.</p>
<p>Eget quis mi enim, leo lacinia pharetra, semper. Eget in volutpat mollis at volutpat lectus velit, sed auctor. Porttitor fames arcu quis fusce augue enim. Quis at habitant diam at. Suscipit tristique risus, at donec. In turpis vel et quam imperdiet. Ipsum molestie aliquet sodales id est ac volutpat.</p>
<figure>
<img src="/images/dummy-image.png" alt="Image caption goes here">
<figcaption>Image caption goes here</figcaption>
</figure>
<p>Dolor enim eu tortor urna sed duis nulla. Aliquam vestibulum, nulla odio nisl vitae. In aliquet pellentesque aenean hac vestibulum turpis mi bibendum diam. Tempor integer aliquam in vitae malesuada fringilla.</p>
<blockquote>
<p>"Ipsum sit mattis nulla quam nulla. Gravida id gravida ac enim mauris id. Non pellentesque congue eget consectetur turpis. Sapien, dictum molestie sem tempor. Diam elit, orci, tincidunt aenean tempus."</p>
</blockquote>
<p>Tristique odio senectus nam posuere ornare leo metus, ultricies. Blandit duis ultricies vulputate morbi feugiat cras placerat elit. Aliquam tellus lorem sed ac. Montes, sed mattis pellentesque suscipit accumsan. Cursus viverra aenean magna risus elementum faucibus molestie pellentesque. Arcu ultricies sed mauris vestibulum.</p>
</section>
<section>
<h2>Conclusion</h2>
<p>Morbi sed imperdiet in ipsum, adipiscing elit dui lectus. Tellus id scelerisque est ultricies ultricies. Duis est sit sed leo nisl, blandit elit sagittis. Quisque tristique consequat quam sed. Nisl at scelerisque amet nulla purus habitasse.</p>
<p>Nunc sed faucibus bibendum feugiat sed interdum. Ipsum egestas condimentum mi massa. In tincidunt pharetra consectetur sed duis facilisis metus. Etiam egestas in nec sed et. Quis lobortis at sit dictum eget nibh tortor commodo cursus.</p>
<p>Odio felis sagittis, morbi feugiat tortor vitae feugiat fusce aliquet. Nam elementum urna nisi aliquet erat dolor enim. Ornare id morbi eget ipsum. Aliquam senectus neque ut id eget consectetur dictum. Donec posuere pharetra odio consequat scelerisque et, nunc tortor. Nulla adipiscing erat a erat. Condimentum lorem posuere gravida enim posuere cursus diam.</p>
</section>
<section>
<span>MOM</span>
<span>FOOD</span>
<span>BOOKS</span>
<span>WORDPRESS</span>
</section>`,
featured: '/images/news-1.jpg',
slug: 'hotman-paris-membuka-perpustakaan-di-tengah-diskotik',
author: 'John Doe',
date: new Date(),
categories: [],
tags: ['Category', 'Popular', 'Trending', 'Latest'],
}

View File

@ -1,7 +1,9 @@
import htmlParse from 'html-react-parser'
import { useReadingTime } from 'react-hook-reading-time'
import { useRouteLoaderData } from 'react-router'
import type { TTagResponse } from '~/apis/common/get-tags'
import { ProfileIcon } from '~/components/icons/profile'
import { Card } from '~/components/ui/card'
import { CarouselSection } from '~/components/ui/carousel-section'
import { SocialShareButtons } from '~/components/ui/social-share'
@ -14,10 +16,11 @@ export const NewsDetailPage = () => {
'routes/_news.detail.$slug',
)
const currentUrl = globalThis.location
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { newsDetailData }: any = loaderData
const { newsDetailData } = loaderData || {}
const { title, content, featured_image, author, live_at, tags } =
newsDetailData
newsDetailData || {}
const { text } = useReadingTime(content || '')
return (
<div className="sm-max:mx-5 relative">
@ -27,17 +30,26 @@ export const NewsDetailPage = () => {
{title}
</h2>
{/* next planing create component for this section */}
{/* START TODO: create component for this section */}
<div className="my-5 w-full items-center justify-between gap-2 align-middle sm:flex">
<div className="mb-2 flex items-center gap-2 align-middle">
{author?.profile_picture ? (
<img
src={author.avatar}
alt={author.name}
className="h-12 w-12 rounded-full"
src={author?.profile_picture}
alt={author?.name}
className="h-12 w-12 rounded-full bg-[#C4C4C4] object-cover"
/>
) : (
<ProfileIcon className="h-12 w-12 rounded-full bg-[#C4C4C4]" />
)}
<div>
<h4 className="text-md">{author.name}</h4>
<p className="text-sm">{formatDate(live_at)} . 5 min read </p>
<h4 className="text-md">{author?.name}</h4>
<p className="flex gap-1 text-sm">
<span>{live_at && `${formatDate(live_at)}`}</span>
<span>·</span>
<span>{text}</span>
</p>
</div>
</div>
{/* <IconsSocial className="flex-row" /> */}
@ -46,7 +58,7 @@ export const NewsDetailPage = () => {
title={title}
/>
</div>
{/* end next planing create component for this section */}
{/* END TODO: create component for this section */}
<div className="w-full bg-amber-200">
<img
src={featured_image}
@ -57,7 +69,7 @@ export const NewsDetailPage = () => {
<div className="mt-8 flex items-center justify-center">
<article className="prose prose-stone">
{htmlParse(content)}
{content && htmlParse(content)}
</article>
</div>
<div className="items-end justify-between border-b-gray-300 py-4 sm:flex">

View File

@ -1,11 +1,12 @@
import { getNewsBySlug } from '~/apis/common/get-news-by-slug'
import { getUser } from '~/apis/news/get-user'
import { APP } from '~/configs/meta'
import { handleCookie } from '~/libs/cookies'
import { NewsDetailPage } from '~/pages/news-detail'
import type { Route } from './+types/_news.detail.$slug'
export const loader = async ({ request }: Route.LoaderArgs) => {
export const loader = async ({ request, params }: Route.LoaderArgs) => {
const { userToken } = await handleCookie(request)
let userData
if (userToken) {
@ -14,21 +15,30 @@ export const loader = async ({ request }: Route.LoaderArgs) => {
})
userData = data
}
// TODO need handel if user not accses non premium data
// TODO: need handle if user not access non premium data
const { data: newsDetailData } = await getNewsBySlug({
slug: request.url.split('/').pop() ?? '',
slug: params.slug,
accessToken: userToken,
})
// const { data: categoriesData } = await getCategories()
return {
newsDetailData,
userData,
// categoriesData,
}
}
export const meta = ({ data }: Route.MetaArgs) => {
const { newsDetailData } = data
const metaTitle = APP.title
const title = `${newsDetailData.title} - ${metaTitle}`
return [
{
title,
},
]
}
const NewsDetailLayout = () => <NewsDetailPage />
export default NewsDetailLayout

View File

@ -7,7 +7,7 @@ export type TNews = {
>[]
}
export type TNewsDetail = {
type TNewsDetail = {
title: string
content: string
featured: string

View File

@ -42,6 +42,7 @@
"react-colorful": "^5.6.1",
"react-dom": "^19.0.0",
"react-hook-form": "^7.54.2",
"react-hook-reading-time": "^1.0.0",
"react-router": "^7.1.3",
"react-share": "^5.2.2",
"remix-hook-form": "^6.1.3",

15
pnpm-lock.yaml generated
View File

@ -92,6 +92,9 @@ importers:
react-hook-form:
specifier: ^7.54.2
version: 7.54.2(react@19.0.0)
react-hook-reading-time:
specifier: ^1.0.0
version: 1.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react-router:
specifier: ^7.1.3
version: 7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@ -3894,6 +3897,13 @@ packages:
peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19
react-hook-reading-time@1.0.0:
resolution: {integrity: sha512-kIudDiGHCTzBlV95WM6xPN3EBUViQynJvcul/NL+8My6fsl0BeKoCi9Dp19g69PlyF3WLA3QAyjVL99+Ucgs6A==}
engines: {node: '>=8', npm: '>=5'}
peerDependencies:
react: ^16.13.1
react-dom: ^16.13.1
react-hotkeys-hook@4.6.1:
resolution: {integrity: sha512-XlZpbKUj9tkfgPgT9gA+1p7Ey6vFIZHttUjPqpTdyT5nqQ8mHL7elxvSbaC+dpSiHUSmr21Ya1mDxBZG3aje4Q==}
peerDependencies:
@ -8628,6 +8638,11 @@ snapshots:
dependencies:
react: 19.0.0
react-hook-reading-time@1.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
react-hotkeys-hook@4.6.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
react: 19.0.0