Compare commits

...

10 Commits

Author SHA1 Message Date
Anang Yusman 04a40eb952 update domain 2026-02-16 14:09:54 +08:00
Anang Yusman fb75399e48 update ckeeditor 2026-02-10 12:59:35 +08:00
Anang Yusman ced07906ad update yml 2026-02-05 11:46:35 +08:00
Anang Yusman d1d7d33c41 update landing 2026-01-30 19:00:19 +08:00
Anang Yusman 8db50bdc90 update 2026-01-14 11:07:46 +08:00
Anang Yusman fe4b0bd917 update 2026-01-06 10:25:24 +08:00
Anang Yusman 2e8c45ad97 update 2025-12-31 15:33:30 +08:00
Anang Yusman eb1031cc53 update 2025-12-23 15:17:16 +08:00
Anang Yusman 515c5c8802 update 2025-12-18 10:59:54 +08:00
Anang Yusman 304d972aa5 update 2025-12-15 11:05:35 +08:00
24 changed files with 725 additions and 592 deletions

View File

@ -11,12 +11,12 @@ build-dev:
name: docker:25.0.3-cli name: docker:25.0.3-cli
services: services:
- name: docker:25.0.3-dind - name: docker:25.0.3-dind
command: ["--insecure-registry=103.82.242.92:8900"] command: ["--insecure-registry=38.47.185.86:8900"]
script: script:
- docker logout - docker logout
- docker login -u $DEPLOY_USERNAME -p $DEPLOY_TOKEN 103.82.242.92:8900 - docker login -u $DEPLOY_USERNAME -p $DEPLOY_TOKEN 38.47.185.86:8900
- docker build -t 103.82.242.92:8900/medols/web-berita-bumn:dev . - docker build -t 38.47.185.86:8900/medols/web-berita-bumn:dev .
- docker push 103.82.242.92:8900/medols/web-berita-bumn:dev - docker push 38.47.185.86:8900/medols/web-berita-bumn:dev
auto-deploy: auto-deploy:
stage: deploy stage: deploy
@ -27,4 +27,4 @@ auto-deploy:
services: services:
- docker:dind - docker:dind
script: script:
- curl --user admin:$JENKINS_PWD http://103.31.38.120:8080/job/auto-deploy-berita-bumn/build?token=autodeploymedols - curl --user admin:$JENKINS_PWD http://38.47.185.86:8080/job/auto-deploy-berita-bumn/build?token=autodeploymedols

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 190 KiB

View File

@ -5,6 +5,7 @@ import Link from "next/link";
import { import {
getArticleById, getArticleById,
getArticleBySlug, getArticleBySlug,
getArticleFiles,
getListArticle, getListArticle,
} from "@/service/article"; } from "@/service/article";
import { close, error, loading } from "@/config/swal"; import { close, error, loading } from "@/config/swal";
@ -22,6 +23,7 @@ import {
} from "@/service/master-user"; } from "@/service/master-user";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { Badge } from "../ui/badge"; import { Badge } from "../ui/badge";
import { formatTextToHtmlTag } from "@/utils/global";
type TabKey = "trending" | "comments" | "latest"; type TabKey = "trending" | "comments" | "latest";
@ -74,13 +76,13 @@ export default function DetailContent() {
startDate: null, startDate: null,
endDate: null, endDate: null,
}); });
const [detailfiles, setDetailFiles] = useState<any>([]); const [detailFiles, setDetailFiles] = useState<any[]>([]);
const [mainImage, setMainImage] = useState(0); const [mainImage, setMainImage] = useState(0);
const [thumbnail, setThumbnail] = useState("-"); const [thumbnail, setThumbnail] = useState("-");
const [diseId, setDiseId] = useState(0); const [diseId, setDiseId] = useState(0);
const [thumbnailImg, setThumbnailImg] = useState<File[]>([]); const [thumbnailImg, setThumbnailImg] = useState<File[]>([]);
const [selectedMainImage, setSelectedMainImage] = useState<number | null>( const [selectedMainImage, setSelectedMainImage] = useState<number | null>(
null null,
); );
const [selectedIndex, setSelectedIndex] = useState(0); const [selectedIndex, setSelectedIndex] = useState(0);
@ -300,16 +302,38 @@ export default function DetailContent() {
initStateData(); initStateData();
}, [listCategory]); }, [listCategory]);
useEffect(() => {
setSelectedIndex(0);
}, [detailFiles]);
async function initStateData() { async function initStateData() {
loading(); loading();
const res = await getArticleBySlug(slug); try {
const data = res.data?.data; // 1⃣ Ambil artikel by slug
const res = await getArticleBySlug(slug);
const data = res?.data?.data;
setThumbnail(data?.thumbnailUrl); if (!data?.id) return;
setDiseId(data?.aiArticleId);
setDetailFiles(data?.files); setArticleDetail(data);
setArticleDetail(data); setThumbnail(data.thumbnailUrl);
close(); setDiseId(data.aiArticleId);
// 2⃣ Ambil SEMUA article files
const filesRes = await getArticleFiles();
const allFiles = filesRes?.data?.data ?? [];
// 3⃣ FILTER sesuai articleId
const filteredFiles = allFiles.filter(
(file: any) => file.articleId === data.id,
);
setDetailFiles(filteredFiles);
} catch (error) {
console.error("Init state detail error:", error);
} finally {
close();
}
} }
if (!articleDetail?.files || articleDetail.files.length === 0) { if (!articleDetail?.files || articleDetail.files.length === 0) {
@ -320,6 +344,16 @@ export default function DetailContent() {
); );
} }
function removeImgTags(htmlString?: { __html: string }) {
const parser = new DOMParser();
const doc = parser.parseFromString(String(htmlString?.__html), "text/html");
const images = doc.querySelectorAll("img");
images.forEach((img) => img.remove());
return { __html: doc.body.innerHTML };
}
return ( return (
<> <>
<div className="bg-white grid grid-cols-1 md:grid-cols-3 gap-6 px-8 py-8"> <div className="bg-white grid grid-cols-1 md:grid-cols-3 gap-6 px-8 py-8">
@ -355,14 +389,20 @@ export default function DetailContent() {
<span></span> <span></span>
<span> <span>
<span> <span>
{new Date(articleDetail?.publishedAt).toLocaleDateString( {new Date(
"id-ID", articleDetail?.publishedAt || articleDetail?.createdAt,
{ )
.toLocaleString("id-ID", {
day: "numeric", day: "numeric",
month: "long", month: "long",
year: "numeric", year: "numeric",
} hour: "2-digit",
)} minute: "2-digit",
hour12: false,
timeZone: "Asia/Jakarta",
})
.replace("pukul ", "")}{" "}
WIB
</span> </span>
</span> </span>
<span></span> <span></span>
@ -371,38 +411,43 @@ export default function DetailContent() {
<div className="w-full h-auto mb-6"> <div className="w-full h-auto mb-6">
{/* Gambar utama */} {/* Gambar utama */}
<div className="w-full"> {detailFiles.length > 0 ? (
<Image <>
src={articleDetail.files[selectedIndex].fileUrl} <Image
alt={articleDetail.files[selectedIndex].fileAlt || "Berita"} src={detailFiles[selectedIndex]?.fileUrl}
width={800} alt={detailFiles[selectedIndex]?.fileAlt || "Berita"}
height={400} width={800}
className="rounded-lg w-full object-cover" height={400}
/> className="rounded-lg w-full object-cover"
</div> />
{/* Thumbnail */} <div className="flex gap-2 mt-3 overflow-x-auto">
<div className="flex gap-2 mt-3 overflow-x-auto"> {detailFiles.map((file, index) => (
{articleDetail.files.map((file: any, index: number) => ( <button
<button key={file.id}
key={file.id || index} onClick={() => setSelectedIndex(index)}
onClick={() => setSelectedIndex(index)} className={`border-2 rounded-lg ${
className={`border-2 rounded-lg overflow-hidden ${ selectedIndex === index
selectedIndex === index ? "border-red-500"
? "border-red-500" : "border-transparent"
: "border-transparent" }`}
}`} >
> <Image
<Image src={file.fileUrl}
src={file.fileUrl} alt={file.fileAlt || "Thumbnail"}
alt={file.fileAlt || "Thumbnail"} width={100}
width={100} height={80}
height={80} className="object-cover"
className="object-cover" />
/> </button>
</button> ))}
))} </div>
</div> </>
) : (
<div className="h-[400px] flex items-center justify-center bg-gray-100 rounded-lg">
<p className="text-gray-400">Gambar tidak tersedia</p>
</div>
)}
{/* Slug */} {/* Slug */}
<p className="text-sm text-gray-500 mt-2 text-end"> <p className="text-sm text-gray-500 mt-2 text-end">
@ -476,11 +521,12 @@ export default function DetailContent() {
</Link> </Link>
</div> </div>
<div className="flex-1 overflow-y-auto"> <div className="flex-1 overflow-y-auto">
<div className="text-gray-700 leading-relaxed text-justify"> <div className="prose max-w-none text-justify">
<div <div
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={removeImgTags(
__html: articleDetail?.htmlDescription || "", formatTextToHtmlTag(articleDetail?.htmlDescription),
}} )}
className="text-sm lg:text-xl lg:leading-8 text-justify space-y-4"
/> />
</div> </div>
{/* <Author /> */} {/* <Author /> */}
@ -590,11 +636,11 @@ export default function DetailContent() {
htmlFor="komentar" htmlFor="komentar"
className="block text-sm font-medium mb-1" className="block text-sm font-medium mb-1"
> >
Komentar <span className="text-green-600">*</span> Komentar <span className="text-blue-600">*</span>
</label> </label>
<textarea <textarea
id="komentar" id="komentar"
className="w-full border border-gray-300 rounded-md p-3 h-40 focus:outline-none focus:ring-2 focus:ring-green-600" className="w-full border border-gray-300 rounded-md p-3 h-40 focus:outline-none focus:ring-2 focus:ring-blue-600"
{...register("comment", { required: true })} {...register("comment", { required: true })}
/> />
</div> </div>
@ -605,7 +651,7 @@ export default function DetailContent() {
htmlFor="nama" htmlFor="nama"
className="block text-sm font-medium mb-1" className="block text-sm font-medium mb-1"
> >
Nama <span className="text-green-600">*</span> Nama <span className="text-blue-600">*</span>
</label> </label>
<input <input
type="text" type="text"
@ -621,7 +667,7 @@ export default function DetailContent() {
htmlFor="email" htmlFor="email"
className="block text-sm font-medium mb-1" className="block text-sm font-medium mb-1"
> >
Email <span className="text-green-600">*</span> Email <span className="text-blue-600">*</span>
</label> </label>
<input <input
type="email" type="email"
@ -633,7 +679,7 @@ export default function DetailContent() {
<button <button
type="submit" type="submit"
className="bg-green-600 hover:bg-green-700 text-white font-semibold px-6 py-2 rounded-md transition mt-2 w-full" className="bg-blue-600 hover:bg-blue-700 text-white font-semibold px-6 py-2 rounded-md transition mt-2 w-full"
> >
KIRIM KOMENTAR KIRIM KOMENTAR
</button> </button>
@ -666,7 +712,7 @@ export default function DetailContent() {
</div> </div>
<button <button
type="submit" type="submit"
className="bg-green-600 hover:bg-green-700 text-white font-semibold px-6 py-2 rounded-md transition mt-4 w-full" className="bg-blue-600 hover:bg-blue-700 text-white font-semibold px-6 py-2 rounded-md transition mt-4 w-full"
> >
Kirim Kirim
</button> </button>
@ -735,7 +781,7 @@ export default function DetailContent() {
onClick={() => setActiveTab(tab.id)} onClick={() => setActiveTab(tab.id)}
className={`pb-2 text-sm font-medium ${ className={`pb-2 text-sm font-medium ${
activeTab === tab.id activeTab === tab.id
? "border-b-2 border-green-600 text-green-600" ? "border-b-2 border-blue-600 text-blue-600"
: "text-gray-600" : "text-gray-600"
}`} }`}
> >
@ -801,7 +847,7 @@ export default function DetailContent() {
</div> </div>
<div className="mt-6"> <div className="mt-6">
<h3 className="text-base font-semibold mb-2 text-gray-800 border-b pb-1 border-green-600 inline-block"> <h3 className="text-base font-semibold mb-2 text-gray-800 border-b pb-1 border-blue-600 inline-block">
Recommended Recommended
</h3> </h3>
@ -828,7 +874,7 @@ export default function DetailContent() {
day: "2-digit", day: "2-digit",
month: "long", month: "long",
year: "numeric", year: "numeric",
} },
)} )}
</p> </p>
</div> </div>
@ -858,7 +904,7 @@ export default function DetailContent() {
day: "2-digit", day: "2-digit",
month: "long", month: "long",
year: "numeric", year: "numeric",
} },
)} )}
</p> </p>
</div> </div>

View File

@ -1,7 +1,7 @@
// components/custom-editor.js import React, { useCallback, useEffect, useRef, useState } from "react";
import React from "react";
import { CKEditor } from "@ckeditor/ckeditor5-react"; import { CKEditor } from "@ckeditor/ckeditor5-react";
import "@/styles/custom-editor.css";
import Editor from "@/vendor/ckeditor5/build/ckeditor"; import Editor from "@/vendor/ckeditor5/build/ckeditor";
function CustomEditor(props) { function CustomEditor(props) {
@ -47,7 +47,7 @@ function CustomEditor(props) {
padding: 1rem; padding: 1rem;
} }
p { p {
margin: 0.5em 0; margin: 0.5em 0 !important;
} }
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.5em 0; margin: 1em 0 0.5em 0;
@ -72,98 +72,6 @@ function CustomEditor(props) {
}, },
}} }}
/> />
<style jsx>{`
.ckeditor-wrapper {
border-radius: 6px;
overflow: hidden;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1),
0 1px 2px 0 rgba(0, 0, 0, 0.06);
}
.ckeditor-wrapper :global(.ck.ck-editor__main) {
min-height: ${props.height || 400}px;
max-height: ${maxHeight}px;
}
.ckeditor-wrapper :global(.ck.ck-editor__editable) {
min-height: ${(props.height || 400) - 50}px;
max-height: ${maxHeight - 50}px;
overflow-y: auto !important;
scrollbar-width: thin;
scrollbar-color: #cbd5e1 #f1f5f9;
background: #fff !important;
color: #111 !important;
}
/* Dark mode support */
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable) {
background: #111 !important;
color: #f9fafb !important;
}
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h1),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h2),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h3),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h4),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h5),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h6) {
color: #f9fafb !important;
}
:global(.dark)
.ckeditor-wrapper
:global(.ck.ck-editor__editable blockquote) {
background-color: #1f2937 !important;
border-left-color: #374151 !important;
color: #f3f4f6 !important;
}
/* Custom scrollbar styling for webkit browsers */
.ckeditor-wrapper :global(.ck.ck-editor__editable::-webkit-scrollbar) {
width: 8px;
}
.ckeditor-wrapper
:global(.ck.ck-editor__editable::-webkit-scrollbar-track) {
background: #f1f5f9;
border-radius: 4px;
}
.ckeditor-wrapper
:global(.ck.ck-editor__editable::-webkit-scrollbar-thumb) {
background: #cbd5e1;
border-radius: 4px;
}
.ckeditor-wrapper
:global(.ck.ck-editor__editable::-webkit-scrollbar-thumb:hover) {
background: #94a3b8;
}
/* Dark mode scrollbar */
:global(.dark)
.ckeditor-wrapper
:global(.ck.ck-editor__editable::-webkit-scrollbar-track) {
background: #1f2937;
}
:global(.dark)
.ckeditor-wrapper
:global(.ck.ck-editor__editable::-webkit-scrollbar-thumb) {
background: #4b5563;
}
:global(.dark)
.ckeditor-wrapper
:global(.ck.ck-editor__editable::-webkit-scrollbar-thumb:hover) {
background: #6b7280;
}
/* Ensure content doesn't overflow */
.ckeditor-wrapper :global(.ck.ck-editor__editable .ck-content) {
overflow: hidden;
}
`}</style>
</div> </div>
); );
} }

View File

@ -48,7 +48,8 @@ function ViewEditor(props) {
.ckeditor-view-wrapper { .ckeditor-view-wrapper {
border-radius: 6px; border-radius: 6px;
overflow: hidden; overflow: hidden;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), box-shadow:
0 1px 3px 0 rgba(0, 0, 0, 0.1),
0 1px 2px 0 rgba(0, 0, 0, 0.06); 0 1px 2px 0 rgba(0, 0, 0, 0.06);
} }

View File

@ -514,7 +514,7 @@ export default function CreateArticleForm() {
id="title" id="title"
type="text" type="text"
placeholder="Masukkan judul artikel" placeholder="Masukkan judul artikel"
className="w-full border rounded-lg dark:border-gray-400" className="h-16 px-4 text-2xl leading-tight"
{...field} {...field}
/> />
)} )}

View File

@ -23,6 +23,7 @@ import {
deleteArticleFiles, deleteArticleFiles,
getArticleByCategory, getArticleByCategory,
getArticleById, getArticleById,
getArticleFiles,
submitApproval, submitApproval,
unPublishArticle, unPublishArticle,
updateArticle, updateArticle,
@ -196,27 +197,49 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
async function initState() { async function initState() {
loading(); loading();
const res = await getArticleById(id); try {
const data = res.data?.data; // 1⃣ Ambil ARTICLE
setDetailData(data); const articleRes = await getArticleById(id);
setValue("title", data?.title); const articleData = articleRes.data?.data;
setValue("customCreatorName", data?.customCreatorName);
setValue("slug", data?.slug);
setValue("source", data?.source);
const cleanDescription = data?.htmlDescription
? data.htmlDescription
.replace(/\\"/g, '"')
.replace(/\\n/g, "\n", "\\")
.trim()
: "";
setValue("description", cleanDescription);
setValue("tags", data?.tags ? data.tags.split(",") : []);
setThumbnail(data?.thumbnailUrl);
setDiseId(data?.aiArticleId);
setDetailFiles(data?.files);
setupInitCategory(data?.categories); if (!articleData) return;
close();
// ===== ARTICLE DATA =====
setDetailData(articleData);
setValue("title", articleData.title);
setValue("customCreatorName", articleData.customCreatorName);
setValue("slug", articleData.slug);
setValue("source", articleData.source);
const cleanDescription = articleData.htmlDescription
? articleData.htmlDescription
.replace(/\\"/g, '"')
.replace(/\\n/g, "\n")
.trim()
: "";
setValue("description", cleanDescription);
setValue("tags", articleData.tags ? articleData.tags.split(",") : []);
setThumbnail(articleData.thumbnailUrl);
setDiseId(articleData.aiArticleId);
setupInitCategory(articleData.categories);
// 2⃣ Ambil SEMUA article files
const filesRes = await getArticleFiles();
const allFiles = filesRes.data?.data ?? [];
// 3⃣ FILTER berdasarkan ARTICLE ID yang sedang dibuka
const filteredFiles = allFiles.filter(
(file: any) => file.articleId === articleData.id
);
setDetailFiles(filteredFiles);
} catch (error) {
console.error("Init state error:", error);
} finally {
close();
}
} }
const setupInitCategory = (data: any) => { const setupInitCategory = (data: any) => {
@ -667,9 +690,10 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
name="title" name="title"
render={({ field: { onChange, value } }) => ( render={({ field: { onChange, value } }) => (
<div className="w-full"> <div className="w-full">
<label htmlFor="title" className="block text-sm font-medium mb-1"> <label htmlFor="title" className="block text-xl font-medium mb-2">
Judul Judul
</label> </label>
<Input <Input
type="text" type="text"
id="title" id="title"
@ -677,7 +701,7 @@ export default function EditArticleForm(props: { isDetail: boolean }) {
value={value ?? ""} value={value ?? ""}
readOnly={isDetail} readOnly={isDetail}
onChange={onChange} onChange={onChange}
className="w-full border rounded-lg" className="h-16 px-4 text-2xl leading-tight"
/> />
</div> </div>
)} )}

View File

@ -72,7 +72,7 @@ export default function Development() {
<div className="mb-4"> <div className="mb-4">
<h2 className="text-xl font-black text-[#000]">JAGA NEGERI</h2> <h2 className="text-xl font-black text-[#000]">JAGA NEGERI</h2>
<div className="w-10 h-1 bg-green-600 mt-1 rounded"></div> <div className="w-10 h-1 bg-blue-600 mt-1 rounded"></div>
</div> </div>
<div className="border-b border-gray-300 mb-5"></div> <div className="border-b border-gray-300 mb-5"></div>
@ -95,7 +95,7 @@ export default function Development() {
<div className="flex flex-col"> <div className="flex flex-col">
<p className="text-[11px] font-bold text-black"> <p className="text-[11px] font-bold text-black">
<span className="border-b-2 border-green-600 pb-[1px]"> <span className="border-b-2 border-blue-600 pb-[1px]">
{item.categories?.[0]?.title || "Kategori"} {item.categories?.[0]?.title || "Kategori"}
</span> </span>
</p> </p>

View File

@ -11,7 +11,7 @@ export default function Footer() {
<div className="flex items-center justify-end"> <div className="flex items-center justify-end">
<div className="flex justify-center md:justify-end"> <div className="flex justify-center md:justify-end">
<Image <Image
src="/bumn.png" src="/berita-bumn-logo.png"
alt="Logo" alt="Logo"
width={230} width={230}
height={230} height={230}
@ -38,7 +38,7 @@ export default function Footer() {
className="w-full border border-gray-300 rounded-md px-4 py-3 outline-none" className="w-full border border-gray-300 rounded-md px-4 py-3 outline-none"
/> />
<button className="mt-4 bg-green-600 hover:bg-green-500 text-black px-6 py-3 rounded-md font-medium"> <button className="mt-4 bg-blue-600 hover:bg-blue-500 text-white px-6 py-3 rounded-md font-medium">
SIGN UP SIGN UP
</button> </button>
</div> </div>
@ -62,7 +62,7 @@ export default function Footer() {
</div> </div>
<p className="text-start text-gray-500 text-sm mt-8 pl-5"> <p className="text-start text-gray-500 text-sm mt-8 pl-5">
© 2025 Milenial Bersuara - All Rights Reserved. © 2025 Berita Bumn - All Rights Reserved.
</p> </p>
</footer> </footer>
); );

View File

@ -51,7 +51,7 @@ export default function Header() {
{/* FLASH STRIP */} {/* FLASH STRIP */}
<div className="flex items-center justify-between mt-6 mb-3"> <div className="flex items-center justify-between mt-6 mb-3">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<h4 className="text-green-600 font-semibold">Flash</h4> <h4 className="text-blue-600 font-semibold">Flash</h4>
<span className="text-red-500"></span> <span className="text-red-500"></span>
</div> </div>
<div className="text-xs text-gray-500 hidden md:block">LOAD MORE </div> <div className="text-xs text-gray-500 hidden md:block">LOAD MORE </div>
@ -125,7 +125,7 @@ export default function Header() {
{/* White Card Overlay */} {/* White Card Overlay */}
<div className="absolute bottom-6 left-6 bg-white bg-opacity-95 backdrop-blur-sm p-6 shadow-lg max-w-lg"> <div className="absolute bottom-6 left-6 bg-white bg-opacity-95 backdrop-blur-sm p-6 shadow-lg max-w-lg">
<span className="text-[11px] bg-green-700 text-white px-2 py-1 rounded-sm"> <span className="text-[11px] bg-blue-700 text-white px-2 py-1 rounded-sm">
{mainArticle.categoryName || {mainArticle.categoryName ||
mainArticle.categories?.[0]?.title || mainArticle.categories?.[0]?.title ||
"Berita"} "Berita"}
@ -144,14 +144,13 @@ export default function Header() {
</span> </span>
<span></span> <span></span>
<span> <span>
{new Date(mainArticle.publishedAt).toLocaleDateString( {new Date(
"id-ID", mainArticle.publishedAt || mainArticle.createdAt,
{ ).toLocaleDateString("id-ID", {
day: "2-digit", day: "2-digit",
month: "long", month: "long",
year: "numeric", year: "numeric",
} })}
)}
</span> </span>
</div> </div>
</div> </div>
@ -190,7 +189,9 @@ export default function Header() {
{item.title} {item.title}
</p> </p>
<span className="text-xs text-gray-500 mt-1"> <span className="text-xs text-gray-500 mt-1">
{new Date(item.publishedAt).toLocaleDateString("id-ID", { {new Date(
item.publishedAt || item.createdAt,
).toLocaleDateString("id-ID", {
day: "2-digit", day: "2-digit",
month: "long", month: "long",
year: "numeric", year: "numeric",

View File

@ -69,7 +69,7 @@ export default function NewsTerkini() {
<section className="max-w-7xl mx-auto px-4 grid grid-cols-1 lg:grid-cols-[2fr_1fr] gap-6"> <section className="max-w-7xl mx-auto px-4 grid grid-cols-1 lg:grid-cols-[2fr_1fr] gap-6">
<div> <div>
<h2 className="text-lg font-bold text-gray-900">BERITA TERKINI</h2> <h2 className="text-lg font-bold text-gray-900">BERITA TERKINI</h2>
<div className="w-14 h-1 bg-green-600 mt-1 mb-4"></div> <div className="w-14 h-1 bg-blue-600 mt-1 mb-4"></div>
<div className="space-y-6"> <div className="space-y-6">
{articles.map((item) => ( {articles.map((item) => (
@ -81,7 +81,7 @@ export default function NewsTerkini() {
<div className="flex gap-4"> <div className="flex gap-4">
<div className="flex-1"> <div className="flex-1">
{/* CATEGORY */} {/* CATEGORY */}
<p className="text-[11px] text-green-700 font-semibold mb-1"> <p className="text-[11px] text-blue-700 font-semibold mb-1">
{item.categories?.[0]?.title || "Kategori"} {item.categories?.[0]?.title || "Kategori"}
</p> </p>
@ -98,7 +98,15 @@ export default function NewsTerkini() {
{/* AUTHOR + DATE */} {/* AUTHOR + DATE */}
<p className="text-xs text-gray-400 mt-2"> <p className="text-xs text-gray-400 mt-2">
By {item.customCreatorName || item.createdByName} {" "} By {item.customCreatorName || item.createdByName} {" "}
{formatDate(item.publishedAt)} <span>
{new Date(
item.publishedAt || item.createdAt,
).toLocaleDateString("id-ID", {
day: "numeric",
month: "long",
year: "numeric",
})}
</span>
</p> </p>
</div> </div>
<div className="relative w-40 h-28 rounded overflow-hidden flex-shrink-0"> <div className="relative w-40 h-28 rounded overflow-hidden flex-shrink-0">
@ -115,14 +123,14 @@ export default function NewsTerkini() {
</div> </div>
{/* LOAD MORE */} {/* LOAD MORE */}
<div className="text-center mt-4 text-green-600 text-sm cursor-pointer"> <div className="text-center mt-4 text-blue-600 text-sm cursor-pointer">
LOAD MORE LOAD MORE
</div> </div>
</div> </div>
<div className="lg:col-span-1"> <div className="lg:col-span-1">
<h2 className="text-lg font-bold text-gray-900">TERBANYAK DIBAGIKAN</h2> <h2 className="text-lg font-bold text-gray-900">TERBANYAK DIBAGIKAN</h2>
<div className="w-14 h-1 bg-green-600 mt-1 mb-4"></div> <div className="w-14 h-1 bg-blue-600 mt-1 mb-4"></div>
<div className="space-y-4"> <div className="space-y-4">
{popular.map((item, index) => ( {popular.map((item, index) => (
@ -132,7 +140,7 @@ export default function NewsTerkini() {
className="flex gap-3 border-b pb-4" className="flex gap-3 border-b pb-4"
> >
{/* NOMOR */} {/* NOMOR */}
<div className="text-green-600 font-extrabold text-3xl leading-none"> <div className="text-blue-600 font-extrabold text-3xl leading-none">
{(index + 1).toString().padStart(2, "0")} {(index + 1).toString().padStart(2, "0")}
</div> </div>

View File

@ -63,7 +63,7 @@ export default function LatestNews() {
{/* TITLE */} {/* TITLE */}
<div className="mb-4"> <div className="mb-4">
<h2 className="text-xl font-black text-[#000]">BERITA POPULER</h2> <h2 className="text-xl font-black text-[#000]">BERITA POPULER</h2>
<div className="w-10 h-1 bg-green-600 mt-1 rounded"></div> <div className="w-10 h-1 bg-blue-600 mt-1 rounded"></div>
</div> </div>
{/* GRID 4 KOLOM */} {/* GRID 4 KOLOM */}
@ -82,7 +82,7 @@ export default function LatestNews() {
{/* BADGE CATEGORY DI DALAM GAMBAR */} {/* BADGE CATEGORY DI DALAM GAMBAR */}
<div className="absolute bottom-2 left-2"> <div className="absolute bottom-2 left-2">
<span className="px-3 py-1 text-[10px] font-semibold bg-green-600 text-white rounded"> <span className="px-3 py-1 text-[10px] font-semibold bg-blue-600 text-white rounded">
{item.categories?.[0]?.title || "Kategori"} {item.categories?.[0]?.title || "Kategori"}
</span> </span>
</div> </div>
@ -100,7 +100,9 @@ export default function LatestNews() {
</span> </span>
<span className="text-yellow-500">-</span> <span className="text-yellow-500">-</span>
<span> <span>
{new Date(item.publishedAt).toLocaleDateString("id-ID", { {new Date(
item.publishedAt || item.createdAt,
).toLocaleDateString("id-ID", {
day: "numeric", day: "numeric",
month: "long", month: "long",
year: "numeric", year: "numeric",

View File

@ -1,129 +1,36 @@
// components/landing-page/navbar.tsx
"use client"; "use client";
import { useState } from "react"; import { Search } from "lucide-react";
import Image from "next/image"; import Image from "next/image";
import { Search, Menu } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
export default function Navbar() { export default function Navbar() {
const [open, setOpen] = useState(false);
const pathname = usePathname(); const pathname = usePathname();
const isActive = (href: any) => {
return pathname === href || pathname.startsWith(href + "/");
};
return ( return (
<header className="w-full bg-[#022b5f] text-white"> <div className="w-full bg-white py-4 border-b">
<div className="max-w-7xl mx-auto px-2 py-2"> <div className="max-w-screen-xl mx-auto flex flex-col justify-between px-4">
<div className="flex items-center justify-between px-6 py-2 border-b border-[#053d84]"> {/* Left: Logo */}
{/* Logo + Search */} <div className="flex flex-row justify-between mb-3">
<div className="flex items-center gap-4"> <div className="flex items-center">
<Image src="/bumn.png" alt="Logo" width={40} height={40} /> <Image
<div className="relative"> src="/berita-bumn-logo.png"
<input alt="Kritik Tajam Logo"
type="text" width={140}
placeholder="Search..." height={100}
className="px-3 py-2 rounded-md w-[280px] text-black focus:outline-none bg-white" />
/>
<Search
className="absolute right-2 top-2.5 text-white"
size={18}
/>
</div>
</div> </div>
{/* Date + Login */}
<div className="flex items-center gap-4 text-sm">
<span>Jumat, April 18, 2025</span>
<Link
href="/auth"
className="flex items-center gap-1 font-semibold"
>
Login
</Link>
</div>
</div>
{/* NAVBAR */}
<div className="flex items-center justify-between px-6 py-3">
{/* Left: Menu Items */}
<div className="flex items-center gap-6"> <div className="flex items-center gap-6">
<button onClick={() => setOpen(!open)}> {/* Social Icons */}
<Menu className="text-white" /> <div className="hidden md:flex items-center gap-5 text-black text-xl">
</button> <Link href="#">
<nav className="hidden md:flex gap-6 text-sm font-semibold">
<Link
href="/"
className={pathname === "/" ? "text-yellow-400" : ""}
>
HOME
</Link>
<Link
href="/category/bumn"
className={
pathname === "/category/bumn" ? "text-yellow-400" : ""
}
>
SEPUTAR BUMN
</Link>
<Link
href="/category/economy"
className={
pathname === "/category/economy" ? "text-yellow-400" : ""
}
>
ECONOMY
</Link>
<Link
href="/category/business"
className={
pathname === "/category/business" ? "text-yellow-400" : ""
}
>
BUSINESS
</Link>
<Link
href="/category/opinion"
className={
pathname === "/category/opinion" ? "text-yellow-400" : ""
}
>
OPINION
</Link>
<Link
href="/category/markets"
className={
pathname === "/category/markets" ? "text-yellow-400" : ""
}
>
MARKETS
</Link>
<Link
href="/category/tech"
className={
pathname === "/category/tech" ? "text-yellow-400" : ""
}
>
TECH
</Link>
<Link
href="/category/real-estate"
className={
pathname === "/category/real-estate" ? "text-yellow-400" : ""
}
>
REAL ESTATE
</Link>
</nav>
</div>
{/* Right: Socials + Subscribe */}
<div className="flex items-center gap-4">
<div className="flex gap-3 text-white text-lg">
<Link href="#" aria-label="Facebook">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="15" width="18"
height="15"
viewBox="0 0 24 24" viewBox="0 0 24 24"
> >
<path <path
@ -132,11 +39,11 @@ export default function Navbar() {
/> />
</svg> </svg>
</Link> </Link>
<Link href="#" aria-label="Twitter">
<Link href="#">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="15" width="18"
height="15"
viewBox="0 0 24 24" viewBox="0 0 24 24"
> >
<path <path
@ -145,95 +52,157 @@ export default function Navbar() {
/> />
</svg> </svg>
</Link> </Link>
<Link href="#" aria-label="Google" className="text-[#F5F5F5]">
<Link href="#">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="15" width="18"
height="15"
viewBox="0 0 24 24" viewBox="0 0 24 24"
> >
<path <path
fill="currentColor" fill="currentColor"
// fill-rule="evenodd" d="M7.8 2h8.4C19.4 2 22 4.6 22 7.8v8.4a5.8 5.8 0 0 1-5.8 5.8H7.8C4.6 22 2 19.4 2 16.2V7.8A5.8 5.8 0 0 1 7.8 2m-.2 2A3.6 3.6 0 0 0 4 7.6v8.8C4 18.39 5.61 20 7.6 20h8.8a3.6 3.6 0 0 0 3.6-3.6V7.6C20 5.61 18.39 4 16.4 4zm9.65 1.5a1.25 1.25 0 0 1 1.25 1.25A1.25 1.25 0 0 1 17.25 8A1.25 1.25 0 0 1 16 6.75a1.25 1.25 0 0 1 1.25-1.25M12 7a5 5 0 0 1 5 5a5 5 0 0 1-5 5a5 5 0 0 1-5-5a5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3a3 3 0 0 0 3 3a3 3 0 0 0 3-3a3 3 0 0 0-3-3"
d="M7.796 14.333v-2.618h7.211c.066.382.12.763.12 1.265c0 4.364-2.923 7.462-7.33 7.462A7.63 7.63 0 0 1 .16 12.806a7.63 7.63 0 0 1 7.636-7.637c2.062 0 3.786.753 5.117 1.997L10.84 9.162c-.567-.546-1.56-1.178-3.044-1.178c-2.607 0-4.734 2.16-4.734 4.822s2.127 4.821 4.734 4.821c3.022 0 4.157-2.17 4.331-3.294zm13.27-2.6H23.2v2.134h-2.133V16h-2.134v-2.133H16.8v-2.134h2.133V9.6h2.134z"
// clip-rule="evenodd"
/> />
</svg> </svg>
</Link> </Link>
<Link href="#" aria-label="Pinterest">
<svg
xmlns="http://www.w3.org/2000/svg"
width="15"
height="15"
viewBox="0 0 24 24"
>
<defs>
<path
id="akarIconsPinterestFill0"
fill="#fff"
d="M0 0h24v24H0z"
/>
</defs>
<g fill="none">
<g
// clip-path="url(#akarIconsPinterestFill1)"
>
<g
// clip-path="url(#akarIconsPinterestFill2)"
>
<path
fill="currentColor"
d="M0 12c0 5.123 3.211 9.497 7.73 11.218c-.11-.937-.227-2.482.025-3.566c.217-.932 1.401-5.938 1.401-5.938s-.357-.715-.357-1.774c0-1.66.962-2.9 2.161-2.9c1.02 0 1.512.765 1.512 1.682c0 1.025-.653 2.557-.99 3.978c-.281 1.189.597 2.159 1.769 2.159c2.123 0 3.756-2.239 3.756-5.471c0-2.861-2.056-4.86-4.991-4.86c-3.398 0-5.393 2.549-5.393 5.184c0 1.027.395 2.127.889 2.726a.36.36 0 0 1 .083.343c-.091.378-.293 1.189-.332 1.355c-.053.218-.173.265-.4.159c-1.492-.694-2.424-2.875-2.424-4.627c0-3.769 2.737-7.229 7.892-7.229c4.144 0 7.365 2.953 7.365 6.899c0 4.117-2.595 7.431-6.199 7.431c-1.211 0-2.348-.63-2.738-1.373c0 0-.599 2.282-.744 2.84c-.282 1.084-1.064 2.456-1.549 3.235C9.584 23.815 10.77 24 12 24c6.627 0 12-5.373 12-12S18.627 0 12 0S0 5.373 0 12"
/>
</g>
</g>
<defs>
<clipPath id="akarIconsPinterestFill1">
<use href="#akarIconsPinterestFill0" />
</clipPath>
<clipPath id="akarIconsPinterestFill2">
<use href="#akarIconsPinterestFill0" />
</clipPath>
</defs>
</g>
</svg>
</Link>
<Link href="#" aria-label="Vk"> <Link href="#">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="15" width="18"
height="15"
viewBox="0 0 24 24" viewBox="0 0 24 24"
> >
<path <path
fill="currentColor" fill="currentColor"
// fill-rule="evenodd" d="M12.244 4c.534.003 1.87.016 3.29.073l.504.022c1.429.067 2.857.183 3.566.38c.945.266 1.687 1.04 1.938 2.022c.4 1.56.45 4.602.456 5.339l.001.152v.174c-.007.737-.057 3.78-.457 5.339c-.254.985-.997 1.76-1.938 2.022c-.709.197-2.137.313-3.566.38l-.504.023c-1.42.056-2.756.07-3.29.072l-.235.001h-.255c-1.13-.007-5.856-.058-7.36-.476c-.944-.266-1.687-1.04-1.938-2.022c-.4-1.56-.45-4.602-.456-5.339v-.326c.006-.737.056-3.78.456-5.339c.254-.985.997-1.76 1.939-2.021c1.503-.419 6.23-.47 7.36-.476zM9.999 8.5v7l6-3.5z"
d="M23.45 5.948c.166-.546 0-.948-.795-.948H20.03c-.668 0-.976.347-1.143.73c0 0-1.335 3.196-3.226 5.272c-.612.602-.89.793-1.224.793c-.167 0-.418-.191-.418-.738V5.948c0-.656-.184-.948-.74-.948H9.151c-.417 0-.668.304-.668.593c0 .621.946.765 1.043 2.513v3.798c0 .833-.153.984-.487.984c-.89 0-3.055-3.211-4.34-6.885C4.45 5.288 4.198 5 3.527 5H.9c-.75 0-.9.347-.9.73c0 .682.89 4.07 4.145 8.551C6.315 17.341 9.37 19 12.153 19c1.669 0 1.875-.368 1.875-1.003v-2.313c0-.737.158-.884.687-.884c.39 0 1.057.192 2.615 1.667C19.11 18.216 19.403 19 20.405 19h2.625c.75 0 1.126-.368.91-1.096c-.238-.724-1.088-1.775-2.215-3.022c-.612-.71-1.53-1.475-1.809-1.858c-.389-.491-.278-.71 0-1.147c0 0 3.2-4.426 3.533-5.929"
// clip-rule="evenodd"
/>
</svg>
</Link>
<Link href="#" aria-label="Wifi">
<svg
xmlns="http://www.w3.org/2000/svg"
width="15"
height="15"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M12 21q-1.05 0-1.775-.725T9.5 18.5t.725-1.775T12 16t1.775.725t.725 1.775t-.725 1.775T12 21m-5.65-5.65l-2.1-2.15q1.475-1.475 3.463-2.337T12 10t4.288.875t3.462 2.375l-2.1 2.1q-1.1-1.1-2.55-1.725T12 13t-3.1.625t-2.55 1.725M2.1 11.1L0 9q2.3-2.35 5.375-3.675T12 4t6.625 1.325T24 9l-2.1 2.1q-1.925-1.925-4.462-3.012T12 7T6.563 8.088T2.1 11.1"
/> />
</svg> </svg>
</Link> </Link>
</div> </div>
<button className="bg-yellow-400 text-black px-4 py-2 rounded-sm font-semibold"> </div>
SUBSCRIBE </div>
{/* Middle Menu */}
<div className="flex flex-row justify-between">
<nav className="hidden md:flex items-center gap-10 text-sm font-semibold">
<Link
href="/"
className={
isActive("/")
? "text-blue-400 underline"
: "text-black hover:text-blue-500"
}
>
HOME
</Link>
<Link
href="/category/bumn"
className={
isActive("/category/bumn")
? "text-blue-400 underline"
: "text-black hover:text-blue-500"
}
>
SEPUTAR BUMN
</Link>
<Link
href="/category/economy"
className={
isActive("/category/economy")
? "text-blue-400 underline"
: "text-black hover:text-blue-500"
}
>
ECONOMY
</Link>
<Link
href="/category/business"
className={
isActive("/category/business")
? "text-blue-400 underline"
: "text-black hover:text-blue-500"
}
>
BUSINESS
</Link>
<Link
href="/category/opinion"
className={
isActive("/category/opinion")
? "text-blue-400 underline"
: "text-black hover:text-blue-500"
}
>
OPINION
</Link>
<Link
href="/category/markets"
className={
isActive("/category/markets")
? "text-blue-400 underline"
: "text-black hover:text-blue-500"
}
>
MARKETS
</Link>
<Link
href="/category/tech"
className={
isActive("/category/tech")
? "text-blue-400 underline"
: "text-black hover:text-blue-500"
}
>
TECH
</Link>
<Link
href="/category/real-estate"
className={
isActive("/category/real-estate")
? "text-blue-400 underline"
: "text-black hover:text-blue-500"
}
>
REAL ESTATE
</Link>
</nav>
<div className="flex items-center gap-2">
<button
// onClick={() => document.documentElement.classList.toggle("dark")}
className="w-10 h-5 rounded-full bg-gray-300 dark:bg-gray-700 relative transition-all"
>
<div className="w-5 h-5 bg-white dark:bg-black rounded-full shadow absolute top-0 left-0 dark:left-5 transition-all"></div>
</button> </button>
{/* BURGER BUTTON (mobile menu) */}
<button className="md:hidden p-2 rounded-lg border">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2}
stroke="currentColor"
className="w-6 h-6"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
</button>
<button className="p-2 border rounded-full">
<Search size={15} />
</button>
<Link href={"/auth"}>
<button className="bg-blue-600 text-white px-5 py-2 rounded-full text-sm font-semibold">
LOGIN
</button>
</Link>
</div> </div>
</div> </div>
</div> </div>
</header> </div>
); );
} }

View File

@ -63,7 +63,7 @@ export default function OpinionNews() {
{/* TITLE */} {/* TITLE */}
<div className="mb-4"> <div className="mb-4">
<h2 className="text-xl font-black text-[#000]">BERITA OPINI</h2> <h2 className="text-xl font-black text-[#000]">BERITA OPINI</h2>
<div className="w-10 h-1 bg-green-600 mt-1 rounded"></div> <div className="w-10 h-1 bg-blue-600 mt-1 rounded"></div>
</div> </div>
{/* GRID 4 KOLOM */} {/* GRID 4 KOLOM */}
@ -82,7 +82,7 @@ export default function OpinionNews() {
{/* BADGE CATEGORY DI DALAM GAMBAR */} {/* BADGE CATEGORY DI DALAM GAMBAR */}
<div className="absolute bottom-2 left-2"> <div className="absolute bottom-2 left-2">
<span className="px-3 py-1 text-[10px] font-semibold bg-green-600 text-white rounded"> <span className="px-3 py-1 text-[10px] font-semibold bg-blue-600 text-white rounded">
{item.categories?.[0]?.title || "Kategori"} {item.categories?.[0]?.title || "Kategori"}
</span> </span>
</div> </div>
@ -100,7 +100,9 @@ export default function OpinionNews() {
</span> </span>
<span className="text-yellow-500">-</span> <span className="text-yellow-500">-</span>
<span> <span>
{new Date(item.publishedAt).toLocaleDateString("id-ID", { {new Date(
item.publishedAt || item.createdAt,
).toLocaleDateString("id-ID", {
day: "numeric", day: "numeric",
month: "long", month: "long",
year: "numeric", year: "numeric",

View File

@ -316,7 +316,7 @@ export default function ArticleTable() {
return cellValue; return cellValue;
} }
}, },
[article, page] [article, page],
); );
let typingTimer: NodeJS.Timeout; let typingTimer: NodeJS.Timeout;
@ -445,8 +445,8 @@ export default function ArticleTable() {
</div> </div>
</div> </div>
<div className="w-full overflow-x-hidden"> <div className="w-full overflow-x-hidden">
<div className="w-full mx-auto overflow-x-hidden"> <div className="w-full overflow-x-auto">
<Table className="w-full table-fixed border text-sm"> <Table className="min-w-[1000px] w-full table-auto border text-sm">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
{(username === "admin-mabes" {(username === "admin-mabes"
@ -455,7 +455,18 @@ export default function ArticleTable() {
).map((column) => ( ).map((column) => (
<TableHead <TableHead
key={column.uid} key={column.uid}
className="truncate bg-white dark:bg-black text-black dark:text-white border-b text-md" className={`bg-white dark:bg-black text-black dark:text-white
text-sm font-semibold border-b px-3 py-3
${
column.uid === "no"
? "min-w-[60px] text-center"
: column.uid === "title"
? "min-w-[280px]"
: column.uid === "actions"
? "min-w-[100px] text-center"
: "min-w-[160px]"
}
`}
> >
{column.name} {column.name}
</TableHead> </TableHead>
@ -472,7 +483,17 @@ export default function ArticleTable() {
).map((column) => ( ).map((column) => (
<TableCell <TableCell
key={column.uid} key={column.uid}
className="truncate text-black dark:text-white max-w-[200px]" className={`text-black dark:text-white text-sm px-3 py-3 align-top
${
column.uid === "no"
? "min-w-[60px] text-center font-medium"
: column.uid === "title"
? "min-w-[280px] whitespace-normal break-words leading-snug"
: column.uid === "actions"
? "min-w-[100px] text-center"
: "min-w-[160px] whitespace-normal break-words"
}
`}
> >
{renderCell(item, column.uid)} {renderCell(item, column.uid)}
</TableCell> </TableCell>

View File

@ -1,13 +1,11 @@
import type { NextConfig } from "next"; /** @type {import('next').NextConfig} */
const nextConfig = {
const nextConfig: NextConfig = {
images: { images: {
domains: ["mikulnews.com", "dev.mikulnews.com"], domains: ["mikulnews.com", "dev.mikulnews.com"],
}, },
eslint: { eslint: {
ignoreDuringBuilds: true, ignoreDuringBuilds: true,
}, },
// Add experimental features for better chunk handling
experimental: { experimental: {
optimizePackageImports: ["@ckeditor/ckeditor5-react", "react-apexcharts"], optimizePackageImports: ["@ckeditor/ckeditor5-react", "react-apexcharts"],
}, },

367
package-lock.json generated
View File

@ -37,12 +37,12 @@
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lightningcss": "^1.30.1", "lightningcss": "^1.30.1",
"lucide-react": "^0.544.0", "lucide-react": "^0.544.0",
"next": "15.5.3", "next": "^16.1.1",
"react": "19.1.0", "react": "^19.2.3",
"react-apexcharts": "^1.7.0", "react-apexcharts": "^1.7.0",
"react-datepicker": "^8.4.0", "react-datepicker": "^8.4.0",
"react-day-picker": "^9.7.0", "react-day-picker": "^9.7.0",
"react-dom": "19.1.0", "react-dom": "^19.2.4",
"react-dropzone": "^14.3.8", "react-dropzone": "^14.3.8",
"react-hook-form": "^7.59.0", "react-hook-form": "^7.59.0",
"react-password-checklist": "^1.8.1", "react-password-checklist": "^1.8.1",
@ -1413,9 +1413,9 @@
} }
}, },
"node_modules/@img/sharp-win32-x64": { "node_modules/@img/sharp-win32-x64": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz", "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
"integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==", "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1489,9 +1489,9 @@
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==" "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="
}, },
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "15.5.3", "version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.3.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.1.tgz",
"integrity": "sha512-RSEDTRqyihYXygx/OJXwvVupfr9m04+0vH8vyy0HfZ7keRto6VX9BbEk0J2PUk0VGy6YhklJUSrgForov5F9pw==" "integrity": "sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA=="
}, },
"node_modules/@next/eslint-plugin-next": { "node_modules/@next/eslint-plugin-next": {
"version": "15.5.3", "version": "15.5.3",
@ -1502,115 +1502,10 @@
"fast-glob": "3.3.1" "fast-glob": "3.3.1"
} }
}, },
"node_modules/@next/swc-darwin-arm64": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.3.tgz",
"integrity": "sha512-nzbHQo69+au9wJkGKTU9lP7PXv0d1J5ljFpvb+LnEomLtSbJkbZyEs6sbF3plQmiOB2l9OBtN2tNSvCH1nQ9Jg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.3.tgz",
"integrity": "sha512-w83w4SkOOhekJOcA5HBvHyGzgV1W/XvOfpkrxIse4uPWhYTTRwtGEM4v/jiXwNSJvfRvah0H8/uTLBKRXlef8g==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.3.tgz",
"integrity": "sha512-+m7pfIs0/yvgVu26ieaKrifV8C8yiLe7jVp9SpcIzg7XmyyNE7toC1fy5IOQozmr6kWl/JONC51osih2RyoXRw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.3.tgz",
"integrity": "sha512-u3PEIzuguSenoZviZJahNLgCexGFhso5mxWCrrIMdvpZn6lkME5vc/ADZG8UUk5K1uWRy4hqSFECrON6UKQBbQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.3.tgz",
"integrity": "sha512-lDtOOScYDZxI2BENN9m0pfVPJDSuUkAD1YXSvlJF0DKwZt0WlA7T7o3wrcEr4Q+iHYGzEaVuZcsIbCps4K27sA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.3.tgz",
"integrity": "sha512-9vWVUnsx9PrY2NwdVRJ4dUURAQ8Su0sLRPqcCCxtX5zIQUBES12eRVHq6b70bbfaVaxIDGJN2afHui0eDm+cLg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "15.5.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.3.tgz",
"integrity": "sha512-1CU20FZzY9LFQigRi6jM45oJMU3KziA5/sSG+dXeVaTm661snQP6xu3ykGxxwU5sLG3sh14teO/IOEPVsQMRfA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-x64-msvc": { "node_modules/@next/swc-win32-x64-msvc": {
"version": "15.5.3", "version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.3.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.1.tgz",
"integrity": "sha512-JMoLAq3n3y5tKXPQwCK5c+6tmwkuFDa2XAxz8Wm4+IVthdBZdZGh+lmiLUHg9f9IDwIQpUjp+ysd6OkYTyZRZw==", "integrity": "sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -3441,6 +3336,14 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true "dev": true
}, },
"node_modules/baseline-browser-mapping": {
"version": "2.9.11",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz",
"integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
}
},
"node_modules/blurhash": { "node_modules/blurhash": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/blurhash/-/blurhash-2.0.5.tgz", "resolved": "https://registry.npmjs.org/blurhash/-/blurhash-2.0.5.tgz",
@ -3523,9 +3426,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001743", "version": "1.0.30001761",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz",
"integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==", "integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -3874,9 +3777,9 @@
} }
}, },
"node_modules/detect-libc": { "node_modules/detect-libc": {
"version": "2.1.0", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@ -5872,12 +5775,13 @@
"dev": true "dev": true
}, },
"node_modules/next": { "node_modules/next": {
"version": "15.5.3", "version": "16.1.1",
"resolved": "https://registry.npmjs.org/next/-/next-15.5.3.tgz", "resolved": "https://registry.npmjs.org/next/-/next-16.1.1.tgz",
"integrity": "sha512-r/liNAx16SQj4D+XH/oI1dlpv9tdKJ6cONYPwwcCC46f2NjpaRWY+EKCzULfgQYV6YKXjHBchff2IZBSlZmJNw==", "integrity": "sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==",
"dependencies": { "dependencies": {
"@next/env": "15.5.3", "@next/env": "16.1.1",
"@swc/helpers": "0.5.15", "@swc/helpers": "0.5.15",
"baseline-browser-mapping": "^2.8.3",
"caniuse-lite": "^1.0.30001579", "caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31", "postcss": "8.4.31",
"styled-jsx": "5.1.6" "styled-jsx": "5.1.6"
@ -5886,18 +5790,18 @@
"next": "dist/bin/next" "next": "dist/bin/next"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0" "node": ">=20.9.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@next/swc-darwin-arm64": "15.5.3", "@next/swc-darwin-arm64": "16.1.1",
"@next/swc-darwin-x64": "15.5.3", "@next/swc-darwin-x64": "16.1.1",
"@next/swc-linux-arm64-gnu": "15.5.3", "@next/swc-linux-arm64-gnu": "16.1.1",
"@next/swc-linux-arm64-musl": "15.5.3", "@next/swc-linux-arm64-musl": "16.1.1",
"@next/swc-linux-x64-gnu": "15.5.3", "@next/swc-linux-x64-gnu": "16.1.1",
"@next/swc-linux-x64-musl": "15.5.3", "@next/swc-linux-x64-musl": "16.1.1",
"@next/swc-win32-arm64-msvc": "15.5.3", "@next/swc-win32-arm64-msvc": "16.1.1",
"@next/swc-win32-x64-msvc": "15.5.3", "@next/swc-win32-x64-msvc": "16.1.1",
"sharp": "^0.34.3" "sharp": "^0.34.4"
}, },
"peerDependencies": { "peerDependencies": {
"@opentelemetry/api": "^1.1.0", "@opentelemetry/api": "^1.1.0",
@ -6294,9 +6198,9 @@
] ]
}, },
"node_modules/react": { "node_modules/react": {
"version": "19.1.0", "version": "19.2.4",
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@ -6348,14 +6252,14 @@
} }
}, },
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "19.1.0", "version": "19.2.4",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
"dependencies": { "dependencies": {
"scheduler": "^0.26.0" "scheduler": "^0.27.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^19.1.0" "react": "^19.2.4"
} }
}, },
"node_modules/react-dropzone": { "node_modules/react-dropzone": {
@ -6667,14 +6571,14 @@
} }
}, },
"node_modules/scheduler": { "node_modules/scheduler": {
"version": "0.26.0", "version": "0.27.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==" "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "7.7.2", "version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"devOptional": true, "devOptional": true,
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
@ -6730,15 +6634,15 @@
} }
}, },
"node_modules/sharp": { "node_modules/sharp": {
"version": "0.34.4", "version": "0.34.5",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
"integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==", "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
"hasInstallScript": true, "hasInstallScript": true,
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"@img/colour": "^1.0.0", "@img/colour": "^1.0.0",
"detect-libc": "^2.1.0", "detect-libc": "^2.1.2",
"semver": "^7.7.2" "semver": "^7.7.3"
}, },
"engines": { "engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0" "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@ -6747,28 +6651,30 @@
"url": "https://opencollective.com/libvips" "url": "https://opencollective.com/libvips"
}, },
"optionalDependencies": { "optionalDependencies": {
"@img/sharp-darwin-arm64": "0.34.4", "@img/sharp-darwin-arm64": "0.34.5",
"@img/sharp-darwin-x64": "0.34.4", "@img/sharp-darwin-x64": "0.34.5",
"@img/sharp-libvips-darwin-arm64": "1.2.3", "@img/sharp-libvips-darwin-arm64": "1.2.4",
"@img/sharp-libvips-darwin-x64": "1.2.3", "@img/sharp-libvips-darwin-x64": "1.2.4",
"@img/sharp-libvips-linux-arm": "1.2.3", "@img/sharp-libvips-linux-arm": "1.2.4",
"@img/sharp-libvips-linux-arm64": "1.2.3", "@img/sharp-libvips-linux-arm64": "1.2.4",
"@img/sharp-libvips-linux-ppc64": "1.2.3", "@img/sharp-libvips-linux-ppc64": "1.2.4",
"@img/sharp-libvips-linux-s390x": "1.2.3", "@img/sharp-libvips-linux-riscv64": "1.2.4",
"@img/sharp-libvips-linux-x64": "1.2.3", "@img/sharp-libvips-linux-s390x": "1.2.4",
"@img/sharp-libvips-linuxmusl-arm64": "1.2.3", "@img/sharp-libvips-linux-x64": "1.2.4",
"@img/sharp-libvips-linuxmusl-x64": "1.2.3", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
"@img/sharp-linux-arm": "0.34.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
"@img/sharp-linux-arm64": "0.34.4", "@img/sharp-linux-arm": "0.34.5",
"@img/sharp-linux-ppc64": "0.34.4", "@img/sharp-linux-arm64": "0.34.5",
"@img/sharp-linux-s390x": "0.34.4", "@img/sharp-linux-ppc64": "0.34.5",
"@img/sharp-linux-x64": "0.34.4", "@img/sharp-linux-riscv64": "0.34.5",
"@img/sharp-linuxmusl-arm64": "0.34.4", "@img/sharp-linux-s390x": "0.34.5",
"@img/sharp-linuxmusl-x64": "0.34.4", "@img/sharp-linux-x64": "0.34.5",
"@img/sharp-wasm32": "0.34.4", "@img/sharp-linuxmusl-arm64": "0.34.5",
"@img/sharp-win32-arm64": "0.34.4", "@img/sharp-linuxmusl-x64": "0.34.5",
"@img/sharp-win32-ia32": "0.34.4", "@img/sharp-wasm32": "0.34.5",
"@img/sharp-win32-x64": "0.34.4" "@img/sharp-win32-arm64": "0.34.5",
"@img/sharp-win32-ia32": "0.34.5",
"@img/sharp-win32-x64": "0.34.5"
} }
}, },
"node_modules/shebang-command": { "node_modules/shebang-command": {
@ -7623,6 +7529,111 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }
},
"node_modules/@next/swc-darwin-arm64": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.1.tgz",
"integrity": "sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.1.tgz",
"integrity": "sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.1.tgz",
"integrity": "sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.1.tgz",
"integrity": "sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.1.tgz",
"integrity": "sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.1.tgz",
"integrity": "sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.1.tgz",
"integrity": "sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
} }
} }
} }

View File

@ -38,12 +38,12 @@
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lightningcss": "^1.30.1", "lightningcss": "^1.30.1",
"lucide-react": "^0.544.0", "lucide-react": "^0.544.0",
"next": "15.5.3", "next": "^16.1.1",
"react": "19.1.0", "react": "^19.2.3",
"react-apexcharts": "^1.7.0", "react-apexcharts": "^1.7.0",
"react-datepicker": "^8.4.0", "react-datepicker": "^8.4.0",
"react-day-picker": "^9.7.0", "react-day-picker": "^9.7.0",
"react-dom": "19.1.0", "react-dom": "^19.2.4",
"react-dropzone": "^14.3.8", "react-dropzone": "^14.3.8",
"react-hook-form": "^7.59.0", "react-hook-form": "^7.59.0",
"react-password-checklist": "^1.8.1", "react-password-checklist": "^1.8.1",

BIN
public/berita-bumn-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

View File

@ -143,6 +143,13 @@ export async function uploadArticleThumbnail(id: string, data: any) {
return await httpPostInterceptor(`/articles/thumbnail/${id}`, data, headers); return await httpPostInterceptor(`/articles/thumbnail/${id}`, data, headers);
} }
export async function getArticleFiles() {
const headers = {
"content-type": "application/json",
};
return await httpGet(`/article-files`, headers);
}
export async function deleteArticleFiles(id: number) { export async function deleteArticleFiles(id: number) {
const headers = { const headers = {
"content-type": "multipart/form-data", "content-type": "multipart/form-data",

View File

@ -1,6 +1,6 @@
import axios from "axios"; import axios from "axios";
const baseURL = "https://dev.mikulnews.com/api"; const baseURL = "https://beritabumn.com/api";
const axiosBaseInstance = axios.create({ const axiosBaseInstance = axios.create({
baseURL, baseURL,

View File

@ -2,7 +2,7 @@ import axios from "axios";
import { postSignIn } from "../master-user"; import { postSignIn } from "../master-user";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
const baseURL = "https://dev.mikulnews.com/api"; const baseURL = "https://beritabumn.com/api";
const refreshToken = Cookies.get("refresh_token"); const refreshToken = Cookies.get("refresh_token");
@ -28,7 +28,7 @@ axiosInterceptorInstance.interceptors.request.use(
}, },
(error) => { (error) => {
return Promise.reject(error); return Promise.reject(error);
} },
); );
// Response interceptor // Response interceptor
@ -66,7 +66,7 @@ axiosInterceptorInstance.interceptors.response.use(
} }
return Promise.reject(error); return Promise.reject(error);
} },
); );
export default axiosInterceptorInstance; export default axiosInterceptorInstance;

121
styles/custom-editor.css Normal file
View File

@ -0,0 +1,121 @@
/* ========== CKEditor Wrapper ========== */
.ckeditor-wrapper {
border-radius: 6px;
overflow: hidden;
box-shadow:
0 1px 3px 0 rgba(0, 0, 0, 0.1),
0 1px 2px 0 rgba(0, 0, 0, 0.06);
}
/* ========== Main Editor Container ========== */
.ckeditor-wrapper .ck.ck-editor__main {
min-height: var(--editor-min-height, 400px);
max-height: var(--editor-max-height, 600px);
}
/* ========== Editable Content Area (ClassicEditor) ========== */
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline {
min-height: calc(var(--editor-min-height, 400px) - 50px);
max-height: calc(var(--editor-max-height, 600px) - 50px);
overflow-y: auto !important;
scrollbar-width: thin;
scrollbar-color: #cbd5e1 #f1f5f9;
background: #fff !important;
color: #111 !important;
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
font-size: 14px;
line-height: 1.6;
padding: 1rem;
border: none !important;
}
/* ========== Headings and Text Formatting ========== */
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h1,
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h2,
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h3,
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h4,
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h5,
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h6 {
margin: 1em 0 0.5em 0;
color: inherit !important;
}
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline p {
margin: 0.5em 0 !important;
}
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline ul,
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline ol {
margin: 0.5em 0;
padding-left: 2em;
}
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline blockquote {
margin: 1em 0;
padding: 0.5em 1em;
border-left: 4px solid #d1d5db;
background-color: #f9fafb;
color: inherit !important;
}
/* ========== Dark Mode Support ========== */
.dark .ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline {
background: #111 !important;
color: #f9fafb !important;
}
.dark .ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h1,
.dark .ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h2,
.dark .ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h3,
.dark .ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h4,
.dark .ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h5,
.dark .ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline h6 {
color: #f9fafb !important;
}
.dark .ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline blockquote {
background-color: #1f2937 !important;
border-left-color: #374151 !important;
color: #f3f4f6 !important;
}
/* ========== Custom Scrollbars (Light & Dark) ========== */
.ckeditor-wrapper .ck.ck-content.ck-editor__editable_inline::-webkit-scrollbar {
width: 8px;
}
.ckeditor-wrapper
.ck.ck-content.ck-editor__editable_inline::-webkit-scrollbar-track {
background: #f1f5f9;
border-radius: 4px;
}
.ckeditor-wrapper
.ck.ck-content.ck-editor__editable_inline::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
}
.ckeditor-wrapper
.ck.ck-content.ck-editor__editable_inline::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
.dark
.ckeditor-wrapper
.ck.ck-content.ck-editor__editable_inline::-webkit-scrollbar-track {
background: #1f2937;
}
.dark
.ckeditor-wrapper
.ck.ck-content.ck-editor__editable_inline::-webkit-scrollbar-thumb {
background: #4b5563;
}
.dark
.ckeditor-wrapper
.ck.ck-content.ck-editor__editable_inline::-webkit-scrollbar-thumb:hover {
background: #6b7280;
}

View File

@ -1,7 +1,11 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2017", "target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"], "lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true, "allowJs": true,
"skipLibCheck": true, "skipLibCheck": true,
"strict": true, "strict": true,
@ -11,7 +15,7 @@
"moduleResolution": "bundler", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"jsx": "preserve", "jsx": "react-jsx",
"incremental": true, "incremental": true,
"plugins": [ "plugins": [
{ {
@ -19,9 +23,19 @@
} }
], ],
"paths": { "paths": {
"@/*": ["./*"] "@/*": [
"./*"
]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": [
"exclude": ["node_modules"] "next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
} }