From d3dc3b501666321a6702e5f3554d1dc99799def9 Mon Sep 17 00:00:00 2001
From: "fredy.siswanto"
Date: Thu, 6 Mar 2025 22:49:56 +0700
Subject: [PATCH] feat: enhance news API schema with author and categories
details, desc: update dashboard to display author names, and improve
pagination button styles
---
app/apis/admin/get-news.ts | 30 ++++++++-----
app/app.css | 36 +++++++++++++++
app/components/ui/table.tsx | 3 +-
app/data/contents.ts | 61 --------------------------
app/pages/dashboard-contents/index.tsx | 17 ++++---
app/pages/news-detail/data.ts | 35 +--------------
app/pages/news-detail/index.tsx | 16 +------
app/types/news.ts | 38 ----------------
app/utils/render.tsx | 5 ++-
9 files changed, 70 insertions(+), 171 deletions(-)
diff --git a/app/apis/admin/get-news.ts b/app/apis/admin/get-news.ts
index 04a0a06..aa860aa 100644
--- a/app/apis/admin/get-news.ts
+++ b/app/apis/admin/get-news.ts
@@ -2,19 +2,26 @@ import { z } from 'zod'
import { HttpServer, type THttpServer } from '~/libs/http-server'
+const authorSchema = z.object({
+ id: z.string(),
+ name: z.string(),
+ profile_picture: z.string(),
+})
+
+const categoriesCodeSchema = z.array(
+ z.object({
+ id: z.string(),
+ name: z.string(),
+ code: z.string(),
+ }),
+)
const newsSchema = z.object({
data: z.array(
z.object({
id: z.string(),
title: z.string(),
content: z.string(),
- categories: z.array(
- z.object({
- id: z.string(),
- name: z.string(),
- code: z.string(),
- }),
- ),
+ categories: categoriesCodeSchema,
tags: z.array(
z.object({
id: z.string(),
@@ -29,15 +36,14 @@ const newsSchema = z.object({
live_at: z.string(),
created_at: z.string(),
updated_at: z.string(),
- author: z.object({
- id: z.string(),
- name: z.string(),
- profile_picture: z.string(),
- }),
+ author: authorSchema,
}),
),
})
+export type TAuthor = z.infer
+export type TCategories = z.infer
+
export const getNews = async (parameters: THttpServer) => {
try {
const { data } = await HttpServer(parameters).get(`/api/news`)
diff --git a/app/app.css b/app/app.css
index 74741fe..573dc5b 100644
--- a/app/app.css
+++ b/app/app.css
@@ -37,3 +37,39 @@ nav[aria-label='pagination'] {
display: flex;
justify-content: center;
}
+/* Style untuk tombol aktif (current) */
+.dt-paging-button.current {
+ background-color: #2e2f7c !important;
+ color: white !important;
+}
+
+/* Style tombol aktif, kecuali jika disabled */
+div.dt-container .dt-paging .dt-paging-button.current:not(.disabled),
+div.dt-container .dt-paging .dt-paging-button.current:not(.disabled):hover {
+ color: white !important;
+ background-color: #2e2f7c !important;
+ min-width: 24px;
+ padding: 3px 6px;
+}
+
+/* Style tombol disabled */
+div.dt-container .dt-paging .dt-paging-button.disabled {
+ background-color: transparent !important;
+ color: #ccc !important;
+ cursor: not-allowed;
+ pointer-events: none; /* Agar tidak bisa diklik */
+}
+
+/* Menghindari hover effect untuk tombol yang disabled */
+div.dt-container .dt-paging .dt-paging-button:not(.disabled):hover {
+ background-color: #2e2f7c !important;
+ color: white !important;
+}
+
+/* Style default tombol */
+div.dt-container .dt-paging .dt-paging-button {
+ min-width: 24px;
+ padding: 3px 6px;
+ background-color: transparent !important;
+ color: #2e2f7c !important;
+}
diff --git a/app/components/ui/table.tsx b/app/components/ui/table.tsx
index 3225929..fcd38ec 100644
--- a/app/components/ui/table.tsx
+++ b/app/components/ui/table.tsx
@@ -3,8 +3,7 @@ import DataTable from 'datatables.net-react'
import React from 'react'
export type UiTableProperties = {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- data: any[]
+ data: any // eslint-disable-line @typescript-eslint/no-explicit-any
columns: ConfigColumns[]
slots?: any // eslint-disable-line @typescript-eslint/no-explicit-any
options?: Config
diff --git a/app/data/contents.ts b/app/data/contents.ts
index 921ca77..3e33c05 100644
--- a/app/data/contents.ts
+++ b/app/data/contents.ts
@@ -95,67 +95,6 @@ export const BERITA: TNews = {
],
}
-export const KAJIAN: TNews = {
- title: 'KAJIAN',
- description: DUMMY_DESCRIPTION,
- items: [
- {
- title: 'Travelling as a way of self-discovery and progress ',
- content:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.',
- featured: '/images/news-2.jpg',
- tags: ['Hukum Property'],
- isPremium: true,
- slug: 'travelling-as-a-way-of-self-discovery-and-progress ',
- },
- {
- title: 'Travelling as a way of self-discovery and progress ',
- content:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.',
- featured: '/images/news-2.jpg',
- tags: ['Hukum Property'],
- isPremium: true,
- slug: 'travelling-as-a-way-of-self-discovery-and-progress ',
- },
- {
- title: 'Travelling as a way of self-discovery and progress ',
- content:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.',
- featured: '/images/news-2.jpg',
- tags: ['Hukum Property'],
- isPremium: true,
- slug: 'travelling-as-a-way-of-self-discovery-and-progress ',
- },
- {
- title: 'Travelling as a way of self-discovery and progress ',
- content:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.',
- featured: 'https://placehold.co/600x400.png',
- tags: ['Hukum Property'],
- isPremium: true,
- slug: 'travelling-as-a-way-of-self-discovery-and-progress ',
- },
- {
- title: 'How does writing influence your personal brand? ',
- content:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.',
- featured: '/images/news-3.jpg',
- tags: ['Hukum Property'],
- isPremium: true,
- slug: 'how-does-writing-influence-your-personal-brand',
- },
- {
- title: 'Helping a local business reinvent itself ',
- content:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.',
- featured: '/images/news-4.jpg',
- tags: ['Hukum Property'],
- isPremium: true,
- slug: 'helping-a-local-business-reinvent-itself',
- },
- ],
-}
-
export const BANNER: TBanner[] = [
{
id: 1,
diff --git a/app/pages/dashboard-contents/index.tsx b/app/pages/dashboard-contents/index.tsx
index e7fa581..d45ac44 100644
--- a/app/pages/dashboard-contents/index.tsx
+++ b/app/pages/dashboard-contents/index.tsx
@@ -2,11 +2,11 @@ import DT from 'datatables.net-dt'
import DataTable from 'datatables.net-react'
import { Link, useRouteLoaderData } from 'react-router'
+import type { TAuthor, TCategories } from '~/apis/admin/get-news'
import { Button } from '~/components/ui/button'
import { UiTable } from '~/components/ui/table'
import { TitleDashboard } from '~/components/ui/title-dashboard'
import type { loader } from '~/routes/_admin.lg-admin._dashboard.contents'
-import type { TCategory } from '~/types/news'
import { formatDate } from '~/utils/formatter'
export const ContentsPage = () => {
@@ -19,8 +19,8 @@ export const ContentsPage = () => {
const dataTable = newsData
const dataColumns = [
{ title: 'No', data: 'id' },
- { title: 'Tanggal Konten', data: 'created_at' },
- { title: 'Nama Penulis', data: 'author_id' },
+ { title: 'Tanggal Konten', data: 'live_at' },
+ { title: 'Nama Penulis', data: 'author' },
{ title: 'Judul', data: 'title' },
{ title: 'Kategori', data: 'categories' },
{
@@ -34,18 +34,17 @@ export const ContentsPage = () => {
},
{
title: 'Action',
- data: 'id',
+ data: 'slug',
},
]
const dataSlot = {
1: (value: string) => {
return formatDate(value)
},
-
- 4: (value: TCategory[]) => {
- return value.map((item: { name: string }) => {
- return `${item.name}`
- })
+ 2: (value: TAuthor) => `${value.name}`,
+ 4: (value: TCategories) => {
+ const categories = value.map((item) => item.name).join(', ')
+ return `${categories}`
},
6: (value: string | number) => {
return (
diff --git a/app/pages/news-detail/data.ts b/app/pages/news-detail/data.ts
index 92f69b4..111f4fc 100644
--- a/app/pages/news-detail/data.ts
+++ b/app/pages/news-detail/data.ts
@@ -1,5 +1,4 @@
-import { DUMMY_DESCRIPTION } from '~/data/contents'
-import type { TNews, TNewsDetail } from '~/types/news'
+import type { TNewsDetail } from '~/types/news'
export const CONTENT: TNewsDetail = {
title: 'Hotman Paris Membuka Perpustakaan di tengah Diskotik',
@@ -38,35 +37,3 @@ export const CONTENT: TNewsDetail = {
categories: [],
tags: ['Category', 'Popular', 'Trending', 'Latest'],
}
-
-export const BERITA: TNews = {
- title: 'BERITA',
- description: DUMMY_DESCRIPTION,
- items: [
- {
- title: 'Travelling as a way of self-discovery and progress',
- content:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.',
- featured: '/images/news-2.jpg',
- tags: ['Hukum Property'],
- slug: 'travelling-as-a-way-of-self-discovery-and-progress',
- },
- {
- title: 'How does writing influence your personal brand?',
- content:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.',
- featured: '/images/news-3.jpg',
- tags: ['Hukum'],
- slug: 'how-does-writing-influence-your-personal-brand',
- },
- {
- title: 'Helping a local business reinvent itself',
- content:
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros.',
- featured: '/images/news-4.jpg',
- tags: ['Hukum Property'],
- isPremium: true,
- slug: 'helping-a-local-business-reinvent-itself',
- },
- ],
-}
diff --git a/app/pages/news-detail/index.tsx b/app/pages/news-detail/index.tsx
index 954d239..67df854 100644
--- a/app/pages/news-detail/index.tsx
+++ b/app/pages/news-detail/index.tsx
@@ -34,7 +34,7 @@ export const NewsDetailPage = () => {
-
+
{/* end next planing create component for this section */}
@@ -50,7 +50,7 @@ export const NewsDetailPage = () => {
{htmlParse(content)}
-
+
Share this post
@@ -66,18 +66,6 @@ export const NewsDetailPage = () => {
))}
-
-
-

-
-
{author}
-
Job title, Company name
-
-
diff --git a/app/types/news.ts b/app/types/news.ts
index 327a755..d04e998 100644
--- a/app/types/news.ts
+++ b/app/types/news.ts
@@ -18,41 +18,3 @@ export type TNewsDetail = {
isPremium?: boolean
categories?: Array
}
-
-export type TTag = {
- id: string
- code: string
- name: string
- created_at: string
- updated_at: string
-}
-
-export type TCategory = {
- id: string
- name: string
- code: string
- created_at: string
- updated_at: string
-}
-
-export type Author = {
- id: string
- name: string
- profile_picture: string
-}
-
-export type TKontents = {
- id: string
- title: string
- content: string
- featured_image: string
- tags: TTag[]
- categories: TCategory[]
- is_premium: boolean
- slug: string
- author_id: string
- live_at: string
- created_at: string
- updated_at: string
- author: Author
-}
diff --git a/app/utils/render.tsx b/app/utils/render.tsx
index 6989a95..267b30b 100644
--- a/app/utils/render.tsx
+++ b/app/utils/render.tsx
@@ -12,7 +12,10 @@ type TGetPremiumAttribute = {
export const getPremiumAttribute = (parameters: TGetPremiumAttribute) => {
const { isPremium, slug, onClick, userData } = parameters
- if (isPremium && (!userData || userData?.subscribe_plan_code === 'basic')) {
+ if (
+ isPremium &&
+ (!userData || userData?.subscribe.subscribe_plan.code === 'basic')
+ ) {
return {
onClick,
to: '',