fix: fixing filter and add thumbnail in admin update

This commit is contained in:
Sabda Yagra 2025-07-21 22:23:30 +07:00
parent 481cf1a2b4
commit e0bb77e7af
15 changed files with 435 additions and 304 deletions

View File

@ -134,7 +134,7 @@ const DetailVideo = () => {
const handleDownload = () => { const handleDownload = () => {
if (downloadProgress === 0) { if (downloadProgress === 0) {
if (!userId) { if (!userId) {
router.push("/auth/login"); router.push("/auth");
} else { } else {
sendActivityLog(2); sendActivityLog(2);
sendActivityLog(3); sendActivityLog(3);

View File

@ -34,6 +34,7 @@ import FilterImageComponent from "@/components/landing-page/filter-all/image-fil
import FilterVideoComponent from "@/components/landing-page/filter-all/video-filter-card"; import FilterVideoComponent from "@/components/landing-page/filter-all/video-filter-card";
import FilterDocumentComponent from "@/components/landing-page/filter-all/document-filter-card"; import FilterDocumentComponent from "@/components/landing-page/filter-all/document-filter-card";
import FilterAudioComponent from "@/components/landing-page/filter-all/audio-filter-card"; import FilterAudioComponent from "@/components/landing-page/filter-all/audio-filter-card";
import { useTranslations } from "next-intl";
export default function FilterPage() { export default function FilterPage() {
const router = useRouter(); const router = useRouter();
@ -86,6 +87,8 @@ export default function FilterPage() {
const [categories, setCategories] = useState([]); const [categories, setCategories] = useState([]);
const [userLevels, setUserLevels] = useState([]); const [userLevels, setUserLevels] = useState([]);
const [contentAll, setContentAll] = useState([]); const [contentAll, setContentAll] = useState([]);
const t = useTranslations("FilterPage");
const [isFilterOpen, setIsFilterOpen] = useState(true);
// const [startDate, endDate] = dateRange; // const [startDate, endDate] = dateRange;
@ -387,22 +390,35 @@ export default function FilterPage() {
}; };
return ( return (
<div className="flex flex-col"> <div className="flex flex-col w-full max-w-screen overflow-x-hidden">
{/* Header */} <div className="flex flex-row md:flex-row items-start gap-3 py-10 px-4 lg:px-20 bg-[#f7f7f7] dark:bg-black">
<p> {t("content", { defaultValue: "Content" })}</p>
<div className="flex flex-col md:flex-row items-start gap-5 p-10 bg-[#f7f7f7] dark:bg-black"> {">"}
<p> <p>
{" "} <span className="font-bold">
Konten {">"} <span className="font-bold">Semua Konten</span> {t("allContent", { defaultValue: "All Content" })}
</span>
</p> </p>
<p className="font-bold">|</p> <p className="font-bold">|</p>
<p>{`Hasil Pencarian ${title} `}</p> <p>{`${t("thereIs", { defaultValue: "There Is" })} ${totalContent} ${t(
{`Terdapat ${contentAll?.length} konten yang dapat diunduh`} "downloadableContent",
{ defaultValue: "Downloadable ContentS" }
)}`}</p>
</div> </div>
{/* Left */} {/* Left */}
<div className="flex flex-col lg:flex-row gap-6 p-4"> <div className="flex flex-col lg:flex-row gap-6 pl-4 lg:pl-20 py-4">
<div className="lg:w-[25%] w-full bg-[#f7f7f7] dark:bg-black p-4 rounded-lg shadow-md"> <div className="lg:hidden flex justify-end mb-2">
<button
onClick={() => setIsFilterOpen(!isFilterOpen)}
className="text-sm text-white bg-[#bb3523] px-4 py-1 rounded-md shadow"
>
{isFilterOpen ? "Hide Filter" : "Show Filter"}
</button>
</div>
{isFilterOpen && (
<div className="h-fit min-w-full lg:min-w-[280px] max-w-full lg:max-w-[300px] bg-[#f7f7f7] dark:bg-black p-4 rounded-lg shadow-md">
<h2 className="text-lg font-semibold mb-4 flex items-center gap-1"> <h2 className="text-lg font-semibold mb-4 flex items-center gap-1">
<Icon icon="stash:filter-light" fontSize={30} /> <Icon icon="stash:filter-light" fontSize={30} />
Filter Filter
@ -414,7 +430,7 @@ export default function FilterPage() {
htmlFor="search" htmlFor="search"
className="block text-sm font-medium text-gray-700 dark:text-white" className="block text-sm font-medium text-gray-700 dark:text-white"
> >
Pencarian {t("search", { defaultValue: "Search" })}
</label> </label>
<Input <Input
value={searchTitle} value={searchTitle}
@ -423,39 +439,45 @@ export default function FilterPage() {
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
type="text" type="text"
id="search" id="search"
placeholder="Cari judul..." placeholder={t("searchTitle", {
defaultValue: "Search Title",
})}
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 dark:text-white"> <label className="block text-sm font-medium text-gray-700 dark:text-white">
Tahun & Bulan {t("monthYear", { defaultValue: "Month Year" })}
</label> </label>
<ReactDatePicker <ReactDatePicker
selected={monthYearFilter} selected={monthYearFilter}
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" className="mt-1 w-full text-xs border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
onChange={(date) => setMonthYearFilter(date)} onChange={(date) => setMonthYearFilter(date)}
dateFormat="MM | yyyy" dateFormat="MM | yyyy"
placeholderText="Pilih Tahun dan Bulan" placeholderText={t("selectYear", {
defaultValue: "Select Year",
})}
showMonthYearPicker showMonthYearPicker
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 dark:text-white"> <label className="block text-sm font-medium text-gray-700 dark:text-white">
Tanggal {t("date", { defaultValue: "Date" })}
</label> </label>
<div className="flex flex-row justify justify-between gap-2"> <div className="flex flex-row justify justify-between gap-2">
<ReactDatePicker <ReactDatePicker
selectsRange selectsRange
className="mt-1 w-full border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" className="mt-1 w-full border text-sm rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
startDate={dateRange[0]} startDate={dateRange[0]}
endDate={dateRange[1]} endDate={dateRange[1]}
onChange={(update) => { onChange={(update) => {
setDateRange(update); setDateRange(update);
}} }}
placeholderText="Pilih Tanggal" placeholderText={t("selectDate", {
defaultValue: "Select Date",
})}
onCalendarClose={() => setCalenderState(!calenderState)} onCalendarClose={() => setCalenderState(!calenderState)}
/> />
<div className="flex items-center"> <div className="flex items-center">
@ -476,7 +498,7 @@ export default function FilterPage() {
<div> <div>
<h3 className="text-sm font-medium text-gray-700 dark:text-white"> <h3 className="text-sm font-medium text-gray-700 dark:text-white">
Kategori {t("categories", { defaultValue: "Categories" })}
</h3> </h3>
<ul className="mt-2 space-y-2"> <ul className="mt-2 space-y-2">
{categories.map((category: any) => ( {categories.map((category: any) => (
@ -499,6 +521,63 @@ export default function FilterPage() {
</label> </label>
</li> </li>
))} ))}
{/* <div className="mt-4 flex gap-2 justify-center items-center">
<button
onClick={() =>
setCategoryPage((prev) => Math.max(prev - 1, 1))
}
disabled={categoryPage === 1}
className="px-3 py-1 border rounded disabled:opacity-50"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="m13.15 16.15l-3.625-3.625q-.125-.125-.175-.25T9.3 12t.05-.275t.175-.25L13.15 7.85q.075-.075.163-.112T13.5 7.7q.2 0 .35.138T14 8.2v7.6q0 .225-.15.363t-.35.137q-.05 0-.35-.15"
/>
</svg>
</button>
{Array.from({ length: categoryTotalPages }, (_, i) => (
<button
key={i}
onClick={() => setCategoryPage(i + 1)}
className={`px-3 py-1 border rounded ${
categoryPage === i + 1
? "bg-[#bb3523] text-white"
: ""
}`}
>
{i + 1}
</button>
))}
<button
onClick={() =>
setCategoryPage((prev) =>
Math.min(prev + 1, categoryTotalPages)
)
}
disabled={categoryPage === categoryTotalPages}
className="px-3 py-1 border rounded disabled:opacity-50"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M10.5 16.3q-.2 0-.35-.137T10 15.8V8.2q0-.225.15-.362t.35-.138q.05 0 .35.15l3.625 3.625q.125.125.175.25t.05.275t-.05.275t-.175.25L10.85 16.15q-.075.075-.162.113t-.188.037"
/>
</svg>
</button>
</div> */}
</ul> </ul>
</div> </div>
{/* Garis */} {/* Garis */}
@ -506,7 +585,7 @@ export default function FilterPage() {
{/* Garis */} {/* Garis */}
<div> <div>
<h3 className="text-sm font-medium text-gray-700 dark:text-white"> <h3 className="text-sm font-medium text-gray-700 dark:text-white">
Format Konten Format
</h3> </h3>
<ul className="mt-2 space-y-2"> <ul className="mt-2 space-y-2">
<li> <li>
@ -514,13 +593,13 @@ export default function FilterPage() {
<Checkbox <Checkbox
id="png" id="png"
value="png" value="png"
checked={formatFilter.includes("image")} checked={formatFilter.includes("png")}
onCheckedChange={(e) => onCheckedChange={(e) =>
handleFormatFilter(Boolean(e), "image") handleFormatFilter(Boolean(e), "png")
} }
/> />
<span className="ml-2 text-gray-700 dark:text-white"> <span className="ml-2 text-gray-700 dark:text-white">
Foto PNG
</span> </span>
</label> </label>
</li> </li>
@ -529,13 +608,13 @@ export default function FilterPage() {
<Checkbox <Checkbox
id="jpeg" id="jpeg"
value="jpeg" value="jpeg"
checked={formatFilter.includes("video")} checked={formatFilter.includes("jpeg")}
onCheckedChange={(e) => onCheckedChange={(e) =>
handleFormatFilter(Boolean(e), "video") handleFormatFilter(Boolean(e), "jpeg")
} }
/> />
<span className="ml-2 text-gray-700 dark:text-white"> <span className="ml-2 text-gray-700 dark:text-white">
Audio Visual JPEG
</span> </span>
</label> </label>
</li> </li>
@ -544,28 +623,13 @@ export default function FilterPage() {
<Checkbox <Checkbox
id="jpg" id="jpg"
value="jpg" value="jpg"
checked={formatFilter.includes("document")} checked={formatFilter.includes("jpg")}
onCheckedChange={(e) => onCheckedChange={(e) =>
handleFormatFilter(Boolean(e), "document") handleFormatFilter(Boolean(e), "jpg")
} }
/> />
<span className="ml-2 text-gray-700 dark:text-white"> <span className="ml-2 text-gray-700 dark:text-white">
Teks JPG
</span>
</label>
</li>
<li>
<label className="inline-flex items-center">
<Checkbox
id="jpg"
value="jpg"
checked={formatFilter.includes("audio")}
onCheckedChange={(e) =>
handleFormatFilter(Boolean(e), "audio")
}
/>
<span className="ml-2 text-gray-700 dark:text-white">
Audio
</span> </span>
</label> </label>
</li> </li>
@ -582,21 +646,29 @@ export default function FilterPage() {
</div> </div>
</div> </div>
</div> </div>
)}
{/* Konten Kanan */} {/* Konten Kanan */}
<div className="flex-1 w-[75%]"> <div className="w-full pl-4 pr-4 lg:pr-16 pb-4 overflow-x-hidden">
<div className="w-full">
<div className="flex flex-col items-end mb-4"> <div className="flex flex-col items-end mb-4">
<h2 className="text-lg font-semibold">Urutkan berdasarkan</h2> <h2 className="text-lg font-semibold">
{t("sortBy", { defaultValue: "Sort By" })}
</h2>
<select <select
defaultValue={sortBy == "popular" ? "terpopuler" : "terbaru"} defaultValue={sortBy == "popular" ? "terpopuler" : "terbaru"}
onChange={(e) => handleSorting(e)} onChange={(e) => handleSorting(e)}
className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
> >
<option value="terbaru">Terbaru</option> <option value="latest">
<option value="terpopuler">Terpopuler</option> {t("latest", { defaultValue: "Latest" })}
</option>
<option value="popular">
{t("mostPopular", { defaultValue: "Most Popular" })}
</option>
</select> </select>
</div> </div>
<div className="flex flex-col gap-2 w-full"> <div className="flex flex-col gap-4 w-full">
<FilterImageComponent <FilterImageComponent
categoryFilter={categoryFilter} categoryFilter={categoryFilter}
sortByOpt={sortByOpt} sortByOpt={sortByOpt}
@ -629,5 +701,6 @@ export default function FilterPage() {
</div> </div>
</div> </div>
</div> </div>
</div>
); );
} }

View File

@ -488,10 +488,16 @@ const FilterPage = () => {
<div className="flex flex-col md:flex-row items-start gap-5 py-10 px-4 lg:px-20 bg-[#f7f7f7] dark:bg-black"> <div className="flex flex-col md:flex-row items-start gap-5 py-10 px-4 lg:px-20 bg-[#f7f7f7] dark:bg-black">
<p> <p>
{" "} {" "}
Audio {">"} <span className="font-bold">{t("allAudio", { defaultValue: "All Audio" })}</span> Audio {">"}{" "}
<span className="font-bold">
{t("allAudio", { defaultValue: "All Audio" })}
</span>
</p> </p>
<p className="font-bold">|</p> <p className="font-bold">|</p>
<p>{`${t("thereIs", { defaultValue: "There Is" })} ${totalContent} ${t("downloadableAudio", { defaultValue: "Downloadable Audio" })}`}</p> <p>{`${t("thereIs", { defaultValue: "There Is" })} ${totalContent} ${t(
"downloadableAudio",
{ defaultValue: "Downloadable Audio" }
)}`}</p>
</div> </div>
{/* Left */} {/* Left */}
@ -531,7 +537,9 @@ const FilterPage = () => {
className="mt-1 w-full text-xs border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" className="mt-1 w-full text-xs border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
onChange={(date) => setMonthYearFilter(date)} onChange={(date) => setMonthYearFilter(date)}
dateFormat="MM | yyyy" dateFormat="MM | yyyy"
placeholderText={t("selectYear", { defaultValue: "Select Year" })} placeholderText={t("selectYear", {
defaultValue: "Select Year",
})}
showMonthYearPicker showMonthYearPicker
/> />
</div> </div>
@ -549,7 +557,9 @@ const FilterPage = () => {
onChange={(update) => { onChange={(update) => {
setDateRange(update); setDateRange(update);
}} }}
placeholderText={t("searchDate", { defaultValue: "Search Date" })} placeholderText={t("searchDate", {
defaultValue: "Search Date",
})}
onCalendarClose={() => setCalenderState(!calenderState)} onCalendarClose={() => setCalenderState(!calenderState)}
/> />
<div className="flex items-center"> <div className="flex items-center">
@ -593,8 +603,7 @@ const FilterPage = () => {
</label> </label>
</li> </li>
))} ))}
<div className="mt-4 flex gap-2 justify-center items-center"> {/* <div className="mt-4 flex gap-2 justify-center items-center">
{/* Tombol Prev */}
<button <button
onClick={() => onClick={() =>
setCategoryPage((prev) => Math.max(prev - 1, 1)) setCategoryPage((prev) => Math.max(prev - 1, 1))
@ -615,7 +624,6 @@ const FilterPage = () => {
</svg> </svg>
</button> </button>
{/* Nomor Halaman */}
{Array.from({ length: categoryTotalPages }, (_, i) => ( {Array.from({ length: categoryTotalPages }, (_, i) => (
<button <button
key={i} key={i}
@ -628,7 +636,6 @@ const FilterPage = () => {
</button> </button>
))} ))}
{/* Tombol Next */}
<button <button
onClick={() => onClick={() =>
setCategoryPage((prev) => setCategoryPage((prev) =>
@ -650,7 +657,7 @@ const FilterPage = () => {
/> />
</svg> </svg>
</button> </button>
</div> </div> */}
</ul> </ul>
</div> </div>
{/* Garis */} {/* Garis */}
@ -709,14 +716,20 @@ const FilterPage = () => {
<div className="w-full pr-4 lg:pr-16 pb-4"> <div className="w-full pr-4 lg:pr-16 pb-4">
<Reveal> <Reveal>
<div className="flex flex-col items-end mb-4"> <div className="flex flex-col items-end mb-4">
<h2 className="text-lg font-semibold">{t("sortBy", { defaultValue: "Sort By" })} </h2> <h2 className="text-lg font-semibold">
{t("sortBy", { defaultValue: "Sort By" })}{" "}
</h2>
<select <select
defaultValue={sortBy == "popular" ? "terpopuler" : "terbaru"} defaultValue={sortBy == "popular" ? "terpopuler" : "terbaru"}
onChange={(e) => handleSorting(e)} onChange={(e) => handleSorting(e)}
className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500" className="border rounded-md py-2 px-3 focus:ring-red-500 focus:border-red-500"
> >
<option value="latest">{t("latest", { defaultValue: "Latest" })}</option> <option value="latest">
<option value="popular">{t("mostPopular", { defaultValue: "Most Popular" })}</option> {t("latest", { defaultValue: "Latest" })}
</option>
<option value="popular">
{t("mostPopular", { defaultValue: "Most Popular" })}
</option>
</select> </select>
</div> </div>

View File

@ -609,8 +609,7 @@ const FilterPage = () => {
</label> </label>
</li> </li>
))} ))}
<div className="mt-4 flex gap-2 justify-center items-center"> {/* <div className="mt-4 flex gap-2 justify-center items-center">
{/* Tombol Prev */}
<button <button
onClick={() => onClick={() =>
setCategoryPage((prev) => Math.max(prev - 1, 1)) setCategoryPage((prev) => Math.max(prev - 1, 1))
@ -631,7 +630,6 @@ const FilterPage = () => {
</svg> </svg>
</button> </button>
{/* Nomor Halaman */}
{Array.from({ length: categoryTotalPages }, (_, i) => ( {Array.from({ length: categoryTotalPages }, (_, i) => (
<button <button
key={i} key={i}
@ -644,7 +642,6 @@ const FilterPage = () => {
</button> </button>
))} ))}
{/* Tombol Next */}
<button <button
onClick={() => onClick={() =>
setCategoryPage((prev) => setCategoryPage((prev) =>
@ -666,7 +663,7 @@ const FilterPage = () => {
/> />
</svg> </svg>
</button> </button>
</div> </div> */}
</ul> </ul>
</div> </div>
{/* Garis */} {/* Garis */}

View File

@ -485,24 +485,24 @@ const FilterPage = () => {
clearTimeout(typingTimer); clearTimeout(typingTimer);
}; };
const shimmer = (w: number, h: number) => ` // const shimmer = (w: number, h: number) => `
<svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> // <svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs> // <defs>
<linearGradient id="g"> // <linearGradient id="g">
<stop stop-color="#bcbcbd" offset="20%" /> // <stop stop-color="#bcbcbd" offset="20%" />
<stop stop-color="#f9fafb" offset="50%" /> // <stop stop-color="#f9fafb" offset="50%" />
<stop stop-color="#bcbcbd" offset="70%" /> // <stop stop-color="#bcbcbd" offset="70%" />
</linearGradient> // </linearGradient>
</defs> // </defs>
<rect width="${w}" height="${h}" fill="#bcbcbd" /> // <rect width="${w}" height="${h}" fill="#bcbcbd" />
<rect id="r" width="${w}" height="${h}" fill="url(#g)" /> // <rect id="r" width="${w}" height="${h}" fill="url(#g)" />
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" /> // <animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
</svg>`; // </svg>`;
const toBase64 = (str: string) => // const toBase64 = (str: string) =>
typeof window === "undefined" // typeof window === "undefined"
? Buffer.from(str).toString("base64") // ? Buffer.from(str).toString("base64")
: window.btoa(str); // : window.btoa(str);
return ( return (
<div className="flex flex-col"> <div className="flex flex-col">
@ -517,8 +517,9 @@ const FilterPage = () => {
<p>{`${t("thereIs", { defaultValue: "There Is" })} ${totalContent} ${t("downloadableImage", { defaultValue: "Downloadable Image" })}`}</p> <p>{`${t("thereIs", { defaultValue: "There Is" })} ${totalContent} ${t("downloadableImage", { defaultValue: "Downloadable Image" })}`}</p>
</div> </div>
{/* Left */}
<div className="flex flex-col lg:flex-row gap-6 pl-4 lg:pl-20 py-4"> <div className="flex flex-col lg:flex-row gap-6 pl-4 lg:pl-20 py-4">
{/* Left */}
<div className="lg:hidden flex justify-end mb-2"> <div className="lg:hidden flex justify-end mb-2">
<button <button
onClick={() => setIsFilterOpen(!isFilterOpen)} onClick={() => setIsFilterOpen(!isFilterOpen)}
@ -626,8 +627,7 @@ const FilterPage = () => {
</label> </label>
</li> </li>
))} ))}
<div className="mt-4 flex gap-2 justify-center items-center"> {/* <div className="mt-4 flex gap-2 justify-center items-center">
{/* Tombol Prev */}
<button <button
onClick={() => onClick={() =>
setCategoryPage((prev) => Math.max(prev - 1, 1)) setCategoryPage((prev) => Math.max(prev - 1, 1))
@ -648,7 +648,6 @@ const FilterPage = () => {
</svg> </svg>
</button> </button>
{/* Nomor Halaman */}
{Array.from({ length: categoryTotalPages }, (_, i) => ( {Array.from({ length: categoryTotalPages }, (_, i) => (
<button <button
key={i} key={i}
@ -663,7 +662,6 @@ const FilterPage = () => {
</button> </button>
))} ))}
{/* Tombol Next */}
<button <button
onClick={() => onClick={() =>
setCategoryPage((prev) => setCategoryPage((prev) =>
@ -685,7 +683,7 @@ const FilterPage = () => {
/> />
</svg> </svg>
</button> </button>
</div> </div> */}
</ul> </ul>
</div> </div>
{/* Garis */} {/* Garis */}

View File

@ -610,8 +610,7 @@ const FilterPage = () => {
</label> </label>
</li> </li>
))} ))}
<div className="mt-4 flex gap-2 justify-center items-center"> {/* <div className="mt-4 flex gap-2 justify-center items-center">
{/* Tombol Prev */}
<button <button
onClick={() => onClick={() =>
setCategoryPage((prev) => Math.max(prev - 1, 1)) setCategoryPage((prev) => Math.max(prev - 1, 1))
@ -632,7 +631,6 @@ const FilterPage = () => {
</svg> </svg>
</button> </button>
{/* Nomor Halaman */}
{Array.from({ length: categoryTotalPages }, (_, i) => ( {Array.from({ length: categoryTotalPages }, (_, i) => (
<button <button
key={i} key={i}
@ -645,7 +643,6 @@ const FilterPage = () => {
</button> </button>
))} ))}
{/* Tombol Next */}
<button <button
onClick={() => onClick={() =>
setCategoryPage((prev) => setCategoryPage((prev) =>
@ -667,7 +664,7 @@ const FilterPage = () => {
/> />
</svg> </svg>
</button> </button>
</div> </div> */}
</ul> </ul>
</div> </div>
{/* Garis */} {/* Garis */}

View File

@ -106,25 +106,21 @@ const CustomEditor = dynamic(
export default function FormVideoUpdate() { export default function FormVideoUpdate() {
const MySwal = withReactContent(Swal); const MySwal = withReactContent(Swal);
const router = useRouter(); const router = useRouter();
const { id } = useParams() as { id: string }; const { id } = useParams() as { id: string };
console.log(id); console.log(id);
const editor = useRef(null); const editor = useRef(null);
type VideoSchema = z.infer<typeof videoSchema>; type VideoSchema = z.infer<typeof videoSchema>;
let progressInfo: any = []; let progressInfo: any = [];
let counterUpdateProgress = 0; let counterUpdateProgress = 0;
const [progressList, setProgressList] = useState<any>([]); const [progressList, setProgressList] = useState<any>([]);
let uploadPersen = 0; let uploadPersen = 0;
const [isStartUpload, setIsStartUpload] = useState(false); const [isStartUpload, setIsStartUpload] = useState(false);
const [counterProgress, setCounterProgress] = useState(0); const [counterProgress, setCounterProgress] = useState(0);
const t = useTranslations("Form"); const t = useTranslations("Form");
const [selectedFiles, setSelectedFiles] = useState<File[]>([]); const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
const taskId = Cookies.get("taskId"); const taskId = Cookies.get("taskId");
const scheduleId = Cookies.get("scheduleId"); const scheduleId = Cookies.get("scheduleId");
const scheduleType = Cookies.get("scheduleType"); const scheduleType = Cookies.get("scheduleType");
const [categories, setCategories] = useState<Category[]>([]); const [categories, setCategories] = useState<Category[]>([]);
const [selectedCategory, setSelectedCategory] = useState<any>(); const [selectedCategory, setSelectedCategory] = useState<any>();
const [tags, setTags] = useState<any[]>([]); const [tags, setTags] = useState<any[]>([]);
@ -133,7 +129,6 @@ export default function FormVideoUpdate() {
const [selectedPublishers, setSelectedPublishers] = useState<number[]>([]); const [selectedPublishers, setSelectedPublishers] = useState<number[]>([]);
const [detailVideo, setDetailVideo] = useState<any>([]); const [detailVideo, setDetailVideo] = useState<any>([]);
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null); const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
const [files, setFiles] = useState<FileWithPreview[]>([]); const [files, setFiles] = useState<FileWithPreview[]>([]);
const [selectedTarget, setSelectedTarget] = useState(""); const [selectedTarget, setSelectedTarget] = useState("");
const [unitSelection, setUnitSelection] = useState({ const [unitSelection, setUnitSelection] = useState({
@ -609,7 +604,7 @@ export default function FormVideoUpdate() {
const fileList = files.map((file: any) => ( const fileList = files.map((file: any) => (
<div <div
key={file.id} // Gunakan ID file sebagai key key={file.id}
className="flex justify-between border px-3.5 py-3 my-6 rounded-md" className="flex justify-between border px-3.5 py-3 my-6 rounded-md"
> >
<div className="flex gap-3 items-center"> <div className="flex gap-3 items-center">
@ -728,7 +723,9 @@ export default function FormVideoUpdate() {
<div className="flex flex-col lg:flex-row gap-10"> <div className="flex flex-col lg:flex-row gap-10">
<Card className="w-full lg:w-8/12"> <Card className="w-full lg:w-8/12">
<div className="px-6 py-6"> <div className="px-6 py-6">
<p className="text-lg font-semibold mb-3">{t("form-video", { defaultValue: "Form Video" })}</p> <p className="text-lg font-semibold mb-3">
{t("form-video", { defaultValue: "Form Video" })}
</p>
<div className="gap-5 mb-5"> <div className="gap-5 mb-5">
{/* Input Title */} {/* Input Title */}
<div className="space-y-2 py-3"> <div className="space-y-2 py-3">
@ -767,7 +764,11 @@ export default function FormVideoUpdate() {
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{/* Show the category from details if it doesn't exist in categories list */} {/* Show the category from details if it doesn't exist in categories list */}
{detail && !categories.find(cat => String(cat.id) === String(detail.category.id)) && ( {detail &&
!categories.find(
(cat) =>
String(cat.id) === String(detail.category.id)
) && (
<SelectItem <SelectItem
key={String(detail.category.id)} key={String(detail.category.id)}
value={String(detail.category.id)} value={String(detail.category.id)}
@ -789,7 +790,9 @@ export default function FormVideoUpdate() {
</div> </div>
<div className="py-3 space-y-2"> <div className="py-3 space-y-2">
<Label>{t("description", { defaultValue: "Description" })}</Label> <Label>
{t("description", { defaultValue: "Description" })}
</Label>
<Controller <Controller
control={control} control={control}
name="description" name="description"
@ -804,7 +807,9 @@ export default function FormVideoUpdate() {
)} )}
</div> </div>
<div className="py-3 space-y-2"> <div className="py-3 space-y-2">
<Label>{t("select-file", { defaultValue: "Select File" })}</Label> <Label>
{t("select-file", { defaultValue: "Select File" })}
</Label>
{/* <Input {/* <Input
id="fileInput" id="fileInput"
type="file" type="file"
@ -820,7 +825,9 @@ export default function FormVideoUpdate() {
{t("drag-file", { defaultValue: "Drag File" })} {t("drag-file", { defaultValue: "Drag File" })}
</h4> </h4>
<div className=" text-xs text-muted-foreground"> <div className=" text-xs text-muted-foreground">
{t("upload-file-video-max", { defaultValue: "Upload File Video Max" })} {t("upload-file-video-max", {
defaultValue: "Upload File Video Max",
})}
</div> </div>
</div> </div>
</div> </div>
@ -829,7 +836,9 @@ export default function FormVideoUpdate() {
<div>{fileList}</div> <div>{fileList}</div>
<div className=" flex justify-between gap-2"> <div className=" flex justify-between gap-2">
<div className="flex flex-row items-center gap-3 py-3"> <div className="flex flex-row items-center gap-3 py-3">
<Label>{t("watermark", { defaultValue: "Watermark" })}</Label> <Label>
{t("watermark", { defaultValue: "Watermark" })}
</Label>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Switch defaultChecked color="primary" id="c2" /> <Switch defaultChecked color="primary" id="c2" />
</div> </div>
@ -869,7 +878,9 @@ export default function FormVideoUpdate() {
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-blue-500 text-sm" className="text-blue-500 text-sm"
> >
{t("view-file", { defaultValue: "View File" })} {t("view-file", {
defaultValue: "View File",
})}
</a> </a>
</div> </div>
<div> <div>
@ -887,7 +898,9 @@ export default function FormVideoUpdate() {
} }
className="form-checkbox" className="form-checkbox"
/> />
<span>{t("all", { defaultValue: "All" })}</span> <span>
{t("all", { defaultValue: "All" })}
</span>
</Label> </Label>
</div> </div>
<div> <div>
@ -980,7 +993,7 @@ export default function FormVideoUpdate() {
)} )}
</div> </div>
</div> </div>
<div className="mt-3 px-3 space-y-2"> {/* <div className="mt-3 px-3 space-y-2">
<Label>{t("preview", { defaultValue: "Preview" })}</Label> <Label>{t("preview", { defaultValue: "Preview" })}</Label>
<Card className="mt-2"> <Card className="mt-2">
<img <img
@ -989,7 +1002,39 @@ export default function FormVideoUpdate() {
className="w-full h-auto rounded" className="w-full h-auto rounded"
/> />
</Card> </Card>
</div> */}
<div className="mt-3 px-3 space-y-2">
<Label>{t("preview", { defaultValue: "Preview" })}</Label>
<Input
type="file"
accept="image/*"
onChange={(e) => {
const file = e.target.files?.[0];
if (file) {
setSelectedFiles([file]);
}
}}
className="dark:border dark:border-gray-500 dark:rounded-lg"
/>
{selectedFiles.length > 0 ? (
<Card className="mt-2">
<img
src={URL.createObjectURL(selectedFiles[0])}
alt="Thumbnail Baru"
className="w-full h-auto rounded"
/>
</Card>
) : (
<Card className="mt-2">
<img
src={detail?.thumbnailLink}
alt="Thumbnail Lama"
className="w-full h-auto rounded"
/>
</Card>
)}
</div> </div>
<div className="px-3 py-3"> <div className="px-3 py-3">
<div className="space-y-2"> <div className="space-y-2">
<Label>{t("tags", { defaultValue: "Tags" })}</Label> <Label>{t("tags", { defaultValue: "Tags" })}</Label>
@ -1027,7 +1072,9 @@ export default function FormVideoUpdate() {
</div> </div>
<div className="px-3 py-3"> <div className="px-3 py-3">
<div className="flex flex-col gap-6 space-y-2"> <div className="flex flex-col gap-6 space-y-2">
<Label>{t("publish-target", { defaultValue: "Publish Target" })}</Label> <Label>
{t("publish-target", { defaultValue: "Publish Target" })}
</Label>
{options.map((option: Option) => ( {options.map((option: Option) => (
<div key={option.id} className="flex gap-2 items-center"> <div key={option.id} className="flex gap-2 items-center">
<Checkbox <Checkbox
@ -1047,7 +1094,9 @@ export default function FormVideoUpdate() {
</div> </div>
<div className="px-3 py-3 flex flex-row items-center text-blue-500 gap-2 text-sm"> <div className="px-3 py-3 flex flex-row items-center text-blue-500 gap-2 text-sm">
<MailIcon /> <MailIcon />
<p className="">{t("suggestion-box", { defaultValue: "Suggestion Box" })} (0)</p> <p className="">
{t("suggestion-box", { defaultValue: "Suggestion Box" })} (0)
</p>
</div> </div>
<div className="px-3 py-3"> <div className="px-3 py-3">
<p>{t("information", { defaultValue: "Information" })}:</p> <p>{t("information", { defaultValue: "Information" })}:</p>

View File

@ -145,7 +145,7 @@ export default function FilterAudioComponent(props: {
<div className="flex flex-row gap-6"> <div className="flex flex-row gap-6">
<Link <Link
href={`/audio/detail/${audio?.slug}`} href={`/audio/detail/${audio?.slug}`}
className="flex flex-col sm:flex-row items-center bg-white dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full" className="flex flex-col sm:flex-row items-center bg-white dark:bg-gray-800 cursor-pointer shadow- rounded-lg p-2 gap-4 w-full"
> >
<div className="flex items-center justify-center bg-red-500 text-white rounded-lg w-16 h-8 lg:h-16"> <div className="flex items-center justify-center bg-red-500 text-white rounded-lg w-16 h-8 lg:h-16">
<svg <svg
@ -165,9 +165,9 @@ export default function FilterAudioComponent(props: {
<div className="flex flex-col flex-1"> <div className="flex flex-col flex-1">
<div className="text-gray-500 dark:text-gray-400 flex flex-row text-sm"> <div className="text-gray-500 dark:text-gray-400 flex flex-row text-sm">
{formatDateToIndonesian(new Date(audio?.createdAt))}{" "} {formatDateToIndonesian(new Date(audio?.createdAt))}{" "}
{audio?.timezone ? audio?.timezone : "WIB"} |{" "} {audio?.timezone ? audio?.timezone : "WIB"} | &nbsp;
<Icon icon="formkit:eye" width="15" height="15" />{" "} <Icon icon="formkit:eye" width="15" height="15" />
{audio?.clickCount}{" "} &nbsp;{audio?.clickCount}{" "}
</div> </div>
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm h-5 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible"> <div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm h-5 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible">
{audio?.title} {audio?.title}
@ -178,8 +178,8 @@ export default function FilterAudioComponent(props: {
</CarouselItem> </CarouselItem>
))} ))}
</CarouselContent> </CarouselContent>
<CarouselPrevious /> <CarouselPrevious className="-ml-0" />
<CarouselNext /> <CarouselNext className="-mr-0" />
</Carousel> </Carousel>
</div> </div>
) : ( ) : (

View File

@ -192,8 +192,8 @@ export default function FilterDocumentComponent(props: {
</CarouselItem> </CarouselItem>
))} ))}
</CarouselContent> </CarouselContent>
<CarouselPrevious /> <CarouselPrevious className="-ml-0" />
<CarouselNext /> <CarouselNext className="-mr-0" />
</Carousel> </Carousel>
</div> </div>
) : ( ) : (

View File

@ -164,8 +164,8 @@ export default function FilterImageComponent(props: {
</CarouselItem> </CarouselItem>
))} ))}
</CarouselContent> </CarouselContent>
<CarouselPrevious /> <CarouselPrevious className="-ml-0" />
<CarouselNext /> <CarouselNext className="-mr-0" />
</Carousel> </Carousel>
</div> </div>
) : ( ) : (

View File

@ -165,8 +165,8 @@ export default function FilterVideoComponent(props: {
</CarouselItem> </CarouselItem>
))} ))}
</CarouselContent> </CarouselContent>
<CarouselPrevious /> <CarouselPrevious className="-ml-0" />
<CarouselNext /> <CarouselNext className="-mr-0" />
</Carousel> </Carousel>
</div> </div>
) : ( ) : (

View File

@ -1,6 +1,5 @@
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import router from "next/router";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Icon } from "@iconify/react/dist/iconify.js"; import { Icon } from "@iconify/react/dist/iconify.js";
import { import {
@ -13,7 +12,6 @@ import {
} from "../ui/select"; } from "../ui/select";
import Image from "next/image"; import Image from "next/image";
import { getHeroData } from "@/service/landing/landing"; import { getHeroData } from "@/service/landing/landing";
import { title } from "process";
import { htmlToString } from "@/utils/globals"; import { htmlToString } from "@/utils/globals";
import { Link, useRouter } from "@/i18n/routing"; import { Link, useRouter } from "@/i18n/routing";
import { Button } from "../ui/button"; import { Button } from "../ui/button";

View File

@ -298,7 +298,7 @@ const DetailAudio = () => {
async function shareToEmail() { async function shareToEmail() {
if (Number(userRoleId) < 1 || userRoleId == undefined) { if (Number(userRoleId) < 1 || userRoleId == undefined) {
router.push("/auth/login"); router.push("/auth");
} else { } else {
const data = { const data = {
mediaUploadId: id?.split("-")?.[0], mediaUploadId: id?.split("-")?.[0],

View File

@ -641,6 +641,9 @@
"timeTable1": "TIMETABLE /" "timeTable1": "TIMETABLE /"
}, },
"FilterPage": { "FilterPage": {
"downloadableContent": "Downloadable Content",
"content": "Content",
"allContent":"All Content",
"image": "Image", "image": "Image",
"video": "Video", "video": "Video",
"text": "Text", "text": "Text",
@ -653,10 +656,10 @@
"searchTitle": "Find Title...", "searchTitle": "Find Title...",
"monthYear": "Month and Year", "monthYear": "Month and Year",
"thereIs": "There is", "thereIs": "There is",
"downloadableImage": "downloadable image", "downloadableImage": "Downloadable image",
"downloadableVideo": "downloadable video", "downloadableVideo": "Downloadable video",
"downloadableText": "downloadable text", "downloadableText": "Downloadable text",
"downloadableAudio": "downloadable audio", "downloadableAudio": "Downloadable audio",
"date": "Date", "date": "Date",
"selectYear": "Select Month and Year", "selectYear": "Select Month and Year",
"selectDate": "Select Date", "selectDate": "Select Date",

View File

@ -642,6 +642,9 @@
"timeTable1": "JADWAL /" "timeTable1": "JADWAL /"
}, },
"FilterPage": { "FilterPage": {
"content": "Konten",
"downloadableContent": "artikel berisi konten yang dapat di unduh",
"allContent": "Semua Konten",
"image": "Foto", "image": "Foto",
"video": "Audio Visual", "video": "Audio Visual",
"text": "Teks", "text": "Teks",