diff --git a/.env b/.env
new file mode 100644
index 0000000..f104216
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+MEDOLS_CLIENT_KEY=bb65b1ad-e954-4a1a-b4d0-74df5bb0b640
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index bfe57c0..acf2fe1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,9 +30,6 @@ yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
-# env files (can opt-in for committing if needed)
-.env*
-
# vercel
.vercel
diff --git a/Dockerfile b/Dockerfile
index 335d444..2b874db 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,6 +16,9 @@ COPY package.json ./
# Menyalin direktori ckeditor5 jika diperlukan
COPY vendor/ckeditor5 ./vendor/ckeditor5
+# Menyalin env
+COPY .env .env
+
# Install dependencies
RUN pnpm install
# RUN pnpm install --frozen-lockfile
diff --git a/app/category/popular/page.tsx b/app/category/popular/page.tsx
index 3684a13..60e05d8 100644
--- a/app/category/popular/page.tsx
+++ b/app/category/popular/page.tsx
@@ -1,10 +1,6 @@
-import Author from "@/components/landing-page/author";
import Footer from "@/components/landing-page/footer";
import Header from "@/components/landing-page/header";
-import Latest from "@/components/landing-page/latest";
-import LatestandPopular from "@/components/landing-page/latest-and-popular";
import Navbar from "@/components/landing-page/navbar";
-import News from "@/components/landing-page/news";
import Image from "next/image";
export default function Home() {
diff --git a/app/layout.tsx b/app/layout.tsx
index 63e2178..e9bc5ad 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,6 +1,8 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
+import ChunkErrorBoundary from "@/components/layout/chunk-error-boundary";
+import "@/utils/chunk-error-handler";
const geistSans = Geist({
variable: "--font-geist-sans",
@@ -25,7 +27,9 @@ export default function RootLayout({
return (
- {children}
+
+ {children}
+
);
diff --git a/components/form/article/create-article-form.tsx b/components/form/article/create-article-form.tsx
index cfe4e28..1f6b448 100644
--- a/components/form/article/create-article-form.tsx
+++ b/components/form/article/create-article-form.tsx
@@ -27,7 +27,7 @@ import {
saveManualContext,
updateManualArticle,
} from "@/service/generate-article";
-import { getUserLevels } from "@/service/user-levels/user-levels-service";
+import { getUserLevels } from "@/service/user-levels-service";
import { Checkbox } from "@/components/ui/checkbox";
import { Button } from "@/components/ui/button";
import { getCategoryById } from "@/service/master-categories";
diff --git a/components/form/form-master-user-edit.tsx b/components/form/form-master-user-edit.tsx
index 75c3b5f..75b2654 100644
--- a/components/form/form-master-user-edit.tsx
+++ b/components/form/form-master-user-edit.tsx
@@ -12,7 +12,7 @@ import { z } from "zod";
import ReactSelect from "react-select";
import makeAnimated from "react-select/animated";
import { editMasterUsers, getDetailMasterUsers } from "@/service/master-user";
-import { getAllUserLevels } from "@/service/user-levels/user-levels-service";
+import { getAllUserLevels } from "@/service/user-levels-service";
import { listUserRole } from "@/service/master-user-role";
import { Card } from "../ui/card";
import { Label } from "../ui/label";
diff --git a/components/form/form-master-user.tsx b/components/form/form-master-user.tsx
index de4a3d9..3484c09 100644
--- a/components/form/form-master-user.tsx
+++ b/components/form/form-master-user.tsx
@@ -13,7 +13,7 @@ import ReactSelect from "react-select";
import makeAnimated from "react-select/animated";
import { zodResolver } from "@hookform/resolvers/zod";
import { createMasterUser } from "@/service/master-user";
-import { getAllUserLevels } from "@/service/user-levels/user-levels-service";
+import { getAllUserLevels } from "@/service/user-levels-service";
import { listUserRole } from "@/service/master-user-role";
import { Card } from "../ui/card";
import { Input } from "../ui/input";
diff --git a/components/form/login.tsx b/components/form/login.tsx
index 7eeee15..42e3829 100644
--- a/components/form/login.tsx
+++ b/components/form/login.tsx
@@ -78,13 +78,13 @@ export default function Login() {
secure: true,
sameSite: "strict",
});
- const resActivity = await saveActivity(
+ await saveActivity(
{
activityTypeId: 1,
url: "https://dev.mikulnews.com/auth",
userId: profile?.data?.data?.id,
},
- accessData?.id_token
+ response?.data?.data?.access_token
);
Cookies.set("profile_picture", profile?.data?.data?.profilePictureUrl, {
expires: 1,
diff --git a/components/landing-page/latest-and-popular.tsx b/components/landing-page/latest-and-popular.tsx
index c3942b2..67bdd64 100644
--- a/components/landing-page/latest-and-popular.tsx
+++ b/components/landing-page/latest-and-popular.tsx
@@ -250,7 +250,11 @@ export default function LatestandPopular() {
{
+ constructor(props: Props) {
+ super(props);
+ this.state = { hasError: false };
+ }
+
+ static getDerivedStateFromError(error: Error): State {
+ // Check if it's a chunk loading error
+ if (error.name === 'ChunkLoadError' || error.message.includes('Loading chunk')) {
+ return { hasError: true, error };
+ }
+ return { hasError: false };
+ }
+
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
+ console.error('Chunk loading error:', error, errorInfo);
+
+ // If it's a chunk loading error, try to reload the page
+ if (error.name === 'ChunkLoadError' || error.message.includes('Loading chunk')) {
+ this.setState({ hasError: true, error });
+ }
+ }
+
+ handleRetry = () => {
+ // Clear the error state and reload the page
+ this.setState({ hasError: false, error: undefined });
+ window.location.reload();
+ };
+
+ render() {
+ if (this.state.hasError) {
+ if (this.props.fallback) {
+ return this.props.fallback;
+ }
+
+ return (
+
+
+
+
+
+
+
+ Chunk Loading Error
+
+
+ There was an issue loading a part of the application. This usually happens when the application has been updated.
+
+
+
+
+
+
+
+
+
+ {process.env.NODE_ENV === 'development' && this.state.error && (
+
+
+ Error Details (Development)
+
+
+ {this.state.error.message}
+
+
+ )}
+
+
+ );
+ }
+
+ return this.props.children;
+ }
+}
+
+export default ChunkErrorBoundary;
\ No newline at end of file
diff --git a/components/main/dashboard/chart/column-chart.tsx b/components/main/dashboard/chart/column-chart.tsx
index 747bd02..d29575c 100644
--- a/components/main/dashboard/chart/column-chart.tsx
+++ b/components/main/dashboard/chart/column-chart.tsx
@@ -1,7 +1,7 @@
"use client";
import { getStatisticMonthly } from "@/service/article";
import React, { useEffect, useState } from "react";
-import dynamic from "next/dynamic";
+import { SafeReactApexChart } from "@/utils/dynamic-import";
type WeekData = {
week: number;
@@ -53,9 +53,6 @@ const ApexChartColumn = (props: {
const [seriesComment, setSeriesComment] = useState([]);
const [seriesView, setSeriesView] = useState([]);
const [seriesShare, setSeriesShare] = useState([]);
- const ReactApexChart = dynamic(() => import("react-apexcharts"), {
- ssr: false,
- });
useEffect(() => {
initFetch();
@@ -132,7 +129,7 @@ const ApexChartColumn = (props: {
return (
-
{
- const res = await createAdvertiseById(Number(id));
+ const res = await getAdvertiseById(Number(id));
const data = res?.data?.data;
setValue("id", String(data?.id));
setValue("title", data?.title);
diff --git a/components/table/article-table.tsx b/components/table/article-table.tsx
index ff15804..319f42a 100644
--- a/components/table/article-table.tsx
+++ b/components/table/article-table.tsx
@@ -19,7 +19,7 @@ import Cookies from "js-cookie";
import {
deleteArticle,
getArticleByCategory,
- getListArticle,
+ getArticlePagination,
updateIsBannerArticle,
} from "@/service/article";
import {
@@ -91,9 +91,6 @@ export default function ArticleTable() {
useEffect(() => {
initState();
- }, [page, showData, startDateValue, selectedCategories]);
-
- useEffect(() => {
getCategories();
}, []);
@@ -103,7 +100,7 @@ export default function ArticleTable() {
setCategories(data);
}
- async function initState() {
+ const initState = useCallback(async () => {
loading();
const req = {
limit: showData,
@@ -116,11 +113,11 @@ export default function ArticleTable() {
sort: "desc",
sortBy: "created_at",
};
- const res = await getListArticle(req);
+ const res = await getArticlePagination(req);
await getTableNumber(parseInt(showData), res.data?.data);
setTotalPage(res?.data?.meta?.totalPage);
close();
- }
+ }, [page]);
const getTableNumber = async (limit: number, data: Article[]) => {
if (data) {
diff --git a/next.config.ts b/next.config.ts
index f955c56..9e3686f 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,15 +1,16 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
- env: {
- MEDOLS_CLIENT_KEY: process.env.MEDOLS_CLIENT_KEY,
- },
images: {
domains: ["mikulnews.com", "dev.mikulnews.com"],
},
eslint: {
ignoreDuringBuilds: true,
},
+ // Add experimental features for better chunk handling
+ experimental: {
+ optimizePackageImports: ['@ckeditor/ckeditor5-react', 'react-apexcharts'],
+ },
};
export default nextConfig;
diff --git a/public/default-image.jpg b/public/default-image.jpg
new file mode 100644
index 0000000..ce9446e
Binary files /dev/null and b/public/default-image.jpg differ
diff --git a/service/activity-log.ts b/service/activity-log.ts
index 2056d6f..98634ee 100644
--- a/service/activity-log.ts
+++ b/service/activity-log.ts
@@ -1,5 +1,4 @@
-import { PaginationRequest } from "@/types/globals";
-import { httpGet, httpPost, httpPut } from "./http-config/axios-base-service";
+import { httpGet, httpPost } from "./http-config/http-base-services";
export async function saveActivity(data: any, token?: string) {
const headers = token
@@ -11,11 +10,10 @@ export async function saveActivity(data: any, token?: string) {
"content-type": "application/json",
};
const pathUrl = `/activity-logs`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPost(pathUrl, data, headers);
}
export async function getActivity() {
- const headers = { "content-type": "application/json" };
const pathUrl = `/activity-logs/statistics`;
- return await httpGet(pathUrl, headers);
+ return await httpGet(pathUrl);
}
diff --git a/service/advertisement.ts b/service/advertisement.ts
index fe5fa69..90b5123 100644
--- a/service/advertisement.ts
+++ b/service/advertisement.ts
@@ -1,68 +1,42 @@
-import {
- httpDeleteInterceptor,
- httpGet,
- httpPost,
- httpPut,
-} from "./http-config/axios-base-service";
import Cookies from "js-cookie";
+import { httpDeleteInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
+import { httpGet } from "./http-config/http-base-services";
const token = Cookies.get("access_token");
export async function createAdvertise(data: any) {
- const headers = {
- "content-type": "application/json",
- Authorization: `Bearer ${token}`,
- };
const pathUrl = `/advertisement`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPostInterceptor(pathUrl, data);
}
export async function createMediaFileAdvertise(id: string | number, data: any) {
const headers = {
"content-type": "multipart/form-data",
};
const pathUrl = `/advertisement/upload/${id}`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPostInterceptor(pathUrl, data, headers);
}
export async function getAdvertise(data: any) {
- const headers = {
- "content-type": "application/json",
- };
- const pathUrl = `/advertisement?page=${data?.page || 1}&limit=${
- data?.limit || ""
- }&placement=${data?.placement || ""}&isPublish=${data.isPublish || ""}`;
- return await httpGet(pathUrl, headers);
+ const pathUrl = `/advertisement?page=${data?.page || 1}&limit=${data?.limit || ""}&placement=${data?.placement || ""}&isPublish=${data.isPublish || ""}`;
+ return await httpGet(pathUrl);
}
-export async function createAdvertiseById(id: number) {
- const headers = {
- "content-type": "application/json",
- };
+export async function getAdvertiseById(id: number) {
const pathUrl = `/advertisement/${id}`;
- return await httpGet(pathUrl, headers);
+ return await httpGet(pathUrl);
}
export async function editAdvertise(data: any) {
- const headers = {
- "content-type": "application/json",
- };
const pathUrl = `/advertisement/${data?.id}`;
- return await httpPut(pathUrl, headers, data);
+ return await httpPutInterceptor(pathUrl, data);
}
export async function editAdvertiseIsActive(data: any) {
- const headers = {
- "content-type": "application/json",
- Authorization: `Bearer ${token}`,
- };
const pathUrl = `/advertisement/publish/${data?.id}?isPublish=${data?.isActive}`;
- return await httpPut(pathUrl, headers);
+ return await httpPutInterceptor(pathUrl, data);
}
export async function deleteAdvertise(id: number) {
- const headers = {
- "content-type": "application/json",
- };
const pathUrl = `/advertisement/${id}`;
- return await httpDeleteInterceptor(pathUrl, headers);
+ return await httpDeleteInterceptor(pathUrl);
}
diff --git a/service/article.ts b/service/article.ts
index 98d1d5b..8faddf4 100644
--- a/service/article.ts
+++ b/service/article.ts
@@ -1,7 +1,6 @@
import { PaginationRequest } from "@/types/globals";
-import Cookies from "js-cookie";
import { httpGet } from "./http-config/http-base-services";
-import { httpDeleteInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
+import { httpDeleteInterceptor, httpGetInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
export async function getListArticle(props: PaginationRequest) {
const {
@@ -29,6 +28,28 @@ export async function getListArticle(props: PaginationRequest) {
);
}
+export async function getArticlePagination(props: PaginationRequest) {
+ const {
+ page,
+ limit,
+ search,
+ startDate,
+ endDate,
+ category,
+ sortBy,
+ sort,
+ categorySlug,
+ isBanner,
+ } = props;
+ return await httpGetInterceptor(
+ `/articles?limit=${limit}&page=${page}&title=${search}&startDate=${startDate || ""}&endDate=${
+ endDate || ""
+ }&categoryId=${category || ""}&sortBy=${sortBy || "created_at"}&sort=${
+ sort || "asc"
+ }&category=${categorySlug || ""}&isBanner=${isBanner || ""}`
+ );
+}
+
export async function getTopArticles(props: PaginationRequest) {
const { page, limit, search, startDate, endDate, isPublish, category } =
props;
@@ -75,7 +96,7 @@ export async function deleteArticle(id: string) {
}
export async function getArticleByCategory() {
- return await httpGet(`/article-categories?limit=1000`);
+ return await httpGetInterceptor(`/article-categories?limit=1000`);
}
export async function getCategoryPagination(data: any) {
return await httpGet(
diff --git a/service/http-config/axios-base-instance.ts b/service/http-config/axios-base-instance.ts
index 03f30f6..de3efbe 100644
--- a/service/http-config/axios-base-instance.ts
+++ b/service/http-config/axios-base-instance.ts
@@ -5,7 +5,8 @@ const baseURL = "https://dev.mikulnews.com/api";
const axiosBaseInstance = axios.create({
baseURL,
headers: {
- "content-type": "application/json",
+ "Content-Type": "application/json",
+ "X-Client-Key": "bb65b1ad-e954-4a1a-b4d0-74df5bb0b640"
},
});
diff --git a/service/http-config/axios-base-service.ts b/service/http-config/axios-base-service.ts
deleted file mode 100644
index c33fd16..0000000
--- a/service/http-config/axios-base-service.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-import { getCsrfToken } from "../master-user";
-import axiosInterceptorInstance from "./axios-interceptor-instance";
-import axiosBaseInstance from "./http-base-instance";
-import mediahubBaseInstance from "./mediahub-base-service";
-import Cookies from "js-cookie";
-
-const defaultHeaders = {
- "Content-Type": "application/json",
-};
-
-export async function httpPost(pathUrl: any, headers: any, data?: any) {
- const resCsrf = await getCsrfToken();
- const csrfToken = resCsrf?.data?.csrf_token;
-
- const mergedHeaders = {
- ...defaultHeaders,
- ...headers,
- ...(csrfToken ? { "X-CSRF-TOKEN": csrfToken } : {}),
- };
-
- const response = await axiosBaseInstance
- .post(pathUrl, data, { headers: mergedHeaders })
- .catch(function (error: any) {
- console.log(error);
- return error.response;
- });
- console.log("Response base svc : ", response);
- if (response?.status == 200 || response?.status == 201) {
- return {
- error: false,
- message: "success",
- data: response?.data,
- };
- } else {
- return {
- error: true,
- message: response?.data?.message || response?.data || null,
- data: null,
- };
- }
-}
-
-export async function httpGet(pathUrl: any, headers: any) {
- const response = await axiosInterceptorInstance
- .get(pathUrl, { headers })
- .catch(function (error: any) {
- console.log(error);
- return error.response;
- });
- console.log("Response base svc : ", response);
- if (response?.status == 200 || response?.status == 201) {
- return {
- error: false,
- message: "success",
- data: response?.data,
- };
- } else {
- return {
- error: true,
- message: response?.data?.message || response?.data || null,
- data: null,
- };
- }
-}
-
-export async function httpPut(pathUrl: any, headers: any, data?: any) {
- const resCsrf = await getCsrfToken();
- const csrfToken = resCsrf?.data?.csrf_token;
-
- const defaultHeaders = {
- "Content-Type": "application/json",
- };
- const mergedHeaders = {
- ...defaultHeaders,
- ...headers,
- ...(csrfToken ? { "X-CSRF-TOKEN": csrfToken } : {}),
- };
-
- const response = await axiosBaseInstance
- .put(pathUrl, data, { headers: mergedHeaders })
- .catch(function (error: any) {
- console.log(error);
- return error.response;
- });
- console.log("Response base svc : ", response);
- if (response?.status == 200 || response?.status == 201) {
- return {
- error: false,
- message: "success",
- data: response?.data,
- };
- } else {
- return {
- error: true,
- message: response?.data?.message || response?.data || null,
- data: null,
- };
- }
-}
-
-export async function httpDeleteInterceptor(pathUrl: any, headers: any) {
- const resCsrf = await getCsrfToken();
- const csrfToken = resCsrf?.data?.csrf_token;
-
- const defaultHeaders = {
- "Content-Type": "application/json",
- };
- const mergedHeaders = {
- ...defaultHeaders,
- ...headers,
- ...(csrfToken ? { "X-CSRF-TOKEN": csrfToken } : {}),
- };
-
- const response = await axiosBaseInstance
- .delete(pathUrl, { headers: mergedHeaders })
- .catch((error) => error.response);
- console.log("Response interceptor : ", response);
- if (response?.status == 200 || response?.status == 201) {
- return {
- error: false,
- message: "success",
- data: response?.data,
- };
- } else {
- return {
- error: true,
- message: response?.data?.message || response?.data || null,
- data: null,
- };
- }
-}
-
-export async function mediahubGet(pathUrl: any, headers: any) {
- const response = await mediahubBaseInstance
- .get(pathUrl, { headers })
- .catch(function (error: any) {
- console.log(error);
- return error.response;
- });
- console.log("Response base svc : ", response);
- if (response?.status == 200 || response?.status == 201) {
- return {
- error: false,
- message: "success",
- data: response?.data,
- };
- } else {
- return {
- error: true,
- message: response?.data?.message || response?.data || null,
- data: null,
- };
- }
-}
diff --git a/service/http-config/axios-interceptor-instance.ts b/service/http-config/axios-interceptor-instance.ts
index e90570d..422a192 100644
--- a/service/http-config/axios-interceptor-instance.ts
+++ b/service/http-config/axios-interceptor-instance.ts
@@ -10,7 +10,7 @@ const axiosInterceptorInstance = axios.create({
baseURL,
headers: {
"Content-Type": "application/json",
- "X-Client-Key": process.env.MEDOLS_CLIENT_KEY
+ "X-Client-Key": "bb65b1ad-e954-4a1a-b4d0-74df5bb0b640"
},
withCredentials: true,
});
diff --git a/service/http-config/http-base-instance.ts b/service/http-config/http-base-instance.ts
deleted file mode 100644
index b7d47a7..0000000
--- a/service/http-config/http-base-instance.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import axios from "axios";
-
-const baseURL = "https://dev.mikulnews.com/api";
-
-const axiosBaseInstance = axios.create({
- baseURL,
- headers: {
- "content-type": "application/json",
- "X-Client-Key": process.env.MEDOLS_CLIENT_KEY
- },
- withCredentials: true,
-});
-
-export default axiosBaseInstance;
diff --git a/service/http-config/http-base-services.ts b/service/http-config/http-base-services.ts
index 92e46f9..755d158 100644
--- a/service/http-config/http-base-services.ts
+++ b/service/http-config/http-base-services.ts
@@ -1,12 +1,12 @@
-import axiosBaseInstance from "./http-base-instance";
+import axiosBaseInstance from "./axios-base-instance";
const defaultHeaders = {
"Content-Type": "application/json",
- "X-Client-Key": process.env.MEDOLS_CLIENT_KEY
+ "X-Client-Key": "bb65b1ad-e954-4a1a-b4d0-74df5bb0b640"
};
-export async function httpGet(pathUrl: any, headers?: any) {
-
+export async function httpGet(pathUrl: any, headers?: any) {
+ console.log("X-HEADERS : ", defaultHeaders)
const mergedHeaders = {
...defaultHeaders,
...headers,
@@ -33,9 +33,13 @@ export async function httpGet(pathUrl: any, headers?: any) {
}
}
-export async function httpPost(pathUrl: any, headers: any, data: any) {
+export async function httpPost(pathUrl: any, data: any, headers?: any) {
+ const mergedHeaders = {
+ ...defaultHeaders,
+ ...headers,
+ };
const response = await axiosBaseInstance
- .post(pathUrl, data, { headers })
+ .post(pathUrl, data, { headers: mergedHeaders })
.catch(function (error) {
console.log(error);
return error.response;
diff --git a/service/http-config/http-interceptor-services.ts b/service/http-config/http-interceptor-services.ts
index a9238b6..4d33d96 100644
--- a/service/http-config/http-interceptor-services.ts
+++ b/service/http-config/http-interceptor-services.ts
@@ -5,12 +5,13 @@ import { getCsrfToken } from "../master-user";
const defaultHeaders = {
"Content-Type": "application/json",
- "X-Client-Key": process.env.MEDOLS_CLIENT_KEY
+ "X-Client-Key": "bb65b1ad-e954-4a1a-b4d0-74df5bb0b640"
};
export async function httpGetInterceptor(pathUrl: any) {
+ console.log("X-HEADERS : ", defaultHeaders)
const response = await axiosInterceptorInstance
- .get(pathUrl)
+ .get(pathUrl, { headers: defaultHeaders })
.catch((error) => error.response);
console.log("Response interceptor : ", response);
if (response?.status == 200 || response?.status == 201) {
@@ -97,7 +98,7 @@ export async function httpPutInterceptor(pathUrl: any, data: any, headers?: any)
}
}
-export async function httpDeleteInterceptor(pathUrl: any, headers: any) {
+export async function httpDeleteInterceptor(pathUrl: any, headers?: any) {
const resCsrf = await getCsrfToken();
const csrfToken = resCsrf?.data?.csrf_token;
diff --git a/service/http-config/mediahub-base-service.ts b/service/http-config/mediahub-base-service.ts
deleted file mode 100644
index 499c570..0000000
--- a/service/http-config/mediahub-base-service.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import axios from "axios";
-
-const baseURL = "https://mediahub.polri.go.id/api";
-
-const mediahubBaseInstance = axios.create({
- baseURL,
- headers: {
- "content-type": "application/json",
- },
-});
-
-export default mediahubBaseInstance;
diff --git a/service/magazine.tsx b/service/magazine.tsx
index 9c76d36..d711c8d 100644
--- a/service/magazine.tsx
+++ b/service/magazine.tsx
@@ -1,75 +1,50 @@
import { PaginationRequest } from "@/types/globals";
-import {
- httpDeleteInterceptor,
- httpGet,
- httpPost,
- httpPut,
-} from "./http-config/axios-base-service";
import Cookies from "js-cookie";
+import { httpDeleteInterceptor, httpGetInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
const token = Cookies.get("access_token");
export async function createMagazine(data: any) {
- const headers = {
- "content-type": "application/json",
- Authorization: `Bearer ${token}`,
- };
const pathUrl = `/magazines`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPostInterceptor(pathUrl, data);
}
export async function getListMagazine(props: PaginationRequest) {
const { page, limit, search, startDate, endDate } = props;
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(
+ return await httpGetInterceptor(
`/magazines?limit=${limit}&page=${page}&title=${search}&startDate=${
startDate || ""
- }&endDate=${endDate || ""}`,
- headers
+ }&endDate=${endDate || ""}`
);
}
export async function updateMagazine(id: string, data: any) {
- const headers = {
- "content-type": "application/json",
- };
const pathUrl = `/magazines/${id}`;
- return await httpPut(pathUrl, headers, data);
+ return await httpPutInterceptor(pathUrl, data);
}
export async function getMagazineById(id: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(`/magazines/${id}`, headers);
+ return await httpGetInterceptor(`/magazines/${id}`);
}
export async function deleteMagazine(id: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpDeleteInterceptor(`magazines/${id}`, headers);
+ return await httpDeleteInterceptor(`magazines/${id}`);
}
export async function uploadMagazineFile(id: string, data: any) {
const headers = {
"content-type": "multipart/form-data",
};
- return await httpPost(`/magazine-files/${id}`, headers, data);
+ return await httpPostInterceptor(`/magazine-files/${id}`, data, headers);
}
export async function uploadMagazineThumbnail(id: string, data: any) {
const headers = {
"content-type": "multipart/form-data",
};
- return await httpPost(`/magazines/thumbnail/${id}`, headers, data);
+ return await httpPostInterceptor(`/magazines/thumbnail/${id}`, data, headers);
}
export async function deleteMagazineFiles(id: number) {
- const headers = {
- "content-type": "multipart/form-data",
- };
- return await httpDeleteInterceptor(`magazine-files/${id}`, headers);
+ return await httpDeleteInterceptor(`magazine-files/${id}`);
}
diff --git a/service/master-categories.tsx b/service/master-categories.tsx
index 9efd3ec..44276b5 100644
--- a/service/master-categories.tsx
+++ b/service/master-categories.tsx
@@ -1,47 +1,29 @@
-import {
- httpDeleteInterceptor,
- httpGet,
- httpPost,
- httpPut,
-} from "./http-config/axios-base-service";
import Cookies from "js-cookie";
+import { httpDeleteInterceptor, httpGetInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
const token = Cookies.get("access_token");
export async function createCategory(data: any) {
- const headers = {
- "content-type": "application/json",
- Authorization: `Bearer ${token}`,
- };
const pathUrl = `/article-categories`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPostInterceptor(pathUrl, data);
}
export async function updateCategory(id: string, data: any) {
- const headers = {
- "content-type": "application/json",
- };
const pathUrl = `/article-categories/${id}`;
- return await httpPut(pathUrl, headers, data);
+ return await httpPutInterceptor(pathUrl, data);
}
export async function getCategoryById(id: number) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(`/article-categories/${id}`, headers);
+ return await httpGetInterceptor(`/article-categories/${id}`);
}
export async function deleteCategory(id: number) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpDeleteInterceptor(`article-categories/${id}`, headers);
+ return await httpDeleteInterceptor(`article-categories/${id}`);
}
export async function uploadCategoryThumbnail(id: string, data: any) {
const headers = {
"content-type": "multipart/form-data",
};
- return await httpPost(`/article-categories/thumbnail/${id}`, headers, data);
+ return await httpPostInterceptor(`/article-categories/thumbnail/${id}`, data, headers);
}
diff --git a/service/master-user-role.ts b/service/master-user-role.ts
index eda2837..567045b 100644
--- a/service/master-user-role.ts
+++ b/service/master-user-role.ts
@@ -1,42 +1,29 @@
-import {
- httpDeleteInterceptor,
- httpGet,
- httpPost,
-} from "./http-config/axios-base-service";
-
import Cookies from "js-cookie";
+import { httpDeleteInterceptor, httpGetInterceptor, httpPostInterceptor } from "./http-config/http-interceptor-services";
const token = Cookies.get("access_token");
export async function listUserRole(data: any) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(
- `/user-roles?limit=${data.limit}&page=${data.page}`,
- headers
+ return await httpGetInterceptor(
+ `/user-roles?limit=${data.limit}&page=${data.page}`
);
}
export async function createMasterUserRole(data: any) {
- const headers = {
- "content-type": "application/json",
- Authorization: `Bearer ${token}`,
- };
const pathUrl = `/user-roles`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPostInterceptor(pathUrl, data);
}
export async function getMasterUserRoleById(id: any) {
const headers = {
"content-type": "application/json",
};
- return await httpGet(`/user-roles/${id}`, headers);
+ return await httpGetInterceptor(`/user-roles/${id}`);
}
export async function deleteMasterUserRole(id: string) {
const headers = {
"content-type": "application/json",
};
- return await httpDeleteInterceptor(`/user-roles/${id}`, headers);
+ return await httpDeleteInterceptor(`/user-roles/${id}`);
}
diff --git a/service/master-user.ts b/service/master-user.ts
index cf875e1..ede054b 100644
--- a/service/master-user.ts
+++ b/service/master-user.ts
@@ -1,6 +1,6 @@
-import { httpDeleteInterceptor, httpGet, httpPost, httpPut } from "./http-config/axios-base-service";
import Cookies from "js-cookie";
-import axiosBaseInstance from "./http-config/http-base-instance";
+import { httpGet, httpPost } from "./http-config/http-base-services";
+import { httpDeleteInterceptor, httpGetInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
const token = Cookies.get("access_token");
const id = Cookies.get("uie");
@@ -13,78 +13,55 @@ export async function listMasterUsers(data: any) {
}
export async function createMasterUser(data: any) {
- const headers = {
- "content-type": "application/json",
- };
const pathUrl = `/users`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPostInterceptor(pathUrl, data);
}
+
export async function emailValidation(data: any) {
- const headers = {
- "content-type": "application/json",
- };
const pathUrl = `/users/email-validation`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPost(pathUrl, data);
}
export async function setupEmail(data: any) {
- const headers = {
- "content-type": "application/json",
- };
const pathUrl = `/users/setup-email`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPost(pathUrl, data);
}
export async function getDetailMasterUsers(id: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(`/users/detail/${id}`, headers);
+ const pathUrl = `/users/detail/${id}`;
+ return await httpGetInterceptor(pathUrl);
}
export async function editMasterUsers(data: any, id: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpPut(`/users/${id}`, headers, data);
+ const pathUrl = `/users/${id}`
+ return await httpPutInterceptor(pathUrl, data);
}
export async function deleteMasterUser(id: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpDeleteInterceptor(`/users/${id}`, headers);
+ const pathUrl = `/users/${id}`
+ return await httpDeleteInterceptor(pathUrl);
}
export async function postSignIn(data: any) {
- const headers = {
- accept: "application/json",
- "content-type": "application/json",
- };
const pathUrl = `/users/login`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPost(pathUrl, data);
}
-export async function getProfile(code?: string) {
+export async function getProfile(token?: string) {
const headers = {
"content-type": "application/json",
- Authorization: `Bearer ${code || token}`,
+ "Authorization": `Bearer ${token}`,
};
- return await httpGet(`/users/info`, headers);
+ const pathUrl = `/users/info`;
+ return await httpGet(pathUrl, headers);
}
export async function updateProfile(data: any) {
- const headers = {
- "content-type": "application/json",
- Authorization: `Bearer ${token}`,
- };
- return await httpPut(`/users/${id}`, headers, data);
+ const pathUrl = `/users/${id}`;
+ return await httpPutInterceptor(pathUrl, data);
}
export async function savePassword(data: any) {
- const headers = {
- "content-type": "application/json",
- Authorization: `Bearer ${token}`,
- };
- return await httpPost(`/users/save-password`, headers, data);
+ const pathUrl = `/users/save-password`
+ return await httpPostInterceptor(pathUrl, data);
}
export async function resetPassword(data: any) {
@@ -102,23 +79,13 @@ export async function checkUsernames(username: string) {
}
export async function otpRequest(email: string, name: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpPost(`/users/otp-request`, headers, { email, name });
+ const pathUrl = `/users/otp-request`;
+ return await httpPost(pathUrl, { email, name });
}
export async function otpValidation(email: string, otpCode: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpPost(`/users/otp-validation`, headers, { email, otpCode });
-}
-export async function otpValidationLogin(data: any) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpPost(`/users/otp-validation`, headers, data);
+ const pathUrl = `/users/otp-validation`
+ return await httpPost(pathUrl, { email, otpCode });
}
export async function postArticleComment(data: any) {
@@ -134,31 +101,21 @@ export async function postArticleComment(data: any) {
}
export async function editArticleComment(data: any, id: number) {
- const headers = {
- "content-type": "application/json",
- Authorization: `Bearer ${token}`,
- };
- return await httpPut(`/article-comments/${id}`, headers, data);
+ const pathUrl = `/article-comments/${id}`;
+ return await httpPutInterceptor(pathUrl, data);
}
export async function getArticleComment(id: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(`/article-comments?isPublic=true&articleId=${id}`, headers);
+ const pathUrl = `/article-comments?isPublic=true&articleId=${id}`;
+ return await httpGet(pathUrl);
}
export async function deleteArticleComment(id: number) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpDeleteInterceptor(`/article-comments/${id}`, headers);
+ const pathUrl = `/article-comments/${id}`
+ return await httpDeleteInterceptor(pathUrl);
}
export async function getCsrfToken() {
const pathUrl = "csrf-token";
- const headers = {
- "content-type": "application/json",
- };
- return httpGet(pathUrl, headers);
+ return httpGet(pathUrl);
}
\ No newline at end of file
diff --git a/service/static-page-service.ts b/service/static-page-service.ts
index ad2a87d..41631ec 100644
--- a/service/static-page-service.ts
+++ b/service/static-page-service.ts
@@ -1,47 +1,28 @@
import { PaginationRequest } from "@/types/globals";
-import {
- httpDeleteInterceptor,
- httpGet,
- httpPost,
- httpPut,
-} from "./http-config/axios-base-service";
+import { httpGetInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
+import { httpGet } from "./http-config/http-base-services";
export async function createCustomStaticPage(data: any) {
- const headers = {
- "content-type": "application/json",
- };
const pathUrl = `/custom-static-pages`;
- return await httpPost(pathUrl, headers, data);
+ return await httpPostInterceptor(pathUrl, data);
}
export async function editCustomStaticPage(data: any) {
- const headers = {
- "content-type": "application/json",
- };
const pathUrl = `/custom-static-pages/${data.id}`;
- return await httpPut(pathUrl, headers, data);
+ return await httpPutInterceptor(pathUrl, data);
}
export async function getCustomStaticPage(props: PaginationRequest) {
const { page, limit, search } = props;
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(
- `/custom-static-pages?limit=${limit}&page=${page}&title=${search}`,
- headers
- );
+ const pathUrl = `/custom-static-pages?limit=${limit}&page=${page}&title=${search}`;
+ return await httpGetInterceptor(pathUrl);
}
+
export async function getCustomStaticDetail(id: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(`/custom-static-pages/${id}`, headers);
+ return await httpGetInterceptor(`/custom-static-pages/${id}`);
}
export async function getCustomStaticDetailBySlug(slug: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(`/custom-static-pages/slug/${slug}`, headers);
+ const pathUrl = `/custom-static-pages/slug/${slug}`;
+ return await httpGet(pathUrl);
}
diff --git a/service/user-levels-service.ts b/service/user-levels-service.ts
new file mode 100644
index 0000000..3a2ca3e
--- /dev/null
+++ b/service/user-levels-service.ts
@@ -0,0 +1,30 @@
+
+import Cookies from "js-cookie";
+import { httpGetInterceptor, httpPostInterceptor, httpPutInterceptor } from "./http-config/http-interceptor-services";
+const token = Cookies.get("access_token");
+
+export async function getAllUserLevels(data?: any) {
+ const pathUrl = `user-levels?limit=${data?.limit || ""}&levelNumber=${
+ data?.levelNumber || ""
+ }&name=${data?.search || ""}&page=${data?.page || "1"}`
+ return await httpGetInterceptor(pathUrl);
+}
+export async function getUserLevels(id: string) {
+ return await httpGetInterceptor(`user-levels/${id}`);
+}
+
+export async function getAccountById(id: string) {
+ return await httpGetInterceptor(`user-account/findById/${id}`);
+}
+
+export async function createUserLevels(data: any) {
+ return await httpPostInterceptor(`user-levels`, data);
+}
+
+export async function editUserLevels(id: string, data: any) {
+ return await httpPutInterceptor(`user-levels/${id}`, data);
+}
+
+export async function changeIsApproval(data: any) {
+ return await httpPutInterceptor(`user-levels/enable-approval`, data);
+}
diff --git a/service/user-levels/user-levels-service.ts b/service/user-levels/user-levels-service.ts
deleted file mode 100644
index 5f1f457..0000000
--- a/service/user-levels/user-levels-service.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-
-import Cookies from "js-cookie";
-import { httpGet, httpPost, httpPut } from "../http-config/axios-base-service";
-
-const token = Cookies.get("access_token");
-
-export async function getAllUserLevels(data?: any) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(
- `user-levels?limit=${data?.limit || ""}&levelNumber=${
- data?.levelNumber || ""
- }&name=${data?.search || ""}&page=${data?.page || "1"}`,
- headers
- );
-}
-export async function getUserLevels(id: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(`user-levels/${id}`, headers);
-}
-
-export async function getAccountById(id: string) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpGet(`user-account/findById/${id}`, headers);
-}
-
-export async function createUserLevels(request: any) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpPost(`user-levels`, headers, request);
-}
-
-export async function editUserLevels(id: string, request: any) {
- const headers = {
- "content-type": "application/json",
- };
- return await httpPut(`user-levels/${id}`, headers, request);
-}
-
-export async function changeIsApproval(request: any) {
- const headers = {
- "content-type": "application/json",
- Authorization: `Bearer ${token}`,
- };
- return await httpPut(`user-levels/enable-approval`, headers, request);
-}
diff --git a/utils/chunk-error-handler.ts b/utils/chunk-error-handler.ts
new file mode 100644
index 0000000..fc09c39
--- /dev/null
+++ b/utils/chunk-error-handler.ts
@@ -0,0 +1,87 @@
+// Global chunk loading error handler
+export function setupChunkErrorHandler() {
+ if (typeof window === 'undefined') return;
+
+ // Handle chunk loading errors
+ window.addEventListener('error', (event) => {
+ const error = event.error;
+
+ // Check if it's a chunk loading error
+ if (
+ error?.name === 'ChunkLoadError' ||
+ error?.message?.includes('Loading chunk') ||
+ error?.message?.includes('Failed to fetch')
+ ) {
+ console.warn('Chunk loading error detected:', error);
+
+ // Prevent the error from being logged to console
+ event.preventDefault();
+
+ // Show a user-friendly message
+ const message = document.createElement('div');
+ message.style.cssText = `
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ background: #fef2f2;
+ border: 1px solid #fecaca;
+ color: #dc2626;
+ padding: 12px 16px;
+ border-radius: 8px;
+ font-size: 14px;
+ z-index: 9999;
+ max-width: 300px;
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
+ `;
+ message.innerHTML = `
+
+ ⚠️
+ Application update detected. Please refresh the page.
+
+
+ `;
+
+ document.body.appendChild(message);
+
+ // Auto-remove after 10 seconds
+ setTimeout(() => {
+ if (message.parentNode) {
+ message.parentNode.removeChild(message);
+ }
+ }, 10000);
+ }
+ });
+
+ // Handle unhandled promise rejections (which might include chunk loading errors)
+ window.addEventListener('unhandledrejection', (event) => {
+ const error = event.reason;
+
+ if (
+ error?.name === 'ChunkLoadError' ||
+ error?.message?.includes('Loading chunk') ||
+ error?.message?.includes('Failed to fetch')
+ ) {
+ console.warn('Unhandled chunk loading rejection:', error);
+ event.preventDefault();
+
+ // Reload the page after a short delay
+ setTimeout(() => {
+ window.location.reload();
+ }, 1000);
+ }
+ });
+}
+
+// Auto-setup when this module is imported
+if (typeof window !== 'undefined') {
+ setupChunkErrorHandler();
+}
\ No newline at end of file
diff --git a/utils/dynamic-import.ts b/utils/dynamic-import.ts
new file mode 100644
index 0000000..2469892
--- /dev/null
+++ b/utils/dynamic-import.ts
@@ -0,0 +1,70 @@
+import dynamic from 'next/dynamic';
+import { ComponentType } from 'react';
+
+interface DynamicImportOptions {
+ ssr?: boolean;
+ loading?: () => React.ReactElement;
+ retries?: number;
+ retryDelay?: number;
+}
+
+export function createSafeDynamicImport>(
+ importFn: () => Promise<{ default: T }>,
+ options: DynamicImportOptions = {}
+) {
+ const { ssr = false, loading, retries = 3, retryDelay = 1000 } = options;
+
+ return dynamic(
+ () => {
+ return new Promise((resolve, reject) => {
+ let attempts = 0;
+
+ const attemptImport = async () => {
+ try {
+ const module = await importFn();
+ resolve(module.default);
+ } catch (error) {
+ attempts++;
+
+ // Check if it's a chunk loading error
+ if (
+ (error as any)?.name === 'ChunkLoadError' ||
+ (error as any)?.message?.includes('Loading chunk') ||
+ (error as any)?.message?.includes('Failed to fetch')
+ ) {
+ if (attempts < retries) {
+ console.warn(`Chunk loading failed, retrying... (${attempts}/${retries})`);
+ setTimeout(attemptImport, retryDelay);
+ return;
+ }
+ }
+
+ reject(error);
+ }
+ };
+
+ attemptImport();
+ });
+ },
+ {
+ ssr,
+ loading,
+ }
+ );
+}
+
+// Predefined safe dynamic imports for common components
+export const SafeCustomEditor = createSafeDynamicImport(
+ () => import('@/components/editor/custom-editor'),
+ { ssr: false }
+);
+
+export const SafeViewEditor = createSafeDynamicImport(
+ () => import('@/components/editor/view-editor'),
+ { ssr: false }
+);
+
+export const SafeReactApexChart = createSafeDynamicImport(
+ () => import('react-apexcharts'),
+ { ssr: false }
+);
\ No newline at end of file