feat: enhance news detail page with dynamic data loading and social sharing functionality
This commit is contained in:
parent
ee209b6ceb
commit
50fdd6bc02
@ -11,6 +11,8 @@ type TParameters = {
|
|||||||
slug: string
|
slug: string
|
||||||
} & THttpServer
|
} & THttpServer
|
||||||
|
|
||||||
|
export type TNewDetailResponse = z.infer<typeof dataResponseSchema>
|
||||||
|
|
||||||
export const getNewsBySlug = async (parameters: TParameters) => {
|
export const getNewsBySlug = async (parameters: TParameters) => {
|
||||||
const { slug, accessToken } = parameters
|
const { slug, accessToken } = parameters
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { XIcon } from '~/components/icons/x'
|
|||||||
|
|
||||||
type SocialMediaProperties = {
|
type SocialMediaProperties = {
|
||||||
className?: string
|
className?: string
|
||||||
|
slug?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataSocialMedia = [
|
const dataSocialMedia = [
|
||||||
|
|||||||
@ -1,20 +1,28 @@
|
|||||||
import htmlParse from 'html-react-parser'
|
import htmlParse from 'html-react-parser'
|
||||||
|
import { useRouteLoaderData } from 'react-router'
|
||||||
|
|
||||||
import { Breadcrumb } from '~/components/ui/breadcrumb'
|
import type { TTagResponse } from '~/apis/common/get-tags'
|
||||||
import { Card } from '~/components/ui/card'
|
import { Card } from '~/components/ui/card'
|
||||||
import { CarouselSection } from '~/components/ui/carousel-section'
|
import { CarouselSection } from '~/components/ui/carousel-section'
|
||||||
import { IconsSocial } from '~/components/ui/social-share'
|
import { IconsSocial } from '~/components/ui/social-share'
|
||||||
import { BERITA } from '~/data/contents'
|
import { BERITA } from '~/data/contents'
|
||||||
|
import type { loader } from '~/routes/_news.detail.$slug'
|
||||||
import { CONTENT } from './data'
|
import { formatDate } from '~/utils/formatter'
|
||||||
|
|
||||||
export const NewsDetailPage = () => {
|
export const NewsDetailPage = () => {
|
||||||
const { title, content, featured, slug, author, date, tags } = CONTENT
|
const loaderData = useRouteLoaderData<typeof loader>(
|
||||||
|
'routes/_news.detail.$slug',
|
||||||
|
)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const { newsDetailData }: any = loaderData
|
||||||
|
const { title, content, featured_image, slug, author, live_at, tags } =
|
||||||
|
newsDetailData
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sm-max:mx-5 relative">
|
<div className="sm-max:mx-5 relative">
|
||||||
<Card>
|
<Card>
|
||||||
<div className="py-5 sm:px-30">
|
<div className="py-5 sm:px-30">
|
||||||
<Breadcrumb slug={slug} />
|
|
||||||
<h2 className="text-xl font-extrabold text-[#2E2F7C] sm:text-4xl">
|
<h2 className="text-xl font-extrabold text-[#2E2F7C] sm:text-4xl">
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
@ -28,10 +36,8 @@ export const NewsDetailPage = () => {
|
|||||||
className="h-12 w-12 rounded-full"
|
className="h-12 w-12 rounded-full"
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-md">{author}</h4>
|
<h4 className="text-md">{author.name}</h4>
|
||||||
<p className="text-sm">
|
<p className="text-sm">{formatDate(live_at)} . 5 min read </p>
|
||||||
{date.toJSON().slice(0, 10)} . 5 min read{' '}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<IconsSocial className="flex-row" />
|
<IconsSocial className="flex-row" />
|
||||||
@ -39,7 +45,7 @@ export const NewsDetailPage = () => {
|
|||||||
{/* end next planing create component for this section */}
|
{/* end next planing create component for this section */}
|
||||||
<div className="w-full bg-amber-200">
|
<div className="w-full bg-amber-200">
|
||||||
<img
|
<img
|
||||||
src={featured}
|
src={featured_image}
|
||||||
alt={title}
|
alt={title}
|
||||||
className="w-full object-cover object-center sm:h-[600px]"
|
className="w-full object-cover object-center sm:h-[600px]"
|
||||||
/>
|
/>
|
||||||
@ -53,15 +59,18 @@ export const NewsDetailPage = () => {
|
|||||||
<div className="items-end justify-between border-b-gray-300 py-4 sm:flex">
|
<div className="items-end justify-between border-b-gray-300 py-4 sm:flex">
|
||||||
<div className="flex flex-col max-sm:mb-3">
|
<div className="flex flex-col max-sm:mb-3">
|
||||||
<p className="mb-2">Share this post</p>
|
<p className="mb-2">Share this post</p>
|
||||||
<IconsSocial className="a" />
|
<IconsSocial
|
||||||
|
className="a"
|
||||||
|
slug={slug}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap items-end gap-2">
|
<div className="flex flex-wrap items-end gap-2">
|
||||||
{tags?.map((tag) => (
|
{tags?.map((tag: TTagResponse) => (
|
||||||
<span
|
<span
|
||||||
key={tag}
|
key={tag.id}
|
||||||
className="rounded bg-gray-300 p-1"
|
className="rounded bg-gray-300 p-1"
|
||||||
>
|
>
|
||||||
{tag}
|
{tag.name}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,34 @@
|
|||||||
|
import { getNewsBySlug } from '~/apis/common/get-news-by-slug'
|
||||||
|
import { getUser } from '~/apis/news/get-user'
|
||||||
|
import { handleCookie } from '~/libs/cookies'
|
||||||
import { NewsDetailPage } from '~/pages/news-detail'
|
import { NewsDetailPage } from '~/pages/news-detail'
|
||||||
|
|
||||||
|
import type { Route } from './+types/_news.detail.$slug'
|
||||||
|
|
||||||
|
export const loader = async ({ request }: Route.LoaderArgs) => {
|
||||||
|
const { userToken } = await handleCookie(request)
|
||||||
|
let userData
|
||||||
|
if (userToken) {
|
||||||
|
const { data } = await getUser({
|
||||||
|
accessToken: userToken,
|
||||||
|
})
|
||||||
|
userData = data
|
||||||
|
}
|
||||||
|
// TODO need handel if user not accses non premium data
|
||||||
|
const { data: newsDetailData } = await getNewsBySlug({
|
||||||
|
slug: request.url.split('/').pop() ?? '',
|
||||||
|
accessToken: userToken,
|
||||||
|
})
|
||||||
|
|
||||||
|
// const { data: categoriesData } = await getCategories()
|
||||||
|
|
||||||
|
return {
|
||||||
|
newsDetailData,
|
||||||
|
userData,
|
||||||
|
// categoriesData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const NewsDetailLayout = () => <NewsDetailPage />
|
const NewsDetailLayout = () => <NewsDetailPage />
|
||||||
|
|
||||||
export default NewsDetailLayout
|
export default NewsDetailLayout
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user