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",
|
header: "Nama",
|
||||||
cell: ({ row }) => <span>{row.getValue("name")}</span>,
|
cell: ({ row }) => <span>{row.getValue("fullname")}</span>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "region",
|
accessorKey: "address",
|
||||||
header: "Wilayah",
|
header: "Wilayah",
|
||||||
cell: ({ row }) => <span>{row.getValue("region")}</span>,
|
cell: ({ row }) => <span>{row.getValue("address")}</span>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "skills",
|
accessorKey: "role.name",
|
||||||
header: "Bidang Keahlian",
|
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 { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { close, loading } from "@/config/swal";
|
import { close, loading } from "@/config/swal";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
|
import { listDataExperts } from "@/service/experts/experts";
|
||||||
|
|
||||||
const dummyData = [
|
const dummyData = [
|
||||||
{
|
{
|
||||||
|
|
@ -93,6 +94,7 @@ const AddExpertTable = () => {
|
||||||
const [statusFilter, setStatusFilter] = React.useState<number[]>([]);
|
const [statusFilter, setStatusFilter] = React.useState<number[]>([]);
|
||||||
const [page, setPage] = React.useState(1);
|
const [page, setPage] = React.useState(1);
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
|
const [limit, setLimit] = React.useState(10);
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
@ -145,19 +147,44 @@ const AddExpertTable = () => {
|
||||||
});
|
});
|
||||||
}, [page, showData]);
|
}, [page, showData]);
|
||||||
|
|
||||||
async function fetchData() {
|
// async function fetchData() {
|
||||||
try {
|
// try {
|
||||||
loading();
|
// 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) => {
|
contentData.forEach((item: any, index: number) => {
|
||||||
item.no = (page - 1) * Number(showData) + index + 1;
|
item.no = (page - 1) * limit + index + 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
setDataTable(contentData);
|
setDataTable(contentData);
|
||||||
setTotalData(contentData?.length);
|
setTotalData(data?.totalElements);
|
||||||
setTotalPage(1);
|
setTotalPage(data?.totalPages);
|
||||||
close();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching tasks:", error);
|
console.error("Error fetching tasks:", error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,27 +23,30 @@ import {
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} 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({
|
const FormSchema = z.object({
|
||||||
name: z.string({
|
name: z.string({
|
||||||
required_error: "Required",
|
required_error: "Required",
|
||||||
}),
|
}),
|
||||||
|
username: z.string({
|
||||||
|
required_error: "Required",
|
||||||
|
}),
|
||||||
|
password: z.string({
|
||||||
|
required_error: "Required",
|
||||||
|
}),
|
||||||
phoneNumber: z.string({
|
phoneNumber: z.string({
|
||||||
required_error: "Required",
|
required_error: "Required",
|
||||||
}),
|
}),
|
||||||
email: z.string({
|
email: z.string({
|
||||||
required_error: "Required",
|
required_error: "Required",
|
||||||
}),
|
}),
|
||||||
position: z.string({
|
|
||||||
required_error: "Required",
|
|
||||||
}),
|
|
||||||
region: z.string({
|
|
||||||
required_error: "Required",
|
|
||||||
}),
|
|
||||||
skills: z.string({
|
skills: z.string({
|
||||||
required_error: "Required",
|
required_error: "Required",
|
||||||
}),
|
}),
|
||||||
experience: z.string({
|
experiences: z.string({
|
||||||
required_error: "Required",
|
required_error: "Required",
|
||||||
}),
|
}),
|
||||||
company: z.string({
|
company: z.string({
|
||||||
|
|
@ -51,12 +54,34 @@ const FormSchema = z.object({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type Placements = {
|
||||||
|
index: number;
|
||||||
|
roleId?: string;
|
||||||
|
userLevelId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export default function AddExpertForm() {
|
export default function AddExpertForm() {
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const form = useForm<z.infer<typeof FormSchema>>({
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
resolver: zodResolver(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>) => {
|
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
|
|
@ -77,9 +102,85 @@ export default function AddExpertForm() {
|
||||||
const save = async (data: z.infer<typeof FormSchema>) => {
|
const save = async (data: z.infer<typeof FormSchema>) => {
|
||||||
console.log("data", data);
|
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() {
|
function successSubmit() {
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Sukses",
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SiteBreadcrumb />
|
<SiteBreadcrumb />
|
||||||
|
|
@ -118,6 +242,22 @@ export default function AddExpertForm() {
|
||||||
</FormItem>
|
</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
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="phoneNumber"
|
name="phoneNumber"
|
||||||
|
|
@ -152,45 +292,16 @@ export default function AddExpertForm() {
|
||||||
/>
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="position"
|
name="password"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Posisi</FormLabel>
|
<FormLabel>Password</FormLabel>
|
||||||
<Select onValueChange={field.onChange} value={field.value}>
|
<Input
|
||||||
<FormControl>
|
type="password"
|
||||||
<SelectTrigger>
|
value={field.value}
|
||||||
<SelectValue placeholder="Pilih Region" />
|
placeholder="Masukkan Password"
|
||||||
</SelectTrigger>
|
onChange={field.onChange}
|
||||||
</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>
|
|
||||||
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
|
@ -208,19 +319,20 @@ export default function AddExpertForm() {
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="komunikasi">Komunikasi</SelectItem>
|
{userCompetencies?.map((item: any) => (
|
||||||
<SelectItem value="hukum">Hukum</SelectItem>
|
<SelectItem key={item.id} value={String(item.id)}>
|
||||||
<SelectItem value="bahasa">Bahasa</SelectItem>
|
{item.name}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="experience"
|
name="experiences"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Pengalaman</FormLabel>
|
<FormLabel>Pengalaman</FormLabel>
|
||||||
|
|
@ -231,15 +343,13 @@ export default function AddExpertForm() {
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="akademisi">Akademisi</SelectItem>
|
{userExperiences?.map((item: any) => (
|
||||||
<SelectItem value="praktisi">Praktisi</SelectItem>
|
<SelectItem key={item.id} value={String(item.id)}>
|
||||||
<SelectItem value="akademisi+praktisi">
|
{item.name}
|
||||||
Akademisi + Praktisi
|
</SelectItem>
|
||||||
</SelectItem>
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
</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">
|
<div className="flex flex-row justify-end gap-2 mt-4 pt-4">
|
||||||
<Button
|
<Button
|
||||||
size="md"
|
size="md"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export default function PerformancePolda() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SiteBreadcrumb />
|
<SiteBreadcrumb />
|
||||||
<p className="font-semibold">PERFORMANCE KUMULATIF PER POLDA</p>
|
<p className="font-semibold">PERFORMANCE KUMULATIF PER POLRES</p>
|
||||||
<PerformancePolresViz />
|
<PerformancePolresViz />
|
||||||
</div>
|
</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 />
|
<SiteBreadcrumb />
|
||||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
{selectedTab === "content"
|
{selectedTab === "content" ? "List Media" : " List Banner"}
|
||||||
? "Daftar List Media"
|
|
||||||
: "Table List Banner"}
|
|
||||||
|
|
||||||
<div className="flex flex-row gap-1 border-2 rounded-md w-fit mb-5">
|
<div className="flex flex-row gap-1 border-2 rounded-md w-fit mb-5">
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import Image from "next/image";
|
||||||
import { Upload } from "tus-js-client";
|
import { Upload } from "tus-js-client";
|
||||||
import { getCookiesDecrypt } from "@/lib/utils";
|
import { getCookiesDecrypt } from "@/lib/utils";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
title: z.string({
|
title: z.string({
|
||||||
|
|
@ -109,7 +110,7 @@ export default function CreateCategoryModal() {
|
||||||
const levelNumber = getCookiesDecrypt("ulne");
|
const levelNumber = getCookiesDecrypt("ulne");
|
||||||
const userLevelId = getCookiesDecrypt("ulie");
|
const userLevelId = getCookiesDecrypt("ulie");
|
||||||
const poldaState = Cookies.get("state");
|
const poldaState = Cookies.get("state");
|
||||||
|
const t = useTranslations("Menu");
|
||||||
const [files, setFiles] = useState<File[]>([]);
|
const [files, setFiles] = useState<File[]>([]);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [satkerData, setSatkerData] = useState<string[]>([]);
|
const [satkerData, setSatkerData] = useState<string[]>([]);
|
||||||
|
|
@ -239,12 +240,12 @@ export default function CreateCategoryModal() {
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button color="primary" size="md">
|
<Button color="primary" size="md">
|
||||||
Tambah Kategori
|
{t("add-category")}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent size="md">
|
<DialogContent size="md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Tambah Kategori</DialogTitle>
|
<DialogTitle> {t("add-category")}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,12 @@ import {
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import CreateCategoryModal from "./create";
|
import CreateCategoryModal from "./create";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const AdminCategoryTable = () => {
|
const AdminCategoryTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
const t = useTranslations("Menu");
|
||||||
const dataChange = searchParams?.get("dataChange");
|
const dataChange = searchParams?.get("dataChange");
|
||||||
const [openModal, setOpenModal] = React.useState(false);
|
const [openModal, setOpenModal] = React.useState(false);
|
||||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||||
|
|
@ -127,7 +129,7 @@ const AdminCategoryTable = () => {
|
||||||
return (
|
return (
|
||||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
<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">
|
<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 />
|
<CreateCategoryModal />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import { useDropzone } from "react-dropzone";
|
||||||
import { CloudUpload } from "lucide-react";
|
import { CloudUpload } from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { Upload } from "tus-js-client";
|
import { Upload } from "tus-js-client";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
answer: z.string({
|
answer: z.string({
|
||||||
|
|
@ -79,7 +80,7 @@ const publishToList = [
|
||||||
export default function CreateFAQModal() {
|
export default function CreateFAQModal() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const t = useTranslations("Menu");
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [satkerData, setSatkerData] = useState<string[]>([]);
|
const [satkerData, setSatkerData] = useState<string[]>([]);
|
||||||
const [unitData, setUnitData] = useState<string[]>([]);
|
const [unitData, setUnitData] = useState<string[]>([]);
|
||||||
|
|
@ -120,12 +121,12 @@ export default function CreateFAQModal() {
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button color="primary" size="md">
|
<Button color="primary" size="md">
|
||||||
Tambah FAQ
|
{t("add")} FAQ
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent size="md">
|
<DialogContent size="md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Tambah FAQ</DialogTitle>
|
<DialogTitle>{t("add")} FAQ</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import { useDropzone } from "react-dropzone";
|
||||||
import { CloudUpload } from "lucide-react";
|
import { CloudUpload } from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { Upload } from "tus-js-client";
|
import { Upload } from "tus-js-client";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
question: z.string({
|
question: z.string({
|
||||||
|
|
@ -77,7 +78,7 @@ const publishToList = [
|
||||||
export default function CreateFAQModal() {
|
export default function CreateFAQModal() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const t = useTranslations("Menu");
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof FormSchema>>({
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
|
|
@ -110,12 +111,12 @@ export default function CreateFAQModal() {
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button color="primary" size="md">
|
<Button color="primary" size="md">
|
||||||
Tambah Feedback
|
{t("add")} Feedback
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent size="md">
|
<DialogContent size="md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Tambah Feedback</DialogTitle>
|
<DialogTitle>{t("add")} Feedback</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,13 @@ import {
|
||||||
} from "@/service/settings/settings";
|
} from "@/service/settings/settings";
|
||||||
|
|
||||||
import CreateFAQModal from "./create";
|
import CreateFAQModal from "./create";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const AdminFeedbackTable = () => {
|
const AdminFeedbackTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const dataChange = searchParams?.get("dataChange");
|
const dataChange = searchParams?.get("dataChange");
|
||||||
|
|
||||||
const [openModal, setOpenModal] = React.useState(false);
|
const [openModal, setOpenModal] = React.useState(false);
|
||||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||||
const [totalData, setTotalData] = React.useState<number>(1);
|
const [totalData, setTotalData] = React.useState<number>(1);
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import {
|
||||||
CommandList,
|
CommandList,
|
||||||
} from "@/components/ui/command";
|
} from "@/components/ui/command";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
name: z.string({
|
name: z.string({
|
||||||
|
|
@ -55,6 +56,7 @@ const FormSchema = z.object({
|
||||||
export default function CreateTagModal() {
|
export default function CreateTagModal() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const t = useTranslations("Menu");
|
||||||
const [categoryList, setCategoryList] = useState<
|
const [categoryList, setCategoryList] = useState<
|
||||||
{ id: number; label: string; value: string }[]
|
{ id: number; label: string; value: string }[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
@ -107,12 +109,12 @@ export default function CreateTagModal() {
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button color="primary" size="md">
|
<Button color="primary" size="md">
|
||||||
Tambah Tag
|
{t("add-tags")}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent size="md">
|
<DialogContent size="md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Tambah Tag</DialogTitle>
|
<DialogTitle> {t("add-tags")}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,12 @@ import {
|
||||||
} from "@/service/settings/settings";
|
} from "@/service/settings/settings";
|
||||||
|
|
||||||
import CreateFAQModal from "./create";
|
import CreateFAQModal from "./create";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const AdminTagTable = () => {
|
const AdminTagTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
const t = useTranslations("Menu");
|
||||||
const dataChange = searchParams?.get("dataChange");
|
const dataChange = searchParams?.get("dataChange");
|
||||||
const [openModal, setOpenModal] = React.useState(false);
|
const [openModal, setOpenModal] = React.useState(false);
|
||||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||||
|
|
@ -124,7 +126,7 @@ const AdminTagTable = () => {
|
||||||
return (
|
return (
|
||||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
<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">
|
<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 />
|
<CreateFAQModal />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,9 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
||||||
);
|
);
|
||||||
const [selectedEventDate, setSelectedEventDate] = useState<Date | null>(null);
|
const [selectedEventDate, setSelectedEventDate] = useState<Date | null>(null);
|
||||||
const roleId = Number(getCookiesDecrypt("urie")) || 0;
|
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 [apiEvents, setApiEvents] = useState<CalendarEvent[]>([]);
|
||||||
const [Isloading, setLoading] = useState<boolean>(false);
|
const [Isloading, setLoading] = useState<boolean>(false);
|
||||||
const [draggableInitialized, setDraggableInitialized] =
|
const [draggableInitialized, setDraggableInitialized] =
|
||||||
|
|
@ -574,11 +577,11 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
||||||
<div className="grid grid-cols-12 gap-6 divide-x divide-border">
|
<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">
|
<Card className="col-span-12 lg:col-span-4 2xl:col-span-3 pb-5">
|
||||||
<CardContent className="p-0">
|
<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 ? (
|
{roleId == 3 || roleId == 11 || roleId == 2 || roleId == 12 ? (
|
||||||
<Button
|
<Button
|
||||||
onClick={handleDateClick}
|
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" />
|
<Plus className="w-4 h-4 me-1" />
|
||||||
{t("addEvent")}
|
{t("addEvent")}
|
||||||
|
|
@ -589,8 +592,8 @@ const CalendarView = ({ categories }: CalendarViewProps) => {
|
||||||
<div>
|
<div>
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
{roleId == 2 ? (
|
{roleId === 3 && userLevelId === 216 ? (
|
||||||
<Button className="dark:bg-background dark:text-foreground ">
|
<Button className="dark:bg-background dark:text-foreground w-[250px]">
|
||||||
<Book className="w-4 h-4" />
|
<Book className="w-4 h-4" />
|
||||||
{t("bag-pa-monitoring-results")}
|
{t("bag-pa-monitoring-results")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ import { listEnableCategory } from "@/service/content/content";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const BlogTable = () => {
|
const BlogTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -73,7 +74,7 @@ const BlogTable = () => {
|
||||||
);
|
);
|
||||||
const [categoryFilter, setCategoryFilter] = React.useState<string>("");
|
const [categoryFilter, setCategoryFilter] = React.useState<string>("");
|
||||||
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -17,155 +17,162 @@ import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import { deleteBlog } from "@/service/blog/blog";
|
import { deleteBlog } from "@/service/blog/blog";
|
||||||
import { error, loading } from "@/lib/swal";
|
import { error, loading } from "@/lib/swal";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
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 formattedDate =
|
const columns: ColumnDef<any>[] = [
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
{
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
accessorKey: "no",
|
||||||
: "-";
|
header: t("no"),
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "tags",
|
header: t("title"),
|
||||||
header: "Tag",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => <span className="">{row.getValue("tags")}</span>,
|
<span className="whitespace-normal">{row.getValue("title")}</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: "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;
|
||||||
|
|
||||||
{
|
const formattedDate =
|
||||||
id: "actions",
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
accessorKey: "action",
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
header: "Actions",
|
: "-";
|
||||||
enableHiding: false,
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
cell: ({ row }) => {
|
},
|
||||||
const router = useRouter();
|
},
|
||||||
const MySwal = withReactContent(Swal);
|
{
|
||||||
|
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) {
|
// Mengambil `statusName` dari data API
|
||||||
loading();
|
const status = row.getValue("statusName") as string;
|
||||||
const resDelete = await deleteBlog(id);
|
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
||||||
|
|
||||||
if (resDelete?.error) {
|
// Gunakan `statusName` untuk pencocokan
|
||||||
error(resDelete.message);
|
const statusStyles =
|
||||||
return false;
|
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() {
|
function success() {
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Sukses",
|
title: "Sukses",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonColor: "#3085d6",
|
confirmButtonColor: "#3085d6",
|
||||||
confirmButtonText: "OK",
|
confirmButtonText: "OK",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDeleteBlog = (id: any) => {
|
const handleDeleteBlog = (id: any) => {
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Hapus Data",
|
title: "Hapus Data",
|
||||||
text: "",
|
text: "",
|
||||||
icon: "warning",
|
icon: "warning",
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
cancelButtonColor: "#3085d6",
|
cancelButtonColor: "#3085d6",
|
||||||
confirmButtonColor: "#d33",
|
confirmButtonColor: "#d33",
|
||||||
confirmButtonText: "Hapus",
|
confirmButtonText: "Hapus",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
deleteProcess(id);
|
deleteProcess(id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open menu</span>
|
<span className="sr-only">Open menu</span>
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
<Link href={`/contributor/blog/detail/${row.original.id}`}>
|
<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">
|
<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" />
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
View
|
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>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link href={`/contributor/blog/update/${row.original.id}`}>
|
</DropdownMenu>
|
||||||
<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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
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 { deleteMedia } from "@/service/content/content";
|
||||||
import { error } from "@/lib/swal";
|
import { error } from "@/lib/swal";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const MySwal = withReactContent(Swal);
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Title",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("title");
|
||||||
const title: string = row.getValue("title");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("categoryName")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "categoryName",
|
header: t("upload-date"),
|
||||||
header: "Category Name",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => (
|
const createdAt = row.getValue("createdAt") as
|
||||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
| string
|
||||||
),
|
| number
|
||||||
},
|
| undefined;
|
||||||
{
|
|
||||||
accessorKey: "createdAt",
|
|
||||||
header: "Upload Date",
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const createdAt = row.getValue("createdAt") as
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "creatorName",
|
||||||
accessorKey: "creatorName",
|
header: t("creator-group"),
|
||||||
header: "Creator Group",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||||
<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: "creatorGroupLevelName",
|
||||||
accessorKey: "statusName",
|
header: t("source"),
|
||||||
header: "Status",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="whitespace-nowrap">
|
||||||
const statusColors: Record<string, string> = {
|
{row.getValue("creatorGroupLevelName")}
|
||||||
diterima: "bg-green-100 text-green-600",
|
</span>
|
||||||
"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: "publishedOn",
|
||||||
id: "actions",
|
header: t("published"),
|
||||||
accessorKey: "action",
|
cell: ({ row }) => {
|
||||||
header: "Actions",
|
const isPublish = row.original.isPublish;
|
||||||
enableHiding: false,
|
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||||
cell: ({ row }) => {
|
|
||||||
const MySwal = withReactContent(Swal);
|
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
let displayText = "-";
|
||||||
// loading();
|
if (isPublish && !isPublishOnPolda) {
|
||||||
const data = {
|
displayText = "Mabes";
|
||||||
id,
|
} 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) {
|
// Gunakan `statusName` untuk pencocokan
|
||||||
error(response.message);
|
const statusStyles =
|
||||||
return false;
|
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||||
}
|
|
||||||
success();
|
|
||||||
}
|
|
||||||
|
|
||||||
function success() {
|
return (
|
||||||
MySwal.fire({
|
<Badge
|
||||||
title: "Sukses",
|
className={cn(
|
||||||
icon: "success",
|
"rounded-full px-5 w-full whitespace-nowrap",
|
||||||
confirmButtonColor: "#3085d6",
|
statusStyles
|
||||||
confirmButtonText: "OK",
|
)}
|
||||||
}).then((result) => {
|
>
|
||||||
if (result.isConfirmed) {
|
{status} {/* Tetap tampilkan nilai asli */}
|
||||||
window.location.reload();
|
</Badge>
|
||||||
}
|
);
|
||||||
});
|
},
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
];
|
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";
|
} from "@/service/content/content";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TableAudio = () => {
|
const TableAudio = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -99,7 +100,7 @@ const TableAudio = () => {
|
||||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
"use client";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
|
|
||||||
|
|
@ -19,237 +20,224 @@ import { deleteMedia } from "@/service/content/content";
|
||||||
import { error, loading } from "@/lib/swal";
|
import { error, loading } from "@/lib/swal";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const MySwal = withReactContent(Swal);
|
const useTableColumns = () => {
|
||||||
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
const columns: ColumnDef<any>[] = [
|
const MySwal = withReactContent(Swal);
|
||||||
{
|
const columns: ColumnDef<any>[] = [
|
||||||
accessorKey: "no",
|
{
|
||||||
header: "No",
|
accessorKey: "no",
|
||||||
cell: ({ row }) => (
|
header: t("no"),
|
||||||
<div className="flex items-center gap-5">
|
cell: ({ row }) => (
|
||||||
<div className="flex-1 text-start">
|
<div className="flex items-center gap-5">
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
<div className="flex-1 text-start">
|
||||||
{row.getValue("no")}
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
</h4>
|
{row.getValue("no")}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Title",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("title");
|
||||||
const title: string = row.getValue("title");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("categoryName")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "categoryName",
|
header: t("upload-date"),
|
||||||
header: "Category Name",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => (
|
const createdAt = row.getValue("createdAt") as
|
||||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
| string
|
||||||
),
|
| number
|
||||||
},
|
| undefined;
|
||||||
{
|
|
||||||
accessorKey: "createdAt",
|
|
||||||
header: "Upload Date",
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const createdAt = row.getValue("createdAt") as
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "creatorName",
|
||||||
accessorKey: "creatorName",
|
header: t("creator-group"),
|
||||||
header: "Creator Group",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||||
<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: "creatorGroupLevelName",
|
||||||
accessorKey: "statusId",
|
header: t("source"),
|
||||||
header: "Status",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="whitespace-nowrap">
|
||||||
const userLevelId = 2; // Gantilah sesuai dengan konteks aplikasi
|
{row.getValue("creatorGroupLevelName")}
|
||||||
const statusId = Number(row.getValue("statusId"));
|
</span>
|
||||||
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: "publishedOn",
|
||||||
|
header: t("published"),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const isPublish = row.original.isPublish;
|
||||||
|
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||||
|
|
||||||
{
|
let displayText = "-";
|
||||||
id: "actions",
|
if (isPublish && !isPublishOnPolda) {
|
||||||
accessorKey: "action",
|
displayText = "Mabes";
|
||||||
header: "Actions",
|
} else if (isPublish && isPublishOnPolda) {
|
||||||
enableHiding: false,
|
displayText = "Mabes & Polda";
|
||||||
cell: ({ row }) => {
|
} else if (!isPublish && isPublishOnPolda) {
|
||||||
const router = useRouter();
|
displayText = "Polda";
|
||||||
const MySwal = withReactContent(Swal);
|
}
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
return (
|
||||||
// loading();
|
<div className="text-center whitespace-nowrap" title={displayText}>
|
||||||
const data = {
|
{displayText}
|
||||||
id,
|
</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) {
|
return (
|
||||||
error(response.message);
|
<Badge
|
||||||
return false;
|
className={cn(
|
||||||
}
|
"rounded-full px-5 w-full whitespace-nowrap",
|
||||||
success();
|
statusStyles
|
||||||
}
|
)}
|
||||||
|
>
|
||||||
function success() {
|
{status} {/* Tetap tampilkan nilai asli */}
|
||||||
MySwal.fire({
|
</Badge>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
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 { Badge } from "@/components/ui/badge";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import TablePagination from "@/components/table/table-pagination";
|
import TablePagination from "@/components/table/table-pagination";
|
||||||
import columns from "./columns";
|
|
||||||
import {
|
import {
|
||||||
deleteMedia,
|
deleteMedia,
|
||||||
listDataImage,
|
listDataImage,
|
||||||
|
|
@ -66,6 +66,7 @@ import withReactContent from "sweetalert2-react-content";
|
||||||
import { error } from "@/lib/swal";
|
import { error } from "@/lib/swal";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TableImage = () => {
|
const TableImage = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -104,7 +105,7 @@ const TableImage = () => {
|
||||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -16,137 +16,146 @@ import {
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
import withReactContent from "sweetalert2-react-content";
|
||||||
|
import Swal from "sweetalert2";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const MySwal = withReactContent(Swal);
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "contentTitle",
|
||||||
accessorKey: "contentTitle",
|
header: t("title"),
|
||||||
header: "Judul",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("contentTitle");
|
||||||
const title: string = row.getValue("contentTitle");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("contentCreatedGroupBy")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: "contentTag",
|
|
||||||
header: "Tag",
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<span className="whitespace-nowrap">{row.getValue("contentTag")}</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
accessorKey: "contentType",
|
accessorKey: "isPublish",
|
||||||
header: "Tipe Konten ",
|
header: "Status",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => {
|
||||||
<span className="whitespace-nowrap">{row.getValue("contentType")}</span>
|
const isPublish = row.getValue<boolean>("isPublish");
|
||||||
),
|
return (
|
||||||
},
|
<div>
|
||||||
{
|
|
||||||
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}>
|
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="sm"
|
||||||
className={`bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent ${
|
color={isPublish ? "success" : "warning"}
|
||||||
isDisabled ? "cursor-not-allowed opacity-50" : ""
|
variant="outline"
|
||||||
}`}
|
className={`btn btn-sm ${
|
||||||
disabled={isDisabled} // Disable button if isPublish is true
|
isPublish ? "btn-outline-success" : "btn-outline-warning"
|
||||||
|
} pill-btn ml-1`}
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open menu</span>
|
{isPublish ? "Diterima" : "Menunggu Review"}
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</div>
|
||||||
<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 ${
|
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" : ""
|
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" />
|
<span className="sr-only">Open menu</span>
|
||||||
Pindah Ke Mediahub
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
</DropdownMenuItem>
|
</Button>
|
||||||
</Link>
|
</DropdownMenuTrigger>
|
||||||
</DropdownMenuContent>
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
</DropdownMenu>
|
<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,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
// export type CompanyData = {
|
// export type CompanyData = {
|
||||||
// no: number;
|
// no: number;
|
||||||
|
|
@ -77,7 +80,8 @@ const TableSPIT = () => {
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
const userId = getCookiesDecrypt("uie");
|
const userId = getCookiesDecrypt("uie");
|
||||||
const userLevelId = getCookiesDecrypt("ulie");
|
const userLevelId = getCookiesDecrypt("ulie");
|
||||||
|
const t = useTranslations("AnalyticsDashboard");
|
||||||
|
const [dateFilter, setDateFilter] = React.useState("");
|
||||||
const [totalData, setTotalData] = React.useState<number>(1);
|
const [totalData, setTotalData] = React.useState<number>(1);
|
||||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||||
|
|
@ -86,7 +90,7 @@ const TableSPIT = () => {
|
||||||
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
const [statusFilter, setStatusFilter] = React.useState<any[]>([]);
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: spitTable,
|
data: spitTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
@ -117,7 +121,7 @@ const TableSPIT = () => {
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [page, limit, search, statusFilter]);
|
}, [page, limit, search, statusFilter, dateFilter]);
|
||||||
|
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
let isPublish;
|
let isPublish;
|
||||||
|
|
@ -129,8 +133,18 @@ const TableSPIT = () => {
|
||||||
isPublish = statusFilter.includes(1) ? false : true;
|
isPublish = statusFilter.includes(1) ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formattedStartDate = dateFilter
|
||||||
|
? format(new Date(dateFilter), "yyyy-MM-dd")
|
||||||
|
: "";
|
||||||
|
|
||||||
try {
|
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 data = res?.data?.data;
|
||||||
const contentData = data?.content || [];
|
const contentData = data?.content || [];
|
||||||
|
|
||||||
|
|
@ -192,6 +206,15 @@ const TableSPIT = () => {
|
||||||
<div className="flex flex-row justify-between my-1 mx-1">
|
<div className="flex flex-row justify-between my-1 mx-1">
|
||||||
<p>Filter</p>
|
<p>Filter</p>
|
||||||
</div>
|
</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>
|
<Label className="ml-2 mt-2">Status</Label>
|
||||||
<div className="flex items-center px-4 py-1">
|
<div className="flex items-center px-4 py-1">
|
||||||
<input
|
<input
|
||||||
|
|
|
||||||
|
|
@ -17,212 +17,224 @@ import { error } from "@/lib/swal";
|
||||||
import { deleteMedia } from "@/service/content/content";
|
import { deleteMedia } from "@/service/content/content";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const MySwal = withReactContent(Swal);
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Title",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("title");
|
||||||
const title: string = row.getValue("title");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("categoryName")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "categoryName",
|
header: t("upload-date"),
|
||||||
header: "Category Name",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => (
|
const createdAt = row.getValue("createdAt") as
|
||||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
| string
|
||||||
),
|
| number
|
||||||
},
|
| undefined;
|
||||||
{
|
|
||||||
accessorKey: "createdAt",
|
|
||||||
header: "Upload Date",
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const createdAt = row.getValue("createdAt") as
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "creatorName",
|
||||||
accessorKey: "creatorName",
|
header: t("creator-group"),
|
||||||
header: "Creator Group",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||||
<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: "creatorGroupLevelName",
|
||||||
{
|
header: t("source"),
|
||||||
accessorKey: "statusName",
|
cell: ({ row }) => (
|
||||||
header: "Status",
|
<span className="whitespace-nowrap">
|
||||||
cell: ({ row }) => {
|
{row.getValue("creatorGroupLevelName")}
|
||||||
const statusColors: Record<string, string> = {
|
</span>
|
||||||
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: "publishedOn",
|
||||||
id: "actions",
|
header: t("published"),
|
||||||
accessorKey: "action",
|
cell: ({ row }) => {
|
||||||
header: "Actions",
|
const isPublish = row.original.isPublish;
|
||||||
enableHiding: false,
|
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||||
cell: ({ row }) => {
|
|
||||||
const MySwal = withReactContent(Swal);
|
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
let displayText = "-";
|
||||||
// loading();
|
if (isPublish && !isPublishOnPolda) {
|
||||||
const data = {
|
displayText = "Mabes";
|
||||||
id,
|
} 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) {
|
// Gunakan `statusName` untuk pencocokan
|
||||||
error(response.message);
|
const statusStyles =
|
||||||
return false;
|
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
||||||
}
|
|
||||||
success();
|
|
||||||
}
|
|
||||||
|
|
||||||
function success() {
|
return (
|
||||||
MySwal.fire({
|
<Badge
|
||||||
title: "Sukses",
|
className={cn(
|
||||||
icon: "success",
|
"rounded-full px-5 w-full whitespace-nowrap",
|
||||||
confirmButtonColor: "#3085d6",
|
statusStyles
|
||||||
confirmButtonText: "OK",
|
)}
|
||||||
}).then((result) => {
|
>
|
||||||
if (result.isConfirmed) {
|
{status} {/* Tetap tampilkan nilai asli */}
|
||||||
window.location.reload();
|
</Badge>
|
||||||
}
|
);
|
||||||
});
|
},
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
];
|
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";
|
} from "@/service/content/content";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TableTeks = () => {
|
const TableTeks = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -98,7 +99,7 @@ const TableTeks = () => {
|
||||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -17,209 +17,223 @@ import { deleteMedia } from "@/service/content/content";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import { error } from "@/lib/swal";
|
import { error } from "@/lib/swal";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const MySwal = withReactContent(Swal);
|
||||||
header: "No",
|
|
||||||
cell: ({ row }) => (
|
const columns: ColumnDef<any>[] = [
|
||||||
<div className="flex items-center gap-5">
|
{
|
||||||
<div className="flex-1 text-start">
|
accessorKey: "no",
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
header: t("no"),
|
||||||
{row.getValue("no")}
|
cell: ({ row }) => (
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Title",
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
const title: string = row.getValue("title");
|
||||||
const title: string = row.getValue("title");
|
return (
|
||||||
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("categoryName")}
|
||||||
</span>
|
</span>
|
||||||
);
|
),
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "categoryName",
|
header: t("upload-date"),
|
||||||
header: "Category Name",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => (
|
const createdAt = row.getValue("createdAt") as
|
||||||
<span className="whitespace-nowrap">{row.getValue("categoryName")}</span>
|
| string
|
||||||
),
|
| number
|
||||||
},
|
| undefined;
|
||||||
{
|
|
||||||
accessorKey: "createdAt",
|
|
||||||
header: "Upload Date",
|
|
||||||
cell: ({ row }) => {
|
|
||||||
const createdAt = row.getValue("createdAt") as
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "creatorName",
|
||||||
accessorKey: "creatorName",
|
header: t("creator-group"),
|
||||||
header: "Creator Group",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||||
<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: "creatorGroupLevelName",
|
||||||
{
|
header: t("source"),
|
||||||
accessorKey: "statusName",
|
cell: ({ row }) => (
|
||||||
header: "Status",
|
<span className="whitespace-nowrap">
|
||||||
cell: ({ row }) => {
|
{row.getValue("creatorGroupLevelName")}
|
||||||
const statusColors: Record<string, string> = {
|
</span>
|
||||||
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: "publishedOn",
|
||||||
id: "actions",
|
header: t("published"),
|
||||||
accessorKey: "action",
|
cell: ({ row }) => {
|
||||||
header: "Actions",
|
const isPublish = row.original.isPublish;
|
||||||
enableHiding: false,
|
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||||
cell: ({ row }) => {
|
|
||||||
const MySwal = withReactContent(Swal);
|
|
||||||
|
|
||||||
async function doDelete(id: any) {
|
let displayText = "-";
|
||||||
// loading();
|
if (isPublish && !isPublishOnPolda) {
|
||||||
const data = {
|
displayText = "Mabes";
|
||||||
id,
|
} 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) {
|
return (
|
||||||
error(response.message);
|
<Badge
|
||||||
return false;
|
className={cn(
|
||||||
}
|
"rounded-full px-5 w-full whitespace-nowrap",
|
||||||
success();
|
statusStyles
|
||||||
}
|
)}
|
||||||
|
>
|
||||||
function success() {
|
{status} {/* Tetap tampilkan nilai asli */}
|
||||||
MySwal.fire({
|
</Badge>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
];
|
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";
|
} from "@/service/content/content";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TableVideo = () => {
|
const TableVideo = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -98,7 +99,7 @@ const TableVideo = () => {
|
||||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -13,105 +13,111 @@ import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const columns: ColumnDef<any>[] = [
|
||||||
header: "No",
|
{
|
||||||
cell: ({ row }) => (
|
accessorKey: "no",
|
||||||
<div className="flex items-center gap-5">
|
header: t("no"),
|
||||||
<div className="flex-1 text-start">
|
cell: ({ row }) => (
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
<div className="flex items-center gap-5">
|
||||||
{row.getValue("no")}
|
<div className="flex-1 text-start">
|
||||||
</h4>
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
|
{row.getValue("no")}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Judul",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<div className="flex items-center gap-5">
|
||||||
<div className="flex items-center gap-5">
|
<div className="flex-1 text-start">
|
||||||
<div className="flex-1 text-start">
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
{row.getValue("title")}
|
||||||
{row.getValue("title")}
|
</h4>
|
||||||
</h4>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "createdAt",
|
header: t("upload-date"),
|
||||||
header: "Tanggal Unggah ",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
const createdAt = row.getValue("createdAt") as
|
||||||
const createdAt = row.getValue("createdAt") as
|
| string
|
||||||
| string
|
| number
|
||||||
| number
|
| undefined;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "isActive",
|
||||||
accessorKey: "isActive",
|
header: "Status",
|
||||||
header: "Status",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
const isActive = row.getValue<boolean>("isActive");
|
||||||
const isActive = row.getValue<boolean>("isActive");
|
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
return (
|
||||||
return (
|
<div>
|
||||||
<div>
|
{isActive ? (
|
||||||
{isActive ? (
|
<b className="text-blue-500">Terkirim</b>
|
||||||
<b className="text-blue-500">Terkirim</b>
|
) : (
|
||||||
) : (
|
<b className="text-danger">Belum Terkirim</b>
|
||||||
<b className="text-danger">Belum Terkirim</b>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
id: "actions",
|
||||||
id: "actions",
|
accessorKey: "action",
|
||||||
accessorKey: "action",
|
header: t("action"),
|
||||||
header: "Actions",
|
enableHiding: false,
|
||||||
enableHiding: false,
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
return (
|
||||||
return (
|
<DropdownMenu>
|
||||||
<DropdownMenu>
|
<DropdownMenuTrigger asChild>
|
||||||
<DropdownMenuTrigger asChild>
|
<Button
|
||||||
<Button
|
size="icon"
|
||||||
size="icon"
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
>
|
||||||
>
|
<span className="sr-only">Open menu</span>
|
||||||
<span className="sr-only">Open menu</span>
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
</Button>
|
||||||
</Button>
|
</DropdownMenuTrigger>
|
||||||
</DropdownMenuTrigger>
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<Link
|
||||||
<Link
|
href={`/contributor/planning/mediahub/publish/${row.original.id}`}
|
||||||
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">
|
||||||
<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" />
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
Publish
|
||||||
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>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<DropdownMenuItem
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
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 search from "@/app/[locale]/(protected)/app/chat/components/search";
|
||||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const MediahubTable = () => {
|
const MediahubTable = () => {
|
||||||
const t = useTranslations("Planning");
|
const t = useTranslations("Planning");
|
||||||
|
|
@ -78,7 +79,7 @@ const MediahubTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -13,103 +13,109 @@ import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const columns: ColumnDef<any>[] = [
|
||||||
header: "No",
|
{
|
||||||
cell: ({ row }) => (
|
accessorKey: "no",
|
||||||
<div className="flex items-center gap-5">
|
header: t("no"),
|
||||||
<div className="flex-1 text-start">
|
cell: ({ row }) => (
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
<div className="flex items-center gap-5">
|
||||||
{row.getValue("no")}
|
<div className="flex-1 text-start">
|
||||||
</h4>
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
|
{row.getValue("no")}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "title",
|
header: t("title"),
|
||||||
header: "Judul",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => (
|
<div className="flex items-center gap-5">
|
||||||
<div className="flex items-center gap-5">
|
<div className="flex-1 text-start">
|
||||||
<div className="flex-1 text-start">
|
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
{row.getValue("title")}
|
||||||
{row.getValue("title")}
|
</h4>
|
||||||
</h4>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "createdAt",
|
||||||
accessorKey: "createdAt",
|
header: t("upload-date"),
|
||||||
header: "Tanggal Unggah ",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
const createdAt = row.getValue("createdAt") as
|
||||||
const createdAt = row.getValue("createdAt") as
|
| string
|
||||||
| string
|
| number
|
||||||
| number
|
| undefined;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
const formattedDate =
|
const formattedDate =
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
createdAt && !isNaN(new Date(createdAt).getTime())
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
||||||
: "-";
|
: "-";
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "isActive",
|
||||||
accessorKey: "isActive",
|
header: "Status",
|
||||||
header: "Status",
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
const isActive = row.getValue<boolean>("isActive");
|
||||||
const isActive = row.getValue<boolean>("isActive");
|
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
||||||
console.log("isActive value:", isActive); // TypeScript type is inferred correctly
|
return (
|
||||||
return (
|
<div>
|
||||||
<div>
|
{isActive ? (
|
||||||
{isActive ? (
|
<b className="text-blue-500">Terkirim</b>
|
||||||
<b className="text-blue-500">Terkirim</b>
|
) : (
|
||||||
) : (
|
<b className="text-danger">Belum Terkirim</b>
|
||||||
<b className="text-danger">Belum Terkirim</b>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
id: "actions",
|
||||||
id: "actions",
|
accessorKey: "action",
|
||||||
accessorKey: "action",
|
header: t("action"),
|
||||||
header: "Actions",
|
enableHiding: false,
|
||||||
enableHiding: false,
|
cell: ({ row }) => {
|
||||||
cell: ({ row }) => {
|
return (
|
||||||
return (
|
<DropdownMenu>
|
||||||
<DropdownMenu>
|
<DropdownMenuTrigger asChild>
|
||||||
<DropdownMenuTrigger asChild>
|
<Button
|
||||||
<Button
|
size="icon"
|
||||||
size="icon"
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
>
|
||||||
>
|
<span className="sr-only">Open menu</span>
|
||||||
<span className="sr-only">Open menu</span>
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
</Button>
|
||||||
</Button>
|
</DropdownMenuTrigger>
|
||||||
</DropdownMenuTrigger>
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<Link
|
||||||
<Link
|
href={`/contributor/planning/medsos-mediahub/publish/${row.original.id}`}
|
||||||
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">
|
||||||
<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" />
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
Publish
|
||||||
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>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
<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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
export default columns;
|
return columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useTableColumns;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import columns from "./columns";
|
||||||
import { getPlanningSentPagination } from "@/service/planning/planning";
|
import { getPlanningSentPagination } from "@/service/planning/planning";
|
||||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const MedsosTable = () => {
|
const MedsosTable = () => {
|
||||||
const t = useTranslations("Planning");
|
const t = useTranslations("Planning");
|
||||||
|
|
@ -77,7 +78,7 @@ const MedsosTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -12,163 +12,171 @@ import {
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
accessorKey: "title",
|
accessorKey: "title",
|
||||||
header: "Title",
|
header: t("title"),
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
const title: string = row.getValue("title");
|
const title: string = row.getValue("title");
|
||||||
return (
|
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("uploaderName")}
|
||||||
</span>
|
</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;
|
id: "actions",
|
||||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
accessorKey: "action",
|
||||||
|
header: t("action"),
|
||||||
// Gunakan `statusName` untuk pencocokan
|
enableHiding: false,
|
||||||
const statusStyles =
|
cell: ({ row }) => {
|
||||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
return (
|
<DropdownMenuTrigger asChild>
|
||||||
<Badge
|
<Button
|
||||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
size="icon"
|
||||||
>
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
{status} {/* Tetap tampilkan nilai asli */}
|
>
|
||||||
</Badge>
|
<span className="sr-only">Open menu</span>
|
||||||
);
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
},
|
</Button>
|
||||||
},
|
</DropdownMenuTrigger>
|
||||||
{
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
accessorKey: "speaker",
|
<Link
|
||||||
header: "Disampaikan oleh",
|
href={`/contributor/schedule/event/detail/${row.original.id}`}
|
||||||
cell: ({ row }: { row: { original: any } }) => {
|
>
|
||||||
console.log("Row Original Data:", row.original);
|
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||||
const { speakerTitle, speakerName } = row.original;
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
return (
|
View
|
||||||
<span className="whitespace-nowrap">
|
</DropdownMenuItem>
|
||||||
{speakerTitle || ""} {speakerName || ""}
|
</Link>
|
||||||
</span>
|
<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" />
|
||||||
accessorKey: "uploaderName",
|
Edit
|
||||||
header: "Sumber ",
|
</DropdownMenuItem>
|
||||||
cell: ({ row }) => (
|
</Link>
|
||||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
<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
|
||||||
|
|
||||||
{
|
|
||||||
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
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
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 { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const EventTable = () => {
|
const EventTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -55,7 +56,7 @@ const EventTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -12,163 +12,172 @@ import {
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
accessorKey: "title",
|
accessorKey: "title",
|
||||||
header: "Title",
|
header: t("title"),
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
const title: string = row.getValue("title");
|
const title: string = row.getValue("title");
|
||||||
return (
|
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("uploaderName")}
|
||||||
</span>
|
</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;
|
id: "actions",
|
||||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
accessorKey: "action",
|
||||||
|
header: t("action"),
|
||||||
// Gunakan `statusName` untuk pencocokan
|
enableHiding: false,
|
||||||
const statusStyles =
|
cell: ({ row }) => {
|
||||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
return (
|
<DropdownMenuTrigger asChild>
|
||||||
<Badge
|
<Button
|
||||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
size="icon"
|
||||||
>
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
{status} {/* Tetap tampilkan nilai asli */}
|
>
|
||||||
</Badge>
|
<span className="sr-only">Open menu</span>
|
||||||
);
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
},
|
</Button>
|
||||||
},
|
</DropdownMenuTrigger>
|
||||||
{
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
accessorKey: "speaker",
|
<Link
|
||||||
header: "Disampaikan oleh",
|
href={`/contributor/schedule/press-conference/detail/${row.original.id}`}
|
||||||
cell: ({ row }: { row: { original: any } }) => {
|
>
|
||||||
console.log("Row Original Data:", row.original);
|
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||||
const { speakerTitle, speakerName } = row.original;
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
return (
|
Detail
|
||||||
<span className="whitespace-nowrap">
|
</DropdownMenuItem>
|
||||||
{speakerTitle || ""} {speakerName || ""}
|
</Link>
|
||||||
</span>
|
<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" />
|
||||||
accessorKey: "uploaderName",
|
Edit
|
||||||
header: "Sumber ",
|
</DropdownMenuItem>
|
||||||
cell: ({ row }) => (
|
</Link>
|
||||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
<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
|
||||||
|
|
||||||
{
|
|
||||||
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
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
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 { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const PressConferenceTable = () => {
|
const PressConferenceTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -68,7 +69,7 @@ const PressConferenceTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -12,163 +12,172 @@ import {
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</div>
|
),
|
||||||
),
|
},
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
accessorKey: "title",
|
accessorKey: "title",
|
||||||
header: "Title",
|
header: t("title"),
|
||||||
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
cell: ({ row }: { row: { getValue: (key: string) => string } }) => {
|
||||||
const title: string = row.getValue("title");
|
const title: string = row.getValue("title");
|
||||||
return (
|
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">
|
<span className="whitespace-nowrap">
|
||||||
{title.length > 50 ? `${title.slice(0, 30)}...` : title}
|
{row.getValue("uploaderName")}
|
||||||
</span>
|
</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;
|
id: "actions",
|
||||||
const statusName = status?.toLocaleLowerCase(); // Ubah ke huruf kecil
|
accessorKey: "action",
|
||||||
|
header: t("action"),
|
||||||
// Gunakan `statusName` untuk pencocokan
|
enableHiding: false,
|
||||||
const statusStyles =
|
cell: ({ row }) => {
|
||||||
statusColors[statusName] || "bg-gray-100 text-gray-600";
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
return (
|
<DropdownMenuTrigger asChild>
|
||||||
<Badge
|
<Button
|
||||||
className={cn("rounded-full px-5 whitespace-nowrap", statusStyles)}
|
size="icon"
|
||||||
>
|
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||||
{status} {/* Tetap tampilkan nilai asli */}
|
>
|
||||||
</Badge>
|
<span className="sr-only">Open menu</span>
|
||||||
);
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
},
|
</Button>
|
||||||
},
|
</DropdownMenuTrigger>
|
||||||
{
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
accessorKey: "speaker",
|
<Link
|
||||||
header: "Disampaikan oleh",
|
href={`/contributor/schedule/press-release/detail/${row.original.id}`}
|
||||||
cell: ({ row }: { row: { original: any } }) => {
|
>
|
||||||
console.log("Row Original Data:", row.original);
|
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||||
const { speakerTitle, speakerName } = row.original;
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
return (
|
View
|
||||||
<span className="whitespace-nowrap">
|
</DropdownMenuItem>
|
||||||
{speakerTitle || ""} {speakerName || ""}
|
</Link>
|
||||||
</span>
|
<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" />
|
||||||
accessorKey: "uploaderName",
|
Edit
|
||||||
header: "Sumber ",
|
</DropdownMenuItem>
|
||||||
cell: ({ row }) => (
|
</Link>
|
||||||
<span className="whitespace-nowrap">{row.getValue("uploaderName")}</span>
|
<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
|
||||||
|
|
||||||
{
|
|
||||||
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
|
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
export default columns;
|
return columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useTableColumns;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import { paginationSchedule } from "@/service/schedule/schedule";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { CardHeader, CardTitle } from "@/components/ui/card";
|
import { CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const PressReleaseTable = () => {
|
const PressReleaseTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -69,7 +70,7 @@ const PressReleaseTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -20,187 +20,193 @@ import { deleteTask } from "@/service/task";
|
||||||
import { error, loading } from "@/lib/swal";
|
import { error, loading } from "@/lib/swal";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
const columns: ColumnDef<any>[] = [
|
||||||
header: "No",
|
{
|
||||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
accessorKey: "no",
|
||||||
},
|
header: t("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>;
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "assignmentType",
|
header: t("title"),
|
||||||
header: "Category Task",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<div>
|
||||||
const type = row.getValue("assignmentType") as { name: string };
|
<span>{row.getValue("title")}</span>
|
||||||
return <span>{type?.name}</span>;
|
{row.original.isForward && (
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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>
|
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
variant={"outline"}
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
color="primary"
|
||||||
|
size="sm"
|
||||||
|
className="ml-3 rounded-xl"
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open menu</span>
|
Forward
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
)}
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
</div>
|
||||||
<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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
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 { Label } from "@/components/ui/label";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TaskTable = () => {
|
const TaskTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -83,7 +84,7 @@ const TaskTable = () => {
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [isSpecificAttention, setIsSpecificAttention] = React.useState(true);
|
const [isSpecificAttention, setIsSpecificAttention] = React.useState(true);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -181,16 +181,16 @@ export default function ExecutiveDashboard() {
|
||||||
const view2 =
|
const view2 =
|
||||||
levelName == "MABES POLRI"
|
levelName == "MABES POLRI"
|
||||||
? isInternational[1]
|
? isInternational[1]
|
||||||
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-konten-publisher?"
|
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-published-produksi?"
|
||||||
: "views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-konten-publisher?"
|
: "views/2023_04_MediaHUB-Viz-POLDA_Rev202/db-published-produksi-executive?"
|
||||||
: `views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-konten-publisher-polda?provinsi-polda=${poldaState}&`;
|
: `views/2023_04_MediaHUB-Viz-POLDA_Rev202/db-konten-publisher-polda-executive?provinsi-polda=${poldaState}&`;
|
||||||
|
|
||||||
const view3 =
|
const view3 =
|
||||||
levelName == "MABES POLRI"
|
levelName == "MABES POLRI"
|
||||||
? isInternational[2]
|
? isInternational[2]
|
||||||
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-waktu-akses-pengguna?"
|
? "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_Rev202/db-waktu-akses-pengguna-executive?"
|
||||||
: `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-polda-executive?provinsi-polda=${poldaState}&`;
|
||||||
|
|
||||||
const view4 =
|
const view4 =
|
||||||
levelName == "MABES POLRI"
|
levelName == "MABES POLRI"
|
||||||
|
|
@ -212,6 +212,21 @@ export default function ExecutiveDashboard() {
|
||||||
async function initState() {
|
async function initState() {
|
||||||
const response1 = await generateTicket();
|
const response1 = await generateTicket();
|
||||||
setTicket1(response1?.data?.data);
|
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();
|
initState();
|
||||||
|
|
@ -235,35 +250,6 @@ export default function ExecutiveDashboard() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SiteBreadcrumb />
|
<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">
|
<div className="mt-3 flex flex-row gap-3 justify-center">
|
||||||
<Card className="rounded-sm w-4/12 p-3">
|
<Card className="rounded-sm w-4/12 p-3">
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between">
|
||||||
|
|
@ -298,7 +284,7 @@ export default function ExecutiveDashboard() {
|
||||||
<LucideBoxSelect />
|
<LucideBoxSelect />
|
||||||
</div>
|
</div>
|
||||||
<div className="my-5">
|
<div className="my-5">
|
||||||
{ticket1 == "" ? (
|
{ticket2 == "" ? (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${baseUrl + view4 + param}`}
|
src={`${baseUrl + view4 + param}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
|
|
@ -307,7 +293,7 @@ export default function ExecutiveDashboard() {
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${`${url + ticket1}/${view4}${param}`}`}
|
src={`${`${url + ticket2}/${view4}${param}`}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="750"
|
height="750"
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
|
|
@ -323,7 +309,7 @@ export default function ExecutiveDashboard() {
|
||||||
<LucideBoxSelect />
|
<LucideBoxSelect />
|
||||||
</div>
|
</div>
|
||||||
<div className="my-5">
|
<div className="my-5">
|
||||||
{ticket1 == "" ? (
|
{ticket3 == "" ? (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${baseUrl + view5 + param}`}
|
src={`${baseUrl + view5 + param}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
|
|
@ -332,7 +318,7 @@ export default function ExecutiveDashboard() {
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${`${url + ticket1}/${view5}${param}`}`}
|
src={`${`${url + ticket3}/${view5}${param}`}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="750"
|
height="750"
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
|
|
@ -342,24 +328,24 @@ export default function ExecutiveDashboard() {
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full mt-3">
|
<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">
|
<div className="flex flex-row justify-between">
|
||||||
<p className="text-base font-semibold">Konten Paling Populer</p>
|
<p className="text-base font-semibold">Konten Paling Populer</p>
|
||||||
<LucideBoxSelect />
|
<LucideBoxSelect />
|
||||||
</div>
|
</div>
|
||||||
<div className="my-5">
|
<div className="my-5">
|
||||||
{ticket2 == "" ? (
|
{ticket4 == "" ? (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${baseUrl + view2 + param}`}
|
src={`${baseUrl + view2 + param}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="750"
|
height="650"
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${`${url + ticket2}/${view2}${param}`}`}
|
src={`${`${url + ticket4}/${view2}${param}`}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="750"
|
height="650"
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
@ -367,7 +353,7 @@ export default function ExecutiveDashboard() {
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full mt-3">
|
<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">
|
<div className="flex flex-row justify-between">
|
||||||
<p className="text-base font-semibold">
|
<p className="text-base font-semibold">
|
||||||
Heatmap Konten Dengan Interaksi
|
Heatmap Konten Dengan Interaksi
|
||||||
|
|
@ -378,18 +364,18 @@ export default function ExecutiveDashboard() {
|
||||||
<LucideBoxSelect />
|
<LucideBoxSelect />
|
||||||
</div>
|
</div>
|
||||||
<div className="my-5">
|
<div className="my-5">
|
||||||
{ticket3 == "" ? (
|
{ticket5 == "" ? (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${baseUrl + view3 + param}`}
|
src={`${baseUrl + view3 + param}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="750"
|
height="600"
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${`${url + ticket3}/${view3}${param}`}`}
|
src={`${`${url + ticket5}/${view3}${param}`}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="750"
|
height="600"
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
@ -397,7 +383,7 @@ export default function ExecutiveDashboard() {
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full mt-3">
|
<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">
|
<div className="flex flex-row justify-between">
|
||||||
<p className="text-base font-semibold">Emergency Issue</p>
|
<p className="text-base font-semibold">Emergency Issue</p>
|
||||||
<LucideBoxSelect />
|
<LucideBoxSelect />
|
||||||
|
|
@ -405,7 +391,7 @@ export default function ExecutiveDashboard() {
|
||||||
|
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="my-5">
|
<div className="my-5">
|
||||||
{ticket1 == "" ? (
|
{ticket6 == "" ? (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${baseUrl + view1 + param}`}
|
src={`${baseUrl + view1 + param}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
|
|
@ -414,7 +400,7 @@ export default function ExecutiveDashboard() {
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<iframe
|
<iframe
|
||||||
src={`${`${url + ticket1}/${view1}${param}`}`}
|
src={`${`${url + ticket6}/${view1}${param}`}`}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="750"
|
height="750"
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ import {
|
||||||
getTicketingEscalationPagination,
|
getTicketingEscalationPagination,
|
||||||
listTicketingInternal,
|
listTicketingInternal,
|
||||||
} from "@/service/communication/communication";
|
} from "@/service/communication/communication";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const CollaborationTable = () => {
|
const CollaborationTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -88,7 +89,7 @@ const CollaborationTable = () => {
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -13,102 +13,113 @@ import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link, useRouter } from "@/i18n/routing";
|
import { Link, useRouter } from "@/i18n/routing";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
{
|
||||||
},
|
accessorKey: "no",
|
||||||
{
|
header: t("no"),
|
||||||
accessorKey: "title",
|
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||||
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>;
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "createdAt",
|
header: t("question"),
|
||||||
header: "Waktu",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="normal-case"> {row.getValue("title")}</span>
|
||||||
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: "commentFromUserName",
|
||||||
accessorKey: "isActive",
|
header: t("sender"),
|
||||||
header: "Status",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="normal-case">
|
||||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
{row.getValue("commentFromUserName")}
|
||||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
</span>
|
||||||
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: "Type",
|
||||||
{
|
header: t("type"),
|
||||||
id: "actions",
|
cell: ({ row }) => {
|
||||||
accessorKey: "action",
|
const type = row.original.type;
|
||||||
header: "Actions",
|
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||||
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: "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 { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
{
|
||||||
},
|
accessorKey: "no",
|
||||||
{
|
header: t("no"),
|
||||||
accessorKey: "title",
|
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||||
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>;
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
accessorKey: "createdAt",
|
header: t("question"),
|
||||||
header: "Waktu",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="normal-case"> {row.getValue("title")}</span>
|
||||||
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: "commentFromUserName",
|
||||||
accessorKey: "isActive",
|
header: t("sender"),
|
||||||
header: "Status",
|
cell: ({ row }) => (
|
||||||
cell: ({ row }) => {
|
<span className="normal-case">
|
||||||
const isActive = row.getValue("isActive") as boolean; // Ambil nilai isActive
|
{row.getValue("commentFromUserName")}
|
||||||
const status = isActive ? "Open" : "Closed"; // Tentukan teks berdasarkan isActive
|
</span>
|
||||||
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: "type",
|
||||||
{
|
header: t("type"),
|
||||||
id: "actions",
|
cell: ({ row }) => {
|
||||||
accessorKey: "action",
|
const type = row.original.type; // Akses properti category
|
||||||
header: "Actions",
|
return <span className="normal-case">{type?.name || "N/A"}</span>;
|
||||||
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: "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,
|
getTicketingEscalationPagination,
|
||||||
listTicketingInternal,
|
listTicketingInternal,
|
||||||
} from "@/service/communication/communication";
|
} from "@/service/communication/communication";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const EscalationTable = () => {
|
const EscalationTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -87,7 +88,7 @@ const EscalationTable = () => {
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -13,97 +13,104 @@ import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
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 formattedDate =
|
const columns: ColumnDef<any>[] = [
|
||||||
createdAt && !isNaN(new Date(createdAt).getTime())
|
{
|
||||||
? format(new Date(createdAt), "dd-MM-yyyy HH:mm:ss")
|
accessorKey: "no",
|
||||||
: "-";
|
header: t("no"),
|
||||||
return <span className="whitespace-nowrap">{formattedDate}</span>;
|
cell: ({ row }) => <span> {row.getValue("no")}</span>,
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
accessorKey: "title",
|
||||||
id: "actions",
|
header: t("question"),
|
||||||
accessorKey: "action",
|
cell: ({ row }) => (
|
||||||
header: "Actions",
|
<span className="normal-case"> {row.getValue("title")}</span>
|
||||||
enableHiding: false,
|
),
|
||||||
cell: ({ row }) => {
|
},
|
||||||
return (
|
{
|
||||||
<DropdownMenu>
|
accessorKey: "createdBy",
|
||||||
<DropdownMenuTrigger asChild>
|
header: t("sender"),
|
||||||
<Button
|
cell: ({ row }) => {
|
||||||
size="icon"
|
const createdBy = row.original.createdBy; // Akses properti category
|
||||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
return (
|
||||||
>
|
<span className="normal-case">{createdBy?.fullname || "N/A"}</span>
|
||||||
<span className="sr-only">Open menu</span>
|
);
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
},
|
||||||
</Button>
|
},
|
||||||
</DropdownMenuTrigger>
|
{
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
accessorKey: "sendTo",
|
||||||
<Link
|
header: t("sendto"),
|
||||||
href={`/shared/communication/internal/detail/${row.original.id}`}
|
cell: ({ row }) => {
|
||||||
>
|
const sendTo = row.original.sendTo; // Akses properti category
|
||||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
return <span className="normal-case">{sendTo?.fullname || "N/A"}</span>;
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
},
|
||||||
View
|
},
|
||||||
|
{
|
||||||
|
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>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</DropdownMenuContent>
|
||||||
<Link
|
</DropdownMenu>
|
||||||
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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
];
|
||||||
];
|
|
||||||
|
|
||||||
export default columns;
|
return columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useTableColumns;
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ import {
|
||||||
} from "@/service/content/content";
|
} from "@/service/content/content";
|
||||||
import { listTicketingInternal } from "@/service/communication/communication";
|
import { listTicketingInternal } from "@/service/communication/communication";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const InternalTable = () => {
|
const InternalTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -88,7 +89,7 @@ const InternalTable = () => {
|
||||||
const userLevelId = getCookiesDecrypt("ulie");
|
const userLevelId = getCookiesDecrypt("ulie");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -18,198 +18,206 @@ import Swal from "sweetalert2";
|
||||||
import { error } from "@/lib/swal";
|
import { error } from "@/lib/swal";
|
||||||
import { deleteMedia } from "@/service/content/content";
|
import { deleteMedia } from "@/service/content/content";
|
||||||
import { publishContest } from "@/service/contest/contest";
|
import { publishContest } from "@/service/contest/contest";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const columns: ColumnDef<any>[] = [
|
const useTableColumns = () => {
|
||||||
{
|
const t = useTranslations("Table"); // Panggil di dalam hook
|
||||||
accessorKey: "no",
|
|
||||||
header: "No",
|
const columns: ColumnDef<any>[] = [
|
||||||
cell: ({ row }) => (
|
{
|
||||||
<div className="flex items-center gap-5">
|
accessorKey: "no",
|
||||||
<div className="flex-1 text-start">
|
header: t("no"),
|
||||||
<h4 className="text-sm font-medium text-default-600 whitespace-nowrap mb-1">
|
cell: ({ row }) => (
|
||||||
{row.getValue("no")}
|
<div className="flex items-center gap-5">
|
||||||
</h4>
|
<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>
|
||||||
</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>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
|
accessorKey: "hastagCode",
|
||||||
{
|
header: t("code"),
|
||||||
id: "actions",
|
cell: ({ row }) => (
|
||||||
accessorKey: "action",
|
<div className="flex items-center gap-5">
|
||||||
header: "Actions",
|
<div className="flex-1 text-start">
|
||||||
enableHiding: false,
|
<h4
|
||||||
cell: ({ row }) => {
|
className="text-sm font-bold
|
||||||
const MySwal = withReactContent(Swal);
|
text-default-600 whitespace-nowrap mb-1"
|
||||||
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"
|
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open menu</span>
|
{row.getValue("hastagCode")}
|
||||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
</h4>
|
||||||
</Button>
|
</div>
|
||||||
</DropdownMenuTrigger>
|
</div>
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
),
|
||||||
{((userRoleId == 11 || userRoleId == 12) &&
|
},
|
||||||
row?.original?.isPublishForMabes != true) ||
|
{
|
||||||
(userRoleId == 3 &&
|
accessorKey: "theme",
|
||||||
userLevelNumber == 1 &&
|
header: t("title"),
|
||||||
row?.original?.isPublishForAll != true) ? (
|
cell: ({ row }) => (
|
||||||
<DropdownMenuItem
|
<div className="flex items-center gap-5">
|
||||||
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"
|
<div className="flex-1 text-start">
|
||||||
onClick={() => handlePublishContest(row.original.id)}
|
<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" />
|
<span className="sr-only">Open menu</span>
|
||||||
Publish
|
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||||
</DropdownMenuItem>
|
</Button>
|
||||||
) : (
|
</DropdownMenuTrigger>
|
||||||
""
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
)}
|
{((userRoleId == 11 || userRoleId == 12) &&
|
||||||
<Link href={`/shared/contest/detail/${row.original.id}`}>
|
row?.original?.isPublishForMabes != true) ||
|
||||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
(userRoleId == 3 &&
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
userLevelNumber == 1 &&
|
||||||
View
|
row?.original?.isPublishForAll != true) ? (
|
||||||
</DropdownMenuItem>
|
<DropdownMenuItem
|
||||||
</Link>
|
className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none"
|
||||||
{/* <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" />
|
<SquarePen className="w-4 h-4 me-1.5" />
|
||||||
Edit
|
Edit
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
@ -217,11 +225,14 @@ const columns: ColumnDef<any>[] = [
|
||||||
<Trash2 className="w-4 h-4 me-1.5" />
|
<Trash2 className="w-4 h-4 me-1.5" />
|
||||||
Delete
|
Delete
|
||||||
</DropdownMenuItem> */}
|
</DropdownMenuItem> */}
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</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 TablePagination from "@/components/table/table-pagination";
|
||||||
import columns from "./columns";
|
import columns from "./columns";
|
||||||
import { listContest } from "@/service/contest/contest";
|
import { listContest } from "@/service/contest/contest";
|
||||||
|
import useTableColumns from "./columns";
|
||||||
|
|
||||||
const TaskTable = () => {
|
const TaskTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -63,7 +64,7 @@ const TaskTable = () => {
|
||||||
const [totalPage, setTotalPage] = React.useState(1);
|
const [totalPage, setTotalPage] = React.useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState<string>("");
|
const [search, setSearch] = React.useState<string>("");
|
||||||
|
const columns = useTableColumns();
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
columns,
|
columns,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
import {
|
import {
|
||||||
Carousel,
|
Carousel,
|
||||||
CarouselContent,
|
CarouselContent,
|
||||||
|
|
@ -30,14 +31,6 @@ const AudioSliderPage = () => {
|
||||||
initFetch();
|
initFetch();
|
||||||
}, [page, limit, search]);
|
}, [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 initFetch = async () => {
|
||||||
const response = await listCuratedContent(search, limit, page - 1, 4, "1");
|
const response = await listCuratedContent(search, limit, page - 1, 4, "1");
|
||||||
console.log(response);
|
console.log(response);
|
||||||
|
|
@ -48,11 +41,6 @@ const AudioSliderPage = () => {
|
||||||
setDisplayAudio(contentData);
|
setDisplayAudio(contentData);
|
||||||
};
|
};
|
||||||
|
|
||||||
// const shuffleAndSetVideos = () => {
|
|
||||||
// const shuffled = shuffleArray([...audioData]);
|
|
||||||
// setDisplayAudio(shuffled.slice(0, 3));
|
|
||||||
// };
|
|
||||||
|
|
||||||
const shuffleArray = (array: any[]) => {
|
const shuffleArray = (array: any[]) => {
|
||||||
for (let i = array.length - 1; i > 0; i--) {
|
for (let i = array.length - 1; i > 0; i--) {
|
||||||
const j = Math.floor(Math.random() * (i + 1));
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
|
@ -62,46 +50,61 @@ const AudioSliderPage = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Carousel className="w-full pr-3">
|
<div className="w-full px-2">
|
||||||
<CarouselContent>
|
{displayAudio.length > 0 && (
|
||||||
{Array.from({ length: 5 }).map((_, index) => (
|
<div>
|
||||||
<CarouselItem key={index}>
|
<div className="flex justify-between items-center mb-2">
|
||||||
<div className="p-1 flex flex-row md:basis-1/2 lg:basis-1/2 gap-3">
|
<h2 className="text-xl font-semibold">Audio</h2>
|
||||||
{displayAudio?.map((audio: any) => (
|
<Link
|
||||||
<Link
|
href={"/shared/curated-content/giat-routine/video/all"}
|
||||||
href={`/shared/curated-content//giat-routine/audio/detail/${audio.id}`}
|
className="text-sm text-gray-500 hover:text-gray-700 flex items-center"
|
||||||
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"
|
Lihat Semua <Icon icon="lucide:arrow-right" className="ml-1" />
|
||||||
>
|
</Link>
|
||||||
<div className="flex items-center justify-center bg-red-500 text-white rounded-lg w-12 h-12">
|
</div>
|
||||||
<svg
|
<Carousel className="w-full">
|
||||||
width="28"
|
<CarouselContent>
|
||||||
height="28"
|
{displayAudio.map((audio, index) => (
|
||||||
viewBox="0 0 32 34"
|
<CarouselItem key={index} className="md:basis-1/3 lg:basis-1/3">
|
||||||
fill="null"
|
<div className="p-2">
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<Card className=" shadow-md rounded-lg overflow-hidden">
|
||||||
>
|
<Link
|
||||||
<path
|
href={`/shared/curated-content/giat-routine/audio/detail/${audio.id}`}
|
||||||
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"
|
<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>
|
<svg
|
||||||
</div>
|
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="flex flex-col flex-1">
|
||||||
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
<div className="font-semibold text-gray-900 dark:text-white mt-1 text-sm">
|
||||||
{audio?.title}
|
{audio?.title}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</CarouselItem>
|
||||||
))}
|
))}
|
||||||
</div>
|
</CarouselContent>
|
||||||
</CarouselItem>
|
<CarouselPrevious />
|
||||||
))}
|
<CarouselNext />
|
||||||
</CarouselContent>
|
</Carousel>
|
||||||
<CarouselPrevious />
|
</div>
|
||||||
<CarouselNext />
|
)}
|
||||||
</Carousel>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -574,35 +574,36 @@ export default function DetailAudio() {
|
||||||
key={data.id}
|
key={data.id}
|
||||||
className="flex items-center gap-3 mt-2"
|
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" />
|
<Music className="object-cover w-32 h-32" />
|
||||||
<div className="flex flex-wrap lg:flex-row gap-3 items-center">
|
<div className="flex flex-wrap lg:flex-row gap-3 items-center">
|
||||||
{/* Mabes Checkbox */}
|
{/* Mabes Checkbox */}
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={data.placements === "mabes"} // Automatically checks if placement matches
|
checked={data.placements === "mabes"}
|
||||||
disabled // To reflect read-only behavior
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Nasional</span>
|
<span>Nasional</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* Polda Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={data.placements === "polda"} // Automatically checks if placement matches
|
checked={data.placements === "polda"}
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Wilayah</span>
|
<span>Wilayah</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* International Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<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
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>International</span>
|
<span>International</span>
|
||||||
|
|
|
||||||
|
|
@ -580,28 +580,33 @@ export default function DetailDocument() {
|
||||||
alt={data.fileName}
|
alt={data.fileName}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-wrap lg:flex-row gap-3 items-center">
|
<div className="flex flex-wrap lg:flex-row gap-3 items-center">
|
||||||
{/* Mabes Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={data.placements === "mabes"} // Automatically checks if placement matches
|
checked={data.placements === "mabes"}
|
||||||
disabled // To reflect read-only behavior
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Nasional</span>
|
<span>Nasional</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* Polda Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={data.placements === "polda"} // Automatically checks if placement matches
|
checked={data.placements === "polda"}
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Wilayah</span>
|
<span>Wilayah</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* International Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<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
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>International</span>
|
<span>International</span>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { Link } from "@/components/navigation";
|
import { Link } from "@/components/navigation";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
import {
|
import {
|
||||||
Carousel,
|
Carousel,
|
||||||
CarouselContent,
|
CarouselContent,
|
||||||
|
|
@ -30,14 +31,6 @@ const TeksSliderPage = () => {
|
||||||
initFetch();
|
initFetch();
|
||||||
}, [page, limit, search]);
|
}, [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 initFetch = async () => {
|
||||||
const response = await listCuratedContent(search, limit, page - 1, 3, "1");
|
const response = await listCuratedContent(search, limit, page - 1, 3, "1");
|
||||||
console.log(response);
|
console.log(response);
|
||||||
|
|
@ -47,77 +40,85 @@ const TeksSliderPage = () => {
|
||||||
setHasData(displayDocument && displayDocument.length > 0);
|
setHasData(displayDocument && displayDocument.length > 0);
|
||||||
setDisplayDocument(contentData);
|
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 (
|
return (
|
||||||
<Carousel className="w-full pr-3">
|
<div className="w-full px-2">
|
||||||
<CarouselContent>
|
{displayDocument.length > 0 && (
|
||||||
<CarouselItem>
|
<div>
|
||||||
<div className="p-1 flex flex-row md:basis-1/2 lg:basis-1/3 gap-3">
|
<div className="flex justify-between items-center mb-2">
|
||||||
{displayDocument?.map((document: any) => (
|
<h2 className="text-xl font-semibold">Teks</h2>
|
||||||
<Link
|
<Link
|
||||||
href={`/shared/curated-content/giat-routine/document/detail/${document.id}`}
|
href={"/shared/curated-content/giat-routine/video/all"}
|
||||||
key={document?.id}
|
className="text-sm text-gray-500 hover:text-gray-700 flex items-center"
|
||||||
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"
|
>
|
||||||
>
|
Lihat Semua <Icon icon="lucide:arrow-right" className="ml-1" />
|
||||||
<div className="flex items-center justify-center rounded-lg w-16 h-16">
|
</Link>
|
||||||
<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>
|
</div>
|
||||||
</CarouselItem>
|
<Carousel className="w-full">
|
||||||
</CarouselContent>
|
<CarouselContent>
|
||||||
<CarouselPrevious />
|
{displayDocument.map((document, index) => (
|
||||||
<CarouselNext />
|
<CarouselItem key={index} className="md:basis-1/3 lg:basis-1/3">
|
||||||
</Carousel>
|
<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>
|
</div>
|
||||||
<div className="ml-5 pb-3">
|
<div className="ml-5 pb-3">
|
||||||
<div className="flex justify-between items-center mx-3">
|
<div className="flex justify-between items-center mx-3"></div>
|
||||||
<Label className="text-base">Image</Label>
|
|
||||||
</div>
|
|
||||||
<div className="px-5 my-5">
|
<div className="px-5 my-5">
|
||||||
<ImageSliderPage />
|
<ImageSliderPage />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ import { getCookiesDecrypt } from "@/lib/utils";
|
||||||
import { close, loading } from "@/lib/swal";
|
import { close, loading } from "@/lib/swal";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { htmlToString } from "@/utils/globals";
|
import { htmlToString } from "@/utils/globals";
|
||||||
|
import { Link } from "@/i18n/routing";
|
||||||
|
|
||||||
const detailSchema = z.object({
|
const detailSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
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>
|
<p className="text-blue-500">Kotak Saran (0)</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Link
|
||||||
<Button>Content Rewrite</Button>
|
href={
|
||||||
|
"/shared/curated-content/giat-routine/image/detail/content-rewrite"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button>Content Rewrite</Button>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -534,25 +540,31 @@ export default function DetailImage() {
|
||||||
{/* Mabes Checkbox */}
|
{/* Mabes Checkbox */}
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={data.placements === "mabes"} // Automatically checks if placement matches
|
checked={data.placements === "mabes"}
|
||||||
disabled // To reflect read-only behavior
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Nasional</span>
|
<span>Nasional</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* Polda Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={data.placements === "polda"} // Automatically checks if placement matches
|
checked={data.placements === "polda"}
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Wilayah</span>
|
<span>Wilayah</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* International Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<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
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>International</span>
|
<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";
|
} from "@/components/ui/carousel";
|
||||||
import { listCuratedContent } from "@/service/curated-content/curated-content";
|
import { listCuratedContent } from "@/service/curated-content/curated-content";
|
||||||
|
|
||||||
import {
|
import { formatDateToIndonesian } from "@/utils/globals";
|
||||||
formatDateToIndonesian,
|
|
||||||
generateLocalizedPath,
|
|
||||||
textEllipsis,
|
|
||||||
} from "@/utils/globals";
|
|
||||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||||
import {
|
import { useRouter } from "next/navigation";
|
||||||
SortingState,
|
import React, { useEffect, useState } from "react";
|
||||||
ColumnFiltersState,
|
|
||||||
VisibilityState,
|
type ImageData = {
|
||||||
PaginationState,
|
id: string;
|
||||||
} from "@tanstack/react-table";
|
title: string;
|
||||||
import {
|
createdAt: string;
|
||||||
useParams,
|
timezone: string;
|
||||||
usePathname,
|
thumbnailLink: string;
|
||||||
useRouter,
|
clickCount: string;
|
||||||
useSearchParams,
|
};
|
||||||
} from "next/navigation";
|
|
||||||
import React, { Component, useEffect, useState } from "react";
|
|
||||||
|
|
||||||
const ImageSliderPage = () => {
|
const ImageSliderPage = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const [imageData, setImageData] = useState<ImageData[]>([]);
|
||||||
const [imageData, setImageData] = useState<any>();
|
|
||||||
const [displayImage, setDisplayImage] = useState<any[]>([]);
|
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit] = useState(10);
|
||||||
const [search, setSearch] = React.useState("");
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [page, limit, search]);
|
}, [page]);
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (imageData?.length > 0) {
|
|
||||||
// shuffleAndSetVideos();
|
|
||||||
// const interval = setInterval(shuffleAndSetVideos, 5000);
|
|
||||||
// return () => clearInterval(interval); // Cleanup interval on unmount
|
|
||||||
// }
|
|
||||||
// }, [imageData]);
|
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const response = await listCuratedContent(search, limit, page - 1, 1, "1");
|
const response = await listCuratedContent("", limit, page - 1, 1, "1");
|
||||||
console.log(response);
|
const data = response?.data?.data?.content || [];
|
||||||
|
setImageData(data);
|
||||||
const data = response?.data?.data;
|
|
||||||
const contentData = data?.content;
|
|
||||||
setImageData(contentData);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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 (
|
return (
|
||||||
<Carousel className="w-full pr-3">
|
<div className="w-full px-2">
|
||||||
<CarouselContent>
|
{imageData.length > 0 && (
|
||||||
{Array.from({ length: 5 }).map((_, index) => (
|
<div>
|
||||||
<CarouselItem key={index}>
|
<div className="flex justify-between items-center mb-2">
|
||||||
<div className="p-1 flex flex-row md:basis-1/2 lg:basis-1/2 gap-3">
|
<h2 className="text-xl font-semibold">Foto</h2>
|
||||||
{imageData?.map((image: any) => (
|
<Link
|
||||||
<Card
|
href={"/shared/curated-content/giat-routine/image/all"}
|
||||||
key={image?.id}
|
className="text-sm text-gray-500 hover:text-gray-700 flex items-center"
|
||||||
className="hover:sc ale-110 transition-transform duration-300"
|
>
|
||||||
>
|
Lihat Semua <Icon icon="lucide:arrow-right" className="ml-1" />
|
||||||
<Link
|
</Link>
|
||||||
href={`/shared/curated-content//giat-routine/image/detail/${image.id}`}
|
</div>
|
||||||
>
|
<Carousel className="w-full">
|
||||||
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
|
<CarouselContent>
|
||||||
<img
|
{imageData.map((image, index) => (
|
||||||
src={image?.thumbnailLink}
|
<CarouselItem key={index} className="md:basis-1/3 lg:basis-1/3">
|
||||||
className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg"
|
<div className="p-2">
|
||||||
/>
|
<Card className="shadow-md rounded-lg overflow-hidden">
|
||||||
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">
|
<Link
|
||||||
{formatDateToIndonesian(new Date(image?.createdAt))}{" "}
|
href={`/shared/curated-content/giat-routine/image/detail/${image.id}`}
|
||||||
{image?.timezone ? image?.timezone : "WIB"}|{" "}
|
>
|
||||||
<Icon icon="formkit:eye" width="15" height="15" />
|
<CardContent className="p-0">
|
||||||
{image?.clickCount}{" "}
|
<img
|
||||||
<svg
|
src={image?.thumbnailLink}
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
alt={image?.title}
|
||||||
width="1em"
|
className="w-full h-56 object-cover rounded-t-lg"
|
||||||
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"
|
|
||||||
/>
|
/>
|
||||||
</svg>{" "}
|
<div className="p-3">
|
||||||
</div>
|
<p className="text-xs text-gray-500">
|
||||||
<div className="font-semibold pr-3 pb-3 mx-2 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible w-full">
|
{formatDateToIndonesian(
|
||||||
{image?.title}
|
new Date(image?.createdAt)
|
||||||
</div>
|
)}{" "}
|
||||||
</CardContent>
|
{image?.timezone || "WIB"} |
|
||||||
</Link>
|
<Icon
|
||||||
</Card>
|
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>
|
</CarouselContent>
|
||||||
</CarouselItem>
|
<CarouselPrevious />
|
||||||
))}
|
<CarouselNext />
|
||||||
</CarouselContent>
|
</Carousel>
|
||||||
<CarouselPrevious />
|
</div>
|
||||||
<CarouselNext />
|
)}
|
||||||
</Carousel>
|
</div>
|
||||||
// <div className="mx-3 px-5">
|
|
||||||
// <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
||||||
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import {
|
||||||
CarouselNext,
|
CarouselNext,
|
||||||
CarouselPrevious,
|
CarouselPrevious,
|
||||||
} from "@/components/ui/carousel";
|
} from "@/components/ui/carousel";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
import { listCuratedContent } from "@/service/curated-content/curated-content";
|
import { listCuratedContent } from "@/service/curated-content/curated-content";
|
||||||
import { getListContent } from "@/service/landing/landing";
|
import { getListContent } from "@/service/landing/landing";
|
||||||
import { formatDateToIndonesian } from "@/utils/globals";
|
import { formatDateToIndonesian } from "@/utils/globals";
|
||||||
|
|
@ -15,9 +16,18 @@ import { Icon } from "@iconify/react/dist/iconify.js";
|
||||||
import image from "next/image";
|
import image from "next/image";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
type VideoData = {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
createdAt: string;
|
||||||
|
timezone: string;
|
||||||
|
thumbnailLink: string;
|
||||||
|
clickCount: string;
|
||||||
|
};
|
||||||
|
|
||||||
const VideoSliderPage = () => {
|
const VideoSliderPage = () => {
|
||||||
const [allVideoData, setAllVideoData] = useState<any[]>([]);
|
const [allVideoData, setAllVideoData] = useState<any[]>([]);
|
||||||
const [displayVideos, setDisplayVideos] = useState<any[]>([]);
|
const [videoData, setVideoData] = useState<VideoData[]>([]);
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
|
|
@ -26,86 +36,74 @@ const VideoSliderPage = () => {
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [page, limit, search]);
|
}, [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 fetchData = async () => {
|
||||||
const response = await listCuratedContent(search, limit, page - 1, 2, "1");
|
const response = await listCuratedContent(search, limit, page - 1, 2, "1");
|
||||||
console.log(response);
|
console.log(response);
|
||||||
|
|
||||||
const data = response?.data?.data;
|
const data = response?.data?.data;
|
||||||
const contentData = data?.content;
|
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 (
|
return (
|
||||||
<Carousel className="w-full pr-3">
|
<div className="w-full px-2">
|
||||||
<CarouselContent>
|
{videoData.length > 0 && (
|
||||||
{Array.from({ length: 5 }).map((_, index) => (
|
<div>
|
||||||
<CarouselItem key={index}>
|
<div className="flex justify-between items-center mb-2">
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
<h2 className="text-xl font-semibold">Video</h2>
|
||||||
{allVideoData.map((video: any) => (
|
<Link
|
||||||
<Card
|
href={"/shared/curated-content/giat-routine/video/all"}
|
||||||
key={video?.id}
|
className="text-sm text-gray-500 hover:text-gray-700 flex items-center"
|
||||||
className="hover:scale-110 transition-transform duration-300"
|
>
|
||||||
>
|
Lihat Semua <Icon icon="lucide:arrow-right" className="ml-1" />
|
||||||
<Link
|
</Link>
|
||||||
href={`/shared/curated-content/giat-routine/video/detail/${video.id}`}
|
</div>
|
||||||
>
|
<Carousel className="w-full">
|
||||||
<CardContent className="flex flex-col text-xs lg:text-sm w-full p-0">
|
<CarouselContent>
|
||||||
<img
|
{videoData.map((video, index) => (
|
||||||
src={video?.thumbnailLink}
|
<CarouselItem key={index} className="md:basis-1/3 lg:basis-1/3">
|
||||||
className="h-60 object-cover items-center justify-center cursor-pointer rounded-lg"
|
<div className="p-2">
|
||||||
/>
|
<Card className="shadow-md rounded-lg overflow-hidden">
|
||||||
<div className="flex flex-row items-center gap-2 text-[10px] mx-2">
|
<Link
|
||||||
{formatDateToIndonesian(new Date(video?.createdAt))}{" "}
|
href={`/shared/curated-content/giat-routine/video/detail/${video.id}`}
|
||||||
{video?.timezone || "WIB"} |
|
>
|
||||||
<Icon icon="formkit:eye" width="15" height="15" />
|
<CardContent className="p-0">
|
||||||
{video?.clickCount}
|
<img
|
||||||
<svg
|
src={video?.thumbnailLink}
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
alt={video?.title}
|
||||||
width="1em"
|
className="w-full h-56 object-cover rounded-t-lg"
|
||||||
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"
|
|
||||||
/>
|
/>
|
||||||
</svg>
|
<div className="p-3">
|
||||||
</div>
|
<p className="text-xs text-gray-500">
|
||||||
<div className="font-semibold pr-3 pb-3 mx-2 hover:h-auto truncate hover:whitespace-normal hover:overflow-visible w-full">
|
{formatDateToIndonesian(
|
||||||
{video?.title}
|
new Date(video?.createdAt)
|
||||||
</div>
|
)}{" "}
|
||||||
</CardContent>
|
{video?.timezone || "WIB"} |
|
||||||
</Link>
|
<Icon
|
||||||
</Card>
|
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>
|
</CarouselContent>
|
||||||
</CarouselItem>
|
<CarouselPrevious />
|
||||||
))}
|
<CarouselNext />
|
||||||
</CarouselContent>
|
</Carousel>
|
||||||
<CarouselPrevious />
|
</div>
|
||||||
<CarouselNext />
|
)}
|
||||||
</Carousel>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -523,39 +523,39 @@ export default function DetailImage() {
|
||||||
key={data.id}
|
key={data.id}
|
||||||
className="flex items-center gap-3 mt-2"
|
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
|
<img
|
||||||
className="object-cover w-20 h-20 lg:w-32 lg:h-32"
|
className="object-cover w-20 h-20 lg:w-32 lg:h-32"
|
||||||
src={"/assets/video-icon.webp"}
|
src={"/assets/video-icon.webp"}
|
||||||
alt={` ${data.id}`}
|
alt={` ${data.id}`}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-wrap lg:flex-row gap-3 items-center">
|
<div className="flex flex-wrap lg:flex-row gap-3 items-center">
|
||||||
{/* Mabes Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={data.placements === "mabes"} // Automatically checks if placement matches
|
checked={data.placements === "mabes"}
|
||||||
disabled // To reflect read-only behavior
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Nasional</span>
|
<span>Nasional</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* Polda Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={data.placements === "polda"} // Automatically checks if placement matches
|
checked={data.placements === "polda"}
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Wilayah</span>
|
<span>Wilayah</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* International Checkbox */}
|
|
||||||
<label className=" cursor-pointer flex items-center gap-2">
|
<label className=" cursor-pointer flex items-center gap-2">
|
||||||
<Checkbox
|
<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
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>International</span>
|
<span>International</span>
|
||||||
|
|
|
||||||
|
|
@ -24,15 +24,19 @@ import AudioSliderPage from "./giat-routine/audio/audio";
|
||||||
import ImageSliderPage from "./giat-routine/image/image";
|
import ImageSliderPage from "./giat-routine/image/image";
|
||||||
import TeksSliderPage from "./giat-routine/document/teks";
|
import TeksSliderPage from "./giat-routine/document/teks";
|
||||||
import ContestTable from "../contest/components/contest-table";
|
import ContestTable from "../contest/components/contest-table";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
const CuratedContentPage = () => {
|
const CuratedContentPage = () => {
|
||||||
|
const t = useTranslations("Curation");
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SiteBreadcrumb />
|
<SiteBreadcrumb />
|
||||||
<div className="my-3">
|
<div className="my-3">
|
||||||
<Tabs defaultValue="giat-routine" className="w-full">
|
<Tabs defaultValue="giat-routine" className="w-full">
|
||||||
<Card className="py-3 px-2 my-4">
|
<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">
|
<TabsList className="flex-wrap">
|
||||||
<TabsTrigger
|
<TabsTrigger
|
||||||
value="giat-routine"
|
value="giat-routine"
|
||||||
|
|
@ -73,80 +77,15 @@ const CuratedContentPage = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-5 pb-3">
|
<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">
|
<div className="px-5 my-5">
|
||||||
<VideoSliderPage />
|
<VideoSliderPage />
|
||||||
</div>
|
</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">
|
<div className="px-5 my-5">
|
||||||
<AudioSliderPage />
|
<AudioSliderPage />
|
||||||
</div>
|
</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">
|
<div className="px-5 my-5">
|
||||||
<ImageSliderPage />
|
<ImageSliderPage />
|
||||||
</div>
|
</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">
|
<div className="px-5 my-5">
|
||||||
<TeksSliderPage />
|
<TeksSliderPage />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -442,7 +442,22 @@ export default function FormAudio() {
|
||||||
return;
|
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,
|
...data,
|
||||||
title: finalTitle,
|
title: finalTitle,
|
||||||
description: finalDescription,
|
description: finalDescription,
|
||||||
|
|
@ -461,6 +476,10 @@ export default function FormAudio() {
|
||||||
|
|
||||||
let id = Cookies.get("idCreate");
|
let id = Cookies.get("idCreate");
|
||||||
|
|
||||||
|
if (scheduleId !== undefined) {
|
||||||
|
requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini
|
||||||
|
}
|
||||||
|
|
||||||
if (id == undefined) {
|
if (id == undefined) {
|
||||||
const response = await createMedia(requestData);
|
const response = await createMedia(requestData);
|
||||||
console.log("Form Data Submitted:", requestData);
|
console.log("Form Data Submitted:", requestData);
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ import { options } from "@fullcalendar/core/preact.js";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { getCsrfToken } from "@/service/auth";
|
import { getCsrfToken } from "@/service/auth";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
|
import { request } from "http";
|
||||||
|
|
||||||
interface FileWithPreview extends File {
|
interface FileWithPreview extends File {
|
||||||
preview: string;
|
preview: string;
|
||||||
|
|
@ -443,11 +444,28 @@ export default function FormImage() {
|
||||||
const finalTags = tags.join(", ");
|
const finalTags = tags.join(", ");
|
||||||
const finalTitle = isSwitchOn ? title : data.title;
|
const finalTitle = isSwitchOn ? title : data.title;
|
||||||
const finalDescription = articleBody || data.description;
|
const finalDescription = articleBody || data.description;
|
||||||
|
|
||||||
if (!finalDescription.trim()) {
|
if (!finalDescription.trim()) {
|
||||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||||
return;
|
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,
|
...data,
|
||||||
title: finalTitle,
|
title: finalTitle,
|
||||||
description: finalDescription,
|
description: finalDescription,
|
||||||
|
|
@ -466,14 +484,14 @@ export default function FormImage() {
|
||||||
|
|
||||||
let id = Cookies.get("idCreate");
|
let id = Cookies.get("idCreate");
|
||||||
|
|
||||||
|
if (scheduleId !== undefined) {
|
||||||
|
requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini
|
||||||
|
}
|
||||||
|
|
||||||
if (id == undefined) {
|
if (id == undefined) {
|
||||||
const response = await createMedia(requestData);
|
const response = await createMedia(requestData);
|
||||||
console.log("Form Data Submitted:", 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 });
|
Cookies.set("idCreate", response?.data?.data, { expires: 1 });
|
||||||
id = response?.data?.data;
|
id = response?.data?.data;
|
||||||
|
|
||||||
|
|
@ -489,16 +507,15 @@ export default function FormImage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload File
|
// Upload File
|
||||||
const progressInfoArr = [];
|
const progressInfoArr = files.map((item) => ({
|
||||||
for (const item of files) {
|
percentage: 0,
|
||||||
progressInfoArr.push({ percentage: 0, fileName: item.name });
|
fileName: item.name,
|
||||||
}
|
}));
|
||||||
progressInfo = progressInfoArr;
|
progressInfo = progressInfoArr;
|
||||||
setIsStartUpload(true);
|
setIsStartUpload(true);
|
||||||
setProgressList(progressInfoArr);
|
setProgressList(progressInfoArr);
|
||||||
|
|
||||||
close();
|
close();
|
||||||
// showProgress();
|
|
||||||
files.map(async (item: any, index: number) => {
|
files.map(async (item: any, index: number) => {
|
||||||
await uploadResumableFile(
|
await uploadResumableFile(
|
||||||
index,
|
index,
|
||||||
|
|
@ -509,8 +526,6 @@ export default function FormImage() {
|
||||||
});
|
});
|
||||||
|
|
||||||
Cookies.remove("idCreate");
|
Cookies.remove("idCreate");
|
||||||
|
|
||||||
// MySwal.fire("Sukses", "Data berhasil disimpan.", "success");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = (data: ImageSchema) => {
|
const onSubmit = (data: ImageSchema) => {
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,33 @@ export default function FormConvertSPIT() {
|
||||||
return temp;
|
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: {
|
const save = async (data: {
|
||||||
contentTitle: string;
|
contentTitle: string;
|
||||||
contentDescription: string;
|
contentDescription: string;
|
||||||
|
|
@ -785,6 +812,66 @@ export default function FormConvertSPIT() {
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<Label className="text-xl">Penempatan file</Label>
|
<Label className="text-xl">Penempatan file</Label>
|
||||||
</div>
|
</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) => (
|
{files?.map((file, index) => (
|
||||||
<div
|
<div
|
||||||
key={file.contentId}
|
key={file.contentId}
|
||||||
|
|
|
||||||
|
|
@ -441,7 +441,22 @@ export default function FormTeks() {
|
||||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||||
return;
|
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,
|
...data,
|
||||||
title: finalTitle,
|
title: finalTitle,
|
||||||
description: finalDescription,
|
description: finalDescription,
|
||||||
|
|
@ -460,6 +475,10 @@ export default function FormTeks() {
|
||||||
|
|
||||||
let id = Cookies.get("idCreate");
|
let id = Cookies.get("idCreate");
|
||||||
|
|
||||||
|
if (scheduleId !== undefined) {
|
||||||
|
requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini
|
||||||
|
}
|
||||||
|
|
||||||
if (id == undefined) {
|
if (id == undefined) {
|
||||||
const response = await createMedia(requestData);
|
const response = await createMedia(requestData);
|
||||||
console.log("Form Data Submitted:", requestData);
|
console.log("Form Data Submitted:", requestData);
|
||||||
|
|
|
||||||
|
|
@ -441,7 +441,22 @@ export default function FormVideo() {
|
||||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||||
return;
|
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,
|
...data,
|
||||||
title: finalTitle,
|
title: finalTitle,
|
||||||
description: finalDescription,
|
description: finalDescription,
|
||||||
|
|
@ -460,6 +475,10 @@ export default function FormVideo() {
|
||||||
|
|
||||||
let id = Cookies.get("idCreate");
|
let id = Cookies.get("idCreate");
|
||||||
|
|
||||||
|
if (scheduleId !== undefined) {
|
||||||
|
requestData.attachFromScheduleId = Number(scheduleId); // ✅ Tambahkan nilai ini
|
||||||
|
}
|
||||||
|
|
||||||
if (id == undefined) {
|
if (id == undefined) {
|
||||||
const response = await createMedia(requestData);
|
const response = await createMedia(requestData);
|
||||||
console.log("Form Data Submitted:", requestData);
|
console.log("Form Data Submitted:", requestData);
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ export default function FormContestDetail() {
|
||||||
mabes: false,
|
mabes: false,
|
||||||
polda: false,
|
polda: false,
|
||||||
polres: false,
|
polres: false,
|
||||||
|
satker: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
@ -224,18 +225,17 @@ export default function FormContestDetail() {
|
||||||
}, [detail?.targetOutput]);
|
}, [detail?.targetOutput]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (detail?.targetParticipantTopLevel) {
|
if (detail?.targetOutput) {
|
||||||
const outputSet = new Set(
|
const outputSet = new Set(detail.targetOutput.split(",").map(Number));
|
||||||
detail.targetParticipantTopLevel.split(",").map(Number)
|
|
||||||
);
|
|
||||||
setUnitSelection({
|
setUnitSelection({
|
||||||
allUnit: outputSet.has(0),
|
allUnit: outputSet.has(0),
|
||||||
mabes: outputSet.has(1),
|
mabes: outputSet.has(1),
|
||||||
polda: outputSet.has(2),
|
polda: outputSet.has(2),
|
||||||
polres: outputSet.has(3),
|
polres: outputSet.has(3),
|
||||||
|
satker: outputSet.has(4),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [detail?.targetParticipantTopLevel]);
|
}, [detail?.targetOutput]);
|
||||||
|
|
||||||
const handleCheckboxChange = (levelId: number) => {
|
const handleCheckboxChange = (levelId: number) => {
|
||||||
setCheckedLevels((prev) => {
|
setCheckedLevels((prev) => {
|
||||||
|
|
@ -267,6 +267,7 @@ export default function FormContestDetail() {
|
||||||
mabes: "1",
|
mabes: "1",
|
||||||
polda: "2",
|
polda: "2",
|
||||||
polres: "3",
|
polres: "3",
|
||||||
|
satker: "4",
|
||||||
};
|
};
|
||||||
|
|
||||||
const assignmentPurposeString = Object.keys(unitSelection)
|
const assignmentPurposeString = Object.keys(unitSelection)
|
||||||
|
|
@ -436,7 +437,7 @@ export default function FormContestDetail() {
|
||||||
fileTypeId: string,
|
fileTypeId: string,
|
||||||
duration: string
|
duration: string
|
||||||
) {
|
) {
|
||||||
console.log(idx, id, file, fileTypeId, duration);
|
console.log("Param Upload : ", idx, id, file, fileTypeId, duration);
|
||||||
|
|
||||||
const resCsrf = await getCsrfToken();
|
const resCsrf = await getCsrfToken();
|
||||||
const csrfToken = resCsrf?.data?.token;
|
const csrfToken = resCsrf?.data?.token;
|
||||||
|
|
@ -451,7 +452,7 @@ export default function FormContestDetail() {
|
||||||
retryDelays: [0, 3000, 6000, 12_000, 24_000],
|
retryDelays: [0, 3000, 6000, 12_000, 24_000],
|
||||||
chunkSize: 20_000,
|
chunkSize: 20_000,
|
||||||
metadata: {
|
metadata: {
|
||||||
assignmentId: id,
|
contestId: id,
|
||||||
filename: file.name,
|
filename: file.name,
|
||||||
contentType: file.type,
|
contentType: file.type,
|
||||||
fileTypeId: fileTypeId,
|
fileTypeId: fileTypeId,
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import {
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from "@/components/ui/popover";
|
} from "@/components/ui/popover";
|
||||||
import { cn } from "@/lib/utils";
|
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 { Calendar } from "@/components/ui/calendar";
|
||||||
import { addDays, format, parseISO, setDate } from "date-fns";
|
import { addDays, format, parseISO, setDate } from "date-fns";
|
||||||
import { DateRange } from "react-day-picker";
|
import { DateRange } from "react-day-picker";
|
||||||
|
|
@ -30,6 +30,7 @@ import { error, loading } from "@/lib/swal";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import {
|
import {
|
||||||
detailSchedule,
|
detailSchedule,
|
||||||
|
getListScheduleAttachment,
|
||||||
listScheduleNext,
|
listScheduleNext,
|
||||||
listScheduleToday,
|
listScheduleToday,
|
||||||
postSchedule,
|
postSchedule,
|
||||||
|
|
@ -61,6 +62,14 @@ interface Detail {
|
||||||
addressLong: number;
|
addressLong: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Attachment {
|
||||||
|
id: any;
|
||||||
|
title: string;
|
||||||
|
fileTypeId: number;
|
||||||
|
type: number;
|
||||||
|
fileTypeName: string;
|
||||||
|
}
|
||||||
|
|
||||||
export default function FormEventDetail() {
|
export default function FormEventDetail() {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const { id } = useParams() as { id: string };
|
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() {
|
async function getDataByDate() {
|
||||||
const resToday = await listScheduleToday();
|
const resToday = await listScheduleToday();
|
||||||
const today = resToday?.data?.data;
|
const today = resToday?.data?.data;
|
||||||
|
|
@ -120,6 +137,7 @@ export default function FormEventDetail() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initState();
|
initState();
|
||||||
|
getDataAttachment();
|
||||||
}, [refresh, setValue]);
|
}, [refresh, setValue]);
|
||||||
|
|
||||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
|
@ -130,6 +148,29 @@ export default function FormEventDetail() {
|
||||||
setEndTime(e.target.value);
|
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 (
|
return (
|
||||||
<div className="flex flex-col lg:flex-row gap-2">
|
<div className="flex flex-col lg:flex-row gap-2">
|
||||||
<Card className="w-full lg:w-9/12">
|
<Card className="w-full lg:w-9/12">
|
||||||
|
|
@ -336,92 +377,67 @@ export default function FormEventDetail() {
|
||||||
<Button color="primary" size="sm" type="button">
|
<Button color="primary" size="sm" type="button">
|
||||||
<Plus /> Tambah Lampiran
|
<Plus /> Tambah Lampiran
|
||||||
</Button>
|
</Button>
|
||||||
<p>0 Lampiran</p>
|
<p>{lampiran?.length || 0} Lampiran</p>
|
||||||
</div>
|
</div>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="max-w-md p-6 bg-white rounded-lg shadow-lg h-[420px] w-[700px]">
|
<DialogContent className="max-w-md p-6 bg-white rounded-lg shadow-lg h-[420px] w-[700px]">
|
||||||
<h2 className="text-lg font-semibold">
|
<h2 className="text-lg font-semibold">
|
||||||
Pilih Jenis Lampiran
|
Pilih Jenis Lampiran
|
||||||
</h2>
|
</h2>
|
||||||
<div className=" space-y-4 gap-y-4">
|
<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">
|
type: 2,
|
||||||
<img
|
img: "/assets/img/upload-video.png",
|
||||||
src={"/assets/img/upload-video.png"}
|
label: "Audio Visual",
|
||||||
alt={"item.label"}
|
},
|
||||||
className="w-12 h-12"
|
{
|
||||||
/>
|
type: 1,
|
||||||
<h3 className="text-base font-semibold">
|
img: "/assets/img/upload-image.png",
|
||||||
Audio Visual
|
label: "Foto",
|
||||||
</h3>
|
},
|
||||||
|
{
|
||||||
|
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>
|
||||||
<div className="w-8/12">
|
</a>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
@ -430,7 +446,52 @@ export default function FormEventDetail() {
|
||||||
""
|
""
|
||||||
)}
|
)}
|
||||||
</div>
|
</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">
|
<Button type="submit" color="primary">
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import {
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from "@/components/ui/popover";
|
} from "@/components/ui/popover";
|
||||||
import { cn } from "@/lib/utils";
|
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 { Calendar } from "@/components/ui/calendar";
|
||||||
import { addDays, format, parseISO, setDate } from "date-fns";
|
import { addDays, format, parseISO, setDate } from "date-fns";
|
||||||
import { DateRange } from "react-day-picker";
|
import { DateRange } from "react-day-picker";
|
||||||
|
|
@ -30,6 +30,7 @@ import { error, loading } from "@/lib/swal";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import {
|
import {
|
||||||
detailSchedule,
|
detailSchedule,
|
||||||
|
getListScheduleAttachment,
|
||||||
listScheduleNext,
|
listScheduleNext,
|
||||||
listScheduleToday,
|
listScheduleToday,
|
||||||
postSchedule,
|
postSchedule,
|
||||||
|
|
@ -50,6 +51,7 @@ import {
|
||||||
import { formatDate } from "@fullcalendar/core/index.js";
|
import { formatDate } from "@fullcalendar/core/index.js";
|
||||||
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
|
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
|
||||||
import { Link } from "@/i18n/routing";
|
import { Link } from "@/i18n/routing";
|
||||||
|
import $ from "jquery";
|
||||||
|
|
||||||
const taskSchema = z.object({
|
const taskSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
|
|
@ -68,6 +70,14 @@ interface Detail {
|
||||||
addressLong: number;
|
addressLong: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Attachment {
|
||||||
|
id: any;
|
||||||
|
title: string;
|
||||||
|
fileTypeId: number;
|
||||||
|
type: number;
|
||||||
|
fileTypeName: string;
|
||||||
|
}
|
||||||
|
|
||||||
export default function FormDetailPressRillis() {
|
export default function FormDetailPressRillis() {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const { id } = useParams() as { id: string };
|
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() {
|
async function getDataByDate() {
|
||||||
const resToday = await listScheduleToday();
|
const resToday = await listScheduleToday();
|
||||||
const today = resToday?.data?.data;
|
const today = resToday?.data?.data;
|
||||||
|
|
@ -129,6 +147,7 @@ export default function FormDetailPressRillis() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initState();
|
initState();
|
||||||
|
getDataAttachment();
|
||||||
}, [refresh, setValue]);
|
}, [refresh, setValue]);
|
||||||
|
|
||||||
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleStartTime = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
|
@ -139,20 +158,26 @@ export default function FormDetailPressRillis() {
|
||||||
setEndTime(e.target.value);
|
setEndTime(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUploadAttachment = () => {
|
const handleDestinationUpload = (
|
||||||
const scheduleId = Cookies.get("scheduleId");
|
type: number,
|
||||||
|
id: string | number,
|
||||||
|
setOpen: (open: boolean) => void,
|
||||||
|
router: any
|
||||||
|
) => {
|
||||||
|
setOpen(false); // Tutup modal dialog
|
||||||
|
|
||||||
if (scheduleId == undefined) {
|
if (id !== undefined) {
|
||||||
MySwal.fire({
|
Cookies.set("scheduleId", id.toString(), { expires: 1 });
|
||||||
title: "Simpan Jadwal Terlebih Dahulu",
|
Cookies.set("scheduleType", "3", { expires: 1 });
|
||||||
icon: "info",
|
|
||||||
confirmButtonColor: "#3085d6",
|
const routes: Record<number, string> = {
|
||||||
confirmButtonText: "Ok",
|
1: "/in/contributor/schedule/media/image/create",
|
||||||
}).then((result) => {
|
2: "/in/contributor/schedule/media/video/create",
|
||||||
if (result.isConfirmed) {
|
3: "/in/contributor/schedule/media/text/create",
|
||||||
return true;
|
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">
|
<Button color="primary" size="sm" type="button">
|
||||||
<Plus /> Tambah Lampiran
|
<Plus /> Tambah Lampiran
|
||||||
</Button>
|
</Button>
|
||||||
<p>0 Lampiran</p>
|
<p>{lampiran?.length || 0} Lampiran</p>
|
||||||
</div>
|
</div>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="max-w-md p-6 bg-white rounded-lg shadow-lg h-[420px] w-[700px]">
|
<DialogContent className="max-w-md p-6 bg-white rounded-lg shadow-lg h-[420px] w-[700px]">
|
||||||
<h2 className="text-lg font-semibold">
|
<h2 className="text-lg font-semibold">
|
||||||
Pilih Jenis Lampiran
|
Pilih Jenis Lampiran
|
||||||
</h2>
|
</h2>
|
||||||
<div className=" space-y-4 gap-y-4">
|
<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">
|
type: 2,
|
||||||
<img
|
img: "/assets/img/upload-video.png",
|
||||||
src={"/assets/img/upload-video.png"}
|
label: "Audio Visual",
|
||||||
alt={"item.label"}
|
},
|
||||||
className="w-12 h-12"
|
{
|
||||||
/>
|
type: 1,
|
||||||
<h3 className="text-base font-semibold">
|
img: "/assets/img/upload-image.png",
|
||||||
Audio Visual
|
label: "Foto",
|
||||||
</h3>
|
},
|
||||||
|
{
|
||||||
|
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>
|
||||||
<div className="w-8/12">
|
</a>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</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">
|
<div className="mt-4 flex justify-end">
|
||||||
<Button type="submit" color="primary">
|
<Button type="submit" color="primary">
|
||||||
Submit
|
Submit
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ const Division = () => {
|
||||||
<div className="mx-auto px-4 w-full">
|
<div className="mx-auto px-4 w-full">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
{/* <Reveal> */}
|
{/* <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" ? (
|
{pathname?.split("/")[1] == "in" ? (
|
||||||
<>
|
<>
|
||||||
{t("coverageOnly")} <span className="text-[#bb3523]">{t("division")}</span>{" "}
|
{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 DateRangePicker from "@/components/date-range-picker";
|
||||||
import { usePathname } from "@/components/navigation";
|
import { usePathname } from "@/components/navigation";
|
||||||
import { cn, getCookiesDecrypt } from "@/lib/utils";
|
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 = ({
|
const PageTitle = ({
|
||||||
title,
|
title,
|
||||||
|
|
@ -30,7 +41,35 @@ const PageTitle = ({
|
||||||
<div className="text-2xl font-medium text-default-800 capitalize">
|
<div className="text-2xl font-medium text-default-800 capitalize">
|
||||||
Dashboard
|
Dashboard
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,8 @@ const LoginForm = () => {
|
||||||
Number(profile?.data?.data?.roleId) == 10 ||
|
Number(profile?.data?.data?.roleId) == 10 ||
|
||||||
Number(profile?.data?.data?.roleId) == 11 ||
|
Number(profile?.data?.data?.roleId) == 11 ||
|
||||||
Number(profile?.data?.data?.roleId) == 12 ||
|
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) {
|
if (profile?.data?.data?.roleId === 18) {
|
||||||
window.location.href = "/in/dashboard/executive";
|
window.location.href = "/in/dashboard/executive";
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ const ProfileInfo = () => {
|
||||||
<div className="text-sm font-medium capitalize lg:block hidden">
|
<div className="text-sm font-medium capitalize lg:block hidden">
|
||||||
{detail?.fullname}
|
{detail?.fullname}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs">({detail?.fullname})</p>
|
<p className="text-xs">({detail?.username})</p>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-base me-2.5 lg:inline-block hidden">
|
<span className="text-base me-2.5 lg:inline-block hidden">
|
||||||
<Icon icon="heroicons-outline:chevron-down"></Icon>
|
<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 React from 'react'
|
||||||
import { Ellipsis, LogOut } from "lucide-react";
|
import { Ellipsis, LogOut } from "lucide-react";
|
||||||
import { usePathname } from "@/components/navigation";
|
import { usePathname } from "@/components/navigation";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn, getCookiesDecrypt } from "@/lib/utils";
|
||||||
import { getMenuList } from "@/lib/menus";
|
import { getMenuList } from "@/lib/menus";
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
import {
|
import {
|
||||||
|
|
@ -26,6 +26,7 @@ import Logo from '@/components/logo';
|
||||||
import SidebarHoverToggle from '@/components/partials/sidebar/sidebar-hover-toggle';
|
import SidebarHoverToggle from '@/components/partials/sidebar/sidebar-hover-toggle';
|
||||||
import { useMenuHoverConfig } from '@/hooks/use-menu-hover';
|
import { useMenuHoverConfig } from '@/hooks/use-menu-hover';
|
||||||
import { useMediaQuery } from '@/hooks/use-media-query';
|
import { useMediaQuery } from '@/hooks/use-media-query';
|
||||||
|
import TeamWorkspaceSwitcher from '../common/team-workspace-switcher';
|
||||||
|
|
||||||
|
|
||||||
export function MenuClassic({ }) {
|
export function MenuClassic({ }) {
|
||||||
|
|
@ -36,7 +37,7 @@ export function MenuClassic({ }) {
|
||||||
const direction = getLangDir(params?.locale ?? '');
|
const direction = getLangDir(params?.locale ?? '');
|
||||||
|
|
||||||
const isDesktop = useMediaQuery('(min-width: 1280px)')
|
const isDesktop = useMediaQuery('(min-width: 1280px)')
|
||||||
|
const userRoleId = getCookiesDecrypt("urie");
|
||||||
|
|
||||||
const menuList = getMenuList(pathname, t);
|
const menuList = getMenuList(pathname, t);
|
||||||
const [config, setConfig] = useConfig()
|
const [config, setConfig] = useConfig()
|
||||||
|
|
@ -71,17 +72,16 @@ export function MenuClassic({ }) {
|
||||||
|
|
||||||
|
|
||||||
<ScrollArea className="[&>div>div[style]]:!block" dir={direction}>
|
<ScrollArea className="[&>div>div[style]]:!block" dir={direction}>
|
||||||
{/* {isDesktop && (
|
{isDesktop && Number(userRoleId) == 19 ? (
|
||||||
<div className={cn(' space-y-3 mt-6 ', {
|
<div className={cn(' space-y-3 mt-6 ', {
|
||||||
'px-4': !collapsed || hovered,
|
'px-4': !collapsed || hovered,
|
||||||
'text-center': collapsed || !hovered
|
'text-center': collapsed || !hovered
|
||||||
})}>
|
})}>
|
||||||
|
<TeamWorkspaceSwitcher />
|
||||||
<TeamSwitcher />
|
{/* <SearchBar /> */}
|
||||||
<SearchBar />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)} */}
|
) : ""}
|
||||||
|
|
||||||
<nav className="mt-4 h-full w-full">
|
<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">
|
<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]
|
? isInternational[0]
|
||||||
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-konten-top10?"
|
? "views/2023_04_MediaHUB-Viz_INTL_Rev202/db-konten-top10?"
|
||||||
: "views/2023_04_MediaHUB-Viz-POLDA_Rev201/db-ranking-polda?"
|
: "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 =
|
const view2 =
|
||||||
levelName == "MABES POLRI"
|
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 Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
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({
|
MySwal.fire({
|
||||||
title: '<p class="text-green-600 font-bold">Sukses</p>',
|
title: '<p class="text-green-600 font-bold">Sukses</p>',
|
||||||
icon: "success",
|
icon: "success",
|
||||||
|
|
@ -38,7 +39,7 @@ export function success(redirect: string): void {
|
||||||
allowOutsideClick: false,
|
allowOutsideClick: false,
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
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 =====
|
// ===== MENU TEMPLATE DASHCODE =====
|
||||||
// {
|
// {
|
||||||
// groupLabel: t("apps"),
|
// groupLabel: t("apps"),
|
||||||
|
|
@ -1527,21 +1591,21 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-conference",
|
href: "/contributor/schedule/press-conference",
|
||||||
label: "konferensi pers",
|
label: t("press-conference"),
|
||||||
active: pathname.includes("/schedule/press-conference"),
|
active: pathname.includes("/schedule/press-conference"),
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/event",
|
href: "/contributor/schedule/event",
|
||||||
label: "event",
|
label: t("event"),
|
||||||
active: pathname.includes("/schedule/event"),
|
active: pathname.includes("/schedule/event"),
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-release",
|
href: "/contributor/schedule/press-release",
|
||||||
label: "pers rilis",
|
label: t("press-release"),
|
||||||
active: pathname.includes("/schedule/press-release"),
|
active: pathname.includes("/schedule/press-release"),
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
children: [],
|
||||||
|
|
@ -1725,21 +1789,21 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-conference",
|
href: "/contributor/schedule/press-conference",
|
||||||
label: "konferensi pers",
|
label: t("press-conference"),
|
||||||
active: pathname.includes("/schedule/press-conference"),
|
active: pathname.includes("/schedule/press-conference"),
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/event",
|
href: "/contributor/schedule/event",
|
||||||
label: "event",
|
label: t("event"),
|
||||||
active: pathname.includes("/schedule/event"),
|
active: pathname.includes("/schedule/event"),
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-release",
|
href: "/contributor/schedule/press-release",
|
||||||
label: "pers rilis",
|
label: t("press-release"),
|
||||||
active: pathname.includes("/schedule/press-release"),
|
active: pathname.includes("/schedule/press-release"),
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
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) {
|
} else if (Number(userLevelId) == 761) {
|
||||||
menusSelected = [
|
menusSelected = [
|
||||||
|
|
@ -1891,7 +2019,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-conference",
|
href: "/contributor/schedule/press-conference",
|
||||||
label: "konferensi pers",
|
label: t("press-conference"),
|
||||||
active: pathname.includes("/schedule/press-conference"),
|
active: pathname.includes("/schedule/press-conference"),
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
|
|
@ -1905,7 +2033,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-release",
|
href: "/contributor/schedule/press-release",
|
||||||
label: "pers rilis",
|
label: t("press-release"),
|
||||||
active: pathname.includes("/schedule/press-release"),
|
active: pathname.includes("/schedule/press-release"),
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
children: [],
|
||||||
|
|
@ -2105,21 +2233,21 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-conference",
|
href: "/contributor/schedule/press-conference",
|
||||||
label: "konferensi pers",
|
label: t("press-conference"),
|
||||||
active: pathname.includes("/schedule/press-conference"),
|
active: pathname.includes("/schedule/press-conference"),
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/event",
|
href: "/contributor/schedule/event",
|
||||||
label: "event",
|
label: t("event"),
|
||||||
active: pathname.includes("/schedule/event"),
|
active: pathname.includes("/schedule/event"),
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-release",
|
href: "/contributor/schedule/press-release",
|
||||||
label: "pers rilis",
|
label: t("press-release"),
|
||||||
active: pathname.includes("/schedule/press-release"),
|
active: pathname.includes("/schedule/press-release"),
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
children: [],
|
||||||
|
|
@ -2314,21 +2442,21 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-conference",
|
href: "/contributor/schedule/press-conference",
|
||||||
label: "konferensi pers",
|
label: t("press-conference"),
|
||||||
active: pathname.includes("/schedule/press-conference"),
|
active: pathname.includes("/schedule/press-conference"),
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/event",
|
href: "/contributor/schedule/event",
|
||||||
label: "event",
|
label: t("event"),
|
||||||
active: pathname.includes("/schedule/event"),
|
active: pathname.includes("/schedule/event"),
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/contributor/schedule/press-release",
|
href: "/contributor/schedule/press-release",
|
||||||
label: "pers rilis",
|
label: t("press-release"),
|
||||||
active: pathname.includes("/schedule/press-release"),
|
active: pathname.includes("/schedule/press-release"),
|
||||||
icon: "heroicons:shopping-cart",
|
icon: "heroicons:shopping-cart",
|
||||||
children: [],
|
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 = [
|
menusSelected = [
|
||||||
{
|
{
|
||||||
groupLabel: t("apps"),
|
groupLabel: t("apps"),
|
||||||
|
|
@ -2706,16 +2834,16 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
icon: "material-symbols:dashboard",
|
icon: "material-symbols:dashboard",
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
href: "/dashboard",
|
href: "/dashboard/executive",
|
||||||
label: "Breakdown",
|
label: "Executive",
|
||||||
active: pathname === "/dashboard",
|
active: pathname === "/dashboard/executive",
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/dashboard/executive",
|
href: "/dashboard",
|
||||||
label: "Executive",
|
label: "Breakdown",
|
||||||
active: pathname === "/dashboard/executive",
|
active: pathname === "/dashboard",
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
|
|
@ -2723,20 +2851,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
groupLabel: "",
|
// groupLabel: "",
|
||||||
id: "agenda-setting",
|
// id: "agenda-setting",
|
||||||
menus: [
|
// menus: [
|
||||||
{
|
// {
|
||||||
id: "agenda-setting",
|
// id: "agenda-setting",
|
||||||
href: "/contributor/agenda-setting",
|
// href: "/contributor/agenda-setting",
|
||||||
label: t("agenda-setting"),
|
// label: t("agenda-setting"),
|
||||||
active: pathname.includes("/agenda-setting"),
|
// active: pathname.includes("/agenda-setting"),
|
||||||
icon: "iconoir:journal-page",
|
// icon: "iconoir:journal-page",
|
||||||
submenus: [],
|
// submenus: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
groupLabel: "",
|
groupLabel: "",
|
||||||
id: "management-user",
|
id: "management-user",
|
||||||
|
|
@ -3015,16 +3143,16 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
icon: "material-symbols:dashboard",
|
icon: "material-symbols:dashboard",
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
href: "/dashboard",
|
href: "/dashboard/executive",
|
||||||
label: "Breakdown",
|
label: "Executive",
|
||||||
active: pathname === "/dashboard",
|
active: pathname === "/dashboard/executive",
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/dashboard/executive",
|
href: "/dashboard",
|
||||||
label: "Executive",
|
label: "Breakdown",
|
||||||
active: pathname === "/dashboard/executive",
|
active: pathname === "/dashboard",
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
|
|
@ -3074,20 +3202,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
groupLabel: "",
|
// groupLabel: "",
|
||||||
id: "agenda-setting",
|
// id: "agenda-setting",
|
||||||
menus: [
|
// menus: [
|
||||||
{
|
// {
|
||||||
id: "agenda-setting",
|
// id: "agenda-setting",
|
||||||
href: "/contributor/agenda-setting",
|
// href: "/contributor/agenda-setting",
|
||||||
label: t("agenda-setting"),
|
// label: t("agenda-setting"),
|
||||||
active: pathname.includes("/agenda-setting"),
|
// active: pathname.includes("/agenda-setting"),
|
||||||
icon: "iconoir:journal-page",
|
// icon: "iconoir:journal-page",
|
||||||
submenus: [],
|
// submenus: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
groupLabel: "",
|
groupLabel: "",
|
||||||
id: "performance-polres",
|
id: "performance-polres",
|
||||||
|
|
@ -3159,35 +3287,70 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// groupLabel: "",
|
groupLabel: "",
|
||||||
// id: "settings",
|
id: "settings",
|
||||||
// menus: [
|
menus: [
|
||||||
// {
|
{
|
||||||
// id: "settings",
|
id: "settings",
|
||||||
// href: "/admin/settings",
|
href: "/admin/settings",
|
||||||
// label: t("settings"),
|
label: t("settings"),
|
||||||
// active: pathname.includes("/settinng"),
|
active: pathname.includes("/settinng"),
|
||||||
// icon: "material-symbols:settings",
|
icon: "material-symbols:settings",
|
||||||
// submenus: [
|
submenus: [
|
||||||
// {
|
{
|
||||||
// href: "/admin/settings/category",
|
href: "/admin/settings/category",
|
||||||
// label: t("category"),
|
label: t("category"),
|
||||||
// active: pathname === "/admin/settings/category",
|
active: pathname === "/admin/settings/category",
|
||||||
// icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
// children: [],
|
children: [],
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// href: "/admin/settings/tag",
|
href: "/admin/settings/tag",
|
||||||
// label: "Tag",
|
label: "Tag",
|
||||||
// active: pathname === "/admin/settings/tag",
|
active: pathname === "/admin/settings/tag",
|
||||||
// icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
// children: [],
|
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 {
|
} else {
|
||||||
menusSelected = [
|
menusSelected = [
|
||||||
|
|
@ -3201,11 +3364,39 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
label: t("dashboard"),
|
label: t("dashboard"),
|
||||||
active: pathname.includes("/dashboard"),
|
active: pathname.includes("/dashboard"),
|
||||||
icon: "material-symbols: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: [],
|
submenus: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
groupLabel: "",
|
groupLabel: "",
|
||||||
id: "content-production",
|
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: "",
|
groupLabel: "",
|
||||||
id: "communication",
|
id: "communication",
|
||||||
|
|
@ -3273,6 +3507,41 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
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",
|
"colors": "Colors",
|
||||||
"performance-polda": "Performance Polda",
|
"performance-polda": "Performance Polda",
|
||||||
"performance-polres": "Performance Polres",
|
"performance-polres": "Performance Polres",
|
||||||
|
"performance-satker": "Performance Satker",
|
||||||
"analysis": "Analysis",
|
"analysis": "Analysis",
|
||||||
"management-content": "Content Management ",
|
"management-content": "Content Management ",
|
||||||
"add-experts": "Add Experts",
|
"add-experts": "Add Experts",
|
||||||
"category": "Category",
|
"category": "Category",
|
||||||
|
"add-category": "Add Category",
|
||||||
|
"tags": "Tags",
|
||||||
|
"add-tags": "Add Tags",
|
||||||
|
"add": "Add",
|
||||||
"privacy": "Privacy Policy"
|
"privacy": "Privacy Policy"
|
||||||
},
|
},
|
||||||
"Changelog": {
|
"Changelog": {
|
||||||
|
|
@ -580,7 +585,8 @@
|
||||||
"schedule": "Schedule",
|
"schedule": "Schedule",
|
||||||
"press-conference": "Press Conference",
|
"press-conference": "Press Conference",
|
||||||
"press-release": "Press Release",
|
"press-release": "Press Release",
|
||||||
"create-schedule": "Create Schedule"
|
"create-schedule": "Create Schedule",
|
||||||
|
"event": "event"
|
||||||
},
|
},
|
||||||
"Blog": {
|
"Blog": {
|
||||||
"table": "Table",
|
"table": "Table",
|
||||||
|
|
@ -599,5 +605,37 @@
|
||||||
"table": "Table",
|
"table": "Table",
|
||||||
"contest": "Lomba",
|
"contest": "Lomba",
|
||||||
"create-contest": "Create Contest"
|
"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",
|
"colors": "Colors",
|
||||||
"performance-polda": "Performa Polda",
|
"performance-polda": "Performa Polda",
|
||||||
"performance-polres": "Performa Polres",
|
"performance-polres": "Performa Polres",
|
||||||
|
"performance-satker": "Performa Satker",
|
||||||
"analysis": "Analisa",
|
"analysis": "Analisa",
|
||||||
"management-content": "Manajemen Konten",
|
"management-content": "Manajemen Konten",
|
||||||
"add-experts": "Tambah Tenaga Ahli",
|
"add-experts": "Tambah Tenaga Ahli",
|
||||||
"category": "Kategori",
|
"category": "Kategori",
|
||||||
|
"add-category": "Tambah Kategori",
|
||||||
|
"tags": "Tag",
|
||||||
|
"add-tags": "Tambah Tag",
|
||||||
|
"add": "Tambah",
|
||||||
"privacy": "Kebijakan Privacy"
|
"privacy": "Kebijakan Privacy"
|
||||||
},
|
},
|
||||||
"Changelog": {
|
"Changelog": {
|
||||||
|
|
@ -581,7 +586,8 @@
|
||||||
"schedule": "Jadwal",
|
"schedule": "Jadwal",
|
||||||
"press-conference": "Konferensi Pers",
|
"press-conference": "Konferensi Pers",
|
||||||
"press-release": "Pers Rilis",
|
"press-release": "Pers Rilis",
|
||||||
"create-schedule": "Buat Jadwal"
|
"create-schedule": "Buat Jadwal",
|
||||||
|
"event": "event"
|
||||||
},
|
},
|
||||||
"Blog": {
|
"Blog": {
|
||||||
"table": "Tabel",
|
"table": "Tabel",
|
||||||
|
|
@ -600,5 +606,37 @@
|
||||||
"table": "Tabel",
|
"table": "Tabel",
|
||||||
"contest": "Lomba",
|
"contest": "Lomba",
|
||||||
"create-contest": "Buat 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,
|
page: any,
|
||||||
limit: any,
|
limit: any,
|
||||||
title = "",
|
title = "",
|
||||||
|
contentCreatedDate = "",
|
||||||
isPublish: any
|
isPublish: any
|
||||||
) {
|
) {
|
||||||
return await httpGetInterceptor(
|
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) {
|
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);
|
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
|
// Request interceptor
|
||||||
axiosInterceptorInstance.interceptors.request.use(
|
axiosInterceptorInstance.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
console.log("Config interceptor : ", config);
|
|
||||||
const accessToken = Cookies.get("access_token");
|
const accessToken = Cookies.get("access_token");
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
if (config.headers)
|
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";
|
const url = "users/user-schools/list";
|
||||||
return httpGetInterceptor(url);
|
return httpGetInterceptor(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getListCompetencies() {
|
export async function getListCompetencies() {
|
||||||
const url = "users/user-competencies/list";
|
const url = "users/user-competencies/list";
|
||||||
return httpGetInterceptor(url);
|
return httpGetInterceptor(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getListExperiences() {
|
||||||
|
const url = "users/user-experiences/list";
|
||||||
|
return httpGetInterceptor(url);
|
||||||
|
}
|
||||||
|
|
||||||
export async function saveUserInternal(data: any) {
|
export async function saveUserInternal(data: any) {
|
||||||
const url = "users/save";
|
const url = "users/save";
|
||||||
return httpPostInterceptor(url, data);
|
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) {
|
export async function getUserById(id: string) {
|
||||||
const url = `users?id=${id}`;
|
const url = `users?id=${id}`;
|
||||||
return httpGetInterceptor(url);
|
return httpGetInterceptor(url);
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,15 @@ import {
|
||||||
import { httpGet } from "../http-config/http-base-service";
|
import { httpGet } from "../http-config/http-base-service";
|
||||||
import { any } from "zod";
|
import { any } from "zod";
|
||||||
|
|
||||||
export async function paginationSchedule(size: number, page: number, type: any, title: string = "") {
|
export async function paginationSchedule(
|
||||||
return await httpGetInterceptor(`schedule/pagination?enablePage=1&scheduleTypeId=${type}&page=${page}&size=${size}&title=${title}`);
|
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) {
|
export async function postSchedule(data: any) {
|
||||||
|
|
@ -49,6 +56,11 @@ export async function listScheduleToday() {
|
||||||
return httpGetInterceptor(url);
|
return httpGetInterceptor(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getListScheduleAttachment(scheduleId: any) {
|
||||||
|
const url = `media/list?&enablePage=0&scheduleId=${scheduleId}`;
|
||||||
|
return httpGetInterceptor(url);
|
||||||
|
}
|
||||||
|
|
||||||
export async function listScheduleNext() {
|
export async function listScheduleNext() {
|
||||||
const url = "schedule/next-activity";
|
const url = "schedule/next-activity";
|
||||||
return httpGetInterceptor(url);
|
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() {
|
export async function generateTicket() {
|
||||||
const url = "/admin/tableau-ticket";
|
const url = "/admin/tableau-ticket";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue