Publikasi
+
+ Publikasi
@@ -55,6 +73,9 @@ export default function SidebarNav() {
Channel Humas Polri
+
+
+
@@ -64,9 +85,12 @@ export default function SidebarNav() {
-
+
+
+
+
diff --git a/components/detail/Propim.tsx b/components/detail/Propim.tsx
index 40a8aa7..ef375f0 100644
--- a/components/detail/Propim.tsx
+++ b/components/detail/Propim.tsx
@@ -1,6 +1,5 @@
'use client'
-import { Card, CardBody, Tab, Tabs } from '@nextui-org/react'
-import React from 'react'
+import { Tab, Tabs } from '@nextui-org/react'
export default function Task() {
return (
diff --git a/components/form/form-article.tsx b/components/form/form-article.tsx
new file mode 100644
index 0000000..55e99a0
--- /dev/null
+++ b/components/form/form-article.tsx
@@ -0,0 +1,264 @@
+'use client'
+import { Button, Card, Chip, Input, Select, SelectItem, Selection } from '@nextui-org/react'
+import JoditEditor from 'jodit-react';
+import React, { useRef, useState } from 'react'
+import * as z from "zod";
+import Swal from 'sweetalert2';
+import withReactContent from 'sweetalert2-react-content';
+import { useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { createArticle } from '@/service/article';
+import { error } from '@/config/swal';
+
+const articleSchema = z.object({
+ title: z.string().min(1, { message: "Required" }),
+ article: z.string().min(1, { message: "Required" }),
+ slug: z.string().min(1, { message: "Required" }),
+ tags: z.string().min(0, { message: "Required" }).optional(),
+ description: z.string().min(1, { message: "Required" }).optional(),
+
+});
+
+export default function FormArticle() {
+ const [id, setId] = useState
();
+ const [title, setTitle] = useState("");
+ const [article, setArticle] = React.useState(new Set([]));
+ const [slug, setSlug] = useState("");
+ const [tags, setTags] = useState([]);
+ const [newTags, setNewTags] = useState("");
+ const editor = useRef(null);
+ const [content, setContent] = useState('');
+ const MySwal = withReactContent(Swal);
+
+ const formOptions = { resolver: zodResolver(articleSchema) };
+ type MicroIssueSchema = z.infer;
+ const {
+ register,
+ control,
+ handleSubmit,
+ setValue,
+ formState: { errors },
+ } = useForm(formOptions);
+
+ const TypeId = [
+ {
+ key: 1,
+ label: "Article"
+ },
+ {
+ key: 2,
+ label: "Magazine"
+ },
+ ]
+
+ const CategoryArticle = [
+ {
+ key: 1,
+ label: "Article"
+ },
+ {
+ key: 2,
+ label: "Magazine"
+ },
+ ]
+
+ const handleClose = (tagsToRemove: string) => {
+ setTags(tags.filter((tag) => tag !== tagsToRemove));
+ if (tags.length === 1) {
+ setTags([]);
+ }
+ };
+
+ const handleAddTags = (e: any) => {
+ if (newTags.trim() !== "") {
+ setTags([...tags, newTags.trim()]);
+ setNewTags("");
+ e.preventDefault();
+ }
+ };
+
+ const handleKeyDown = (event: any) => {
+ if (event.key === "Enter") {
+ handleAddTags(event);
+ }
+ };
+
+
+ async function save(data: any,) {
+ const formData = {
+ id: id,
+ title,
+ jenisArtikel: article,
+ slug,
+ tags,
+ description: content,
+ };
+
+ console.log("Form Data:", formData);
+ if (id != undefined) {
+ formData.id = id;
+ }
+
+ const response = await createArticle(formData);
+
+ if (response?.error) {
+ error(response.message);
+ return false;
+ }
+ };
+
+ async function onSubmit(data: any) {
+ MySwal.fire({
+ title: "Simpan Data",
+ text: "",
+ icon: "warning",
+ showCancelButton: true,
+ cancelButtonColor: "#d33",
+ confirmButtonColor: "#3085d6",
+ confirmButtonText: "Simpan",
+ }).then((result) => {
+ if (result.isConfirmed) {
+ save(data);
+ }
+ });
+ }
+ return (
+
+ )
+}
diff --git a/components/icons.tsx b/components/icons.tsx
index 99fd9b9..a417d7c 100644
--- a/components/icons.tsx
+++ b/components/icons.tsx
@@ -770,4 +770,710 @@ export const Checklist = ({
-);
\ No newline at end of file
+);
+
+export const ChevronLeftIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const DotsYIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+
+export const DotsXIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const EyeIconMdi = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+
+export const OnlineIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const OfflineIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+
+);
+
+export const CreateIconIon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const DeleteIcon = ({
+ size,
+ height = 12,
+ width = 10,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+
+export const AccIcon = ({
+ size,
+ height = 12,
+ width = 10,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const CloseIcon = ({
+ size,
+ height = 12,
+ width = 10,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const RefundIcon = ({
+ size,
+ height = 12,
+ width = 10,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const AddIcon = ({
+ size,
+ height = 12,
+ width = 12,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const CompanyIcon = ({
+ size,
+ height = 12,
+ width = 12,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const EmailIcon = ({
+ size,
+ height = 12,
+ width = 12,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const PhoneIcon = ({
+ size,
+ height = 12,
+ width = 12,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const MessageIcon = ({
+ size,
+ height = 12,
+ width = 12,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+
+export const UserIcon = ({
+ size,
+ height = 12,
+ width = 12,
+ fill = "none",
+ ...props
+}: IconSvgProps) => (
+
+
+
+);
+
+export const EyeOffIconMdi = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const DateIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const WarningIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const PasswordIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const TimeIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const VolumeLowIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const VolumeHighIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+export const FormVerticalIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const FormHorizontalIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const FormCustomIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const FormLayoutIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const FormValidationIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const FormWizardIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const FacebookIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const GoogleIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
diff --git a/components/icons/dashboard-icon.tsx b/components/icons/dashboard-icon.tsx
new file mode 100644
index 0000000..0ba10c7
--- /dev/null
+++ b/components/icons/dashboard-icon.tsx
@@ -0,0 +1,172 @@
+import * as React from "react";
+import { IconSvgProps } from "@/types/globals";
+
+
+export const DashboardUserIcon = ({
+ size,
+ height = 48,
+ width = 48,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const DashboardBriefcaseIcon = ({
+ size,
+ height = 48,
+ width = 48,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+export const DashboardMailboxIcon = ({
+ size,
+ height = 48,
+ width = 48,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+export const DashboardBookmarkIcon = ({
+ size,
+ height = 48,
+ width = 48,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+export const DashboardSpeecIcon = ({
+ size,
+ height = 48,
+ width = 48,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const DashboardConnectIcon = ({
+ size,
+ height = 48,
+ width = 48,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+
+export const DashboardTopLeftPointIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+
+export const DashboardRightDownPointIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
\ No newline at end of file
diff --git a/components/icons/sidebar-icon.tsx b/components/icons/sidebar-icon.tsx
new file mode 100644
index 0000000..691ca2c
--- /dev/null
+++ b/components/icons/sidebar-icon.tsx
@@ -0,0 +1,167 @@
+import * as React from "react";
+import { IconSvgProps } from "@/types/globals";
+
+export const MenuBurgerIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const DashboardIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const HomeIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const Submenu1Icon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const Submenu2Icon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
+
+export const InfoCircleIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+);
+
+
+export const MinusCircleIcon = ({
+ size,
+ height = 24,
+ width = 24,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+
+
+);
+
+export const TableIcon = ({
+ size,
+ height = 24,
+ width = 22,
+ fill = "currentColor",
+ ...props
+}: IconSvgProps) => (
+
+);
\ No newline at end of file
diff --git a/components/layout/admin-layout.tsx b/components/layout/admin-layout.tsx
new file mode 100644
index 0000000..2b4e2c4
--- /dev/null
+++ b/components/layout/admin-layout.tsx
@@ -0,0 +1,39 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import Sidebar from "../sidebar/sidebar";
+import { SidebarProvider } from "../sidebar/sidebar-context";
+import { Breadcrumb } from "../ui/breadcrumb";
+
+interface Props {
+ children: React.ReactNode;
+}
+
+export const AdminLayout = ({ children }: Props) => {
+ const [isOpen, setIsOpen] = useState(true);
+ const updateSidebarData = (newData: boolean) => {
+ setIsOpen(newData);
+ };
+
+ const [hasMounted, setHasMounted] = useState(false);
+
+ // Hooks
+ useEffect(() => {
+ setHasMounted(true);
+ }, []);
+
+ // Render
+ if (!hasMounted) return null;
+
+ return (
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/components/main/dashboard/chart/column-chart.tsx b/components/main/dashboard/chart/column-chart.tsx
new file mode 100644
index 0000000..e1a9181
--- /dev/null
+++ b/components/main/dashboard/chart/column-chart.tsx
@@ -0,0 +1,81 @@
+import React, { Component } from 'react';
+import ReactApexChart from 'react-apexcharts';
+
+interface State {
+ series: { name: string; data: number[] }[];
+ options: {
+ chart: { type: string; height: number };
+ plotOptions: { bar: { colors: { ranges: { from: number; to: number; color: string }[] }; columnWidth: string } };
+ dataLabels: { enabled: boolean };
+ yaxis: { title: { text: string }; labels: { formatter: (y: number) => string } };
+ xaxis: { type: string; categories: string[]; labels: { rotate: number } };
+ };
+}
+
+class ApexChartColumn extends Component<{}, State> {
+ render() {
+ return (
+
+
+ {
+ return y.toFixed(0);
+ },
+ },
+ },
+ xaxis: {
+ type: 'datetime',
+ categories: [
+ '2020-05-01', '2020-05-02', '2020-05-03', '2020-05-04', '2020-05-05',
+ ],
+ labels: {
+ rotate: -90,
+ },
+ },
+
+ }}
+ series={[
+ {
+ name: 'Earning This Month ',
+ data: [
+ 1.45, 5.9, -0.42, -12.6, -18.1
+ ],
+ },
+ ]} type="bar" height={350} />
+
+
+
+ );
+ }
+}
+
+export default ApexChartColumn;
\ No newline at end of file
diff --git a/components/main/dashboard/chart/donut-chart.tsx b/components/main/dashboard/chart/donut-chart.tsx
new file mode 100644
index 0000000..921c099
--- /dev/null
+++ b/components/main/dashboard/chart/donut-chart.tsx
@@ -0,0 +1,51 @@
+import React, { Component } from 'react';
+import ReactApexChart from 'react-apexcharts';
+
+interface State {
+ series: { name: string; data: number[] }[];
+ options: {
+ chart: { type: string; height: number };
+ dataLabels: { enabled: boolean };
+ };
+}
+
+class ApexChartDonut extends Component<{}, State> {
+ render() {
+ return (
+
+ );
+ }
+}
+
+export default ApexChartDonut;
\ No newline at end of file
diff --git a/components/main/dashboard/chart/line-area-chart.tsx b/components/main/dashboard/chart/line-area-chart.tsx
new file mode 100644
index 0000000..7ea3ed9
--- /dev/null
+++ b/components/main/dashboard/chart/line-area-chart.tsx
@@ -0,0 +1,74 @@
+import React, { Component } from 'react';
+import ReactApexChart from 'react-apexcharts';
+
+interface State {
+ series: { name: string; data: number[] }[];
+ options: {
+ chart: { type: string; height: number };
+ plotOptions: { bar: { colors: { ranges: { from: number; to: number; color: string }[] }; columnWidth: string } };
+ dataLabels: { enabled: boolean };
+ yaxis: { title: { text: string }; labels: { formatter: (y: number) => string } };
+ xaxis: { type: string; categories: string[]; labels: { rotate: number } };
+ };
+}
+
+class ApexChartLineArea extends Component<{}, State> {
+ render() {
+ return (
+
+
+
+ );
+ }
+}
+
+export default ApexChartLineArea;
\ No newline at end of file
diff --git a/components/main/dashboard/dashboard-container.tsx b/components/main/dashboard/dashboard-container.tsx
new file mode 100644
index 0000000..0d09829
--- /dev/null
+++ b/components/main/dashboard/dashboard-container.tsx
@@ -0,0 +1,176 @@
+'use client'
+import { DashboardBookmarkIcon, DashboardBriefcaseIcon, DashboardConnectIcon, DashboardMailboxIcon, DashboardRightDownPointIcon, DashboardSpeecIcon, DashboardTopLeftPointIcon, DashboardUserIcon } from "@/components/icons/dashboard-icon";
+import { Submenu1Icon } from "@/components/icons/sidebar-icon";
+import { Button, Select, SelectItem, SelectSection } from "@nextui-org/react";
+import ApexChartColumn from "./chart/column-chart";
+import ApexChartDonut from "./chart/donut-chart";
+import ApexChartLineArea from "./chart/line-area-chart";
+
+export default function DashboardContainer() {
+ return (
+
+
+
+
+
+
+
Revenue Update
+ Overview of Profit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
$63,489.50
+
Total Earnings
+
+
+
+
+
+
Earning this month
+
$48,820
+
+
+
+
+
+
Expense this month
+
$26,498
+
+
+
+
+
+
+
+
+
+
Yearly Breakup
+
+
+
+
+
+
+
+
+
+
+
+
+
bawah
+
+
+ )
+}
\ No newline at end of file
diff --git a/components/navbar/NavbarHumas.tsx b/components/navbar/NavbarHumas.tsx
index a4e5cc5..c6e7fc3 100644
--- a/components/navbar/NavbarHumas.tsx
+++ b/components/navbar/NavbarHumas.tsx
@@ -1,20 +1,39 @@
'use client'
+import { siteConfig } from '@/config/site';
import { Input } from '@nextui-org/input';
import { Navbar, NavbarContent, NavbarItem, NavbarMenu, NavbarMenuItem, NavbarMenuToggle } from '@nextui-org/navbar';
-import { Button, Dropdown, DropdownItem, DropdownMenu, DropdownSection, DropdownTrigger, autocomplete } from '@nextui-org/react';
-import Link from "next/link";
-import { ChevronDownIcon, ChevronRightIcon, ChevronRightWhite, ChevronUpIcon, FbIcon, IdnIcon, IgIcon, SearchIcon, TtIcon, TwIcon, YtIcon } from '../icons';
-import { ThemeSwitch } from '../theme-switch';
+import { Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger } from '@nextui-org/react';
import Image from 'next/image';
-import { siteConfig } from '@/config/site';
+import Link from "next/link";
import { useState } from 'react';
+import { ChevronDownIcon, ChevronRightIcon, ChevronUpIcon, FbIcon, IdnIcon, IgIcon, SearchIcon, TtIcon, TwIcon, YtIcon } from '../icons';
+import { ThemeSwitch } from '../theme-switch';
+
+interface MenuItem {
+ key: string;
+ label: string;
+ href: URL;
+ submenu?: SubMenuItem[];
+}
+
+interface SubMenuItem {
+ label: string;
+ href: string;
+}
+
+interface DropdownOpenState {
+ [key: string]: boolean;
+}
+
export default function NavbarHumas() {
+ const [dropdownOpen, setDropdownOpen] = useState({});
- const [dropdownOpen, setDropdownOpen] = useState(false);
-
- const toggleDropdown = () => {
- setDropdownOpen(!dropdownOpen);
+ const toggleDropdown = (key: any) => {
+ setDropdownOpen({
+ ...dropdownOpen,
+ [key]: !dropdownOpen[key]
+ });
};
const searchInput = (
@@ -138,7 +157,7 @@ export default function NavbarHumas() {
-