[QUDO-134,QUDO-133,QUDO-130] feat:ui iklan, ui kalender, change API AI content rewrite

This commit is contained in:
Anang Yusman 2025-06-03 09:01:25 +08:00
commit 20753e53b1
45 changed files with 2666 additions and 2466 deletions

View File

@ -13,6 +13,12 @@ import LatestContentKaltara from "@/components/landing-page/landing-polda-kaltar
import ContactUsKaltara from "@/components/landing-page/landing-polda-kaltara/contact-us-kaltara";
import NewsTickerKaltara from "../../tbnews/[polda_name]/components/news-tickers-kaltara";
import ContentCategoryKaltara from "@/components/landing-page/landing-polda-kaltara/content-category-kaltara";
import HeroNew from "@/components/landing-page/hero-new";
import Navbar from "@/components/landing-page/navbar";
import SearchSection from "@/components/landing-page/search-section";
import Footer from "@/components/landing-page/footer";
import SearchSectionPolda from "@/components/landing-page/search-section-polda";
import HeroNewPolda from "@/components/landing-page/hero-new-polda";
const page = () => {
const params = useParams();
@ -30,12 +36,19 @@ const page = () => {
<NewsTickerKaltara />
</div>
) : (
// <div>
// {/* <HeaderBanner /> */}
// <HeroNew group="polda" />
// <WelcomePolda />
// <NewContent group="polda" type="latest" />
// <NewContent group="polda" type="popular" />
// <ContentCategory type="" group="polda" />
// </div>
<div>
<HeaderBanner />
<WelcomePolda />
<NewContent group="polda" type="latest" />
<NewContent group="polda" type="popular" />
<ContentCategory type="" group="polda" />
<HeroNewPolda />
<div className="flex-1 ">
<SearchSectionPolda />
</div>
</div>
);
};

View File

@ -1,20 +1,29 @@
"use client";
import ContentCategory from "@/components/landing-page/content-category";
import Footer from "@/components/landing-page/footer";
import HeaderBannerSatker from "@/components/landing-page/header-banner-satker";
import HeroNewSatker from "@/components/landing-page/hero-new-satker";
import NewContent from "@/components/landing-page/new-content";
import SearchSectionSatker from "@/components/landing-page/search-section-satker";
import WelcomeSatker from "@/components/landing-page/welcome-satker";
import React from "react";
const page = () => {
return (
// <div>
// <HeaderBannerSatker />
// <WelcomeSatker />
// <NewContent group="satker" type="latest" />
// <NewContent group="satker" type="popular" />
// <ContentCategory group="satker" type="latest" />
// </div>
<div>
<HeaderBannerSatker />
<WelcomeSatker />
<NewContent group="satker" type="latest" />
<NewContent group="satker" type="popular" />
<ContentCategory group="satker" type="latest" />
</div>
<HeroNewSatker />
<div className="flex-1 ">
<SearchSectionSatker />
</div>
</div>
);
};

View File

@ -1,11 +1,6 @@
"use client";
import SearchSection from "@/components/landing-page/search-section";
import NewContent from "@/components/landing-page/new-content";
import PopularContent from "@/components/landing-page/popular-content";
import ContentCategory from "@/components/landing-page/content-category";
import Coverage from "@/components/landing-page/coverage";
import Hero from "@/components/landing-page/hero";
import Footer from "@/components/landing-page/footer";
import Navbar from "@/components/landing-page/navbar";
import { ReactLenis } from "@studio-freight/react-lenis";
@ -16,7 +11,7 @@ const Home = ({ params: { locale } }: { params: { locale: string } }) => {
return (
<MountedProvider isProtected={false}>
<ReactLenis root>
<div className="">
<div>
<Navbar />
<HeroNew group="mabes" />
<div className="flex-1 ">

View File

@ -64,13 +64,11 @@ export function CalendarPolriAdd() {
</div>
</div>
{/* Nama Iklan */}
<div>
<p className="font-medium">Nama Acara</p>
<Input placeholder="Masukkan nama acara" />
</div>
{/* Upload */}
<div className="border-2 border-dashed rounded-md p-4 flex flex-col items-center justify-center text-center text-sm text-muted-foreground">
<svg
className="w-6 h-6 mb-2 text-blue-500"
@ -94,13 +92,11 @@ export function CalendarPolriAdd() {
<div className="text-xs mt-1">Max 10 MB files are allowed</div>
</div>
{/* Deskripsi */}
<div>
<p className="font-medium">Deskripsi</p>
<Textarea placeholder="Masukkan deskripsi acara" rows={4} />
</div>
{/* Button Submit */}
<div className="text-right">
<Button
type="submit"

View File

@ -32,7 +32,6 @@ export function TambahIklanModal() {
</DialogHeader>
<div className="space-y-4">
{/* Target Area */}
<div>
<p className="font-medium">Target Area</p>
<div className="flex flex-wrap gap-4 mt-2">
@ -47,7 +46,6 @@ export function TambahIklanModal() {
</div>
</div>
{/* Publish Area */}
<div>
<p className="font-medium">Publish Area</p>
<div className="flex flex-wrap gap-4 mt-2">
@ -62,13 +60,11 @@ export function TambahIklanModal() {
</div>
</div>
{/* Nama Iklan */}
<div>
<p className="font-medium">Nama Iklan</p>
<Input placeholder="Masukkan nama iklan" />
</div>
{/* Upload */}
<div className="border-2 border-dashed rounded-md p-4 flex flex-col items-center justify-center text-center text-sm text-muted-foreground">
<svg
className="w-6 h-6 mb-2 text-blue-500"
@ -92,13 +88,11 @@ export function TambahIklanModal() {
<div className="text-xs mt-1">Max 10 MB files are allowed</div>
</div>
{/* Deskripsi */}
<div>
<p className="font-medium">Deskripsi</p>
<Textarea placeholder="Masukkan deskripsi iklan" rows={4} />
</div>
{/* Button Submit */}
<div className="text-right">
<Button
type="submit"

View File

@ -1,15 +1,7 @@
"use client";
import React, { useEffect, useState } from "react";
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import Image from "next/image";
import Coverage from "./coverage";
import Division from "./division";
@ -30,33 +22,20 @@ const AreaCoverageWorkUnits = () => {
};
}, [openPolda, openSatker]);
return (
<div className="mx-auto px-4 lg:px-8 py-6">
<div className="mx-auto px-4 lg:px-0 py-6">
<h2 className="text-start text-lg md:text-xl font-bold text-[#bb3523] border-b-2 border-[#bb3523] mb-4 uppercase">
Liputan <span className="text-[#bb3523]">Wilayah</span> &{" "}
<span className="text-[#bb3523]">Satker</span>
Liputan <span className="text-[#bb3523]">Wilayah</span> & <span className="text-[#bb3523]">Satker</span>
</h2>
<div className="flex flex-col justify-center lg:flex-row gap-8 ">
{/* POLDA */}
<Dialog open={openPolda} onOpenChange={setOpenPolda}>
<DialogTrigger asChild>
<button
onClick={() => setOpenPolda(true)}
className="flex flex-col gap-2 justify-center items-center shadow-lg group rounded-xl py-5 px-24 border-2 border-transparent hover:border-[#bb3523] transition-all duration-300"
>
<Image
width={1920}
height={1080}
alt="indo"
src="/assets/indo.png"
className="h-32 w-32 group-hover:scale-110 group-hover:border-[#bb3523] "
/>
<button onClick={() => setOpenPolda(true)} className="flex flex-col gap-2 justify-center items-center shadow-lg group rounded-xl py-5 w-full border-2 border-transparent hover:border-[#bb3523] transition-all duration-300">
<Image width={1920} height={1080} alt="indo" src="/assets/indo.png" className="h-32 w-32 group-hover:scale-110 group-hover:border-[#bb3523] " />
<p className="text-base font-bold">Polda Jajaran</p>
</button>
</DialogTrigger>
<DialogContent
size="md"
className="max-h-[90vh] overflow-hidden flex flex-col "
>
<DialogContent size="md" className="max-h-[90vh] overflow-hidden flex flex-col ">
<DialogHeader className="flex flex-col justify-center">
<DialogTitle>
<p className="text-center">Polda Jajaran</p>
@ -78,15 +57,11 @@ const AreaCoverageWorkUnits = () => {
{/* SATKER */}
<Dialog open={openSatker} onOpenChange={setOpenSatker}>
<DialogTrigger className="flex flex-col gap-2 justify-center items-center shadow-lg group rounded-xl py-5 px-24 border-2 border-transparent hover:border-[#bb3523] transition-all duration-300">
<Image
width={1920}
height={1080}
alt="polri"
src="/assets/logo-polri.png"
className="h-32 w-32 group-hover:scale-110 group-hover:border-[#bb3523] transition-transform duration-300"
/>
<p className="text-base font-bold">Satuan Kerja Polri</p>
<DialogTrigger asChild>
<button className="flex flex-col gap-2 justify-center items-center shadow-lg group rounded-xl py-5 w-full border-2 border-transparent hover:border-[#bb3523] transition-all duration-300">
<Image width={1920} height={1080} alt="polri" src="/assets/logo-polri.png" className="h-32 w-32 group-hover:scale-110 group-hover:border-[#bb3523] transition-transform duration-300" />
<p className="text-base font-bold">Satuan Kerja Polri</p>
</button>
</DialogTrigger>
<DialogContent size="md">
<DialogHeader className="flex flex-col justify-center">

View File

@ -1,20 +1,11 @@
import {
getCategoryData,
getPublicCategoryData,
} from "@/service/landing/landing";
import { getCategoryData, getPublicCategoryData } from "@/service/landing/landing";
import React, { useEffect, useState } from "react";
import { Reveal } from "./Reveal";
import { useTranslations } from "next-intl";
import { usePathname } from "next/navigation";
import { useParams } from "next/navigation";
import Image from "next/image";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "../ui/carousel";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "../ui/carousel";
import { useRouter } from "@/i18n/routing";
import { Button } from "../ui/button";
@ -28,26 +19,14 @@ const ContentCategory = (props: { group?: string; type: string }) => {
const satkerName = params?.satker_name;
const router = useRouter();
let prefixPath = poldaName
? `/polda/${poldaName}`
: satkerName
? `/satker/${satkerName}`
: "/";
let prefixPath = poldaName ? `/polda/${poldaName}` : satkerName ? `/satker/${satkerName}` : "/";
useEffect(() => {
initFetch();
}, []);
const initFetch = async () => {
const response = await getPublicCategoryData(
props.group == "mabes"
? ""
: props.group == "polda" && poldaName && String(poldaName)?.length > 1
? poldaName
: props.group == "satker" &&
satkerName &&
String(satkerName)?.length > 1
? "satker-" + satkerName
: "",
props.group == "mabes" ? "" : props.group == "polda" && poldaName && String(poldaName)?.length > 1 ? poldaName : props.group == "satker" && satkerName && String(satkerName)?.length > 1 ? "satker-" + satkerName : "",
"",
locale == "en" ? true : false
);
@ -73,78 +52,55 @@ const ContentCategory = (props: { group?: string; type: string }) => {
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
</svg>`;
const toBase64 = (str: string) =>
typeof window === "undefined"
? Buffer.from(str).toString("base64")
: window.btoa(str);
const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str));
return (
<div className="px-4 py-10">
<div className="px-4 lg:px-0 py-10">
<Reveal>
<div className="flex flex-col p-4">
<div className="flex flex-col">
<h2 className="text-start text-lg md:text-xl font-bold text-[#bb3523] border-b-2 border-[#bb3523] mb-4 uppercase">
{pathname?.split("/")[1] == "in" ? (
<>
<span className="text-[#bb3523] dark:text-white">
{t("category")}&nbsp;
</span>
<span className="text-[#bb3523] dark:text-white">{t("category")}&nbsp;</span>
{t("content")}
</>
) : (
<>
<span className="text-[#bb3523] dark:text-white">
{t("content")}&nbsp;
</span>
<span className="text-[#bb3523] dark:text-white">{t("content")}&nbsp;</span>
{t("category")}
</>
)}
</h2>
<div className="grid grid-cols-2 md:grid-cols-2 lg:grid-cols-4 gap-4">
{(seeAllValue ? categories : categories?.slice(0, 4))?.map(
(category: any) => (
<div key={category?.id}>
<div
onClick={() =>
router.push(
`${prefixPath}all/filter?category=${category?.id}`
)
}
className="cursor-pointer relative group rounded-md overflow-hidden shadow-md hover:shadow-lg block"
>
{/* Gambar */}
<Image
placeholder={`data:image/svg+xml;base64,${toBase64(
shimmer(700, 475)
)}`}
alt="category"
width={2560}
height={1440}
src={category?.thumbnailLink}
className="w-full lg:h-[250px] h-40 object-cover group-hover:scale-110 transition-transform duration-300"
/>
{(seeAllValue ? categories : categories?.slice(0, 8))?.map((category: any) => (
<div key={category?.id}>
<div onClick={() => router.push(`${prefixPath}all/filter?category=${category?.id}`)} className="cursor-pointer relative group rounded-md overflow-hidden shadow-md hover:shadow-lg block">
{/* Gambar */}
<Image
placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`}
alt="category"
width={2560}
height={1440}
src={category?.thumbnailLink}
className="w-full lg:h-[300px] h-40 object-cover group-hover:scale-110 transition-transform duration-300"
/>
{/* Overlay gelap */}
<div className="absolute inset-0 bg-black bg-opacity-25 group-hover:bg-opacity-35 transition-all duration-300 rounded-md"></div>
{/* Overlay gelap */}
<div className="absolute inset-0 bg-black bg-opacity-50 group-hover:bg-opacity-35 transition-all duration-300 rounded-md"></div>
{/* Judul */}
<div className="absolute bottom-5 left-0 right-16 bg-transparent backdrop-blur-md text-white p-4 border-l-2 border-[#bb3523] z-10 group-hover:scale-x-150 origin-left">
<h3 className="text-sm font-semibold truncate">
{category?.name}
</h3>
</div>
{/* Judul */}
<div className="absolute bottom-5 left-1/2 transform -translate-x-1/2 text-white">
<h3 className="text-sm font-semibold text-center">{category?.name}</h3>
</div>
</div>
)
)}
</div>
))}
</div>
{/* Tombol See More / See Less */}
{categories?.length > 8 && (
<div className="flex items-center flex-row justify-center mt-6">
<Button
onClick={() => setSeeAllValue(!seeAllValue)}
className="bg-white hover:bg-[#bb3523] text-[#bb3523] hover:text-white border-2 border-[#bb3523]"
>
<Button onClick={() => setSeeAllValue(!seeAllValue)} className="bg-white hover:bg-[#bb3523] text-[#bb3523] hover:text-white border-2 border-[#bb3523]">
{seeAllValue ? t("seeLess") : t("seeMore")}
</Button>
</div>

View File

@ -8,100 +8,64 @@ import { usePathname } from "next/navigation";
import Image from "next/image";
const regions = [
{ name: "Polda Aceh", slug: "aceh", logo: "/logo/polda/polda-aceh.png" },
{ name: "Polda Bali", slug: "bali", logo: "/logo/polda/polda-bali.png" },
{
name: "Polda Metro Jaya",
slug: "metro-jaya",
logo: "/logo/polda/polda-metro.png",
},
{
name: "Polda Jawa Barat",
slug: "jawa-barat",
logo: "/logo/polda/polda-jawabarat.png",
name: "Polda Bangka Belitung",
slug: "bangka-belitung",
logo: "/logo/polda/polda-bangkabelitung.png",
},
{
name: "Polda Banten",
slug: "banten",
logo: "/logo/polda/polda-banten.png",
},
{
name: "Polda Bengkulu",
slug: "bengkulu",
logo: "/logo/polda/polda-bengkulu.png",
},
{
name: "Polda DIY",
slug: "di-yogyakarta",
logo: "/logo/polda/polda-jogja.png",
},
{
name: "Polda Gorontalo",
slug: "gorontalo",
logo: "/logo/polda/polda-gorontalo.png",
},
{ name: "Polda Jambi", slug: "jambi", logo: "/logo/polda/polda-jambi.png" },
{
name: "Polda Jawa Barat",
slug: "jawa-barat",
logo: "/logo/polda/polda-jawabarat.png",
},
{
name: "Polda Jawa Tengah",
slug: "jawa-tengah",
logo: "/logo/polda/polda-jawatengah.png",
},
{
name: "Polda D.I Yogyakarta",
slug: "di-yogyakarta",
logo: "/logo/polda/polda-jogja.png",
},
{
name: "Polda Jawa Timur",
slug: "jawa-timur",
logo: "/logo/polda/polda-jawatimur.png",
},
{ name: "Polda Aceh", slug: "aceh", logo: "/logo/polda/polda-aceh.png" },
{
name: "Polda Sumatera Utara",
slug: "sumatera-utara",
logo: "/logo/polda/polda-sumut.png",
},
{
name: "Polda Sumatera Barat",
slug: "sumatera-barat",
logo: "/logo/polda/polda-sumatera-barat.png",
},
{ name: "Polda Riau", slug: "riau", logo: "/logo/polda/polda-riau.png" },
{
name: "Polda Kep. Riau",
slug: "kepulauan-riau",
logo: "/logo/polda/polda-kepri.png",
},
{ name: "Polda Jambi", slug: "jambi", logo: "/logo/polda/polda-jambi.png" },
{
name: "Polda Sumatera Selatan",
slug: "sumatera-selatan",
logo: "/logo/polda/polda-sumsel.png",
},
{
name: "Polda Kep. Bangka Belitung",
slug: "bangka-belitung",
logo: "/logo/polda/polda-bangkabelitung.png",
},
{
name: "Polda Bengkulu",
slug: "bengkulu",
logo: "/logo/polda/polda-bengkulu.png",
},
{
name: "Polda Lampung",
slug: "lampung",
logo: "/logo/polda/polda-lampung.png",
},
{
name: "Polda Nusa Tenggara Barat",
slug: "ntb",
logo: "/logo/polda/polda-ntb.png",
},
{
name: "Polda Nusa Tenggara Timur",
slug: "ntt",
logo: "/logo/polda/polda-ntt.png",
},
{ name: "Polda Bali", slug: "bali", logo: "/logo/polda/polda-bali.png" },
{
name: "Polda Kalimantan Barat",
slug: "kalimantan-barat",
logo: "/logo/polda/polda-kalbar.png",
},
{
name: "Polda Kalimantan Tengah",
slug: "kalimantan-tengah",
logo: "/logo/polda/polda-kalteng.png",
},
{
name: "Polda Kalimantan Selatan",
slug: "kalimantan-selatan",
logo: "/logo/polda/polda-kalsel.png",
},
{
name: "Polda Kalimantan Tengah",
slug: "kalimantan-tengah",
logo: "/logo/polda/polda-kalteng.png",
},
{
name: "Polda Kalimantan Timur",
slug: "kalimantan-timur",
@ -113,20 +77,47 @@ const regions = [
logo: "/logo/polda/polda-kaltara.png",
},
{
name: "Polda Sulawesi Tengah",
slug: "sulawesi-tengah",
logo: "/logo/polda/polda-sulawesi-tengah.png",
name: "Polda Kepulauan Riau",
slug: "kepulauan-riau",
logo: "/logo/polda/polda-kepri.png",
},
{
name: "Polda Sulawesi Utara",
slug: "sulawesi-utara",
logo: "/logo/polda/polda-sulawesi-utara.png",
name: "Polda Lampung",
slug: "lampung",
logo: "/logo/polda/polda-lampung.png",
},
{
name: "Polda Gorontalo",
slug: "gorontalo",
logo: "/logo/polda/polda-gorontalo.png",
name: "Polda Maluku",
slug: "maluku",
logo: "/logo/polda/polda-maluku.png",
},
{
name: "Polda Maluku Utara",
slug: "maluku-utara",
logo: "/logo/polda/polda-maluku-utara.png",
},
{
name: "Polda Metro Jaya",
slug: "metro-jaya",
logo: "/logo/polda/polda-metro.png",
},
{
name: "Polda NTB",
slug: "ntb",
logo: "/logo/polda/polda-ntb.png",
},
{
name: "Polda NTT",
slug: "ntt",
logo: "/logo/polda/polda-ntt.png",
},
{ name: "Polda Papua", slug: "papua", logo: "/logo/polda/polda-papua.png" },
{
name: "Polda Papua Barat",
slug: "papua-barat",
logo: "/logo/polda/polda-papua-barat.png",
},
{ name: "Polda Riau", slug: "riau", logo: "/logo/polda/polda-riau.png" },
{
name: "Polda Sulawesi Barat",
slug: "sulawesi-barat",
@ -137,54 +128,59 @@ const regions = [
slug: "sulawesi-selatan",
logo: "/logo/polda/polda-sulsel.png",
},
{
name: "Polda Sulawesi Tengah",
slug: "sulawesi-tengah",
logo: "/logo/polda/polda-sulawesi-tengah.png",
},
{
name: "Polda Sulawesi Tenggara",
slug: "sulawesi-tenggara",
logo: "/logo/polda/polda-sulawesi-tenggara.png",
},
{
name: "Polda Maluku Utara",
slug: "maluku-utara",
logo: "/logo/polda/polda-maluku-utara.png",
name: "Polda Sulawesi Utara",
slug: "sulawesi-utara",
logo: "/logo/polda/polda-sulawesi-utara.png",
},
{
name: "Polda Maluku",
slug: "maluku",
logo: "/logo/polda/polda-maluku.png",
name: "Polda Sumatera Barat",
slug: "sumatera-barat",
logo: "/logo/polda/polda-sumatera-barat.png",
},
{
name: "Polda Papua Barat",
slug: "papua-barat",
logo: "/logo/polda/polda-papua-barat.png",
},
{ name: "Polda Papua", slug: "papua", logo: "/logo/polda/polda-papua.png" },
{
name: "Satuan Kerja POLRI",
slug: "satker-polri",
logo: "/logo/satker/SATUAN-KERJA-POLRI.png",
name: "Polda Sumatera Selatan",
slug: "sumatera-selatan",
logo: "/logo/polda/polda-sumsel.png",
},
{
name: "Internasional",
slug: "internasional",
logo: "/assets/polda/internasional.png",
name: "Polda Sumatera Utara",
slug: "sumatera-utara",
logo: "/logo/polda/polda-sumut.png",
},
// {
// name: "Satuan Kerja POLRI",
// slug: "satker-polri",
// logo: "/logo/satker/SATUAN-KERJA-POLRI.png",
// },
// {
// name: "Internasional",
// slug: "internasional",
// logo: "/assets/polda/internasional.png",
// },
];
const Coverage: React.FC = () => {
const [seeAllValue, setSeeAllValue] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
const [filteredList, setFilteredList] = useState<typeof regions | undefined>(
regions
);
const [filteredList, setFilteredList] = useState<typeof regions | undefined>(regions);
const pathname = usePathname();
const t = useTranslations("LandingPage");
const handleSearch = () => {
const value = searchTerm.toLowerCase();
const filtered = regions.filter((polda) =>
polda.name.toLowerCase().includes(value)
);
const filtered = regions.filter((polda) => polda.name.toLowerCase().includes(value));
setFilteredList(filtered);
};
@ -202,32 +198,16 @@ const Coverage: React.FC = () => {
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
</svg>`;
const toBase64 = (str: string) =>
typeof window === "undefined"
? Buffer.from(str).toString("base64")
: window.btoa(str);
const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str));
return (
<div className="w-full">
<div className="max-h-[60vh] overflow-y-auto px-4">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 gap-6 px-4 max-h-[60vh]">
{filteredList?.map((region: any) => (
<Link
key={region.slug}
href={`/polda/${region.slug}`}
className="flex flex-col items-center text-center p-3 border rounded-lg shadow-md hover:shadow-lg transition-all"
>
<Link key={region.slug} href={`/polda/${region.slug}`} className="flex flex-col items-center text-center p-3 border rounded-lg shadow-md hover:shadow-lg transition-all">
<div className="mb-1 flex items-center justify-center">
<Image
placeholder={`data:image/svg+xml;base64,${toBase64(
shimmer(700, 475)
)}`}
width={1920}
height={1080}
src={region.logo}
alt={region.name}
className="w-14 h-14 object-contain"
/>
<Image placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`} width={1920} height={1080} src={region.logo} alt={region.name} className="w-14 h-14 object-contain" />
</div>
<p className="text-xs font-semibold">{region.name}</p>
</Link>

View File

@ -8,45 +8,55 @@ import { usePathname } from "next/navigation";
import Image from "next/image";
const regions = [
{ name: "SIBER", slug: "siber", logo: "/logo/satker/SIBER.png" },
{ name: "DIVKUM", slug: "divkum", logo: "/logo/satker/DIVKUM.png" },
{ name: "PUSKEU", slug: "puskeu", logo: "/logo/satker/PUSKEU.png" },
{ name: "YANMA", slug: "yanma", logo: "/logo/satker/YANMA.png" },
{ name: "SSDM", slug: "ssdm", logo: "/logo/satker/SSDM.png" },
{ name: "ITWASUM", slug: "itwasum", logo: "/logo/satker/ITWASUM.png" },
{ name: "STIK-PTIK", slug: "stik-ptik", logo: "/logo/satker/STIK-PTIK.png" },
{ name: "SATUAN KERJA POLRI", slug: "satuan-kerja-polri", logo: "/logo/satker/SATUAN-KERJA-POLRI.png" },
{ name: "BRIMOB", slug: "brimob", logo: "/logo/satker/BRIMOB.png" },
{ name: "DIV HUMAS", slug: "div-humas", logo: "/logo/satker/DIV-HUMAS.png" },
{ name: "PUSLITBANG", slug: "puslitbang", logo: "/logo/satker/PUSLITBANG.png" },
{ name: "BINMAS", slug: "binmas", logo: "/logo/satker/BINMAS.png" },
{ name: "DIV TIK", slug: "div-tik", logo: "/logo/satker/DIV-TIK.png" },
{ name: "SPRIPIM", slug: "spripim", logo: "/logo/satker/SPRIPIM.png" },
{ name: "DIVPROPRAM", slug: "divpropram", logo: "/logo/satker/DIVPROPAM.png" },
{ name: "KORPS SABHARA BAHARKAM", slug: "korps-sabhara-baharkam", logo: "/logo/satker/KORPS-SABHARA-BAHARKAM.png" },
{ name: "PUSDOKKES", slug: "pusdokkes", logo: "/logo/satker/PUSDOKKES.png" },
{ name: "BAHARKAM", slug: "baharkam", logo: "/logo/satker/BAHARKAM.png" },
{ name: "POLAIRUD", slug: "polairud", logo: "/logo/satker/POLAIRUD.png" },
{ name: "ITWASUM POLRI", slug: "itwasum", logo: "/logo/satker/ITWASUM.png" },
{ name: "BAINTELKAM POLRI", slug: "baintelkam", logo: "/logo/satker/BAINTELKAM.png" },
{ name: "BAHARKAM POLRI", slug: "baharkam", logo: "/logo/satker/BAHARKAM.png" },
{ name: "BARESKRIM POLRI", slug: "bareskrim", logo: "/logo/satker/BARESKRIM.png" },
{ name: "LEMDIKLAT POLRI", slug: "lemdiklat", logo: "/logo/satker/LEMDIKLAT.png" },
{ name: "KORBRIMOB POLRI", slug: "brimob", logo: "/logo/satker/BRIMOB.png" },
{ name: "STAMAOPS POLRI", slug: "sops", logo: "/logo/satker/SOPS.png" },
{ name: "STAMARENA POLRI", slug: "srena", logo: "/logo/satker/SRENA.png" },
{ name: "SSDM POLRI", slug: "ssdm", logo: "/logo/satker/SSDM.png" },
{ name: "SLOG POLRI", slug: "slog", logo: "/logo/satker/SLOG.png" },
{ name: "SAHLI KAPOLRI", slug: "sahli-kapolri", logo: "/logo/satker/STAFAHLI.png" },
{ name: "DIVPROPRAM POLRI", slug: "divpropram", logo: "/logo/satker/DIVPROPAM.png" },
{ name: "DIVKUM", slug: "divkum", logo: "/assets/satker/divkum.png" },
{ name: "DIVHUBINTER POLRI", slug: "divhubinter", logo: "/logo/satker/DIVHUBINTER.png" },
{ name: "DIVTIK POLRI", slug: "div-tik", logo: "/logo/satker/DIV-TIK.png" },
{ name: "KORLANTAS POLRI", slug: "korlantas", logo: "/logo/satker/KORLANTAS.png" },
{ name: "DENSUS 88 POLRI", slug: "densus-88", logo: "/logo/satker/DENSUS88.png" },
{ name: "PUSDOKKES POLRI", slug: "pusdokkes", logo: "/logo/satker/PUSDOKKES.png" },
{ name: "PUSLITBANG POLRI", slug: "puslitbang", logo: "/logo/satker/PUSLITBANG.png" },
{ name: "PUSKEU POLRI", slug: "puskeu", logo: "/logo/satker/PUSKEU.png" },
{ name: "PUSJARAH POLRI", slug: "pusjarah", logo: "/logo/satker/PUSJARAH.png" },
{ name: "SETUM POLRI", slug: "setum", logo: "/logo/satker/SETUM.png" },
{ name: "YANMA POLRI", slug: "yanma", logo: "/logo/satker/YANMA.png" },
{ name: "SPRIPIM POLRI", slug: "spripim", logo: "/logo/satker/SPRIPIM.png" },
{ name: "KORPOLAIRUD BAHARKAM POLRI", slug: "polairud", logo: "/logo/satker/POLAIRUD.png" },
{ name: "KORSABHARA BAHARKAM POLRI", slug: "korps-sabhara-baharkam", logo: "/logo/satker/KORPS-SABHARA-BAHARKAM.png" },
{ name: "KORBINMAS BAHARKAM POLRI", slug: "binmas", logo: "/logo/satker/BINMAS.png" },
{ name: "DITTIPIDUM BARESKRIM POLRI", slug: "dittipidum", logo: "/logo/satker/DITTIPIDUM.png" },
{ name: "DITTIPIDEKSUS BARESKRIM POLRI", slug: "dittipideksus", logo: "/logo/satker/DITTIPIDEKSUS.png" },
{ name: "DITTIPIDKOR BARESKRIM POLRI", slug: "dittipidkor", logo: "/logo/satker/DITTIPIDKOR.png" },
{ name: "DITTIPIDNARKOBA BARESKRIM POLRI", slug: "dittipidnarkoba", logo: "/logo/satker/DITTIPIDNARKOBA.png" },
{ name: "DITTIPIDTER BARESKRIM POLRI", slug: "dittipidter", logo: "/logo/satker/DITTIPIDTER.png" },
{ name: "DITTIPIDSIBER BARESKRIM POLRI", slug: "dittipidsiber", logo: "/logo/satker/DITTIPIDSIBER.png" },
{ name: "DIT PPA-PPO BARESKRIM POLRI", slug: "dit-ppa-ppo", logo: "/logo/satker/DITPPAPPO.png" },
{ name: "PUSLABFOR BARESKRIM POLRI", slug: "puslabfor", logo: "/assets/satker/puslabfor.png" },
{ name: "PUSIKNAS BARESKRIM POLRI", slug: "pusiknas", logo: "/logo/satker/PUSKINAS.png" },
{ name: "STIK LEMDIKLAT POLRI", slug: "stik-ptik", logo: "/logo/satker/STIK-PTIK.png" },
{ name: "AKPOL LEMDIKLAT POLRI", slug: "akpol", logo: "/logo/satker/AKPOL.png" },
{ name: "SESPIM LEMDIKLAT POLRI", slug: "sespim-polri", logo: "/logo/satker/SESPIM-POLRI.png" },
{ name: "SETUKPA LEMDIKLAT POLRI", slug: "setupa-polri", logo: "/assets/satker/setupa-polri.png" },
{ name: "SEPOLWAN LEMDIKLAT POLRI", slug: "sepolwan-polri", logo: "/assets/satker/sepolwan.png" },
{ name: "SEBASA LEMDIKLAT POLRI", slug: "sebasa-polri", logo: "/assets/satker/sebasa.png" },
{ name: "RUMKIT BHAYANGKARA TK I", slug: "rumkit-bhayangkara", logo: "/assets/satker/rumkit.png" },
{ name: "POLAIR", slug: "polair", logo: "/logo/satker/POLAIR.png" },
{ name: "POLUDARA", slug: "poludara", logo: "/logo/satker/POLUDARA.png" },
{ name: "LEMDIKLAT", slug: "lemdiklat", logo: "/logo/satker/LEMDIKLAT.png" },
{ name: "AKPOL", slug: "akpol", logo: "/logo/satker/AKPOL.png" },
{ name: "KORLANTAS", slug: "korlantas", logo: "/logo/satker/KORLANTAS.png" },
{ name: "PUSINAFIS", slug: "pusinafis", logo: "/logo/satker/PUSINAFIS.png" },
{ name: "PUSJARAH", slug: "pusjarah", logo: "/logo/satker/PUSJARAH.png" },
{ name: "PUSIKNAS", slug: "pusiknas", logo: "/logo/satker/PUSKINAS.png" },
{ name: "SLOG", slug: "slog", logo: "/logo/satker/SLOG.png" },
{ name: "BAINTELKAM", slug: "baintelkam", logo: "/logo/satker/BAINTELKAM.png" },
{ name: "BARESKRIM", slug: "bareskrim", logo: "/logo/satker/BARESKRIM.png" },
{ name: "DIVHUBINTER", slug: "divhubinter", logo: "/logo/satker/DIVHUBINTER.png" },
{ name: "SETUM", slug: "setum", logo: "/logo/satker/SETUM.png" },
{ name: "PUSLABFOR", slug: "puslabfor", logo: "/assets/satker/puslabfor.png" },
{ name: "DENSUS 88", slug: "densus-88", logo: "/logo/satker/DENSUS88.png" },
{ name: "SAHLI KAPOLRI", slug: "sahli-kapolri", logo: "/logo/satker/STAFAHLI.png" },
{ name: "SOPS", slug: "sops", logo: "/logo/satker/SOPS.png" },
{ name: "SRENA", slug: "srena", logo: "/logo/satker/SRENA.png" },
{ name: "SESPIM POLRI", slug: "sespim-polri", logo: "/logo/satker/SESPIM-POLRI.png" },
{ name: "SETUPA POLRI", slug: "setupa-polri", logo: "/assets/satker/setupa-polri.png" },
// { name: "SIBER", slug: "siber", logo: "/logo/satker/SIBER.png" },
// { name: "SATUAN KERJA POLRI", slug: "satuan-kerja-polri", logo: "/logo/satker/SATUAN-KERJA-POLRI.png" },
// { name: "DIV HUMAS", slug: "div-humas", logo: "/logo/satker/DIV-HUMAS.png" },
];
const Division = () => {

View File

@ -0,0 +1,370 @@
import { formatDateToIndonesian, shimmer, toBase64 } from "@/utils/globals";
import React, { useEffect, useRef, useState } from "react";
import "swiper/css/bundle";
import "swiper/css/navigation";
import { getHeroData, listStaticBanner } from "@/service/landing/landing";
import Link from "next/link";
import { useParams, usePathname, useRouter } from "next/navigation";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
import { Skeleton } from "../ui/skeleton";
import Image from "next/image";
import Cookies from "js-cookie";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../ui/card";
import { Label } from "../ui/label";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { Textarea } from "../ui/textarea";
import { Checkbox } from "../ui/checkbox";
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "../ui/dialog";
import { Autoplay, Navigation, Pagination } from "swiper/modules";
import { Swiper, SwiperClass, SwiperSlide } from "swiper/react";
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
import { ChevronLeft, ChevronRight } from "lucide-react";
type HeroModalProps = {
onClose: () => void;
group: string;
poldaName?: string;
satkerName?: string;
};
const HeroModal = ({ onClose, group, poldaName, satkerName }: HeroModalProps) => {
const [heroData, setHeroData] = useState<any>();
const params = useParams();
const locale = params?.locale;
const swiperRef = useRef<SwiperClass | null>(null);
useEffect(() => {
async function fetchCategories() {
const url = "https://netidhub.com/api/csrf";
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error: ", error);
}
}
fetchCategories();
initFetch();
}, []);
useEffect(() => {
document.body.classList.add("overflow-hidden");
return () => {
document.body.classList.remove("overflow-hidden");
};
}, []);
const initFetch = async () => {
if (group === "polda" && poldaName && String(poldaName).length > 1) {
const response = await listStaticBanner(poldaName);
const banners =
response?.data?.data?.map((item: any) => {
const media = item?.mediaUpload;
if (media?.fileType) {
media.fileTypeId = media.fileType.id;
}
return media;
}) || [];
console.log("banner Modal", banners);
setHeroData(banners);
} else {
console.log("Test");
setHeroData([]);
}
};
return (
<div className="fixed inset-0 flex items-center justify-center backdrop-brightness-50 z-50 ">
<div className="relative dark:bg-gray-900 rounded-lg w-[90%] md:w-[600px] p-4 shadow-none">
{heroData?.length > 0 && (
<>
<button className="absolute left-3 top-1/2 z-10 -translate-y-1/2 text-white text-3xl" onClick={() => swiperRef.current?.slidePrev()}>
<ChevronLeft />
</button>
<button className="absolute right-3 top-1/2 z-10 -translate-y-1/2 text-white text-3xl" onClick={() => swiperRef.current?.slideNext()}>
<ChevronRight />
</button>
</>
)}
<Swiper pagination={{ dynamicBullets: true }} modules={[Pagination, Autoplay]} onSwiper={(swiper) => (swiperRef.current = swiper)} autoplay={{ delay: 3000 }} className="mySwiper w-full">
<div className="relative h-[310px] lg:h-[420px]">
<button onClick={onClose} className="absolute top-3 right-3 text-gray-700 dark:text-gray-300 hover:text-black dark:hover:text-white border border-white bg-white rounded-full h-8 w-8 z-10">
</button>
{heroData && heroData.length > 0 ? (
heroData.map((list: any, index: number) => (
<SwiperSlide key={list?.id}>
<div className="relative h-[310px] lg:h-[420px]">
<Image src={list?.thumbnailLink} alt="gambar-utama" width={1920} height={1080} placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`} className="w-full h-[310px] lg:h-[420px] rounded-lg object-cover" />
<div className="absolute bottom-0 left-0 right-0 bg-black/30 backdrop-brightness-50 text-white pb-4 px-4 pt-8 rounded-bl-2xl rounded-tr-2xl mx-3 mb-2">
<div className="absolute top-0 left-0 bottom-0 w-2 bg-[#bb3523] rounded-bl-lg"></div>
<span className="absolute top-0 left-0 mt-2 mb-3 mx-3 bg-[#bb3523] text-white text-xs font-semibold uppercase px-2 py-1 rounded">{list?.categoryName || "Liputan Kegiatan"}</span>
<Link href={`${locale}/image/detail/${list?.slug}`}>
<h2 className="text-lg leading-tight">{list?.title}</h2>
</Link>
<p className="text-xs flex items-center gap-1 mt-2 opacity-80">
{formatDateToIndonesian(new Date(list?.createdAt))} {list?.timezone || "WIB"} |{" "}
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" className="inline-block">
<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>
{list?.clickCount}
</p>
</div>
</div>
</SwiperSlide>
))
) : (
<div className="flex items-center justify-center h-full">
<Image width={1920} height={1080} src="/assets/empty-data.png" alt="empty" className="h-52 w-52 my-4" />
</div>
)}
</div>
<style jsx global>{`
.swiper-pagination-bullet {
background: white !important;
opacity: 0.7;
}
.swiper-pagination-bullet-active {
background: white !important;
opacity: 1;
}
`}</style>
</Swiper>
</div>
</div>
);
};
const ONE_MONTH = 30 * 24 * 60 * 60 * 1000;
const HeroNewPolda = (props: { group?: string }) => {
const router = useRouter();
const pathname = usePathname();
const params = useParams();
const locale = params?.locale;
const [isLoading, setIsLoading] = useState<any>(true);
const [heroData, setHeroData] = useState<any>();
const [content, setContent] = useState<any>();
const [showModal, setShowModal] = useState(false);
const [showSurveyModal, setShowSurveyModal] = useState(false);
const [showFormModal, setShowFormModal] = useState(false);
const poldaName = params?.polda_name;
const satkerName = params?.satker_name;
useEffect(() => {
const timer = setTimeout(() => {
setIsLoading(false);
}, 3000);
return () => clearTimeout(timer);
}, []);
useEffect(() => {
const roleId = Cookies.get("urie");
if (!roleId) {
setShowModal(true);
}
initFetch();
}, []);
// useEffect(() => {
// const roleId = Cookies.get("urie");
// const lastShown = Cookies.get("surveyLastShown");
// const now = new Date().getTime();
// if (roleId && roleId !== "2") {
// if (!lastShown || now - parseInt(lastShown) > ONE_MONTH) {
// setShowSurveyModal(true);
// Cookies.set("surveyLastShown", now.toString(), { expires: 30 });
// }
// }
// initFetch();
// }, []);
useEffect(() => {
const roleId = Cookies.get("urie");
const lastShown = Cookies.get("surveyLastShown");
const now = new Date().getTime();
const allowedRoles = ["1", "2", "3"];
if (roleId && allowedRoles.includes(roleId)) {
if (!lastShown || now - parseInt(lastShown) > ONE_MONTH) {
setShowSurveyModal(true);
Cookies.set("surveyLastShown", now.toString(), { expires: 30 });
}
}
initFetch();
}, []);
useEffect(() => {
async function fetchCategories() {
const url = "https://netidhub.com/api/csrf";
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error: ", error);
}
}
fetchCategories();
initFetch();
}, []);
const initFetch = async () => {
const response = await getHeroData();
console.log(response);
let data = response?.data?.data?.content;
setHeroData(data);
if (data && props.group === "polda" && poldaName && String(poldaName)?.length > 1) {
const resStatic = await listStaticBanner(poldaName);
for (let i = 0; i < resStatic?.data?.data?.length; i++) {
const media = resStatic?.data.data[i]?.mediaUpload;
media.fileTypeId = media.fileType?.id;
data = data.filter((item: any) => item.id != media.id);
data.splice(0, 0, media);
}
setContent(data);
}
};
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">
<defs>
<linearGradient id="g">
<stop stop-color="#bcbcbd" offset="20%" />
<stop stop-color="#f9fafb" offset="50%" />
<stop stop-color="#bcbcbd" offset="70%" />
</linearGradient>
</defs>
<rect width="${w}" height="${h}" fill="#bcbcbd" />
<rect id="r" width="${w}" height="${h}" fill="url(#g)" />
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
</svg>`;
const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str));
return (
<div className="flex items-start justify-center mx-auto w-auto">
<div className="relative">{showModal && <HeroModal onClose={() => setShowModal(false)} group="polda" />}</div>
{isLoading ? (
<div className="flex flex-col space-y-3 mx-auto w-full lg:w-2/3">
<Skeleton className="h-[310px] lg:h-[420px]" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
) : (
<div className="relative w-full h-full">
<Carousel className="lg:w-full lg:h-full">
<CarouselContent>
{content?.map((list: any) => (
<CarouselItem key={list?.id}>
<div className="relative h-[310px] lg:h-[700px] mt-1">
<Image src={list?.thumbnailLink} alt="gambar-utama" width={1920} height={1080} placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`} className="w-full h-[320px] lg:h-[700px] object-cover" />
<div className="absolute inset-0 bg-black bg-opacity-40" />
<Link
href={
Number(list?.fileTypeId) == 1
? `${locale}/image/detail/${list?.slug}`
: Number(list?.fileTypeId) == 2
? `${locale}/video/detail/${list?.slug}`
: Number(list?.fileTypeId) == 3
? `${locale}/document/detail/${list?.slug}`
: `${locale}/audio/detail/${list?.slug}`
}
>
<div className="absolute bottom-20 left-32 w-[60%] lg:w-[45%] text-white px-4 pt-10 pb-4">
<span className="absolute top-0 left-3 text-red-600 text-lg font-bold uppercase px-1 py-2 rounded">{list?.categoryName || "Liputan Kegiatan"}</span>
<h2 className="text-xl font-bold leading-tight">{list?.title}</h2>
<p className="text-base flex items-center gap-1 mt-2 opacity-80">
{formatDateToIndonesian(new Date(list?.createdAt))} {list?.timezone || "WIB"} | 👁 {list?.clickCount}
</p>
</div>
</Link>
</div>
</CarouselItem>
))}
</CarouselContent>
</Carousel>
<div className="hidden lg:flex flex-col gap-3 absolute bottom-4 right-4 w-[520px] bg-black/40 p-4 rounded-lg z-10">
{heroData?.slice(0, 3).map((item: any) => (
<li key={item?.id} className="flex gap-4 flex-row lg:w-full mx-2">
<div className="flex-shrink-0 w-32 rounded-lg">
<Image placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`} width={720} height={480} src={item?.thumbnailLink} alt={item?.title} className="w-full h-[100px] object-cover rounded-lg" />
</div>
<div className="w-[280px] lg:w-[200px]">
<Link
href={
Number(item?.fileTypeId) == 1
? `${locale}/image/detail/${item?.slug}`
: Number(item?.fileTypeId) == 2
? `${locale}/video/detail/${item?.slug}`
: Number(item?.fileTypeId) == 3
? `${locale}/document/detail/${item?.slug}`
: `${locale}/audio/detail/${item?.slug}`
}
>
<span className="py-1 rounded-lg flex text-red-600 font-bold uppercase w-fit">{item?.categoryName}</span>
<h3 className="text-base text-white font-bold h-6 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible">{item?.title}</h3>
<p className="text-[10px] flex flex-row items-center gap-1 text-white mt-1">
{formatDateToIndonesian(new Date(item?.createdAt))} {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>
</Link>
</div>
</li>
))}
</div>
</div>
)}
</div>
);
};
export default HeroNewPolda;

View File

@ -0,0 +1,370 @@
import { formatDateToIndonesian, shimmer, toBase64 } from "@/utils/globals";
import React, { useEffect, useRef, useState } from "react";
import "swiper/css/bundle";
import "swiper/css/navigation";
import { getHeroData, listStaticBanner } from "@/service/landing/landing";
import Link from "next/link";
import { useParams, usePathname, useRouter } from "next/navigation";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
import { Skeleton } from "../ui/skeleton";
import Image from "next/image";
import Cookies from "js-cookie";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../ui/card";
import { Label } from "../ui/label";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { Textarea } from "../ui/textarea";
import { Checkbox } from "../ui/checkbox";
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "../ui/dialog";
import { Autoplay, Navigation, Pagination } from "swiper/modules";
import { Swiper, SwiperClass, SwiperSlide } from "swiper/react";
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
import { ChevronLeft, ChevronRight } from "lucide-react";
type HeroModalProps = {
onClose: () => void;
group: string;
poldaName?: string;
satkerName?: string;
};
const HeroModal = ({ onClose, group, poldaName, satkerName }: HeroModalProps) => {
const [heroData, setHeroData] = useState<any>();
const params = useParams();
const locale = params?.locale;
const swiperRef = useRef<SwiperClass | null>(null);
useEffect(() => {
async function fetchCategories() {
const url = "https://netidhub.com/api/csrf";
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error: ", error);
}
}
fetchCategories();
initFetch();
}, []);
useEffect(() => {
document.body.classList.add("overflow-hidden");
return () => {
document.body.classList.remove("overflow-hidden");
};
}, []);
const initFetch = async () => {
if (group === "satker" && satkerName && String(satkerName).length > 1) {
const response = await listStaticBanner(satkerName);
const banners =
response?.data?.data?.map((item: any) => {
const media = item?.mediaUpload;
if (media?.fileType) {
media.fileTypeId = media.fileType.id;
}
return media;
}) || [];
console.log("banner Modal", banners);
setHeroData(banners);
} else {
console.log("Test");
setHeroData([]);
}
};
return (
<div className="fixed inset-0 flex items-center justify-center backdrop-brightness-50 z-50 ">
<div className="relative dark:bg-gray-900 rounded-lg w-[90%] md:w-[600px] p-4 shadow-none">
{heroData?.length > 0 && (
<>
<button className="absolute left-3 top-1/2 z-10 -translate-y-1/2 text-white text-3xl" onClick={() => swiperRef.current?.slidePrev()}>
<ChevronLeft />
</button>
<button className="absolute right-3 top-1/2 z-10 -translate-y-1/2 text-white text-3xl" onClick={() => swiperRef.current?.slideNext()}>
<ChevronRight />
</button>
</>
)}
<Swiper pagination={{ dynamicBullets: true }} modules={[Pagination, Autoplay]} onSwiper={(swiper) => (swiperRef.current = swiper)} autoplay={{ delay: 3000 }} className="mySwiper w-full">
<div className="relative h-[310px] lg:h-[420px]">
<button onClick={onClose} className="absolute top-3 right-3 text-gray-700 dark:text-gray-300 hover:text-black dark:hover:text-white border border-white bg-white rounded-full h-8 w-8 z-10">
</button>
{heroData && heroData.length > 0 ? (
heroData.map((list: any, index: number) => (
<SwiperSlide key={list?.id}>
<div className="relative h-[310px] lg:h-[420px]">
<Image src={list?.thumbnailLink} alt="gambar-utama" width={1920} height={1080} placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`} className="w-full h-[310px] lg:h-[420px] rounded-lg object-cover" />
<div className="absolute bottom-0 left-0 right-0 bg-black/30 backdrop-brightness-50 text-white pb-4 px-4 pt-8 rounded-bl-2xl rounded-tr-2xl mx-3 mb-2">
<div className="absolute top-0 left-0 bottom-0 w-2 bg-[#bb3523] rounded-bl-lg"></div>
<span className="absolute top-0 left-0 mt-2 mb-3 mx-3 bg-[#bb3523] text-white text-xs font-semibold uppercase px-2 py-1 rounded">{list?.categoryName || "Liputan Kegiatan"}</span>
<Link href={`${locale}/image/detail/${list?.slug}`}>
<h2 className="text-lg leading-tight">{list?.title}</h2>
</Link>
<p className="text-xs flex items-center gap-1 mt-2 opacity-80">
{formatDateToIndonesian(new Date(list?.createdAt))} {list?.timezone || "WIB"} |{" "}
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" className="inline-block">
<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>
{list?.clickCount}
</p>
</div>
</div>
</SwiperSlide>
))
) : (
<div className="flex items-center justify-center h-full">
<Image width={1920} height={1080} src="/assets/empty-data.png" alt="empty" className="h-52 w-52 my-4" />
</div>
)}
</div>
<style jsx global>{`
.swiper-pagination-bullet {
background: white !important;
opacity: 0.7;
}
.swiper-pagination-bullet-active {
background: white !important;
opacity: 1;
}
`}</style>
</Swiper>
</div>
</div>
);
};
const ONE_MONTH = 30 * 24 * 60 * 60 * 1000;
const HeroNewSatker = (props: { group?: string }) => {
const router = useRouter();
const pathname = usePathname();
const params = useParams();
const locale = params?.locale;
const [isLoading, setIsLoading] = useState<any>(true);
const [heroData, setHeroData] = useState<any>();
const [content, setContent] = useState<any>();
const [showModal, setShowModal] = useState(false);
const [showSurveyModal, setShowSurveyModal] = useState(false);
const [showFormModal, setShowFormModal] = useState(false);
const poldaName = params?.polda_name;
const satkerName = params?.satker_name;
useEffect(() => {
const timer = setTimeout(() => {
setIsLoading(false);
}, 3000);
return () => clearTimeout(timer);
}, []);
useEffect(() => {
const roleId = Cookies.get("urie");
if (!roleId) {
setShowModal(true);
}
initFetch();
}, []);
// useEffect(() => {
// const roleId = Cookies.get("urie");
// const lastShown = Cookies.get("surveyLastShown");
// const now = new Date().getTime();
// if (roleId && roleId !== "2") {
// if (!lastShown || now - parseInt(lastShown) > ONE_MONTH) {
// setShowSurveyModal(true);
// Cookies.set("surveyLastShown", now.toString(), { expires: 30 });
// }
// }
// initFetch();
// }, []);
useEffect(() => {
const roleId = Cookies.get("urie");
const lastShown = Cookies.get("surveyLastShown");
const now = new Date().getTime();
const allowedRoles = ["1", "2", "3"];
if (roleId && allowedRoles.includes(roleId)) {
if (!lastShown || now - parseInt(lastShown) > ONE_MONTH) {
setShowSurveyModal(true);
Cookies.set("surveyLastShown", now.toString(), { expires: 30 });
}
}
initFetch();
}, []);
useEffect(() => {
async function fetchCategories() {
const url = "https://netidhub.com/api/csrf";
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error: ", error);
}
}
fetchCategories();
initFetch();
}, []);
const initFetch = async () => {
const response = await getHeroData();
console.log(response);
let data = response?.data?.data?.content;
setHeroData(data);
if (data && props.group === "satker" && satkerName && String(satkerName)?.length > 1) {
const resStatic = await listStaticBanner(satkerName);
for (let i = 0; i < resStatic?.data?.data?.length; i++) {
const media = resStatic?.data.data[i]?.mediaUpload;
media.fileTypeId = media.fileType?.id;
data = data.filter((item: any) => item.id != media.id);
data.splice(0, 0, media);
}
setContent(data);
}
};
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">
<defs>
<linearGradient id="g">
<stop stop-color="#bcbcbd" offset="20%" />
<stop stop-color="#f9fafb" offset="50%" />
<stop stop-color="#bcbcbd" offset="70%" />
</linearGradient>
</defs>
<rect width="${w}" height="${h}" fill="#bcbcbd" />
<rect id="r" width="${w}" height="${h}" fill="url(#g)" />
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
</svg>`;
const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str));
return (
<div className="flex items-start justify-center mx-auto w-auto">
<div className="relative">{showModal && <HeroModal onClose={() => setShowModal(false)} group="satker" />}</div>
{isLoading ? (
<div className="flex flex-col space-y-3 mx-auto w-full lg:w-2/3">
<Skeleton className="h-[310px] lg:h-[420px]" />
<div className="space-y-2">
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
) : (
<div className="relative w-full h-full">
<Carousel className="lg:w-full lg:h-full">
<CarouselContent>
{content?.map((list: any) => (
<CarouselItem key={list?.id}>
<div className="relative h-[310px] lg:h-[700px] mt-1">
<Image src={list?.thumbnailLink} alt="gambar-utama" width={1920} height={1080} placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`} className="w-full h-[320px] lg:h-[700px] object-cover" />
<div className="absolute inset-0 bg-black bg-opacity-40" />
<Link
href={
Number(list?.fileTypeId) == 1
? `${locale}/image/detail/${list?.slug}`
: Number(list?.fileTypeId) == 2
? `${locale}/video/detail/${list?.slug}`
: Number(list?.fileTypeId) == 3
? `${locale}/document/detail/${list?.slug}`
: `${locale}/audio/detail/${list?.slug}`
}
>
<div className="absolute bottom-20 left-32 w-[60%] lg:w-[45%] text-white px-4 pt-10 pb-4">
<span className="absolute top-0 left-3 text-red-600 text-lg font-bold uppercase px-1 py-2 rounded">{list?.categoryName || "Liputan Kegiatan"}</span>
<h2 className="text-xl font-bold leading-tight">{list?.title}</h2>
<p className="text-base flex items-center gap-1 mt-2 opacity-80">
{formatDateToIndonesian(new Date(list?.createdAt))} {list?.timezone || "WIB"} | 👁 {list?.clickCount}
</p>
</div>
</Link>
</div>
</CarouselItem>
))}
</CarouselContent>
</Carousel>
<div className="hidden lg:flex flex-col gap-3 absolute bottom-4 right-4 w-[520px] bg-black/40 p-4 rounded-lg z-10">
{heroData?.slice(0, 3).map((item: any) => (
<li key={item?.id} className="flex gap-4 flex-row lg:w-full mx-2">
<div className="flex-shrink-0 w-32 rounded-lg">
<Image placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`} width={720} height={480} src={item?.thumbnailLink} alt={item?.title} className="w-full h-[100px] object-cover rounded-lg" />
</div>
<div className="w-[280px] lg:w-[200px]">
<Link
href={
Number(item?.fileTypeId) == 1
? `${locale}/image/detail/${item?.slug}`
: Number(item?.fileTypeId) == 2
? `${locale}/video/detail/${item?.slug}`
: Number(item?.fileTypeId) == 3
? `${locale}/document/detail/${item?.slug}`
: `${locale}/audio/detail/${item?.slug}`
}
>
<span className="py-1 rounded-lg flex text-red-600 font-bold uppercase w-fit">{item?.categoryName}</span>
<h3 className="text-base text-white font-bold h-6 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible">{item?.title}</h3>
<p className="text-[10px] flex flex-row items-center gap-1 text-white mt-1">
{formatDateToIndonesian(new Date(item?.createdAt))} {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>
</Link>
</div>
</li>
))}
</div>
</div>
)}
</div>
);
};
export default HeroNewSatker;

File diff suppressed because it is too large Load Diff

View File

@ -2,13 +2,7 @@
import React, { useEffect, useState } from "react";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
import { Carousel, CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
import { useParams, usePathname } from "next/navigation";
import { Icon } from "@iconify/react/dist/iconify.js";
import { formatDateToIndonesian, secondToTimes } from "@/utils/globals";
@ -18,6 +12,7 @@ import { Reveal } from "./Reveal";
import { useTranslations } from "next-intl";
import { Skeleton } from "../ui/skeleton";
import Image from "next/image";
import { motion } from "framer-motion";
const NewContent = (props: { group: string; type: string }) => {
const [newContent, setNewContent] = useState<any>();
@ -30,12 +25,28 @@ const NewContent = (props: { group: string; type: string }) => {
const poldaName = params?.polda_name;
const satkerName = params?.satker_name;
const t = useTranslations("LandingPage");
const [api, setApi] = React.useState<CarouselApi | null>(null);
const [current, setCurrent] = React.useState(0);
const [count, setCount] = React.useState(0);
let prefixPath = poldaName
? `/polda/${poldaName}`
: satkerName
? `/satker/${satkerName}`
: "/";
React.useEffect(() => {
if (!api) return;
setCount(api.scrollSnapList().length);
setCurrent(api.selectedScrollSnap());
const onSelect = () => {
setCurrent(api.selectedScrollSnap());
};
api.on("select", onSelect);
return () => {
api.off("select", onSelect);
};
}, [api]);
let prefixPath = poldaName ? `/polda/${poldaName}` : satkerName ? `/satker/${satkerName}` : "/";
useEffect(() => {
const timer = setTimeout(() => {
@ -55,26 +66,8 @@ const NewContent = (props: { group: string; type: string }) => {
page: 0,
size: 5,
sortBy: props.type == "popular" ? "clickCount" : "createdAt",
contentTypeId:
selectedTab == "image"
? "1"
: selectedTab == "video"
? "2"
: selectedTab == "text"
? "3"
: selectedTab == "audio"
? "4"
: "",
group:
props.group == "mabes"
? ""
: props.group == "polda" && poldaName && String(poldaName)?.length > 1
? poldaName
: props.group == "satker" &&
satkerName &&
String(satkerName)?.length > 1
? "satker-" + satkerName
: "",
contentTypeId: selectedTab == "image" ? "1" : selectedTab == "video" ? "2" : selectedTab == "text" ? "3" : selectedTab == "audio" ? "4" : "",
group: props.group == "mabes" ? "" : props.group == "polda" && poldaName && String(poldaName)?.length > 1 ? poldaName : props.group == "satker" && satkerName && String(satkerName)?.length > 1 ? "satker-" + satkerName : "",
isInt: locale == "en" ? true : false,
};
const response = await getListContent(request);
@ -96,44 +89,31 @@ const NewContent = (props: { group: string; type: string }) => {
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
</svg>`;
const toBase64 = (str: string) =>
typeof window === "undefined"
? Buffer.from(str).toString("base64")
: window.btoa(str);
const toBase64 = (str: string) => (typeof window === "undefined" ? Buffer.from(str).toString("base64") : window.btoa(str));
return (
<div className="px-4 py-4">
<div className="px-4 lg:px-0 py-4">
<Reveal>
<div className="flex flex-col p-4">
<h2 className="flex items-center text-lg md:text-xl font-bold text-[#bb3523] border-b-2 border-[#bb3523] mb-4 uppercase">
<div className="flex flex-col">
<h2 className="flex items-center text-lg md:text-xl font-bold text-[#bb3523] border-b-2 border-[#bb3523] uppercase">
{pathname?.split("/")[1] == "in" ? (
<>
<span className="text-[#bb3523] ">{t("content")}</span>&nbsp;
{props.type == "popular"
? "Terpopuler"
: props.type == "latest"
? t("new")
: "Serupa"}
{props.type == "popular" ? "Terpopuler" : props.type == "latest" ? t("new") : "Serupa"}
</>
) : (
<>
<span className="text-[#bb3523] ">
{props.type == "popular"
? "Popular"
: props.type == "latest"
? t("new")
: "Serupa"}
</span>
<span className="text-[#bb3523] ">{props.type == "popular" ? "Popular" : props.type == "latest" ? t("new") : "Serupa"}</span>
&nbsp;
{t("content")}
</>
)}
</h2>
<div className="mx-auto w-full justify-start flex px-10 flex-col lg:flex-row gap-5 mb-4">
<div className="mx-auto w-full justify-start flex flex-col lg:flex-row gap-5 my-8">
<Tabs value={selectedTab} onValueChange={setSelectedTab}>
<TabsList className="flex gap-2 bg-transparent p-0">
{[
{ label: "video", value: "video" },
{ label: "Audio Visual", value: "video" },
{ label: "Audio", value: "audio" },
{ label: "Foto", value: "image" },
{ label: "Teks", value: "text" },
@ -142,7 +122,7 @@ const NewContent = (props: { group: string; type: string }) => {
key={tab.value}
value={tab.value}
className={`
rounded-md px-4 py-2 text-sm transition-all
rounded-md px-6 py-2 text-sm transition-all
bg-[#f5f5f5] text-[#666] hover:bg-[#e0e0e0]
data-[state=active]:bg-[#bb0000]
data-[state=active]:text-white
@ -163,304 +143,243 @@ const NewContent = (props: { group: string; type: string }) => {
<Skeleton className="h-[200px] w-[400px] rounded-xl hidden md:block" />
</div>
) : (
<div className="px-0 lg:px-10">
<div className="">
{selectedTab == "image" ? (
newContent?.length > 0 ? (
<Carousel className="w-full mx-auto">
<Carousel setApi={setApi} className="w-full mx-auto">
<CarouselContent>
{newContent?.map((image: any) => (
<CarouselItem
key={image?.id}
className="md:basis-1/2 lg:basis-1/3"
>
<div
onClick={() =>
router.push(
prefixPath + `/image/detail/${image?.slug}`
)
}
className="cursor-pointer relative group overflow-hidden shadow-md hover:shadow-lg"
>
<Image
placeholder={`data:image/svg+xml;base64,${toBase64(
shimmer(700, 475)
)}`}
width={2560}
height={1440}
alt="image"
src={image?.thumbnailLink}
className="w-full rounded-lg h-48 lg:h-60 object-cover group-hover:scale-100 transition-transform duration-300"
/>
<div className="absolute bottom-0 left-0 right-0 bg-gray-500/55 border-l-4 border-[#bb3523] rounded-lg backdrop-blur-sm text-white p-2">
<p className="text-sm lg:text-base mb-2 font-semibold h-6 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible">
{image?.title}
</p>
<p className="flex flex-row items-center text-[10px] gap-1">
{formatDateToIndonesian(
new Date(image?.createdAt)
)}{" "}
{image?.timezone ? image?.timezone : "WIB"} |{" "}
<Icon
icon="formkit:eye"
width="15"
height="15"
/>{" "}
{image.clickCount}{" "}
</p>
<CarouselItem key={image?.id} className="md:basis-1/2 lg:basis-1/3">
<div onClick={() => router.push(prefixPath + `/image/detail/${image?.slug}`)} className="cursor-pointer relative group overflow-hidden bg-white rounded-xl shadow-md hover:shadow-lg transition-shadow duration-300">
{/* Image with motion effect */}
<motion.div className="w-full h-48 lg:h-60" whileHover={{ scale: 0.95 }} transition={{ duration: 0.3 }}>
<Image placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`} width={2560} height={1440} alt="image" src={image?.thumbnailLink} className="w-full h-full object-cover" />
</motion.div>
{/* Badge category */}
{/* <div className="absolute top-2 left-2 bg-white px-2 py-1 rounded-sm text-[10px] font-bold text-[#bb3523]">{image?.category?.toUpperCase() ?? "GIAT PIMPINAN"}</div> */}
{/* Red icon overlay */}
<div className="absolute top-2 right-2 bg-[#bb3523] rounded-full p-1">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="white"
d="M20 6a2 2 0 0 1 2 2v11.333a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2zm-8.268 7.944L7.136 18.54l-.066.06l-.07.054v.68h13v-.68l-.07-.053l-.066-.06l-2.24-2.24l-.353.354l.055.055a1 1 0 0 1-1.32 1.497l-.094-.083zM17 3a2 2 0 0 1 1.995 1.85L19 5H5a1 1 0 0 0-.993.883L4 6v12a2 2 0 0 1-1.995-1.85L2 16V6a3 3 0 0 1 2.824-2.995L5 3zm3 5H7v7.848L10.848 12a1.25 1.25 0 0 1 1.768 0l3.241 3.24l.884-.883a1.25 1.25 0 0 1 1.768 0L20 15.848zm-3.5 1.5a1.5 1.5 0 1 1 0 3a1.5 1.5 0 0 1 0-3"
/>
</g>
</svg>{" "}
</div>
{/* Caption section */}
<div className="p-4">
<p className="text-[12px] font-bold text-[#bb3523] uppercase mb-1">{image?.categoryName?.toUpperCase() ?? "Giat Pimpinan"}</p>
<p className="text-lg font-semibold text-black truncate">{image?.title}</p>
{/* <p className="flex flex-row items-center text-[10px] gap-1 mt-2 text-gray-600">
{formatDateToIndonesian(new Date(image?.createdAt))} {image?.timezone ?? "WIB"} |
<Icon icon="formkit:eye" width="15" height="15" /> {image.clickCount}
</p> */}
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious className="hover:bg-black" />
<CarouselNext className="hover:bg-black -mr-6" />
<div className="flex justify-center mt-4">
{Array.from({ length: count }).map((_, index) => (
<button key={index} className={`w-3 h-3 mx-1 rounded-full ${index === current ? "bg-gray-800" : "bg-gray-300"}`} onClick={() => api?.scrollTo(index)} aria-label={`Slide ${index + 1}`} />
))}
</div>
<CarouselPrevious className="hover:bg-black ml-2" />
<CarouselNext className="hover:bg-black mr-2" />
</Carousel>
) : (
<p className="flex items-center justify-center">
<Image
width={1920}
height={1080}
src="/assets/empty-data.png"
alt="empty"
className="h-52 w-52 my-4"
/>
<Image width={1920} height={1080} src="/assets/empty-data.png" alt="empty" className="h-52 w-52 my-4" />
</p>
)
) : selectedTab == "audio" ? (
newContent?.length > 0 ? (
<Carousel className="w-full max-w-7xl mx-auto">
<Carousel setApi={setApi} className="w-full max-w-7xl mx-auto">
<CarouselContent>
{newContent?.map((audio: any) => (
<CarouselItem
key={audio?.id}
className="md:basis-1/2 lg:basis-1/3 "
>
<div className="flex flex-row gap-6">
<div
onClick={() =>
router.push(
prefixPath + `/audio/detail/${audio?.slug}`
)
}
className="cursor-pointer flex flex-row sm:flex-row items-center bg-white dark:bg-gray-800 shadow-md border rounded-lg p-4 my-3 gap-4 w-full "
>
<div className="flex items-center justify-center bg-red-500 text-white rounded-lg lg:w-24 h-8 lg:h-16 w-10 p-3">
<svg
width="32"
height="34"
viewBox="0 0 32 34"
fill="null"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M23.404 0.452014C23.7033 0.35857 24.0204 0.336816 24.3297 0.388509C24.639 0.440203 24.9318 0.563895 25.1845 0.749599C25.4371 0.935304 25.6426 1.17782 25.7843 1.45756C25.9259 1.73731 25.9998 2.04644 26 2.36001V14.414C25.3462 14.2296 24.6766 14.1064 24 14.046V8.36001L10 12.736V27C10 28.1264 9.6197 29.2197 8.92071 30.1029C8.22172 30.9861 7.24499 31.6075 6.14877 31.8663C5.05255 32.125 3.90107 32.0061 2.88089 31.5287C1.86071 31.0514 1.03159 30.2435 0.52787 29.2361C0.024152 28.2286 -0.124656 27.0806 0.105556 25.9781C0.335768 24.8755 0.931513 23.883 1.79627 23.1613C2.66102 22.4396 3.74413 22.031 4.87009 22.0017C5.99606 21.9724 7.09893 22.3242 8.00001 23V6.73601C7.99982 6.30956 8.13596 5.8942 8.38854 5.55059C8.64112 5.20698 8.99692 4.9531 9.40401 4.82601L23.404 0.452014ZM10 10.64L24 6.26601V2.36001L10 6.73601V10.64ZM5.00001 24C4.20436 24 3.44129 24.3161 2.87869 24.8787C2.31608 25.4413 2.00001 26.2044 2.00001 27C2.00001 27.7957 2.31608 28.5587 2.87869 29.1213C3.44129 29.6839 4.20436 30 5.00001 30C5.79566 30 6.55872 29.6839 7.12133 29.1213C7.68394 28.5587 8.00001 27.7957 8.00001 27C8.00001 26.2044 7.68394 25.4413 7.12133 24.8787C6.55872 24.3161 5.79566 24 5.00001 24ZM32 25C32 27.387 31.0518 29.6761 29.364 31.364C27.6761 33.0518 25.387 34 23 34C20.6131 34 18.3239 33.0518 16.636 31.364C14.9482 29.6761 14 27.387 14 25C14 22.6131 14.9482 20.3239 16.636 18.6361C18.3239 16.9482 20.6131 16 23 16C25.387 16 27.6761 16.9482 29.364 18.6361C31.0518 20.3239 32 22.6131 32 25ZM27.47 24.128L21.482 20.828C21.3298 20.7443 21.1583 20.7016 20.9846 20.7043C20.8108 20.707 20.6408 20.7549 20.4912 20.8433C20.3416 20.9317 20.2176 21.0576 20.1315 21.2086C20.0453 21.3595 20 21.5302 20 21.704V28.304C20 28.4778 20.0453 28.6486 20.1315 28.7995C20.2176 28.9504 20.3416 29.0763 20.4912 29.1647C20.6408 29.2531 20.8108 29.301 20.9846 29.3037C21.1583 29.3064 21.3298 29.2638 21.482 29.18L27.47 25.88C27.6268 25.7937 27.7575 25.6669 27.8486 25.5128C27.9397 25.3587 27.9877 25.183 27.9877 25.004C27.9877 24.825 27.9397 24.6493 27.8486 24.4952C27.7575 24.3412 27.6268 24.2143 27.47 24.128Z"
fill="white"
/>
</svg>
</div>
<CarouselItem key={audio?.id} className="md:basis-1/2 lg:basis-1/3">
<div onClick={() => router.push(prefixPath + `/audio/detail/${audio?.slug}`)} className="cursor-pointer bg-white rounded-xl shadow-md hover:shadow-lg transition-shadow duration-300 overflow-hidden">
{/* Icon Background */}
<div className="flex items-center justify-center bg-[#bb3523] w-full h-[170px] text-white">
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150" viewBox="0 0 20 20">
<path
fill="currentColor"
d="M14.702 2.226A1 1 0 0 1 16 3.18v6.027a5.5 5.5 0 0 0-1-.184V6.18L8 8.368V15.5a2.5 2.5 0 1 1-1-2V5.368a1 1 0 0 1 .702-.955zM8 7.32l7-2.187V3.18L8 5.368zM5.5 14a1.5 1.5 0 1 0 0 3a1.5 1.5 0 0 0 0-3m13.5.5a4.5 4.5 0 1 1-9 0a4.5 4.5 0 0 1 9 0m-2.265-.436l-2.994-1.65a.5.5 0 0 0-.741.438v3.3a.5.5 0 0 0 .741.438l2.994-1.65a.5.5 0 0 0 0-.876"
/>
</svg>{" "}
</div>
<div className="flex flex-col flex-1">
<div className="text-gray-500 dark:text-gray-400 flex flex-row text-sm text-center items-center">
{formatDateToIndonesian(
new Date(audio?.createdAt)
)}{" "}
{audio?.timezone ? audio?.timezone : "WIB"}{" "}
|&nbsp;{" "}
<Icon
icon="formkit:eye"
width="15"
height="15"
/>
&nbsp; {audio?.clickCount}{" "}
</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">
{audio?.title}
</div>
<p className="text-sm">
{" "}
{audio?.duration
? secondToTimes(Number(audio?.duration))
: "00:00:00"}
</p>
</div>
{/* Caption */}
<div className="p-4">
<p className="text-[12px] font-bold text-[#bb3523] uppercase mb-1">{audio?.categoryName?.toUpperCase() ?? "GIAT PIMPINAN"}</p>
<p className="text-xl font-semibold text-black truncate">{audio?.title}</p>
{/* <p className="text-[10px] text-gray-600 mt-2 flex items-center gap-1">
{formatDateToIndonesian(new Date(audio?.createdAt))} {audio?.timezone ?? "WIB"} |
<Icon icon="formkit:eye" width="15" height="15" /> {audio?.clickCount}
</p> */}
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
<div className="flex justify-center mt-4">
{Array.from({ length: count }).map((_, index) => (
<button key={index} className={`w-3 h-3 mx-1 rounded-full ${index === current ? "bg-gray-800" : "bg-gray-300"}`} onClick={() => api?.scrollTo(index)} aria-label={`Slide ${index + 1}`} />
))}
</div>
<CarouselPrevious className="hover:bg-black ml-2" />
<CarouselNext className="hover:bg-black mr-2" />
</Carousel>
) : (
<p className="flex items-center justify-center">
<Image
width={1920}
height={1080}
src="/assets/empty-data.png"
alt="empty"
className="h-52 w-52 my-4"
/>
<Image width={1920} height={1080} src="/assets/empty-data.png" alt="empty" className="h-52 w-52 my-4" />
</p>
)
) : selectedTab == "video" ? (
newContent?.length > 0 ? (
<Carousel className="w-full max-w-7xl mx-auto">
<Carousel setApi={setApi} className="w-full mx-auto">
<CarouselContent>
{newContent?.map((video: any) => (
<CarouselItem
key={video?.id}
className="md:basis-1/2 lg:basis-1/3"
>
<div
onClick={() =>
router.push(
prefixPath + `/video/detail/${video?.slug}`
)
}
className="cursor-pointer relative group rounded-md overflow-hidden shadow-md hover:shadow-lg"
>
<Image
placeholder={`data:image/svg+xml;base64,${toBase64(
shimmer(700, 475)
)}`}
alt="video"
width={2560}
height={1440}
src={video?.thumbnailLink}
className="w-full h-40 lg:h-60 object-cover rounded-lg group-hover:scale-100 transition-transform duration-300"
/>
<div className="absolute bottom-0 rounded-lg left-0 right-0 border-l-4 border-[#bb3523] bg-gray-600 text-white p-2">
<p className="text-sm lg:text-base mb-2 font-semibold h-6 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible">
{video?.title}
</p>
<p className="flex flex-row items-center text-[10px] gap-1">
{formatDateToIndonesian(
new Date(video?.createdAt)
)}{" "}
{video?.timezone ? video?.timezone : "WIB"}|{" "}
<Icon
icon="formkit:eye"
width="15"
height="15"
/>{" "}
{video?.clickCount}{" "}
</p>
<CarouselItem key={video?.id} className="md:basis-1/2 lg:basis-1/3">
<div onClick={() => router.push(prefixPath + `/video/detail/${video?.slug}`)} className="cursor-pointer relative group overflow-hidden bg-white rounded-xl shadow-md hover:shadow-lg transition-shadow duration-300">
{/* Image with motion effect */}
<motion.div className="w-full h-48 lg:h-60" whileHover={{ scale: 0.95 }} transition={{ duration: 0.3 }}>
<Image placeholder={`data:image/svg+xml;base64,${toBase64(shimmer(700, 475))}`} alt="video" width={2560} height={1440} src={video?.thumbnailLink} className="w-full h-full object-cover" />
</motion.div>
{/* Badge category */}
{/* <div className="absolute top-2 left-2 bg-white px-2 py-1 rounded-sm text-[10px] font-bold text-[#bb3523]">{video?.category?.toUpperCase() ?? "VIDEO"}</div> */}
{/* Red icon overlay */}
<div className="absolute top-2 right-2 bg-[#bb3523] rounded-full p-1">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="white"
d="M20 6a2 2 0 0 1 2 2v11.333a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2zm-8.268 7.944L7.136 18.54l-.066.06l-.07.054v.68h13v-.68l-.07-.053l-.066-.06l-2.24-2.24l-.353.354l.055.055a1 1 0 0 1-1.32 1.497l-.094-.083zM17 3a2 2 0 0 1 1.995 1.85L19 5H5a1 1 0 0 0-.993.883L4 6v12a2 2 0 0 1-1.995-1.85L2 16V6a3 3 0 0 1 2.824-2.995L5 3zm3 5H7v7.848L10.848 12a1.25 1.25 0 0 1 1.768 0l3.241 3.24l.884-.883a1.25 1.25 0 0 1 1.768 0L20 15.848zm-3.5 1.5a1.5 1.5 0 1 1 0 3a1.5 1.5 0 0 1 0-3"
/>
</g>
</svg>{" "}
</div>
{/* Caption section */}
<div className="p-4">
<p className="text-[12px] font-bold text-[#bb3523] uppercase mb-1">{video?.categoryName?.toUpperCase() ?? "Video"}</p>
<p className="text-lg font-semibold text-black truncate">{video?.title}</p>
{/* <p className="flex flex-row items-center text-[10px] gap-1 mt-2 text-gray-600">
{formatDateToIndonesian(new Date(video?.createdAt))} {video?.timezone ?? "WIB"} |
<Icon icon="formkit:eye" width="15" height="15" /> {video?.clickCount}
</p> */}
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
{/* Pagination Dots */}
<div className="flex justify-center mt-4">
{Array.from({ length: count }).map((_, index) => (
<button key={index} className={`w-3 h-3 mx-1 rounded-full ${index === current ? "bg-gray-800" : "bg-gray-300"}`} onClick={() => api?.scrollTo(index)} aria-label={`Slide ${index + 1}`} />
))}
</div>
<CarouselPrevious className="hover:bg-black ml-2" />
<CarouselNext className="hover:bg-black mr-2" />
</Carousel>
) : (
<p className="flex items-center justify-center">
<Image
width={1920}
height={1080}
src="/assets/empty-data.png"
alt="empty"
className="h-52 w-52 my-4"
/>
<Image width={1920} height={1080} src="/assets/empty-data.png" alt="empty" className="h-52 w-52 my-4" />
</p>
)
) : newContent.length > 0 ? (
<Carousel className="w-full max-w-7xl mx-auto">
<Carousel setApi={setApi} className="w-full max-w-7xl mx-auto">
<CarouselContent>
{newContent?.map((text: any) => (
<CarouselItem
key={text?.id}
className="md:basis-1/2 lg:basis-1/3"
>
<div className="md:basis-1/2 lg:basis-1/3">
<div
onClick={() =>
router.push(
prefixPath + `/document/detail/${text?.slug}`
)
}
className="flex flex-row bg-yellow-500 sm:flex-row items-center dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4"
>
<div className="flex items-center justify-center rounded-lg w-16 h-2 lg:h-16">
<svg
width="28"
height="34"
viewBox="0 0 28 34"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.6665 17.4167C5.6665 17.0851 5.7982 16.7672 6.03262 16.5328C6.26704 16.2984 6.58498 16.1667 6.9165 16.1667C7.24802 16.1667 7.56597 16.2984 7.80039 16.5328C8.03481 16.7672 8.1665 17.0851 8.1665 17.4167C8.1665 17.7482 8.03481 18.0661 7.80039 18.3005C7.56597 18.535 7.24802 18.6667 6.9165 18.6667C6.58498 18.6667 6.26704 18.535 6.03262 18.3005C5.7982 18.0661 5.6665 17.7482 5.6665 17.4167ZM6.9165 21.1667C6.58498 21.1667 6.26704 21.2984 6.03262 21.5328C5.7982 21.7672 5.6665 22.0851 5.6665 22.4167C5.6665 22.7482 5.7982 23.0661 6.03262 23.3005C6.26704 23.535 6.58498 23.6667 6.9165 23.6667C7.24802 23.6667 7.56597 23.535 7.80039 23.3005C8.03481 23.0661 8.1665 22.7482 8.1665 22.4167C8.1665 22.0851 8.03481 21.7672 7.80039 21.5328C7.56597 21.2984 7.24802 21.1667 6.9165 21.1667ZM5.6665 27.4167C5.6665 27.0851 5.7982 26.7672 6.03262 26.5328C6.26704 26.2984 6.58498 26.1667 6.9165 26.1667C7.24802 26.1667 7.56597 26.2984 7.80039 26.5328C8.03481 26.7672 8.1665 27.0851 8.1665 27.4167C8.1665 27.7482 8.03481 28.0661 7.80039 28.3005C7.56597 28.535 7.24802 28.6667 6.9165 28.6667C6.58498 28.6667 6.26704 28.535 6.03262 28.3005C5.7982 28.0661 5.6665 27.7482 5.6665 27.4167ZM11.9165 16.1667C11.585 16.1667 11.267 16.2984 11.0326 16.5328C10.7982 16.7672 10.6665 17.0851 10.6665 17.4167C10.6665 17.7482 10.7982 18.0661 11.0326 18.3005C11.267 18.535 11.585 18.6667 11.9165 18.6667H21.0832C21.4147 18.6667 21.7326 18.535 21.9671 18.3005C22.2015 18.0661 22.3332 17.7482 22.3332 17.4167C22.3332 17.0851 22.2015 16.7672 21.9671 16.5328C21.7326 16.2984 21.4147 16.1667 21.0832 16.1667H11.9165ZM10.6665 22.4167C10.6665 22.0851 10.7982 21.7672 11.0326 21.5328C11.267 21.2984 11.585 21.1667 11.9165 21.1667H21.0832C21.4147 21.1667 21.7326 21.2984 21.9671 21.5328C22.2015 21.7672 22.3332 22.0851 22.3332 22.4167C22.3332 22.7482 22.2015 23.0661 21.9671 23.3005C21.7326 23.535 21.4147 23.6667 21.0832 23.6667H11.9165C11.585 23.6667 11.267 23.535 11.0326 23.3005C10.7982 23.0661 10.6665 22.7482 10.6665 22.4167ZM11.9165 26.1667C11.585 26.1667 11.267 26.2984 11.0326 26.5328C10.7982 26.7672 10.6665 27.0851 10.6665 27.4167C10.6665 27.7482 10.7982 28.0661 11.0326 28.3005C11.267 28.535 11.585 28.6667 11.9165 28.6667H21.0832C21.4147 28.6667 21.7326 28.535 21.9671 28.3005C22.2015 28.0661 22.3332 27.7482 22.3332 27.4167C22.3332 27.0851 22.2015 26.7672 21.9671 26.5328C21.7326 26.2984 21.4147 26.1667 21.0832 26.1667H11.9165ZM26.3565 11.0233L16.6415 1.31C16.6157 1.28605 16.5885 1.26378 16.5598 1.24333C16.5392 1.22742 16.5192 1.21074 16.4998 1.19333C16.3852 1.08512 16.2632 0.984882 16.1348 0.893332C16.0922 0.865802 16.0476 0.841298 16.0015 0.819999L15.9215 0.779999L15.8382 0.731666C15.7482 0.679999 15.6565 0.626665 15.5615 0.586665C15.2296 0.454104 14.8783 0.376423 14.5215 0.356665C14.4885 0.354519 14.4557 0.350625 14.4232 0.344999C14.3779 0.338012 14.3323 0.334114 14.2865 0.333332H3.99984C3.11578 0.333332 2.26794 0.684521 1.64281 1.30964C1.01769 1.93476 0.666504 2.78261 0.666504 3.66667V30.3333C0.666504 31.2174 1.01769 32.0652 1.64281 32.6904C2.26794 33.3155 3.11578 33.6667 3.99984 33.6667H23.9998C24.8839 33.6667 25.7317 33.3155 26.3569 32.6904C26.982 32.0652 27.3332 31.2174 27.3332 30.3333V13.38C27.333 12.496 26.9817 11.6483 26.3565 11.0233ZM24.8332 30.3333C24.8332 30.5543 24.7454 30.7663 24.5891 30.9226C24.4328 31.0789 24.2208 31.1667 23.9998 31.1667H3.99984C3.77882 31.1667 3.56686 31.0789 3.41058 30.9226C3.2543 30.7663 3.1665 30.5543 3.1665 30.3333V3.66667C3.1665 3.44565 3.2543 3.23369 3.41058 3.07741C3.56686 2.92113 3.77882 2.83333 3.99984 2.83333H13.9998V10.3333C13.9998 11.2174 14.351 12.0652 14.9761 12.6904C15.6013 13.3155 16.4491 13.6667 17.3332 13.6667H24.8332V30.3333ZM16.4998 4.70166L22.9632 11.1667H17.3332C17.1122 11.1667 16.9002 11.0789 16.7439 10.9226C16.5876 10.7663 16.4998 10.5543 16.4998 10.3333V4.70166Z"
fill="black"
/>
</svg>
</div>
<CarouselItem key={text?.id} className="md:basis-1/2 lg:basis-1/3">
<div onClick={() => router.push(prefixPath + `/document/detail/${text?.slug}`)} className="cursor-pointer rounded-lg shadow-md overflow-hidden bg-white">
{/* Ikon di tengah dengan latar kuning */}
<div className="bg-[#e0c350] flex items-center justify-center h-[170px] text-white">
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150" viewBox="0 0 16 16">
<path
fill="currentColor"
d="M5 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V5.414a1.5 1.5 0 0 0-.44-1.06L9.647 1.439A1.5 1.5 0 0 0 8.586 1zM4 3a1 1 0 0 1 1-1h3v2.5A1.5 1.5 0 0 0 9.5 6H12v7a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1zm7.793 2H9.5a.5.5 0 0 1-.5-.5V2.207zM7 7.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5M7.5 9a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1zM7 11.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5M5.5 8a.5.5 0 1 0 0-1a.5.5 0 0 0 0 1M6 9.5a.5.5 0 1 1-1 0a.5.5 0 0 1 1 0M5.5 12a.5.5 0 1 0 0-1a.5.5 0 0 0 0 1"
/>
</svg>
</div>
<div className="flex w-full pr-10 flex-col flex-1">
<div className="text-gray-500 dark:text-gray-400 flex flex-row items-center text-xs gap-0 lg:gap-1 mt-1 lg:text-sm">
{formatDateToIndonesian(
new Date(text?.createdAt)
)}
{text?.timezone ? text?.timezone : "WIB"}|
<Icon
icon="formkit:eye"
width="15"
height="15"
/>
{/* Konten bawah */}
<div className="p-4 flex flex-col gap-2">
{/* Kategori merah */}
<div className="text-[12px] font-bold text-red-600 uppercase">{text?.categoryName?.toUpperCase() ?? "Text"}</div>
{/* Judul */}
<div className="font-semibold text-gray-900 text-xl leading-snug line-clamp-2">{text?.title}</div>
{/* Meta info */}
{/* <div className="text-gray-500 flex items-center text-xs gap-2">
<span>
{formatDateToIndonesian(new Date(text?.createdAt))}
{text?.timezone ? text?.timezone : "WIB"}
</span>
<span className="flex items-center gap-1">
<Icon icon="formkit:eye" width={14} height={14} />
{text?.clickCount}
</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 ">
{text?.title}
</div>
<div className="flex gap-2 items-center text-sm text-red-500 dark:text-red-500">
<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 {t("document")}
</div>
</div>
</span>
</div> */}
{/* Download */}
{/* <div className="flex items-center gap-2 text-sm text-red-500 mt-2">
<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 {t("document")}
</div> */}
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
{/* Pagination Dots */}
<div className="flex justify-center mt-4">
{Array.from({ length: count }).map((_, index) => (
<button key={index} className={`w-3 h-3 mx-1 rounded-full ${index === current ? "bg-gray-800" : "bg-gray-300"}`} onClick={() => api?.scrollTo(index)} aria-label={`Slide ${index + 1}`} />
))}
</div>
<CarouselPrevious className="hover:bg-black ml-2" />
<CarouselNext className="hover:bg-black mr-2" />
</Carousel>
) : (
<p className="flex items-center justify-center">
<Image
width={1920}
height={1080}
src="/assets/empty-data.png"
alt="empty"
className="h-52 w-52 my-4"
/>
<Image width={1920} height={1080} src="/assets/empty-data.png" alt="empty" className="h-52 w-52 my-4" />
</p>
)}
</div>
)}
</div>
<div className="flex items-center flex-row justify-center">
<div
onClick={() =>
router.push(
prefixPath + `/${selectedTab}/filter?sortBy=${props.type}`
)
}
className="cursor-pointer border text-[#bb3523] rounded-lg text-sm lg:text-md px-4 py-1 border-[#bb3523]"
>
{/* <div className="flex items-center flex-row justify-center">
<div onClick={() => router.push(prefixPath + `/${selectedTab}/filter?sortBy=${props.type}`)} className="cursor-pointer border text-[#bb3523] rounded-lg text-sm lg:text-md px-4 py-1 border-[#bb3523]">
{t("seeAll")}
</div>
</div>
</div> */}
</Reveal>
</div>
);

View File

@ -0,0 +1,55 @@
"use client";
import Image from "next/image";
import { useParams } from "next/navigation";
const regions = [
{ name: "Polda Aceh", slug: "aceh", logo: "/logo/polda/polda-aceh.png" },
{ name: "Polda Bali", slug: "bali", logo: "/logo/polda/polda-bali.png" },
{ name: "Polda Bangka Belitung", slug: "bangka-belitung", logo: "/logo/polda/polda-bangkabelitung.png" },
{ name: "Polda Banten", slug: "banten", logo: "/logo/polda/polda-banten.png" },
{ name: "Polda Bengkulu", slug: "bengkulu", logo: "/logo/polda/polda-bengkulu.png" },
{ name: "Polda DIY", slug: "di-yogyakarta", logo: "/logo/polda/polda-jogja.png" },
{ name: "Polda Gorontalo", slug: "gorontalo", logo: "/logo/polda/polda-gorontalo.png" },
{ name: "Polda Jambi", slug: "jambi", logo: "/logo/polda/polda-jambi.png" },
{ name: "Polda Jawa Barat", slug: "jawa-barat", logo: "/logo/polda/polda-jawabarat.png" },
{ name: "Polda Jawa Tengah", slug: "jawa-tengah", logo: "/logo/polda/polda-jawatengah.png" },
{ name: "Polda Jawa Timur", slug: "jawa-timur", logo: "/logo/polda/polda-jawatimur.png" },
{ name: "Polda Kalimantan Barat", slug: "kalimantan-barat", logo: "/logo/polda/polda-kalbar.png" },
{ name: "Polda Kalimantan Selatan", slug: "kalimantan-selatan", logo: "/logo/polda/polda-kalsel.png" },
{ name: "Polda Kalimantan Tengah", slug: "kalimantan-tengah", logo: "/logo/polda/polda-kalteng.png" },
{ name: "Polda Kalimantan Timur", slug: "kalimantan-timur", logo: "/logo/polda/polda-kaltim.png" },
{ name: "Polda Kalimantan Utara", slug: "kaltara", logo: "/logo/polda/polda-kaltara.png" },
{ name: "Polda Kepulauan Riau", slug: "kepulauan-riau", logo: "/logo/polda/polda-kepri.png" },
{ name: "Polda Lampung", slug: "lampung", logo: "/logo/polda/polda-lampung.png" },
{ name: "Polda Maluku", slug: "maluku", logo: "/logo/polda/polda-maluku.png" },
{ name: "Polda Maluku Utara", slug: "maluku-utara", logo: "/logo/polda/polda-maluku-utara.png" },
{ name: "Polda Metro Jaya", slug: "metro-jaya", logo: "/logo/polda/polda-metro.png" },
{ name: "Polda NTB", slug: "ntb", logo: "/logo/polda/polda-ntb.png" },
{ name: "Polda NTT", slug: "ntt", logo: "/logo/polda/polda-ntt.png" },
{ name: "Polda Papua", slug: "papua", logo: "/logo/polda/polda-papua.png" },
{ name: "Polda Papua Barat", slug: "papua-barat", logo: "/logo/polda/polda-papua-barat.png" },
{ name: "Polda Riau", slug: "riau", logo: "/logo/polda/polda-riau.png" },
{ name: "Polda Sulawesi Barat", slug: "sulawesi-barat", logo: "/logo/polda/polda-sulbar.png" },
{ name: "Polda Sulawesi Selatan", slug: "sulawesi-selatan", logo: "/logo/polda/polda-sulsel.png" },
{ name: "Polda Sulawesi Tengah", slug: "sulawesi-tengah", logo: "/logo/polda/polda-sulawesi-tengah.png" },
{ name: "Polda Sulawesi Tenggara", slug: "sulawesi-tenggara", logo: "/logo/polda/polda-sulawesi-tenggara.png" },
{ name: "Polda Sulawesi Utara", slug: "sulawesi-utara", logo: "/logo/polda/polda-sulawesi-utara.png" },
{ name: "Polda Sumatera Barat", slug: "sumatera-barat", logo: "/logo/polda/polda-sumatera-barat.png" },
{ name: "Polda Sumatera Selatan", slug: "sumatera-selatan", logo: "/logo/polda/polda-sumsel.png" },
{ name: "Polda Sumatera Utara", slug: "sumatera-utara", logo: "/logo/polda/polda-sumut.png" },
];
export default function PoldaLogo() {
const params = useParams();
const poldaSlug = params?.slug ?? ""; // pastikan kamu di route [slug] atau [poldaSlug]
const region = regions.find((r) => r.slug === poldaSlug);
const logoSrc = region?.logo ?? "/logo/polda/default.png";
return (
<div className="flex justify-center items-center my-6">
<Image src={logoSrc} alt={region?.name || "Logo Polda"} width={128} height={128} className="object-contain" priority />
</div>
);
}

View File

@ -0,0 +1,115 @@
import search from "@/app/[locale]/(protected)/app/chat/components/search";
import { useTranslations } from "next-intl";
import { useParams, useRouter } from "next/navigation";
import router from "next/router";
import React, { useEffect, useState } from "react";
import { Icon } from "@iconify/react/dist/iconify.js";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import Image from "next/image";
import { getHeroData } from "@/service/landing/landing";
import { title } from "process";
import { htmlToString } from "@/utils/globals";
import { Link } from "@/i18n/routing";
const ScrollableContentPolda = () => {
const [contentType, setContentType] = useState("all");
const [search, setSearch] = useState("");
const router = useRouter();
const params = useParams();
const locale = params?.locale;
const t = useTranslations("LandingPage");
const poldaName: any = params?.polda_name;
const [content, setContent] = useState<any>();
useEffect(() => {
async function fetchCategories() {
const url = "https://netidhub.com/api/csrf";
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error: ", error);
}
}
fetchCategories();
initFetch();
}, []);
const initFetch = async () => {
const response = await getHeroData();
console.log(response);
let data = response?.data?.data?.content;
setContent(data);
};
return (
<>
<div className="">
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 dark:text-white">
<span className="text-[#c03724] dark:text-white">
{t("welcome")} Polda {poldaName?.replace("-", " ")}
</span>
{/* <span className="text-[#c03724] dark:text-white">
&nbsp;{t("download")}&nbsp;{t("coverage")}
</span>{" "} */}
</h1>
<div className="w-[10%] h-1 bg-[#bb3523] mt-2"></div>
<div className="w-full h-1 bg-[#bb3523] mx-auto"></div>
<p className="text-sm md:text-base text-black dark:text-gray-100 mt-4">
{t("officialPolda")} {poldaName?.replace("-", " ")}
</p>
<div className="mt-6 flex flex-col md:flex-row justify-center gap-4">
<div className="flex flex-row items-center w-full rounded-lg gap-2 overflow-hidden">
<Select value={contentType} onValueChange={setContentType}>
<SelectTrigger className="w-[180px] h-[55px]">
<span className="text-black">
<svg className="mx-2 dark:" width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M20 7.5H5C4.6023 7.5004 4.221 7.65856 3.93978 7.93978C3.65856 8.221 3.5004 8.6023 3.5 9V19.5C3.5004 19.8977 3.65856 20.279 3.93978 20.5602C4.221 20.8414 4.6023 20.9996 5 21H20C20.3977 20.9996 20.779 20.8414 21.0602 20.5602C21.3414 20.279 21.4996 19.8977 21.5 19.5V9C21.4996 8.6023 21.3414 8.221 21.0602 7.93978C20.779 7.65856 20.3977 7.5004 20 7.5ZM10.25 17.25V11.25L15.5 14.25L10.25 17.25ZM5 4.5H20V6H5V4.5ZM6.5 1.5H18.5V3H6.5V1.5Z"
fill="currentColor"
/>
</svg>
</span>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="all">{t("allContent")}</SelectItem>
<SelectItem value="image">{t("image")}</SelectItem>
<SelectItem value="video">{t("video")}</SelectItem>
<SelectItem value="document">{t("text")}</SelectItem>
<SelectItem value="audio">{t("audio")}</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<div className="flex items-center flex-1 border border-gray-300 rounded-lg overflow-hidden">
<span className="material-icons text-black dark:text-white px-4">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path
fill="currentColor"
d="m19.6 21l-6.3-6.3q-.75.6-1.725.95T9.5 16q-2.725 0-4.612-1.888T3 9.5t1.888-4.612T9.5 3t4.613 1.888T16 9.5q0 1.1-.35 2.075T14.7 13.3l6.3 6.3zM9.5 14q1.875 0 3.188-1.312T14 9.5t-1.312-3.187T9.5 5T6.313 6.313T5 9.5t1.313 3.188T9.5 14"
/>
</svg>
</span>
<input type="text" placeholder={t("searchCoverageHere")} className="w-full py-4 px-2 text-sm text-gray-700 dark:text-gray-100 focus:outline-none" onChange={(e) => setSearch(e.target.value)} />
</div>
</div>
<button onClick={() => router.push(`/${contentType}/filter?title=${search}`)} className="flex justify-center items-center px-6 w-full lg:w-[20%] py-4 bg-[#bb3523] gap-2 text-white rounded-lg hover:bg-red-700">
{t("searchCoverage")}
<Icon icon="ri:arrow-right-s-line" fontSize={20} />
</button>
</div>
</div>
</>
);
};
export default ScrollableContentPolda;

View File

@ -0,0 +1,115 @@
import search from "@/app/[locale]/(protected)/app/chat/components/search";
import { useTranslations } from "next-intl";
import { useParams, useRouter } from "next/navigation";
import router from "next/router";
import React, { useEffect, useState } from "react";
import { Icon } from "@iconify/react/dist/iconify.js";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import Image from "next/image";
import { getHeroData } from "@/service/landing/landing";
import { title } from "process";
import { htmlToString } from "@/utils/globals";
import { Link } from "@/i18n/routing";
const ScrollableContentSatker = () => {
const [contentType, setContentType] = useState("all");
const [search, setSearch] = useState("");
const router = useRouter();
const params = useParams();
const locale = params?.locale;
const t = useTranslations("LandingPage");
const satkerName: any = params?.satker_name;
const [content, setContent] = useState<any>();
useEffect(() => {
async function fetchCategories() {
const url = "https://netidhub.com/api/csrf";
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Fetch error: ", error);
}
}
fetchCategories();
initFetch();
}, []);
const initFetch = async () => {
const response = await getHeroData();
console.log(response);
let data = response?.data?.data?.content;
setContent(data);
};
return (
<>
<div className="">
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 dark:text-white">
<span className="text-[#c03724] dark:text-white">
{t("welcome")} Polda {satkerName?.replace("-", " ")}
</span>
{/* <span className="text-[#c03724] dark:text-white">
&nbsp;{t("download")}&nbsp;{t("coverage")}
</span>{" "} */}
</h1>
<div className="w-[10%] h-1 bg-[#bb3523] mt-2"></div>
<div className="w-full h-1 bg-[#bb3523] mx-auto"></div>
<p className="text-sm md:text-base text-black dark:text-gray-100 mt-4">
{t("officialPolda")} {satkerName?.replace("-", " ")}
</p>
<div className="mt-6 flex flex-col md:flex-row justify-center gap-4">
<div className="flex flex-row items-center w-full rounded-lg gap-2 overflow-hidden">
<Select value={contentType} onValueChange={setContentType}>
<SelectTrigger className="w-[180px] h-[55px]">
<span className="text-black">
<svg className="mx-2 dark:" width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M20 7.5H5C4.6023 7.5004 4.221 7.65856 3.93978 7.93978C3.65856 8.221 3.5004 8.6023 3.5 9V19.5C3.5004 19.8977 3.65856 20.279 3.93978 20.5602C4.221 20.8414 4.6023 20.9996 5 21H20C20.3977 20.9996 20.779 20.8414 21.0602 20.5602C21.3414 20.279 21.4996 19.8977 21.5 19.5V9C21.4996 8.6023 21.3414 8.221 21.0602 7.93978C20.779 7.65856 20.3977 7.5004 20 7.5ZM10.25 17.25V11.25L15.5 14.25L10.25 17.25ZM5 4.5H20V6H5V4.5ZM6.5 1.5H18.5V3H6.5V1.5Z"
fill="currentColor"
/>
</svg>
</span>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="all">{t("allContent")}</SelectItem>
<SelectItem value="image">{t("image")}</SelectItem>
<SelectItem value="video">{t("video")}</SelectItem>
<SelectItem value="document">{t("text")}</SelectItem>
<SelectItem value="audio">{t("audio")}</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<div className="flex items-center flex-1 border border-gray-300 rounded-lg overflow-hidden">
<span className="material-icons text-black dark:text-white px-4">
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path
fill="currentColor"
d="m19.6 21l-6.3-6.3q-.75.6-1.725.95T9.5 16q-2.725 0-4.612-1.888T3 9.5t1.888-4.612T9.5 3t4.613 1.888T16 9.5q0 1.1-.35 2.075T14.7 13.3l6.3 6.3zM9.5 14q1.875 0 3.188-1.312T14 9.5t-1.312-3.187T9.5 5T6.313 6.313T5 9.5t1.313 3.188T9.5 14"
/>
</svg>
</span>
<input type="text" placeholder={t("searchCoverageHere")} className="w-full py-4 px-2 text-sm text-gray-700 dark:text-gray-100 focus:outline-none" onChange={(e) => setSearch(e.target.value)} />
</div>
</div>
<button onClick={() => router.push(`/${contentType}/filter?title=${search}`)} className="flex justify-center items-center px-6 w-full lg:w-[20%] py-4 bg-[#bb3523] gap-2 text-white rounded-lg hover:bg-red-700">
{t("searchCoverage")}
<Icon icon="ri:arrow-right-s-line" fontSize={20} />
</button>
</div>
</div>
</>
);
};
export default ScrollableContentSatker;

View File

@ -4,14 +4,7 @@ import { useParams, useRouter } from "next/navigation";
import router from "next/router";
import React, { useEffect, useState } from "react";
import { Icon } from "@iconify/react/dist/iconify.js";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import Image from "next/image";
import { getHeroData } from "@/service/landing/landing";
import { title } from "process";
@ -57,26 +50,31 @@ const ScrollableContent = () => {
};
return (
<>
<div className="text-center">
<div className="">
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 dark:text-white">
<span className="text-[#bb3523] dark:text-white">
{t("exploration")}
<span className="text-[#c03724] dark:text-white">
{t("exploration")}&nbsp;{t("and")}
</span>
<span className="text-[#c03724] dark:text-white">
&nbsp;{t("download")}&nbsp;{t("coverage")}
</span>{" "}
{t("and")}{" "}
<span className="text-[#bb3523] dark:text-white">
{t("download")}
</span>{" "}
{t("coverage")}{" "}
</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">
{t("officialCoverage")}
</p>
<div className="w-[10%] h-1 bg-[#bb3523] mt-2"></div>
<div className="w-full h-1 bg-[#bb3523] mx-auto"></div>
<p className="text-sm md:text-base text-black dark:text-gray-100 mt-4">{t("officialCoverage")}</p>
<div className="mt-6 flex flex-col md:flex-row justify-center gap-4">
<div className="flex flex-row items-center w-full rounded-lg gap-2 overflow-hidden">
<Select value={contentType} onValueChange={setContentType}>
<SelectTrigger className="w-[180px]">
<SelectTrigger className="w-[180px] h-[55px]">
<span className="text-black">
<svg className="mx-2 dark:" width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M20 7.5H5C4.6023 7.5004 4.221 7.65856 3.93978 7.93978C3.65856 8.221 3.5004 8.6023 3.5 9V19.5C3.5004 19.8977 3.65856 20.279 3.93978 20.5602C4.221 20.8414 4.6023 20.9996 5 21H20C20.3977 20.9996 20.779 20.8414 21.0602 20.5602C21.3414 20.279 21.4996 19.8977 21.5 19.5V9C21.4996 8.6023 21.3414 8.221 21.0602 7.93978C20.779 7.65856 20.3977 7.5004 20 7.5ZM10.25 17.25V11.25L15.5 14.25L10.25 17.25ZM5 4.5H20V6H5V4.5ZM6.5 1.5H18.5V3H6.5V1.5Z"
fill="currentColor"
/>
</svg>
</span>
<SelectValue />
</SelectTrigger>
<SelectContent>
@ -91,55 +89,32 @@ const ScrollableContent = () => {
</Select>
<div className="flex items-center flex-1 border border-gray-300 rounded-lg overflow-hidden">
<span className="material-icons text-black dark:text-white px-4">
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
>
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
<path
fill="currentColor"
d="m19.6 21l-6.3-6.3q-.75.6-1.725.95T9.5 16q-2.725 0-4.612-1.888T3 9.5t1.888-4.612T9.5 3t4.613 1.888T16 9.5q0 1.1-.35 2.075T14.7 13.3l6.3 6.3zM9.5 14q1.875 0 3.188-1.312T14 9.5t-1.312-3.187T9.5 5T6.313 6.313T5 9.5t1.313 3.188T9.5 14"
/>
</svg>
</span>
<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"
onChange={(e) => setSearch(e.target.value)}
/>
<input type="text" placeholder={t("searchCoverageHere")} className="w-full py-4 px-2 text-sm text-gray-700 dark:text-gray-100 focus:outline-none" onChange={(e) => setSearch(e.target.value)} />
</div>
</div>
<button
onClick={() =>
router.push(`/${contentType}/filter?title=${search}`)
}
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"
>
<button onClick={() => router.push(`/${contentType}/filter?title=${search}`)} className="flex justify-center items-center px-6 w-full lg:w-[20%] py-4 bg-[#bb3523] gap-2 text-white rounded-lg hover:bg-red-700">
{t("searchCoverage")}
<Icon icon="ri:arrow-right-s-line" fontSize={20} />
</button>
</div>
</div>
<div className="flex flex-col md:flex-row gap-6 py-8">
{/* Berita Polda */}
<div className="w-full md:w-1/2 px-4">
<h2 className="text-lg md:text-xl font-bold text-[#bb3523] border-b-2 border-[#bb3523] mb-4 uppercase">
Berita Polda
</h2>
<h2 className="text-lg md:text-xl font-bold text-[#bb3523] mb-2 uppercase">Berita Polda</h2>
<div className="w-[10%] h-1 bg-[#bb3523]"></div>
<div className="w-full h-1 bg-[#bb3523] mx-auto mb-4"></div>
<div className="grid gap-4">
{content?.slice(0, 4).map((item: any, index: number) => (
<div
key={index}
className={`bg-white rounded-lg shadow-md overflow-hidden ${
index === 0 ? "" : "flex"
}`}
>
<div
className={`relative ${
index === 0 ? "w-full h-48" : " w-1/2 h-[150px]"
}`}
>
<div key={index} className={`bg-white rounded-lg shadow-md overflow-hidden ${index === 0 ? "" : "flex"}`}>
<div className={`relative ${index === 0 ? "w-full h-48" : " w-1/2 h-[150px]"}`}>
<Link
href={
Number(item?.fileTypeId) == 1
@ -151,21 +126,16 @@ const ScrollableContent = () => {
: `${locale}/audio/detail/${item?.slug}`
}
>
<Image
src={item.thumbnailLink}
alt={item.title}
layout="fill"
objectFit="cover"
/>
<div className="absolute top-2 right-2 bg-white rounded-full p-1 shadow">
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.5em"
height="1.5em"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2m-2 0H5V5h14ZM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5Z" />
<Image src={item.thumbnailLink} alt={item.title} layout="fill" objectFit="cover" />
<div className="absolute top-2 right-2 bg-[#c03724] rounded-full p-1 shadow">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="white"
d="M20 6a2 2 0 0 1 2 2v11.333a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2zm-8.268 7.944L7.136 18.54l-.066.06l-.07.054v.68h13v-.68l-.07-.053l-.066-.06l-2.24-2.24l-.353.354l.055.055a1 1 0 0 1-1.32 1.497l-.094-.083zM17 3a2 2 0 0 1 1.995 1.85L19 5H5a1 1 0 0 0-.993.883L4 6v12a2 2 0 0 1-1.995-1.85L2 16V6a3 3 0 0 1 2.824-2.995L5 3zm3 5H7v7.848L10.848 12a1.25 1.25 0 0 1 1.768 0l3.241 3.24l.884-.883a1.25 1.25 0 0 1 1.768 0L20 15.848zm-3.5 1.5a1.5 1.5 0 1 1 0 3a1.5 1.5 0 0 1 0-3"
/>
</g>
</svg>
</div>
</Link>
@ -182,46 +152,35 @@ const ScrollableContent = () => {
}
> */}
<div className={`${index === 0 ? "p-4" : "p-3 w-[50%]"}`}>
<p className="text-sm text-[#bb3523] font-bold mb-1">
{item.categoryName}
</p>
<h3 className="text-sm font-semibold text-gray-800">
{item.title}
</h3>
<p className="text-xs text-gray-500 mt-1 truncate">
{htmlToString(item.description)}
</p>
<p className="text-sm text-[#bb3523] font-bold mb-1">{item.categoryName}</p>
<h3 className="text-sm font-semibold text-gray-800">{item.title}</h3>
<p className="text-xs text-gray-500 mt-1 truncate">{htmlToString(item.description)}</p>
</div>
{/* </Link> */}
</div>
))}
<button className="w-full mt-2 py-2 border border-[#bb3523] text-[#bb3523] rounded-lg font-semibold hover:bg-[#bb3523] hover:text-white transition">
LIHAT SEMUA
</button>
<button className="w-fit px-2 mt-2 py-2 border flex flex-row gap-2 border-[#bb3523] bg-white text-[#bb3523] rounded-lg font-semibold hover:bg-[#bb3523] hover:border-white hover:text-white transition">
LEBIH SEDIKIT
<span className="text-[#bb3523] hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="m10 17l5-5m0 0l-5-5" />
</svg>
</span>
</button>{" "}
</div>
</div>
{/* Berita SATKER */}
<div className="w-full md:w-1/2 px-4">
<h2 className="text-lg md:text-xl font-bold text-[#bb3523] border-b-2 border-[#bb3523] mb-4 uppercase">
Berita Satker
</h2>
<h2 className="text-lg md:text-xl font-bold mb-2 text-[#bb3523] uppercase">Berita Satker</h2>
<div className="w-[10%] h-1 bg-[#bb3523]"></div>
<div className="w-full h-1 bg-[#bb3523] mx-auto mb-4"></div>
<div className="grid gap-4">
{content
?.filter((item: any) => item.isPublishOnPolda === true)
.slice(0, 4)
.map((item: any, index: number) => (
<div
key={index}
className={`bg-white rounded-lg shadow-md overflow-hidden ${
index === 0 ? "" : "flex"
}`}
>
<div
className={`relative ${
index === 0 ? "w-full h-48" : " w-1/2 h-[150px]"
}`}
>
<div key={index} className={`bg-white rounded-lg shadow-md overflow-hidden ${index === 0 ? "" : "flex"}`}>
<div className={`relative ${index === 0 ? "w-full h-48" : " w-1/2 h-[150px]"}`}>
<Link
href={
Number(item?.fileTypeId) == 1
@ -233,40 +192,34 @@ const ScrollableContent = () => {
: `${locale}/audio/detail/${item?.slug}`
}
>
<Image
src={item.thumbnailLink}
alt={item.title}
layout="fill"
objectFit="cover"
/>
<div className="absolute top-2 right-2 bg-white rounded-full p-1 shadow">
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.5em"
height="1.5em"
viewBox="0 0 24 24"
fill="currentColor"
>
<path d="M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2m-2 0H5V5h14ZM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5Z" />
<Image src={item.thumbnailLink} alt={item.title} layout="fill" objectFit="cover" />
<div className="absolute top-2 right-2 bg-[#c03724] rounded-full p-1 shadow">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none">
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
<path
fill="white"
d="M20 6a2 2 0 0 1 2 2v11.333a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2zm-8.268 7.944L7.136 18.54l-.066.06l-.07.054v.68h13v-.68l-.07-.053l-.066-.06l-2.24-2.24l-.353.354l.055.055a1 1 0 0 1-1.32 1.497l-.094-.083zM17 3a2 2 0 0 1 1.995 1.85L19 5H5a1 1 0 0 0-.993.883L4 6v12a2 2 0 0 1-1.995-1.85L2 16V6a3 3 0 0 1 2.824-2.995L5 3zm3 5H7v7.848L10.848 12a1.25 1.25 0 0 1 1.768 0l3.241 3.24l.884-.883a1.25 1.25 0 0 1 1.768 0L20 15.848zm-3.5 1.5a1.5 1.5 0 1 1 0 3a1.5 1.5 0 0 1 0-3"
/>
</g>
</svg>
</div>
</Link>
</div>
<div className={`${index === 0 ? "p-4" : "p-3 w-[50%]"}`}>
<p className="text-sm text-[#bb3523] font-bold mb-1">
{item.categoryName}
</p>
<h3 className="text-sm font-semibold text-gray-800">
{item.title}
</h3>
<p className="text-xs text-gray-500 mt-1 truncate">
{htmlToString(item.description)}
</p>
<p className="text-sm text-[#bb3523] font-bold mb-1">{item.categoryName}</p>
<h3 className="text-sm font-semibold text-gray-800">{item.title}</h3>
<p className="text-xs text-gray-500 mt-1 truncate">{htmlToString(item.description)}</p>
</div>
</div>
))}
<button className="w-full mt-2 py-2 border border-[#bb3523] text-[#bb3523] rounded-lg font-semibold hover:bg-[#bb3523] hover:text-white transition">
LIHAT SEMUA
<button className="w-fit px-2 mt-2 py-2 border flex flex-row gap-2 border-[#bb3523] bg-white text-[#bb3523] rounded-lg font-semibold hover:bg-[#bb3523] hover:text-white transition">
LEBIH SEDIKIT
<span className="text-[#bb3523] hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="m10 17l5-5m0 0l-5-5" />
</svg>
</span>
</button>
</div>
</div>

View File

@ -0,0 +1,58 @@
import search from "@/app/[locale]/(protected)/app/chat/components/search";
import { Select, SelectTrigger, SelectValue, SelectContent, SelectGroup, SelectItem } from "@radix-ui/react-select";
import { Icon } from "lucide-react";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
import router from "next/router";
import React, { useState } from "react";
import ScrollableContent from "./search-section-new";
import NewContent from "./new-content";
import ContentCategory from "./content-category";
import AreaCoverageWorkUnits from "./area-coverage-and-work-units";
import EventCalender from "./event-calender";
import UserSurveyBox from "./survey-box";
import ScrollableContentPolda from "./scrollable-content-polda";
const LeftBanner = () => (
<div className="sticky top-0 space-y-4">
<img src="/images/all-img/kiri1.png" alt="Banner Kiri 1" />
<img src="/images/all-img/kiri2.png" alt="Banner Kiri 2" />
</div>
);
const RightBanner = () => (
<div className="sticky top-0 space-y-4">
<img src="/images/all-img/kanan2.png" alt="Banner Kanan 1" />
<img src="/images/all-img/kanan1.png" alt="Banner Kanan 2" />
</div>
);
const SearchSectionPolda = () => {
const [contentType, setContentType] = useState("all");
const [search, setSearch] = useState("");
const router = useRouter();
const t = useTranslations("LandingPage");
return (
<div className="flex w-full min-h-screen bg-center bg-cover bg-no-repeat" style={{ backgroundImage: "url('/assets/background.png')" }}>
<div className="hidden xl:block w-[15%] pr-4 py-5 sticky top-[150px] space-y-4 self-start">
<LeftBanner />
</div>
<div className="w-full xl:w-[70%] px-4 py-8 bg-white">
<ScrollableContentPolda />
<NewContent group="polda" type="latest" />
<NewContent group="polda" type="popular" />
<ContentCategory group="polda" type="popular" />
<AreaCoverageWorkUnits />
<EventCalender />
<UserSurveyBox />
</div>
<div className="hidden xl:block w-[15%] pl-4 py-5 sticky top-[150px] space-y-4 self-start">
<RightBanner />
</div>
</div>
);
};
export default SearchSectionPolda;

View File

@ -0,0 +1,59 @@
import search from "@/app/[locale]/(protected)/app/chat/components/search";
import { Select, SelectTrigger, SelectValue, SelectContent, SelectGroup, SelectItem } from "@radix-ui/react-select";
import { Icon } from "lucide-react";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
import router from "next/router";
import React, { useState } from "react";
import ScrollableContent from "./search-section-new";
import NewContent from "./new-content";
import ContentCategory from "./content-category";
import AreaCoverageWorkUnits from "./area-coverage-and-work-units";
import EventCalender from "./event-calender";
import UserSurveyBox from "./survey-box";
import ScrollableContentPolda from "./scrollable-content-polda";
import ScrollableContentSatker from "./scrollable-content-satker";
const LeftBanner = () => (
<div className="sticky top-0 space-y-4">
<img src="/images/all-img/kiri1.png" alt="Banner Kiri 1" />
<img src="/images/all-img/kiri2.png" alt="Banner Kiri 2" />
</div>
);
const RightBanner = () => (
<div className="sticky top-0 space-y-4">
<img src="/images/all-img/kanan2.png" alt="Banner Kanan 1" />
<img src="/images/all-img/kanan1.png" alt="Banner Kanan 2" />
</div>
);
const SearchSectionSatker = () => {
const [contentType, setContentType] = useState("all");
const [search, setSearch] = useState("");
const router = useRouter();
const t = useTranslations("LandingPage");
return (
<div className="flex w-full min-h-screen bg-center bg-cover bg-no-repeat" style={{ backgroundImage: "url('/assets/background.png')" }}>
<div className="hidden xl:block w-[15%] pr-4 py-5 sticky top-[150px] space-y-4 self-start">
<LeftBanner />
</div>
<div className="w-full xl:w-[70%] px-4 py-8 bg-white">
<ScrollableContentSatker />
<NewContent group="satker" type="latest" />
<NewContent group="satker" type="popular" />
<ContentCategory group="satker" type="popular" />
<AreaCoverageWorkUnits />
<EventCalender />
<UserSurveyBox />
</div>
<div className="hidden xl:block w-[15%] pl-4 py-5 sticky top-[150px] space-y-4 self-start">
<RightBanner />
</div>
</div>
);
};
export default SearchSectionSatker;

View File

@ -1,12 +1,5 @@
import search from "@/app/[locale]/(protected)/app/chat/components/search";
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectGroup,
SelectItem,
} from "@radix-ui/react-select";
import { Select, SelectTrigger, SelectValue, SelectContent, SelectGroup, SelectItem } from "@radix-ui/react-select";
import { Icon } from "lucide-react";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
@ -18,6 +11,7 @@ import ContentCategory from "./content-category";
import AreaCoverageWorkUnits from "./area-coverage-and-work-units";
import EventCalender from "./event-calender";
import UserSurveyBox from "./survey-box";
import ScrollableContentPolda from "./scrollable-content-polda";
const LeftBanner = () => (
<div className="sticky top-0 space-y-4">
@ -39,12 +33,12 @@ const SearchSection = () => {
const router = useRouter();
const t = useTranslations("LandingPage");
return (
<div className="flex w-full min-h-screen bg-gray-100 dark:bg-zinc-800">
<div className="flex w-full min-h-screen bg-center bg-cover bg-no-repeat" style={{ backgroundImage: "url('/assets/background.png')" }}>
<div className="hidden xl:block w-[15%] pr-4 py-5 sticky top-[150px] space-y-4 self-start">
<LeftBanner />
</div>
<div className="w-full xl:w-[70%] px-4 py-8">
<div className="w-full xl:w-[70%] px-4 py-8 bg-white">
<ScrollableContent />
<NewContent group="mabes" type="latest" />
<NewContent group="mabes" type="popular" />

View File

@ -1,13 +1,5 @@
import React, { useState } from "react";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../ui/dialog";
import FormSurvey from "./survey";
import { Controller, useForm } from "react-hook-form";
import { Textarea } from "../ui/textarea";
@ -54,49 +46,16 @@ const UserSurveyBox = () => {
});
const options = {
accessFrequency: [
"Setiap hari",
"Beberapa kali seminggu",
"Beberapa kali dalam sebulan",
"Baru pertama kali",
],
accessFrequency: ["Setiap hari", "Beberapa kali seminggu", "Beberapa kali dalam sebulan", "Baru pertama kali"],
uiExperienceDesign: ["Sangat baik", "Baik", "Cukup", "Kurang", "Buruk"],
uiExperienceNavigation: [
"Sangat mudah",
"Mudah",
"Cukup",
"Sulit",
"Sangat sulit",
],
uiExperienceSpeed: [
"Sangat cepat",
"Cepat",
"Cukup",
"Lambat",
"Sangat lambat",
],
uiExperienceNavigation: ["Sangat mudah", "Mudah", "Cukup", "Sulit", "Sangat sulit"],
uiExperienceSpeed: ["Sangat cepat", "Cepat", "Cukup", "Lambat", "Sangat lambat"],
infoAccuracy: ["Sangat puas", "Puas", "Cukup", "Kurang puas", "Tidak puas"],
infoCompleteness: [
"Sangat lengkap",
"Lengkap",
"Cukup",
"Kurang lengkap",
"Tidak lengkap",
],
usefulness: [
"Sangat membantu",
"Membantu",
"Cukup membantu",
"Kurang membantu",
"Tidak membantu",
],
infoCompleteness: ["Sangat lengkap", "Lengkap", "Cukup", "Kurang lengkap", "Tidak lengkap"],
usefulness: ["Sangat membantu", "Membantu", "Cukup membantu", "Kurang membantu", "Tidak membantu"],
};
const renderControllerGroup = (
name: keyof SurveySchema,
question: string,
choices: string[]
) => (
const renderControllerGroup = (name: keyof SurveySchema, question: string, choices: string[]) => (
<div className="space-y-2">
<p className="font-medium">{question}</p>
<div className="grid grid-cols-2 gap-2">
@ -107,21 +66,14 @@ const UserSurveyBox = () => {
control={control}
render={({ field }) => (
<label className="flex items-center space-x-2">
<Checkbox
checked={field.value === choice}
onCheckedChange={() => field.onChange(choice)}
/>
<Checkbox checked={field.value === choice} onCheckedChange={() => field.onChange(choice)} />
<span>{choice}</span>
</label>
)}
/>
))}
</div>
{errors[name] && (
<p className="text-red-500 text-sm">
{errors[name]?.message as string}
</p>
)}
{errors[name] && <p className="text-red-500 text-sm">{errors[name]?.message as string}</p>}
</div>
);
@ -138,120 +90,81 @@ const UserSurveyBox = () => {
}
};
return (
<div className="mt-8 rounded-lg bg-white dark:bg-zinc-900 p-4 shadow">
<h2 className="text-lg font-bold mb-2">
SURVEI KEPUASAN PENGGUNA MEDIAHUB POLRI
</h2>
<p className="text-sm text-gray-700 dark:text-gray-300 mb-4">
Kami menghargai pendapat Anda! Survei ini bertujuan untuk meningkatkan
kualitas layanan MediaHub Polri. Mohon luangkan waktu beberapa menit
untuk mengisi survei ini.
</p>
<Dialog open={openPolda} onOpenChange={setOpenPolda}>
<DialogTrigger asChild>
<Button
size="md"
onClick={() => setOpenPolda(true)}
className="flex flex-col gap-2 justify-center items-center shadow-lg group rounded-xl py-5 px-24 border-2 bg-[#bb3523] hover:bg-white] transition-all duration-300"
>
<p className="text-base font-bold">Survey Sekarang</p>
</Button>
</DialogTrigger>
<DialogContent
size="md"
className="max-h-[90vh] overflow-auto flex flex-col "
>
<DialogHeader>
<DialogTitle className="text-lg font-bold">
SURVEI KEPUASAN PENGGUNA MEDIAHUB POLRI
</DialogTitle>
<DialogDescription className="text-sm">
Kami menghargai pendapat Anda! Survei ini bertujuan untuk
meningkatkan kualitas layanan MediaHub Polri.
</DialogDescription>
</DialogHeader>
<div className="relative mt-8 rounded-lg bg-white dark:bg-zinc-900 p-6 shadow overflow-hidden">
{/* Garis menyerong */}
<div className="hidden lg:block absolute right-64 top-0">
<img src="/assets/line1.png" alt="line" className="" />
</div>
<div className="hidden lg:block absolute right-60 top-0">
<img src="/assets/line1.png" alt="line" className="" />
</div>
<div className="hidden lg:block absolute right-56 top-0">
<img src="/assets/line1.png" alt="line" className="" />
</div>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6 mt-4">
{renderControllerGroup(
"accessFrequency",
"1. Seberapa sering Anda mengakses MediaHub Polri?",
options.accessFrequency
)}
<div>
<p className="font-medium">
2. Bagaimana pengalaman Anda dalam mengakses website ini?
</p>
<div className="space-y-3 mt-2">
{renderControllerGroup(
"uiExperienceDesign",
"a) Tampilan dan desain website",
options.uiExperienceDesign
)}
{renderControllerGroup(
"uiExperienceNavigation",
"b) Kemudahan navigasi",
options.uiExperienceNavigation
)}
{renderControllerGroup(
"uiExperienceSpeed",
"c) Kecepatan akses website",
options.uiExperienceSpeed
)}
</div>
</div>
<div>
<p className="font-medium">
3. Seberapa puas Anda dengan informasi yang tersedia di MediaHub
Polri?
</p>
<div className="space-y-3 mt-2">
{renderControllerGroup(
"infoAccuracy",
"a) Akurat dan terpercaya",
options.infoAccuracy
)}
{renderControllerGroup(
"infoCompleteness",
"b) Kelengkapan berita dan informasi",
options.infoCompleteness
)}
</div>
</div>
{renderControllerGroup(
"usefulness",
"4. Apakah Anda merasa website ini membantu dalam mendapatkan informasi terkait Polri?",
options.usefulness
)}
<div>
<p className="font-medium">5. Apa saran atau masukan Anda?</p>
<Controller
name="suggestion"
control={control}
render={({ field }) => (
<Textarea
placeholder="Tulis pesan Anda..."
value={field.value}
onChange={field.onChange}
/>
)}
/>
</div>
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={() => setShowSurvey(false)}>
Batal
{/* Grid konten */}
<div className="relative z-10 grid grid-cols-1 md:grid-cols-2 gap-4 items-center">
{/* Kiri: Teks dan tombol */}
<div>
<h2 className="text-2xl font-bold mb-2">SURVEI KEPUASAN PENGGUNA MEDIAHUB POLRI</h2>
<p className="text-sm text-gray-700 dark:text-gray-300 mb-6">Kami menghargai pendapat Anda! Survei ini bertujuan untuk meningkatkan kualitas layanan MediaHub Polri. Mohon luangkan waktu beberapa menit untuk mengisi survei ini.</p>
<Dialog open={openPolda} onOpenChange={setOpenPolda}>
<DialogTrigger asChild>
<Button size="md" onClick={() => setOpenPolda(true)} className="bg-[#bb3523] hover:bg-[#9e2e1e] text-white font-bold px-6 py-3 rounded shadow-md transition-all duration-300">
SURVEY SEKARANG
</Button>
<Button type="submit" disabled={isLoading}>
{isLoading ? "Mengirim..." : "Kirim"}
</Button>
</div>
</form>
</DialogContent>
</Dialog>
</DialogTrigger>
<DialogContent size="md" className="max-h-[90vh] overflow-auto flex flex-col">
<DialogHeader>
<DialogTitle className="text-lg font-bold">SURVEI KEPUASAN PENGGUNA MEDIAHUB POLRI</DialogTitle>
<DialogDescription className="text-sm">Kami menghargai pendapat Anda! Survei ini bertujuan untuk meningkatkan kualitas layanan MediaHub Polri.</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6 mt-4">
{renderControllerGroup("accessFrequency", "1. Seberapa sering Anda mengakses MediaHub Polri?", options.accessFrequency)}
<div>
<p className="font-medium">2. Bagaimana pengalaman Anda dalam mengakses website ini?</p>
<div className="space-y-3 mt-2">
{renderControllerGroup("uiExperienceDesign", "a) Tampilan dan desain website", options.uiExperienceDesign)}
{renderControllerGroup("uiExperienceNavigation", "b) Kemudahan navigasi", options.uiExperienceNavigation)}
{renderControllerGroup("uiExperienceSpeed", "c) Kecepatan akses website", options.uiExperienceSpeed)}
</div>
</div>
<div>
<p className="font-medium">3. Seberapa puas Anda dengan informasi yang tersedia di MediaHub Polri?</p>
<div className="space-y-3 mt-2">
{renderControllerGroup("infoAccuracy", "a) Akurat dan terpercaya", options.infoAccuracy)}
{renderControllerGroup("infoCompleteness", "b) Kelengkapan berita dan informasi", options.infoCompleteness)}
</div>
</div>
{renderControllerGroup("usefulness", "4. Apakah Anda merasa website ini membantu dalam mendapatkan informasi terkait Polri?", options.usefulness)}
<div>
<p className="font-medium">5. Apa saran atau masukan Anda?</p>
<Controller name="suggestion" control={control} render={({ field }) => <Textarea placeholder="Tulis pesan Anda..." value={field.value} onChange={field.onChange} />} />
</div>
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={() => setShowSurvey(false)}>
Batal
</Button>
<Button type="submit" disabled={isLoading}>
{isLoading ? "Mengirim..." : "Kirim"}
</Button>
</div>
</form>
</DialogContent>
</Dialog>
</div>
{/* Kanan: Gambar survey */}
<div className="hidden lg:flex justify-center md:justify-end">
<img src="/assets/survey.png" alt="Survey Illustration" className="w-48 h-auto" />
</div>
</div>
</div>
);
};

View File

@ -26,10 +26,10 @@ const WelcomePolda = () => {
return (
<section className="w-full py-8 px-4 ">
<div className="max-w-screen-xl mx-auto text-center">
<div className="">
{/* Heading */}
<h1 className="text-2xl md:text-3xl font-bold text-gray-800 dark:text-white">
{t("welcome")} <span className="text-[#bb3523] dark:text-white">Polda</span> <span className="capitalize">{poldaName.replace("-", " ")}</span>
<span className="text-[#bb3523] dark:text-white">{t("welcome")} Di Polda</span> <span className="capitalize text-[#bb3523] dark:text-white">{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">

View File

@ -353,6 +353,7 @@
},
"LandingPage": {
"content": "Content",
"searchCoverageHere": "Find Coverage Here...",
"new": "Latest",
"schedule": "Schedule",
"index": "Index",
@ -362,6 +363,7 @@
"download": "Download",
"coverage": "Our Official Coverage",
"officialCoverage": "Official coverage sourced from Polri activities at the National Police Headquarters and Regional Police throughout Indonesia",
"officialPolda": "Official Coverage Sourced From Police Activities At Polda",
"allContent": "All Content",
"searchCoverage": "Search Coverage",
"newContent": "Latest Content",

View File

@ -358,13 +358,15 @@
"schedule": "Jadwal",
"index": "Indeks",
"search": "Pencarian",
"exploration": "Eksplorasi",
"and": "dan",
"download": "Unduh",
"coverage": "Liputan Resmi Kami",
"exploration": "EKSPLORASI",
"and": "DAN",
"download": "DOWNLOAD",
"coverage": "LIPUTAN RESMI KAMI",
"officialCoverage": "Liputan resmi yang bersumber dari kegiatan Polri di Mabes dan Polda seluruh Indonesia",
"officialPolda": "Liputan Resmi Yang Bersumber Dari Kegiatan Polri Di Polda",
"allContent": "Semua Konten",
"searchCoverage": "Cari Liputan",
"searchCoverageHere": "Cari Liputan Disini",
"newContent": "Konten Terbaru",
"video": "Audio Visual",
"audio": "Audio",

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

BIN
public/assets/divkum.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
public/assets/line1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

BIN
public/assets/survey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

View File

@ -1,12 +1 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
else
exec node "$basedir/../typescript/bin/tsc" "$@"
fi
../typescript/bin/tsc

View File

@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\typescript\bin\tsc" %*

View File

@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../typescript/bin/tsc" $args
} else {
& "$basedir/node$exe" "$basedir/../typescript/bin/tsc" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../typescript/bin/tsc" $args
} else {
& "node$exe" "$basedir/../typescript/bin/tsc" $args
}
$ret=$LASTEXITCODE
}
exit $ret

View File

@ -1,12 +1 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
else
exec node "$basedir/../typescript/bin/tsserver" "$@"
fi
../typescript/bin/tsserver

View File

@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\typescript\bin\tsserver" %*

View File

@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../typescript/bin/tsserver" $args
} else {
& "$basedir/node$exe" "$basedir/../typescript/bin/tsserver" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../typescript/bin/tsserver" $args
} else {
& "node$exe" "$basedir/../typescript/bin/tsserver" $args
}
$ret=$LASTEXITCODE
}
exit $ret

View File

@ -1,55 +1,55 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -1,49 +1,49 @@
# TypeScript
[![GitHub Actions CI](https://github.com/microsoft/TypeScript/workflows/CI/badge.svg)](https://github.com/microsoft/TypeScript/actions?query=workflow%3ACI)
[![Devops Build Status](https://dev.azure.com/typescript/TypeScript/_apis/build/status/Typescript/node10)](https://dev.azure.com/typescript/TypeScript/_build?definitionId=7)
[![npm version](https://badge.fury.io/js/typescript.svg)](https://www.npmjs.com/package/typescript)
[![Downloads](https://img.shields.io/npm/dm/typescript.svg)](https://www.npmjs.com/package/typescript)
[TypeScript](https://www.typescriptlang.org/) is a language for application-scale JavaScript. TypeScript adds optional types to JavaScript that support tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript compiles to readable, standards-based JavaScript. Try it out at the [playground](https://www.typescriptlang.org/play/), and stay up to date via [our blog](https://blogs.msdn.microsoft.com/typescript) and [Twitter account](https://twitter.com/typescript).
Find others who are using TypeScript at [our community page](https://www.typescriptlang.org/community/).
## Installing
For the latest stable version:
```bash
npm install -g typescript
```
For our nightly builds:
```bash
npm install -g typescript@next
```
## Contribute
There are many ways to [contribute](https://github.com/microsoft/TypeScript/blob/main/CONTRIBUTING.md) to TypeScript.
* [Submit bugs](https://github.com/microsoft/TypeScript/issues) and help us verify fixes as they are checked in.
* Review the [source code changes](https://github.com/microsoft/TypeScript/pulls).
* Engage with other TypeScript users and developers on [StackOverflow](https://stackoverflow.com/questions/tagged/typescript).
* Help each other in the [TypeScript Community Discord](https://discord.gg/typescript).
* Join the [#typescript](https://twitter.com/search?q=%23TypeScript) discussion on Twitter.
* [Contribute bug fixes](https://github.com/microsoft/TypeScript/blob/main/CONTRIBUTING.md).
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see
the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com)
with any additional questions or comments.
## Documentation
* [TypeScript in 5 minutes](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)
* [Programming handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
* [Homepage](https://www.typescriptlang.org/)
## Roadmap
For details on our planned features and future direction please refer to our [roadmap](https://github.com/microsoft/TypeScript/wiki/Roadmap).
# TypeScript
[![GitHub Actions CI](https://github.com/microsoft/TypeScript/workflows/CI/badge.svg)](https://github.com/microsoft/TypeScript/actions?query=workflow%3ACI)
[![Devops Build Status](https://dev.azure.com/typescript/TypeScript/_apis/build/status/Typescript/node10)](https://dev.azure.com/typescript/TypeScript/_build?definitionId=7)
[![npm version](https://badge.fury.io/js/typescript.svg)](https://www.npmjs.com/package/typescript)
[![Downloads](https://img.shields.io/npm/dm/typescript.svg)](https://www.npmjs.com/package/typescript)
[TypeScript](https://www.typescriptlang.org/) is a language for application-scale JavaScript. TypeScript adds optional types to JavaScript that support tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript compiles to readable, standards-based JavaScript. Try it out at the [playground](https://www.typescriptlang.org/play/), and stay up to date via [our blog](https://blogs.msdn.microsoft.com/typescript) and [Twitter account](https://twitter.com/typescript).
Find others who are using TypeScript at [our community page](https://www.typescriptlang.org/community/).
## Installing
For the latest stable version:
```bash
npm install -g typescript
```
For our nightly builds:
```bash
npm install -g typescript@next
```
## Contribute
There are many ways to [contribute](https://github.com/microsoft/TypeScript/blob/main/CONTRIBUTING.md) to TypeScript.
* [Submit bugs](https://github.com/microsoft/TypeScript/issues) and help us verify fixes as they are checked in.
* Review the [source code changes](https://github.com/microsoft/TypeScript/pulls).
* Engage with other TypeScript users and developers on [StackOverflow](https://stackoverflow.com/questions/tagged/typescript).
* Help each other in the [TypeScript Community Discord](https://discord.gg/typescript).
* Join the [#typescript](https://twitter.com/search?q=%23TypeScript) discussion on Twitter.
* [Contribute bug fixes](https://github.com/microsoft/TypeScript/blob/main/CONTRIBUTING.md).
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see
the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com)
with any additional questions or comments.
## Documentation
* [TypeScript in 5 minutes](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)
* [Programming handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
* [Homepage](https://www.typescriptlang.org/)
## Roadmap
For details on our planned features and future direction please refer to our [roadmap](https://github.com/microsoft/TypeScript/wiki/Roadmap).

File diff suppressed because one or more lines are too long

0
vendor/ckeditor5/node_modules/typescript/bin/tsc generated vendored Normal file → Executable file
View File

0
vendor/ckeditor5/node_modules/typescript/bin/tsserver generated vendored Normal file → Executable file
View File

View File

@ -1,497 +1,497 @@
{
"typesMap": {
"jquery": {
"match": "jquery(-(\\.?\\d+)+)?(\\.intellisense)?(\\.min)?\\.js$",
"types": ["jquery"]
},
"WinJS": {
"match": "^(.*\\/winjs-[.\\d]+)\\/js\\/base\\.js$",
"exclude": [["^", 1, "/.*"]],
"types": ["winjs"]
},
"Kendo": {
"match": "^(.*\\/kendo(-ui)?)\\/kendo\\.all(\\.min)?\\.js$",
"exclude": [["^", 1, "/.*"]],
"types": ["kendo-ui"]
},
"Office Nuget": {
"match": "^(.*\\/office\\/1)\\/excel-\\d+\\.debug\\.js$",
"exclude": [["^", 1, "/.*"]],
"types": ["office"]
},
"References": {
"match": "^(.*\\/_references\\.js)$",
"exclude": [["^", 1, "$"]]
},
"Datatables.net": {
"match": "^.*\\/(jquery\\.)?dataTables(\\.all)?(\\.min)?\\.js$",
"types": ["datatables.net"]
},
"Ace": {
"match": "^(.*)\\/ace.js",
"exclude": [["^", 1, "/.*"]],
"types": ["ace"]
}
},
"simpleMap": {
"accounting": "accounting",
"ace.js": "ace",
"ag-grid": "ag-grid",
"alertify": "alertify",
"alt": "alt",
"amcharts.js": "amcharts",
"amplify": "amplifyjs",
"angular": "angular",
"angular-bootstrap-lightbox": "angular-bootstrap-lightbox",
"angular-cookie": "angular-cookie",
"angular-file-upload": "angular-file-upload",
"angularfire": "angularfire",
"angular-gettext": "angular-gettext",
"angular-google-analytics": "angular-google-analytics",
"angular-local-storage": "angular-local-storage",
"angularLocalStorage": "angularLocalStorage",
"angular-scroll": "angular-scroll",
"angular-spinner": "angular-spinner",
"angular-strap": "angular-strap",
"angulartics": "angulartics",
"angular-toastr": "angular-toastr",
"angular-translate": "angular-translate",
"angular-ui-router": "angular-ui-router",
"angular-ui-tree": "angular-ui-tree",
"angular-wizard": "angular-wizard",
"async": "async",
"atmosphere": "atmosphere",
"aws-sdk": "aws-sdk",
"aws-sdk-js": "aws-sdk",
"axios": "axios",
"backbone": "backbone",
"backbone.layoutmanager": "backbone.layoutmanager",
"backbone.paginator": "backbone.paginator",
"backbone.radio": "backbone.radio",
"backbone-associations": "backbone-associations",
"backbone-relational": "backbone-relational",
"backgrid": "backgrid",
"Bacon": "baconjs",
"benchmark": "benchmark",
"blazy": "blazy",
"bliss": "blissfuljs",
"bluebird": "bluebird",
"body-parser": "body-parser",
"bootbox": "bootbox",
"bootstrap": "bootstrap",
"bootstrap-editable": "x-editable",
"bootstrap-maxlength": "bootstrap-maxlength",
"bootstrap-notify": "bootstrap-notify",
"bootstrap-slider": "bootstrap-slider",
"bootstrap-switch": "bootstrap-switch",
"bowser": "bowser",
"breeze": "breeze",
"browserify": "browserify",
"bson": "bson",
"c3": "c3",
"canvasjs": "canvasjs",
"chai": "chai",
"chalk": "chalk",
"chance": "chance",
"chartist": "chartist",
"cheerio": "cheerio",
"chokidar": "chokidar",
"chosen.jquery": "chosen",
"chroma": "chroma-js",
"ckeditor.js": "ckeditor",
"cli-color": "cli-color",
"clipboard": "clipboard",
"codemirror": "codemirror",
"colors": "colors",
"commander": "commander",
"commonmark": "commonmark",
"compression": "compression",
"confidence": "confidence",
"connect": "connect",
"Control.FullScreen": "leaflet.fullscreen",
"cookie": "cookie",
"cookie-parser": "cookie-parser",
"cookies": "cookies",
"core": "core-js",
"core-js": "core-js",
"crossfilter": "crossfilter",
"crossroads": "crossroads",
"css": "css",
"ct-ui-router-extras": "ui-router-extras",
"d3": "d3",
"dagre-d3": "dagre-d3",
"dat.gui": "dat-gui",
"debug": "debug",
"deep-diff": "deep-diff",
"Dexie": "dexie",
"dialogs": "angular-dialog-service",
"dojo.js": "dojo",
"doT": "dot",
"dragula": "dragula",
"drop": "drop",
"dropbox": "dropboxjs",
"dropzone": "dropzone",
"Dts Name": "Dts Name",
"dust-core": "dustjs-linkedin",
"easeljs": "easeljs",
"ejs": "ejs",
"ember": "ember",
"envify": "envify",
"epiceditor": "epiceditor",
"es6-promise": "es6-promise",
"ES6-Promise": "es6-promise",
"es6-shim": "es6-shim",
"expect": "expect",
"express": "express",
"express-session": "express-session",
"ext-all.js": "extjs",
"extend": "extend",
"fabric": "fabricjs",
"faker": "faker",
"fastclick": "fastclick",
"favico": "favico.js",
"featherlight": "featherlight",
"FileSaver": "FileSaver",
"fingerprint": "fingerprintjs",
"fixed-data-table": "fixed-data-table",
"flickity.pkgd": "flickity",
"flight": "flight",
"flow": "flowjs",
"Flux": "flux",
"formly": "angular-formly",
"foundation": "foundation",
"fpsmeter": "fpsmeter",
"fuse": "fuse",
"generator": "yeoman-generator",
"gl-matrix": "gl-matrix",
"globalize": "globalize",
"graceful-fs": "graceful-fs",
"gridstack": "gridstack",
"gulp": "gulp",
"gulp-rename": "gulp-rename",
"gulp-uglify": "gulp-uglify",
"gulp-util": "gulp-util",
"hammer": "hammerjs",
"handlebars": "handlebars",
"hasher": "hasher",
"he": "he",
"hello.all": "hellojs",
"highcharts.js": "highcharts",
"highlight": "highlightjs",
"history": "history",
"History": "history",
"hopscotch": "hopscotch",
"hotkeys": "angular-hotkeys",
"html2canvas": "html2canvas",
"humane": "humane",
"i18next": "i18next",
"icheck": "icheck",
"impress": "impress",
"incremental-dom": "incremental-dom",
"Inquirer": "inquirer",
"insight": "insight",
"interact": "interactjs",
"intercom": "intercomjs",
"intro": "intro.js",
"ion.rangeSlider": "ion.rangeSlider",
"ionic": "ionic",
"is": "is_js",
"iscroll": "iscroll",
"jade": "jade",
"jasmine": "jasmine",
"joint": "jointjs",
"jquery": "jquery",
"jquery.address": "jquery.address",
"jquery.are-you-sure": "jquery.are-you-sure",
"jquery.blockUI": "jquery.blockUI",
"jquery.bootstrap.wizard": "jquery.bootstrap.wizard",
"jquery.bootstrap-touchspin": "bootstrap-touchspin",
"jquery.color": "jquery.color",
"jquery.colorbox": "jquery.colorbox",
"jquery.contextMenu": "jquery.contextMenu",
"jquery.cookie": "jquery.cookie",
"jquery.customSelect": "jquery.customSelect",
"jquery.cycle.all": "jquery.cycle",
"jquery.cycle2": "jquery.cycle2",
"jquery.dataTables": "jquery.dataTables",
"jquery.dropotron": "jquery.dropotron",
"jquery.fancybox.pack.js": "fancybox",
"jquery.fancytree-all": "jquery.fancytree",
"jquery.fileupload": "jquery.fileupload",
"jquery.flot": "flot",
"jquery.form": "jquery.form",
"jquery.gridster": "jquery.gridster",
"jquery.handsontable.full": "jquery-handsontable",
"jquery.joyride": "jquery.joyride",
"jquery.jqGrid": "jqgrid",
"jquery.mmenu": "jquery.mmenu",
"jquery.mockjax": "jquery-mockjax",
"jquery.noty": "jquery.noty",
"jquery.payment": "jquery.payment",
"jquery.pjax": "jquery.pjax",
"jquery.placeholder": "jquery.placeholder",
"jquery.qrcode": "jquery.qrcode",
"jquery.qtip": "qtip2",
"jquery.raty": "raty",
"jquery.scrollTo": "jquery.scrollTo",
"jquery.signalR": "signalr",
"jquery.simplemodal": "jquery.simplemodal",
"jquery.timeago": "jquery.timeago",
"jquery.tinyscrollbar": "jquery.tinyscrollbar",
"jquery.tipsy": "jquery.tipsy",
"jquery.tooltipster": "tooltipster",
"jquery.transit": "jquery.transit",
"jquery.uniform": "jquery.uniform",
"jquery.watch": "watch",
"jquery-sortable": "jquery-sortable",
"jquery-ui": "jqueryui",
"js.cookie": "js-cookie",
"js-data": "js-data",
"js-data-angular": "js-data-angular",
"js-data-http": "js-data-http",
"jsdom": "jsdom",
"jsnlog": "jsnlog",
"json5": "json5",
"jspdf": "jspdf",
"jsrender": "jsrender",
"js-signals": "js-signals",
"jstorage": "jstorage",
"jstree": "jstree",
"js-yaml": "js-yaml",
"jszip": "jszip",
"katex": "katex",
"kefir": "kefir",
"keymaster": "keymaster",
"keypress": "keypress",
"kinetic": "kineticjs",
"knockback": "knockback",
"knockout": "knockout",
"knockout.mapping": "knockout.mapping",
"knockout.validation": "knockout.validation",
"knockout-paging": "knockout-paging",
"knockout-pre-rendered": "knockout-pre-rendered",
"ladda": "ladda",
"later": "later",
"lazy": "lazy.js",
"Leaflet.Editable": "leaflet-editable",
"leaflet.js": "leaflet",
"less": "less",
"linq": "linq",
"loading-bar": "angular-loading-bar",
"lodash": "lodash",
"log4javascript": "log4javascript",
"loglevel": "loglevel",
"lokijs": "lokijs",
"lovefield": "lovefield",
"lunr": "lunr",
"lz-string": "lz-string",
"mailcheck": "mailcheck",
"maquette": "maquette",
"marked": "marked",
"math": "mathjs",
"MathJax.js": "mathjax",
"matter": "matter-js",
"md5": "blueimp-md5",
"md5.js": "crypto-js",
"messenger": "messenger",
"method-override": "method-override",
"minimatch": "minimatch",
"minimist": "minimist",
"mithril": "mithril",
"mobile-detect": "mobile-detect",
"mocha": "mocha",
"mock-ajax": "jasmine-ajax",
"modernizr": "modernizr",
"Modernizr": "Modernizr",
"moment": "moment",
"moment-range": "moment-range",
"moment-timezone": "moment-timezone",
"mongoose": "mongoose",
"morgan": "morgan",
"mousetrap": "mousetrap",
"ms": "ms",
"mustache": "mustache",
"native.history": "history",
"nconf": "nconf",
"ncp": "ncp",
"nedb": "nedb",
"ng-cordova": "ng-cordova",
"ngDialog": "ng-dialog",
"ng-flow-standalone": "ng-flow",
"ng-grid": "ng-grid",
"ng-i18next": "ng-i18next",
"ng-table": "ng-table",
"node_redis": "redis",
"node-clone": "clone",
"node-fs-extra": "fs-extra",
"node-glob": "glob",
"Nodemailer": "nodemailer",
"node-mime": "mime",
"node-mkdirp": "mkdirp",
"node-mongodb-native": "mongodb",
"node-mysql": "mysql",
"node-open": "open",
"node-optimist": "optimist",
"node-progress": "progress",
"node-semver": "semver",
"node-tar": "tar",
"node-uuid": "node-uuid",
"node-xml2js": "xml2js",
"nopt": "nopt",
"notify": "notify",
"nouislider": "nouislider",
"npm": "npm",
"nprogress": "nprogress",
"numbro": "numbro",
"numeral": "numeraljs",
"nunjucks": "nunjucks",
"nv.d3": "nvd3",
"object-assign": "object-assign",
"oboe-browser": "oboe",
"office": "office-js",
"offline": "offline-js",
"onsenui": "onsenui",
"OpenLayers.js": "openlayers",
"openpgp": "openpgp",
"p2": "p2",
"packery.pkgd": "packery",
"page": "page",
"pako": "pako",
"papaparse": "papaparse",
"passport": "passport",
"passport-local": "passport-local",
"path": "pathjs",
"pdfkit":"pdfkit",
"peer": "peerjs",
"peg": "pegjs",
"photoswipe": "photoswipe",
"picker.js": "pickadate",
"pikaday": "pikaday",
"pixi": "pixi.js",
"platform": "platform",
"Please": "pleasejs",
"plottable": "plottable",
"polymer": "polymer",
"postal": "postal",
"preloadjs": "preloadjs",
"progress": "progress",
"purify": "dompurify",
"purl": "purl",
"q": "q",
"qs": "qs",
"qunit": "qunit",
"ractive": "ractive",
"rangy-core": "rangy",
"raphael": "raphael",
"raven": "ravenjs",
"react": "react",
"react-bootstrap": "react-bootstrap",
"react-intl": "react-intl",
"react-redux": "react-redux",
"ReactRouter": "react-router",
"ready": "domready",
"redux": "redux",
"request": "request",
"require": "require",
"restangular": "restangular",
"reveal": "reveal",
"rickshaw": "rickshaw",
"rimraf": "rimraf",
"rivets": "rivets",
"rx": "rx",
"rx.angular": "rx-angular",
"sammy": "sammyjs",
"SAT": "sat",
"sax-js": "sax",
"screenfull": "screenfull",
"seedrandom": "seedrandom",
"select2": "select2",
"selectize": "selectize",
"serve-favicon": "serve-favicon",
"serve-static": "serve-static",
"shelljs": "shelljs",
"should": "should",
"showdown": "showdown",
"sigma": "sigmajs",
"signature_pad": "signature_pad",
"sinon": "sinon",
"sjcl": "sjcl",
"slick": "slick-carousel",
"smoothie": "smoothie",
"socket.io": "socket.io",
"socket.io-client": "socket.io-client",
"sockjs": "sockjs-client",
"sortable": "angular-ui-sortable",
"soundjs": "soundjs",
"source-map": "source-map",
"spectrum": "spectrum",
"spin": "spin",
"sprintf": "sprintf",
"stampit": "stampit",
"state-machine": "state-machine",
"Stats": "stats",
"store": "storejs",
"string": "string",
"string_score": "string_score",
"strophe": "strophe",
"stylus": "stylus",
"sugar": "sugar",
"superagent": "superagent",
"svg": "svgjs",
"svg-injector": "svg-injector",
"swfobject": "swfobject",
"swig": "swig",
"swipe": "swipe",
"swiper": "swiper",
"system.js": "systemjs",
"tether": "tether",
"three": "threejs",
"through": "through",
"through2": "through2",
"timeline": "timelinejs",
"tinycolor": "tinycolor",
"tmhDynamicLocale": "angular-dynamic-locale",
"toaster": "angularjs-toaster",
"toastr": "toastr",
"tracking": "tracking",
"trunk8": "trunk8",
"turf": "turf",
"tweenjs": "tweenjs",
"TweenMax": "gsap",
"twig": "twig",
"twix": "twix",
"typeahead.bundle": "typeahead",
"typescript": "typescript",
"ui": "winjs",
"ui-bootstrap-tpls": "angular-ui-bootstrap",
"ui-grid": "ui-grid",
"uikit": "uikit",
"underscore": "underscore",
"underscore.string": "underscore.string",
"update-notifier": "update-notifier",
"url": "jsurl",
"UUID": "uuid",
"validator": "validator",
"vega": "vega",
"vex": "vex-js",
"video": "videojs",
"vue": "vue",
"vue-router": "vue-router",
"webtorrent": "webtorrent",
"when": "when",
"winston": "winston",
"wrench-js": "wrench",
"ws": "ws",
"xlsx": "xlsx",
"xml2json": "x2js",
"xmlbuilder-js": "xmlbuilder",
"xregexp": "xregexp",
"yargs": "yargs",
"yosay": "yosay",
"yui": "yui",
"yui3": "yui",
"zepto": "zepto",
"ZeroClipboard": "zeroclipboard",
"ZSchema-browser": "z-schema"
}
{
"typesMap": {
"jquery": {
"match": "jquery(-(\\.?\\d+)+)?(\\.intellisense)?(\\.min)?\\.js$",
"types": ["jquery"]
},
"WinJS": {
"match": "^(.*\\/winjs-[.\\d]+)\\/js\\/base\\.js$",
"exclude": [["^", 1, "/.*"]],
"types": ["winjs"]
},
"Kendo": {
"match": "^(.*\\/kendo(-ui)?)\\/kendo\\.all(\\.min)?\\.js$",
"exclude": [["^", 1, "/.*"]],
"types": ["kendo-ui"]
},
"Office Nuget": {
"match": "^(.*\\/office\\/1)\\/excel-\\d+\\.debug\\.js$",
"exclude": [["^", 1, "/.*"]],
"types": ["office"]
},
"References": {
"match": "^(.*\\/_references\\.js)$",
"exclude": [["^", 1, "$"]]
},
"Datatables.net": {
"match": "^.*\\/(jquery\\.)?dataTables(\\.all)?(\\.min)?\\.js$",
"types": ["datatables.net"]
},
"Ace": {
"match": "^(.*)\\/ace.js",
"exclude": [["^", 1, "/.*"]],
"types": ["ace"]
}
},
"simpleMap": {
"accounting": "accounting",
"ace.js": "ace",
"ag-grid": "ag-grid",
"alertify": "alertify",
"alt": "alt",
"amcharts.js": "amcharts",
"amplify": "amplifyjs",
"angular": "angular",
"angular-bootstrap-lightbox": "angular-bootstrap-lightbox",
"angular-cookie": "angular-cookie",
"angular-file-upload": "angular-file-upload",
"angularfire": "angularfire",
"angular-gettext": "angular-gettext",
"angular-google-analytics": "angular-google-analytics",
"angular-local-storage": "angular-local-storage",
"angularLocalStorage": "angularLocalStorage",
"angular-scroll": "angular-scroll",
"angular-spinner": "angular-spinner",
"angular-strap": "angular-strap",
"angulartics": "angulartics",
"angular-toastr": "angular-toastr",
"angular-translate": "angular-translate",
"angular-ui-router": "angular-ui-router",
"angular-ui-tree": "angular-ui-tree",
"angular-wizard": "angular-wizard",
"async": "async",
"atmosphere": "atmosphere",
"aws-sdk": "aws-sdk",
"aws-sdk-js": "aws-sdk",
"axios": "axios",
"backbone": "backbone",
"backbone.layoutmanager": "backbone.layoutmanager",
"backbone.paginator": "backbone.paginator",
"backbone.radio": "backbone.radio",
"backbone-associations": "backbone-associations",
"backbone-relational": "backbone-relational",
"backgrid": "backgrid",
"Bacon": "baconjs",
"benchmark": "benchmark",
"blazy": "blazy",
"bliss": "blissfuljs",
"bluebird": "bluebird",
"body-parser": "body-parser",
"bootbox": "bootbox",
"bootstrap": "bootstrap",
"bootstrap-editable": "x-editable",
"bootstrap-maxlength": "bootstrap-maxlength",
"bootstrap-notify": "bootstrap-notify",
"bootstrap-slider": "bootstrap-slider",
"bootstrap-switch": "bootstrap-switch",
"bowser": "bowser",
"breeze": "breeze",
"browserify": "browserify",
"bson": "bson",
"c3": "c3",
"canvasjs": "canvasjs",
"chai": "chai",
"chalk": "chalk",
"chance": "chance",
"chartist": "chartist",
"cheerio": "cheerio",
"chokidar": "chokidar",
"chosen.jquery": "chosen",
"chroma": "chroma-js",
"ckeditor.js": "ckeditor",
"cli-color": "cli-color",
"clipboard": "clipboard",
"codemirror": "codemirror",
"colors": "colors",
"commander": "commander",
"commonmark": "commonmark",
"compression": "compression",
"confidence": "confidence",
"connect": "connect",
"Control.FullScreen": "leaflet.fullscreen",
"cookie": "cookie",
"cookie-parser": "cookie-parser",
"cookies": "cookies",
"core": "core-js",
"core-js": "core-js",
"crossfilter": "crossfilter",
"crossroads": "crossroads",
"css": "css",
"ct-ui-router-extras": "ui-router-extras",
"d3": "d3",
"dagre-d3": "dagre-d3",
"dat.gui": "dat-gui",
"debug": "debug",
"deep-diff": "deep-diff",
"Dexie": "dexie",
"dialogs": "angular-dialog-service",
"dojo.js": "dojo",
"doT": "dot",
"dragula": "dragula",
"drop": "drop",
"dropbox": "dropboxjs",
"dropzone": "dropzone",
"Dts Name": "Dts Name",
"dust-core": "dustjs-linkedin",
"easeljs": "easeljs",
"ejs": "ejs",
"ember": "ember",
"envify": "envify",
"epiceditor": "epiceditor",
"es6-promise": "es6-promise",
"ES6-Promise": "es6-promise",
"es6-shim": "es6-shim",
"expect": "expect",
"express": "express",
"express-session": "express-session",
"ext-all.js": "extjs",
"extend": "extend",
"fabric": "fabricjs",
"faker": "faker",
"fastclick": "fastclick",
"favico": "favico.js",
"featherlight": "featherlight",
"FileSaver": "FileSaver",
"fingerprint": "fingerprintjs",
"fixed-data-table": "fixed-data-table",
"flickity.pkgd": "flickity",
"flight": "flight",
"flow": "flowjs",
"Flux": "flux",
"formly": "angular-formly",
"foundation": "foundation",
"fpsmeter": "fpsmeter",
"fuse": "fuse",
"generator": "yeoman-generator",
"gl-matrix": "gl-matrix",
"globalize": "globalize",
"graceful-fs": "graceful-fs",
"gridstack": "gridstack",
"gulp": "gulp",
"gulp-rename": "gulp-rename",
"gulp-uglify": "gulp-uglify",
"gulp-util": "gulp-util",
"hammer": "hammerjs",
"handlebars": "handlebars",
"hasher": "hasher",
"he": "he",
"hello.all": "hellojs",
"highcharts.js": "highcharts",
"highlight": "highlightjs",
"history": "history",
"History": "history",
"hopscotch": "hopscotch",
"hotkeys": "angular-hotkeys",
"html2canvas": "html2canvas",
"humane": "humane",
"i18next": "i18next",
"icheck": "icheck",
"impress": "impress",
"incremental-dom": "incremental-dom",
"Inquirer": "inquirer",
"insight": "insight",
"interact": "interactjs",
"intercom": "intercomjs",
"intro": "intro.js",
"ion.rangeSlider": "ion.rangeSlider",
"ionic": "ionic",
"is": "is_js",
"iscroll": "iscroll",
"jade": "jade",
"jasmine": "jasmine",
"joint": "jointjs",
"jquery": "jquery",
"jquery.address": "jquery.address",
"jquery.are-you-sure": "jquery.are-you-sure",
"jquery.blockUI": "jquery.blockUI",
"jquery.bootstrap.wizard": "jquery.bootstrap.wizard",
"jquery.bootstrap-touchspin": "bootstrap-touchspin",
"jquery.color": "jquery.color",
"jquery.colorbox": "jquery.colorbox",
"jquery.contextMenu": "jquery.contextMenu",
"jquery.cookie": "jquery.cookie",
"jquery.customSelect": "jquery.customSelect",
"jquery.cycle.all": "jquery.cycle",
"jquery.cycle2": "jquery.cycle2",
"jquery.dataTables": "jquery.dataTables",
"jquery.dropotron": "jquery.dropotron",
"jquery.fancybox.pack.js": "fancybox",
"jquery.fancytree-all": "jquery.fancytree",
"jquery.fileupload": "jquery.fileupload",
"jquery.flot": "flot",
"jquery.form": "jquery.form",
"jquery.gridster": "jquery.gridster",
"jquery.handsontable.full": "jquery-handsontable",
"jquery.joyride": "jquery.joyride",
"jquery.jqGrid": "jqgrid",
"jquery.mmenu": "jquery.mmenu",
"jquery.mockjax": "jquery-mockjax",
"jquery.noty": "jquery.noty",
"jquery.payment": "jquery.payment",
"jquery.pjax": "jquery.pjax",
"jquery.placeholder": "jquery.placeholder",
"jquery.qrcode": "jquery.qrcode",
"jquery.qtip": "qtip2",
"jquery.raty": "raty",
"jquery.scrollTo": "jquery.scrollTo",
"jquery.signalR": "signalr",
"jquery.simplemodal": "jquery.simplemodal",
"jquery.timeago": "jquery.timeago",
"jquery.tinyscrollbar": "jquery.tinyscrollbar",
"jquery.tipsy": "jquery.tipsy",
"jquery.tooltipster": "tooltipster",
"jquery.transit": "jquery.transit",
"jquery.uniform": "jquery.uniform",
"jquery.watch": "watch",
"jquery-sortable": "jquery-sortable",
"jquery-ui": "jqueryui",
"js.cookie": "js-cookie",
"js-data": "js-data",
"js-data-angular": "js-data-angular",
"js-data-http": "js-data-http",
"jsdom": "jsdom",
"jsnlog": "jsnlog",
"json5": "json5",
"jspdf": "jspdf",
"jsrender": "jsrender",
"js-signals": "js-signals",
"jstorage": "jstorage",
"jstree": "jstree",
"js-yaml": "js-yaml",
"jszip": "jszip",
"katex": "katex",
"kefir": "kefir",
"keymaster": "keymaster",
"keypress": "keypress",
"kinetic": "kineticjs",
"knockback": "knockback",
"knockout": "knockout",
"knockout.mapping": "knockout.mapping",
"knockout.validation": "knockout.validation",
"knockout-paging": "knockout-paging",
"knockout-pre-rendered": "knockout-pre-rendered",
"ladda": "ladda",
"later": "later",
"lazy": "lazy.js",
"Leaflet.Editable": "leaflet-editable",
"leaflet.js": "leaflet",
"less": "less",
"linq": "linq",
"loading-bar": "angular-loading-bar",
"lodash": "lodash",
"log4javascript": "log4javascript",
"loglevel": "loglevel",
"lokijs": "lokijs",
"lovefield": "lovefield",
"lunr": "lunr",
"lz-string": "lz-string",
"mailcheck": "mailcheck",
"maquette": "maquette",
"marked": "marked",
"math": "mathjs",
"MathJax.js": "mathjax",
"matter": "matter-js",
"md5": "blueimp-md5",
"md5.js": "crypto-js",
"messenger": "messenger",
"method-override": "method-override",
"minimatch": "minimatch",
"minimist": "minimist",
"mithril": "mithril",
"mobile-detect": "mobile-detect",
"mocha": "mocha",
"mock-ajax": "jasmine-ajax",
"modernizr": "modernizr",
"Modernizr": "Modernizr",
"moment": "moment",
"moment-range": "moment-range",
"moment-timezone": "moment-timezone",
"mongoose": "mongoose",
"morgan": "morgan",
"mousetrap": "mousetrap",
"ms": "ms",
"mustache": "mustache",
"native.history": "history",
"nconf": "nconf",
"ncp": "ncp",
"nedb": "nedb",
"ng-cordova": "ng-cordova",
"ngDialog": "ng-dialog",
"ng-flow-standalone": "ng-flow",
"ng-grid": "ng-grid",
"ng-i18next": "ng-i18next",
"ng-table": "ng-table",
"node_redis": "redis",
"node-clone": "clone",
"node-fs-extra": "fs-extra",
"node-glob": "glob",
"Nodemailer": "nodemailer",
"node-mime": "mime",
"node-mkdirp": "mkdirp",
"node-mongodb-native": "mongodb",
"node-mysql": "mysql",
"node-open": "open",
"node-optimist": "optimist",
"node-progress": "progress",
"node-semver": "semver",
"node-tar": "tar",
"node-uuid": "node-uuid",
"node-xml2js": "xml2js",
"nopt": "nopt",
"notify": "notify",
"nouislider": "nouislider",
"npm": "npm",
"nprogress": "nprogress",
"numbro": "numbro",
"numeral": "numeraljs",
"nunjucks": "nunjucks",
"nv.d3": "nvd3",
"object-assign": "object-assign",
"oboe-browser": "oboe",
"office": "office-js",
"offline": "offline-js",
"onsenui": "onsenui",
"OpenLayers.js": "openlayers",
"openpgp": "openpgp",
"p2": "p2",
"packery.pkgd": "packery",
"page": "page",
"pako": "pako",
"papaparse": "papaparse",
"passport": "passport",
"passport-local": "passport-local",
"path": "pathjs",
"pdfkit":"pdfkit",
"peer": "peerjs",
"peg": "pegjs",
"photoswipe": "photoswipe",
"picker.js": "pickadate",
"pikaday": "pikaday",
"pixi": "pixi.js",
"platform": "platform",
"Please": "pleasejs",
"plottable": "plottable",
"polymer": "polymer",
"postal": "postal",
"preloadjs": "preloadjs",
"progress": "progress",
"purify": "dompurify",
"purl": "purl",
"q": "q",
"qs": "qs",
"qunit": "qunit",
"ractive": "ractive",
"rangy-core": "rangy",
"raphael": "raphael",
"raven": "ravenjs",
"react": "react",
"react-bootstrap": "react-bootstrap",
"react-intl": "react-intl",
"react-redux": "react-redux",
"ReactRouter": "react-router",
"ready": "domready",
"redux": "redux",
"request": "request",
"require": "require",
"restangular": "restangular",
"reveal": "reveal",
"rickshaw": "rickshaw",
"rimraf": "rimraf",
"rivets": "rivets",
"rx": "rx",
"rx.angular": "rx-angular",
"sammy": "sammyjs",
"SAT": "sat",
"sax-js": "sax",
"screenfull": "screenfull",
"seedrandom": "seedrandom",
"select2": "select2",
"selectize": "selectize",
"serve-favicon": "serve-favicon",
"serve-static": "serve-static",
"shelljs": "shelljs",
"should": "should",
"showdown": "showdown",
"sigma": "sigmajs",
"signature_pad": "signature_pad",
"sinon": "sinon",
"sjcl": "sjcl",
"slick": "slick-carousel",
"smoothie": "smoothie",
"socket.io": "socket.io",
"socket.io-client": "socket.io-client",
"sockjs": "sockjs-client",
"sortable": "angular-ui-sortable",
"soundjs": "soundjs",
"source-map": "source-map",
"spectrum": "spectrum",
"spin": "spin",
"sprintf": "sprintf",
"stampit": "stampit",
"state-machine": "state-machine",
"Stats": "stats",
"store": "storejs",
"string": "string",
"string_score": "string_score",
"strophe": "strophe",
"stylus": "stylus",
"sugar": "sugar",
"superagent": "superagent",
"svg": "svgjs",
"svg-injector": "svg-injector",
"swfobject": "swfobject",
"swig": "swig",
"swipe": "swipe",
"swiper": "swiper",
"system.js": "systemjs",
"tether": "tether",
"three": "threejs",
"through": "through",
"through2": "through2",
"timeline": "timelinejs",
"tinycolor": "tinycolor",
"tmhDynamicLocale": "angular-dynamic-locale",
"toaster": "angularjs-toaster",
"toastr": "toastr",
"tracking": "tracking",
"trunk8": "trunk8",
"turf": "turf",
"tweenjs": "tweenjs",
"TweenMax": "gsap",
"twig": "twig",
"twix": "twix",
"typeahead.bundle": "typeahead",
"typescript": "typescript",
"ui": "winjs",
"ui-bootstrap-tpls": "angular-ui-bootstrap",
"ui-grid": "ui-grid",
"uikit": "uikit",
"underscore": "underscore",
"underscore.string": "underscore.string",
"update-notifier": "update-notifier",
"url": "jsurl",
"UUID": "uuid",
"validator": "validator",
"vega": "vega",
"vex": "vex-js",
"video": "videojs",
"vue": "vue",
"vue-router": "vue-router",
"webtorrent": "webtorrent",
"when": "when",
"winston": "winston",
"wrench-js": "wrench",
"ws": "ws",
"xlsx": "xlsx",
"xml2json": "x2js",
"xmlbuilder-js": "xmlbuilder",
"xregexp": "xregexp",
"yargs": "yargs",
"yosay": "yosay",
"yui": "yui",
"yui3": "yui",
"zepto": "zepto",
"ZeroClipboard": "zeroclipboard",
"ZSchema-browser": "z-schema"
}
}