This commit is contained in:
Anang Yusman 2025-02-17 22:57:44 +08:00
commit c4ba5e44f0
36 changed files with 1933 additions and 769 deletions

View File

@ -23,7 +23,7 @@ RUN pnpm install --frozen-lockfile
COPY . .
# Build aplikasi
RUN pnpm run build
RUN NODE_OPTIONS="--max-old-space-size=4096" pnpm next build
# Expose port untuk server
EXPOSE 3000

View File

@ -8,13 +8,20 @@ import { Link, useRouter } from "@/i18n/routing";
import { Textarea } from "@/components/ui/textarea";
import { BarWave } from "react-cssfx-loading";
import { useToast } from "@/components/ui/use-toast";
import { checkWishlistStatus, deleteWishlist, getDetail, saveWishlist } from "@/service/landing/landing";
import { checkWishlistStatus, createPublicSuggestion, deletePublicSuggestion, deleteWishlist, getDetail, getPublicSuggestionList, saveWishlist } from "@/service/landing/landing";
import { getCookiesDecrypt } from "@/lib/utils";
import { close, error, loading } from "@/config/swal";
import { close, error, loading, warning } from "@/config/swal";
import { useTranslations } from "next-intl";
import { checkMaliciousText, getPublicLocaleTimestamp } from "@/utils/globals";
import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import parse from "html-react-parser";
const DetailAudio = () => {
const [selectedSize, setSelectedSize] = useState<string>("L");
const [selectedTab, setSelectedTab] = useState("video");
const t = useTranslations("LandingPage");
const router = useRouter();
const pathname = usePathname();
const params = useParams();
@ -29,6 +36,11 @@ const DetailAudio = () => {
const [main, setMain] = useState<any>();
const [resolutionSelected, setResolutionSelected] = useState("720");
const [imageSizeSelected, setImageSizeSelected] = useState("l");
const [message, setMessage] = useState("");
const userRoleId = getCookiesDecrypt("urie");
const [listSuggestion, setListSuggestion] = useState<any>();
const [visibleInput, setVisibleInput] = useState<string | null>(null);
const MySwal = withReactContent(Swal);
const userId = getCookiesDecrypt("uie");
@ -215,7 +227,120 @@ const DetailAudio = () => {
{ label: "S", value: "1066 x 599 px" },
{ label: "XS", value: "800 x 450 px" },
];
async function sendSuggestionParent() {
if (message?.length > 3) {
loading();
const data = {
mediaUploadId: slug?.split("-")?.[0],
message,
parentId: null,
};
const response = await createPublicSuggestion(data);
console.log(response);
setMessage("");
const responseGet = await getPublicSuggestionList(slug?.split("-")?.[0]);
console.log(responseGet?.data?.data);
setListSuggestion(responseGet?.data?.data);
// Hapus nilai semua input secara manual jika perlu
const inputs = document.querySelectorAll("input");
inputs.forEach((input) => {
input.value = "";
});
close();
}
}
const getInputValue = (e: any) => {
const message = e.target.value;
console.log(message);
setMessage(message);
};
const postData = () => {
const checkMessage = checkMaliciousText(message);
if (checkMessage == "") {
if (Number(userRoleId) < 1 || userRoleId == undefined) {
router.push("/auth");
} else {
sendSuggestionParent();
}
} else {
warning(checkMessage);
}
};
function addDefaultProfile(ev: any) {
ev.target.src = "/assets/avatar-profile.png";
}
const showInput = (e: any) => {
console.log(document.querySelector(`#${e}`)?.classList);
document.querySelector(`#${e}`)?.classList.toggle("none");
setVisibleInput(visibleInput === e ? null : e);
};
async function sendSuggestionChild(parentId: any) {
const inputElement = document.querySelector(`#input-comment-${parentId}`) as HTMLInputElement;
if (inputElement && inputElement.value.length > 3) {
loading();
const data = {
mediaUploadId: slug?.split("-")?.[0],
message: inputElement.value,
parentId,
};
console.log(data);
const response = await createPublicSuggestion(data);
console.log(response);
const responseGet: any = await getPublicSuggestionList(slug?.split("-")?.[0]);
console.log(responseGet.data?.data);
setListSuggestion(responseGet.data?.data);
// Reset input field
inputElement.value = "";
// document.querySelector("#comment-id-" + parentId)?.style.display = "none";
close();
}
}
async function deleteDataSuggestion(dataId: any) {
loading();
const response = await deletePublicSuggestion(dataId);
console.log(response);
const responseGet = await getPublicSuggestionList(slug.split("-")?.[0]);
console.log(responseGet.data?.data);
setListSuggestion(responseGet.data?.data);
close();
}
const deleteData = (dataId: any) => {
MySwal.fire({
title: "Delete Comment",
icon: "warning",
showCancelButton: true,
cancelButtonColor: "#3085d6",
confirmButtonColor: "#d33",
confirmButtonText: "Delete",
}).then((result: any) => {
if (result.isConfirmed) {
deleteDataSuggestion(dataId);
console.log(dataId);
}
});
};
const postDataChild = (id: any) => {
const checkMessage = checkMaliciousText(message);
if (checkMessage == "") {
if (Number(userRoleId) < 1 || userRoleId == undefined) {
router.push("/auth");
} else {
sendSuggestionChild(id);
}
} else {
warning(checkMessage);
}
};
return (
<>
<div className="min-h-screen px-4 md:px-24 py-4">
@ -316,10 +441,188 @@ const DetailAudio = () => {
<div className="w-full mb-8">
{/* Comment */}
<div className="flex flex-col my-16 gap-5 p-10 bg-gray-300">
{/* <div className="flex flex-col my-16 gap-5 p-10 bg-gray-300">
<p className="flex items-start text-lg">Berikan Komentar</p>
<Textarea placeholder="Type your comments here." className="flex items-start justify-center" />
<button className="flex items-start bg-[#bb3523] rounded-lg w-fit px-4 py-1">Kirim</button>
</div> */}
<div className="flex flex-col my-16 p-4 lg:p-10 bg-[#f7f7f7]">
<div className="gap-5 flex flex-col px-4 lg:px-14">
<p className="flex items-start text-lg">{t("comment")}</p>
<Textarea placeholder="Type your comments here." className="flex w-full pb-12" onChange={getInputValue} />
<button onClick={() => postData()} className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-4 py-1">
{t("send")}
</button>
</div>
<div className="border-b-2 border-slate-300 mt-4 w-auto"></div>
<div>
{listSuggestion?.map((data: any) => (
<div className="flex flex-col">
<div className="flex flex-row mt-2 px-4 lg:px-14">
<img src={data?.suggestionFrom?.profilePictureUrl} className="h-12 lg:h-16 w-12 lg:w-16 mr-2" onError={addDefaultProfile} alt="" />
<div className="border border-slate-300 w-full p-2 lg:p-4 bg-white gap-1">
<p className="text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
{Number(data.suggestionFrom?.roleId) == 2 || Number(data.suggestionFrom?.roleId) == 3 || Number(data.suggestionFrom?.roleId) == 4 ? "HUMAS POLRI" : data.suggestionFrom?.fullname}
{getPublicLocaleTimestamp(new Date(data.createdAt))}
</p>
<p className="text-slate-500 text-[13px] lg:text-sm mb-4">{data?.message}</p>
<div>
<a
style={
Number(data.suggestionFrom?.id) == Number(userId)
? {
display: "none",
}
: {}
}
onClick={() => showInput(`comment-id-${data.id}`)}
className="mr-2"
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("reply")}</small>
</a>
{Number(data.suggestionFrom?.id) == Number(userId) || Number(userRoleId) == 2 ? (
<a onClick={() => deleteData(data.id)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("delete")}</small>
</a>
) : (
""
)}
</div>
</div>
</div>
{visibleInput === `comment-id-${data.id}` && (
<div id={`comment-id-${data.id}`} className="px-4 pl-[72px] lg:px-14 lg:pl-32 mt-2 ">
<Textarea id={`input-comment-${data.id}`} className="p-4 focus:outline-none focus:border-sky-500" placeholder={t("enterReply")} />
<div className="flex flex-row gap-3">
<a onClick={() => postDataChild(data.id)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 mt-2 cursor-pointer">{t("send")}</small>
</a>
<a onClick={() => showInput(`comment-id-${data.id}`)}>
<small className="flex items-start bg-[#bb3523] rounded-lg mt-2 w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("cancel")}</small>
</a>
</div>
</div>
)}
{data.children.length > 0
? data.children?.map((child1: any) => (
<div className="flex flex-col">
<div className="flex flex-row mt-2 px-4 lg:pr-14 pl-16 lg:pl-32">
<img src={child1.suggestionFrom?.profilePictureUrl} onError={addDefaultProfile} alt="" className="h-10 lg:h-16 w-10 lg:w-16 mr-2" />
<div className="border border-slate-300 w-full p-2 lg:p-4 bg-white gap-1">
<p className="text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
{" "}
<b>{Number(child1.suggestionFrom?.roleId) == 2 || Number(child1.suggestionFrom?.roleId) == 3 || Number(child1.suggestionFrom?.roleId) == 4 ? "HUMAS POLRI" : child1.suggestionFrom?.fullname}</b>{" "}
{getPublicLocaleTimestamp(new Date(child1.createdAt))}
</p>
<p className="text-slate-500 text-[13px] lg:text-sm mb-4">{parse(String(child1?.message))}</p>
<div>
<a
style={
Number(child1.suggestionFrom?.id) == Number(userId)
? {
display: "none",
}
: {}
}
onClick={() => showInput(`comment-id-${child1.id}`)}
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("reply")}</small>
</a>
<a
style={
Number(child1.suggestionFrom?.id) == Number(userId)
? {}
: {
display: "none",
}
}
onClick={() => deleteData(child1.id)}
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("delete")}</small>
</a>
</div>
</div>
</div>
{visibleInput === `comment-id-${child1.id}` && (
<div id={`comment-id-${child1.id}`} className="px-4 lg:px-14 pl-28 lg:pl-[200px]">
<Textarea name="" className="mt-2 " id={`input-comment-${child1.id}`} placeholder={t("enterReply")} />
<div className="flex flex-row mt-2 gap-3">
<a onClick={() => postDataChild(child1.id)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("send")}</small>
</a>
<a onClick={() => showInput(`comment-id-${child1.id}`)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("cancel")}</small>
</a>
</div>
</div>
)}
{child1.children.length > 0
? child1.children?.map((child2: any) => (
<div className="">
<div className="flex flex-row mt-2 px-4 lg:pr-14 pl-28 lg:pl-48">
<img src={child2.suggestionFrom?.profilePictureUrl} className="h-9 lg:h-16 w-9 lg:w-16 mr-2" onError={addDefaultProfile} alt="" />
<div className="border border-slate-300 w-full p-2 lg:p-4 bg-white gap-1">
<p className="text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
{" "}
<b>{Number(child2.suggestionFrom?.roleId) == 2 || Number(child2.suggestionFrom?.roleId) == 3 || Number(child2.suggestionFrom?.roleId) == 4 ? "HUMAS POLRI" : child2.suggestionFrom?.fullname}</b>{" "}
{getPublicLocaleTimestamp(new Date(child2.createdAt))}
</p>
<p className="text-slate-500 text-sm mb-4">{parse(String(child2?.message))}</p>
<div>
<a
style={
Number(child2.suggestionFrom?.id) == Number(userId)
? {
display: "none",
}
: {}
}
onClick={() => showInput(`comment-id-${child2.id}`)}
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("reply")}</small>
</a>
<a
style={
Number(child2.suggestionFrom?.id) == Number(userId)
? {}
: {
display: "none",
}
}
onClick={() => deleteData(child2.id)}
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("delete")}</small>
</a>
</div>
</div>
</div>
{visibleInput === `comment-id-${child2.id}` && (
<div id={`comment-id-${child2.id}`} className="px-4 lg:px-14 pl-40 lg:pl-[265px]">
<Textarea name="" id={`input-comment-${child2.id}`} className="my-2" placeholder="Masukkan balasan anda" />
<div className="flex flex-row gap-3">
<a onClick={() => postDataChild(child2.id)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("send")}</small>
</a>
<a onClick={() => showInput(`comment-id-${child2.id}`)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("cancel")}</small>
</a>
</div>
</div>
)}
</div>
))
: ""}
</div>
))
: ""}
</div>
))}
</div>
</div>
{/* Konten Serupa */}

View File

@ -6,10 +6,20 @@ import { Icon } from "@iconify/react/dist/iconify.js";
import NewContent from "@/components/landing-page/new-content";
import { Textarea } from "@/components/ui/textarea";
import { getCookiesDecrypt } from "@/lib/utils";
import { checkWishlistStatus, deleteWishlist, getDetail, saveWishlist } from "@/service/landing/landing";
import { close, error, loading } from "@/config/swal";
import { checkWishlistStatus, createPublicSuggestion, deletePublicSuggestion, deleteWishlist, getDetail, getPublicSuggestionList, saveWishlist } from "@/service/landing/landing";
import { close, error, loading, successCallback, warning } from "@/config/swal";
import { useToast } from "@/components/ui/use-toast";
import { Link, useRouter } from "@/i18n/routing";
import { checkMaliciousText, formatDateToIndonesian, getPublicLocaleTimestamp } from "@/utils/globals";
import { useTranslations } from "next-intl";
import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { useSearchParams } from "next/navigation";
import { sendMediaUploadToEmail } from "@/service/media-tracking/media-tracking";
import parse from "html-react-parser";
const DetailDocument = () => {
const [selectedSize, setSelectedSize] = useState<string>("L");
@ -29,6 +39,20 @@ const DetailDocument = () => {
const [main, setMain] = useState<any>();
const [resolutionSelected, setResolutionSelected] = useState("720");
const [imageSizeSelected, setImageSizeSelected] = useState("l");
const t = useTranslations("LandingPage");
const [message, setMessage] = useState("");
const userRoleId = getCookiesDecrypt("urie");
const [listSuggestion, setListSuggestion] = useState<any>();
const [visibleInput, setVisibleInput] = useState<string | null>(null);
const MySwal = withReactContent(Swal);
const [width, setWidth] = useState<any>();
let typeString = "document";
const [content, setContent] = useState<any>([]);
const [emailShareInput, setEmailShareInput] = useState<any>();
const [emailShareList, setEmailShareList] = useState<any>();
const [emailMessageInput, setEmailMessageInput] = useState();
const searchParams = useSearchParams();
const id = searchParams?.get("id");
const userId = getCookiesDecrypt("uie");
@ -215,8 +239,282 @@ const DetailDocument = () => {
xhr.send();
};
async function sendSuggestionParent() {
if (message?.length > 3) {
loading();
const data = {
mediaUploadId: slug?.split("-")?.[0],
message,
parentId: null,
};
const response = await createPublicSuggestion(data);
console.log(response);
setMessage("");
const responseGet = await getPublicSuggestionList(slug?.split("-")?.[0]);
console.log(responseGet?.data?.data);
setListSuggestion(responseGet?.data?.data);
// Hapus nilai semua input secara manual jika perlu
const inputs = document.querySelectorAll("input");
inputs.forEach((input) => {
input.value = "";
});
close();
}
}
const getInputValue = (e: any) => {
const message = e.target.value;
console.log(message);
setMessage(message);
};
const postData = () => {
const checkMessage = checkMaliciousText(message);
if (checkMessage == "") {
if (Number(userRoleId) < 1 || userRoleId == undefined) {
router.push("/auth");
} else {
sendSuggestionParent();
}
} else {
warning(checkMessage);
}
};
function addDefaultProfile(ev: any) {
ev.target.src = "/assets/avatar-profile.png";
}
const showInput = (e: any) => {
console.log(document.querySelector(`#${e}`)?.classList);
document.querySelector(`#${e}`)?.classList.toggle("none");
setVisibleInput(visibleInput === e ? null : e);
};
async function sendSuggestionChild(parentId: any) {
const inputElement = document.querySelector(`#input-comment-${parentId}`) as HTMLInputElement;
if (inputElement && inputElement.value.length > 3) {
loading();
const data = {
mediaUploadId: slug?.split("-")?.[0],
message: inputElement.value,
parentId,
};
console.log(data);
const response = await createPublicSuggestion(data);
console.log(response);
const responseGet: any = await getPublicSuggestionList(slug?.split("-")?.[0]);
console.log(responseGet.data?.data);
setListSuggestion(responseGet.data?.data);
// Reset input field
inputElement.value = "";
// document.querySelector("#comment-id-" + parentId)?.style.display = "none";
close();
}
}
async function deleteDataSuggestion(dataId: any) {
loading();
const response = await deletePublicSuggestion(dataId);
console.log(response);
const responseGet = await getPublicSuggestionList(slug.split("-")?.[0]);
console.log(responseGet.data?.data);
setListSuggestion(responseGet.data?.data);
close();
}
const deleteData = (dataId: any) => {
MySwal.fire({
title: "Delete Comment",
icon: "warning",
showCancelButton: true,
cancelButtonColor: "#3085d6",
confirmButtonColor: "#d33",
confirmButtonText: "Delete",
}).then((result: any) => {
if (result.isConfirmed) {
deleteDataSuggestion(dataId);
console.log(dataId);
}
});
};
const postDataChild = (id: any) => {
const checkMessage = checkMaliciousText(message);
if (checkMessage == "") {
if (Number(userRoleId) < 1 || userRoleId == undefined) {
router.push("/auth");
} else {
sendSuggestionChild(id);
}
} else {
warning(checkMessage);
}
};
const handleShare = (type: any, url: any) => {
if (Number(userRoleId) < 1 || userRoleId == undefined) {
router.push("/auth/login");
} else {
sendActivityLog(2);
sendActivityLog(4);
if (type == "wa" && width <= 768) {
window.open(`whatsapp://send?${url}`, "_blank");
} else if (type == "wa" && width > 768) {
window.open(`https://web.whatsapp.com/send?${url}`, "_blank", "noreferrer");
} else {
window.open(url);
}
}
};
const handleEmailList = (e: any) => {
const arrayEmail: any = [];
for (let i = 0; i < emailShareList?.length; i += 1) {
arrayEmail.push(emailShareList[i]);
}
if (e.which == 13) {
if (e.target.value) {
arrayEmail.push(e.target.value);
setEmailShareList(arrayEmail);
setEmailShareInput("");
}
e.preventDefault();
}
return false;
};
async function shareToEmail() {
if (Number(userRoleId) < 1 || userRoleId == undefined) {
router.push("/auth/login");
} else {
const data = {
mediaUploadId: id?.split("-")?.[0],
email: emailShareList || [emailShareInput],
message: emailMessageInput,
url: window.location.href,
};
loading();
const res = await sendMediaUploadToEmail(data);
if (res?.error) {
error(res.message);
return false;
}
close();
successCallback("Konten Telah Dikirim");
}
}
return (
// <>
// <div className="px-4 md:px-24 py-4">
// <div className="rounded-md overflow-hidden md:flex">
// {/* Bagian Kiri */}
// <div className="md:w-3/4">
// <div className="relative">
// <img src={detailDataDocument?.files[selectedDocument]?.url} alt="Main" className="rounded-lg w-auto h-fit" />
// <div className="absolute top-4 left-4"></div>
// </div>
// {/* Footer Informasi */}
// <div className="text-sm text-gray-500 flex justify-between items-center border-t mt-4">
// <p className="flex flex-row items-center mt-3">
// oleh&nbsp;<span className="font-semibold text-black">{detailDataDocument?.uploadedBy?.userLevel?.name}</span>&nbsp;|&nbsp;Diupdate pada {detailDataDocument?.updatedAt} WIB&nbsp;|&nbsp;
// <Icon icon="formkit:eye" width="15" height="15" />
// &nbsp;
// {detailDataDocument?.clickCount}
// </p>
// <p className="mt-3">Kreator: {detailDataDocument?.creatorName}</p>
// </div>
// {/* Keterangan */}
// <div className="md:w-3/4">
// <h1 className="flex flex-row font-bold text-2xl my-8">{detailDataDocument?.title}</h1>
// <div dangerouslySetInnerHTML={{ __html: detailDataDocument?.htmlDescription }} />
// </div>
// </div>
// {/* Bagian Kanan */}
// <div className="md:w-1/4 p-4 bg-[#f7f7f7] h-fit rounded-lg mx-4">
// {isSaved ? (
// <a onClick={() => handleDeleteWishlist()} className="flex flex-col mb-3 items-center justify-center cursor-pointer">
// <Icon icon="material-symbols:bookmark" width={40} />
// <p className="text-base lg:text-lg">Hapus</p>
// </a>
// ) : (
// <a onClick={() => doBookmark()} className="flex flex-col mb-3 items-center justify-center cursor-pointer">
// <Icon icon="material-symbols:bookmark-outline" width={40} />
// <p className="text-base lg:text-lg">Simpan</p>
// </a>
// )}
// {/* garis */}
// <div className="border-t border-black my-4"></div>
// <Link href={`/all/filter?title=polda&category=${detailDataDocument?.category.id}`} className="bg-red-600 text-white text-xs font-bold px-3 py-3 my-3 flex justify-center items-center rounded">
// {detailDataDocument?.category?.name}
// </Link>
// <div className="flex justify-center flex-wrap gap-2 mb-4">
// {detailDataDocument?.tags?.split(",").map((tag: string) => (
// <a onClick={() => router.push(`/all/filter?tag=${tag}`)} key={tag} className="bg-gray-200 text-gray-700 text-xs px-3 py-1 rounded-full cursor-pointer hover:bg-gray-500">
// {tag}
// </a>
// ))}
// </div>
// <div className="border-t border-black my-4"></div>
// {/* Opsi Ukuran Foto */}
// <h4 className="flex text-lg justify-center items-center font-semibold my-3">Opsi Ukuran Foto</h4>
// <div className="border-t border-black my-4"></div>
// <div className="space-y-2">
// {sizes.map((size: any) => (
// <div className="flex flex-row justify-between">
// <div key={size.label} className="items-center flex flex-row gap-2 cursor-pointer">
// <input type="radio" name="size" value={size.label} checked={selectedSize === size.label} onChange={() => setSelectedSize(size.label)} className="text-red-600 focus:ring-red-600" />
// <div className="text-sm">{size.label}</div>
// </div>
// <div className="">
// <div className="text-sm">{size.value}</div>
// </div>
// </div>
// ))}
// </div>
// {/* Download Semua */}
// <div className="mt-4">
// <label className="flex items-center space-x-2 text-sm">
// <input type="checkbox" className="text-red-600 focus:ring-red-600" onChange={() => setIsDownloadAll(!isDownloadAll)} />
// <span>Download Semua File?</span>
// </label>
// </div>
// {/* Tombol Download */}
// <button onClick={handleDownload} className="mt-4 bg-red-600 text-white w-full py-2 flex justify-center items-center gap-1 rounded-md text-sm hover:bg-red-700">
// <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
// <path fill="white" d="m12 16l-5-5l1.4-1.45l2.6 2.6V4h2v8.15l2.6-2.6L17 11zm-6 4q-.825 0-1.412-.587T4 18v-3h2v3h12v-3h2v3q0 .825-.587 1.413T18 20z" />
// </svg>
// Download
// </button>
// </div>
// </div>
// </div>
// <div className="w-full mb-8">
// {/* Comment */}
// <div className="flex flex-col my-16 p-10 bg-[#f7f7f7]">
// <div className="gap-5 flex flex-col px-4 lg:px-16">
// <p className="flex items-start text-lg">Berikan Komentar</p>
// <Textarea placeholder="Type your comments here." className="flex w-full" />
// <button className="flex items-start bg-[#bb3523] rounded-lg text-white w-fit px-4 py-1">Kirim</button>
// </div>
// </div>
// {/* Konten Serupa */}
// <div className="">
// <NewContent group="polda" type={"similar"} />
// </div>
// </div>
// </>
<>
<div className="px-4 md:px-24 py-4">
<div className="rounded-md overflow-hidden md:flex">
@ -227,19 +525,42 @@ const DetailDocument = () => {
<div className="absolute top-4 left-4"></div>
</div>
{/* Footer Informasi */}
<div className="text-sm text-gray-500 flex justify-between items-center border-t mt-4">
<p className="flex flex-row items-center mt-3">
<div className="text-gray-500 flex flex-col lg:flex-row justify-between items-center border-t mt-4">
{/* <p className="flex flex-row items-center mt-3">
oleh&nbsp;<span className="font-semibold text-black">{detailDataDocument?.uploadedBy?.userLevel?.name}</span>&nbsp;|&nbsp;Diupdate pada {detailDataDocument?.updatedAt} WIB&nbsp;|&nbsp;
<Icon icon="formkit:eye" width="15" height="15" />
&nbsp;
{detailDataDocument?.clickCount}
</p>
<p className="mt-3">Kreator: {detailDataDocument?.creatorName}</p>
<p className="mt-3">Kreator: {detailDataDocument?.creatorName}</p> */}
<div className="flex flex-col lg:flex-row items-center mt-3 lg:justify-between">
<p className="text-xs lg:text-sm">
{t("by")}&nbsp;<span className="font-semibold text-black">{detailDataDocument?.uploadedBy?.userLevel?.name}</span>
</p>
{/* <p className="text-xs lg:text-sm">
&nbsp;|&nbsp; {t("updatedOn")} {detailDataDocument?.updatedAt} WIB &nbsp;|&nbsp;
</p> */}
<p className="text-xs lg:text-sm">
&nbsp;|&nbsp;{t("updatedOn")}&nbsp;
{formatDateToIndonesian(new Date(detailDataDocument?.updatedAt))} {"WIB"}
</p>
<p className="text-xs lg:text-sm flex justify-center items-center">
&nbsp;| &nbsp;
<Icon icon="formkit:eye" width="15" height="15" />
&nbsp;{detailDataDocument?.clickCount}&nbsp;
</p>
</div>
<div className="mt-3">
<p className="flex text-end text-xs lg:text-sm font-semibold">
{t("creator")}
{detailDataDocument?.creatorName}
</p>
</div>
</div>
{/* Keterangan */}
<div className="md:w-3/4">
<h1 className="flex flex-row font-bold text-2xl my-8">{detailDataDocument?.title}</h1>
<div className="">
<h1 className="flex flex-row font-bold text-lg lg:text-2xl my-8 text-justify space-y-4">{detailDataDocument?.title}</h1>
<div dangerouslySetInnerHTML={{ __html: detailDataDocument?.htmlDescription }} />
</div>
</div>
@ -249,12 +570,12 @@ const DetailDocument = () => {
{isSaved ? (
<a onClick={() => handleDeleteWishlist()} className="flex flex-col mb-3 items-center justify-center cursor-pointer">
<Icon icon="material-symbols:bookmark" width={40} />
<p className="text-base lg:text-lg">Hapus</p>
<p className="text-base lg:text-lg">{t("delete")}</p>
</a>
) : (
<a onClick={() => doBookmark()} className="flex flex-col mb-3 items-center justify-center cursor-pointer">
<Icon icon="material-symbols:bookmark-outline" width={40} />
<p className="text-base lg:text-lg">Simpan</p>
<p className="text-base lg:text-lg">{t("save")}</p>
</a>
)}
@ -276,7 +597,7 @@ const DetailDocument = () => {
<div className="border-t border-black my-4"></div>
{/* Opsi Ukuran Foto */}
<h4 className="flex text-lg justify-center items-center font-semibold my-3">Opsi Ukuran Foto</h4>
<h4 className="flex text-lg justify-center items-center font-semibold my-3">{t("docSize")}</h4>
<div className="border-t border-black my-4"></div>
<div className="space-y-2">
{sizes.map((size: any) => (
@ -296,7 +617,7 @@ const DetailDocument = () => {
<div className="mt-4">
<label className="flex items-center space-x-2 text-sm">
<input type="checkbox" className="text-red-600 focus:ring-red-600" onChange={() => setIsDownloadAll(!isDownloadAll)} />
<span>Download Semua File?</span>
<span>{t("downloadAll")}</span>
</label>
</div>
@ -305,19 +626,223 @@ const DetailDocument = () => {
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="white" d="m12 16l-5-5l1.4-1.45l2.6 2.6V4h2v8.15l2.6-2.6L17 11zm-6 4q-.825 0-1.412-.587T4 18v-3h2v3h12v-3h2v3q0 .825-.587 1.413T18 20z" />
</svg>
Download
{t("download")}
</button>
{/* Tombol Bagikan */}
<div className="flex flex-row py-3">
<p className="text-base font-semibold">{t("share")}</p>
<a className="ml-8 cursor-pointer" onClick={() => handleShare("fb", `https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fmediahub.polri.go.id%2F${typeString}%2Fdetail%2F${content?.id}&quote=${content?.title}`)}>
<Icon icon="brandico:facebook" height="20" className="px-auto text-red-600 text-center" />
</a>
<a className="ml-5 cursor-pointer" onClick={() => handleShare("tw", `https://twitter.com/share?url=https%3A%2F%2Fmediahub.polri.go.id%2F${typeString}%2Fdetail%2F${content?.id}&text=${content?.title}`)}>
<Icon icon="mdi:twitter" width="23" className="text-red-600 text-center" />
</a>
<a className="ml-5 cursor-pointer" onClick={() => handleShare("wa", `text=${content?.title}%0D%0A%0D%0Ahttps%3A%2F%2Fmediahub.polri.go.id%2F${typeString}%2Fdetail%2F${content?.id}`)}>
<Icon icon="ri:whatsapp-fill" width="23" className="text-red-600 text-center" />
</a>
<Popover>
<PopoverTrigger className="flex justify-end gap-1 cursor-pointer" asChild>
<a className="ml-5 cursor-pointer" data-toggle="dropdown" href="#" aria-expanded="false">
<Icon icon="material-symbols-light:mail" width="23" className="text-red-600 text-center" />
</a>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">{t("shareTo")}</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("pressEnter")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
{t("send")}
</Button>
</div>
</PopoverContent>
</Popover>
</div>
</div>
</div>
</div>
<div className="w-full mb-8">
{/* Comment */}
<div className="flex flex-col my-16 p-10 bg-[#f7f7f7]">
<div className="gap-5 flex flex-col px-4 lg:px-16">
<p className="flex items-start text-lg">Berikan Komentar</p>
<Textarea placeholder="Type your comments here." className="flex w-full" />
<button className="flex items-start bg-[#bb3523] rounded-lg text-white w-fit px-4 py-1">Kirim</button>
<div className="flex flex-col my-16 p-4 lg:p-10 bg-[#f7f7f7]">
<div className="gap-5 flex flex-col px-4 lg:px-14">
<p className="flex items-start text-lg">{t("comment")}</p>
<Textarea placeholder="Type your comments here." className="flex w-full pb-12" onChange={getInputValue} />
<button onClick={() => postData()} className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-4 py-1">
{t("send")}
</button>
</div>
<div className="border-b-2 border-slate-300 mt-4 w-auto"></div>
<div>
{listSuggestion?.map((data: any) => (
<div className="flex flex-col">
<div className="flex flex-row mt-2 px-4 lg:px-14">
<img src={data?.suggestionFrom?.profilePictureUrl} className="h-12 lg:h-16 w-12 lg:w-16 mr-2" onError={addDefaultProfile} alt="" />
<div className="border border-slate-300 w-full p-2 lg:p-4 bg-white gap-1">
<p className="text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
{Number(data.suggestionFrom?.roleId) == 2 || Number(data.suggestionFrom?.roleId) == 3 || Number(data.suggestionFrom?.roleId) == 4 ? "HUMAS POLRI" : data.suggestionFrom?.fullname}
{getPublicLocaleTimestamp(new Date(data.createdAt))}
</p>
<p className="text-slate-500 text-[13px] lg:text-sm mb-4">{data?.message}</p>
<div>
<a
style={
Number(data.suggestionFrom?.id) == Number(userId)
? {
display: "none",
}
: {}
}
onClick={() => showInput(`comment-id-${data.id}`)}
className="mr-2"
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("reply")}</small>
</a>
{Number(data.suggestionFrom?.id) == Number(userId) || Number(userRoleId) == 2 ? (
<a onClick={() => deleteData(data.id)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("delete")}</small>
</a>
) : (
""
)}
</div>
</div>
</div>
{visibleInput === `comment-id-${data.id}` && (
<div id={`comment-id-${data.id}`} className="px-4 pl-[72px] lg:px-14 lg:pl-32 mt-2 ">
<Textarea id={`input-comment-${data.id}`} className="p-4 focus:outline-none focus:border-sky-500" placeholder={t("enterReply")} />
<div className="flex flex-row gap-3">
<a onClick={() => postDataChild(data.id)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 mt-2 cursor-pointer">{t("send")}</small>
</a>
<a onClick={() => showInput(`comment-id-${data.id}`)}>
<small className="flex items-start bg-[#bb3523] rounded-lg mt-2 w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("cancel")}</small>
</a>
</div>
</div>
)}
{data.children.length > 0
? data.children?.map((child1: any) => (
<div className="flex flex-col">
<div className="flex flex-row mt-2 px-4 lg:pr-14 pl-16 lg:pl-32">
<img src={child1.suggestionFrom?.profilePictureUrl} onError={addDefaultProfile} alt="" className="h-10 lg:h-16 w-10 lg:w-16 mr-2" />
<div className="border border-slate-300 w-full p-2 lg:p-4 bg-white gap-1">
<p className="text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
{" "}
<b>{Number(child1.suggestionFrom?.roleId) == 2 || Number(child1.suggestionFrom?.roleId) == 3 || Number(child1.suggestionFrom?.roleId) == 4 ? "HUMAS POLRI" : child1.suggestionFrom?.fullname}</b>{" "}
{getPublicLocaleTimestamp(new Date(child1.createdAt))}
</p>
<p className="text-slate-500 text-[13px] lg:text-sm mb-4">{parse(String(child1?.message))}</p>
<div>
<a
style={
Number(child1.suggestionFrom?.id) == Number(userId)
? {
display: "none",
}
: {}
}
onClick={() => showInput(`comment-id-${child1.id}`)}
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("reply")}</small>
</a>
<a
style={
Number(child1.suggestionFrom?.id) == Number(userId)
? {}
: {
display: "none",
}
}
onClick={() => deleteData(child1.id)}
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("delete")}</small>
</a>
</div>
</div>
</div>
{visibleInput === `comment-id-${child1.id}` && (
<div id={`comment-id-${child1.id}`} className="px-4 lg:px-14 pl-28 lg:pl-[200px]">
<Textarea name="" className="mt-2 " id={`input-comment-${child1.id}`} placeholder={t("enterReply")} />
<div className="flex flex-row mt-2 gap-3">
<a onClick={() => postDataChild(child1.id)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("send")}</small>
</a>
<a onClick={() => showInput(`comment-id-${child1.id}`)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("cancel")}</small>
</a>
</div>
</div>
)}
{child1.children.length > 0
? child1.children?.map((child2: any) => (
<div className="">
<div className="flex flex-row mt-2 px-4 lg:pr-14 pl-28 lg:pl-48">
<img src={child2.suggestionFrom?.profilePictureUrl} className="h-9 lg:h-16 w-9 lg:w-16 mr-2" onError={addDefaultProfile} alt="" />
<div className="border border-slate-300 w-full p-2 lg:p-4 bg-white gap-1">
<p className="text-slate-500 text-sm lg:text-base border-b-2 border-slate-200 mb-2">
{" "}
<b>{Number(child2.suggestionFrom?.roleId) == 2 || Number(child2.suggestionFrom?.roleId) == 3 || Number(child2.suggestionFrom?.roleId) == 4 ? "HUMAS POLRI" : child2.suggestionFrom?.fullname}</b>{" "}
{getPublicLocaleTimestamp(new Date(child2.createdAt))}
</p>
<p className="text-slate-500 text-sm mb-4">{parse(String(child2?.message))}</p>
<div>
<a
style={
Number(child2.suggestionFrom?.id) == Number(userId)
? {
display: "none",
}
: {}
}
onClick={() => showInput(`comment-id-${child2.id}`)}
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("reply")}</small>
</a>
<a
style={
Number(child2.suggestionFrom?.id) == Number(userId)
? {}
: {
display: "none",
}
}
onClick={() => deleteData(child2.id)}
>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("delete")}</small>
</a>
</div>
</div>
</div>
{visibleInput === `comment-id-${child2.id}` && (
<div id={`comment-id-${child2.id}`} className="px-4 lg:px-14 pl-40 lg:pl-[265px]">
<Textarea name="" id={`input-comment-${child2.id}`} className="my-2" placeholder={t("enterReply")} />
<div className="flex flex-row gap-3">
<a onClick={() => postDataChild(child2.id)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("send")}</small>
</a>
<a onClick={() => showInput(`comment-id-${child2.id}`)}>
<small className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-2 text-xs lg:text-base lg:px-4 py-1 cursor-pointer">{t("cancel")}</small>
</a>
</div>
</div>
)}
</div>
))
: ""}
</div>
))
: ""}
</div>
))}
</div>
</div>

View File

@ -17,7 +17,7 @@ import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import { checkMaliciousText, getPublicLocaleTimestamp } from "@/utils/globals";
import { checkMaliciousText, formatDateToIndonesian, getPublicLocaleTimestamp } from "@/utils/globals";
import parse from "html-react-parser";
import $ from "jquery";
import { useTranslations } from "next-intl";
@ -594,12 +594,17 @@ const DetailAudio = () => {
<p className="text-xs lg:text-sm">
{t("by")}&nbsp;<span className="font-semibold text-black">{detailDataAudio?.uploadedBy?.userLevel?.name}</span>
</p>
<p className="text-xs lg:text-sm">
{/* <p className="text-xs lg:text-sm">
&nbsp;|&nbsp;{t("updatedOn")} {detailDataAudio?.updatedAt} WIB &nbsp;|&nbsp;
</p> */}
<p className="text-xs lg:text-sm">
&nbsp;|&nbsp;{t("updatedOn")}&nbsp;
{formatDateToIndonesian(new Date(detailDataAudio?.updatedAt))} {"WIB"}
</p>
<p className="text-xs lg:text-sm flex justify-center items-center">
&nbsp;| &nbsp;
<Icon icon="formkit:eye" width="15" height="15" />
&nbsp; {detailDataAudio?.clickCount} &nbsp;
&nbsp;{detailDataAudio?.clickCount}&nbsp;
</p>
</div>
<div className="mt-3">
@ -611,7 +616,7 @@ const DetailAudio = () => {
{/* Keterangan */}
<div className="w-full">
<h1 className="flex flex-row font-bold text-lg lg:text-2xl my-8">{detailDataAudio?.title}</h1>
<div className="font-light text-justify mb-5 lg:mb-0" dangerouslySetInnerHTML={{ __html: detailDataAudio?.htmlDescription }} />
<div className="font-light text-justify mb-5 lg:mb-0 space-y-4" dangerouslySetInnerHTML={{ __html: detailDataAudio?.htmlDescription }} />
</div>
</div>
@ -724,7 +729,7 @@ const DetailAudio = () => {
<p className="flex items-start text-lg">{t("comment")}</p>
<Textarea placeholder="Type your comments here." className="flex w-full pb-12" onChange={getInputValue} />
<button onClick={() => postData()} className="flex items-start bg-[#bb3523] rounded-lg w-fit text-white px-4 py-1">
{t("send")}
{t("send")}
</button>
</div>

View File

@ -1,59 +1,159 @@
"use client";
import { Reveal } from "@/components/landing-page/Reveal";
import React from "react";
import { getCookiesDecrypt } from "@/lib/utils";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
import { yupResolver } from "@hookform/resolvers/yup";
import * as Yup from "yup";
import { useForm } from "react-hook-form";
import { getInfoProfile, getProfile, getSubjects } from "@/service/auth";
import { close, error, loading, successCallback } from "@/config/swal";
import { sendMessage } from "@/service/landing/landing";
import { useTranslations } from "next-intl";
const ContactForm = () => {
const router = useRouter();
const userId = getCookiesDecrypt("uie");
const [subjects, setSubjects] = useState<any>();
const [isOtherActive, setIsOtherActive] = useState(false);
const t = useTranslations("LandingPage");
const form = document.getElementById("form") as HTMLFormElement;
// Form Handling
const validationSchema = Yup.object().shape({
name: Yup.string().required("Nama tidak boleh kosong"),
email: Yup.string().required("Email tidak boleh kosong"),
subjects: Yup.string().required("Subjek tidak boleh kosong"),
message: Yup.string().required("Pesan tidak boleh kosong"),
});
const formOptions = {
resolver: yupResolver(validationSchema),
};
const { register, handleSubmit, formState, setValue } = useForm(formOptions);
const { errors } = formState;
useEffect(() => {
async function initState() {
const response = await getInfoProfile();
const responseSubject = await getSubjects();
const profile = response?.data?.data;
setSubjects(responseSubject?.data?.data);
console.log(response);
setValue("name", profile?.fullname);
setValue("email", profile?.email); // setValue('name', profile?.fullname);
// setValue('name', profile?.fullname);
}
initState();
}, []);
async function save(data: any) {
loading();
const finalData = {
name: data.name,
email: data.email,
phone: data.phone,
title: isOtherActive ? data.othersubject : data.subjects,
message: data.message,
};
const response = await sendMessage(finalData);
if (response?.error) {
error(response?.message);
return false;
}
close();
successCallback("Terima kasih, pesan Anda telah terkirim");
// $("#form")[0].onreset();
if (form) {
form.reset();
}
}
async function onSubmit(data: any) {
if (userId == undefined) {
router.push("/auth/login");
} else {
save(data);
}
}
const handleSubjects = (e: any) => {
const id = e.target.value;
if (id == "Lainnya") {
setIsOtherActive(true);
} else {
setIsOtherActive(false);
}
};
return (
<div className="max-w-2xl mx-auto bg-white p-6">
<form method="POST" id="form" onSubmit={handleSubmit(onSubmit)} className="max-w-2xl mx-auto bg-white p-6">
<Reveal>
{/* Header */}
<div className="flex items-center justify-center mb-6">
<img src="/assets/icons-contact.png" alt="contact" />
<h2 className="ml-4 text-2xl font-bold">Hubungi Kami</h2>
<h2 className="ml-4 text-2xl font-bold">{t("contactUs")}</h2>
</div>
<h3 className="text-lg font-semibold text-gray-800 mb-1">Tulis Pesan</h3>
<p className="text-sm text-gray-600 mb-6">Silahkan tinggalkan pesan Anda pada kolom yang tersedia</p>
<h3 className="text-lg font-semibold text-gray-800 mb-1">{t("writeMessage")}</h3>
<p className="text-sm text-gray-600 mb-6">{t("leaveMessage")}</p>
{/* Form */}
<form>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">Nama</label>
<input type="text" placeholder="Masukkan nama lengkap Anda" className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" required />
<label className="block text-sm font-medium text-gray-700 mb-1">{t("name")}</label>
<input type="text" placeholder={t("enterName")} className={`w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.name ? "block" : ""}`} {...register("name")} required />
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" placeholder="name@mail.com" className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" required />
<input type="email" placeholder="name@mail.com" className={`w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.email ? "block" : ""}`} {...register("email")} required />
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">No. Handphone (Optional)</label>
<input type="text" placeholder="Masukkan no.handphone" className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" />
<label className="block text-sm font-medium text-gray-700 mb-1">{t("number")} (Optional)</label>
<input type="text" placeholder={t("enterNumber")} className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" />
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">Subjek</label>
<select className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" defaultValue="">
<label className="block text-sm font-medium text-gray-700 mb-1">{t("subject")}</label>
<select
className={`w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.subjects ? "block" : ""}`}
{...register("subjects", { onChange: (e) => handleSubjects(e) })}
defaultValue=""
>
<option value="" disabled>
Pilih Subjek
{t("selectSubject")}
</option>
<option value="1">Pertanyaan</option>
<option value="2">Kritik</option>
<option value="3">Saran</option>
{/* <option value="1">{t("question")}</option>
<option value="2">{t("criticism")}</option>
<option value="3">{t("suggestion")}</option> */}
{subjects?.map((list: any) => (
<option key={list.id} value={list.title}>
{list.title}
</option>
))}
</select>
</div>
<div className="mb-4">
<label className="block text-sm font-medium text-gray-700 mb-1">Pesan</label>
<textarea placeholder="Tulis pesan Anda" rows={4} className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
<label className="block text-sm font-medium text-gray-700 mb-1">{t("messages")}</label>
<textarea placeholder={t("writeYourMessage")} rows={4} className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
</div>
<button type="submit" className="w-fit bg-blue-500 flex justify-self-end text-white p-2 px-8 rounded-md hover:bg-blue-600 transition">
Kirim
{t("send")}
</button>
</form>
</Reveal>
</div>
</form>
);
};

View File

@ -5,7 +5,7 @@ import { checkWishlistStatus, deleteWishlist, getInfoProfile, mediaWishlist, sav
import React, { useEffect, useState } from "react";
import { Link, useRouter } from "@/i18n/routing";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useSearchParams } from "next/navigation";
import { usePathname, useSearchParams } from "next/navigation";
import { Card, CardContent } from "@/components/ui/card";
import HeaderManagement from "@/components/landing-page/header-management";
import SidebarManagement from "@/components/landing-page/sidebar-management";
@ -19,6 +19,7 @@ import { Button } from "@/components/ui/button";
import { sendMediaUploadToEmail } from "@/service/media-tracking/media-tracking";
import ImageBlurry from "@/components/ui/image-blurry";
import Image from "next/image";
import { useTranslations } from "next-intl";
const Galery = (props: any) => {
const [profile, setProfile] = useState<any>();
@ -26,6 +27,7 @@ const Galery = (props: any) => {
const router = useRouter();
const MySwal = withReactContent(Swal);
const searchParams = useSearchParams();
const pathname = usePathname();
const page: any = searchParams?.get("page");
const title = searchParams?.get("title");
const category = searchParams?.get("category");
@ -50,6 +52,7 @@ const Galery = (props: any) => {
const [emailShareInput, setEmailShareInput] = useState<any>();
const [emailMessageInput, setEmailMessageInput] = useState();
const id = searchParams?.get("id");
const t = useTranslations("LandingPage");
useEffect(() => {
getDataVideo();
@ -278,98 +281,117 @@ const Galery = (props: any) => {
<HeaderManagement />
<div className="flex flex-col lg:flex-row">
<SidebarManagement />
<div className="w-full lg:w-2/3 p-8 lg:p-12">
<div>
<h1 className="text-2xl font-semibold mb-3">Galeri Saya</h1>
</div>
<div className="flex flex-col">
<div className="w-full lg:w-2/3 p-8 lg:p-0 mt-12">
<div className="flex flex-col mt-4">
<div className="mx-auto w-full max-w-7xl justify-start flex flex-col lg:flex-row gap-5 mb-4">
<h1 className="text-2xl w-fit font-bold bg-[#bb3523] px-4 py-1 rounded-lg text-center text-white">
{/* <span className="text-black">Galeri </span>
Saya */}
{pathname?.split("/")[1] == "in" ? (
<>
<span className="text-black ">{t("gallery")}</span>&nbsp;
{t("my")}
</>
) : (
<>
<span className="text-black">{t("my")}</span>&nbsp;
{t("gallery")}
</>
)}
</h1>
<Tabs value={selectedTab} onValueChange={setSelectedTab}>
<TabsList className="grid grid-cols-2 lg:flex lg:flex-row ">
<TabsTrigger
value="image"
className="relative text-xs md:text-xl font-bold text-black dark:text-white dark:bg-transparent before:absolute before:top-full before:left-0 before:h-px before:w-full data-[state=active]:before:bg-primary"
>
Foto
{t("image")}
</TabsTrigger>
<div className="text-[#bb3523] text-lg hidden md:inline-block">|</div>
<TabsTrigger
value="video"
className="relative text-xs md:text-xl font-bold text-black dark:text-white dark:bg-transparent before:absolute before:top-full before:left-0 before:h-px before:w-full data-[state=active]:before:bg-primary"
>
Audio Visual
{t("video")}
</TabsTrigger>
<div className="text-[#bb3523] text-lg hidden md:inline-block">|</div>
<TabsTrigger
value="text"
className="relative text-xs md:text-xl font-bold text-black dark:text-white dark:bg-transparent before:absolute before:top-full before:left-0 before:h-px before:w-full data-[state=active]:before:bg-primary"
>
Teks
{t("text")}
</TabsTrigger>
<div className="text-[#bb3523] text-lg hidden md:inline-block">|</div>
<TabsTrigger
value="audio"
className="relative text-xs md:text-xl font-bold text-black dark:text-white dark:bg-transparent before:absolute before:top-full before:left-0 before:h-px before:w-full data-[state=active]:before:bg-primary"
>
Audio
{t("audio")}
</TabsTrigger>
</TabsList>
</Tabs>
</div>
<div className="">
{selectedTab == "video" ? (
contentVideo?.length > 0 ? (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{contentVideo?.map((video: any) => (
<Card key={video?.id}>
<CardContent className="flex flex-col bg-black dark:bg-white w-full rounded-lg p-0">
<Card key={video?.id} className="hover:scale-105 transition-transform duration-300">
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
<div>
<Link href={`/video/detail/${video?.mediaUpload?.slug}`}>
{/* <img src={video?.mediaUpload?.thumbnailLink} className="h-40 object-cover items-center justify-center cursor-pointer rounded-lg " /> */}
<div className="img-container h-60 bg-[#e9e9e9] cursor-pointer rounded-lg">
<ImageBlurry src={video?.mediaUpload?.thumbnailLink} alt={video?.mediaUpload?.title} style={{ objectFit: "contain", width: "100%", height: "100%" }} />
</div>
</Link>
<div className="font-semibold p-4 text-white text-xs lg:text-sm dark:text-black truncate w-full">{video?.mediaUpload?.title}</div>
<Popover>
<PopoverTrigger className="flex justify-end gap-1 cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<Link href={`/content-management/rewrite/create/${video?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
</Link>
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex items-center gap-3">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-3">Bagikan</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">Share Ke Email</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">Email Tujuan :</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder="Tekan Enter untuk input Email" />
<div className="relative group overflow-hidden shadow-md hover:shadow-lg">
<div className="relative h-60 rounded-lg overflow-hidden">
<ImageBlurry src={video?.mediaUpload?.thumbnailLink} alt={video?.mediaUpload?.title} style={{ objectFit: "cover", width: "100%", height: "100%" }} />
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-transparent via-gray-900/80 to-transparent text-white">
<Link href={`/video/detail/${video?.mediaUpload?.slug}`}>
<p className="text-sm p-2 lg:text-base font-semibold truncate">{video?.mediaUpload?.title}</p>
</Link>
<p className="flex text-[10px] ml-1 mb-2 items-end">
<Popover>
<PopoverTrigger className="flex cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(video?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">{t("save")}</p>
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
Kirim
</Button>
</div>
</PopoverContent>
</Popover>
<Link href={`/content-management/rewrite/create/${video?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
</Link>
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex flex-row items-center gap-3">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-1">{t("share")}</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">{t("shareTo")}</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("pressEnter")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
{t("send")}
</Button>
</div>
</PopoverContent>
</Popover>
</div>
</PopoverContent>
</Popover>
</p>
</div>
<a onClick={() => handleDelete(video?.id)} className="flex items-center gap-3 hover:text-red-800 w-full rounded-lg">
<Icon icon="fa:trash" fontSize={20} />
<p className="text-base font-semibold">Hapus</p>
</a>
</PopoverContent>
</Popover>
</div>
</div>
</div>
</CardContent>
</Card>
@ -414,12 +436,16 @@ const Galery = (props: any) => {
</div>
</div>
<Popover>
<PopoverTrigger className="flex justify-end gap-1 cursor-pointer" asChild>
<PopoverTrigger className="flex cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(audio?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">{t("save")}</p>
</div>
<Link href={`/content-management/rewrite/create/${audio?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
@ -427,29 +453,25 @@ const Galery = (props: any) => {
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex items-center gap-3">
<button className="w-full flex flex-row items-center gap-3">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-3">Bagikan</p>
<p className="text-base font-semibold mb-1">{t("share")}</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">Share Ke Email</h1>
<h1 className="mb-2">{t("shareTo")}</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">Email Tujuan :</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder="Tekan Enter untuk input Email" />
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("pressEnter")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
Kirim
{t("send")}
</Button>
</div>
</PopoverContent>
</Popover>
</div>
<a onClick={() => handleDelete(audio?.id)} className="flex items-center gap-3 hover:text-red-800 w-full rounded-lg">
<Icon icon="fa:trash" fontSize={20} />
<p className="text-base font-semibold">Hapus</p>
</a>
</PopoverContent>
</Popover>
</div>
@ -464,54 +486,61 @@ const Galery = (props: any) => {
contentImage?.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{contentImage?.map((image: any) => (
<Card key={image?.id}>
<CardContent className="flex flex-col bg-black dark:bg-white w-full h-full rounded-lg p-0">
<Link href={`/image/detail/${image?.mediaUpload?.slug}`}>
{/* <img src={image?.mediaUpload?.thumbnailLink} className="h-40 object-cover items-center justify-center cursor-pointer rounded-lg place-self-center" /> */}
<div className="img-container h-60 bg-[#e9e9e9] cursor-pointer rounded-lg">
<ImageBlurry src={image?.mediaUpload?.thumbnailLink} alt={image?.mediaUpload?.title} style={{ objectFit: "contain", width: "100%", height: "100%" }} />
</div>
</Link>
<div className="font-semibold p-4 text-white text-xs lg:text-sm dark:text-black truncate w-full">{image?.mediaUpload?.title}</div>
<Popover>
<PopoverTrigger className="flex justify-end gap-1 cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<Link href={`/content-management/rewrite/create/${image?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
</Link>
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex items-center gap-3">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-3">Bagikan</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">Share Ke Email</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">Email Tujuan :</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder="Tekan Enter untuk input Email" />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
Kirim
</Button>
</div>
</PopoverContent>
</Popover>
<Card key={image?.id} className="hover:scale-105 transition-transform duration-300">
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
<div>
<div className="relative group overflow-hidden shadow-md hover:shadow-lg">
<div className="relative h-60 rounded-lg overflow-hidden">
<ImageBlurry src={image?.mediaUpload?.thumbnailLink} alt={image?.mediaUpload?.title} style={{ objectFit: "cover", width: "100%", height: "100%" }} />
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-transparent via-gray-900/80 to-transparent text-white">
<Link href={`/video/detail/${image?.mediaUpload?.slug}`}>
<p className="text-sm p-2 lg:text-base font-semibold truncate">{image?.mediaUpload?.title}</p>
</Link>
<p className="flex text-[10px] ml-1 mb-2 items-end">
<Popover>
<PopoverTrigger className="flex cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(image?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">{t("save")}</p>
</div>
<Link href={`/content-management/rewrite/create/${image?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
</Link>
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex flex-row items-center gap-3">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-1"> {t("share")}</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">{t("shareTo")}</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("pressEnter")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
{t("send")}
</Button>
</div>
</PopoverContent>
</Popover>
</div>
</PopoverContent>
</Popover>
</p>
</div>
</div>
<a onClick={() => handleDelete(image?.id)} className="flex items-center gap-3 hover:text-red-800 w-full rounded-lg">
<Icon icon="fa:trash" fontSize={20} />
<p className="text-base font-semibold">Hapus</p>
</a>
</PopoverContent>
</Popover>
</div>
</div>
</CardContent>
</Card>
))}
@ -542,7 +571,7 @@ const Galery = (props: any) => {
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 512 512">
<path fill="#f00" d="M224 30v256h-64l96 128l96-128h-64V30zM32 434v48h448v-48z" />
</svg>
Download Dokumen
Download {t("document")}
</div>
</div>
<Popover>
@ -552,6 +581,10 @@ const Galery = (props: any) => {
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(document?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">{t("save")}</p>
</div>
<Link href={`/content-management/rewrite/create/${document?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
@ -559,29 +592,25 @@ const Galery = (props: any) => {
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex items-center gap-3">
<button className="w-full flex items-center gap-2">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-3">Bagikan</p>
<p className="text-base font-semibold mb-2">{t("share")}</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">Share Ke Email</h1>
<h1 className="mb-2">{t("shareTo")}</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">Email Tujuan :</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder="Tekan Enter untuk input Email" />
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("pressEnter")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
Kirim
{t("send")}
</Button>
</div>
</PopoverContent>
</Popover>
</div>
<a onClick={() => handleDelete(document?.id)} className="flex items-center gap-3 hover:text-red-800 w-full rounded-lg">
<Icon icon="fa:trash" fontSize={20} />
<p className="text-base font-semibold">Hapus</p>
</a>
</PopoverContent>
</Popover>
</div>

View File

@ -21,6 +21,7 @@ import { Button } from "@/components/ui/button";
import { sendMediaUploadToEmail } from "@/service/media-tracking/media-tracking";
import ImageBlurry from "@/components/ui/image-blurry";
import Image from "next/image";
import { useTranslations } from "next-intl";
const Galery = (props: any) => {
const [profile, setProfile] = useState<any>();
@ -53,6 +54,7 @@ const Galery = (props: any) => {
const [emailShareInput, setEmailShareInput] = useState<any>();
const [emailMessageInput, setEmailMessageInput] = useState();
const id = searchParams?.get("id");
const t = useTranslations("LandingPage");
useEffect(() => {
getDataVideo();
@ -284,98 +286,105 @@ const Galery = (props: any) => {
<HeaderManagement />
<div className="flex flex-col lg:flex-row">
<SidebarManagement />
<div className="w-full lg:w-2/3 p-8 lg:p-12">
<div>
<h1 className="text-2xl font-semibold">Galeri {profile?.institute?.name}</h1>
</div>
<div className="w-full lg:w-2/3 p-8 lg:p-0 mt-12">
<div className="flex flex-col mt-4">
<div className="mx-auto w-full max-w-7xl justify-start flex flex-col lg:flex-row gap-5 mb-4">
<h1 className="text-2xl w-fit font-bold bg-[#bb3523] px-4 py-1 rounded-lg text-center text-white">
<span className="text-black">{t("gallery")} </span>
{profile?.institute?.name}
</h1>
<Tabs value={selectedTab} onValueChange={setSelectedTab}>
<TabsList className="grid grid-cols-2 lg:flex lg:flex-row ">
<TabsTrigger
value="image"
className="relative text-xs md:text-xl font-bold text-black dark:text-white dark:bg-transparent before:absolute before:top-full before:left-0 before:h-px before:w-full data-[state=active]:before:bg-primary"
>
Foto
{t("image")}
</TabsTrigger>
<div className="text-[#bb3523] text-lg hidden md:inline-block">|</div>
<TabsTrigger
value="video"
className="relative text-xs md:text-xl font-bold text-black dark:text-white dark:bg-transparent before:absolute before:top-full before:left-0 before:h-px before:w-full data-[state=active]:before:bg-primary"
>
Audio Visual
{t("video")}
</TabsTrigger>
<div className="text-[#bb3523] text-lg hidden md:inline-block">|</div>
<TabsTrigger
value="text"
className="relative text-xs md:text-xl font-bold text-black dark:text-white dark:bg-transparent before:absolute before:top-full before:left-0 before:h-px before:w-full data-[state=active]:before:bg-primary"
>
Teks
{t("text")}
</TabsTrigger>
<div className="text-[#bb3523] text-lg hidden md:inline-block">|</div>
<TabsTrigger
value="audio"
className="relative text-xs md:text-xl font-bold text-black dark:text-white dark:bg-transparent before:absolute before:top-full before:left-0 before:h-px before:w-full data-[state=active]:before:bg-primary"
>
Audio
{t("audio")}
</TabsTrigger>
</TabsList>
</Tabs>
</div>
<div className="px-2">
{selectedTab == "video" ? (
contentVideo?.length > 0 ? (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{contentVideo?.map((video: any) => (
<Card key={video?.id}>
<CardContent className="flex flex-col bg-black dark:bg-white w-full rounded-lg p-0">
<Card key={video?.id} className="hover:scale-105 transition-transform duration-300">
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
<div>
<Link href={`/video/detail/${video?.mediaUpload?.slug}`}>
{/* <img src={video?.mediaUpload?.thumbnailLink} className="h-40 object-cover items-center justify-center cursor-pointer rounded-lg place-self-center" /> */}
<div className="img-container h-60 bg-[#e9e9e9] cursor-pointer rounded-lg">
<ImageBlurry src={video?.mediaUpload?.thumbnailLink} alt={video?.mediaUpload?.title} style={{ objectFit: "contain", width: "100%", height: "100%" }} />
</div>
</Link>
<div className="font-semibold p-4 text-white text-xs lg:text-sm dark:text-black truncate w-full">{video?.mediaUpload?.title}</div>
<Popover>
<PopoverTrigger className="flex justify-end gap-1 cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(video?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">Simpan</p>
</div>
<Link href={`/content-management/rewrite/create/${video?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
</Link>
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex flex-row items-center gap-3">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-1">Bagikan</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">Share Ke Email</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">Email Tujuan :</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder="Tekan Enter untuk input Email" />
<div className="relative group overflow-hidden shadow-md hover:shadow-lg">
<div className="relative h-60 rounded-lg overflow-hidden">
<ImageBlurry src={video?.mediaUpload?.thumbnailLink} alt={video?.mediaUpload?.title} style={{ objectFit: "cover", width: "100%", height: "100%" }} />
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-transparent via-gray-900/80 to-transparent text-white">
<Link href={`/video/detail/${video?.mediaUpload?.slug}`}>
<p className="text-sm p-2 lg:text-base font-semibold truncate">{video?.mediaUpload?.title}</p>
</Link>
<p className="flex text-[10px] ml-1 mb-2 items-end">
<Popover>
<PopoverTrigger className="flex cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(video?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">{t("save")} </p>
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
Kirim
</Button>
</div>
</PopoverContent>
</Popover>
<Link href={`/content-management/rewrite/create/${video?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
</Link>
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex flex-row items-center gap-3">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-1">{t("share")} </p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">{t("shareTo")} </h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("shareTo")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
{t("send")}
</Button>
</div>
</PopoverContent>
</Popover>
</div>
</PopoverContent>
</Popover>
</p>
</div>
</PopoverContent>
</Popover>
</div>
</div>
</div>
</CardContent>
</Card>
@ -426,7 +435,7 @@ const Galery = (props: any) => {
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(audio?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">Simpan</p>
<p className="text-base font-semibold mb-2">{t("save")}</p>
</div>
<Link href={`/content-management/rewrite/create/${audio?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
@ -437,18 +446,18 @@ const Galery = (props: any) => {
<PopoverTrigger asChild>
<button className="w-full flex items-center gap-2">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-2">Bagikan</p>
<p className="text-base font-semibold mb-2">{t("share")}</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">Share Ke Email</h1>
<h1 className="mb-2">{t("shareTo")}</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">Email Tujuan :</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder="Tekan Enter untuk input Email" />
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("pressEnter")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
Kirim
{t("send")}
</Button>
</div>
</PopoverContent>
@ -468,54 +477,61 @@ const Galery = (props: any) => {
contentImage?.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{contentImage?.map((image: any) => (
<Card key={image?.id}>
<CardContent className="flex flex-col bg-black dark:bg-white w-full rounded-lg p-0">
<Link href={`/image/detail/${image?.mediaUpload?.slug}`}>
{/* <img src={image?.mediaUpload?.thumbnailLink} className="h-40 object-cover items-center justify-center cursor-pointer rounded-lg place-self-center" /> */}
<div className="img-container h-60 bg-[#e9e9e9] cursor-pointer rounded-lg">
<ImageBlurry src={image?.mediaUpload?.thumbnailLink} alt={image?.mediaUpload?.title} style={{ objectFit: "contain", width: "100%", height: "100%" }} />
<Card key={image?.id} className="hover:scale-105 transition-transform duration-300">
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
<div>
<div className="relative group overflow-hidden shadow-md hover:shadow-lg">
<div className="relative h-60 rounded-lg overflow-hidden">
<ImageBlurry src={image?.mediaUpload?.thumbnailLink} alt={image?.mediaUpload?.title} style={{ objectFit: "cover", width: "100%", height: "100%" }} />
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-transparent via-gray-900/80 to-transparent text-white">
<Link href={`/video/detail/${image?.mediaUpload?.slug}`}>
<p className="text-sm p-2 lg:text-base font-semibold truncate">{image?.mediaUpload?.title}</p>
</Link>
<p className="flex text-[10px] ml-1 mb-2 items-end">
<Popover>
<PopoverTrigger className="flex cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(image?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">{t("save")}</p>
</div>
<Link href={`/content-management/rewrite/create/${image?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
</Link>
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex flex-row items-center gap-3">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-1"> {t("share")}</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">{t("shareTo")}</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("pressEnter")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
{t("send")}
</Button>
</div>
</PopoverContent>
</Popover>
</div>
</PopoverContent>
</Popover>
</p>
</div>
</div>
</div>
</Link>
<div className="font-semibold p-4 text-white text-xs lg:text-sm dark:text-black truncate w-full">{image?.mediaUpload?.title}</div>
<Popover>
<PopoverTrigger className="flex justify-end gap-1 cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(image?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">Simpan</p>
</div>
<Link href={`/content-management/rewrite/create/${image?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
</Link>
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex items-center gap-2">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-2">Bagikan</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">Share Ke Email</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">Email Tujuan :</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder="Tekan Enter untuk input Email" />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
Kirim
</Button>
</div>
</PopoverContent>
</Popover>
</div>
</PopoverContent>
</Popover>
</div>
</CardContent>
</Card>
))}
@ -546,7 +562,7 @@ const Galery = (props: any) => {
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 512 512">
<path fill="#f00" d="M224 30v256h-64l96 128l96-128h-64V30zM32 434v48h448v-48z" />
</svg>
Download Dokumen
Download {t("document")}
</div>
</div>
<Popover>
@ -558,7 +574,7 @@ const Galery = (props: any) => {
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(document?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">Simpan</p>
<p className="text-base font-semibold mb-2">{t("save")}</p>
</div>
<Link href={`/content-management/rewrite/create/${document?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
@ -569,18 +585,18 @@ const Galery = (props: any) => {
<PopoverTrigger asChild>
<button className="w-full flex items-center gap-2">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-2">Bagikan</p>
<p className="text-base font-semibold mb-2">{t("share")}</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">Share Ke Email</h1>
<h1 className="mb-2">{t("shareTo")}</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">Email Tujuan :</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder="Tekan Enter untuk input Email" />
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("pressEnter")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
Kirim
{t("send")}
</Button>
</div>
</PopoverContent>

View File

@ -21,10 +21,10 @@ import { getPublicSuggestionList } from "@/service/landing/landing";
import { getDetail } from "@/service/detail/detail";
import { yupResolver } from "@hookform/resolvers/yup";
import * as Yup from "yup";
import { htmlToString } from "@/utils/globals";
import Cookies from "js-cookie";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { useTranslations } from "next-intl";
const imageSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }),
@ -63,6 +63,7 @@ const page = (props: any) => {
const [isLoadingData, setIsLoadingData] = useState<boolean>(false);
const [detailData, setDetailData] = useState<any>(null);
const [articleImages, setArticleImages] = useState<string[]>([]);
const t = useTranslations("LandingPage");
const userLevelId = getCookiesDecrypt("ulie");
const roleId = getCookiesDecrypt("urie");
@ -293,21 +294,21 @@ const page = (props: any) => {
<SidebarManagement />
<div className="w-full lg:w-2/3 p-8 lg:p-12">
<div className="flex flex-col">
<div className="text-xl font-bold mb-5">Content Rewrite</div>
<div className="text-xl font-bold mb-5">{t("content")} Rewrite</div>
<div className="p-8 border border-black rounded-lg">
<form method="POST" onSubmit={handleSubmit(onSubmit)}>
{content && (
<div className="flex flex-col gap-2 ">
<div className="flex flex-col lg:flex-row gap-2">
<div className="gap-1 flex flex-col mb-3">
<p className="font-semibold">Bahasa</p>
<p className="font-semibold">{t("language")}</p>
<Select value={selectedLanguage} onValueChange={setSelectedLanguage}>
<SelectTrigger className="w-full lg:w-[180px]">
<SelectValue placeholder="Pilih Bahasa" />
<SelectValue placeholder={t("selectLanguage")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Pilih Bahasa</SelectLabel>
<SelectLabel>{t("selectLanguage")}</SelectLabel>
<SelectItem value="id">Indonesia</SelectItem>
<SelectItem value="en">English</SelectItem>
</SelectGroup>
@ -315,31 +316,31 @@ const page = (props: any) => {
</Select>
</div>
<div className="gap-1 flex flex-col mb-3">
<p className="font-semibold">Context Type</p>
<p className="font-semibold">{t("contextType")}</p>
<Select value={selectedContextType} onValueChange={setSelectedContextType}>
<SelectTrigger className="w-full lg:w-[180px]">
<SelectValue placeholder="Select Context" />
<SelectValue placeholder={t("selectContext")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Select Context Type</SelectLabel>
<SelectItem value="text">Text</SelectItem>
<SelectItem value="article">Article</SelectItem>
<SelectItem value="transcript">Transcript</SelectItem>
<SelectLabel>{t("selectContext")}</SelectLabel>
<SelectItem value="text">{t("text")}</SelectItem>
<SelectItem value="article">{t("article")}</SelectItem>
<SelectItem value="transcript">{t("transcript")}</SelectItem>
<SelectItem value="url">URL</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<div className="gap-1 flex flex-col mb-3">
<p className="font-semibold">Writing Style</p>
<p className="font-semibold">{t("writingStyle")}</p>
<Select value={selectedWritingStyle} onValueChange={setSelectedWritingStyle}>
<SelectTrigger className="w-full lg:w-[180px]">
<SelectValue placeholder="Select Writing" />
<SelectValue placeholder={t("selectWriting")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Select Writing Style</SelectLabel>
<SelectLabel>{t("selectWriting")}</SelectLabel>
<SelectItem value="firendly">Friendly</SelectItem>
<SelectItem value="profesional">Profesional</SelectItem>
<SelectItem value="informational">Informational</SelectItem>
@ -350,14 +351,14 @@ const page = (props: any) => {
</Select>
</div>
<div className="gap-1 flex flex-col mb-3">
<p className="font-semibold">Article Size</p>
<p className="font-semibold">{t("articleSize")}</p>
<Select value={selectedSize} onValueChange={setSelectedSize}>
<SelectTrigger className="w-full lg:w-[180px]">
<SelectValue placeholder="Select Size" />
<SelectValue placeholder={t("selectSize")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Select Article Size</SelectLabel>
<SelectLabel>{t("selectSize")}</SelectLabel>
<SelectItem value="news">News (300 - 900 words)</SelectItem>
<SelectItem value="info">Info (900 - 2000 words)</SelectItem>
<SelectItem value="detail">Detail (2000 - 5000 words)</SelectItem>
@ -367,7 +368,7 @@ const page = (props: any) => {
</div>
</div>
<div className="mb-3">
<p className="font-semibold">Judul</p>
<p className="font-semibold">{t("title")}</p>
<Controller
control={control}
name="title"
@ -375,7 +376,7 @@ const page = (props: any) => {
/>
</div>
<div className="mb-3">
<p className="font-semibold">Main Keyword</p>
<p className="font-semibold">{t("mainKeyword")}</p>
<Controller
control={control}
name="mainKeyword"
@ -418,7 +419,7 @@ const page = (props: any) => {
</div>
<div className=" mb-3">
<p className="font-semibold">Deskripsi Baru</p>
<p className="font-semibold">{t("newDescription")}</p>
<Controller
control={control}
name="description"
@ -442,10 +443,10 @@ const page = (props: any) => {
}}
className="border border-blue-400 hover:bg-blue-400 hover:text-white text-blue-400 text-sm lg:text-base"
>
Kembali
{t("back")}
</Button>
<Button type="submit" className="border border-blue-500 bg-blue-500 text-sm lg:text-base text-white">
Simpan
{t("save")}
</Button>
</div>
</div>

View File

@ -34,15 +34,12 @@ const page = () => {
const userRoleId = getCookiesDecrypt("urie");
const [articleIds, setArticleIds] = useState<any>([]);
const [isGeneratedArticle, setIsGeneratedArticle] = useState(false);
const [selectedArticleId, setSelectedArticleId] = useState(null);
const [articleBody, setArticleBody] = useState<any>("");
const [selectedAdvConfig, setSelectedAdvConfig] = useState("");
const [selectedWritingStyle, setSelectedWritingStyle] = useState("");
const [selectedContextType, setSelectedContextType] = useState("");
const [selectedLanguage, setSelectedLanguage] = useState("");
const [selectedTitle, setSelectedTitle] = useState("");
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
const [selectedSEO, setSelectedSEO] = useState("");
const [selectedSize, setSelectedSize] = useState("");
const [detailArticle, setDetailArticle] = useState<any>(null);
const userLevelId = getCookiesDecrypt("ulie");

View File

@ -18,6 +18,7 @@ import { Button } from "@/components/ui/button";
import { sendMediaUploadToEmail } from "@/service/media-tracking/media-tracking";
import ImageBlurry from "@/components/ui/image-blurry";
import Image from "next/image";
import { useTranslations } from "next-intl";
const page = () => {
const [, setProfile] = useState();
@ -43,6 +44,7 @@ const page = () => {
const [emailShareInput, setEmailShareInput] = useState<any>();
const [emailMessageInput, setEmailMessageInput] = useState();
const id = searchParams?.get("id");
const t = useTranslations("LandingPage");
useEffect(() => {
async function initState() {
@ -200,59 +202,69 @@ const page = () => {
<HeaderManagement />
<div className="flex flex-col lg:flex-row">
<SidebarManagement />
<div className="w-full lg:w-2/3 p-8 lg:p-12">
<div>
<h1 className="text-2xl font-semibold mb-4">Galeri Content Rewrite</h1>
</div>
<div className="w-full lg:w-2/3 p-8 lg:p-14">
<h1 className="text-2xl w-fit font-bold bg-[#bb3523] px-4 py-1 rounded-lg text-center text-white mb-4">
<span className="text-black">{t("gallery")} </span>
{t("content")} Rewrite
</h1>
<div className="">
{contentImage?.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{contentImage?.map((image: any) => (
<Card key={image?.id}>
<CardContent className="flex flex-col bg-black dark:bg-white w-full rounded-lg p-0">
<div className="">
<Link href={`/content-management/rewrite/detail/${image.id}`}>
{/* <img src={image?.thumbnailUrl} className="h-40 object-cover items-center justify-center cursor-pointer rounded-lg place-self-center" /> */}
<div className="img-container h-60 bg-[#e9e9e9] cursor-pointer rounded-lg">
<Card key={image?.id} className="hover:scale-105 transition-transform duration-300">
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
<div>
<div className="relative group overflow-hidden shadow-md hover:shadow-lg">
<div className="relative h-60 rounded-lg overflow-hidden">
<ImageBlurry src={image?.thumbnailUrl} alt={image?.title} style={{ objectFit: "contain", width: "100%", height: "100%" }} />
</div>
</Link>
<div className="font-semibold p-4 text-white text-xs lg:text-sm dark:text-black truncate w-full">{image?.title}</div>
<Popover>
<PopoverTrigger className="flex justify-end gap-1 cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-40">
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex items-center gap-2">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-3">Bagikan</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">Share Ke Email</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">Email Tujuan :</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder="Tekan Enter untuk input Email" />
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-transparent via-gray-900/80 to-transparent text-white">
<Link href={`/content-management/rewrite/detail/${image.id}`}>
<p className="text-sm p-2 lg:text-base font-semibold truncate">{image?.title}</p>
</Link>
<p className="flex text-[10px] ml-1 mb-2 items-end">
<Popover>
<PopoverTrigger className="flex cursor-pointer" asChild>
<a className="flex justify-end items-end place-items-end">
<Icon className="text-white ml-1" fontSize={25} icon="tabler:dots" />
</a>
</PopoverTrigger>
<PopoverContent className="w-52">
<div onClick={() => handleSaveWishlist(image?.mediaUpload?.id)} className="cursor-pointer flex flex-row gap-2 hover:text-red-800">
<Icon icon="material-symbols:bookmark-outline" fontSize={25} />
<p className="text-base font-semibold mb-2">{t("save")}</p>
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
Kirim
</Button>
</div>
</PopoverContent>
</Popover>
<Link href={`/content-management/rewrite/create/${image?.mediaUpload?.id}`} className="flex flex-row hover:text-red-800 gap-2">
<Icon icon="jam:write" fontSize={25} />
<p className="text-base font-semibold mb-2">Content Rewrite</p>
</Link>
<div className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Popover>
<PopoverTrigger asChild>
<button className="w-full flex flex-row items-center gap-3">
<Icon icon="oi:share" fontSize={20} />
<p className="text-base font-semibold mb-1"> {t("share")}</p>
</button>
</PopoverTrigger>
<PopoverContent>
<div className="flex flex-col">
<h1 className="mb-2">{t("shareTo")}</h1>
<div className="flex flex-col mb-2">
<p className="text-base font-semibold mb-1">{t("destinationEmail")}</p>
<Input value={emailShareInput} onChange={(event) => setEmailShareInput(event.target.value)} onKeyPress={handleEmailList} type="email" placeholder={t("pressEnter")} />
</div>
<Button className="bg-blue-500 text-white p-2 w-fit rounded-lg" onClick={() => shareToEmail()}>
{t("send")}
</Button>
</div>
</PopoverContent>
</Popover>
</div>
</PopoverContent>
</Popover>
</p>
</div>
<a onClick={() => handleDelete(image?.id)} className="flex items-center gap-1 hover:text-red-800 w-full rounded-lg">
<Icon icon="fa:trash" fontSize={20} />
<p className="text-base font-semibold">Hapus</p>
</a>
</PopoverContent>
</Popover>
</div>
</div>
</div>
</CardContent>
</Card>

View File

@ -2,7 +2,7 @@
import HeaderManagement from "@/components/landing-page/header-management";
import SidebarManagement from "@/components/landing-page/sidebar-management";
import { close, error, loading } from "@/config/swal";
import { close, loading } from "@/config/swal";
import { getCookiesDecrypt } from "@/lib/utils";
import { getInfoProfile, getUsersTeams, saveUserReports } from "@/service/landing/landing";
import React, { useEffect, useState } from "react";
@ -10,9 +10,9 @@ import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, Di
import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import { Button } from "@/components/ui/button";
import toast from "react-hot-toast";
import { useToast } from "@/components/ui/use-toast";
import { ToastAction } from "@/components/ui/toast";
import Image from "next/image";
import { useTranslations } from "next-intl";
const page = () => {
const [user, setUser] = useState<any>();
@ -23,6 +23,7 @@ const page = () => {
const MySwal = withReactContent(Swal);
const { toast } = useToast();
const [reportMessageOpen, setReportMessageOpen] = useState(false);
const t = useTranslations("LandingPage");
// const launchModal = (user: any) => {
// setUserSelected(user);
@ -118,25 +119,22 @@ const page = () => {
<SidebarManagement />
<div className="w-2/3 p-12">
<div className="flex flex-col">
<p className="text-lg font-semibold">Tim {profile?.institute?.name}</p>
<p className="text-base mb-3">{user?.length} Anggota</p>
<p className="text-2xl w-fit font-bold bg-[#bb3523] px-4 py-1 rounded-lg text-center text-white my-4 ">
<span className="text-black">{t("team")} </span>
{profile?.institute?.name}
</p>
<p className="text-base mb-3">
{user?.length} {t("teamMembers")} {profile?.institute?.name}
</p>
</div>
<div className="flex flex-row gap-5">
{user?.map((row: any) => (
<div key={row?.id}>
<Dialog>
<DialogTrigger>
<div className="flex flex-col items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="5em" height="5em" viewBox="0 0 16 16">
<path fill="currentColor" d="M11 7c0 1.66-1.34 3-3 3S5 8.66 5 7s1.34-3 3-3s3 1.34 3 3" />
<path
fill="black"
fill-rule="evenodd"
d="M16 8c0 4.42-3.58 8-8 8s-8-3.58-8-8s3.58-8 8-8s8 3.58 8 8M4 13.75C4.16 13.484 5.71 11 7.99 11c2.27 0 3.83 2.49 3.99 2.75A6.98 6.98 0 0 0 14.99 8c0-3.87-3.13-7-7-7s-7 3.13-7 7c0 2.38 1.19 4.49 3.01 5.75"
clip-rule="evenodd"
/>
</svg>
<p className="font-semibold text-md">{row?.fullname}</p>
<div className="flex flex-col items-center border border-gray-500 p-2 bg-[#f8f8f8] rounded-md">
<Image src="/assets/gg-profile.png" alt="" width={1280} height={720} className="h-10 w-10 mb-4" />
<p className="font-bold text-base ">{row?.fullname}</p>
<p className="text-sm font-light">{row?.username || "username"}</p>
</div>
</DialogTrigger>
@ -166,7 +164,7 @@ const page = () => {
</div>
<div className="border-b border-black w-full"></div>
<div className="flex flex-col">
<h1 className="text-red-600 mb-2">Alasan Report Akun</h1>
<h1 className="text-red-600 mb-2">{t("reasonReport")}</h1>
<textarea id="formControlTextarea1" rows={4} className="border border-black font-light" onChange={(e: any) => setReportMessage(e.target.value)} />
</div>
</div>
@ -174,17 +172,17 @@ const page = () => {
<Dialog>
<DialogTrigger asChild>
<Button className="bg-red-500 text-white" type="submit">
Kirim
{t("send")}
</Button>
</DialogTrigger>
<DialogContent>
<h1>Simpan Data?</h1>
<h1>{t("saveData")}</h1>
<DialogFooter>
<DialogClose>
<Button onClick={save}>Simpan</Button>
<Button onClick={save}>{t("save")}</Button>
</DialogClose>
<DialogClose>
<Button>Cancel</Button>
<Button>{t("cancel")}</Button>
</DialogClose>
</DialogFooter>
</DialogContent>

View File

@ -14,7 +14,7 @@ import { sendMediaUploadToEmail } from "@/service/media-tracking/media-tracking"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { checkMaliciousText, getPublicLocaleTimestamp } from "@/utils/globals";
import { checkMaliciousText, formatDateToIndonesian, getPublicLocaleTimestamp } from "@/utils/globals";
import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import parse from "html-react-parser";
@ -435,12 +435,16 @@ const DetailDocument = () => {
<p className="text-xs lg:text-sm">
{t("by")}&nbsp;<span className="font-semibold text-black">{detailDataDocument?.uploadedBy?.userLevel?.name}</span>
</p>
<p className="text-xs lg:text-sm">
{/* <p className="text-xs lg:text-sm">
&nbsp;|&nbsp; {t("updatedOn")} {detailDataDocument?.updatedAt} WIB &nbsp;|&nbsp;
</p> */}
<p className="text-xs lg:text-sm">
&nbsp;|&nbsp;{t("updatedOn")}&nbsp;
{formatDateToIndonesian(new Date(detailDataDocument?.updatedAt))} {"WIB"}
</p>
<p className="text-xs lg:text-sm flex justify-center items-center">
<Icon icon="formkit:eye" width="15" height="15" />
&nbsp; {detailDataDocument?.clickCount} &nbsp;
&nbsp;| &nbsp;<Icon icon="formkit:eye" width="15" height="15" />
&nbsp;{detailDataDocument?.clickCount}&nbsp;
</p>
</div>
<div className="mt-3">
@ -453,7 +457,7 @@ const DetailDocument = () => {
{/* Keterangan */}
<div className="">
<h1 className="flex flex-row font-bold text-lg lg:text-2xl my-8 text-justify">{detailDataDocument?.title}</h1>
<h1 className="flex flex-row font-bold text-lg lg:text-2xl my-8 text-justify space-y-4">{detailDataDocument?.title}</h1>
<div dangerouslySetInnerHTML={{ __html: detailDataDocument?.htmlDescription }} />
</div>
</div>

View File

@ -1,6 +1,7 @@
"use client";
import { Reveal } from "@/components/landing-page/Reveal";
import React, { useState } from "react";
import { useTranslations } from "next-intl";
interface FAQItem {
question: string;
@ -8,22 +9,24 @@ interface FAQItem {
}
const FAQS: React.FC = () => {
const t = useTranslations("LandingPage");
const faqs: FAQItem[] = [
{
question: "APA SAJA KONTEN-KONTEN YANG ADA DI MEDIAHUB DAN KATEGORI DI DALAMNYA?",
answer: "MediaHub memiliki beragam konten seperti berita, video, dan dokumen yang dikategorikan dalam topik seperti edukasi, hiburan, dan informasi terkini.",
question: t("question1"),
answer: t("answer1"),
},
{
question: "BAGAIMANA KONTEN DARI MEDIAHUB DAPAT DIUNDUH?",
answer: "Anda dapat mengunduh konten dengan klik tombol unduh yang tersedia pada setiap konten di halaman MediaHub.",
question: t("question2"),
answer: t("answer2"),
},
{
question: "SIAPA SAJA YANG DAPAT MENDAFTARKAN DIRI SEBAGAI PENGGUNA MEDIAHUB?",
answer: "Semua orang yang memiliki minat terhadap konten di MediaHub dapat mendaftar sebagai pengguna, baik untuk personal maupun profesional.",
question: t("question3"),
answer: t("answer3"),
},
{
question: "APA ITU MEDIAHUB? DAN APA SAJA FITUR YANG ADA DI DALAMNYA?",
answer: "MediaHub adalah platform yang menyediakan berbagai konten informatif dan edukatif. Fitur utama meliputi pencarian, pengunduhan, dan personalisasi konten.",
question: t("question4"),
answer: t("answer4"),
},
];
@ -44,7 +47,7 @@ const FAQS: React.FC = () => {
{/* FAQS Items */}
<div className="space-y-4">
{faqs.map((faq, index) => (
{faqs?.map((faq, index) => (
<div key={index} className="border-b border-gray-300 pb-2 cursor-pointer">
<div className="flex justify-between items-center" onClick={() => toggleFAQ(index)}>
<h3 className="text-sm font-semibold text-gray-800">{faq.question}</h3>

View File

@ -4,7 +4,7 @@ import { Reveal } from "@/components/landing-page/Reveal";
import { error, loading, successCallback } from "@/config/swal";
import { getFeedback, postUserFeedback } from "@/service/landing/landing";
import React, { useEffect, useState } from "react";
import { any } from "zod";
import { useTranslations } from "next-intl";
interface RatingProps {
label: string;
@ -57,6 +57,7 @@ const FeedbackForm: React.FC = () => {
const [userFeedbacks, setUserFeedbacks] = useState<Feedback[]>([]);
const [hasMounted, setHasMounted] = useState(false);
const t = useTranslations("LandingPage");
const handleRatingChange = (id: any, score: any) => {
const listData = [...userFeedbacks];
@ -119,14 +120,14 @@ const FeedbackForm: React.FC = () => {
<div className="max-w-6xl flex flex-col mx-auto p-4 lg:p-40 gap-5">
<div className="flex items-center justify-center mb-6">
<img src="/assets/icons-feedback.png" alt="Feedback" />
<h2 className="ml-4 text-[15px] lg:text-[32px] font-bold text-gray-800">Feedback Pengguna</h2>
<h2 className="ml-4 text-[15px] lg:text-[32px] font-bold text-gray-800">{t("userFeedback")}</h2>
</div>
<Rating label="Silakan berikan rating Anda terkait dengan kemudahan akses website MediaHUB Polri" onRate={(rating) => handleRatingChange("accessibility", rating)} />
<Rating label="Silakan berikan rating Anda terkait dengan tampilan website MediaHUB Polri" onRate={(rating) => handleRatingChange("appearance", rating)} />
<Rating label="Silakan berikan rating Anda terkait dengan konten MediaHUB Polri" onRate={(rating) => handleRatingChange("content", rating)} />
<Rating label={t("ratings")} onRate={(rating) => handleRatingChange("accessibility", rating)} />
<Rating label={t("ratings2")} onRate={(rating) => handleRatingChange("appearance", rating)} />
<Rating label={t("ratings3")} onRate={(rating) => handleRatingChange("content", rating)} />
<div className="flex justify-center">
<button onClick={handleSubmit} className="w-fit lg:w-32 bg-[#2F80ED] text-white py-2 px-4 gap-4 rounded-md hover:bg-blue-600 transition text-sm lg:text-base">
Kirim
{t("send")}
</button>
</div>
</div>

View File

@ -14,7 +14,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { sendMediaUploadToEmail } from "@/service/media-tracking/media-tracking";
import { checkMaliciousText, getPublicLocaleTimestamp } from "@/utils/globals";
import { checkMaliciousText, formatDateToIndonesian, getPublicLocaleTimestamp } from "@/utils/globals";
import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import parse from "html-react-parser";
@ -473,11 +473,16 @@ const DetailInfo = () => {
<p className="text-xs lg:text-sm">
{t("by")}&nbsp;<span className="font-semibold text-black">{detailDataImage?.uploadedBy?.userLevel?.name}</span>
</p>
<p className="text-xs lg:text-sm">
{/* <p className="text-xs lg:text-sm">
&nbsp;|&nbsp;{t("updatedOn")}
{detailDataImage?.updatedAt} WIB &nbsp;|&nbsp;
</p> */}
<p className="text-xs lg:text-sm">
&nbsp;|&nbsp;{t("updatedOn")}&nbsp;
{formatDateToIndonesian(new Date(detailDataImage?.updatedAt))} {"WIB"}
</p>
<p className="text-xs lg:text-sm flex justify-center items-center">
&nbsp;|&nbsp;
<Icon icon="formkit:eye" width="15" height="15" />
&nbsp; {detailDataImage?.clickCount} &nbsp;
</p>
@ -493,7 +498,7 @@ const DetailInfo = () => {
{/* Keterangan */}
<div className="w-full">
<h1 className="flex flex-row font-bold text-lg lg:text-2xl my-8">{detailDataImage?.title}</h1>
<div className="font-light text-justify mb-5 lg:mb-0" dangerouslySetInnerHTML={{ __html: detailDataImage?.htmlDescription }} />
<div className="font-light text-justify mb-5 space-y-4 lg:mb-0" dangerouslySetInnerHTML={{ __html: detailDataImage?.htmlDescription }} />
</div>
</div>

View File

@ -7,12 +7,14 @@ import { Icon } from "@iconify/react/dist/iconify.js";
import { useSearchParams } from "next/navigation";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
import { useTranslations } from "next-intl";
const InboxSection = () => {
const router = useRouter();
const pathname = usePathname();
const isUpdate = pathname.includes("update");
const searchParams = useSearchParams();
const t = useTranslations("LandingPage");
const page: any = searchParams?.get("page");
@ -53,20 +55,20 @@ const InboxSection = () => {
<path d="M12 1C5.925 1 1 5.925 1 12s4.925 11 11 11s11-4.925 11-11S18.075 1 12 1M3 12c0 2.09.713 4.014 1.908 5.542A8.99 8.99 0 0 1 12.065 14a8.98 8.98 0 0 1 7.092 3.458A9 9 0 1 0 3 12m9 9a8.96 8.96 0 0 1-5.672-2.012A6.99 6.99 0 0 1 12.065 16a6.99 6.99 0 0 1 5.689 2.92A8.96 8.96 0 0 1 12 21" />
</g>
</svg>{" "}
<h2 className="ml-4 text-[15px] lg:text-[32px] font-semibold text-gray-800">Pesan Masuk</h2>
<h2 className="ml-4 text-[15px] lg:text-[32px] font-semibold text-gray-800">{t("inbox")}</h2>
</div>
<div className="flex flex-col justify-center items-center gap-3">
<div className="flex justify-center">
<div className="flex flex-row gap-10 items-center justify-center">
<div className="">
<p className="bg-[#bb3523] py-1 px-3 rounded-full">Pesan Masuk</p>
<p className="bg-[#bb3523] py-1 px-3 rounded-full">{t("inbox")}</p>
</div>
<Link href={`/inbox/update`}>Update</Link>
<Link href={`/inbox/update`}>{t("update")}</Link>
</div>
</div>
<div className="py-10 px-8 w-[400px] mt-3 border border-black rounded-lg flex flex-col">
<h1 className="mb-3 text-lg font-semibold">List Notifikasi</h1>
<h1 className="mb-3 text-lg font-semibold">{t("notifList")}</h1>
<div className="hover:bg-slate-200 rounded-md">
{notifications?.map((list: any) => (
<a className="flex flex-row items-center ml-1" href={"/" + list.redirectUrl}>

View File

@ -5,8 +5,8 @@ import { getUserNotifications } from "@/service/landing/landing";
import { getTimestamp } from "@/utils/globals";
import { Icon } from "@iconify/react/dist/iconify.js";
import { useSearchParams } from "next/navigation";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
import { useTranslations } from "next-intl";
const UpdateSection = () => {
const pathname = usePathname();
@ -14,7 +14,7 @@ const UpdateSection = () => {
const searchParams = useSearchParams();
const page: any = searchParams?.get("page");
const pages = page ? page - 1 : 0;
const t = useTranslations("LandingPage");
const [notifications, setNotifications] = useState([]);
const [getTotalData, setGetTotalData] = useState();
const [, setGetTotalPage] = useState();
@ -50,20 +50,20 @@ const UpdateSection = () => {
<path d="M12 1C5.925 1 1 5.925 1 12s4.925 11 11 11s11-4.925 11-11S18.075 1 12 1M3 12c0 2.09.713 4.014 1.908 5.542A8.99 8.99 0 0 1 12.065 14a8.98 8.98 0 0 1 7.092 3.458A9 9 0 1 0 3 12m9 9a8.96 8.96 0 0 1-5.672-2.012A6.99 6.99 0 0 1 12.065 16a6.99 6.99 0 0 1 5.689 2.92A8.96 8.96 0 0 1 12 21" />
</g>
</svg>{" "}
<h2 className="ml-4 text-[15px] lg:text-[32px] font-semibold text-gray-800">Update</h2>
<h2 className="ml-4 text-[15px] lg:text-[32px] font-semibold text-gray-800">{t("update")}</h2>
</div>
<div className="flex flex-col items-center gap-3">
<div className="flex justify-center">
<div className="flex flex-row gap-10 items-center justify-center">
<div>
<Link href={`/inbox`}>Pesan Masuk</Link>
<Link href={`/inbox`}>{t("inbox")}</Link>
</div>
<div className="bg-[#bb3523] py-1 px-3 rounded-full">Update</div>
<div className="bg-[#bb3523] py-1 px-3 rounded-full">{t("update")}</div>
</div>
</div>
<div className="py-10 px-8 w-[400px] mt-3 border border-black rounded-lg flex flex-col">
<h1 className="mb-3 text-lg font-semibold">List Notifikasi</h1>
<h1 className="mb-3 text-lg font-semibold">{t("notifList")}</h1>
<div className="hover:bg-slate-200 rounded-md">
{notifications?.map((list: any) => (
<a className="flex flex-row items-center ml-1" href={"/" + list.redirectUrl}>

View File

@ -16,6 +16,7 @@ import withReactContent from "sweetalert2-react-content";
import { Textarea } from "@/components/ui/textarea";
import { Button } from "@/components/ui/button";
import { Link } from "@/components/navigation";
import { useTranslations } from "next-intl";
const profileSchema = z.object({
password: z.string().min(1, { message: "Judul diperlukan" }),
@ -33,6 +34,7 @@ const ChangePassword: React.FC = () => {
const MySwal = withReactContent(Swal);
const [detail, setDetail] = useState<Detail>();
const [refresh, setRefresh] = useState(false);
const t = useTranslations("LandingPage");
type ProfileSchema = z.infer<typeof profileSchema>;
const {
@ -100,86 +102,45 @@ const ChangePassword: React.FC = () => {
<div className="w-20 h-20 mx-auto rounded-full bg-red-700 flex items-center justify-center">
<span className="text-white text-3xl font-bold">👤</span>
</div>
<h1 className="text-2xl font-bold mt-4">Ubah Profile</h1>
<h1 className="text-2xl font-bold mt-4">{t("changePass")}</h1>
</div>
<div className="flex justify-center gap-4 mb-8">
<Link href={"/profile"}>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">
User Profile
</button>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">{t("userProfile")}</button>
</Link>
<Link href={"/profile/change-profile"}>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">
Ubah Foto
</button>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">{t("changePhoto")}</button>
</Link>
<Link href={"/profile/change-password"}>
<button className="bg-red-700 text-white px-4 py-2 rounded">
Ubah Password
</button>
<button className="bg-red-700 text-white px-4 py-2 rounded">{t("changePass")}</button>
</Link>
</div>
<div className="max-w-3xl mx-auto bg-white shadow-sm p-4 rounded">
<p className="mb-6 text-gray-600">
Silahkan ubah data pribadi Anda pada form berikut.
</p>
<p className="mb-6 text-gray-600">{t("pleaseChange")}</p>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<div className="mb-4">
<Label>
Password<span className="text-red-500">*</span>
{t("password")}
<span className="text-red-500">*</span>
</Label>
<Controller
control={control}
name="password"
render={({ field }) => (
<Input
size="md"
type="password"
defaultValue={field.value}
onChange={field.onChange}
placeholder="Enter Title"
/>
)}
/>
{errors.password?.message && (
<p className="text-red-400 text-sm">
{errors.password.message}
</p>
)}
<Controller control={control} name="password" render={({ field }) => <Input size="md" type="password" defaultValue={field.value} onChange={field.onChange} placeholder={t("inputPass")} />} />
{errors.password?.message && <p className="text-red-400 text-sm">{errors.password.message}</p>}
</div>
<div className="mb-4">
<Label>
Konfirmasi Password<span className="text-red-500">*</span>
{t("confirmPass")}
<span className="text-red-500">*</span>
</Label>
<Controller
control={control}
name="retypePassword"
render={({ field }) => (
<Input
size="md"
type="password"
defaultValue={field.value}
onChange={field.onChange}
placeholder="Enter Title"
/>
)}
/>
{errors.retypePassword?.message && (
<p className="text-red-400 text-sm">
{errors.retypePassword.message}
</p>
)}
<Controller control={control} name="retypePassword" render={({ field }) => <Input size="md" type="password" defaultValue={field.value} onChange={field.onChange} placeholder={t("samePass")} />} />
{errors.retypePassword?.message && <p className="text-red-400 text-sm">{errors.retypePassword.message}</p>}
</div>
<div className="text-right">
<div className="mt-4">
<button
type="submit"
className="bg-red-700 text-white px-6 py-2 rounded hover:bg-red-800 focus:outline-none focus:ring focus:ring-red-300"
>
Simpan
<button type="submit" className="bg-red-700 text-white px-6 py-2 rounded hover:bg-red-800 focus:outline-none focus:ring focus:ring-red-300">
{t("save")}
</button>
</div>
</div>

View File

@ -2,9 +2,11 @@
import { Link } from "@/components/navigation";
import Image from "next/image";
import React, { useState } from "react";
import { useTranslations } from "next-intl";
const ChangeProfile: React.FC = () => {
const [selectedImage, setSelectedImage] = useState<File | null>(null);
const t = useTranslations("LandingPage");
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files[0]) {
@ -32,35 +34,35 @@ const ChangeProfile: React.FC = () => {
<div className="w-20 h-20 mx-auto rounded-full bg-red-700 flex items-center justify-center">
<span className="text-white text-3xl font-bold">👤</span>
</div>
<h1 className="text-2xl font-bold mt-4">Ubah Photo</h1>
<h1 className="text-2xl font-bold mt-4">{t("changePhoto")}</h1>
</div>
<div className="flex justify-center gap-4 mb-8">
<Link href={"/profile"}>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">User Profile</button>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">{t("userProfile")}</button>
</Link>
<Link href={"/profile/change-profile"}>
<button className="bg-red-700 text-white px-4 py-2 rounded">Ubah Foto</button>
<button className="bg-red-700 text-white px-4 py-2 rounded">{t("changePhoto")}</button>
</Link>
<Link href={"/profile/change-password"}>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">Ubah Password</button>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">{t("changePass")}</button>
</Link>
</div>
<div className="w-80 mx-auto bg-gray-900 text-white shadow-md p-8 rounded">
<div className="flex justify-center mb-6">
<div className="w-40 h-40 rounded-full border border-gray-300 flex items-center justify-center">
{selectedImage ? <Image width={1920} height={1080} src={URL.createObjectURL(selectedImage)} alt="Preview" className="w-full h-full rounded-full object-cover" /> : <span className="text-gray-500">No Image</span>}
{selectedImage ? <Image width={1920} height={1080} src={URL.createObjectURL(selectedImage)} alt="Preview" className="w-full h-full rounded-full object-cover" /> : <span className="text-gray-500">{t("noImage")}</span>}
</div>
</div>
<div className="flex justify-center gap-4">
<input type="file" id="upload" accept="image/*" className="hidden" onChange={handleImageChange} />
<label htmlFor="upload" className="bg-blue-600 text-white px-4 py-2 rounded cursor-pointer">
Ganti Foto
{t("changePhoto")}
</label>
<button onClick={handleDelete} className="border border-red-700 text-red-700 px-4 py-2 rounded">
Hapus Foto
{t("deletePhoto")}{" "}
</button>
</div>
</div>

View File

@ -16,15 +16,14 @@ import withReactContent from "sweetalert2-react-content";
import { Textarea } from "@/components/ui/textarea";
import { Button } from "@/components/ui/button";
import { Link } from "@/components/navigation";
import { useTranslations } from "next-intl";
const profileSchema = z.object({
username: z.string().min(1, { message: "Judul diperlukan" }),
fullname: z.string().min(1, { message: "Judul diperlukan" }),
memberIdentity: z.string().min(1, { message: "Judul diperlukan" }),
email: z.string().min(1, { message: "Judul diperlukan" }),
address: z
.string()
.min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }),
address: z.string().min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }),
phoneNumber: z.string().min(1, { message: "Kategori diperlukan" }),
});
@ -45,6 +44,7 @@ const UbahProfile: React.FC = () => {
const MySwal = withReactContent(Swal);
const [detail, setDetail] = useState<Detail>();
const [refresh, setRefresh] = useState(false);
const t = useTranslations("LandingPage");
type ProfileSchema = z.infer<typeof profileSchema>;
const {
@ -117,30 +117,22 @@ const UbahProfile: React.FC = () => {
<div className="w-20 h-20 mx-auto rounded-full bg-red-700 flex items-center justify-center">
<span className="text-white text-3xl font-bold">👤</span>
</div>
<h1 className="text-2xl font-bold mt-4">Ubah Profile</h1>
<h1 className="text-2xl font-bold mt-4">{t("changeProfile")}</h1>
</div>
<div className="flex justify-center gap-4 mb-8">
<Link href={"/profile"}>
<button className="bg-red-700 text-white px-4 py-2 rounded">
User Profile
</button>
<button className="bg-red-700 text-white px-4 py-2 rounded">{t("userProfile")}</button>
</Link>
<Link href={"/profile/change-profile"}>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">
Ubah Foto
</button>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">{t("changePhoto")}</button>
</Link>
<Link href={"/profile/change-password"}>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">
Ubah Password
</button>
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">{t("changePass")}</button>
</Link>
</div>
<div className="max-w-3xl mx-auto bg-white shadow-sm p-4 rounded">
<p className="mb-6 text-gray-600">
Silahkan ubah data pribadi Anda pada form berikut.
</p>
<p className="mb-6 text-gray-600">{t("pleaseChange")}</p>
<form onSubmit={handleSubmit(onSubmit)}>
{detail !== undefined ? (
<div>
@ -148,143 +140,52 @@ const UbahProfile: React.FC = () => {
<Label>
Username<span className="text-red-500">*</span>
</Label>
<Controller
control={control}
name="username"
render={({ field }) => (
<Input
size="md"
type="text"
defaultValue={detail?.username}
onChange={field.onChange}
placeholder="Enter Title"
/>
)}
/>
{errors.username?.message && (
<p className="text-red-400 text-sm">
{errors.username.message}
</p>
)}
<Controller control={control} name="username" render={({ field }) => <Input size="md" type="text" defaultValue={detail?.username} onChange={field.onChange} placeholder="Enter Title" />} />
{errors.username?.message && <p className="text-red-400 text-sm">{errors.username.message}</p>}
</div>
<div className="mb-4">
<Label>
Nama Lengkap<span className="text-red-500">*</span>
{t("fullName")}
<span className="text-red-500">*</span>
</Label>
<Controller
control={control}
name="fullname"
render={({ field }) => (
<Input
size="md"
type="text"
defaultValue={detail?.fullname}
onChange={field.onChange}
placeholder="Enter Title"
/>
)}
/>
{errors.fullname?.message && (
<p className="text-red-400 text-sm">
{errors.fullname.message}
</p>
)}
<Controller control={control} name="fullname" render={({ field }) => <Input size="md" type="text" defaultValue={detail?.fullname} onChange={field.onChange} placeholder="Enter Title" />} />
{errors.fullname?.message && <p className="text-red-400 text-sm">{errors.fullname.message}</p>}
</div>
<div className="mb-4">
<Label>
Nomor Identitas<span className="text-red-500">*</span>
{t("identityNumber")}
<span className="text-red-500">*</span>
</Label>
<Controller
control={control}
name="memberIdentity"
render={({ field }) => (
<Input
size="md"
type="text"
defaultValue={detail?.memberIdentity}
onChange={field.onChange}
placeholder="Enter Title"
/>
)}
/>
{errors.memberIdentity?.message && (
<p className="text-red-400 text-sm">
{errors.memberIdentity.message}
</p>
)}
<Controller control={control} name="memberIdentity" render={({ field }) => <Input size="md" type="text" defaultValue={detail?.memberIdentity} onChange={field.onChange} placeholder="Enter Title" />} />
{errors.memberIdentity?.message && <p className="text-red-400 text-sm">{errors.memberIdentity.message}</p>}
</div>
<div className="mb-4">
<Label>
Email<span className="text-red-500">*</span>
</Label>
<Controller
control={control}
name="email"
render={({ field }) => (
<Input
size="md"
type="text"
defaultValue={detail?.email}
onChange={field.onChange}
placeholder="Enter Title"
/>
)}
/>
{errors.email?.message && (
<p className="text-red-400 text-sm">{errors.email.message}</p>
)}
<Controller control={control} name="email" render={({ field }) => <Input size="md" type="text" defaultValue={detail?.email} onChange={field.onChange} placeholder="Enter Title" />} />
{errors.email?.message && <p className="text-red-400 text-sm">{errors.email.message}</p>}
</div>
<div className="mb-4">
<Label>
Nomor HP<span className="text-red-500">*</span>
{t("number")}
<span className="text-red-500">*</span>
</Label>
<Controller
control={control}
name="phoneNumber"
render={({ field }) => (
<Input
size="md"
type="number"
defaultValue={detail?.phoneNumber}
onChange={field.onChange}
placeholder="Enter Title"
/>
)}
/>
{errors.phoneNumber?.message && (
<p className="text-red-400 text-sm">
{errors.phoneNumber.message}
</p>
)}
<Controller control={control} name="phoneNumber" render={({ field }) => <Input size="md" type="number" defaultValue={detail?.phoneNumber} onChange={field.onChange} placeholder="Enter Title" />} />
{errors.phoneNumber?.message && <p className="text-red-400 text-sm">{errors.phoneNumber.message}</p>}
</div>
<div className="mb-4">
<Label>
Alamat<span className="text-red-500">*</span>
{t("address")}
<span className="text-red-500">*</span>
</Label>
<Controller
control={control}
name="address"
render={({ field }) => (
<Textarea
defaultValue={detail?.address}
onChange={field.onChange}
placeholder="Enter Title"
/>
)}
/>
{errors.address?.message && (
<p className="text-red-400 text-sm">
{errors.address.message}
</p>
)}
<Controller control={control} name="address" render={({ field }) => <Textarea defaultValue={detail?.address} onChange={field.onChange} placeholder="Enter Title" />} />
{errors.address?.message && <p className="text-red-400 text-sm">{errors.address.message}</p>}
</div>
<div className="text-right">
<div className="mt-4">
<button
type="submit"
className="bg-red-700 text-white px-6 py-2 rounded hover:bg-red-800 focus:outline-none focus:ring focus:ring-red-300"
>
Simpan
<button type="submit" className="bg-red-700 text-white px-6 py-2 rounded hover:bg-red-800 focus:outline-none focus:ring focus:ring-red-300">
{t("save")}
</button>
</div>
</div>

View File

@ -15,7 +15,7 @@ import { sendMediaUploadToEmail } from "@/service/media-tracking/media-tracking"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { checkMaliciousText, getPublicLocaleTimestamp } from "@/utils/globals";
import { checkMaliciousText, formatDateToIndonesian, getPublicLocaleTimestamp } from "@/utils/globals";
import withReactContent from "sweetalert2-react-content";
import Swal from "sweetalert2";
import parse from "html-react-parser";
@ -440,13 +440,18 @@ const DetailVideo = () => {
<p className="text-xs lg:text-sm">
{t("by")}&nbsp;<span className="font-semibold text-black">{detailDataVideo?.uploadedBy?.userLevel?.name}</span>
</p>
<p className="text-xs lg:text-sm">
{/* <p className="text-xs lg:text-sm">
&nbsp;|&nbsp;{t("updatedOn")}
{detailDataVideo?.updatedAt} WIB &nbsp;|&nbsp;
</p> */}
<p className="text-xs lg:text-sm">
&nbsp;|&nbsp;{t("updatedOn")}&nbsp;
{formatDateToIndonesian(new Date(detailDataVideo?.updatedAt))} {"WIB"}
</p>
<p className="text-xs lg:text-sm flex justify-center items-center">
&nbsp;|&nbsp;
<Icon icon="formkit:eye" width="15" height="15" />
&nbsp; {detailDataVideo?.clickCount} &nbsp;
&nbsp;{detailDataVideo?.clickCount} &nbsp;
</p>
</div>
<div className="mt-3">
@ -461,7 +466,7 @@ const DetailVideo = () => {
<div className="w-full">
<h1 className="flex flex-row font-bold text-lg lg:text-2xl my-8">{detailDataVideo?.title}</h1>
<div
className="font-light text-justify mb-5 lg:mb-0"
className="font-light text-justify mb-5 space-y-4 lg:mb-0"
dangerouslySetInnerHTML={{
__html: detailDataVideo?.htmlDescription,
}}

View File

@ -34,7 +34,7 @@ const ContentCategory = (props: { group?: string }) => {
const pathname = usePathname();
return (
<div className="mx-auto px-4 lg:px-20 py-10 max-w-screen-2xl ">
<div className="mx-auto px-4 lg:px-24 py-10 max-w-screen-2xl ">
<Reveal>
<h2 className="text-center text-xl lg:text-2xl font-bold text-[#bb3523] mb-4">
{pathname?.split("/")[1] == "in" ? (

View File

@ -60,7 +60,7 @@ const Footer = () => {
<img src="/assets/icon-privacy.png" alt="Privacy" />
<p className="font-semibold text-lg">{t("privacy")}</p>
</div>
<div className="container text-dark">{parse(String(privacy))}</div>
<div className="container text-black space-y-2">{parse(String(privacy))}</div>
</DialogContent>
</Dialog>
</div>

View File

@ -4,9 +4,10 @@ import { useParams, usePathname, useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
import Skeleton, { SkeletonTheme } from "react-loading-skeleton";
import { Link } from "@/i18n/routing";
import { getPublicLocaleTimestamp } from "@/utils/globals";
import { formatDateToIndonesian, getPublicLocaleTimestamp, textEllipsis } from "@/utils/globals";
import { Icon } from "@iconify/react/dist/iconify.js";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
import Image from "next/image";
const HeaderBannerSatker = () => {
const router = useRouter();
@ -26,7 +27,7 @@ const HeaderBannerSatker = () => {
// }
async function fetchData() {
const res = await listData("1", "", "", 5, 0, "createdAt", "", "", "satker-"+satkerName);
const res = await listData("1", "", "", 5, 0, "createdAt", "", "", "satker-" + satkerName);
let data = res?.data?.data?.content;
setContent(data);
setCenterPadding(`${Math.trunc(Number(window.innerWidth) / 10 + 40)}px`);
@ -70,49 +71,130 @@ const HeaderBannerSatker = () => {
};
return (
<div>
{/* Header */}
<div className="p-6 lg:px-16 flex flex-col lg:flex-row">
{/* Header Left */}
<div className="flex flex-col lg:flex-row items-start justify-center gap-8 px-4 lg:px-20 py-4 mx-auto w-auto mt-6">
{isBannerLoading ? (
<SkeletonTheme highlightColor="#f2f2f2">
<Skeleton className="w-[100%] h-[480px]" />
</SkeletonTheme>
) : (
<div className="mt-3">
<Carousel className="w-full h-full">
<CarouselContent>
{content?.map((row: any) => (
<CarouselItem key={row?.id} className="basis-1/2">
<div className="relative h-[310px] lg:h-[420px]">
<img src={row?.thumbnailLink} alt="" className="w-full h-[310px] lg:h-[420px] rounded-lg" />
<div className="absolute bottom-0 left-0 right-0 bg-transparent backdrop-blur-sm text-white p-4 rounded-b-lg">
<span className="text-white bg-[#bb3523] rounded-md w-full h-full font-semibold uppercase text-sm px-4 py-1">{row?.categoryName}</span>
<Link
href={
Number(row.fileType?.id) == 1
? `${asPath.includes("/satker/") == true ? asPath : ""}/image/detail/${row.slug}`
: Number(row.fileType?.id) == 2
? `/video/detail/${row.slug}`
: Number(row.fileType?.id) == 3
? `/document/detail/${row.slug}`
: `/audio/detail/${row.slug}`
}
>
<h3>{row.title}</h3>
</Link>
<p className="text-xs flex flex-row items-center gap-1 mt-1 text-white">
{getPublicLocaleTimestamp(new Date(row?.createdAt))} WIB {" | "}
<Icon icon="formkit:eye" width="15" height="15" /> {row?.clickCount}
</p>
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
<div className="flex flex-col space-y-3 mx-auto w-full lg:w-2/3">
<Skeleton className="h-[310px] lg:h-[420px] rounded-xl" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
) : (
<Carousel className="lg:w-2/3 lg:h-full ">
<CarouselContent>
{content?.map((row: any) => (
<CarouselItem key={row?.id}>
<div className="relative h-[310px] lg:h-[420px]">
<Image src={row?.thumbnailLink} alt="" width={1920} height={1080} className="w-full h-[310px] lg:h-[420px] rounded-lg object-cover" />
<div className="absolute bottom-0 left-0 right-0 bg-transparent backdrop-blur-sm text-white p-4 rounded-b-lg">
<span className="text-white bg-[#bb3523] rounded-md w-full h-full font-semibold uppercase text-sm px-4 py-1">{row?.categoryName}</span>
<Link
href={
Number(row.fileType?.id) == 1
? `${asPath.includes("/satker/") == true ? asPath : ""}/image/detail/${row.slug}`
: Number(row.fileType?.id) == 2
? `/video/detail/${row.slug}`
: Number(row.fileType?.id) == 3
? `/document/detail/${row.slug}`
: `/audio/detail/${row.slug}`
}
>
<h3>{row.title}</h3>
</Link>
<p className="text-xs flex flex-row items-center gap-1 mt-1 text-white">
{getPublicLocaleTimestamp(new Date(row?.createdAt))} WIB {" | "}
<Icon icon="formkit:eye" width="15" height="15" /> {row?.clickCount}
</p>
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
)}
{/* Section Kanan */}
<div>
{isBannerLoading ? (
<>
<div className="flex items-center gap-4 max-w-sm mx-auto mb-3">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
<div className="items-center hidden md:block gap-4 max-w-sm mx-auto mb-3 lg:flex">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
<div className="hidden md:block items-center gap-4 max-w-sm mx-auto mb-3 lg:flex">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
<div className="hidden md:block items-center gap-4 max-w-sm mx-auto mb-3 lg:flex">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
<div className="hidden md:block items-center gap-4 max-w-sm mx-auto lg:flex">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
</>
) : (
<ul className="py-4 lg:py-0 flex flex-row lg:flex-col gap-4 flex-nowrap w-[95vw] lg:w-auto overflow-x-auto">
{content?.map((item: any) => (
<li key={item?.id} className="flex gap-4 flex-row lg:w-full ">
<div className="flex-shrink-0 w-24 rounded-lg">
<Image width={720} height={480} src={item?.thumbnailLink} alt={item?.title} className="w-full h-[73px] object-cover rounded-lg" />
</div>
<div className="w-[280px] lg:w-auto">
<span className="text-white bg-[#bb3523] px-4 py-1 rounded-lg flex text-[8px] font-bold uppercase w-fit">{item?.categoryName}</span>
<Link
href={
Number(item?.fileType?.id) == 1
? `${asPath.includes("/satker/") == true ? asPath : ""}/image/detail/${item?.slug}`
: Number(item?.fileType?.id) == 2
? `/video/detail/${item?.slug}`
: Number(item?.fileType?.id) == 3
? `/document/detail/${item?.slug}`
: `/audio/detail/${item?.slug}`
}
>
<h3 className="text-base font-bold mt-2">{textEllipsis(item?.title, 30)}</h3>
</Link>
<p className="text-[10px] flex flex-row items-center gap-1 text-gray-500 mt-1">
{formatDateToIndonesian(new Date(item?.createdAt))} {item?.timezone ? item?.timezone : "WIB"} |{" "}
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M11.5 18c4 0 7.46-2.22 9.24-5.5C18.96 9.22 15.5 7 11.5 7s-7.46 2.22-9.24 5.5C4.04 15.78 7.5 18 11.5 18m0-12c4.56 0 8.5 2.65 10.36 6.5C20 16.35 16.06 19 11.5 19S3 16.35 1.14 12.5C3 8.65 6.94 6 11.5 6m0 2C14 8 16 10 16 12.5S14 17 11.5 17S7 15 7 12.5S9 8 11.5 8m0 1A3.5 3.5 0 0 0 8 12.5a3.5 3.5 0 0 0 3.5 3.5a3.5 3.5 0 0 0 3.5-3.5A3.5 3.5 0 0 0 11.5 9"
/>
</svg>{" "}
{item?.clickCount}
</p>
</div>
</li>
))}
</ul>
)}
</div>
</div>
</div>
);

View File

@ -4,9 +4,10 @@ import { useParams, usePathname, useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
import Skeleton, { SkeletonTheme } from "react-loading-skeleton";
import { Link } from "@/i18n/routing";
import { getPublicLocaleTimestamp } from "@/utils/globals";
import { formatDateToIndonesian, getPublicLocaleTimestamp, textEllipsis } from "@/utils/globals";
import { Icon } from "@iconify/react/dist/iconify.js";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
import Image from "next/image";
const HeaderBanner = () => {
const router = useRouter();
@ -14,7 +15,6 @@ const HeaderBanner = () => {
const poldaName: any = params?.polda_name;
const asPath: any = usePathname();
const [content, setContent] = useState([]);
const [isBannerLoading, setIsBannerLoading] = useState(true);
const [centerPadding, setCenterPadding] = useState<any>();
@ -70,49 +70,130 @@ const HeaderBanner = () => {
};
return (
<div>
{/* Header */}
<div className="p-6 lg:px-16 flex flex-col lg:flex-row">
{/* Header Left */}
<div className="flex flex-col lg:flex-row items-start justify-center gap-8 px-4 lg:px-20 py-4 mx-auto w-auto mt-6">
{isBannerLoading ? (
<SkeletonTheme highlightColor="#f2f2f2">
<Skeleton className="w-[100%] h-[480px]" />
</SkeletonTheme>
) : (
<div className="mt-3">
<Carousel className="w-full h-full">
<CarouselContent>
{content?.map((row: any) => (
<CarouselItem key={row?.id} className="basis-1/2">
<div className="relative h-[310px] lg:h-[420px]">
<img src={row?.thumbnailLink} alt="" className="w-full h-[310px] lg:h-[420px] rounded-lg" />
<div className="absolute bottom-0 left-0 right-0 bg-transparent backdrop-blur-sm text-white p-4 rounded-b-lg">
<span className="text-white bg-[#bb3523] rounded-md w-full h-full font-semibold uppercase text-sm px-4 py-1">{row?.categoryName}</span>
<Link
href={
Number(row.fileType?.id) == 1
? `${asPath.includes("/polda/") == true ? asPath : ""}/image/detail/${row.slug}`
: Number(row.fileType?.id) == 2
? `/video/detail/${row.slug}`
: Number(row.fileType?.id) == 3
? `/document/detail/${row.slug}`
: `/audio/detail/${row.slug}`
}
>
<h3>{row.title}</h3>
</Link>
<p className="text-xs flex flex-row items-center gap-1 mt-1 text-white">
{getPublicLocaleTimestamp(new Date(row?.createdAt))} WIB {" | "}
<Icon icon="formkit:eye" width="15" height="15" /> {row?.clickCount}
</p>
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
<div className="flex flex-col space-y-3 mx-auto w-full lg:w-2/3">
<Skeleton className="h-[310px] lg:h-[420px] rounded-xl" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
) : (
<Carousel className="lg:w-2/3 lg:h-full ">
<CarouselContent>
{content?.map((row: any) => (
<CarouselItem key={row?.id}>
<div className="relative h-[310px] lg:h-[420px]">
<Image src={row?.thumbnailLink} alt="" width={1920} height={1080} className="w-full h-[310px] lg:h-full rounded-lg object-cover" />
<div className="absolute bottom-0 left-0 right-0 bg-transparent backdrop-blur-sm text-white p-4 rounded-b-lg">
<span className="text-white bg-[#bb3523] rounded-md w-full h-full font-semibold uppercase text-sm px-4 py-1">{row?.categoryName}</span>
<Link
href={
Number(row.fileType?.id) == 1
? `${asPath.includes("/polda/") == true ? asPath : ""}/image/detail/${row.slug}`
: Number(row.fileType?.id) == 2
? `/video/detail/${row.slug}`
: Number(row.fileType?.id) == 3
? `/document/detail/${row.slug}`
: `/audio/detail/${row.slug}`
}
>
<h3>{row.title}</h3>
</Link>
<p className="text-xs flex flex-row items-center gap-1 mt-1 text-white">
{getPublicLocaleTimestamp(new Date(row?.createdAt))} WIB {" | "}
<Icon icon="formkit:eye" width="15" height="15" /> {row?.clickCount}
</p>
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
)}
{/* Header Right */}
<div>
{isBannerLoading ? (
<>
<div className="flex items-center gap-4 max-w-sm mx-auto mb-3">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
<div className="items-center hidden md:block gap-4 max-w-sm mx-auto mb-3 lg:flex">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
<div className="hidden md:block items-center gap-4 max-w-sm mx-auto mb-3 lg:flex">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
<div className="hidden md:block items-center gap-4 max-w-sm mx-auto mb-3 lg:flex">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
<div className="hidden md:block items-center gap-4 max-w-sm mx-auto lg:flex">
<Skeleton className="h-[73px] w-16 rounded-md" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
</>
) : (
<ul className="py-4 lg:py-0 flex flex-row lg:flex-col gap-4 flex-nowrap w-[95vw] lg:w-auto overflow-x-auto">
{content?.map((item: any) => (
<li key={item?.id} className="flex gap-4 flex-row lg:w-full ">
<div className="flex-shrink-0 w-24 rounded-lg">
<Image width={720} height={480} src={item?.thumbnailLink} alt={item?.title} className="w-full h-[73px] object-cover rounded-lg" />
</div>
<div className="w-[280px] lg:w-auto">
<span className="text-white bg-[#bb3523] px-4 py-1 rounded-lg flex text-[8px] font-bold uppercase w-fit">{item?.categoryName}</span>
<Link
href={
Number(item?.fileType?.id) == 1
? `${asPath.includes("/polda/") == true ? asPath : ""}/image/detail/${item?.slug}`
: Number(item?.fileType?.id) == 2
? `/video/detail/${item?.slug}`
: Number(item?.fileType?.id) == 3
? `/document/detail/${item?.slug}`
: `/audio/detail/${item?.slug}`
}
>
<h3 className="text-base font-bold mt-2">{textEllipsis(item?.title, 30)}</h3>
</Link>
<p className="text-[10px] flex flex-row items-center gap-1 text-gray-500 mt-1">
{formatDateToIndonesian(new Date(item?.createdAt))} {item?.timezone ? item?.timezone : "WIB"} |{" "}
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M11.5 18c4 0 7.46-2.22 9.24-5.5C18.96 9.22 15.5 7 11.5 7s-7.46 2.22-9.24 5.5C4.04 15.78 7.5 18 11.5 18m0-12c4.56 0 8.5 2.65 10.36 6.5C20 16.35 16.06 19 11.5 19S3 16.35 1.14 12.5C3 8.65 6.94 6 11.5 6m0 2C14 8 16 10 16 12.5S14 17 11.5 17S7 15 7 12.5S9 8 11.5 8m0 1A3.5 3.5 0 0 0 8 12.5a3.5 3.5 0 0 0 3.5 3.5a3.5 3.5 0 0 0 3.5-3.5A3.5 3.5 0 0 0 11.5 9"
/>
</svg>{" "}
{item?.clickCount}
</p>
</div>
</li>
))}
</ul>
)}
</div>
</div>
</div>
);

View File

@ -5,6 +5,7 @@ import { Link } from "@/i18n/routing";
import { Icon } from "@iconify/react/dist/iconify.js";
import { getInfoProfile, getListPorvinces, getUsersTeams } from "@/service/landing/landing";
import { useParams } from "next/navigation";
import { useTranslations } from "next-intl";
const HeaderManagement = () => {
const [profile, setProfile] = useState<any>();
@ -12,6 +13,7 @@ const HeaderManagement = () => {
const [, setUser] = useState();
const [selectedTab, setSelectedTab] = useState("video");
const params = useParams();
const t = useTranslations("LandingPage");
// const currentRoute = router.pathname;
// const profilePicture = Cookies.get("profile_picture");
@ -67,24 +69,24 @@ const HeaderManagement = () => {
return (
<div>
{/* Header */}
<div className="bg-[#504e52] p-10 lg:p-12">
<div className="bg-[#cccccc] p-5 lg:p-8">
<div className="flex flex-col lg:flex-row justify-center lg:justify-between mx-6 lg:mx-10">
<div className="flex items-center gap-2 ">
<img src="/assets/avatar-profile.png" alt="avatar" className="w-14 h-14" />
<img src="/assets/gg-profile.png" alt="avatar" className="w-14 h-14" />
<div className="flex flex-col mx-2">
<p className="text-white text-sm font-semibold">{profile?.fullname}</p>
<p className="text-white text-sm font-light">{profile?.username}</p>
<p className="text-white text-sm font-light">
Aktif Sejak&nbsp;
<p className="text-black text-sm font-semibold">{profile?.fullname}</p>
<p className="text-black text-sm font-light">{profile?.username}</p>
<p className="text-black text-sm font-light">
{t("activeSince")}&nbsp;
{`${new Date(profile?.createdAt).getDate()}/${new Date(profile?.createdAt).getMonth() + 1}/${new Date(profile?.createdAt).getFullYear()} ${new Date(profile?.createdAt).getHours()}:${new Date(
profile?.createdAt
).getMinutes()}`}
</p>
</div>
</div>
<Link href="/profile" className="flex justify-center items-center text-white gap-2 mt-3 lg:mt-0">
<Icon icon="tdesign:setting-1-filled" />
<p className="text-sm lg:text-base">Pengaturan</p>
<Link href="/profile" className="flex justify-center items-center text-black gap-2 mt-3 lg:mt-0">
<p className="text-sm lg:text-base">{t("fullProfile")}</p>
<Icon icon="ri:arrow-right-s-line" className="h-5 w-5" />
</Link>
</div>
</div>

View File

@ -486,12 +486,12 @@ const Navbar = () => {
<DropdownMenuGroup>
{[
{
name: "Profile & Settings",
name: t("profileSetting"),
icon: "heroicons:user",
href: "/profile",
},
{
name: "Kelola Konten",
name: t("contentManagement"),
icon: "stash:save-ribbon-duotone",
href: "/content-management/galery",
},
@ -1058,12 +1058,12 @@ const Navbar = () => {
<DropdownMenuGroup>
{[
{
name: "Profile & Settings",
name: t("profileSetting"),
icon: "heroicons:user",
href: "/profile",
},
{
name: "Kelola Konten",
name: t("contentManagement"),
icon: "stash:save-ribbon-duotone",
href: "/content-management/galery",
},

View File

@ -5,6 +5,7 @@ import { getInfoProfile, getListPorvinces, getUsersTeams } from "@/service/landi
import { Icon } from "@iconify/react/dist/iconify.js";
import React, { useEffect, useState } from "react";
import { useParams } from "next/navigation";
import { useTranslations } from "next-intl";
const SidebarManagement = () => {
const [profile, setProfile] = useState<any>();
@ -13,6 +14,7 @@ const SidebarManagement = () => {
const [selectedTab, setSelectedTab] = useState("video");
const params = useParams();
const pathname = usePathname();
const t = useTranslations("LandingPage");
// const currentRoute = router.pathname;
// const profilePicture = Cookies.get("profile_picture");
@ -67,7 +69,7 @@ const SidebarManagement = () => {
return (
<div className="p-4 lg:p-12 w-full lg:w-1/3 ">
<div className="border rounded-2xl border-black m-4">
<h1 className="text-xl p-5">Tentang Saya</h1>
<h1 className="text-xl p-5">{t("aboutMe")}</h1>
<div>
<ul className="px-10 mb-4">
<li className="mb-5 font-light">
@ -75,19 +77,19 @@ const SidebarManagement = () => {
<p>{profile?.email}</p>
</li>
<li className="mb-5 font-light">
<p className="font-semibold">No Handphone :</p>
<p className="font-semibold">{t("number")} :</p>
<p>{profile?.phoneNumber}</p>
</li>
<li className="mb-5 font-light">
<p className="font-semibold">Alamat :</p>
<p className="font-semibold">{t("address")} :</p>
<p>{profile?.address}</p>
</li>
<li className="mb-5 font-light">
<p className="font-semibold">Kategori :</p>
<p className="font-semibold">{t("category")} :</p>
<p>{profile?.institute?.categoryRole?.name}</p>
</li>
<li className="mb-5 font-light">
<p className="font-semibold">Instansi/Perusahaan :</p>
<p className="font-semibold">{t("company")} :</p>
<p>{profile?.institute?.name}</p>
</li>
</ul>
@ -99,7 +101,9 @@ const SidebarManagement = () => {
<div className={`${pathname?.includes("/content-management/galery") ? "bg-slate-500 text-white" : ""} hover:bg-slate-500 hover:text-white cursor-pointer p-4 rounded-lg flex justify-between`}>
<div className="flex items-center gap-2 text-lg">
<Icon icon="material-symbols-light:perm-media-rounded" />
<p className="text-sm">Galeri {profile?.institute?.name}</p>
<p className="text-sm">
{t("gallery")} {profile?.institute?.name}
</p>
</div>
<div>
<Icon icon="ri:arrow-right-s-line" fontSize={20} />
@ -110,7 +114,7 @@ const SidebarManagement = () => {
<div className={`${pathname?.includes("/content-management/download") ? "bg-slate-500 text-white" : ""} hover:bg-slate-500 hover:text-white cursor-pointer p-4 rounded-lg flex justify-between`}>
<div className="flex items-center gap-2 text-lg">
<Icon icon="heroicons:photo-solid" />
<p className="text-sm">Galeri Saya</p>
<p className="text-sm">{t("myGallery")} </p>
</div>
<div>
<Icon icon="ri:arrow-right-s-line" fontSize={20} />
@ -121,7 +125,7 @@ const SidebarManagement = () => {
<div className={`${pathname?.includes("/content-management/rewrite") ? "bg-slate-500 text-white" : ""} hover:bg-slate-500 hover:text-white cursor-pointer p-4 rounded-lg flex justify-between`}>
<div className="flex items-center gap-2 text-lg">
<Icon icon="material-symbols-light:perm-media-rounded" />
<p className="text-sm">Galeri Rewrite</p>
<p className="text-sm">{t("gallery")} Rewrite</p>
</div>
<div>
<Icon icon="ri:arrow-right-s-line" fontSize={20} />
@ -132,7 +136,7 @@ const SidebarManagement = () => {
<div className={`${pathname?.includes("/content-management/users") ? "bg-slate-500 text-white" : ""} hover:bg-slate-500 hover:text-white cursor-pointer p-4 rounded-lg flex justify-between`}>
<div className="flex items-center gap-2 text-lg">
<Icon icon="mdi:users-group" />
<p className="text-sm">Tim Pengguna</p>
<p className="text-sm">{t("userTeam")}</p>
</div>
<div>
<Icon icon="ri:arrow-right-s-line" fontSize={20} />

View File

@ -3,6 +3,8 @@ import React, { useEffect, useState } from "react";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { FiFile, FiImage, FiMusic, FiYoutube } from "react-icons/fi";
import { Icon } from "@iconify/react/dist/iconify.js";
import { useTranslations } from "next-intl";
import { Input } from "../ui/input";
const WelcomePolda = () => {
const router = useRouter();
@ -10,7 +12,7 @@ const WelcomePolda = () => {
const params = useParams();
const poldaName: any = params?.polda_name;
const [categorySelect, setCategorySelect] = useState("0");
const [search, setSearch] = useState();
const t = useTranslations("LandingPage");
useEffect(() => {
function initState() {
@ -25,11 +27,11 @@ const WelcomePolda = () => {
<div className="max-w-screen-xl mx-auto text-center">
{/* Heading */}
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 dark:text-white">
Selamat Datang di <span className="text-[#bb3523] dark:text-white">Polda</span> <span className="capitalize">{poldaName.replace("-", " ")}</span>
{t("welcome")} <span className="text-[#bb3523] dark:text-white">Polda</span> <span className="capitalize">{poldaName.replace("-", " ")}</span>
</h1>
<div className="w-[80%] h-1 bg-[#bb3523] mx-auto mt-2"></div>
<p className="text-sm md:text-base text-gray-500 dark:text-gray-100 mt-4">
Liputan resmi yang bersumber dari kegiatan Polri di Polda <span className="capitalize">{poldaName.replace("-", " ")}</span>
{t("polda")} <span className="capitalize">{poldaName.replace("-", " ")}</span>
</p>
{/* Search Form */}
@ -45,7 +47,7 @@ const WelcomePolda = () => {
fill="currentColor"
/>
</svg>
Konten
{t("content")}
<svg className="flex items-center justify-center" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" fill-rule="evenodd" d="m6 7l6 6l6-6l2 2l-8 8l-8-8z" />
</svg>
@ -55,25 +57,25 @@ const WelcomePolda = () => {
<DropdownMenuItem className="flex items-center gap-1.5 p-2 border-b text-default-600 group focus:bg-default focus:text-primary-foreground rounded-none group">
<span className="text-default-700c flex flex-row justify-center items-center group-hover:text-primary-foreground">
<FiYoutube className="mr-2" />
Audio Visual
{t("video")}
</span>
</DropdownMenuItem>
<DropdownMenuItem className="flex items-center gap-1.5 p-2 border-b text-default-600 group focus:bg-default focus:text-primary-foreground rounded-none group">
<span className="text-default-700 flex flex-row justify-center items-center group-hover:text-primary-foreground">
<FiMusic className="mr-2" />
Audio
{t("audio")}
</span>
</DropdownMenuItem>
<DropdownMenuItem className="flex items-center gap-1.5 p-2 border-b text-default-600 group focus:bg-default focus:text-primary-foreground rounded-none group">
<span className="text-default-700 flex flex-row justify-center items-center group-hover:text-primary-foreground">
<FiImage className="mr-2" />
Foto
{t("image")}
</span>
</DropdownMenuItem>
<DropdownMenuItem className="flex items-center gap-1.5 p-2 border-b text-default-600 group focus:bg-default focus:text-primary-foreground rounded-none group">
<span className="text-default-700 flex flex-row justify-center items-center group-hover:text-primary-foreground">
<FiFile className="mr-2" />
Teks
{t("text")}
</span>
</DropdownMenuItem>
</DropdownMenuContent>
@ -87,15 +89,13 @@ const WelcomePolda = () => {
/>
</svg>
</span>
<input type="text" placeholder="Pencarian" className="w-full py-2 px-2 text-sm text-gray-700 dark:text-gray-100 focus:outline-none" />
<Input type="text" placeholder={t("search")} className="w-full py-2 px-2 text-sm text-gray-700 dark:text-gray-100 focus:outline-none" />
</div>
</div>
{/* Search Input */}
{/* Button */}
<button className="flex justify-center items-center px-6 w-full lg:w-[20%] py-2 bg-[#bb3523] gap-2 text-white rounded-lg hover:bg-red-700">
Cari Liputan <Icon icon="ri:arrow-right-s-line" fontSize={20} />
{t("searchCoverage")} <Icon icon="ri:arrow-right-s-line" fontSize={20} />
</button>
</div>
</div>

View File

@ -5,7 +5,7 @@ import React, { useEffect, useState } from "react";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { FiFile, FiImage, FiMusic, FiYoutube } from "react-icons/fi";
import { Icon } from "@iconify/react/dist/iconify.js";
import { capitalize } from "@/utils/globals";
import { useTranslations } from "next-intl";
const WelcomeSatker = () => {
const router = useRouter();
@ -13,7 +13,7 @@ const WelcomeSatker = () => {
const params = useParams();
const satkerName: any = params?.satker_name;
const [categorySelect, setCategorySelect] = useState("0");
const [search, setSearch] = useState();
const t = useTranslations("LandingPage");
useEffect(() => {
function initState() {
@ -28,11 +28,11 @@ const WelcomeSatker = () => {
<div className="max-w-screen-xl mx-auto text-center">
{/* Heading */}
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 dark:text-white">
Selamat Datang di <span className="text-[#bb3523] dark:text-white">Satker</span> <span className="capitalize">{satkerName.replace("-", " ")}</span>
{t("welcome")} <span className="text-[#bb3523] dark:text-white">Satker</span> <span className="capitalize">{satkerName.replace("-", " ")}</span>
</h1>
<div className="w-[80%] h-1 bg-[#bb3523] mx-auto mt-2"></div>
<p className="text-sm md:text-base text-gray-500 dark:text-gray-100 mt-4">
Liputan resmi yang bersumber dari kegiatan Polri di Satker <span className="capitalize">{satkerName.replace("-", " ")}</span>
{t("satker")} <span className="capitalize">{satkerName.replace("-", " ")}</span>
</p>
{/* Search Form */}
@ -48,7 +48,7 @@ const WelcomeSatker = () => {
fill="currentColor"
/>
</svg>
Konten
{t("content")}
<svg className="flex items-center justify-center" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path fill="currentColor" fill-rule="evenodd" d="m6 7l6 6l6-6l2 2l-8 8l-8-8z" />
</svg>
@ -58,25 +58,25 @@ const WelcomeSatker = () => {
<DropdownMenuItem className="flex items-center gap-1.5 p-2 border-b text-default-600 group focus:bg-default focus:text-primary-foreground rounded-none group">
<span className="text-default-700c flex flex-row justify-center items-center group-hover:text-primary-foreground">
<FiYoutube className="mr-2" />
Audio Visual
{t("video")}
</span>
</DropdownMenuItem>
<DropdownMenuItem className="flex items-center gap-1.5 p-2 border-b text-default-600 group focus:bg-default focus:text-primary-foreground rounded-none group">
<span className="text-default-700 flex flex-row justify-center items-center group-hover:text-primary-foreground">
<FiMusic className="mr-2" />
Audio
{t("audio")}
</span>
</DropdownMenuItem>
<DropdownMenuItem className="flex items-center gap-1.5 p-2 border-b text-default-600 group focus:bg-default focus:text-primary-foreground rounded-none group">
<span className="text-default-700 flex flex-row justify-center items-center group-hover:text-primary-foreground">
<FiImage className="mr-2" />
Foto
{t("image")}
</span>
</DropdownMenuItem>
<DropdownMenuItem className="flex items-center gap-1.5 p-2 border-b text-default-600 group focus:bg-default focus:text-primary-foreground rounded-none group">
<span className="text-default-700 flex flex-row justify-center items-center group-hover:text-primary-foreground">
<FiFile className="mr-2" />
Teks
{t("text")}
</span>
</DropdownMenuItem>
</DropdownMenuContent>
@ -90,15 +90,13 @@ const WelcomeSatker = () => {
/>
</svg>
</span>
<input type="text" placeholder="Pencarian" className="w-full py-2 px-2 text-sm text-gray-700 dark:text-gray-100 focus:outline-none" />
<input type="text" placeholder={t("search")} className="w-full py-2 px-2 text-sm text-gray-700 dark:text-gray-100 focus:outline-none" />
</div>
</div>
{/* Search Input */}
{/* Button */}
<button className="flex justify-center items-center px-6 w-full lg:w-[20%] py-2 bg-[#bb3523] gap-2 text-white rounded-lg hover:bg-red-700">
Cari Liputan <Icon icon="ri:arrow-right-s-line" fontSize={20} />
{t("searchCoverage")} <Icon icon="ri:arrow-right-s-line" fontSize={20} />
</button>
</div>
</div>

View File

@ -454,7 +454,70 @@
"addressInst": "Input the complete address of your institution",
"identityEmpty": "Identity number cannot be empty",
"policeNumber": "Police Registration Number",
"breakingNews": "BREAKING NEWS"
"breakingNews": "BREAKING NEWS",
"changeProfile": "Change Profile",
"userProfile": "User Profile",
"changePhoto": "Change Photo",
"changePass": "Change Password",
"pleaseChange": "Please change your personal data in the following form.",
"identityNumber": "Identity Number",
"noImage": "No Image",
"deletePhoto": "Delete Photo",
"activeSince": "Active since",
"fullProfile": "View full profile",
"aboutMe": "About Me",
"company": "Agency/Company",
"gallery": "Gallery",
"myGallery": "My Gallery",
"userTeam": "User Team",
"my": "My",
"team": "Team",
"teamMembers": "Team Members",
"reasonReport": "Reasons for Reporting Account",
"saveData": "Save Data ?",
"language": "Language",
"selectLanguage": "Select Language",
"contextType": "Context Type",
"selectContext": "Select Context",
"article": "Article",
"transcript": "Transcript",
"writingStyle": "Writing Style",
"selectWriting": "Select Writing Style",
"articleSize": "Article Size",
"selectSize": "Select Size",
"title": "Title",
"mainKeyword": "Main Keyword",
"newDescription": "New Description",
"back": "Back",
"notifList": "Notification List",
"userFeedback": "User Feedback",
"ratings": "Please provide your rating regarding the ease of access to the MediaHUB Polri website.",
"ratings2": "Please give your rating regarding the appearance of the MediaHUB Polri website.",
"ratings3": "Please give your rating regarding the content of MediaHUB Polri",
"contactUs": "Contact Us",
"writeMessage": "Write a Message",
"leaveMessage": "Please leave your message in the column provided",
"name": "Name",
"subject": "Subject",
"selectSubject": "Select Subject",
"question": "Question",
"criticism": "Criticism",
"suggestion": "Suggestion",
"messages": "Messages",
"profileSetting": "Profile & Settings",
"enterName": "Enter your full name",
"writeYourMessage": "Write your message",
"question1": "WHAT CONTENT IS ON MEDIAHUB AND WHAT CATEGORIES ARE THERE IN IT?",
"answer1": "MediaHub has a variety of content such as news, videos, and documents categorized into topics such as education, entertainment, and current affairs.",
"question2": "HOW CAN MEDIAHUB CONTENT BE DOWNLOADED?",
"answer2": "You can download content by clicking the download button available on each content on the MediaHub page.",
"question3": "WHO CAN REGISTER AS A MEDIAHUB USER?",
"answer3": "Anyone who has an interest in the content on MediaHub can register as a user, either for personal or professional purposes.",
"question4": "WHAT IS MEDIAHUB? AND WHAT ARE THE FEATURES IN IT?",
"answer4": "MediaHub is a platform that provides various informative and educational content. Key features include search, download, and personalization of content.",
"welcome": "Welcome To",
"polda": "Official coverage sourced from Polri activities at Polda",
"satker": "Official coverage sourced from Polri activities at Satker"
},
"FilterPage": {
"image": "Image",

View File

@ -370,7 +370,7 @@
"updatedOn": "Diupdate pada",
"creator": "Kreator :",
"delete": "Hapus",
"imageSize": "Opsi Ukuran Poto",
"imageSize": "Opsi Ukuran Foto",
"downloadAll": "Download Semua File?",
"share": "Bagikan",
"shareTo": "Bagikan ke Email",
@ -409,7 +409,7 @@
"fullName": "Nama Lengkap",
"enterFullName": "Masukkan Nama Lengkap Anda",
"enterUsername": "Masukkan Username Anda",
"number": "Nomor Telepon",
"number": "Nomor Handphone",
"enterNumber": "Masukkan Nomor Telepon Anda",
"enterEmail": "Masukkan Email Anda",
"address": "Alamat",
@ -454,8 +454,70 @@
"addressInst": "Masukkan Alamat lengkap institusi anda",
"identityEmpty": "Nomor identitas tidak boleh kosong",
"policeNumber": "Nomor Registrasi Polri (NRP)",
"breakingNews": "BERITA TERKINI"
"breakingNews": "BERITA TERKINI",
"changeProfile": "Ubah Profil",
"userProfile": "Profil Pengguna",
"changePhoto": "Ubah Foto",
"changePass": "Ubah Password",
"pleaseChange": "Silahkan ubah data pribadi Anda pada form berikut.",
"identityNumber": "Nomor Identitas",
"noImage": "Tanpa Foto",
"deletePhoto": "Hapus Foto",
"activeSince": "Aktif Sejak",
"fullProfile": "Lihat profil lengkap",
"aboutMe": "Tentang Saya",
"company": "Instansi/Perusahaan",
"gallery": "Galeri",
"myGallery": "Galeri Saya",
"userTeam": "Tim Pengguna",
"my": "Saya",
"team": "Tim",
"teamMembers": "Anggota Tim",
"reasonReport": "Alasan Report Akun",
"saveData": "Simpan Data ?",
"language": "Bahasa",
"selectLanguage": "Pilih Bahasa",
"contextType": "Jenis Konteks",
"selectContext": "Pilih Konteks",
"article": "Artikel",
"transcript": "Transkrip",
"writingStyle": "Gaya Penulisan",
"selectWriting": "Pilih Gaya Penulisan",
"articleSize": "Ukuran Artikel",
"selectSize": "Pilih Ukuran Artikel",
"title": "Judul",
"mainKeyword": "Kata Kunci",
"newDescription": "Deskripsi Baru",
"back": "Kembali",
"notifList": "List Notifikasi",
"userFeedback": "Feedback Pengguna",
"ratings": "Silakan berikan rating Anda terkait dengan kemudahan akses website MediaHUB Polri.",
"ratings2": "Silakan berikan rating Anda terkait dengan tampilan website MediaHUB Polri.",
"ratings3": "Silahkan berikan rating Anda terkait dengan konten MediaHUB Polri.",
"contactUs": "Hubungi Kami",
"writeMessage": "Tulis Pesan",
"leaveMessage": "Silahkan tinggalkan pesan Anda pada kolom yang tersedia.",
"name": "Nama",
"subject": "Subjek",
"selectSubject": "Pilih Subjek",
"question": "Pertanyaan",
"criticism": "Kritik",
"suggestion": "Saran",
"messages": "Pesan",
"profileSetting": "Profil & Pengaturan",
"enterName": "Masukkan Nama Lengkap Anda",
"writeYourMessage": "Write your message",
"question1": "APA SAJA KONTEN-KONTEN YANG ADA DI MEDIAHUB DAN KATEGORI DI DALAMNYA?",
"answer1": "MediaHub memiliki beragam konten seperti berita, video, dan dokumen yang dikategorikan dalam topik seperti edukasi, hiburan, dan informasi terkini.",
"question2": "BAGAIMANA KONTEN DARI MEDIAHUB DAPAT DIUNDUH?",
"answer2": "Anda dapat mengunduh konten dengan klik tombol unduh yang tersedia pada setiap konten di halaman MediaHub.",
"question3": "SIAPA SAJA YANG DAPAT MENDAFTARKAN DIRI SEBAGAI PENGGUNA MEDIAHUB?",
"answer3": "Semua orang yang memiliki minat terhadap konten di MediaHub dapat mendaftar sebagai pengguna, baik untuk personal maupun profesional.",
"question4": "APA ITU MEDIAHUB? DAN APA SAJA FITUR YANG ADA DI DALAMNYA?",
"answer4": "MediaHub adalah platform yang menyediakan berbagai konten informatif dan edukatif. Fitur utama meliputi pencarian, pengunduhan, dan personalisasi konten.",
"welcome": "Selamat Datang di",
"polda": "Liputan resmi yang bersumber dari kegiatan Polri di Polda",
"satker": "Liputan resmi yang bersumber dari kegiatan Polri di Satker"
},
"FilterPage": {
"image": "Foto",

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

View File

@ -63,6 +63,11 @@ export async function getProfile(token: any) {
return httpGetInterceptorWithToken(url, token);
}
export async function getSubjects() {
const url = 'inbox/subjects';
return httpGetInterceptor( url );
}
export async function getInfoProfile() {
const url = "users/info";
return httpGetInterceptor(url);

View File

@ -200,3 +200,8 @@ export async function deleteBlogComments(slug: any) {
const url = `blog/comments?id=${slug}`;
return httpDeleteInterceptor(url);
}
export async function sendMessage(data: any) {
const url = 'inbox';
return httpPostInterceptor( url, data );
}

View File

@ -8,11 +8,7 @@ export const generateLocalizedPath = (href: string, locale: string): string => {
return `/${locale}${href}`;
};
export function textEllipsis(
str: string,
maxLength: number,
{ side = "end", ellipsis = "..." } = {}
) {
export function textEllipsis(str: string, maxLength: number, { side = "end", ellipsis = "..." } = {}) {
if (str !== undefined && str?.length > maxLength) {
switch (side) {
case "start":
@ -27,7 +23,7 @@ export function textEllipsis(
export function formatDateToIndonesian(d: Date) {
try {
const dateString = format(d, "d MMMM yyyy HH:mm", { locale: id });
const dateString = format(d, "d/MM/yy HH:mm", { locale: id });
return dateString;
} catch (error) {
return "";
@ -64,6 +60,14 @@ export function getOnlyDate(date: Date) {
return `${year}-${month}-${day}`;
}
export function getOnlyDateSlash(date: Date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${day}/${month}/${year}`;
}
export function getOnlyMonthAndYear(d: Date) {
const pad = (n: any, s = 2) => `${new Array(s).fill(0)}${n}`.slice(-s);
return `${pad(d.getMonth() + 1)}/${pad(d.getFullYear(), 4)}`;
@ -71,10 +75,7 @@ export function getOnlyMonthAndYear(d: Date) {
export function getPublicLocaleTimestamp(d: any) {
const pad = (n: any, s = 2) => `${new Array(s).fill(0)}${n}`.slice(-s);
return `${pad(d.getDate())}/${pad(d.getMonth() + 1)}/${pad(
d.getFullYear(),
4
)} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
return `${pad(d.getDate())}/${pad(d.getMonth() + 1)}/${pad(d.getFullYear(), 4)} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
}
export function capitalize(s: any) {
@ -87,13 +88,9 @@ export function capitalize(s: any) {
}
export function getLocaleTimestamp(d: Date): string {
const pad = (n: number, s: number = 2): string =>
`${new Array(s).fill(0)}${n}`.slice(-s);
const pad = (n: number, s: number = 2): string => `${new Array(s).fill(0)}${n}`.slice(-s);
return `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${pad(
d.getFullYear(),
4
)} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
return `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${pad(d.getFullYear(), 4)} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
export function getLocaleTime(d: Date) {
@ -102,9 +99,7 @@ export function getLocaleTime(d: Date) {
}
export function getTimestamp(d: Date) {
const pad = (n: any, s = 2) => `${new Array(s).fill(0)}${n}`.slice(-s);
return `${pad(d.getFullYear(), 4)}-${pad(d.getMonth() + 1)}-${pad(
d.getDate()
)} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
return `${pad(d.getFullYear(), 4)}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
export function secondToTimes(sec: number) {
@ -118,10 +113,7 @@ export function secondToTimes(sec: number) {
export function checkMaliciousText(str: any) {
try {
const urlPattern = new RegExp(
"(https?:\\/\\/(?:www\\.|(?!www))[^\\s\\.]+\\.[^\\s]{2,}|www\\.[^\\s]+\\.[^\\s]{2,}|https?:\\/\\/[^\\s]+|\\b(?:https?|ftp):\\/\\/[^\\s/$.?#].[^\\s]*)",
"gi"
);
const urlPattern = new RegExp("(https?:\\/\\/(?:www\\.|(?!www))[^\\s\\.]+\\.[^\\s]{2,}|www\\.[^\\s]+\\.[^\\s]{2,}|https?:\\/\\/[^\\s]+|\\b(?:https?|ftp):\\/\\/[^\\s/$.?#].[^\\s]*)", "gi");
const isContainUrl = urlPattern.test(str);
if (isContainUrl) {
return "Message mengandung URL yang tidak diizinkan";