This commit is contained in:
hanif salafi 2025-09-10 23:51:03 +07:00
commit 0ba8138779
9 changed files with 268 additions and 110 deletions

View File

@ -0,0 +1,9 @@
export const metadata = {
title: "Ticketing",
};
const Layout = ({ children }: { children: React.ReactNode }) => {
return <>{children}</>;
};
export default Layout;

View File

@ -0,0 +1,26 @@
import SiteBreadcrumb from "@/components/site-breadcrumb";
import TicketingTable from "../components/table";
import { useParams } from "next/navigation";
const TicketingPage = async () => {
return (
<div>
<SiteBreadcrumb />
<section
id="table"
className="flex flex-col gap-2 bg-white dark:bg-black rounded-lg p-3 mt-5"
>
{/* <div className="flex justify-between py-3">
<p className="text-lg">Semua Ticket : 0</p>
</div> */}
<TicketingTable />
</section>
</div>
);
};
export default TicketingPage;

View File

@ -16,6 +16,7 @@ import {
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import FormDetailTicketing from "@/components/form/ticketing/ticketing-detail-form"; import FormDetailTicketing from "@/components/form/ticketing/ticketing-detail-form";
import { useParams } from "next/navigation";
/** /**
* TicketingLayout * TicketingLayout
@ -35,14 +36,15 @@ import FormDetailTicketing from "@/components/form/ticketing/ticketing-detail-fo
type Issue = { type Issue = {
id: string | number; id: string | number;
title?: string; title?: string;
source?: string; // e.g., "instagram", "facebook", "tiktok", "youtube", "comment" source?: string;
createdAt?: string; createdAt?: string;
status?: string; status?: string;
timeAgo?: string; timeAgo?: string;
// any other fields from API
}; };
export default function TicketingLayout() { export default function TicketingTable() {
const params = useParams();
const mediaId = params?.media_id;
const [issues, setIssues] = React.useState<Issue[]>([]); const [issues, setIssues] = React.useState<Issue[]>([]);
const [totalElements, setTotalElements] = React.useState<number>(0); const [totalElements, setTotalElements] = React.useState<number>(0);
const [totalPages, setTotalPages] = React.useState<number>(1); const [totalPages, setTotalPages] = React.useState<number>(1);
@ -78,7 +80,7 @@ export default function TicketingLayout() {
async function fetchData() { async function fetchData() {
try { try {
const res = await ticketingPagination(search, pageSize, page - 1); const res = await ticketingPagination(search, pageSize, page - 1, mediaId == 'all' ? "" : mediaId as string);
const data = res?.data?.data; const data = res?.data?.data;
const content = data?.content || []; const content = data?.content || [];
const mapped: Issue[] = content.map((it: any, idx: number) => ({ const mapped: Issue[] = content.map((it: any, idx: number) => ({

View File

@ -1743,6 +1743,117 @@ export default function FormImageUpdate() {
</Fragment> </Fragment>
) : null} ) : null}
{files.length > 0 && ( {files.length > 0 && (
<div className="mt-4 space-y-2">
<Label className="text-lg font-semibold">
{" "}
{t("file-media", { defaultValue: "File Media" })}
</Label>
<div className="grid gap-4">
{files.map((file: any) => (
<div
key={file.id}
className="flex items-center border p-2 rounded-md"
>
<img
src={file.thumbnailFileUrl}
alt={file.fileName}
className="w-16 h-16 object-cover rounded-md mr-4"
/>
<div className="flex flex-wrap gap-3 items-center ">
<div className="flex-grow">
<p className="font-medium">{file.fileName}</p>
<a
href={file.url}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 text-sm"
>
{t("view-file", {
defaultValue: "View File",
})}
</a>
</div>
<div>
<Label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedOptions[
file.id
]?.includes("all")}
onChange={() =>
handleCheckboxChangeImage(
file.id,
"all"
)
}
className="form-checkbox"
/>
<span>
{t("all", { defaultValue: "All" })}
</span>
</Label>
</div>
<div>
<Label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedOptions[
file.id
]?.includes("nasional")}
onChange={() =>
handleCheckboxChangeImage(
file.id,
"nasional"
)
}
className="form-checkbox"
/>
<span>Nasional</span>
</Label>
</div>
<div>
<Label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedOptions[
file.id
]?.includes("wilayah")}
onChange={() =>
handleCheckboxChangeImage(
file.id,
"wilayah"
)
}
className="form-checkbox"
/>
<span>Wilayah</span>
</Label>
</div>
<div>
<Label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedOptions[
file.id
]?.includes("internasional")}
onChange={() =>
handleCheckboxChangeImage(
file.id,
"internasional"
)
}
className="form-checkbox"
/>
<span>Internasional</span>
</Label>
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* {files.length > 0 && (
<div className="mt-4"> <div className="mt-4">
<Label className="text-lg font-semibold"> <Label className="text-lg font-semibold">
{" "} {" "}
@ -1783,7 +1894,6 @@ export default function FormImageUpdate() {
Pengaturan Distribusi Pengaturan Distribusi
</h5> </h5>
{/* Checkbox Tingkat Utama */}
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<p className="text-sm font-medium text-gray-700 mb-3"> <p className="text-sm font-medium text-gray-700 mb-3">
@ -1837,14 +1947,12 @@ export default function FormImageUpdate() {
</div> </div>
</div> </div>
{/* Detail Wilayah */}
{fileUnitSelections[index]?.wilayah && ( {fileUnitSelections[index]?.wilayah && (
<div className="border-t border-gray-200 pt-2"> <div className="border-t border-gray-200 pt-2">
<p className="text-sm font-medium text-gray-700 mb-2"> <p className="text-sm font-medium text-gray-700 mb-2">
Detail Wilayah: Detail Wilayah:
</p> </p>
{/* Checkbox Sub-kategori dengan tombol Kustom sejajar */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-3"> <div className="grid grid-cols-1 md:grid-cols-4 gap-3">
{[ {[
{ key: "polda", label: "POLDA" }, { key: "polda", label: "POLDA" },
@ -1884,7 +1992,6 @@ export default function FormImageUpdate() {
</div> </div>
))} ))}
{/* Tombol Kustom sejajar dengan checkbox */}
<div className="flex items-center justify-center p-3"> <div className="flex items-center justify-center p-3">
<Dialog> <Dialog>
<DialogTrigger asChild> <DialogTrigger asChild>
@ -1917,7 +2024,6 @@ export default function FormImageUpdate() {
key={polda.id} key={polda.id}
className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow" className="border border-gray-200 rounded-lg p-2 bg-white hover:shadow-sm transition-shadow"
> >
{/* Header POLDA */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<Label className="flex items-center gap-3 flex-1 cursor-pointer"> <Label className="flex items-center gap-3 flex-1 cursor-pointer">
<Checkbox <Checkbox
@ -1969,13 +2075,11 @@ export default function FormImageUpdate() {
)} )}
</div> </div>
{/* Sub-items */}
{polda.subDestination && {polda.subDestination &&
expandedPolda[ expandedPolda[
polda.id polda.id
] && ( ] && (
<div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2"> <div className="max-h-[200px] overflow-y-auto border-t border-gray-100 pt-2">
{/* Tombol Pilih Semua untuk sub-items */}
<div className="mb-2 flex justify-start"> <div className="mb-2 flex justify-start">
{(() => { {(() => {
const allSubItemsChecked = const allSubItemsChecked =
@ -2109,7 +2213,7 @@ export default function FormImageUpdate() {
))} ))}
</div> </div>
</div> </div>
)} )} */}
</Fragment> </Fragment>
</div> </div>
</div> </div>

View File

@ -170,7 +170,6 @@ export default function FormConvertSPIT() {
const t = useTranslations("Form"); const t = useTranslations("Form");
const { id } = useParams() as { id: string }; const { id } = useParams() as { id: string };
const [isAlreadySaved, setIsAlreadySaved] = useState(false); const [isAlreadySaved, setIsAlreadySaved] = useState(false);
const { const {
control, control,
handleSubmit, handleSubmit,

View File

@ -972,7 +972,7 @@ export default function FormVideoUpdate() {
</div> </div>
</Card> </Card>
<div className="w-full lg:w-4/12"> <div className="w-full lg:w-4/12">
<Card className=" h-[800px]"> <Card className="h-fit">
<div className="px-3 py-3"> <div className="px-3 py-3">
<div className="space-y-2"> <div className="space-y-2">
<Label>{t("creator", { defaultValue: "Creator" })}</Label> <Label>{t("creator", { defaultValue: "Creator" })}</Label>

View File

@ -13,7 +13,7 @@ export const NAVIGATION_CONFIG: NavigationConfig[] = [
{ roleId: 2, path: "/in/dashboard/executive", label: "Executive Dashboard" }, { roleId: 2, path: "/in/dashboard/executive", label: "Executive Dashboard" },
{ roleId: 3, path: "/in/dashboard", label: "Dashboard" }, { roleId: 3, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 4, path: "/in/dashboard", label: "Dashboard" }, { roleId: 4, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 9, path: "/in/supervisor/ticketing", label: "Ticketing" }, { roleId: 9, path: "/in/supervisor/ticketing/all", label: "Ticketing" },
{ roleId: 10, path: "/in/dashboard", label: "Dashboard" }, { roleId: 10, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 11, path: "/in/dashboard", label: "Dashboard" }, { roleId: 11, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 12, path: "/in/dashboard", label: "Dashboard" }, { roleId: 12, path: "/in/dashboard", label: "Dashboard" },

View File

@ -2642,6 +2642,8 @@ export function getMenuList(pathname: string, t: any): Group[] {
(Number(roleId) == 3 || Number(roleId) == 14 || Number(roleId) == 15) && (Number(roleId) == 3 || Number(roleId) == 14 || Number(roleId) == 15) &&
Number(levelNumber) == 3 Number(levelNumber) == 3
) { ) {
const hideForRole3 = Number(roleId) === 3;
if (Number(userParentLevelId) != 771) { if (Number(userParentLevelId) != 771) {
menusSelected = [ menusSelected = [
{ {
@ -2697,13 +2699,17 @@ export function getMenuList(pathname: string, t: any): Group[] {
icon: "heroicons:share", icon: "heroicons:share",
children: [], children: [],
}, },
{ ...(!hideForRole3
href: "/contributor/content/spit", ? [
label: "spit", {
active: pathname.includes("/content/spit"), href: "/contributor/content/spit",
icon: "heroicons:credit-card", label: "spit",
children: [], active: pathname.includes("/content/spit"),
}, icon: "heroicons:credit-card",
children: [],
},
]
: []),
// { // {
// href: "/contributor/content/nulis-ai", // href: "/contributor/content/nulis-ai",
// label: "nulis ai", // label: "nulis ai",
@ -2729,35 +2735,39 @@ export function getMenuList(pathname: string, t: any): Group[] {
}, },
], ],
}, },
{ ...(!hideForRole3
groupLabel: "", ? [
id: "planning", {
menus: [ groupLabel: "",
{ id: "planning",
id: "planning", menus: [
href: "/contributor/planning", {
label: t("planning"), id: "planning",
active: pathname.includes("/planning"), href: "/contributor/planning",
icon: "pajamas:planning", label: t("planning"),
submenus: [ active: pathname.includes("/planning"),
{ icon: "pajamas:planning",
href: "/contributor/planning/mediahub", submenus: [
label: "mediaHub", {
active: pathname.includes("/planning/mediahub"), href: "/contributor/planning/mediahub",
icon: "heroicons:arrow-trending-up", label: "mediaHub",
children: [], active: pathname.includes("/planning/mediahub"),
}, icon: "heroicons:arrow-trending-up",
{ children: [],
href: "/contributor/planning/medsos-mediahub", },
label: "medsos mediahub", {
active: pathname.includes("/planning/medsos-mediahub"), href: "/contributor/planning/medsos-mediahub",
icon: "heroicons:shopping-cart", label: "medsos mediahub",
children: [], active: pathname.includes("/planning/medsos-mediahub"),
}, icon: "heroicons:shopping-cart",
], children: [],
}, },
], ],
}, },
],
},
]
: []),
{ {
groupLabel: "", groupLabel: "",
id: "task", id: "task",
@ -2808,20 +2818,24 @@ export function getMenuList(pathname: string, t: any): Group[] {
}, },
], ],
}, },
{ ...(!hideForRole3
groupLabel: "", ? [
id: "blog", {
menus: [ groupLabel: "",
{ id: "blog",
id: "blog", menus: [
href: "/contributor/blog", {
label: t("blog"), id: "blog",
active: pathname.includes("/blog"), href: "/contributor/blog",
icon: "fluent:clipboard-text-32-regular", label: t("blog"),
submenus: [], active: pathname.includes("/blog"),
}, icon: "fluent:clipboard-text-32-regular",
], submenus: [],
}, },
],
},
]
: []),
{ {
groupLabel: "", groupLabel: "",
id: "curatedcontent", id: "curatedcontent",
@ -2864,42 +2878,46 @@ export function getMenuList(pathname: string, t: any): Group[] {
}, },
], ],
}, },
{ ...(!hideForRole3
groupLabel: "", ? [
id: "settings", {
menus: [ groupLabel: "",
{ id: "settings",
id: "settings", menus: [
href: "/admin/settings", {
label: t("settings"), id: "settings",
active: pathname.includes("/settinng"), href: "/admin/settings",
icon: "material-symbols:settings", label: t("settings"),
submenus: [ active: pathname.includes("/settinng"),
{ icon: "material-symbols:settings",
href: "/admin/settings/banner", submenus: [
label: "Banner", {
active: pathname === "/admin/settings/banner", href: "/admin/settings/banner",
icon: "heroicons:arrow-trending-up", label: "Banner",
children: [], active: pathname === "/admin/settings/banner",
}, icon: "heroicons:arrow-trending-up",
{ children: [],
href: "/admin/settings/popup", },
label: "Pop Up", {
active: pathname === "/admin/settings/popup", href: "/admin/settings/popup",
icon: "heroicons:arrow-trending-up", label: "Pop Up",
children: [], active: pathname === "/admin/settings/popup",
}, icon: "heroicons:arrow-trending-up",
{ children: [],
href: "/admin/settings/iklan", },
label: "Iklan", {
active: pathname === "/admin/settings/iklan", href: "/admin/settings/iklan",
icon: "heroicons:arrow-trending-up", label: "Iklan",
children: [], active: pathname === "/admin/settings/iklan",
}, icon: "heroicons:arrow-trending-up",
], children: [],
}, },
], ],
}, },
],
},
]
: []),
]; ];
} else if (Number(userParentLevelId) == 771) { } else if (Number(userParentLevelId) == 771) {
menusSelected = [ menusSelected = [
@ -3189,28 +3207,28 @@ export function getMenuList(pathname: string, t: any): Group[] {
icon: "mdi:ticket-outline", icon: "mdi:ticket-outline",
submenus: [ submenus: [
{ {
href: "/supervisor/ticketing", href: "/supervisor/ticketing/all",
label: "All", label: "All",
active: pathname.includes("/supervisor/ticketing"), active: pathname.includes("/ticketing/all"),
icon: "solar:inbox-line-outline", icon: "solar:inbox-line-outline",
children: [], children: [],
}, },
{ {
href: "/", href: "/supervisor/ticketing/4",
label: "Instagram", label: "Instagram",
active: pathname.includes("/ticketing/instagram"), active: pathname.includes("/ticketing/4"),
icon: "ri:chat-private-line", icon: "ri:chat-private-line",
children: [], children: [],
}, },
{ {
href: "/", href: "/supervisor/ticketing/2",
label: "Facebook", label: "Facebook",
active: pathname.includes("/ticketing/facebook"), active: pathname.includes("/ticketing/2"),
icon: "ri:share-forward-2-fill", icon: "ri:share-forward-2-fill",
children: [], children: [],
}, },
{ {
href: "/", href: "/supervisor/ticketing/5",
label: "Youtube", label: "Youtube",
active: pathname.includes("/ticketing/youtube"), active: pathname.includes("/ticketing/youtube"),
icon: "ri:share-forward-2-fill", icon: "ri:share-forward-2-fill",

View File

@ -1,8 +1,8 @@
import { title } from "process"; import { title } from "process";
import { httpGetInterceptor } from "../http-config/http-interceptor-service"; import { httpGetInterceptor } from "../http-config/http-interceptor-service";
export async function ticketingPagination(title: string = '', size: number, page: number) { export async function ticketingPagination(title: string = '', size: number, page: number, mediaId: string) {
return await httpGetInterceptor( return await httpGetInterceptor(
`/ticketing/pagination?enablePage=1&page=${page}&size=${size}&title=${title}` `/ticketing/pagination?enablePage=1&page=${page}&size=${size}&title=${title}&typeId=${mediaId}`
); );
} }