diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..29957bb
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,29 @@
+stages:
+ - build
+ - deploy
+
+build-dev:
+ stage: build
+ when: on_success
+ only:
+ - main
+ image: docker:stable
+ services:
+ - name: docker:dind
+ command: ["--insecure-registry=103.82.242.92:8900"]
+ script:
+ - docker logout
+ - docker login -u $DEPLOY_USERNAME -p $DEPLOY_TOKEN 103.82.242.92:8900
+ - docker build -t 103.82.242.92:8900/medols/web-info-kreasi:dev .
+ - docker push 103.82.242.92:8900/medols/web-info-kreasi:dev
+
+auto-deploy:
+ stage: deploy
+ when: on_success
+ only:
+ - main
+ image: curlimages/curl:latest
+ services:
+ - docker:dind
+ script:
+ - curl --user admin:$JENKINS_PWD http://38.47.180.165:8080/job/auto-deploy-info-kreasi/build?token=autodeploymedols
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..2b874db
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,36 @@
+# Menggunakan image Node.js yang lebih ringan
+FROM node:23.5.0-alpine
+
+# Mengatur port
+ENV PORT 3000
+
+# Install pnpm secara global
+RUN npm install -g pnpm
+
+# Membuat direktori aplikasi dan mengatur sebagai working directory
+WORKDIR /usr/src/app
+
+# Menyalin file penting terlebih dahulu untuk caching
+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
+
+# Menyalin source code aplikasi
+COPY . .
+
+# Build aplikasi
+RUN NODE_OPTIONS="--max-old-space-size=4096" pnpm next build
+
+# Expose port untuk server
+EXPOSE 3000
+
+# Perintah untuk menjalankan aplikasi
+CMD ["pnpm", "run", "start"]
\ No newline at end of file
diff --git a/app/favicon.ico b/app/favicon.ico
index 718d6fe..6018091 100644
Binary files a/app/favicon.ico and b/app/favicon.ico differ
diff --git a/components/details/details-content.tsx b/components/details/details-content.tsx
index 7dcee88..7a4106b 100644
--- a/components/details/details-content.tsx
+++ b/components/details/details-content.tsx
@@ -6,6 +6,7 @@ import { getArticleById, getListArticle } from "@/service/article";
import { close, loading } from "@/config/swal";
import { useParams } from "next/navigation";
import Author from "../landing-page/author";
+import { Link2, MailIcon } from "lucide-react";
type TabKey = "trending" | "comments" | "latest";
@@ -366,7 +367,48 @@ export default function DetailContent() {
}}
/>
-
+ {/* */}
+
+
AUTHOR
+
+ {/* Foto Profil */}
+
+
+
+
+ {/* Info Author */}
+
+
+ {articleDetail?.createdByName}
+
+
+
+ {/* Button lihat semua post */}
+
+
+
+
+
+
+
+
+
+
+
+
Tags:
diff --git a/components/table/article-table.tsx b/components/table/article-table.tsx
index 60c8354..bcc9342 100644
--- a/components/table/article-table.tsx
+++ b/components/table/article-table.tsx
@@ -46,6 +46,7 @@ import {
TableCell,
} from "@/components/ui/table";
import CustomPagination from "../layout/custom-pagination";
+import DatePicker from "react-datepicker";
const columns = [
{ name: "No", uid: "no" },
@@ -60,6 +61,7 @@ const columns = [
const columnsOtherRole = [
{ name: "No", uid: "no" },
{ name: "Judul", uid: "title" },
+ { name: "Source", uid: "source" },
{ name: "Kategori", uid: "category" },
{ name: "Tanggal Unggah", uid: "createdAt" },
{ name: "Kreator", uid: "createdByName" },
@@ -84,7 +86,9 @@ export default function ArticleTable() {
const [search, setSearch] = useState("");
const [categories, setCategories] = useState([]);
const [selectedCategories, setSelectedCategories] = useState("");
- const [startDateValue, setStartDateValue] = useState({
+ const [selectedSource, setSelectedSource] = useState("");
+ const [selectedStatus, setSelectedStatus] = useState("");
+ const [dateRange, setDateRange] = useState({
startDate: null,
endDate: null,
});
@@ -98,24 +102,49 @@ export default function ArticleTable() {
const res = await getArticleByCategory();
const data = res?.data?.data;
setCategories(data);
+ console.log("category", data);
}
+ useEffect(() => {
+ initState();
+ }, [
+ page,
+ showData,
+ search,
+ selectedCategories,
+ selectedSource,
+ dateRange,
+ selectedStatus,
+ ]);
+
async function initState() {
loading();
const req = {
limit: showData,
page: page,
search: search,
- categorySlug: Array.from(selectedCategories).join(","),
+ category: selectedCategories || "",
+ source: selectedSource || "",
+ isPublish:
+ selectedStatus !== "" ? selectedStatus === "publish" : undefined,
+ startDate: dateRange.startDate
+ ? new Date(dateRange.startDate).toISOString()
+ : "",
+ endDate: dateRange.endDate
+ ? new Date(dateRange.endDate).toISOString()
+ : "",
sort: "desc",
sortBy: "created_at",
};
+
const res = await getArticlePagination(req);
- await getTableNumber(parseInt(showData), res.data?.data);
+
+ let data = res.data?.data || [];
+
+ await getTableNumber(parseInt(showData), data);
setTotalPage(res?.data?.meta?.totalPage);
close();
}
-
// panggil ulang setiap state berubah
useEffect(() => {
initState();
@@ -346,24 +375,63 @@ export default function ArticleTable() {
{categories
- ?.filter((category: any) => category.slug != null)
+ ?.filter((category: any) => category.title != null)
.map((category: any) => (
-
+
{category.title}
))}
- {/*
+
+
Source
+
+
+
+
Status
+
+
+
Tanggal
-
setStartDateValue(e)}
- inputClassName="z-50 w-full text-sm bg-transparent border-1 border-gray-200 px-2 py-[6px] rounded-xl h-[40px] text-gray-600 dark:text-gray-300"
+ {
+ setDateRange({
+ startDate: update[0],
+ endDate: update[1],
+ });
+ }}
+ isClearable
+ dateFormat="dd/MM/yyyy"
+ className="z-50 w-full text-sm bg-transparent border border-gray-200 px-2 py-[6px] rounded-xl h-[40px] text-gray-600 dark:text-gray-300"
+ placeholderText="Pilih rentang tanggal"
/>
- */}
+
diff --git a/public/profile.jpg b/public/profile.jpg
new file mode 100644
index 0000000..354bbe1
Binary files /dev/null and b/public/profile.jpg differ
diff --git a/service/article.ts b/service/article.ts
index 8faddf4..5a4c803 100644
--- a/service/article.ts
+++ b/service/article.ts
@@ -1,6 +1,11 @@
import { PaginationRequest } from "@/types/globals";
import { httpGet } from "./http-config/http-base-services";
-import { httpDeleteInterceptor, httpGetInterceptor, 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 {
@@ -40,13 +45,20 @@ export async function getArticlePagination(props: PaginationRequest) {
sort,
categorySlug,
isBanner,
+ isPublish,
+ source,
} = 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 || ""}`
+ `/articles?limit=${limit}&page=${page}&title=${search}&startDate=${
+ startDate || ""
+ }&endDate=${endDate || ""}&categoryId=${category || ""}&source=${
+ source || ""
+ }&isPublish=${isPublish !== undefined ? isPublish : ""}&sortBy=${
+ sortBy || "created_at"
+ }&sort=${sort || "asc"}&category=${categorySlug || ""}&isBanner=${
+ isBanner || ""
+ }`
);
}
diff --git a/types/globals.tsx b/types/globals.tsx
index df33f2b..42a9bdc 100644
--- a/types/globals.tsx
+++ b/types/globals.tsx
@@ -310,6 +310,7 @@ export type PaginationRequest = {
category?: string;
sortBy?: string;
sort?: string;
+ source?: string;
categorySlug?: string;
isBanner?: boolean;
};