fix: logo polda and satker
This commit is contained in:
commit
444ddd6fcb
|
|
@ -40,19 +40,19 @@ const columns: ColumnDef<any>[] = [
|
|||
},
|
||||
|
||||
{
|
||||
accessorKey: "name",
|
||||
accessorKey: "fullname",
|
||||
header: "Nama",
|
||||
cell: ({ row }) => <span>{row.getValue("name")}</span>,
|
||||
cell: ({ row }) => <span>{row.getValue("fullname")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "region",
|
||||
accessorKey: "address",
|
||||
header: "Wilayah",
|
||||
cell: ({ row }) => <span>{row.getValue("region")}</span>,
|
||||
cell: ({ row }) => <span>{row.getValue("address")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "skills",
|
||||
accessorKey: "role.name",
|
||||
header: "Bidang Keahlian",
|
||||
cell: ({ row }) => <span>{row.getValue("skills")}</span>,
|
||||
cell: ({ row }) => <span>{row.original.role?.name ?? "-"}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import { listEnableCategory } from "@/service/content/content";
|
|||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { close, loading } from "@/config/swal";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { listDataExperts } from "@/service/experts/experts";
|
||||
|
||||
const dummyData = [
|
||||
{
|
||||
|
|
@ -93,6 +94,7 @@ const AddExpertTable = () => {
|
|||
const [statusFilter, setStatusFilter] = React.useState<number[]>([]);
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
@ -145,19 +147,44 @@ const AddExpertTable = () => {
|
|||
});
|
||||
}, [page, showData]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
loading();
|
||||
// async function fetchData() {
|
||||
// try {
|
||||
// loading();
|
||||
|
||||
const contentData = dummyData;
|
||||
// const contentData = dummyData;
|
||||
// contentData.forEach((item: any, index: number) => {
|
||||
// item.no = (page - 1) * Number(showData) + index + 1;
|
||||
// });
|
||||
|
||||
// setDataTable(contentData);
|
||||
// setTotalData(contentData?.length);
|
||||
// setTotalPage(1);
|
||||
// close();
|
||||
// } catch (error) {
|
||||
// console.error("Error fetching tasks:", error);
|
||||
// }
|
||||
// }
|
||||
|
||||
async function fetchData() {
|
||||
// const formattedStartDate = startDate
|
||||
// ? format(new Date(startDate), "yyyy-MM-dd")
|
||||
// : "";
|
||||
// const formattedEndDate = endDate
|
||||
// ? format(new Date(endDate), "yyyy-MM-dd")
|
||||
// : "";
|
||||
try {
|
||||
// const isForSelf = Number(roleId) === 4;
|
||||
const res = await listDataExperts(limit, page - 1);
|
||||
|
||||
const data = res?.data?.data;
|
||||
const contentData = data?.content;
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
item.no = (page - 1) * Number(showData) + index + 1;
|
||||
item.no = (page - 1) * limit + index + 1;
|
||||
});
|
||||
|
||||
setDataTable(contentData);
|
||||
setTotalData(contentData?.length);
|
||||
setTotalPage(1);
|
||||
close();
|
||||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
} catch (error) {
|
||||
console.error("Error fetching tasks:", error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,27 +23,30 @@ import {
|
|||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { useEffect, useState } from "react";
|
||||
import { AdministrationLevelList, getListCompetencies, getListExperiences, saveUserInternal, saveUserRolePlacements } from "@/service/management-user/management-user";
|
||||
import { loading } from "@/config/swal";
|
||||
|
||||
const FormSchema = z.object({
|
||||
name: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
username: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
password: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
phoneNumber: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
email: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
position: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
region: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
skills: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
experience: z.string({
|
||||
experiences: z.string({
|
||||
required_error: "Required",
|
||||
}),
|
||||
company: z.string({
|
||||
|
|
@ -51,12 +54,34 @@ const FormSchema = z.object({
|
|||
}),
|
||||
});
|
||||
|
||||
export type Placements = {
|
||||
index: number;
|
||||
roleId?: string;
|
||||
userLevelId?: number;
|
||||
}
|
||||
|
||||
export default function AddExpertForm() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
});
|
||||
const [incrementId, setIncrementId] = useState(1);
|
||||
const [placementRows, setPlacementRows] = useState<Placements[]>([{ index: 0, roleId: "", userLevelId: 0 }]);
|
||||
const [userCompetencies, setUserCompetencies] = useState<any>();
|
||||
const [userExperiences, setUserExperiences] = useState<any>();
|
||||
const [userLevels, setUserLevels] = useState<any>();
|
||||
|
||||
const roleSelection = [
|
||||
{
|
||||
id: "11",
|
||||
name: "Koor Kurator",
|
||||
},
|
||||
{
|
||||
id: "12",
|
||||
name: "Kurator",
|
||||
}
|
||||
];
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||
MySwal.fire({
|
||||
|
|
@ -77,9 +102,85 @@ export default function AddExpertForm() {
|
|||
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||
console.log("data", data);
|
||||
|
||||
// successSubmit();
|
||||
const dataReq = {
|
||||
firstName: data.name,
|
||||
username: data.username,
|
||||
email: data.email,
|
||||
password: data.password,
|
||||
adress: "",
|
||||
roleId: "EXP-ID",
|
||||
phoneNumber: data.phoneNumber,
|
||||
userCompetencyId: data.skills,
|
||||
userExperienceId: data.experiences,
|
||||
companyName: data.company,
|
||||
}
|
||||
|
||||
loading();
|
||||
const res = await saveUserInternal(dataReq);
|
||||
const resData = res?.data?.data;
|
||||
const userProfileId = resData.id;
|
||||
|
||||
var placementArr: any[] = [];
|
||||
placementRows.forEach((row: any) => {
|
||||
placementArr.push({
|
||||
roleId: Number(row.roleId),
|
||||
userLevelId: Number(row.userLevelId),
|
||||
userProfileId: userProfileId,
|
||||
});
|
||||
});
|
||||
|
||||
const dataReq2 = {
|
||||
userId: userProfileId,
|
||||
placements: placementArr
|
||||
}
|
||||
const res2 = await saveUserRolePlacements(dataReq2);
|
||||
const resData2 = res2?.data?.data;
|
||||
|
||||
success("/admin/add-experts");
|
||||
};
|
||||
|
||||
|
||||
function success(redirect: string): void {
|
||||
MySwal.fire({
|
||||
title: '<p class="text-green-600 font-bold">Sukses</p>',
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: '<span class="text-white">OK</span>',
|
||||
allowOutsideClick: false,
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
router.push(redirect);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getDataAdditional();
|
||||
}, []);
|
||||
|
||||
async function getDataAdditional() {
|
||||
const resCompetencies = await getListCompetencies();
|
||||
setUserCompetencies(resCompetencies?.data?.data);
|
||||
|
||||
const resExperiences = await getListExperiences();
|
||||
setUserExperiences(resExperiences?.data?.data);
|
||||
|
||||
const resUserLevels = await AdministrationLevelList();
|
||||
const data = resUserLevels?.data?.data;
|
||||
var levelsArr: any[] = [];
|
||||
data.forEach((levels: any) => {
|
||||
levelsArr.push({
|
||||
id: levels.id,
|
||||
label: levels.name,
|
||||
name: levels.name,
|
||||
value: String(levels.id),
|
||||
levelNumber: levels.levelNumber,
|
||||
});
|
||||
});
|
||||
setUserLevels(levelsArr);
|
||||
}
|
||||
|
||||
|
||||
function successSubmit() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
|
|
@ -92,6 +193,29 @@ export default function AddExpertForm() {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleSelectionChange = (index: number, type: "roleId" | "userLevelId", value: string) => {
|
||||
setPlacementRows((prevRows) =>
|
||||
prevRows.map((row) =>
|
||||
row.index === index ? { ...row, [type]: value } : row
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const handleRemoveRow = (index: number) => {
|
||||
console.log(index);
|
||||
console.log(placementRows);
|
||||
const newPlacements = placementRows.filter((row) => row.index != index);
|
||||
console.log(newPlacements);
|
||||
setPlacementRows(newPlacements);
|
||||
};
|
||||
|
||||
const handleAddRow = () => {
|
||||
setPlacementRows((prevRows: any) => [...prevRows, { index: incrementId, roleId: "", userLevelId: 0 }]);
|
||||
setIncrementId((prevId) => prevId + 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
|
|
@ -118,6 +242,22 @@ export default function AddExpertForm() {
|
|||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<Input
|
||||
value={field.value}
|
||||
placeholder="Masukkan Username"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="phoneNumber"
|
||||
|
|
@ -152,45 +292,16 @@ export default function AddExpertForm() {
|
|||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="position"
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Posisi</FormLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Pilih Region" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="koor-kurator">Koor Kurator</SelectItem>
|
||||
<SelectItem value="kurator">Kurator</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Wilayah</FormLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Pilih Region" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="nasional">Nasional</SelectItem>
|
||||
<SelectItem value="jakarta">DKI Jakarta</SelectItem>
|
||||
<SelectItem value="jabar">Jawa Barat</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormLabel>Password</FormLabel>
|
||||
<Input
|
||||
type="password"
|
||||
value={field.value}
|
||||
placeholder="Masukkan Password"
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
|
|
@ -208,19 +319,20 @@ export default function AddExpertForm() {
|
|||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="komunikasi">Komunikasi</SelectItem>
|
||||
<SelectItem value="hukum">Hukum</SelectItem>
|
||||
<SelectItem value="bahasa">Bahasa</SelectItem>
|
||||
{userCompetencies?.map((item: any) => (
|
||||
<SelectItem key={item.id} value={String(item.id)}>
|
||||
{item.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="experience"
|
||||
name="experiences"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Pengalaman</FormLabel>
|
||||
|
|
@ -231,15 +343,13 @@ export default function AddExpertForm() {
|
|||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="akademisi">Akademisi</SelectItem>
|
||||
<SelectItem value="praktisi">Praktisi</SelectItem>
|
||||
<SelectItem value="akademisi+praktisi">
|
||||
Akademisi + Praktisi
|
||||
</SelectItem>
|
||||
{userExperiences?.map((item: any) => (
|
||||
<SelectItem key={item.id} value={String(item.id)}>
|
||||
{item.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
@ -261,6 +371,59 @@ export default function AddExpertForm() {
|
|||
)}
|
||||
/>
|
||||
|
||||
<div className="mt-4">
|
||||
<FormLabel>Penempatan</FormLabel>
|
||||
{placementRows?.map((row: any) => (
|
||||
<div key={row.index} className="flex items-center gap-2 my-2">
|
||||
<Select onValueChange={(e) => handleSelectionChange(row.index, "roleId", e)} >
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Pilih Role" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{roleSelection?.map((item: any) => (
|
||||
<SelectItem key={item.id} value={String(item.id)}>
|
||||
{item.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select onValueChange={(e) => handleSelectionChange(row.index, "userLevelId", e)}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Pilih User Level" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{userLevels?.map((item: any) => (
|
||||
<SelectItem key={item.id} value={String(item.id)}>
|
||||
{item.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{placementRows.length > 1 && (
|
||||
<Button
|
||||
type="button"
|
||||
size="md"
|
||||
color="destructive"
|
||||
onClick={() => handleRemoveRow(row.index)}
|
||||
>
|
||||
Hapus
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<Button
|
||||
type="button"
|
||||
size="md"
|
||||
onClick={() => handleAddRow()}
|
||||
>
|
||||
Tambah
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row justify-end gap-2 mt-4 pt-4">
|
||||
<Button
|
||||
size="md"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export default function PerformancePolda() {
|
|||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<p className="font-semibold">PERFORMANCE KUMULATIF PER POLDA</p>
|
||||
<p className="font-semibold">PERFORMANCE KUMULATIF PER POLRES</p>
|
||||
<PerformancePolresViz />
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import PerformancePolresViz from "@/components/visualization/performance-polres";
|
||||
import PerformanceSatkerViz from "@/components/visualization/performance-satker";
|
||||
|
||||
export default function PerformanceSatker() {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<p className="font-semibold">PERFORMANCE KUMULATIF PER SATKER</p>
|
||||
<PerformanceSatkerViz />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -14,9 +14,7 @@ export default function AdminBanner() {
|
|||
<SiteBreadcrumb />
|
||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
||||
<div className="flex justify-between">
|
||||
{selectedTab === "content"
|
||||
? "Daftar List Media"
|
||||
: "Table List Banner"}
|
||||
{selectedTab === "content" ? "List Media" : " List Banner"}
|
||||
|
||||
<div className="flex flex-row gap-1 border-2 rounded-md w-fit mb-5">
|
||||
<Button
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import Image from "next/image";
|
|||
import { Upload } from "tus-js-client";
|
||||
import { getCookiesDecrypt } from "@/lib/utils";
|
||||
import Cookies from "js-cookie";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const FormSchema = z.object({
|
||||
title: z.string({
|
||||
|
|
@ -109,7 +110,7 @@ export default function CreateCategoryModal() {
|
|||
const levelNumber = getCookiesDecrypt("ulne");
|
||||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
const poldaState = Cookies.get("state");
|
||||
|
||||
const t = useTranslations("Menu");
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [satkerData, setSatkerData] = useState<string[]>([]);
|
||||
|
|
@ -239,12 +240,12 @@ export default function CreateCategoryModal() {
|
|||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button color="primary" size="md">
|
||||
Tambah Kategori
|
||||
{t("add-category")}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Tambah Kategori</DialogTitle>
|
||||
<DialogTitle> {t("add-category")}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
|
|
|
|||
|
|
@ -44,10 +44,12 @@ import {
|
|||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import CreateCategoryModal from "./create";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const AdminCategoryTable = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const t = useTranslations("Menu");
|
||||
const dataChange = searchParams?.get("dataChange");
|
||||
const [openModal, setOpenModal] = React.useState(false);
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
|
|
@ -127,7 +129,7 @@ const AdminCategoryTable = () => {
|
|||
return (
|
||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
||||
<div className="flex justify-between mb-10 items-center">
|
||||
<p className="text-xl font-medium text-default-900">Kategori</p>
|
||||
<p className="text-xl font-medium text-default-900">{t("category")}</p>
|
||||
<CreateCategoryModal />
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import { useDropzone } from "react-dropzone";
|
|||
import { CloudUpload } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { Upload } from "tus-js-client";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const FormSchema = z.object({
|
||||
answer: z.string({
|
||||
|
|
@ -79,7 +80,7 @@ const publishToList = [
|
|||
export default function CreateFAQModal() {
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
|
||||
const t = useTranslations("Menu");
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [satkerData, setSatkerData] = useState<string[]>([]);
|
||||
const [unitData, setUnitData] = useState<string[]>([]);
|
||||
|
|
@ -120,12 +121,12 @@ export default function CreateFAQModal() {
|
|||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button color="primary" size="md">
|
||||
Tambah FAQ
|
||||
{t("add")} FAQ
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Tambah FAQ</DialogTitle>
|
||||
<DialogTitle>{t("add")} FAQ</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import { useDropzone } from "react-dropzone";
|
|||
import { CloudUpload } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { Upload } from "tus-js-client";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const FormSchema = z.object({
|
||||
question: z.string({
|
||||
|
|
@ -77,7 +78,7 @@ const publishToList = [
|
|||
export default function CreateFAQModal() {
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
|
||||
const t = useTranslations("Menu");
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
|
|
@ -110,12 +111,12 @@ export default function CreateFAQModal() {
|
|||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button color="primary" size="md">
|
||||
Tambah Feedback
|
||||
{t("add")} Feedback
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Tambah Feedback</DialogTitle>
|
||||
<DialogTitle>{t("add")} Feedback</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
|
|
|
|||
|
|
@ -41,11 +41,13 @@ import {
|
|||
} from "@/service/settings/settings";
|
||||
|
||||
import CreateFAQModal from "./create";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const AdminFeedbackTable = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const dataChange = searchParams?.get("dataChange");
|
||||
|
||||
const [openModal, setOpenModal] = React.useState(false);
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import {
|
|||
CommandList,
|
||||
} from "@/components/ui/command";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const FormSchema = z.object({
|
||||
name: z.string({
|
||||
|
|
@ -55,6 +56,7 @@ const FormSchema = z.object({
|
|||
export default function CreateTagModal() {
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
const t = useTranslations("Menu");
|
||||
const [categoryList, setCategoryList] = useState<
|
||||
{ id: number; label: string; value: string }[]
|
||||
>([]);
|
||||
|
|
@ -107,12 +109,12 @@ export default function CreateTagModal() {
|
|||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button color="primary" size="md">
|
||||
Tambah Tag
|
||||
{t("add-tags")}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Tambah Tag</DialogTitle>
|
||||
<DialogTitle> {t("add-tags")}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
|
|
|
|||
|
|
@ -42,10 +42,12 @@ import {
|
|||
} from "@/service/settings/settings";
|
||||
|
||||
import CreateFAQModal from "./create";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const AdminTagTable = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const t = useTranslations("Menu");
|
||||
const dataChange = searchParams?.get("dataChange");
|
||||
const [openModal, setOpenModal] = React.useState(false);
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
|
|
@ -124,7 +126,7 @@ const AdminTagTable = () => {
|
|||
return (
|
||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
||||
<div className="flex justify-between mb-10 items-center">
|
||||
<p className="text-xl font-medium text-default-900">Tag</p>
|
||||
<p className="text-xl font-medium text-default-900">{t("tags")}</p>
|
||||
<CreateFAQModal />
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,9 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
);
|
||||
const [selectedEventDate, setSelectedEventDate] = useState<Date | null>(null);
|
||||
const roleId = Number(getCookiesDecrypt("urie")) || 0;
|
||||
const userLevelId = Number(getCookiesDecrypt("ulie")) || 0;
|
||||
console.log("roleId", roleId);
|
||||
console.log("userlevel", userLevelId);
|
||||
const [apiEvents, setApiEvents] = useState<CalendarEvent[]>([]);
|
||||
const [Isloading, setLoading] = useState<boolean>(false);
|
||||
const [draggableInitialized, setDraggableInitialized] =
|
||||
|
|
@ -574,11 +577,11 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
<div className="grid grid-cols-12 gap-6 divide-x divide-border">
|
||||
<Card className="col-span-12 lg:col-span-4 2xl:col-span-3 pb-5">
|
||||
<CardContent className="p-0">
|
||||
<CardHeader className="border-none mb-2 pt-5">
|
||||
<CardHeader className="border-none mb-2 pt-5 ">
|
||||
{roleId == 3 || roleId == 11 || roleId == 2 || roleId == 12 ? (
|
||||
<Button
|
||||
onClick={handleDateClick}
|
||||
className="dark:bg-background dark:text-foreground"
|
||||
className="dark:bg-background dark:text-foreground w-[250px]"
|
||||
>
|
||||
<Plus className="w-4 h-4 me-1" />
|
||||
{t("addEvent")}
|
||||
|
|
@ -589,8 +592,8 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
|||
<div>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
{roleId == 2 ? (
|
||||
<Button className="dark:bg-background dark:text-foreground ">
|
||||
{roleId === 3 && userLevelId === 216 ? (
|
||||
<Button className="dark:bg-background dark:text-foreground w-[250px]">
|
||||
<Book className="w-4 h-4" />
|
||||
{t("bag-pa-monitoring-results")}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import { listEnableCategory } from "@/service/content/content";
|
|||
import { useTranslations } from "next-intl";
|
||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const BlogTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -73,7 +74,7 @@ const BlogTable = () => {
|
|||
);
|
||||
const [categoryFilter, setCategoryFilter] = React.useState<string>("");
|
||||
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -17,155 +17,162 @@ import Swal from "sweetalert2";
|
|||
import withReactContent from "sweetalert2-react-content";
|
||||
import { deleteBlog } from "@/service/blog/blog";
|
||||
import { error, loading } from "@/lib/swal";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-normal">{row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category",
|
||||
cell: ({ row }) => <span>{row.getValue("categoryName")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "tags",
|
||||
header: "Tag",
|
||||
cell: ({ row }) => <span className="">{row.getValue("tags")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-normal">{row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category"),
|
||||
cell: ({ row }) => <span>{row.getValue("categoryName")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "tags",
|
||||
header: t("tag"),
|
||||
cell: ({ row }) => <span className="">{row.getValue("tags")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
async function deleteProcess(id: any) {
|
||||
loading();
|
||||
const resDelete = await deleteBlog(id);
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
if (resDelete?.error) {
|
||||
error(resDelete.message);
|
||||
return false;
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
async function deleteProcess(id: any) {
|
||||
loading();
|
||||
const resDelete = await deleteBlog(id);
|
||||
|
||||
if (resDelete?.error) {
|
||||
error(resDelete.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteBlog = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
deleteProcess(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/blog/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
const handleDeleteBlog = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
deleteProcess(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/blog/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/blog/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteBlog(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/blog/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteBlog(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -17,211 +17,224 @@ import withReactContent from "sweetalert2-react-content";
|
|||
import { deleteMedia } from "@/service/content/content";
|
||||
import { error } from "@/lib/swal";
|
||||
import Swal from "sweetalert2";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category-name"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("categoryName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category Name",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: "Creator Group",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: "Published",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: t("creator-group"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: t("published"),
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/content/audio/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/content/audio/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
export default columns;
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/audio/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/content/audio/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ import {
|
|||
} from "@/service/content/content";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TableAudio = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -99,7 +100,7 @@ const TableAudio = () => {
|
|||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
"use client";
|
||||
import * as React from "react";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
|
|
@ -19,237 +20,224 @@ import { deleteMedia } from "@/service/content/content";
|
|||
import { error, loading } from "@/lib/swal";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category-name"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("categoryName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category Name",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: "Creator Group",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: "Published",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: t("creator-group"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusId",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const userLevelId = 2; // Gantilah sesuai dengan konteks aplikasi
|
||||
const statusId = Number(row.getValue("statusId"));
|
||||
const reviewedAtLevel = row.original.reviewedAtLevel as string | null;
|
||||
const needApprovalFromLevel = Number(row.original.needApprovalFromLevel);
|
||||
|
||||
let statusName = row.getValue("statusName") as string;
|
||||
let icon = "fa:times-circle";
|
||||
let statusClass = "bg-gray-100 text-gray-600";
|
||||
|
||||
if (
|
||||
(statusId === 2 &&
|
||||
reviewedAtLevel !== null &&
|
||||
!reviewedAtLevel.includes(`:${userLevelId}:`)) ||
|
||||
(statusId === 1 && needApprovalFromLevel === userLevelId)
|
||||
) {
|
||||
statusName = "Menunggu Review";
|
||||
icon = "fa:hourglass-end";
|
||||
statusClass = "bg-orange-100 text-orange-600";
|
||||
} else if (
|
||||
statusId === 2 &&
|
||||
reviewedAtLevel?.includes(`:${userLevelId}:`)
|
||||
) {
|
||||
icon = "fa:check-circle";
|
||||
statusClass = "bg-green-100 text-green-600";
|
||||
} else if (statusId === 2) {
|
||||
icon = "fa:check-circle";
|
||||
statusClass = "bg-green-100 text-green-600";
|
||||
} else if (statusId === 3) {
|
||||
icon = "fa:comment";
|
||||
statusClass = "bg-blue-100 text-blue-600";
|
||||
} else if (statusId === 1) {
|
||||
icon = "fa:hourglass-end";
|
||||
statusClass = "bg-orange-100 text-orange-600";
|
||||
}
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusClass
|
||||
)}
|
||||
>
|
||||
{statusName}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: t("published"),
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
//
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase();
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-red-200 text-red-600";
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/content/image/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/content/image/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/image/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/content/image/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ import { ticketingPagination } from "@/service/ticketing/ticketing";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./columns";
|
||||
|
||||
import {
|
||||
deleteMedia,
|
||||
listDataImage,
|
||||
|
|
@ -66,6 +66,7 @@ import withReactContent from "sweetalert2-react-content";
|
|||
import { error } from "@/lib/swal";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TableImage = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -104,7 +105,7 @@ const TableImage = () => {
|
|||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -16,137 +16,146 @@ import {
|
|||
} from "@/components/ui/dropdown-menu";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "contentTitle",
|
||||
header: "Judul",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("contentTitle");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "contentTitle",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("contentTitle");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "contentTag",
|
||||
header: t("tag"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("contentTag")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "contentType",
|
||||
header: t("type-content"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("contentType")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "contentCreatedGroupBy",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("contentCreatedGroupBy")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "contentTag",
|
||||
header: "Tag",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("contentTag")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "contentType",
|
||||
header: "Tipe Konten ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("contentType")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "contentCreatedGroupBy",
|
||||
header: "Sumber ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("contentCreatedGroupBy")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "isPublish",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.getValue<boolean>("isPublish");
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size="sm"
|
||||
color={isPublish ? "success" : "warning"}
|
||||
variant="outline"
|
||||
className={`btn btn-sm ${
|
||||
isPublish ? "btn-outline-success" : "btn-outline-warning"
|
||||
} pill-btn ml-1`}
|
||||
>
|
||||
{isPublish ? "Diterima" : "Menunggu Review"}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "contentCreatedDate",
|
||||
header: "Tanggal Unggah",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("contentCreatedDate") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const isDisabled = row.original.isPublish; // Check the isPublish value
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild disabled={isDisabled}>
|
||||
{
|
||||
accessorKey: "isPublish",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.getValue<boolean>("isPublish");
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size="icon"
|
||||
className={`bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent ${
|
||||
isDisabled ? "cursor-not-allowed opacity-50" : ""
|
||||
}`}
|
||||
disabled={isDisabled} // Disable button if isPublish is true
|
||||
size="sm"
|
||||
color={isPublish ? "success" : "warning"}
|
||||
variant="outline"
|
||||
className={`btn btn-sm ${
|
||||
isPublish ? "btn-outline-success" : "btn-outline-warning"
|
||||
} pill-btn ml-1`}
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
{isPublish ? "Diterima" : "Menunggu Review"}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/spit/convert/${row.original.contentId}`}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className={`p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none ${
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "contentCreatedDate",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("contentCreatedDate") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const isDisabled = row.original.isPublish; // Check the isPublish value
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild disabled={isDisabled}>
|
||||
<Button
|
||||
size="icon"
|
||||
className={`bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent ${
|
||||
isDisabled ? "cursor-not-allowed opacity-50" : ""
|
||||
}`}
|
||||
disabled={isDisabled} // Disable dropdown item if isPublish is true
|
||||
disabled={isDisabled} // Disable button if isPublish is true
|
||||
>
|
||||
<MoveDownRight className="w-4 h-4 me-1.5" />
|
||||
Pindah Ke Mediahub
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/spit/convert/${row.original.contentId}`}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className={`p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none ${
|
||||
isDisabled ? "cursor-not-allowed opacity-50" : ""
|
||||
}`}
|
||||
disabled={isDisabled} // Disable dropdown item if isPublish is true
|
||||
>
|
||||
<MoveDownRight className="w-4 h-4 me-1.5" />
|
||||
Pindah Ke Mediahub
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ import {
|
|||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
// export type CompanyData = {
|
||||
// no: number;
|
||||
|
|
@ -77,7 +80,8 @@ const TableSPIT = () => {
|
|||
const [search, setSearch] = React.useState("");
|
||||
const userId = getCookiesDecrypt("uie");
|
||||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
|
||||
const t = useTranslations("AnalyticsDashboard");
|
||||
const [dateFilter, setDateFilter] = React.useState("");
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
|
|
@ -86,7 +90,7 @@ const TableSPIT = () => {
|
|||
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: spitTable,
|
||||
columns,
|
||||
|
|
@ -117,7 +121,7 @@ const TableSPIT = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit, search, statusFilter]);
|
||||
}, [page, limit, search, statusFilter, dateFilter]);
|
||||
|
||||
async function fetchData() {
|
||||
let isPublish;
|
||||
|
|
@ -129,8 +133,18 @@ const TableSPIT = () => {
|
|||
isPublish = statusFilter.includes(1) ? false : true;
|
||||
}
|
||||
|
||||
const formattedStartDate = dateFilter
|
||||
? format(new Date(dateFilter), "yyyy-MM-dd")
|
||||
: "";
|
||||
|
||||
try {
|
||||
const res = await listSPIT(page - 1, limit, search, isPublish);
|
||||
const res = await listSPIT(
|
||||
page - 1,
|
||||
limit,
|
||||
search,
|
||||
formattedStartDate,
|
||||
isPublish
|
||||
);
|
||||
const data = res?.data?.data;
|
||||
const contentData = data?.content || [];
|
||||
|
||||
|
|
@ -192,6 +206,15 @@ const TableSPIT = () => {
|
|||
<div className="flex flex-row justify-between my-1 mx-1">
|
||||
<p>Filter</p>
|
||||
</div>
|
||||
<div className="mx-2 my-1">
|
||||
<Label>{t("date")}</Label>
|
||||
<Input
|
||||
type="date"
|
||||
value={dateFilter}
|
||||
onChange={(e) => setDateFilter(e.target.value)}
|
||||
className="max-w-sm"
|
||||
/>
|
||||
</div>
|
||||
<Label className="ml-2 mt-2">Status</Label>
|
||||
<div className="flex items-center px-4 py-1">
|
||||
<input
|
||||
|
|
|
|||
|
|
@ -17,212 +17,224 @@ import { error } from "@/lib/swal";
|
|||
import { deleteMedia } from "@/service/content/content";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import Swal from "sweetalert2";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category-name"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("categoryName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category Name",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: "Creator Group",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: "Published",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: t("creator-group"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: t("published"),
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/content/teks/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/content/teks/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
export default columns;
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/teks/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/content/teks/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ import {
|
|||
} from "@/service/content/content";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TableTeks = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -98,7 +99,7 @@ const TableTeks = () => {
|
|||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -17,209 +17,223 @@ import { deleteMedia } from "@/service/content/content";
|
|||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { error } from "@/lib/swal";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: t("category-name"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("categoryName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "categoryName",
|
||||
header: "Category Name",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: "Creator Group",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: "Sumber",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: "Published",
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorName",
|
||||
header: t("creator-group"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase();
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-red-200 text-red-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("creatorGroupLevelName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
{
|
||||
accessorKey: "publishedOn",
|
||||
header: t("published"),
|
||||
cell: ({ row }) => {
|
||||
const isPublish = row.original.isPublish;
|
||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
let displayText = "-";
|
||||
if (isPublish && !isPublishOnPolda) {
|
||||
displayText = "Mabes";
|
||||
} else if (isPublish && isPublishOnPolda) {
|
||||
displayText = "Mabes & Polda";
|
||||
} else if (!isPublish && isPublishOnPolda) {
|
||||
displayText = "Polda";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase();
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-red-200 text-red-600";
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/content/video/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/content/video/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-full px-5 w-full whitespace-nowrap",
|
||||
statusStyles
|
||||
)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
export default columns;
|
||||
async function doDelete(id: any) {
|
||||
// loading();
|
||||
const data = {
|
||||
id,
|
||||
};
|
||||
|
||||
const response = await deleteMedia(data);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteMedia = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doDelete(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/content/video/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/content/video/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handleDeleteMedia(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ import {
|
|||
} from "@/service/content/content";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TableVideo = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -98,7 +99,7 @@ const TableVideo = () => {
|
|||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -13,105 +13,111 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("title")}
|
||||
</h4>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("title")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Tanggal Unggah ",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue<boolean>("isActive");
|
||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||
return (
|
||||
<div>
|
||||
{isActive ? (
|
||||
<b className="text-blue-500">Terkirim</b>
|
||||
) : (
|
||||
<b className="text-danger">Belum Terkirim</b>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue<boolean>("isActive");
|
||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||
return (
|
||||
<div>
|
||||
{isActive ? (
|
||||
<b className="text-blue-500">Terkirim</b>
|
||||
) : (
|
||||
<b className="text-danger">Belum Terkirim</b>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/planning/mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/planning/mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
// onClick={() => deletePlan(row.id)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
// onClick={() => deletePlan(row.id)}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import { getPlanningSentPagination } from "@/service/planning/planning";
|
|||
import search from "@/app/[locale]/(protected)/app/chat/components/search";
|
||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const MediahubTable = () => {
|
||||
const t = useTranslations("Planning");
|
||||
|
|
@ -78,7 +79,7 @@ const MediahubTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -13,103 +13,109 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("title")}
|
||||
</h4>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("title")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Tanggal Unggah ",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue<boolean>("isActive");
|
||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||
return (
|
||||
<div>
|
||||
{isActive ? (
|
||||
<b className="text-blue-500">Terkirim</b>
|
||||
) : (
|
||||
<b className="text-danger">Belum Terkirim</b>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue<boolean>("isActive");
|
||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||
return (
|
||||
<div>
|
||||
{isActive ? (
|
||||
<b className="text-blue-500">Terkirim</b>
|
||||
) : (
|
||||
<b className="text-danger">Belum Terkirim</b>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/planning/medsos-mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/planning/medsos-mediahub/publish/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import columns from "./columns";
|
|||
import { getPlanningSentPagination } from "@/service/planning/planning";
|
||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const MedsosTable = () => {
|
||||
const t = useTranslations("Planning");
|
||||
|
|
@ -77,7 +78,7 @@ const MedsosTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -12,163 +12,171 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: t("start-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: t("end-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: t("time"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: t("address"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: t("speaker"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("uploaderName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: "Start Date ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: "End Date",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: "Address",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: "Sumber ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/event/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/event/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/event/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/event/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default columns;
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import { useTranslations } from "next-intl";
|
|||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const EventTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -55,7 +56,7 @@ const EventTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -12,163 +12,172 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: t("start-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: t("end-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: t("time"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: t("address"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: t("speaker"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("uploaderName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: "Start Date ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: "End Date",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: "Address",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: "Sumber ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-conference/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import { paginationSchedule } from "@/service/schedule/schedule";
|
|||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const PressConferenceTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -68,7 +69,7 @@ const PressConferenceTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -12,163 +12,172 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const title: string = row.getValue("title");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: t("start-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: t("end-date"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: t("time"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: t("address"),
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: t("speaker"),
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: t("source"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
||||
{row.getValue("uploaderName")}
|
||||
</span>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "startDate",
|
||||
header: "Start Date ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("startDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "endDate",
|
||||
header: "End Date",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("endDate")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "time",
|
||||
header: "Time",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { startTime, endTime } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{startTime || "N/A"} - {endTime || "N/A"}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "address",
|
||||
header: "Address",
|
||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||
const address: string = row.getValue("address");
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{address.length > 50 ? `${address.slice(0, 40)}...` : address}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "statusName",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const statusColors: Record<string, string> = {
|
||||
diterima: "bg-green-100 text-green-600",
|
||||
"menunggu review": "bg-orange-100 text-orange-600",
|
||||
};
|
||||
|
||||
// Mengambil `statusName` dari data API
|
||||
const status = row.getValue("statusName") as string;
|
||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||
|
||||
// Gunakan `statusName` untuk pencocokan
|
||||
const statusStyles =
|
||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
||||
>
|
||||
{status} {/* Tetap tampilkan nilai asli */}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "speaker",
|
||||
header: "Disampaikan oleh",
|
||||
cell: ({ row }: { row: { original: any } }) => {
|
||||
console.log("Row Original Data:", row.original);
|
||||
const { speakerTitle, speakerName } = row.original;
|
||||
return (
|
||||
<span className="whitespace-nowrap">
|
||||
{speakerTitle || ""} {speakerName || ""}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uploaderName",
|
||||
header: "Sumber ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/contributor/schedule/press-release/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import { paginationSchedule } from "@/service/schedule/schedule";
|
|||
import { useTranslations } from "next-intl";
|
||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const PressReleaseTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -69,7 +70,7 @@ const PressReleaseTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -20,187 +20,193 @@ import { deleteTask } from "@/service/task";
|
|||
import { error, loading } from "@/lib/swal";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import Swal from "sweetalert2";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Title",
|
||||
cell: ({ row }) => (
|
||||
<div>
|
||||
<span>{row.getValue("title")}</span>
|
||||
{row.original.isForward && (
|
||||
<Button
|
||||
variant={"outline"}
|
||||
color="primary"
|
||||
size="sm"
|
||||
className="ml-3 rounded-xl"
|
||||
>
|
||||
Forward
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "uniqueCode",
|
||||
header: "Code",
|
||||
cell: ({ row }) => <span>{row.getValue("uniqueCode")}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "assignmentMainType",
|
||||
header: "Type Task",
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue("assignmentMainType") as { name: string };
|
||||
return <span>{type?.name}</span>;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "assignmentType",
|
||||
header: "Category Task",
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue("assignmentType") as { name: string };
|
||||
return <span>{type?.name}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Upload Date ",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.original.isActive;
|
||||
const isDone = row.original.isDone;
|
||||
|
||||
let statusText = "";
|
||||
if (isDone) {
|
||||
statusText = "Selesai";
|
||||
} else if (isActive) {
|
||||
statusText = "Aktif";
|
||||
} else {
|
||||
statusText = "Nonaktif";
|
||||
}
|
||||
|
||||
const statusColors: Record<string, string> = {
|
||||
Aktif: "bg-primary/20 text-primary",
|
||||
Selesai: "bg-success/20 text-success",
|
||||
Nonaktif: "bg-gray-200 text-gray-500",
|
||||
};
|
||||
|
||||
const statusStyles = statusColors[statusText] || "default";
|
||||
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{statusText}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
async function deleteProcess(id: any) {
|
||||
loading();
|
||||
const resDelete = await deleteTask(id);
|
||||
|
||||
if (resDelete?.error) {
|
||||
error(resDelete.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const TaskDelete = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
deleteProcess(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<div>
|
||||
<span>{row.getValue("title")}</span>
|
||||
{row.original.isForward && (
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
variant={"outline"}
|
||||
color="primary"
|
||||
size="sm"
|
||||
className="ml-3 rounded-xl"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
Forward
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/task/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/task/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => TaskDelete(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
{
|
||||
accessorKey: "uniqueCode",
|
||||
header: t("code"),
|
||||
cell: ({ row }) => <span>{row.getValue("uniqueCode")}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "assignmentMainType",
|
||||
header: t("type-task"),
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue("assignmentMainType") as { name: string };
|
||||
return <span>{type?.name}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "assignmentType",
|
||||
header: t("category-task"),
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue("assignmentType") as { name: string };
|
||||
return <span>{type?.name}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("upload-date"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.original.isActive;
|
||||
const isDone = row.original.isDone;
|
||||
|
||||
let statusText = "";
|
||||
if (isDone) {
|
||||
statusText = "Selesai";
|
||||
} else if (isActive) {
|
||||
statusText = "Aktif";
|
||||
} else {
|
||||
statusText = "Nonaktif";
|
||||
}
|
||||
|
||||
const statusColors: Record<string, string> = {
|
||||
Aktif: "bg-primary/20 text-primary",
|
||||
Selesai: "bg-success/20 text-success",
|
||||
Nonaktif: "bg-gray-200 text-gray-500",
|
||||
};
|
||||
|
||||
const statusStyles = statusColors[statusText] || "default";
|
||||
|
||||
return (
|
||||
<Badge className={cn("rounded-full px-5", statusStyles)}>
|
||||
{statusText}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
async function deleteProcess(id: any) {
|
||||
loading();
|
||||
const resDelete = await deleteTask(id);
|
||||
|
||||
if (resDelete?.error) {
|
||||
error(resDelete.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const TaskDelete = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Hapus Data",
|
||||
text: "",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Hapus",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
deleteProcess(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/contributor/task/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link href={`/contributor/task/update/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem
|
||||
onClick={() => TaskDelete(row.original.id)}
|
||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import { listTask } from "@/service/task";
|
|||
import { Label } from "@/components/ui/label";
|
||||
import { format } from "date-fns";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TaskTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -83,7 +84,7 @@ const TaskTable = () => {
|
|||
const [limit, setLimit] = React.useState(10);
|
||||
const [isSpecificAttention, setIsSpecificAttention] = React.useState(true);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -181,16 +181,16 @@ export default function ExecutiveDashboard() {
|
|||
const view2 =
|
||||
levelName == "MABES POLRI"
|
||||
? isInternational[1]
|
||||
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-konten-publisher?"
|
||||
: "views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-konten-publisher?"
|
||||
: `views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-konten-publisher-polda?provinsi-polda=${poldaState}&`;
|
||||
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-published-produksi?"
|
||||
: "views/2023_04_MediaHUB-Viz-POLDA_Rev202/db-published-produksi-executive?"
|
||||
: `views/2023_04_MediaHUB-Viz-POLDA_Rev202/db-konten-publisher-polda-executive?provinsi-polda=${poldaState}&`;
|
||||
|
||||
const view3 =
|
||||
levelName == "MABES POLRI"
|
||||
? isInternational[2]
|
||||
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-waktu-akses-pengguna?"
|
||||
: "views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-waktu-akses-pengguna?"
|
||||
: `views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-waktu-akses-pengguna-polda?provinsi-polda=${poldaState}&`;
|
||||
: "views/2023_04_MediaHUB-Viz-POLDA_Rev202/db-waktu-akses-pengguna-executive?"
|
||||
: `views/2023_04_MediaHUB-Viz-POLDA_Rev202/db-waktu-akses-pengguna-polda-executive?provinsi-polda=${poldaState}&`;
|
||||
|
||||
const view4 =
|
||||
levelName == "MABES POLRI"
|
||||
|
|
@ -212,6 +212,21 @@ export default function ExecutiveDashboard() {
|
|||
async function initState() {
|
||||
const response1 = await generateTicket();
|
||||
setTicket1(response1?.data?.data);
|
||||
|
||||
const response2 = await generateTicket();
|
||||
setTicket2(response2?.data?.data);
|
||||
|
||||
const response3 = await generateTicket();
|
||||
setTicket3(response3?.data?.data);
|
||||
|
||||
const response4 = await generateTicket();
|
||||
setTicket4(response4?.data?.data);
|
||||
|
||||
const response5 = await generateTicket();
|
||||
setTicket5(response5?.data?.data);
|
||||
|
||||
const response6 = await generateTicket();
|
||||
setTicket6(response6?.data?.data);
|
||||
}
|
||||
|
||||
initState();
|
||||
|
|
@ -235,35 +250,6 @@ export default function ExecutiveDashboard() {
|
|||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Download Report</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Download Report</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="w-full">
|
||||
<Label>Date</Label>
|
||||
<Input
|
||||
type="date"
|
||||
// value={dateFilter}
|
||||
// onChange={(e) => setDateFilter(e.target.value)}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="submit"
|
||||
// onClick={downloadReport}
|
||||
>
|
||||
Download
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<div className="mt-3 flex flex-row gap-3 justify-center">
|
||||
<Card className="rounded-sm w-4/12 p-3">
|
||||
<div className="flex flex-row justify-between">
|
||||
|
|
@ -298,7 +284,7 @@ export default function ExecutiveDashboard() {
|
|||
<LucideBoxSelect />
|
||||
</div>
|
||||
<div className="my-5">
|
||||
{ticket1 == "" ? (
|
||||
{ticket2 == "" ? (
|
||||
<iframe
|
||||
src={`${baseUrl + view4 + param}`}
|
||||
width="100%"
|
||||
|
|
@ -307,7 +293,7 @@ export default function ExecutiveDashboard() {
|
|||
/>
|
||||
) : (
|
||||
<iframe
|
||||
src={`${`${url + ticket1}/${view4}${param}`}`}
|
||||
src={`${`${url + ticket2}/${view4}${param}`}`}
|
||||
width="100%"
|
||||
height="750"
|
||||
frameBorder="0"
|
||||
|
|
@ -323,7 +309,7 @@ export default function ExecutiveDashboard() {
|
|||
<LucideBoxSelect />
|
||||
</div>
|
||||
<div className="my-5">
|
||||
{ticket1 == "" ? (
|
||||
{ticket3 == "" ? (
|
||||
<iframe
|
||||
src={`${baseUrl + view5 + param}`}
|
||||
width="100%"
|
||||
|
|
@ -332,7 +318,7 @@ export default function ExecutiveDashboard() {
|
|||
/>
|
||||
) : (
|
||||
<iframe
|
||||
src={`${`${url + ticket1}/${view5}${param}`}`}
|
||||
src={`${`${url + ticket3}/${view5}${param}`}`}
|
||||
width="100%"
|
||||
height="750"
|
||||
frameBorder="0"
|
||||
|
|
@ -342,24 +328,24 @@ export default function ExecutiveDashboard() {
|
|||
</Card>
|
||||
</div>
|
||||
<div className="w-full mt-3">
|
||||
<Card className="rounded-sm p-3 h-[850px]">
|
||||
<Card className="rounded-sm p-3 h-[750px]">
|
||||
<div className="flex flex-row justify-between">
|
||||
<p className="text-base font-semibold">Konten Paling Populer</p>
|
||||
<LucideBoxSelect />
|
||||
</div>
|
||||
<div className="my-5">
|
||||
{ticket2 == "" ? (
|
||||
{ticket4 == "" ? (
|
||||
<iframe
|
||||
src={`${baseUrl + view2 + param}`}
|
||||
width="100%"
|
||||
height="750"
|
||||
height="650"
|
||||
frameBorder="0"
|
||||
/>
|
||||
) : (
|
||||
<iframe
|
||||
src={`${`${url + ticket2}/${view2}${param}`}`}
|
||||
src={`${`${url + ticket4}/${view2}${param}`}`}
|
||||
width="100%"
|
||||
height="750"
|
||||
height="650"
|
||||
frameBorder="0"
|
||||
/>
|
||||
)}
|
||||
|
|
@ -367,7 +353,7 @@ export default function ExecutiveDashboard() {
|
|||
</Card>
|
||||
</div>
|
||||
<div className="w-full mt-3">
|
||||
<Card className="rounded-sm p-3 h-[850px]">
|
||||
<Card className="rounded-sm p-3 h-[750px]">
|
||||
<div className="flex flex-row justify-between">
|
||||
<p className="text-base font-semibold">
|
||||
Heatmap Konten Dengan Interaksi
|
||||
|
|
@ -378,18 +364,18 @@ export default function ExecutiveDashboard() {
|
|||
<LucideBoxSelect />
|
||||
</div>
|
||||
<div className="my-5">
|
||||
{ticket3 == "" ? (
|
||||
{ticket5 == "" ? (
|
||||
<iframe
|
||||
src={`${baseUrl + view3 + param}`}
|
||||
width="100%"
|
||||
height="750"
|
||||
height="600"
|
||||
frameBorder="0"
|
||||
/>
|
||||
) : (
|
||||
<iframe
|
||||
src={`${`${url + ticket3}/${view3}${param}`}`}
|
||||
src={`${`${url + ticket5}/${view3}${param}`}`}
|
||||
width="100%"
|
||||
height="750"
|
||||
height="600"
|
||||
frameBorder="0"
|
||||
/>
|
||||
)}
|
||||
|
|
@ -397,7 +383,7 @@ export default function ExecutiveDashboard() {
|
|||
</Card>
|
||||
</div>
|
||||
<div className="w-full mt-3">
|
||||
<Card className="rounded-sm p-3 h-[300px]">
|
||||
<Card className="rounded-sm p-3 h-auto">
|
||||
<div className="flex flex-row justify-between">
|
||||
<p className="text-base font-semibold">Emergency Issue</p>
|
||||
<LucideBoxSelect />
|
||||
|
|
@ -405,7 +391,7 @@ export default function ExecutiveDashboard() {
|
|||
|
||||
<div className="flex flex-col">
|
||||
<div className="my-5">
|
||||
{ticket1 == "" ? (
|
||||
{ticket6 == "" ? (
|
||||
<iframe
|
||||
src={`${baseUrl + view1 + param}`}
|
||||
width="100%"
|
||||
|
|
@ -414,7 +400,7 @@ export default function ExecutiveDashboard() {
|
|||
/>
|
||||
) : (
|
||||
<iframe
|
||||
src={`${`${url + ticket1}/${view1}${param}`}`}
|
||||
src={`${`${url + ticket6}/${view1}${param}`}`}
|
||||
width="100%"
|
||||
height="750"
|
||||
frameBorder="0"
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ import {
|
|||
getTicketingEscalationPagination,
|
||||
listTicketingInternal,
|
||||
} from "@/service/communication/communication";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const CollaborationTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -88,7 +89,7 @@ const CollaborationTable = () => {
|
|||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -13,102 +13,113 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Pertanyaan",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "commentFromUserName",
|
||||
header: "CreateBy",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("commentFromUserName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "Type",
|
||||
header: "Channel",
|
||||
cell: ({ row }) => {
|
||||
const type = row.original.type;
|
||||
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Waktu",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("question"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
||||
const statusStyles = isActive
|
||||
? "bg-green-100 text-green-600" // Gaya untuk "Open"
|
||||
: "bg-red-100 text-red-600"; // Gaya untuk "Closed"
|
||||
|
||||
return (
|
||||
<Badge className={`rounded-full px-5 ${statusStyles}`}>{status}</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "commentFromUserName",
|
||||
header: t("sender"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">
|
||||
{row.getValue("commentFromUserName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/shared/communication/collaboration/detail/${row.original.id}`
|
||||
)
|
||||
}
|
||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none items-center"
|
||||
>
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
{
|
||||
accessorKey: "Type",
|
||||
header: t("type"),
|
||||
cell: ({ row }) => {
|
||||
const type = row.original.type;
|
||||
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("time"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
export default columns;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
||||
const statusStyles = isActive
|
||||
? "bg-green-100 text-green-600" // Gaya untuk "Open"
|
||||
: "bg-red-100 text-red-600"; // Gaya untuk "Closed"
|
||||
|
||||
return (
|
||||
<Badge className={`rounded-full px-5 ${statusStyles}`}>
|
||||
{status}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/shared/communication/collaboration/detail/${row.original.id}`
|
||||
)
|
||||
}
|
||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none items-center"
|
||||
>
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
Detail
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -13,98 +13,108 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Pertanyaan",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "commentFromUserName",
|
||||
header: "Penerima",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("commentFromUserName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "type",
|
||||
header: "Penerima",
|
||||
cell: ({ row }) => {
|
||||
const type = row.original.type; // Akses properti category
|
||||
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Waktu",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("question"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
||||
const statusStyles = isActive
|
||||
? "bg-green-100 text-green-600" // Gaya untuk "Open"
|
||||
: "bg-red-100 text-red-600"; // Gaya untuk "Closed"
|
||||
|
||||
return (
|
||||
<Badge className={`rounded-full px-5 ${statusStyles}`}>{status}</Badge>
|
||||
);
|
||||
{
|
||||
accessorKey: "commentFromUserName",
|
||||
header: t("sender"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">
|
||||
{row.getValue("commentFromUserName")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/shared/communication/escalation/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
{
|
||||
accessorKey: "type",
|
||||
header: t("type"),
|
||||
cell: ({ row }) => {
|
||||
const type = row.original.type; // Akses properti category
|
||||
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("time"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
export default columns;
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "isActive",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
||||
const statusStyles = isActive
|
||||
? "bg-green-100 text-green-600" // Gaya untuk "Open"
|
||||
: "bg-red-100 text-red-600"; // Gaya untuk "Closed"
|
||||
|
||||
return (
|
||||
<Badge className={`rounded-full px-5 ${statusStyles}`}>
|
||||
{status}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/shared/communication/escalation/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ import {
|
|||
getTicketingEscalationPagination,
|
||||
listTicketingInternal,
|
||||
} from "@/service/communication/communication";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const EscalationTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -87,7 +88,7 @@ const EscalationTable = () => {
|
|||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -13,97 +13,104 @@ import { Button } from "@/components/ui/button";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { format } from "date-fns";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Pertanyaan",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdBy",
|
||||
header: "Pengirim",
|
||||
cell: ({ row }) => {
|
||||
const createdBy = row.original.createdBy; // Akses properti category
|
||||
return (
|
||||
<span className="normal-case">{createdBy?.fullname || "N/A"}</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "sendTo",
|
||||
header: "Penerima",
|
||||
cell: ({ row }) => {
|
||||
const sendTo = row.original.sendTo; // Akses properti category
|
||||
return <span className="normal-case">{sendTo?.fullname || "N/A"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: "Waktu",
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/shared/communication/internal/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: t("question"),
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case"> {row.getValue("title")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "createdBy",
|
||||
header: t("sender"),
|
||||
cell: ({ row }) => {
|
||||
const createdBy = row.original.createdBy; // Akses properti category
|
||||
return (
|
||||
<span className="normal-case">{createdBy?.fullname || "N/A"}</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "sendTo",
|
||||
header: t("sendto"),
|
||||
cell: ({ row }) => {
|
||||
const sendTo = row.original.sendTo; // Akses properti category
|
||||
return <span className="normal-case">{sendTo?.fullname || "N/A"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "createdAt",
|
||||
header: t("time"),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue("createdAt") as
|
||||
| string
|
||||
| number
|
||||
| undefined;
|
||||
|
||||
const formattedDate =
|
||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||
: "-";
|
||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/shared/communication/internal/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/shared/communication/internal/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<Link
|
||||
href={`/shared/communication/internal/update/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<DropdownMenuItem className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-destructive-foreground rounded-none">
|
||||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ import {
|
|||
} from "@/service/content/content";
|
||||
import { listTicketingInternal } from "@/service/communication/communication";
|
||||
import { Link } from "@/components/navigation";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const InternalTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -88,7 +89,7 @@ const InternalTable = () => {
|
|||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -18,198 +18,206 @@ import Swal from "sweetalert2";
|
|||
import { error } from "@/lib/swal";
|
||||
import { deleteMedia } from "@/service/content/content";
|
||||
import { publishContest } from "@/service/contest/contest";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
const useTableColumns = () => {
|
||||
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: t("no"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("no")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "hastagCode",
|
||||
header: "Kode",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4
|
||||
className="text-sm font-bold
|
||||
text-default-600 whitespace-nowrap mb-1"
|
||||
>
|
||||
{row.getValue("hastagCode")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "theme",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("theme")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "duration",
|
||||
header: "Durasi ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("duration")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetOutput",
|
||||
header: "Target Output ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("targetOutput")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetParticipantTopLevel",
|
||||
header: "Target Participant ",
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("targetParticipantTopLevel")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "isPublishForAll", // Bisa menggunakan ini untuk membaca default data
|
||||
header: "Status",
|
||||
cell: ({
|
||||
row,
|
||||
}: {
|
||||
row: {
|
||||
original: { isPublishForAll?: boolean; isPublishForMabes?: boolean };
|
||||
};
|
||||
}) => {
|
||||
const userRoleId: number = Number(getCookiesDecrypt("urie"));
|
||||
const userLevelNumber: number = Number(getCookiesDecrypt("ulne"));
|
||||
|
||||
// Mengambil data dari row.original agar lebih aman
|
||||
const isPublishForAll: boolean = Boolean(row.original.isPublishForAll);
|
||||
const isPublishForMabes: boolean = Boolean(
|
||||
row.original.isPublishForMabes
|
||||
);
|
||||
|
||||
// Logika status berdasarkan role dan data dari API
|
||||
const isPending: boolean =
|
||||
(userRoleId === 3 && userLevelNumber === 1 && !isPublishForAll) || // Role 3 dengan level 1 hanya publish jika isPublishForAll true
|
||||
((userRoleId === 11 || userRoleId === 12) && !isPublishForMabes); // Role 11 dan 12 hanya publish jika isPublishForMabes true
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={`whitespace-nowrap px-2 py-1 rounded-full ${
|
||||
isPending
|
||||
? "bg-orange-100 text-orange-600" // Warna kuning untuk "Pending"
|
||||
: "bg-green-100 text-green-600" // Warna hijau untuk "Publish"
|
||||
}`}
|
||||
>
|
||||
{isPending ? "Pending" : "Publish"}
|
||||
</Badge>
|
||||
);
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Actions",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const userRoleId = Number(getCookiesDecrypt("urie"));
|
||||
const userLevelId = Number(getCookiesDecrypt("ulie"));
|
||||
const userLevelNumber = Number(getCookiesDecrypt("ulne"));
|
||||
|
||||
async function doPublish(id: any) {
|
||||
// loading();
|
||||
// const data = {
|
||||
// id,
|
||||
// };
|
||||
|
||||
const response = await publishContest(id);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handlePublishContest = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Apakah anda ingin publish Lomba?",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Ya",
|
||||
cancelButtonText: "Tidak",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doPublish(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
{
|
||||
accessorKey: "hastagCode",
|
||||
header: t("code"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4
|
||||
className="text-sm font-bold
|
||||
text-default-600 whitespace-nowrap mb-1"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
{((userRoleId == 11 || userRoleId == 12) &&
|
||||
row?.original?.isPublishForMabes != true) ||
|
||||
(userRoleId == 3 &&
|
||||
userLevelNumber == 1 &&
|
||||
row?.original?.isPublishForAll != true) ? (
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"
|
||||
onClick={() => handlePublishContest(row.original.id)}
|
||||
{row.getValue("hastagCode")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "theme",
|
||||
header: t("title"),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="flex-1 text-start">
|
||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||
{row.getValue("theme")}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "duration",
|
||||
header: t("duration"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">{row.getValue("duration")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetOutput",
|
||||
header: t("target-output"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("targetOutput")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "targetParticipantTopLevel",
|
||||
header: t("target-participant"),
|
||||
cell: ({ row }) => (
|
||||
<span className="whitespace-nowrap">
|
||||
{row.getValue("targetParticipantTopLevel")}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "isPublishForAll", // Bisa menggunakan ini untuk membaca default data
|
||||
header: "Status",
|
||||
cell: ({
|
||||
row,
|
||||
}: {
|
||||
row: {
|
||||
original: { isPublishForAll?: boolean; isPublishForMabes?: boolean };
|
||||
};
|
||||
}) => {
|
||||
const userRoleId: number = Number(getCookiesDecrypt("urie"));
|
||||
const userLevelNumber: number = Number(getCookiesDecrypt("ulne"));
|
||||
|
||||
const isPublishForAll: boolean = Boolean(row.original.isPublishForAll);
|
||||
const isPublishForMabes: boolean = Boolean(
|
||||
row.original.isPublishForMabes
|
||||
);
|
||||
|
||||
const isPending: boolean =
|
||||
(userRoleId === 3 && userLevelNumber === 1 && !isPublishForAll) ||
|
||||
((userRoleId === 11 || userRoleId === 12) && !isPublishForMabes);
|
||||
|
||||
const isTerkirim: boolean = isPublishForMabes && !isPublishForAll;
|
||||
|
||||
return (
|
||||
<Badge
|
||||
className={`whitespace-nowrap px-2 py-1 rounded-full ${
|
||||
isPending
|
||||
? "bg-orange-100 text-orange-600" // Warna kuning untuk "Pending"
|
||||
: isTerkirim
|
||||
? "bg-blue-100 text-blue-600" // Warna biru untuk "Terkirim"
|
||||
: "bg-green-100 text-green-600" // Warna hijau untuk "Publish"
|
||||
}`}
|
||||
>
|
||||
{isPending ? "Pending" : isTerkirim ? "Terkirim" : "Publish"}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: t("action"),
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const userRoleId = Number(getCookiesDecrypt("urie"));
|
||||
const userLevelId = Number(getCookiesDecrypt("ulie"));
|
||||
const userLevelNumber = Number(getCookiesDecrypt("ulne"));
|
||||
|
||||
async function doPublish(id: any) {
|
||||
// loading();
|
||||
// const data = {
|
||||
// id,
|
||||
// };
|
||||
|
||||
const response = await publishContest(id);
|
||||
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
success();
|
||||
}
|
||||
|
||||
function success() {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handlePublishContest = (id: any) => {
|
||||
MySwal.fire({
|
||||
title: "Apakah anda ingin publish Lomba?",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#3085d6",
|
||||
confirmButtonColor: "#d33",
|
||||
confirmButtonText: "Ya",
|
||||
cancelButtonText: "Tidak",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
doPublish(id);
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<Upload className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Link href={`/shared/contest/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
{/* <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
{((userRoleId == 11 || userRoleId == 12) &&
|
||||
row?.original?.isPublishForMabes != true) ||
|
||||
(userRoleId == 3 &&
|
||||
userLevelNumber == 1 &&
|
||||
row?.original?.isPublishForAll != true) ? (
|
||||
<DropdownMenuItem
|
||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"
|
||||
onClick={() => handlePublishContest(row.original.id)}
|
||||
>
|
||||
<Upload className="w-4 h-4 me-1.5" />
|
||||
Publish
|
||||
</DropdownMenuItem>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Link href={`/shared/contest/detail/${row.original.id}`}>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
{/* <DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<SquarePen className="w-4 h-4 me-1.5" />
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
|
|
@ -217,11 +225,14 @@ const columns: ColumnDef<any>[] = [
|
|||
<Trash2 className="w-4 h-4 me-1.5" />
|
||||
Delete
|
||||
</DropdownMenuItem> */}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export default columns;
|
||||
return columns;
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import { useRouter, useSearchParams } from "next/navigation";
|
|||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./columns";
|
||||
import { listContest } from "@/service/contest/contest";
|
||||
import useTableColumns from "./columns";
|
||||
|
||||
const TaskTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -63,7 +64,7 @@ const TaskTable = () => {
|
|||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
|
||||
const columns = useTableColumns();
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
|
|
@ -30,14 +31,6 @@ const AudioSliderPage = () => {
|
|||
initFetch();
|
||||
}, [page, limit, search]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (audioData?.length > 0) {
|
||||
// shuffleAndSetVideos();
|
||||
// const interval = setInterval(shuffleAndSetVideos, 5000);
|
||||
// return () => clearInterval(interval); // Cleanup interval on unmount
|
||||
// }
|
||||
// }, [audioData]);
|
||||
|
||||
const initFetch = async () => {
|
||||
const response = await listCuratedContent(search, limit, page - 1, 4, "1");
|
||||
console.log(response);
|
||||
|
|
@ -48,11 +41,6 @@ const AudioSliderPage = () => {
|
|||
setDisplayAudio(contentData);
|
||||
};
|
||||
|
||||
// const shuffleAndSetVideos = () => {
|
||||
// const shuffled = shuffleArray([...audioData]);
|
||||
// setDisplayAudio(shuffled.slice(0, 3));
|
||||
// };
|
||||
|
||||
const shuffleArray = (array: any[]) => {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
|
|
@ -62,46 +50,61 @@ const AudioSliderPage = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Carousel className="w-full pr-3">
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<CarouselItem key={index}>
|
||||
<div className="p-1 flex flex-row md:basis-1/2 lg:basis-1/2 gap-3">
|
||||
{displayAudio?.map((audio: any) => (
|
||||
<Link
|
||||
href={`/shared/curated-content//giat-routine/audio/detail/${audio.id}`}
|
||||
key={audio?.id}
|
||||
className="flex flex-col sm:flex-row items-center hover:scale-100 transition-transform duration-300 bg-white dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full"
|
||||
>
|
||||
<div className="flex items-center justify-center bg-red-500 text-white rounded-lg w-12 h-12">
|
||||
<svg
|
||||
width="28"
|
||||
height="28"
|
||||
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>
|
||||
<div className="w-full px-2">
|
||||
{displayAudio.length > 0 && (
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<h2 className="text-xl font-semibold">Audio</h2>
|
||||
<Link
|
||||
href={"/shared/curated-content/giat-routine/video/all"}
|
||||
className="text-sm text-gray-500 hover:text-gray-700 flex items-center"
|
||||
>
|
||||
Lihat Semua <Icon icon="lucide:arrow-right" className="ml-1" />
|
||||
</Link>
|
||||
</div>
|
||||
<Carousel className="w-full">
|
||||
<CarouselContent>
|
||||
{displayAudio.map((audio, index) => (
|
||||
<CarouselItem key={index} className="md:basis-1/3 lg:basis-1/3">
|
||||
<div className="p-2">
|
||||
<Card className=" shadow-md rounded-lg overflow-hidden">
|
||||
<Link
|
||||
href={`/shared/curated-content/giat-routine/audio/detail/${audio.id}`}
|
||||
>
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<div className="flex items-center justify-center bg-red-500 text-white rounded-lg w-12 h-12 mx-3 my-3">
|
||||
<svg
|
||||
width="28"
|
||||
height="28"
|
||||
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>
|
||||
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
||||
{audio?.title}
|
||||
</div>
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
||||
{audio?.title}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</Card>
|
||||
</div>
|
||||
</Link>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -574,35 +574,36 @@ export default function DetailAudio() {
|
|||
key={data.id}
|
||||
className="flex items-center gap-3 mt-2"
|
||||
>
|
||||
{/* <img
|
||||
className="object-cover w-20 h-20"
|
||||
src={data.thumbnailUrl} // Assuming `thumbnailUrl` is the property that contains the URL for the thumbnail image
|
||||
alt={`Thumbnail ${index}`}
|
||||
/> */}
|
||||
<Music className="object-cover w-32 h-32" />
|
||||
<div className="flex flex-wrap lg:flex-row gap-3 items-center">
|
||||
{/* Mabes Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "mabes"} // Automatically checks if placement matches
|
||||
disabled // To reflect read-only behavior
|
||||
checked={data.placements === "mabes"}
|
||||
disabled
|
||||
/>
|
||||
<span>Nasional</span>
|
||||
</label>
|
||||
|
||||
{/* Polda Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "polda"} // Automatically checks if placement matches
|
||||
checked={data.placements === "polda"}
|
||||
disabled
|
||||
/>
|
||||
<span>Wilayah</span>
|
||||
</label>
|
||||
|
||||
{/* International Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "international"} // Automatically checks if placement matches
|
||||
checked={data.placements === "satker"}
|
||||
disabled
|
||||
/>
|
||||
<span>Satker</span>
|
||||
</label>
|
||||
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "international"}
|
||||
disabled
|
||||
/>
|
||||
<span>International</span>
|
||||
|
|
|
|||
|
|
@ -580,28 +580,33 @@ export default function DetailDocument() {
|
|||
alt={data.fileName}
|
||||
/>
|
||||
<div className="flex flex-wrap lg:flex-row gap-3 items-center">
|
||||
{/* Mabes Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "mabes"} // Automatically checks if placement matches
|
||||
disabled // To reflect read-only behavior
|
||||
checked={data.placements === "mabes"}
|
||||
disabled
|
||||
/>
|
||||
<span>Nasional</span>
|
||||
</label>
|
||||
|
||||
{/* Polda Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "polda"} // Automatically checks if placement matches
|
||||
checked={data.placements === "polda"}
|
||||
disabled
|
||||
/>
|
||||
<span>Wilayah</span>
|
||||
</label>
|
||||
|
||||
{/* International Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "international"} // Automatically checks if placement matches
|
||||
checked={data.placements === "satker"}
|
||||
disabled
|
||||
/>
|
||||
<span>Satker</span>
|
||||
</label>
|
||||
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "international"}
|
||||
disabled
|
||||
/>
|
||||
<span>International</span>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"use client";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
|
|
@ -30,14 +31,6 @@ const TeksSliderPage = () => {
|
|||
initFetch();
|
||||
}, [page, limit, search]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (documentData?.length > 0) {
|
||||
// shuffleAndSetVideos();
|
||||
// const interval = setInterval(shuffleAndSetVideos, 5000);
|
||||
// return () => clearInterval(interval); // Cleanup interval on unmount
|
||||
// }
|
||||
// }, [documentData]);
|
||||
|
||||
const initFetch = async () => {
|
||||
const response = await listCuratedContent(search, limit, page - 1, 3, "1");
|
||||
console.log(response);
|
||||
|
|
@ -47,77 +40,85 @@ const TeksSliderPage = () => {
|
|||
setHasData(displayDocument && displayDocument.length > 0);
|
||||
setDisplayDocument(contentData);
|
||||
};
|
||||
// const shuffleAndSetVideos = () => {
|
||||
// const shuffled = shuffleArray([...documentData]);
|
||||
// setDisplayDocument(shuffled.slice(0, 2));
|
||||
// };
|
||||
|
||||
// const shuffleArray = (array: any[]) => {
|
||||
// for (let i = array.length - 1; i > 0; i--) {
|
||||
// const j = Math.floor(Math.random() * (i + 1));
|
||||
// [array[i], array[j]] = [array[j], array[i]];
|
||||
// }
|
||||
// return array;
|
||||
// };
|
||||
|
||||
return (
|
||||
<Carousel className="w-full pr-3">
|
||||
<CarouselContent>
|
||||
<CarouselItem>
|
||||
<div className="p-1 flex flex-row md:basis-1/2 lg:basis-1/3 gap-3">
|
||||
{displayDocument?.map((document: any) => (
|
||||
<Link
|
||||
href={`/shared/curated-content/giat-routine/document/detail/${document.id}`}
|
||||
key={document?.id}
|
||||
className="flex flex-col bg-yellow-500 sm:flex-row items-center dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full"
|
||||
>
|
||||
<div className="flex items-center justify-center rounded-lg w-16 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>
|
||||
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="text-gray-500 dark:text-gray-400 flex flex-row text-sm">
|
||||
{formatDateToIndonesian(new Date(document?.createdAt))}{" "}
|
||||
{document?.timezone ? document?.timezone : "WIB"} |{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" /> 518
|
||||
</div>
|
||||
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
||||
{document?.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 Dokumen
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
<div className="w-full px-2">
|
||||
{displayDocument.length > 0 && (
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<h2 className="text-xl font-semibold">Teks</h2>
|
||||
<Link
|
||||
href={"/shared/curated-content/giat-routine/video/all"}
|
||||
className="text-sm text-gray-500 hover:text-gray-700 flex items-center"
|
||||
>
|
||||
Lihat Semua <Icon icon="lucide:arrow-right" className="ml-1" />
|
||||
</Link>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
<Carousel className="w-full">
|
||||
<CarouselContent>
|
||||
{displayDocument.map((document, index) => (
|
||||
<CarouselItem key={index} className="md:basis-1/3 lg:basis-1/3">
|
||||
<div className="p-2">
|
||||
<Card className=" shadow-md rounded-lg overflow-hidden">
|
||||
<Link
|
||||
href={`/shared/curated-content/giat-routine/document/detail/${document.id}`}
|
||||
key={document?.id}
|
||||
className="flex flex-col bg-yellow-500 sm:flex-row items-center dark:bg-gray-800 cursor-pointer shadow-md rounded-lg p-4 gap-4 w-full"
|
||||
>
|
||||
<div className="flex items-center justify-center rounded-lg w-16 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>
|
||||
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="text-gray-500 dark:text-gray-400 flex flex-row text-sm">
|
||||
{formatDateToIndonesian(
|
||||
new Date(document?.createdAt)
|
||||
)}{" "}
|
||||
{document?.timezone ? document?.timezone : "WIB"} |{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />{" "}
|
||||
518
|
||||
</div>
|
||||
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
||||
{document?.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 Dokumen
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -52,9 +52,7 @@ const ImageAllPage = () => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="ml-5 pb-3">
|
||||
<div className="flex justify-between items-center mx-3">
|
||||
<Label className="text-base">Image</Label>
|
||||
</div>
|
||||
<div className="flex justify-between items-center mx-3"></div>
|
||||
<div className="px-5 my-5">
|
||||
<ImageSliderPage />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import { getCookiesDecrypt } from "@/lib/utils";
|
|||
import { close, loading } from "@/lib/swal";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { htmlToString } from "@/utils/globals";
|
||||
import { Link } from "@/i18n/routing";
|
||||
|
||||
const detailSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
|
|
@ -443,8 +444,13 @@ export default function DetailImage() {
|
|||
<p className="text-blue-500">Kotak Saran (0)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button>Content Rewrite</Button>
|
||||
<Link
|
||||
href={
|
||||
"/shared/curated-content/giat-routine/image/detail/content-rewrite"
|
||||
}
|
||||
>
|
||||
<Button>Content Rewrite</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -534,25 +540,31 @@ export default function DetailImage() {
|
|||
{/* Mabes Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "mabes"} // Automatically checks if placement matches
|
||||
disabled // To reflect read-only behavior
|
||||
checked={data.placements === "mabes"}
|
||||
disabled
|
||||
/>
|
||||
<span>Nasional</span>
|
||||
</label>
|
||||
|
||||
{/* Polda Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "polda"} // Automatically checks if placement matches
|
||||
checked={data.placements === "polda"}
|
||||
disabled
|
||||
/>
|
||||
<span>Wilayah</span>
|
||||
</label>
|
||||
|
||||
{/* International Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "international"} // Automatically checks if placement matches
|
||||
checked={data.placements === "satker"}
|
||||
disabled
|
||||
/>
|
||||
<span>Satker</span>
|
||||
</label>
|
||||
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "international"}
|
||||
disabled
|
||||
/>
|
||||
<span>International</span>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,349 @@
|
|||
"use client";
|
||||
import { useState } from "react";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import CustomEditor from "@/components/editor/custom-editor";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Link } from "@/i18n/routing";
|
||||
|
||||
const imageSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
description: z
|
||||
.string()
|
||||
.min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }),
|
||||
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
||||
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
});
|
||||
|
||||
const ContentRewritePage = () => {
|
||||
const [step, setStep] = useState("configuration");
|
||||
const [selectedLanguage, setSelectedLanguage] = useState("");
|
||||
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
||||
const [selectedWritingStyle, setSelectedWritingStyle] = useState("");
|
||||
const [selectedSize, setSelectedSize] = useState("");
|
||||
const [selectedSort, setSelectedSort] = useState("");
|
||||
const [selectedArticleId, setSelectedArticleId] = useState<string | null>(
|
||||
null
|
||||
);
|
||||
|
||||
type ImageSchema = z.infer<typeof imageSchema>;
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<ImageSchema>({
|
||||
resolver: zodResolver(imageSchema),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-6">
|
||||
<Card>
|
||||
<CardContent className="p-6">
|
||||
<h2 className="text-xl font-semibold mb-4">Content Rewrite</h2>
|
||||
<div className="flex items-center space-x-6 mb-6">
|
||||
<div className="flex flex-col items-center">
|
||||
<div
|
||||
className={`w-8 h-8 flex items-center justify-center border-2 rounded-full ${
|
||||
step === "configuration"
|
||||
? "border-blue-500 text-blue-500"
|
||||
: "border-gray-400 text-gray-400"
|
||||
}`}
|
||||
>
|
||||
●
|
||||
</div>
|
||||
<p
|
||||
className={
|
||||
step === "configuration"
|
||||
? "text-blue-500 font-semibold"
|
||||
: "text-gray-400"
|
||||
}
|
||||
>
|
||||
Configuration
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className={`flex-1 h-0.5 ${
|
||||
step === "draft"
|
||||
? "bg-blue-500 text-blue-500"
|
||||
: "bg-gray-400 text-gray-400"
|
||||
}`}
|
||||
></div>
|
||||
<div className="flex flex-col items-center">
|
||||
<div
|
||||
className={`w-8 h-8 flex items-center justify-center border-2 rounded-full ${
|
||||
step === "draft"
|
||||
? "border-blue-500 text-blue-500"
|
||||
: "border-gray-400 text-gray-400"
|
||||
}`}
|
||||
>
|
||||
○
|
||||
</div>
|
||||
<p
|
||||
className={
|
||||
step === "draft"
|
||||
? "text-blue-500 font-semibold"
|
||||
: "text-gray-400"
|
||||
}
|
||||
>
|
||||
Draft
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className={`flex-1 h-0.5 ${
|
||||
step === "publish"
|
||||
? "bg-blue-500 text-blue-500"
|
||||
: "bg-gray-400 text-gray-400"
|
||||
}`}
|
||||
></div>
|
||||
<div className="flex flex-col items-center">
|
||||
<div
|
||||
className={`w-8 h-8 flex items-center justify-center border-2 rounded-full ${
|
||||
step === "publish"
|
||||
? "border-blue-500 text-blue-500"
|
||||
: "border-gray-400 text-gray-400"
|
||||
}`}
|
||||
>
|
||||
○
|
||||
</div>
|
||||
<p
|
||||
className={
|
||||
step === "publish"
|
||||
? "text-blue-500 font-semibold"
|
||||
: "text-gray-400"
|
||||
}
|
||||
>
|
||||
Publish
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{step === "configuration" && (
|
||||
<>
|
||||
<div className="flex flex-row gap-3">
|
||||
<div className="space-y-2 py-3 w-4/12">
|
||||
<Label>Bahasa</Label>
|
||||
<Select onValueChange={setSelectedLanguage}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="id">Indonesia</SelectItem>
|
||||
<SelectItem value="en">English</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="space-y-2 py-3 w-4/12">
|
||||
<Label>Writing Style</Label>
|
||||
<Select onValueChange={setSelectedWritingStyle}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="friendly">Friendly</SelectItem>
|
||||
<SelectItem value="profesional">Profesional</SelectItem>
|
||||
<SelectItem value="informational">
|
||||
Informational
|
||||
</SelectItem>
|
||||
<SelectItem value="neutral">Neutral</SelectItem>
|
||||
<SelectItem value="witty">Witty</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="space-y-2 py-3 w-4/12">
|
||||
<Label>Article Size</Label>
|
||||
<Select onValueChange={setSelectedSize}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="news">
|
||||
News (300 - 900 words)
|
||||
</SelectItem>
|
||||
<SelectItem value="info">
|
||||
Info (900 - 2000 words)
|
||||
</SelectItem>
|
||||
<SelectItem value="detail">
|
||||
Detail (2000 - 5000 words)
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<Label>Configuration</Label>
|
||||
<Input
|
||||
placeholder="Type your custom instruction here!"
|
||||
className="h-20"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => setStep("draft")}
|
||||
className=" bg-blue-600 text-white"
|
||||
>
|
||||
Selanjutnya
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{step === "draft" && (
|
||||
<div>
|
||||
<div className="flex flex-row justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="accepted"
|
||||
// checked={filtered.includes("polri")}
|
||||
// onCheckedChange={(e) => handleFilter("polri", Boolean(e))}
|
||||
/>
|
||||
<label
|
||||
htmlFor="accepted"
|
||||
className="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Select All
|
||||
</label>
|
||||
</div>
|
||||
<div className="space-y-2 py-3">
|
||||
<div className="flex flex-row items-center">
|
||||
<Label className="w-[50px]">Sort by</Label>
|
||||
<Select onValueChange={setSelectedSort}>
|
||||
<SelectTrigger size="sm" className="w-[150px]">
|
||||
<SelectValue placeholder="Pilih" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="id">Indonesia</SelectItem>
|
||||
<SelectItem value="en">English</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
{[
|
||||
{
|
||||
src: "/assets/img/image1.png",
|
||||
alt: "Article 1",
|
||||
title: "Kurang dari 24 Jam Polres Muara Enim Ungka...",
|
||||
},
|
||||
{
|
||||
src: "/assets/img/image3.png",
|
||||
alt: "Article 2",
|
||||
title: "Kurang dari 24 Jam Polres Muara Enim Ungka...",
|
||||
},
|
||||
{
|
||||
src: "/assets/img/image3.png",
|
||||
alt: "Article 3",
|
||||
title: "Polres Magelang Kota Konferensi Pers Terkait...",
|
||||
},
|
||||
].map((article, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="border rounded-md overflow-hidden relative"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="absolute top-2 left-2 w-5 h-5 cursor-pointer"
|
||||
/>
|
||||
|
||||
<img
|
||||
src={article.src}
|
||||
alt={article.alt}
|
||||
className="w-full h-40 object-cover"
|
||||
/>
|
||||
|
||||
<p className="p-2 text-sm">{article.title}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row justify-between mt-3">
|
||||
<Button
|
||||
onClick={() => setStep("configuration")}
|
||||
variant={"outline"}
|
||||
color="primary"
|
||||
>
|
||||
Kembali
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setStep("publish")}
|
||||
variant={"default"}
|
||||
color="primary"
|
||||
>
|
||||
Selanjutnya
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{step === "publish" && (
|
||||
<div>
|
||||
<div className="py-3">
|
||||
<div className="flex flex-row justify-between items-center mb-3">
|
||||
<Label>940 Words</Label>
|
||||
<Link
|
||||
href={`/contributor/content/image/update-seo/${selectedArticleId}`}
|
||||
>
|
||||
<Button
|
||||
className="mb-2"
|
||||
size="sm"
|
||||
variant={"outline"}
|
||||
color="primary"
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<Controller
|
||||
control={control}
|
||||
name="description"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<CustomEditor
|
||||
onChange={onChange}
|
||||
// initialData={articleBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{/* {errors.description?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.description.message}
|
||||
</p>
|
||||
)} */}
|
||||
</div>
|
||||
<div className="flex flex-row justify-between mt-3">
|
||||
<Button
|
||||
onClick={() => setStep("configuration")}
|
||||
variant={"outline"}
|
||||
color="primary"
|
||||
>
|
||||
Kembali
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setStep("publish")}
|
||||
variant={"default"}
|
||||
color="primary"
|
||||
>
|
||||
Selanjutnya
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentRewritePage;
|
||||
|
|
@ -10,123 +10,95 @@ import {
|
|||
} from "@/components/ui/carousel";
|
||||
import { listCuratedContent } from "@/service/curated-content/curated-content";
|
||||
|
||||
import {
|
||||
formatDateToIndonesian,
|
||||
generateLocalizedPath,
|
||||
textEllipsis,
|
||||
} from "@/utils/globals";
|
||||
import { formatDateToIndonesian } from "@/utils/globals";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import {
|
||||
SortingState,
|
||||
ColumnFiltersState,
|
||||
VisibilityState,
|
||||
PaginationState,
|
||||
} from "@tanstack/react-table";
|
||||
import {
|
||||
useParams,
|
||||
usePathname,
|
||||
useRouter,
|
||||
useSearchParams,
|
||||
} from "next/navigation";
|
||||
import React, { Component, useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
type ImageData = {
|
||||
id: string;
|
||||
title: string;
|
||||
createdAt: string;
|
||||
timezone: string;
|
||||
thumbnailLink: string;
|
||||
clickCount: string;
|
||||
};
|
||||
|
||||
const ImageSliderPage = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const [imageData, setImageData] = useState<any>();
|
||||
const [displayImage, setDisplayImage] = useState<any[]>([]);
|
||||
const [imageData, setImageData] = useState<ImageData[]>([]);
|
||||
const [page, setPage] = useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState("");
|
||||
const [limit] = useState(10);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [page, limit, search]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (imageData?.length > 0) {
|
||||
// shuffleAndSetVideos();
|
||||
// const interval = setInterval(shuffleAndSetVideos, 5000);
|
||||
// return () => clearInterval(interval); // Cleanup interval on unmount
|
||||
// }
|
||||
// }, [imageData]);
|
||||
}, [page]);
|
||||
|
||||
const fetchData = async () => {
|
||||
const response = await listCuratedContent(search, limit, page - 1, 1, "1");
|
||||
console.log(response);
|
||||
|
||||
const data = response?.data?.data;
|
||||
const contentData = data?.content;
|
||||
setImageData(contentData);
|
||||
const response = await listCuratedContent("", limit, page - 1, 1, "1");
|
||||
const data = response?.data?.data?.content || [];
|
||||
setImageData(data);
|
||||
};
|
||||
|
||||
// const shuffleAndSetVideos = () => {
|
||||
// const shuffled = shuffleArray([...imageData]);
|
||||
// setDisplayImage(shuffled.slice(0, 3));
|
||||
// };
|
||||
|
||||
// const shuffleArray = (array: any[]) => {
|
||||
// for (let i = array.length - 1; i > 0; i--) {
|
||||
// const j = Math.floor(Math.random() * (i + 1));
|
||||
// [array[i], array[j]] = [array[j], array[i]];
|
||||
// }
|
||||
// return array;
|
||||
// };
|
||||
return (
|
||||
<Carousel className="w-full pr-3">
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<CarouselItem key={index}>
|
||||
<div className="p-1 flex flex-row md:basis-1/2 lg:basis-1/2 gap-3">
|
||||
{imageData?.map((image: any) => (
|
||||
<Card
|
||||
key={image?.id}
|
||||
className="hover:sc ale-110 transition-transform duration-300"
|
||||
>
|
||||
<Link
|
||||
href={`/shared/curated-content//giat-routine/image/detail/${image.id}`}
|
||||
>
|
||||
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
|
||||
<img
|
||||
src={image?.thumbnailLink}
|
||||
className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg"
|
||||
/>
|
||||
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">
|
||||
{formatDateToIndonesian(new Date(image?.createdAt))}{" "}
|
||||
{image?.timezone ? image?.timezone : "WIB"}|{" "}
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
{image?.clickCount}{" "}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fill="#f00"
|
||||
d="M7.707 10.293a1 1 0 1 0-1.414 1.414l3 3a1 1 0 0 0 1.414 0l3-3a1 1 0 0 0-1.414-1.414L11 11.586V6h5a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5v5.586zM9 4a1 1 0 0 1 2 0v2H9z"
|
||||
<div className="w-full px-2">
|
||||
{imageData.length > 0 && (
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<h2 className="text-xl font-semibold">Foto</h2>
|
||||
<Link
|
||||
href={"/shared/curated-content/giat-routine/image/all"}
|
||||
className="text-sm text-gray-500 hover:text-gray-700 flex items-center"
|
||||
>
|
||||
Lihat Semua <Icon icon="lucide:arrow-right" className="ml-1" />
|
||||
</Link>
|
||||
</div>
|
||||
<Carousel className="w-full">
|
||||
<CarouselContent>
|
||||
{imageData.map((image, index) => (
|
||||
<CarouselItem key={index} className="md:basis-1/3 lg:basis-1/3">
|
||||
<div className="p-2">
|
||||
<Card className="shadow-md rounded-lg overflow-hidden">
|
||||
<Link
|
||||
href={`/shared/curated-content/giat-routine/image/detail/${image.id}`}
|
||||
>
|
||||
<CardContent className="p-0">
|
||||
<img
|
||||
src={image?.thumbnailLink}
|
||||
alt={image?.title}
|
||||
className="w-full h-56 object-cover rounded-t-lg"
|
||||
/>
|
||||
</svg>{" "}
|
||||
</div>
|
||||
<div className="font-semibold pr-3 pb-3 mx-2 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible w-full">
|
||||
{image?.title}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
<div className="p-3">
|
||||
<p className="text-xs text-gray-500">
|
||||
{formatDateToIndonesian(
|
||||
new Date(image?.createdAt)
|
||||
)}{" "}
|
||||
{image?.timezone || "WIB"} |
|
||||
<Icon
|
||||
icon="formkit:eye"
|
||||
width="15"
|
||||
height="15"
|
||||
className="inline ml-1"
|
||||
/>
|
||||
{image?.clickCount}
|
||||
</p>
|
||||
<h3 className="font-semibold text-sm truncate">
|
||||
{image?.title}
|
||||
</h3>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
// <div className="mx-3 px-5">
|
||||
// <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
|
||||
// </div>
|
||||
// </div>
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { listCuratedContent } from "@/service/curated-content/curated-content";
|
||||
import { getListContent } from "@/service/landing/landing";
|
||||
import { formatDateToIndonesian } from "@/utils/globals";
|
||||
|
|
@ -15,9 +16,18 @@ import { Icon } from "@iconify/react/dist/iconify.js";
|
|||
import image from "next/image";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
type VideoData = {
|
||||
id: string;
|
||||
title: string;
|
||||
createdAt: string;
|
||||
timezone: string;
|
||||
thumbnailLink: string;
|
||||
clickCount: string;
|
||||
};
|
||||
|
||||
const VideoSliderPage = () => {
|
||||
const [allVideoData, setAllVideoData] = useState<any[]>([]);
|
||||
const [displayVideos, setDisplayVideos] = useState<any[]>([]);
|
||||
const [videoData, setVideoData] = useState<VideoData[]>([]);
|
||||
const [page, setPage] = useState(1);
|
||||
const [limit, setLimit] = React.useState(10);
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
|
@ -26,86 +36,74 @@ const VideoSliderPage = () => {
|
|||
fetchData();
|
||||
}, [page, limit, search]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (allVideoData?.length > 0) {
|
||||
// shuffleAndSetVideos();
|
||||
// const interval = setInterval(shuffleAndSetVideos, 5000);
|
||||
// return () => clearInterval(interval); // Cleanup interval on unmount
|
||||
// }
|
||||
// }, [allVideoData]);
|
||||
|
||||
const fetchData = async () => {
|
||||
const response = await listCuratedContent(search, limit, page - 1, 2, "1");
|
||||
console.log(response);
|
||||
|
||||
const data = response?.data?.data;
|
||||
const contentData = data?.content;
|
||||
setAllVideoData(contentData);
|
||||
setVideoData(contentData);
|
||||
};
|
||||
|
||||
// const shuffleAndSetVideos = () => {
|
||||
// const shuffled = shuffleArray([...allVideoData]);
|
||||
// setDisplayVideos(shuffled.slice(0, 3));
|
||||
// };
|
||||
|
||||
// const shuffleArray = (array: any[]) => {
|
||||
// for (let i = array.length - 1; i > 0; i--) {
|
||||
// const j = Math.floor(Math.random() * (i + 1));
|
||||
// [array[i], array[j]] = [array[j], array[i]];
|
||||
// }
|
||||
// return array;
|
||||
// };
|
||||
|
||||
return (
|
||||
<Carousel className="w-full pr-3">
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<CarouselItem key={index}>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{allVideoData.map((video: any) => (
|
||||
<Card
|
||||
key={video?.id}
|
||||
className="hover:scale-110 transition-transform duration-300"
|
||||
>
|
||||
<Link
|
||||
href={`/shared/curated-content/giat-routine/video/detail/${video.id}`}
|
||||
>
|
||||
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
|
||||
<img
|
||||
src={video?.thumbnailLink}
|
||||
className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg"
|
||||
/>
|
||||
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">
|
||||
{formatDateToIndonesian(new Date(video?.createdAt))}{" "}
|
||||
{video?.timezone || "WIB"} |
|
||||
<Icon icon="formkit:eye" width="15" height="15" />
|
||||
{video?.clickCount}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
fill="#f00"
|
||||
d="M7.707 10.293a1 1 0 1 0-1.414 1.414l3 3a1 1 0 0 0 1.414 0l3-3a1 1 0 0 0-1.414-1.414L11 11.586V6h5a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5v5.586zM9 4a1 1 0 0 1 2 0v2H9z"
|
||||
<div className="w-full px-2">
|
||||
{videoData.length > 0 && (
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<h2 className="text-xl font-semibold">Video</h2>
|
||||
<Link
|
||||
href={"/shared/curated-content/giat-routine/video/all"}
|
||||
className="text-sm text-gray-500 hover:text-gray-700 flex items-center"
|
||||
>
|
||||
Lihat Semua <Icon icon="lucide:arrow-right" className="ml-1" />
|
||||
</Link>
|
||||
</div>
|
||||
<Carousel className="w-full">
|
||||
<CarouselContent>
|
||||
{videoData.map((video, index) => (
|
||||
<CarouselItem key={index} className="md:basis-1/3 lg:basis-1/3">
|
||||
<div className="p-2">
|
||||
<Card className="shadow-md rounded-lg overflow-hidden">
|
||||
<Link
|
||||
href={`/shared/curated-content/giat-routine/video/detail/${video.id}`}
|
||||
>
|
||||
<CardContent className="p-0">
|
||||
<img
|
||||
src={video?.thumbnailLink}
|
||||
alt={video?.title}
|
||||
className="w-full h-56 object-cover rounded-t-lg"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="font-semibold pr-3 pb-3 mx-2 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible w-full">
|
||||
{video?.title}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
<div className="p-3">
|
||||
<p className="text-xs text-gray-500">
|
||||
{formatDateToIndonesian(
|
||||
new Date(video?.createdAt)
|
||||
)}{" "}
|
||||
{video?.timezone || "WIB"} |
|
||||
<Icon
|
||||
icon="formkit:eye"
|
||||
width="15"
|
||||
height="15"
|
||||
className="inline ml-1"
|
||||
/>
|
||||
{video?.clickCount}
|
||||
</p>
|
||||
<h3 className="font-semibold text-sm truncate">
|
||||
{video?.title}
|
||||
</h3>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Link>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -523,39 +523,39 @@ export default function DetailImage() {
|
|||
key={data.id}
|
||||
className="flex items-center gap-3 mt-2"
|
||||
>
|
||||
{/* <img
|
||||
className="object-cover w-20 h-20"
|
||||
src={data.thumbnailUrl} // Assuming `thumbnailUrl` is the property that contains the URL for the thumbnail image
|
||||
alt={`Thumbnail ${index}`}
|
||||
/> */}
|
||||
<img
|
||||
className="object-cover w-20 h-20 lg:w-32 lg:h-32"
|
||||
src={"/assets/video-icon.webp"}
|
||||
alt={` ${data.id}`}
|
||||
/>
|
||||
<div className="flex flex-wrap lg:flex-row gap-3 items-center">
|
||||
{/* Mabes Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "mabes"} // Automatically checks if placement matches
|
||||
disabled // To reflect read-only behavior
|
||||
checked={data.placements === "mabes"}
|
||||
disabled
|
||||
/>
|
||||
<span>Nasional</span>
|
||||
</label>
|
||||
|
||||
{/* Polda Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "polda"} // Automatically checks if placement matches
|
||||
checked={data.placements === "polda"}
|
||||
disabled
|
||||
/>
|
||||
<span>Wilayah</span>
|
||||
</label>
|
||||
|
||||
{/* International Checkbox */}
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "international"} // Automatically checks if placement matches
|
||||
checked={data.placements === "satker"}
|
||||
disabled
|
||||
/>
|
||||
<span>Satker</span>
|
||||
</label>
|
||||
|
||||
<label className=" cursor-pointer flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={data.placements === "international"}
|
||||
disabled
|
||||
/>
|
||||
<span>International</span>
|
||||
|
|
|
|||
|
|
@ -24,15 +24,19 @@ import AudioSliderPage from "./giat-routine/audio/audio";
|
|||
import ImageSliderPage from "./giat-routine/image/image";
|
||||
import TeksSliderPage from "./giat-routine/document/teks";
|
||||
import ContestTable from "../contest/components/contest-table";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const CuratedContentPage = () => {
|
||||
const t = useTranslations("Curation");
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="my-3">
|
||||
<Tabs defaultValue="giat-routine" className="w-full">
|
||||
<Card className="py-3 px-2 my-4">
|
||||
<p className="text-lg font-semibold ml-2">Kurasi Konten</p>
|
||||
<p className="text-lg font-semibold ml-2">
|
||||
{t("content-curation")}
|
||||
</p>
|
||||
<TabsList className="flex-wrap">
|
||||
<TabsTrigger
|
||||
value="giat-routine"
|
||||
|
|
@ -73,80 +77,15 @@ const CuratedContentPage = () => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="ml-5 pb-3">
|
||||
<div className="flex justify-between items-center mx-3">
|
||||
<Label className="text-base">Audio Visual</Label>
|
||||
|
||||
<div className="flex items-center">
|
||||
<Label>
|
||||
{" "}
|
||||
<Link
|
||||
href={
|
||||
"/shared/curated-content/giat-routine/video/all"
|
||||
}
|
||||
>
|
||||
Lihat Semua
|
||||
</Link>
|
||||
</Label>
|
||||
<ArrowRight size={18} className="text-slate-600" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-5 my-5">
|
||||
<VideoSliderPage />
|
||||
</div>
|
||||
<div className="flex justify-between items-center mx-3">
|
||||
<Label className="text-base">Audio</Label>
|
||||
<div className="flex items-center">
|
||||
<Label>
|
||||
{" "}
|
||||
<Link
|
||||
href={
|
||||
"/shared/curated-content/giat-routine/audio/all"
|
||||
}
|
||||
>
|
||||
Lihat Semua
|
||||
</Link>
|
||||
</Label>
|
||||
<ArrowRight size={18} className="text-slate-600" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-5 my-5">
|
||||
<AudioSliderPage />
|
||||
</div>
|
||||
<div className="flex justify-between items-center mx-3">
|
||||
<Label className="text-base">Foto</Label>
|
||||
<div className="flex items-center">
|
||||
<Label>
|
||||
{" "}
|
||||
<Link
|
||||
href={
|
||||
"/shared/curated-content/giat-routine/image/all"
|
||||
}
|
||||
>
|
||||
Lihat Semua
|
||||
</Link>
|
||||
</Label>
|
||||
<ArrowRight size={18} className="text-slate-600" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-5 my-5">
|
||||
<ImageSliderPage />
|
||||
</div>
|
||||
<div className="flex justify-between items-center mx-3">
|
||||
<Label className="text-base">Teks</Label>
|
||||
<div className="flex items-center">
|
||||
<Label>
|
||||
{" "}
|
||||
<Link
|
||||
href={
|
||||
"/shared/curated-content/giat-routine/document/all"
|
||||
}
|
||||
>
|
||||
Lihat Semua
|
||||
</Link>
|
||||
</Label>
|
||||
<ArrowRight size={18} className="text-slate-600" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-5 my-5">
|
||||
<TeksSliderPage />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -442,7 +442,22 @@ export default function FormAudio() {
|
|||
return;
|
||||
}
|
||||
|
||||
const requestData = {
|
||||
let requestData: {
|
||||
title: string;
|
||||
description: string;
|
||||
htmlDescription: string;
|
||||
fileTypeId: string;
|
||||
categoryId: any;
|
||||
subCategoryId: any;
|
||||
uploadedBy: string;
|
||||
statusId: string;
|
||||
publishedFor: string;
|
||||
creatorName: string;
|
||||
tags: string;
|
||||
isYoutube: boolean;
|
||||
isInternationalMedia: boolean;
|
||||
attachFromScheduleId?: number; // ✅ Tambahkan properti ini
|
||||
} = {
|
||||
...data,
|
||||
title: finalTitle,
|
||||
description: finalDescription,
|
||||
|
|
@ -461,6 +476,10 @@ export default function FormAudio() {
|
|||
|
||||
let id = Cookies.get("idCreate");
|
||||
|
||||
if (scheduleId !== undefined) {
|
||||
requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini
|
||||
}
|
||||
|
||||
if (id == undefined) {
|
||||
const response = await createMedia(requestData);
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import { options } from "@fullcalendar/core/preact.js";
|
|||
import dynamic from "next/dynamic";
|
||||
import { getCsrfToken } from "@/service/auth";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { request } from "http";
|
||||
|
||||
interface FileWithPreview extends File {
|
||||
preview: string;
|
||||
|
|
@ -443,11 +444,28 @@ export default function FormImage() {
|
|||
const finalTags = tags.join(", ");
|
||||
const finalTitle = isSwitchOn ? title : data.title;
|
||||
const finalDescription = articleBody || data.description;
|
||||
|
||||
if (!finalDescription.trim()) {
|
||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||
return;
|
||||
}
|
||||
const requestData = {
|
||||
|
||||
let requestData: {
|
||||
title: string;
|
||||
description: string;
|
||||
htmlDescription: string;
|
||||
fileTypeId: string;
|
||||
categoryId: any;
|
||||
subCategoryId: any;
|
||||
uploadedBy: string;
|
||||
statusId: string;
|
||||
publishedFor: string;
|
||||
creatorName: string;
|
||||
tags: string;
|
||||
isYoutube: boolean;
|
||||
isInternationalMedia: boolean;
|
||||
attachFromScheduleId?: number; // ✅ Tambahkan properti ini
|
||||
} = {
|
||||
...data,
|
||||
title: finalTitle,
|
||||
description: finalDescription,
|
||||
|
|
@ -466,14 +484,14 @@ export default function FormImage() {
|
|||
|
||||
let id = Cookies.get("idCreate");
|
||||
|
||||
if (scheduleId !== undefined) {
|
||||
requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini
|
||||
}
|
||||
|
||||
if (id == undefined) {
|
||||
const response = await createMedia(requestData);
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
|
||||
// if (response?.error) {
|
||||
// MySwal.fire("Error", response?.message, "error");
|
||||
// return;
|
||||
// }
|
||||
Cookies.set("idCreate", response?.data?.data, { expires: 1 });
|
||||
id = response?.data?.data;
|
||||
|
||||
|
|
@ -489,16 +507,15 @@ export default function FormImage() {
|
|||
}
|
||||
|
||||
// Upload File
|
||||
const progressInfoArr = [];
|
||||
for (const item of files) {
|
||||
progressInfoArr.push({ percentage: 0, fileName: item.name });
|
||||
}
|
||||
const progressInfoArr = files.map((item) => ({
|
||||
percentage: 0,
|
||||
fileName: item.name,
|
||||
}));
|
||||
progressInfo = progressInfoArr;
|
||||
setIsStartUpload(true);
|
||||
setProgressList(progressInfoArr);
|
||||
|
||||
close();
|
||||
// showProgress();
|
||||
files.map(async (item: any, index: number) => {
|
||||
await uploadResumableFile(
|
||||
index,
|
||||
|
|
@ -509,8 +526,6 @@ export default function FormImage() {
|
|||
});
|
||||
|
||||
Cookies.remove("idCreate");
|
||||
|
||||
// MySwal.fire("Sukses", "Data berhasil disimpan.", "success");
|
||||
};
|
||||
|
||||
const onSubmit = (data: ImageSchema) => {
|
||||
|
|
|
|||
|
|
@ -394,6 +394,33 @@ export default function FormConvertSPIT() {
|
|||
return temp;
|
||||
};
|
||||
|
||||
// const setupPlacement = (
|
||||
// index: number,
|
||||
// category: string,
|
||||
// isChecked: boolean
|
||||
// ) => {
|
||||
// setFilePlacements((prev) =>
|
||||
// prev.map((placement, i) =>
|
||||
// i === index
|
||||
// ? isChecked
|
||||
// ? [...new Set([...placement, category])] // Tambahkan kategori jika belum ada
|
||||
// : placement.filter((item) => item !== category) // Hapus kategori jika ada
|
||||
// : placement
|
||||
// )
|
||||
// );
|
||||
// };
|
||||
|
||||
const handleSelectAll = (category: string, isChecked: boolean) => {
|
||||
setFilePlacements((prev: string[][]) =>
|
||||
prev.map(
|
||||
(placement: string[]) =>
|
||||
isChecked
|
||||
? Array.from(new Set([...placement, category])) // Konversi Set ke array dengan Array.from()
|
||||
: placement.filter((item: string) => item !== category) // Hapus jika ada
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const save = async (data: {
|
||||
contentTitle: string;
|
||||
contentDescription: string;
|
||||
|
|
@ -785,6 +812,66 @@ export default function FormConvertSPIT() {
|
|||
<div className="mt-3">
|
||||
<Label className="text-xl">Penempatan file</Label>
|
||||
</div>
|
||||
{files?.length > 1 && (
|
||||
<div className="flex flex-wrap gap-2 mt-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all-content"
|
||||
onCheckedChange={(e) =>
|
||||
handleSelectAll("all", Boolean(e))
|
||||
}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all-content"
|
||||
className="text-xs font-medium"
|
||||
>
|
||||
All
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all-nasional"
|
||||
onCheckedChange={(e) =>
|
||||
handleSelectAll("mabes", Boolean(e))
|
||||
}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all-nasional"
|
||||
className="text-xs font-medium"
|
||||
>
|
||||
All Nasional
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all-wilayah"
|
||||
onCheckedChange={(e) =>
|
||||
handleSelectAll("polda", Boolean(e))
|
||||
}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all-wilayah"
|
||||
className="text-xs font-medium"
|
||||
>
|
||||
All Wilayah
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="all-international"
|
||||
onCheckedChange={(e) =>
|
||||
handleSelectAll("international", Boolean(e))
|
||||
}
|
||||
/>
|
||||
<label
|
||||
htmlFor="all-international"
|
||||
className="text-xs font-medium"
|
||||
>
|
||||
All Internasional
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{files?.map((file, index) => (
|
||||
<div
|
||||
key={file.contentId}
|
||||
|
|
|
|||
|
|
@ -441,7 +441,22 @@ export default function FormTeks() {
|
|||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||
return;
|
||||
}
|
||||
const requestData = {
|
||||
let requestData: {
|
||||
title: string;
|
||||
description: string;
|
||||
htmlDescription: string;
|
||||
fileTypeId: string;
|
||||
categoryId: any;
|
||||
subCategoryId: any;
|
||||
uploadedBy: string;
|
||||
statusId: string;
|
||||
publishedFor: string;
|
||||
creatorName: string;
|
||||
tags: string;
|
||||
isYoutube: boolean;
|
||||
isInternationalMedia: boolean;
|
||||
attachFromScheduleId?: number; // ✅ Tambahkan properti ini
|
||||
} = {
|
||||
...data,
|
||||
title: finalTitle,
|
||||
description: finalDescription,
|
||||
|
|
@ -460,6 +475,10 @@ export default function FormTeks() {
|
|||
|
||||
let id = Cookies.get("idCreate");
|
||||
|
||||
if (scheduleId !== undefined) {
|
||||
requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini
|
||||
}
|
||||
|
||||
if (id == undefined) {
|
||||
const response = await createMedia(requestData);
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
|
|
|
|||
|
|
@ -441,7 +441,22 @@ export default function FormVideo() {
|
|||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||
return;
|
||||
}
|
||||
const requestData = {
|
||||
let requestData: {
|
||||
title: string;
|
||||
description: string;
|
||||
htmlDescription: string;
|
||||
fileTypeId: string;
|
||||
categoryId: any;
|
||||
subCategoryId: any;
|
||||
uploadedBy: string;
|
||||
statusId: string;
|
||||
publishedFor: string;
|
||||
creatorName: string;
|
||||
tags: string;
|
||||
isYoutube: boolean;
|
||||
isInternationalMedia: boolean;
|
||||
attachFromScheduleId?: number; // ✅ Tambahkan properti ini
|
||||
} = {
|
||||
...data,
|
||||
title: finalTitle,
|
||||
description: finalDescription,
|
||||
|
|
@ -460,6 +475,10 @@ export default function FormVideo() {
|
|||
|
||||
let id = Cookies.get("idCreate");
|
||||
|
||||
if (scheduleId !== undefined) {
|
||||
requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini
|
||||
}
|
||||
|
||||
if (id == undefined) {
|
||||
const response = await createMedia(requestData);
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ export default function FormContestDetail() {
|
|||
mabes: false,
|
||||
polda: false,
|
||||
polres: false,
|
||||
satker: false,
|
||||
});
|
||||
|
||||
const {
|
||||
|
|
@ -224,18 +225,17 @@ export default function FormContestDetail() {
|
|||
}, [detail?.targetOutput]);
|
||||
|
||||
useEffect(() => {
|
||||
if (detail?.targetParticipantTopLevel) {
|
||||
const outputSet = new Set(
|
||||
detail.targetParticipantTopLevel.split(",").map(Number)
|
||||
);
|
||||
if (detail?.targetOutput) {
|
||||
const outputSet = new Set(detail.targetOutput.split(",").map(Number));
|
||||
setUnitSelection({
|
||||
allUnit: outputSet.has(0),
|
||||
mabes: outputSet.has(1),
|
||||
polda: outputSet.has(2),
|
||||
polres: outputSet.has(3),
|
||||
satker: outputSet.has(4),
|
||||
});
|
||||
}
|
||||
}, [detail?.targetParticipantTopLevel]);
|
||||
}, [detail?.targetOutput]);
|
||||
|
||||
const handleCheckboxChange = (levelId: number) => {
|
||||
setCheckedLevels((prev) => {
|
||||
|
|
@ -267,6 +267,7 @@ export default function FormContestDetail() {
|
|||
mabes: "1",
|
||||
polda: "2",
|
||||
polres: "3",
|
||||
satker: "4",
|
||||
};
|
||||
|
||||
const assignmentPurposeString = Object.keys(unitSelection)
|
||||
|
|
@ -436,7 +437,7 @@ export default function FormContestDetail() {
|
|||
fileTypeId: string,
|
||||
duration: string
|
||||
) {
|
||||
console.log(idx, id, file, fileTypeId, duration);
|
||||
console.log("Param Upload : ", idx, id, file, fileTypeId, duration);
|
||||
|
||||
const resCsrf = await getCsrfToken();
|
||||
const csrfToken = resCsrf?.data?.token;
|
||||
|
|
@ -451,7 +452,7 @@ export default function FormContestDetail() {
|
|||
retryDelays: [0, 3000, 6000, 12_000, 24_000],
|
||||
chunkSize: 20_000,
|
||||
metadata: {
|
||||
assignmentId: id,
|
||||
contestId: id,
|
||||
filename: file.name,
|
||||
contentType: file.type,
|
||||
fileTypeId: fileTypeId,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {
|
|||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CalendarIcon, Clock1, MapPin, Plus, User2 } from "lucide-react";
|
||||
import { CalendarIcon, Clock1, Eye, MapPin, Plus, User2 } from "lucide-react";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { addDays, format, parseISO, setDate } from "date-fns";
|
||||
import { DateRange } from "react-day-picker";
|
||||
|
|
@ -30,6 +30,7 @@ import { error, loading } from "@/lib/swal";
|
|||
import Cookies from "js-cookie";
|
||||
import {
|
||||
detailSchedule,
|
||||
getListScheduleAttachment,
|
||||
listScheduleNext,
|
||||
listScheduleToday,
|
||||
postSchedule,
|
||||
|
|
@ -61,6 +62,14 @@ interface Detail {
|
|||
addressLong: number;
|
||||
}
|
||||
|
||||
interface Attachment {
|
||||
id: any;
|
||||
title: string;
|
||||
fileTypeId: number;
|
||||
type: number;
|
||||
fileTypeName: string;
|
||||
}
|
||||
|
||||
export default function FormEventDetail() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const { id } = useParams() as { id: string };
|
||||
|
|
@ -89,6 +98,14 @@ export default function FormEventDetail() {
|
|||
},
|
||||
});
|
||||
|
||||
const [lampiran, setDataLampiran] = useState<Attachment[]>([]);
|
||||
|
||||
async function getDataAttachment() {
|
||||
const response = await getListScheduleAttachment(id);
|
||||
console.log("data attach", response?.data?.data?.content);
|
||||
setDataLampiran(response?.data?.data?.content);
|
||||
}
|
||||
|
||||
async function getDataByDate() {
|
||||
const resToday = await listScheduleToday();
|
||||
const today = resToday?.data?.data;
|
||||
|
|
@ -120,6 +137,7 @@ export default function FormEventDetail() {
|
|||
}
|
||||
}
|
||||
initState();
|
||||
getDataAttachment();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
|
@ -130,6 +148,29 @@ export default function FormEventDetail() {
|
|||
setEndTime(e.target.value);
|
||||
};
|
||||
|
||||
const handleDestinationUpload = (
|
||||
type: number,
|
||||
id: string | number,
|
||||
setOpen: (open: boolean) => void,
|
||||
router: any
|
||||
) => {
|
||||
setOpen(false); // Tutup modal dialog
|
||||
|
||||
if (id !== undefined) {
|
||||
Cookies.set("scheduleId", id.toString(), { expires: 1 });
|
||||
Cookies.set("scheduleType", "3", { expires: 1 });
|
||||
|
||||
const routes: Record<number, string> = {
|
||||
1: "/in/contributor/schedule/media/image/create",
|
||||
2: "/in/contributor/schedule/media/video/create",
|
||||
3: "/in/contributor/schedule/media/text/create",
|
||||
4: "/in/contributor/schedule/media/audio/create",
|
||||
};
|
||||
|
||||
router.push(routes[type] || "/admin/schedule/media/audio/create");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col lg:flex-row gap-2">
|
||||
<Card className="w-full lg:w-9/12">
|
||||
|
|
@ -336,92 +377,67 @@ export default function FormEventDetail() {
|
|||
<Button color="primary" size="sm" type="button">
|
||||
<Plus /> Tambah Lampiran
|
||||
</Button>
|
||||
<p>0 Lampiran</p>
|
||||
<p>{lampiran?.length || 0} Lampiran</p>
|
||||
</div>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-md p-6 bg-white rounded-lg shadow-lg h-[420px] w-[700px]">
|
||||
<h2 className="text-lg font-semibold">
|
||||
Pilih Jenis Lampiran
|
||||
</h2>
|
||||
<div className=" space-y-4 gap-y-4">
|
||||
<Link href={"/contributor/schedule/media/video/create"}>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={"/assets/img/upload-video.png"}
|
||||
alt={"item.label"}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">
|
||||
Audio Visual
|
||||
</h3>
|
||||
<div className="space-y-4 gap-y-4">
|
||||
{[
|
||||
{
|
||||
type: 2,
|
||||
img: "/assets/img/upload-video.png",
|
||||
label: "Audio Visual",
|
||||
},
|
||||
{
|
||||
type: 1,
|
||||
img: "/assets/img/upload-image.png",
|
||||
label: "Foto",
|
||||
},
|
||||
{
|
||||
type: 3,
|
||||
img: "/assets/img/upload-text.png",
|
||||
label: "Teks",
|
||||
},
|
||||
{
|
||||
type: 4,
|
||||
img: "/assets/img/upload-audio.png",
|
||||
label: "Audio",
|
||||
},
|
||||
].map((item) => (
|
||||
<a
|
||||
key={item.type}
|
||||
onClick={() =>
|
||||
handleDestinationUpload(
|
||||
item.type,
|
||||
id,
|
||||
setOpen,
|
||||
router
|
||||
)
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={item.img}
|
||||
alt={item.label}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">
|
||||
{item.label}
|
||||
</h3>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa {item.label.toLowerCase()}{" "}
|
||||
dengan format sesuai yang didukung.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa video dengan format avi, wmv,
|
||||
atau mp4 dengan ukuran minimal 2mb dan maksimal
|
||||
500mb.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={"/contributor/schedule/media/image/create"}>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={"/assets/img/upload-image.png"}
|
||||
alt={"item.label"}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">Foto</h3>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa video dengan format avi, wmv,
|
||||
atau mp4 dengan ukuran minimal 2mb dan maksimal
|
||||
500mb.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={"/contributor/schedule/media/text/create"}>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={"/assets/img/upload-text.png"}
|
||||
alt={"item.label"}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">Teks</h3>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa video dengan format avi, wmv,
|
||||
atau mp4 dengan ukuran minimal 2mb dan maksimal
|
||||
500mb.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={"/contributor/schedule/media/audio/create"}>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={"/assets/img/upload-audio.png"}
|
||||
alt={"item.label"}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">Audio</h3>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa video dengan format avi, wmv,
|
||||
atau mp4 dengan ukuran minimal 2mb dan maksimal
|
||||
500mb.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
|
@ -430,7 +446,52 @@ export default function FormEventDetail() {
|
|||
""
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-4 flex justify-end">
|
||||
<div className="mt-6 mx-6">
|
||||
<table className="w-full border border-gray-300 rounded-lg">
|
||||
<thead className="bg-gray-200 text-left">
|
||||
<tr>
|
||||
<th className="p-3 font-semibold">Judul Konten</th>
|
||||
<th className="p-3 font-semibold">Konten</th>
|
||||
<th className="p-3 font-semibold">Tindakan</th>
|
||||
<th className="p-3 font-semibold">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{lampiran.map((item, index) => (
|
||||
<tr key={index} className="border-t border-gray-300">
|
||||
<td className="p-3 text-blue-600 cursor-pointer">
|
||||
{item.title}
|
||||
</td>
|
||||
<td className="p-3">{item.fileTypeName}</td>
|
||||
<td className="p-3 text-blue-600">Konfersi Ai</td>
|
||||
<td className="p-3">
|
||||
<Link
|
||||
href={
|
||||
Number(item.fileTypeId) == 1
|
||||
? `/contributor/content/image/detail/${item.id}`
|
||||
: Number(item.fileTypeId) == 2
|
||||
? `/contributor/content/video/detail/${item.id}`
|
||||
: Number(item.fileTypeId) == 3
|
||||
? `/contributor/content/teks/detail/${item.id}`
|
||||
: `/contributor/content/audio/detail/${item.id}`
|
||||
}
|
||||
target="_blank"
|
||||
className="btn"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Eye
|
||||
className={
|
||||
item.type === 1 ? "text-blue-600" : "text-black"
|
||||
}
|
||||
/>
|
||||
</Link>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="my-4 mr-6 flex justify-end">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {
|
|||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CalendarIcon, Clock1, MapPin, Plus, User2 } from "lucide-react";
|
||||
import { CalendarIcon, Clock1, Eye, MapPin, Plus, User2 } from "lucide-react";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { addDays, format, parseISO, setDate } from "date-fns";
|
||||
import { DateRange } from "react-day-picker";
|
||||
|
|
@ -30,6 +30,7 @@ import { error, loading } from "@/lib/swal";
|
|||
import Cookies from "js-cookie";
|
||||
import {
|
||||
detailSchedule,
|
||||
getListScheduleAttachment,
|
||||
listScheduleNext,
|
||||
listScheduleToday,
|
||||
postSchedule,
|
||||
|
|
@ -50,6 +51,7 @@ import {
|
|||
import { formatDate } from "@fullcalendar/core/index.js";
|
||||
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import $ from "jquery";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
|
|
@ -68,6 +70,14 @@ interface Detail {
|
|||
addressLong: number;
|
||||
}
|
||||
|
||||
interface Attachment {
|
||||
id: any;
|
||||
title: string;
|
||||
fileTypeId: number;
|
||||
type: number;
|
||||
fileTypeName: string;
|
||||
}
|
||||
|
||||
export default function FormDetailPressRillis() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const { id } = useParams() as { id: string };
|
||||
|
|
@ -98,6 +108,14 @@ export default function FormDetailPressRillis() {
|
|||
},
|
||||
});
|
||||
|
||||
const [lampiran, setDataLampiran] = useState<Attachment[]>([]);
|
||||
|
||||
async function getDataAttachment() {
|
||||
const response = await getListScheduleAttachment(id);
|
||||
console.log("data attach", response?.data?.data?.content);
|
||||
setDataLampiran(response?.data?.data?.content);
|
||||
}
|
||||
|
||||
async function getDataByDate() {
|
||||
const resToday = await listScheduleToday();
|
||||
const today = resToday?.data?.data;
|
||||
|
|
@ -129,6 +147,7 @@ export default function FormDetailPressRillis() {
|
|||
}
|
||||
}
|
||||
initState();
|
||||
getDataAttachment();
|
||||
}, [refresh, setValue]);
|
||||
|
||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
|
@ -139,20 +158,26 @@ export default function FormDetailPressRillis() {
|
|||
setEndTime(e.target.value);
|
||||
};
|
||||
|
||||
const handleUploadAttachment = () => {
|
||||
const scheduleId = Cookies.get("scheduleId");
|
||||
const handleDestinationUpload = (
|
||||
type: number,
|
||||
id: string | number,
|
||||
setOpen: (open: boolean) => void,
|
||||
router: any
|
||||
) => {
|
||||
setOpen(false); // Tutup modal dialog
|
||||
|
||||
if (scheduleId == undefined) {
|
||||
MySwal.fire({
|
||||
title: "Simpan Jadwal Terlebih Dahulu",
|
||||
icon: "info",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Ok",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (id !== undefined) {
|
||||
Cookies.set("scheduleId", id.toString(), { expires: 1 });
|
||||
Cookies.set("scheduleType", "3", { expires: 1 });
|
||||
|
||||
const routes: Record<number, string> = {
|
||||
1: "/in/contributor/schedule/media/image/create",
|
||||
2: "/in/contributor/schedule/media/video/create",
|
||||
3: "/in/contributor/schedule/media/text/create",
|
||||
4: "/in/contributor/schedule/media/audio/create",
|
||||
};
|
||||
|
||||
router.push(routes[type] || "/admin/schedule/media/audio/create");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -379,92 +404,67 @@ export default function FormDetailPressRillis() {
|
|||
<Button color="primary" size="sm" type="button">
|
||||
<Plus /> Tambah Lampiran
|
||||
</Button>
|
||||
<p>0 Lampiran</p>
|
||||
<p>{lampiran?.length || 0} Lampiran</p>
|
||||
</div>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-md p-6 bg-white rounded-lg shadow-lg h-[420px] w-[700px]">
|
||||
<h2 className="text-lg font-semibold">
|
||||
Pilih Jenis Lampiran
|
||||
</h2>
|
||||
<div className=" space-y-4 gap-y-4">
|
||||
<Link href={"/contributor/schedule/media/video/create"}>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={"/assets/img/upload-video.png"}
|
||||
alt={"item.label"}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">
|
||||
Audio Visual
|
||||
</h3>
|
||||
<div className="space-y-4 gap-y-4">
|
||||
{[
|
||||
{
|
||||
type: 2,
|
||||
img: "/assets/img/upload-video.png",
|
||||
label: "Audio Visual",
|
||||
},
|
||||
{
|
||||
type: 1,
|
||||
img: "/assets/img/upload-image.png",
|
||||
label: "Foto",
|
||||
},
|
||||
{
|
||||
type: 3,
|
||||
img: "/assets/img/upload-text.png",
|
||||
label: "Teks",
|
||||
},
|
||||
{
|
||||
type: 4,
|
||||
img: "/assets/img/upload-audio.png",
|
||||
label: "Audio",
|
||||
},
|
||||
].map((item) => (
|
||||
<a
|
||||
key={item.type}
|
||||
onClick={() =>
|
||||
handleDestinationUpload(
|
||||
item.type,
|
||||
id,
|
||||
setOpen,
|
||||
router
|
||||
)
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={item.img}
|
||||
alt={item.label}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">
|
||||
{item.label}
|
||||
</h3>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa {item.label.toLowerCase()}{" "}
|
||||
dengan format sesuai yang didukung.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa video dengan format avi, wmv,
|
||||
atau mp4 dengan ukuran minimal 2mb dan maksimal
|
||||
500mb.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={"/contributor/schedule/media/image/create"}>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={"/assets/img/upload-image.png"}
|
||||
alt={"item.label"}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">Foto</h3>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa video dengan format avi, wmv,
|
||||
atau mp4 dengan ukuran minimal 2mb dan maksimal
|
||||
500mb.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={"/contributor/schedule/media/text/create"}>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={"/assets/img/upload-text.png"}
|
||||
alt={"item.label"}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">Teks</h3>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa video dengan format avi, wmv,
|
||||
atau mp4 dengan ukuran minimal 2mb dan maksimal
|
||||
500mb.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={"/contributor/schedule/media/audio/create"}>
|
||||
<div className="flex flex-row items-center space-x-4">
|
||||
<div className="flex flex-col w-4/12 items-center">
|
||||
<img
|
||||
src={"/assets/img/upload-audio.png"}
|
||||
alt={"item.label"}
|
||||
className="w-12 h-12"
|
||||
/>
|
||||
<h3 className="text-base font-semibold">Audio</h3>
|
||||
</div>
|
||||
<div className="w-8/12">
|
||||
<p className="text-sm text-gray-600">
|
||||
Unggah media berupa video dengan format avi, wmv,
|
||||
atau mp4 dengan ukuran minimal 2mb dan maksimal
|
||||
500mb.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
|
@ -472,6 +472,51 @@ export default function FormDetailPressRillis() {
|
|||
) : (
|
||||
""
|
||||
)}
|
||||
<div className="mt-6">
|
||||
<table className="w-full border border-gray-300 rounded-lg">
|
||||
<thead className="bg-gray-200 text-left">
|
||||
<tr>
|
||||
<th className="p-3 font-semibold">Judul Konten</th>
|
||||
<th className="p-3 font-semibold">Konten</th>
|
||||
<th className="p-3 font-semibold">Tindakan</th>
|
||||
<th className="p-3 font-semibold">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{lampiran.map((item, index) => (
|
||||
<tr key={index} className="border-t border-gray-300">
|
||||
<td className="p-3 text-blue-600 cursor-pointer">
|
||||
{item.title}
|
||||
</td>
|
||||
<td className="p-3">{item.fileTypeName}</td>
|
||||
<td className="p-3 text-blue-600">Konfersi Ai</td>
|
||||
<td className="p-3">
|
||||
<Link
|
||||
href={
|
||||
Number(item.fileTypeId) == 1
|
||||
? `/contributor/content/image/detail/${item.id}`
|
||||
: Number(item.fileTypeId) == 2
|
||||
? `/contributor/content/video/detail/${item.id}`
|
||||
: Number(item.fileTypeId) == 3
|
||||
? `/contributor/content/teks/detail/${item.id}`
|
||||
: `/contributor/content/audio/detail/${item.id}`
|
||||
}
|
||||
target="_blank"
|
||||
className="btn"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Eye
|
||||
className={
|
||||
item.type === 1 ? "text-blue-600" : "text-black"
|
||||
}
|
||||
/>
|
||||
</Link>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="mt-4 flex justify-end">
|
||||
<Button type="submit" color="primary">
|
||||
Submit
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ const Division = () => {
|
|||
<div className="mx-auto px-4 w-full">
|
||||
{/* Header */}
|
||||
{/* <Reveal> */}
|
||||
{/* <h2 className="text-center text-2xl font-bold text-gray-800 dark:text-white mb-4">
|
||||
{/* <h2 className="text-center text-2xl font-bold text-gray-800 dark:text-white mb-3">
|
||||
{pathname?.split("/")[1] == "in" ? (
|
||||
<>
|
||||
{t("coverageOnly")} <span className="text-[#bb3523]">{t("division")}</span>{" "}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,17 @@ import React, { useEffect } from "react";
|
|||
import DateRangePicker from "@/components/date-range-picker";
|
||||
import { usePathname } from "@/components/navigation";
|
||||
import { cn, getCookiesDecrypt } from "@/lib/utils";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "./ui/dialog";
|
||||
import { Button } from "./ui/button";
|
||||
import { Label } from "./ui/label";
|
||||
import { Input } from "./ui/input";
|
||||
|
||||
const PageTitle = ({
|
||||
title,
|
||||
|
|
@ -30,7 +41,35 @@ const PageTitle = ({
|
|||
<div className="text-2xl font-medium text-default-800 capitalize">
|
||||
Dashboard
|
||||
</div>
|
||||
<DateRangePicker />
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Download Report</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Download Report</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="w-full">
|
||||
<Label>Date</Label>
|
||||
<Input
|
||||
type="date"
|
||||
// value={dateFilter}
|
||||
// onChange={(e) => setDateFilter(e.target.value)}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="submit"
|
||||
// onClick={downloadReport}
|
||||
>
|
||||
Download
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -160,7 +160,8 @@ const LoginForm = () => {
|
|||
Number(profile?.data?.data?.roleId) == 10 ||
|
||||
Number(profile?.data?.data?.roleId) == 11 ||
|
||||
Number(profile?.data?.data?.roleId) == 12 ||
|
||||
Number(profile?.data?.data?.roleId) == 18
|
||||
Number(profile?.data?.data?.roleId) == 18 ||
|
||||
Number(profile?.data?.data?.roleId) == 19
|
||||
) {
|
||||
if (profile?.data?.data?.roleId === 18) {
|
||||
window.location.href = "/in/dashboard/executive";
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ const ProfileInfo = () => {
|
|||
<div className="text-sm font-medium capitalize lg:block hidden">
|
||||
{detail?.fullname}
|
||||
</div>
|
||||
<p className="text-xs">({detail?.fullname})</p>
|
||||
<p className="text-xs">({detail?.username})</p>
|
||||
</div>
|
||||
<span className="text-base me-2.5 lg:inline-block hidden">
|
||||
<Icon icon="heroicons-outline:chevron-down"></Icon>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,285 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { ChevronsUpDown, Check, CirclePlus } from 'lucide-react';
|
||||
|
||||
import { cn, getCookiesDecrypt } from "@/lib/utils"
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
} from "@/components/ui/command"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
import { useConfig } from "@/hooks/use-config";
|
||||
import { useMediaQuery } from "@/hooks/use-media-query";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useMenuHoverConfig } from "@/hooks/use-menu-hover";
|
||||
import { getInfoProfile } from "@/service/auth";
|
||||
import { getUserRolePlacements, saveUserRolePlacements } from "@/service/management-user/management-user";
|
||||
|
||||
// var groups = [
|
||||
// {
|
||||
// label: "Wilayah Tugas",
|
||||
// teams: [],
|
||||
// },
|
||||
// ]
|
||||
|
||||
// type Team = (typeof groups)[number]["teams"][number]
|
||||
|
||||
type PopoverTriggerProps = React.ComponentPropsWithoutRef<typeof PopoverTrigger>
|
||||
|
||||
interface TeamSwitcherProps extends PopoverTriggerProps { }
|
||||
|
||||
const scaleVariants = {
|
||||
collapsed: { scale: 0.8 },
|
||||
expanded: { scale: 1 }
|
||||
};
|
||||
|
||||
export default function TeamWorkspaceSwitcher({ className }: TeamSwitcherProps) {
|
||||
const [config] = useConfig();
|
||||
const [hoverConfig] = useMenuHoverConfig();
|
||||
const { hovered } = hoverConfig;
|
||||
const [detail, setDetail] = React.useState<any>();
|
||||
const userId = getCookiesDecrypt("uie");
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [showNewTeamDialog, setShowNewTeamDialog] = React.useState(false);
|
||||
const [groups, setGroups] = React.useState<any>()
|
||||
const [selectedTeam, setSelectedTeam] = React.useState<any>({ label: "", value: "" });
|
||||
const isDesktop = useMediaQuery("(min-width: 1280px)")
|
||||
if (config.showSwitcher === false || config.sidebar === 'compact') return null
|
||||
|
||||
React.useEffect(() => {
|
||||
async function initState() {
|
||||
const response = await getInfoProfile();
|
||||
const details = response?.data?.data;
|
||||
|
||||
setDetail(details);
|
||||
console.log("data", details);
|
||||
}
|
||||
|
||||
async function getPlacement() {
|
||||
const response = await getUserRolePlacements(Number(userId));
|
||||
const data = response?.data?.data;
|
||||
|
||||
var placementArr: any[] = [];
|
||||
data?.forEach((row: any) => {
|
||||
placementArr.push({
|
||||
label: row.roleName + " | " + row.userLevelName,
|
||||
value: Number(row.id),
|
||||
});
|
||||
});
|
||||
const groupsTemp = [
|
||||
{
|
||||
label: "Wilayah Tugas",
|
||||
teams: placementArr,
|
||||
}
|
||||
];
|
||||
setGroups(groupsTemp);
|
||||
}
|
||||
|
||||
initState();
|
||||
getPlacement();
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<Dialog open={showNewTeamDialog} onOpenChange={setShowNewTeamDialog}>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
|
||||
|
||||
<PopoverTrigger asChild>
|
||||
|
||||
|
||||
|
||||
<motion.div
|
||||
key={(config.collapsed && !hovered) ? "collapsed" : "expanded"}
|
||||
initial={{ scale: 0.9 }}
|
||||
animate={{ scale: 1 }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
||||
|
||||
|
||||
>
|
||||
{(config.collapsed && !hovered) ? <Button
|
||||
variant="outline"
|
||||
color="secondary"
|
||||
role="combobox"
|
||||
fullWidth
|
||||
aria-expanded={open}
|
||||
aria-label="Select a team"
|
||||
className={cn(" h-14 w-14 mx-auto p-0 md:p-0 dark:border-secondary ring-offset-sidebar", className)}
|
||||
>
|
||||
<Avatar className="">
|
||||
<AvatarImage
|
||||
height={24}
|
||||
width={24}
|
||||
// src={session?.user?.image as any}
|
||||
alt={selectedTeam.label}
|
||||
className="grayscale"
|
||||
/>
|
||||
|
||||
<AvatarFallback>{detail?.username}</AvatarFallback>
|
||||
</Avatar>
|
||||
</Button> : <Button
|
||||
variant="outline"
|
||||
color="secondary"
|
||||
role="combobox"
|
||||
fullWidth
|
||||
aria-expanded={open}
|
||||
aria-label="Select a team"
|
||||
className={cn(" h-auto py-3 md:px-3 px-3 justify-start dark:border-secondary ring-offset-sidebar", className)}
|
||||
>
|
||||
<div className=" flex gap-2 flex-1 items-center">
|
||||
<Avatar className=" flex-none h-[38px] w-[38px]">
|
||||
{/* <AvatarImage
|
||||
height={38}
|
||||
width={38}
|
||||
// src={session?.user?.image as any}
|
||||
alt={selectedTeam.label}
|
||||
className="grayscale"
|
||||
/> */}
|
||||
|
||||
<AvatarFallback><p className="text-md uppercase">{detail?.username[0]}</p></AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex-1 text-start w-[100px]">
|
||||
|
||||
<div className=" text-sm font-semibold text-default-900">{detail?.username}</div>
|
||||
<div className=" text-xs font-normal text-default-500 dark:text-default-700 truncate ">{selectedTeam.label}</div>
|
||||
|
||||
</div>
|
||||
<div className="">
|
||||
<ChevronsUpDown className="ml-auto h-5 w-5 shrink-0 text-default-500 dark:text-default-700" />
|
||||
</div>
|
||||
</div>
|
||||
</Button>}
|
||||
</motion.div>
|
||||
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] p-0">
|
||||
<Command>
|
||||
<CommandList>
|
||||
<CommandInput placeholder="Search team..." className=" placeholder:text-xs" />
|
||||
<CommandEmpty>No team found.</CommandEmpty>
|
||||
{groups?.map((group: any) => (
|
||||
<CommandGroup key={group.label} heading={group.label}>
|
||||
{group.teams.map((team: any) => (
|
||||
<CommandItem
|
||||
key={team.value}
|
||||
onSelect={() => {
|
||||
setSelectedTeam(team)
|
||||
setOpen(false)
|
||||
}}
|
||||
className="text-sm font-normal"
|
||||
>
|
||||
|
||||
{team.label}
|
||||
<Check
|
||||
className={cn(
|
||||
"ml-auto h-4 w-4",
|
||||
selectedTeam.value === team.value
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
/>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
))}
|
||||
</CommandList>
|
||||
{/* <CommandSeparator /> */}
|
||||
{/* <CommandList>
|
||||
<CommandGroup>
|
||||
<DialogTrigger asChild>
|
||||
<CommandItem
|
||||
onSelect={() => {
|
||||
setOpen(false)
|
||||
setShowNewTeamDialog(true)
|
||||
}}
|
||||
>
|
||||
<CirclePlus className="mr-2 h-5 w-5" />
|
||||
Create Team
|
||||
</CommandItem>
|
||||
</DialogTrigger>
|
||||
</CommandGroup>
|
||||
</CommandList> */}
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create team</DialogTitle>
|
||||
<DialogDescription>
|
||||
Add a new team to manage products and customers.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div>
|
||||
<div className="space-y-4 py-2 pb-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="name">Team name</Label>
|
||||
<Input id="name" placeholder="Acme Inc." />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="plan">Subscription plan</Label>
|
||||
<Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a plan" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="free">
|
||||
<span className="font-medium">Free</span> -{" "}
|
||||
<span className="text-muted-foreground">
|
||||
Trial for two weeks
|
||||
</span>
|
||||
</SelectItem>
|
||||
<SelectItem value="pro">
|
||||
<span className="font-medium">Pro</span> -{" "}
|
||||
<span className="text-muted-foreground">
|
||||
$9/month per user
|
||||
</span>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setShowNewTeamDialog(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit">Continue</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
import React from 'react'
|
||||
import { Ellipsis, LogOut } from "lucide-react";
|
||||
import { usePathname } from "@/components/navigation";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { cn, getCookiesDecrypt } from "@/lib/utils";
|
||||
import { getMenuList } from "@/lib/menus";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import {
|
||||
|
|
@ -26,6 +26,7 @@ import Logo from '@/components/logo';
|
|||
import SidebarHoverToggle from '@/components/partials/sidebar/sidebar-hover-toggle';
|
||||
import { useMenuHoverConfig } from '@/hooks/use-menu-hover';
|
||||
import { useMediaQuery } from '@/hooks/use-media-query';
|
||||
import TeamWorkspaceSwitcher from '../common/team-workspace-switcher';
|
||||
|
||||
|
||||
export function MenuClassic({ }) {
|
||||
|
|
@ -36,7 +37,7 @@ export function MenuClassic({ }) {
|
|||
const direction = getLangDir(params?.locale ?? '');
|
||||
|
||||
const isDesktop = useMediaQuery('(min-width: 1280px)')
|
||||
|
||||
const userRoleId = getCookiesDecrypt("urie");
|
||||
|
||||
const menuList = getMenuList(pathname, t);
|
||||
const [config, setConfig] = useConfig()
|
||||
|
|
@ -71,17 +72,16 @@ export function MenuClassic({ }) {
|
|||
|
||||
|
||||
<ScrollArea className="[&>div>div[style]]:!block" dir={direction}>
|
||||
{/* {isDesktop && (
|
||||
{isDesktop && Number(userRoleId) == 19 ? (
|
||||
<div className={cn(' space-y-3 mt-6 ', {
|
||||
'px-4': !collapsed || hovered,
|
||||
'text-center': collapsed || !hovered
|
||||
})}>
|
||||
|
||||
<TeamSwitcher />
|
||||
<SearchBar />
|
||||
<TeamWorkspaceSwitcher />
|
||||
{/* <SearchBar /> */}
|
||||
</div>
|
||||
|
||||
)} */}
|
||||
) : ""}
|
||||
|
||||
<nav className="mt-4 h-full w-full">
|
||||
<ul className=" h-full flex flex-col min-h-[calc(100vh-48px-36px-16px-32px)] lg:min-h-[calc(100vh-32px-40px-32px)] items-start space-y-1 px-4">
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export default function PerformancePoldaViz() {
|
|||
? isInternational[0]
|
||||
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-konten-top10?"
|
||||
: "views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-ranking-polda?"
|
||||
: `/views/2023_09_db-ranking-polres-by-polda_rev100/db-ranking-by-polda?`;
|
||||
: `/views/2023_09_db-ranking-polres-by-polda_rev100/db-ranking-by-polda?polda-selected=${provState}&`;
|
||||
|
||||
const view2 =
|
||||
levelName == "MABES POLRI"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
"use client";
|
||||
import Cookies from "js-cookie";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getCookiesDecrypt } from "@/lib/utils";
|
||||
import { generateTicket } from "@/service/tableau/tableau-service";
|
||||
import { Button } from "../ui/button";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export default function PerformanceSatkerViz() {
|
||||
const [hasMounted, setHasMounted] = useState(false);
|
||||
const t = useTranslations("AnalyticsDashboard");
|
||||
const levelName = getCookiesDecrypt("ulnae");
|
||||
const poldaState = Cookies.get("state");
|
||||
const provState = Cookies.get("state-prov");
|
||||
|
||||
const [ticket1, setTicket1] = useState("");
|
||||
const [ticket2, setTicket2] = useState("");
|
||||
const [ticket3, setTicket3] = useState("");
|
||||
const [ticket4, setTicket4] = useState("");
|
||||
const [isInternational, setIsInternational] = useState([false, false, false]);
|
||||
|
||||
const baseUrl = "https://db-mediahub.polri.go.id/";
|
||||
const url = "https://db-mediahub.polri.go.id/trusted/";
|
||||
|
||||
const view1 =
|
||||
levelName == "MABES POLRI"
|
||||
? isInternational[0]
|
||||
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-konten-top10?"
|
||||
: "views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-konten-top10?"
|
||||
: `/views/2023_09_db-ranking-polres-by-polda_rev100/db-ranking-by-polda?polda-selected=${provState}&`;
|
||||
|
||||
const param = ":embed=yes&:toolbar=yes&:iframeSizedToWindow=true";
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
const response1 = await generateTicket();
|
||||
setTicket1(response1?.data?.data);
|
||||
}
|
||||
|
||||
initState();
|
||||
}, [isInternational]);
|
||||
|
||||
// Hooks
|
||||
useEffect(() => {
|
||||
setHasMounted(true);
|
||||
}, []);
|
||||
|
||||
// Render
|
||||
if (!hasMounted) return null;
|
||||
|
||||
const handleInternational = (index: number, val: boolean) => {
|
||||
const updatedIsInternational = [...isInternational];
|
||||
|
||||
updatedIsInternational[index] = val;
|
||||
setIsInternational(updatedIsInternational);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2 bg-white rounded-lg p-3">
|
||||
<p className="text-lg">
|
||||
<b>
|
||||
{isInternational[0] ? "SATKER PERFORMANCE" : "POLFORMANCE SATKER"}
|
||||
</b>
|
||||
</p>
|
||||
<div className="my-5">
|
||||
{ticket1 == "" ? (
|
||||
<iframe
|
||||
src={`${baseUrl + view1 + param}`}
|
||||
width="100%"
|
||||
height="750"
|
||||
frameBorder="0"
|
||||
/>
|
||||
) : (
|
||||
<iframe
|
||||
src={`${`${url + ticket1}/${view1}${param}`}`}
|
||||
width="100%"
|
||||
height="750"
|
||||
frameBorder="0"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import { Router } from "next/router";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
|
||||
|
|
@ -29,7 +30,7 @@ export function error(msg: string): void {
|
|||
});
|
||||
}
|
||||
|
||||
export function success(redirect: string): void {
|
||||
export function success(router: Router, redirect: string): void {
|
||||
MySwal.fire({
|
||||
title: '<p class="text-green-600 font-bold">Sukses</p>',
|
||||
icon: "success",
|
||||
|
|
@ -38,7 +39,7 @@ export function success(redirect: string): void {
|
|||
allowOutsideClick: false,
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = redirect;
|
||||
router.push(redirect);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
439
lib/menus.ts
439
lib/menus.ts
|
|
@ -260,6 +260,70 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "settings",
|
||||
menus: [
|
||||
{
|
||||
id: "settings",
|
||||
href: "/admin/settings",
|
||||
label: t("settings"),
|
||||
active: pathname.includes("/settinng"),
|
||||
icon: "material-symbols:settings",
|
||||
submenus: [
|
||||
{
|
||||
href: "/admin/settings/category",
|
||||
label: t("category"),
|
||||
active: pathname === "/admin/settings/category",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/tag",
|
||||
label: "Tag",
|
||||
active: pathname === "/admin/settings/tag",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/banner",
|
||||
label: "Banner",
|
||||
active: pathname === "/admin/settings/banner",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/feedback",
|
||||
label: "Feedback",
|
||||
active: pathname === "/admin/settings/feedback",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/faq",
|
||||
label: "FAQ",
|
||||
active: pathname === "/admin/settings/faq",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "https://nat-mediahub.polri.go.id/",
|
||||
label: "Mediahub 2022",
|
||||
active: pathname === "/admin/settings/mediahub-2022",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/privacy",
|
||||
label: t("privacy"),
|
||||
active: pathname === "/admin/settings/privacy",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
// ===== MENU TEMPLATE DASHCODE =====
|
||||
// {
|
||||
// groupLabel: t("apps"),
|
||||
|
|
@ -1527,21 +1591,21 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
submenus: [
|
||||
{
|
||||
href: "/contributor/schedule/press-conference",
|
||||
label: "konferensi pers",
|
||||
label: t("press-conference"),
|
||||
active: pathname.includes("/schedule/press-conference"),
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/event",
|
||||
label: "event",
|
||||
label: t("event"),
|
||||
active: pathname.includes("/schedule/event"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/press-release",
|
||||
label: "pers rilis",
|
||||
label: t("press-release"),
|
||||
active: pathname.includes("/schedule/press-release"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
|
|
@ -1725,21 +1789,21 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
submenus: [
|
||||
{
|
||||
href: "/contributor/schedule/press-conference",
|
||||
label: "konferensi pers",
|
||||
label: t("press-conference"),
|
||||
active: pathname.includes("/schedule/press-conference"),
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/event",
|
||||
label: "event",
|
||||
label: t("event"),
|
||||
active: pathname.includes("/schedule/event"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/press-release",
|
||||
label: "pers rilis",
|
||||
label: t("press-release"),
|
||||
active: pathname.includes("/schedule/press-release"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
|
|
@ -1790,6 +1854,70 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "settings",
|
||||
menus: [
|
||||
{
|
||||
id: "settings",
|
||||
href: "/admin/settings",
|
||||
label: t("settings"),
|
||||
active: pathname.includes("/settinng"),
|
||||
icon: "material-symbols:settings",
|
||||
submenus: [
|
||||
{
|
||||
href: "/admin/settings/category",
|
||||
label: t("category"),
|
||||
active: pathname === "/admin/settings/category",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/tag",
|
||||
label: "Tag",
|
||||
active: pathname === "/admin/settings/tag",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/banner",
|
||||
label: "Banner",
|
||||
active: pathname === "/admin/settings/banner",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/feedback",
|
||||
label: "Feedback",
|
||||
active: pathname === "/admin/settings/feedback",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/faq",
|
||||
label: "FAQ",
|
||||
active: pathname === "/admin/settings/faq",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "https://nat-mediahub.polri.go.id/",
|
||||
label: "Mediahub 2022",
|
||||
active: pathname === "/admin/settings/mediahub-2022",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/privacy",
|
||||
label: t("privacy"),
|
||||
active: pathname === "/admin/settings/privacy",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
} else if (Number(userLevelId) == 761) {
|
||||
menusSelected = [
|
||||
|
|
@ -1891,7 +2019,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
submenus: [
|
||||
{
|
||||
href: "/contributor/schedule/press-conference",
|
||||
label: "konferensi pers",
|
||||
label: t("press-conference"),
|
||||
active: pathname.includes("/schedule/press-conference"),
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
|
|
@ -1905,7 +2033,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
},
|
||||
{
|
||||
href: "/contributor/schedule/press-release",
|
||||
label: "pers rilis",
|
||||
label: t("press-release"),
|
||||
active: pathname.includes("/schedule/press-release"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
|
|
@ -2105,21 +2233,21 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
submenus: [
|
||||
{
|
||||
href: "/contributor/schedule/press-conference",
|
||||
label: "konferensi pers",
|
||||
label: t("press-conference"),
|
||||
active: pathname.includes("/schedule/press-conference"),
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/event",
|
||||
label: "event",
|
||||
label: t("event"),
|
||||
active: pathname.includes("/schedule/event"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/press-release",
|
||||
label: "pers rilis",
|
||||
label: t("press-release"),
|
||||
active: pathname.includes("/schedule/press-release"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
|
|
@ -2314,21 +2442,21 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
submenus: [
|
||||
{
|
||||
href: "/contributor/schedule/press-conference",
|
||||
label: "konferensi pers",
|
||||
label: t("press-conference"),
|
||||
active: pathname.includes("/schedule/press-conference"),
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/event",
|
||||
label: "event",
|
||||
label: t("event"),
|
||||
active: pathname.includes("/schedule/event"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/schedule/press-release",
|
||||
label: "pers rilis",
|
||||
label: t("press-release"),
|
||||
active: pathname.includes("/schedule/press-release"),
|
||||
icon: "heroicons:shopping-cart",
|
||||
children: [],
|
||||
|
|
@ -2533,7 +2661,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
],
|
||||
},
|
||||
];
|
||||
} else if (Number(roleId) == 11) {
|
||||
} else if (Number(roleId) == 11 || Number(roleId) == 19) {
|
||||
menusSelected = [
|
||||
{
|
||||
groupLabel: t("apps"),
|
||||
|
|
@ -2706,16 +2834,16 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
icon: "material-symbols:dashboard",
|
||||
submenus: [
|
||||
{
|
||||
href: "/dashboard",
|
||||
label: "Breakdown",
|
||||
active: pathname === "/dashboard",
|
||||
href: "/dashboard/executive",
|
||||
label: "Executive",
|
||||
active: pathname === "/dashboard/executive",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/dashboard/executive",
|
||||
label: "Executive",
|
||||
active: pathname === "/dashboard/executive",
|
||||
href: "/dashboard",
|
||||
label: "Breakdown",
|
||||
active: pathname === "/dashboard",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
|
|
@ -2723,20 +2851,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "agenda-setting",
|
||||
menus: [
|
||||
{
|
||||
id: "agenda-setting",
|
||||
href: "/contributor/agenda-setting",
|
||||
label: t("agenda-setting"),
|
||||
active: pathname.includes("/agenda-setting"),
|
||||
icon: "iconoir:journal-page",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// groupLabel: "",
|
||||
// id: "agenda-setting",
|
||||
// menus: [
|
||||
// {
|
||||
// id: "agenda-setting",
|
||||
// href: "/contributor/agenda-setting",
|
||||
// label: t("agenda-setting"),
|
||||
// active: pathname.includes("/agenda-setting"),
|
||||
// icon: "iconoir:journal-page",
|
||||
// submenus: [],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "management-user",
|
||||
|
|
@ -3015,16 +3143,16 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
icon: "material-symbols:dashboard",
|
||||
submenus: [
|
||||
{
|
||||
href: "/dashboard",
|
||||
label: "Breakdown",
|
||||
active: pathname === "/dashboard",
|
||||
href: "/dashboard/executive",
|
||||
label: "Executive",
|
||||
active: pathname === "/dashboard/executive",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/dashboard/executive",
|
||||
label: "Executive",
|
||||
active: pathname === "/dashboard/executive",
|
||||
href: "/dashboard",
|
||||
label: "Breakdown",
|
||||
active: pathname === "/dashboard",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
|
|
@ -3074,20 +3202,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "agenda-setting",
|
||||
menus: [
|
||||
{
|
||||
id: "agenda-setting",
|
||||
href: "/contributor/agenda-setting",
|
||||
label: t("agenda-setting"),
|
||||
active: pathname.includes("/agenda-setting"),
|
||||
icon: "iconoir:journal-page",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// groupLabel: "",
|
||||
// id: "agenda-setting",
|
||||
// menus: [
|
||||
// {
|
||||
// id: "agenda-setting",
|
||||
// href: "/contributor/agenda-setting",
|
||||
// label: t("agenda-setting"),
|
||||
// active: pathname.includes("/agenda-setting"),
|
||||
// icon: "iconoir:journal-page",
|
||||
// submenus: [],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "performance-polres",
|
||||
|
|
@ -3159,35 +3287,70 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// groupLabel: "",
|
||||
// id: "settings",
|
||||
// menus: [
|
||||
// {
|
||||
// id: "settings",
|
||||
// href: "/admin/settings",
|
||||
// label: t("settings"),
|
||||
// active: pathname.includes("/settinng"),
|
||||
// icon: "material-symbols:settings",
|
||||
// submenus: [
|
||||
// {
|
||||
// href: "/admin/settings/category",
|
||||
// label: t("category"),
|
||||
// active: pathname === "/admin/settings/category",
|
||||
// icon: "heroicons:arrow-trending-up",
|
||||
// children: [],
|
||||
// },
|
||||
// {
|
||||
// href: "/admin/settings/tag",
|
||||
// label: "Tag",
|
||||
// active: pathname === "/admin/settings/tag",
|
||||
// icon: "heroicons:arrow-trending-up",
|
||||
// children: [],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "settings",
|
||||
menus: [
|
||||
{
|
||||
id: "settings",
|
||||
href: "/admin/settings",
|
||||
label: t("settings"),
|
||||
active: pathname.includes("/settinng"),
|
||||
icon: "material-symbols:settings",
|
||||
submenus: [
|
||||
{
|
||||
href: "/admin/settings/category",
|
||||
label: t("category"),
|
||||
active: pathname === "/admin/settings/category",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/tag",
|
||||
label: "Tag",
|
||||
active: pathname === "/admin/settings/tag",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/banner",
|
||||
label: "Banner",
|
||||
active: pathname === "/admin/settings/banner",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/feedback",
|
||||
label: "Feedback",
|
||||
active: pathname === "/admin/settings/feedback",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/faq",
|
||||
label: "FAQ",
|
||||
active: pathname === "/admin/settings/faq",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "https://nat-mediahub.polri.go.id/",
|
||||
label: "Mediahub 2022",
|
||||
active: pathname === "/admin/settings/mediahub-2022",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/privacy",
|
||||
label: t("privacy"),
|
||||
active: pathname === "/admin/settings/privacy",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
} else {
|
||||
menusSelected = [
|
||||
|
|
@ -3201,11 +3364,39 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
label: t("dashboard"),
|
||||
active: pathname.includes("/dashboard"),
|
||||
icon: "material-symbols:dashboard",
|
||||
submenus: [
|
||||
{
|
||||
href: "/dashboard/executive",
|
||||
label: "Executive",
|
||||
active: pathname === "/dashboard/executive",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/dashboard",
|
||||
label: "Breakdown",
|
||||
active: pathname === "/dashboard",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "management-user",
|
||||
menus: [
|
||||
{
|
||||
id: "management-user-menu",
|
||||
href: "/admin/management-user",
|
||||
label: "Management User",
|
||||
active: pathname.includes("/management-user"),
|
||||
icon: "clarity:users-solid",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "content-production",
|
||||
|
|
@ -3234,6 +3425,49 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "performance-polres",
|
||||
menus: [
|
||||
{
|
||||
id: "performance-polres",
|
||||
href: "/admin/performance-satker",
|
||||
label: t("performance-satker"),
|
||||
active: pathname.includes("/admin/performance-satker"),
|
||||
icon: "ant-design:signal-filled",
|
||||
submenus: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "media-tracking",
|
||||
menus: [
|
||||
{
|
||||
id: "media-tracking",
|
||||
href: "/curator/media-tracking",
|
||||
label: t("media-tracking"),
|
||||
active: pathname.includes("/media-tracking"),
|
||||
icon: "material-symbols:map-search-outline",
|
||||
submenus: [
|
||||
{
|
||||
href: "/admin/media-tracking/media-online",
|
||||
label: "Media Online",
|
||||
active: pathname === "/media-tracking/media-online",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/media-tracking/tb-news",
|
||||
label: "Tracking Beritra Hari Ini",
|
||||
active: pathname === "/media-tracking/news",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupLabel: "",
|
||||
id: "communication",
|
||||
|
|
@ -3273,6 +3507,41 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/banner",
|
||||
label: "Banner",
|
||||
active: pathname === "/admin/settings/banner",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/feedback",
|
||||
label: "Feedback",
|
||||
active: pathname === "/admin/settings/feedback",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/faq",
|
||||
label: "FAQ",
|
||||
active: pathname === "/admin/settings/faq",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "https://nat-mediahub.polri.go.id/",
|
||||
label: "Mediahub 2022",
|
||||
active: pathname === "/admin/settings/mediahub-2022",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/admin/settings/privacy",
|
||||
label: t("privacy"),
|
||||
active: pathname === "/admin/settings/privacy",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -325,10 +325,15 @@
|
|||
"colors": "Colors",
|
||||
"performance-polda": "Performance Polda",
|
||||
"performance-polres": "Performance Polres",
|
||||
"performance-satker": "Performance Satker",
|
||||
"analysis": "Analysis",
|
||||
"management-content": "Content Management ",
|
||||
"add-experts": "Add Experts",
|
||||
"category": "Category",
|
||||
"add-category": "Add Category",
|
||||
"tags": "Tags",
|
||||
"add-tags": "Add Tags",
|
||||
"add": "Add",
|
||||
"privacy": "Privacy Policy"
|
||||
},
|
||||
"Changelog": {
|
||||
|
|
@ -580,7 +585,8 @@
|
|||
"schedule": "Schedule",
|
||||
"press-conference": "Press Conference",
|
||||
"press-release": "Press Release",
|
||||
"create-schedule": "Create Schedule"
|
||||
"create-schedule": "Create Schedule",
|
||||
"event": "event"
|
||||
},
|
||||
"Blog": {
|
||||
"table": "Table",
|
||||
|
|
@ -599,5 +605,37 @@
|
|||
"table": "Table",
|
||||
"contest": "Lomba",
|
||||
"create-contest": "Create Contest"
|
||||
},
|
||||
"Curation": {
|
||||
"content-curation": "Content Curation"
|
||||
},
|
||||
"Table": {
|
||||
"no": "No",
|
||||
"title": "Title",
|
||||
"category-name": "Category Name",
|
||||
"upload-date": "Upload Date",
|
||||
"creator-group": "Creator Group",
|
||||
"source": "source",
|
||||
"published": "Published",
|
||||
"date": "Date",
|
||||
"category": "Category",
|
||||
"tag": "Tag",
|
||||
"type-content": "Content Type",
|
||||
"type-task": "Task Type",
|
||||
"category-task": "Category Task",
|
||||
"code": "Code",
|
||||
"start-date": "Start Date",
|
||||
"end-date": "End Date",
|
||||
"speaker": "Speaker",
|
||||
"time": "Time",
|
||||
"address": "Address",
|
||||
"question": "Question",
|
||||
"sender": "Created By",
|
||||
"sendto": "SendTo",
|
||||
"type": "Type",
|
||||
"duration": "Duration",
|
||||
"target-output": "Target Output",
|
||||
"target-participant": "Target Participant",
|
||||
"action": "Actions"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -326,10 +326,15 @@
|
|||
"colors": "Colors",
|
||||
"performance-polda": "Performa Polda",
|
||||
"performance-polres": "Performa Polres",
|
||||
"performance-satker": "Performa Satker",
|
||||
"analysis": "Analisa",
|
||||
"management-content": "Manajemen Konten",
|
||||
"add-experts": "Tambah Tenaga Ahli",
|
||||
"category": "Kategori",
|
||||
"add-category": "Tambah Kategori",
|
||||
"tags": "Tag",
|
||||
"add-tags": "Tambah Tag",
|
||||
"add": "Tambah",
|
||||
"privacy": "Kebijakan Privacy"
|
||||
},
|
||||
"Changelog": {
|
||||
|
|
@ -581,7 +586,8 @@
|
|||
"schedule": "Jadwal",
|
||||
"press-conference": "Konferensi Pers",
|
||||
"press-release": "Pers Rilis",
|
||||
"create-schedule": "Buat Jadwal"
|
||||
"create-schedule": "Buat Jadwal",
|
||||
"event": "event"
|
||||
},
|
||||
"Blog": {
|
||||
"table": "Tabel",
|
||||
|
|
@ -600,5 +606,37 @@
|
|||
"table": "Tabel",
|
||||
"contest": "Lomba",
|
||||
"create-contest": "Buat Lomba"
|
||||
},
|
||||
"Curation": {
|
||||
"content-curation": "Kurasi Konten"
|
||||
},
|
||||
"Table": {
|
||||
"no": "Nomor",
|
||||
"title": "Judul",
|
||||
"category-name": "Nama Kategori",
|
||||
"upload-date": "Tanggal Upload",
|
||||
"creator-group": "Pembuat",
|
||||
"source": "Sumber",
|
||||
"published": "Diterbitkan",
|
||||
"date": "Tanggal",
|
||||
"category": "Kategori",
|
||||
"tag": "Tag",
|
||||
"type-content": "Tipe Konten",
|
||||
"type-task": "Tipen Penugasan",
|
||||
"category-task": "Kategori Penugasan",
|
||||
"code": "Kode",
|
||||
"start-date": "Tanggal Mulai",
|
||||
"end-date": "Tanggal Selesai",
|
||||
"speaker": "Disampaikan Oleh",
|
||||
"time": "Waktu",
|
||||
"address": "Alamat",
|
||||
"question": "Pertanyaan",
|
||||
"sender": "Pengirim",
|
||||
"sendto": "Penerima",
|
||||
"type": "Tipe",
|
||||
"duration": "Durasi",
|
||||
"target-output": "Target Output",
|
||||
"target-participant": "Target Peserta",
|
||||
"action": "Aksi"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 828 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
|
|
@ -129,10 +129,11 @@ export async function listSPIT(
|
|||
page: any,
|
||||
limit: any,
|
||||
title = "",
|
||||
contentCreatedDate = "",
|
||||
isPublish: any
|
||||
) {
|
||||
return await httpGetInterceptor(
|
||||
`media/spit/pagination?enablePage=1&page=${page}&size=${limit}&sort=desc&sortBy=contentTitleId&title=${title}&isPublish=${isPublish}`
|
||||
`media/spit/pagination?enablePage=1&page=${page}&size=${limit}&sort=desc&sortBy=contentTitleId&title=${title}& contentCreatedDate=${contentCreatedDate}&isPublish=${isPublish}`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +155,7 @@ export async function listEnableCategory(type: any) {
|
|||
}
|
||||
|
||||
export async function listCategory(type: any) {
|
||||
const url = `media/categories/list/publish?enablePage=0&sort=desc&sortBy=id&categoryId=${type}`;
|
||||
const url = `media/categories/list?enablePage=0&sort=desc&sortBy=id&categoryId=${type}`;
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
import {
|
||||
httpDeleteInterceptor,
|
||||
httpGetInterceptor,
|
||||
httpPostInterceptor,
|
||||
} from "../http-config/http-interceptor-service";
|
||||
|
||||
export async function listDataExperts(size: number, page: number) {
|
||||
return await httpGetInterceptor(
|
||||
`users/pagination/internal?enablePage=1&size=${size}&page=${page}&roleId=19&levelId=1`
|
||||
);
|
||||
}
|
||||
|
||||
export async function postBlog(data: any) {
|
||||
const url = "blog";
|
||||
return httpPostInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function getBlog(id: any) {
|
||||
const url = `blog/${id}`;
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import axios from "axios";
|
||||
|
||||
const baseURL = "https://mediahub.polri.go.id/api/";
|
||||
|
||||
const axiosBaseProdInstance = axios.create({
|
||||
baseURL,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
withCredentials: false,
|
||||
});
|
||||
|
||||
export default axiosBaseProdInstance;
|
||||
|
|
@ -17,7 +17,6 @@ const axiosInterceptorInstance = axios.create({
|
|||
// Request interceptor
|
||||
axiosInterceptorInstance.interceptors.request.use(
|
||||
(config) => {
|
||||
console.log("Config interceptor : ", config);
|
||||
const accessToken = Cookies.get("access_token");
|
||||
if (accessToken) {
|
||||
if (config.headers)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,171 @@
|
|||
import { useRouter } from "next/navigation";
|
||||
import Cookies from "js-cookie";
|
||||
import { getCsrfToken } from "../auth";
|
||||
import axiosBaseProdInstance from "./axios-base-prod-instance";
|
||||
|
||||
export async function httpGetInterceptor(pathUrl: any) {
|
||||
const pathname = window.location.pathname;
|
||||
const response = await axiosBaseProdInstance
|
||||
.get(pathUrl)
|
||||
.catch((error) => error.response);
|
||||
console.log("Response interceptor : ", response);
|
||||
if (response?.status == 200 || response?.status == 201) {
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
} else if (response?.status == 401) {
|
||||
Object.keys(Cookies.get()).forEach((cookieName) => {
|
||||
Cookies.remove(cookieName);
|
||||
});
|
||||
if (
|
||||
pathname?.includes("/contributor/") ||
|
||||
pathname?.includes("/admin/") ||
|
||||
pathname?.includes("/supervisor/")
|
||||
) {
|
||||
window.location.href = "/";
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message || response?.data || null,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function httpPostInterceptor(
|
||||
pathUrl: any,
|
||||
data?: any,
|
||||
headers?: any
|
||||
) {
|
||||
const resCsrf = await getCsrfToken();
|
||||
|
||||
const defaultHeaders = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
const mergedHeaders = {
|
||||
...defaultHeaders,
|
||||
...headers,
|
||||
};
|
||||
|
||||
const response = await axiosBaseProdInstance
|
||||
.post(pathUrl, data, { headers: mergedHeaders })
|
||||
.catch((error) => error.response);
|
||||
console.log("Response interceptor : ", response);
|
||||
if (response?.status == 200 || response?.status == 201) {
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
} else if (response?.status == 401) {
|
||||
Object.keys(Cookies.get()).forEach((cookieName) => {
|
||||
Cookies.remove(cookieName);
|
||||
});
|
||||
window.location.href = "/";
|
||||
} else {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message || response?.data || null,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function httpPutInterceptor(
|
||||
pathUrl: any,
|
||||
data: any,
|
||||
headers?: any
|
||||
) {
|
||||
const resCsrf = await getCsrfToken();
|
||||
const csrfToken = resCsrf?.data?.token;
|
||||
|
||||
const defaultHeaders = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
const mergedHeaders = {
|
||||
...defaultHeaders,
|
||||
...headers,
|
||||
};
|
||||
|
||||
const response = await axiosBaseProdInstance
|
||||
.put(pathUrl, data, { headers: mergedHeaders })
|
||||
.catch((error) => error.response);
|
||||
console.log("Response interceptor : ", response);
|
||||
if (response?.status == 200 || response?.status == 201) {
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
} else if (response?.status == 401) {
|
||||
Object.keys(Cookies.get()).forEach((cookieName) => {
|
||||
Cookies.remove(cookieName);
|
||||
});
|
||||
window.location.href = "/";
|
||||
} else {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message || response?.data || null,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function httpDeleteInterceptor(pathUrl: any, data?: any) {
|
||||
const resCsrf = await getCsrfToken();
|
||||
const csrfToken = resCsrf?.data?.token;
|
||||
|
||||
const defaultHeaders = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
const mergedHeaders = {
|
||||
...defaultHeaders,
|
||||
...(csrfToken ? { "X-XSRF-TOKEN": csrfToken } : {}),
|
||||
};
|
||||
|
||||
const response = await axiosBaseProdInstance
|
||||
.delete(pathUrl, { headers: mergedHeaders, data })
|
||||
.catch((error) => error.response);
|
||||
console.log("Response interceptor : ", response);
|
||||
if (response?.status == 200 || response?.status == 201) {
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
} else if (response?.status == 401) {
|
||||
Object.keys(Cookies.get()).forEach((cookieName) => {
|
||||
Cookies.remove(cookieName);
|
||||
});
|
||||
window.location.href = "/";
|
||||
} else {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message || response?.data || null,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function httpGetInterceptorWithToken(pathUrl: any, headers?: any) {
|
||||
const response = await axiosBaseProdInstance
|
||||
.get(pathUrl, headers)
|
||||
.catch((error) => error.response);
|
||||
console.log("Response interceptor : ", response);
|
||||
if (response?.status == 200 || response?.status == 201) {
|
||||
return {
|
||||
error: false,
|
||||
message: "success",
|
||||
data: response?.data,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
error: true,
|
||||
message: response?.data?.message || response?.data || null,
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -30,16 +30,32 @@ export async function getListSchools() {
|
|||
const url = "users/user-schools/list";
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getListCompetencies() {
|
||||
const url = "users/user-competencies/list";
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getListExperiences() {
|
||||
const url = "users/user-experiences/list";
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function saveUserInternal(data: any) {
|
||||
const url = "users/save";
|
||||
return httpPostInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function saveUserRolePlacements(data: any) {
|
||||
const url = "users/role-placements";
|
||||
return httpPostInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function getUserRolePlacements(userId: number) {
|
||||
const url = `users/role-placements?userId=${userId}`;
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getUserById(id: string) {
|
||||
const url = `users?id=${id}`;
|
||||
return httpGetInterceptor(url);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,15 @@ import {
|
|||
import { httpGet } from "../http-config/http-base-service";
|
||||
import { any } from "zod";
|
||||
|
||||
export async function paginationSchedule(size: number, page: number, type: any, title: string = "") {
|
||||
return await httpGetInterceptor(`schedule/pagination?enablePage=1&scheduleTypeId=${type}&page=${page}&size=${size}&title=${title}`);
|
||||
export async function paginationSchedule(
|
||||
size: number,
|
||||
page: number,
|
||||
type: any,
|
||||
title: string = ""
|
||||
) {
|
||||
return await httpGetInterceptor(
|
||||
`schedule/pagination?enablePage=1&scheduleTypeId=${type}&page=${page}&size=${size}&title=${title}`
|
||||
);
|
||||
}
|
||||
|
||||
export async function postSchedule(data: any) {
|
||||
|
|
@ -49,6 +56,11 @@ export async function listScheduleToday() {
|
|||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getListScheduleAttachment(scheduleId: any) {
|
||||
const url = `media/list?&enablePage=0&scheduleId=${scheduleId}`;
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function listScheduleNext() {
|
||||
const url = "schedule/next-activity";
|
||||
return httpGetInterceptor(url);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { httpPostInterceptor } from "../http-config/http-interceptor-service";
|
||||
import { httpPostInterceptor } from "../http-config/http-interceptor-prod-service";
|
||||
|
||||
export async function generateTicket() {
|
||||
const url = "/admin/tableau-ticket";
|
||||
|
|
|
|||
Loading…
Reference in New Issue