feat: new page for satker-content
This commit is contained in:
parent
15a395ccd2
commit
0c5a7f86bb
|
|
@ -49,15 +49,47 @@ const columns: ColumnDef<any>[] = [
|
|||
header: "Jumlah Amplifikasi",
|
||||
cell: ({ row }) => <span>{row.getValue("link")}</span>,
|
||||
},
|
||||
// {
|
||||
// accessorKey: "status",
|
||||
// header: "Status",
|
||||
// cell: ({ row }) => <span>{row.getValue("status")}</span>,
|
||||
// },
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => <span>{row.getValue("status")}</span>,
|
||||
header: () => <div className="text-center">Status</div>,
|
||||
cell: ({ row }) => {
|
||||
const raw = row.getValue("status");
|
||||
|
||||
let value: string | number = "-";
|
||||
|
||||
if (typeof raw === "string" || typeof raw === "number") {
|
||||
value = raw;
|
||||
} else if (raw && typeof raw === "object") {
|
||||
value = JSON.stringify(raw);
|
||||
}
|
||||
|
||||
return <div className="text-center">{value}</div>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "date",
|
||||
header: "Tanggal Penarikan",
|
||||
cell: ({ row }) => <span>{row.getValue("date")}</span>,
|
||||
accessorKey: "createdAt",
|
||||
header: () => <div className="text-center">Tanggal Penarikan</div>,
|
||||
cell: ({ row }) => {
|
||||
const raw = row.getValue("createdAt");
|
||||
if (!raw || typeof raw !== "string")
|
||||
return <div className="text-center">-</div>;
|
||||
|
||||
const date = new Date(raw);
|
||||
if (isNaN(date.getTime())) return <div className="text-center">-</div>;
|
||||
|
||||
const formatted = date.toLocaleDateString("id-ID", {
|
||||
day: "2-digit",
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
return <div className="text-center">{formatted}</div>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
|
|
@ -78,9 +110,9 @@ const columns: ColumnDef<any>[] = [
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link href={`/admin/media-tracking/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 items-center rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
View
|
||||
{row.original.mediaUpload.fileType.secondaryName &&
|
||||
row.original.mediaUpload.fileType.secondaryName.toLowerCase()}
|
||||
</DropdownMenuItem>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormImageDetail from "@/components/form/content/image-detail-form";
|
||||
import FormAudioDetail from "@/components/form/content/audio-detail-form";
|
||||
|
||||
const AudioDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormAudioDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AudioDetailPage;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormImageDetail from "@/components/form/content/image-detail-form";
|
||||
import FormImageUpdate from "@/components/form/content/image-update-form";
|
||||
import FormAudioUpdate from "@/components/form/content/audio-update-form";
|
||||
|
||||
const AudioUpdatePage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormAudioUpdate />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AudioUpdatePage;
|
||||
|
|
@ -83,6 +83,42 @@ const useTableColumns = () => {
|
|||
<span className="whitespace-nowrap">{row.getValue("creatorName")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "fileTypeId",
|
||||
header: "Jenis Konten",
|
||||
cell: ({ row }) => {
|
||||
const type = Number(row.getValue("fileTypeId"));
|
||||
const name = row.original.fileTypeName;
|
||||
|
||||
const label =
|
||||
type === 1
|
||||
? "Image"
|
||||
: type === 2
|
||||
? "Audio Visual"
|
||||
: type === 3
|
||||
? "Text"
|
||||
: type === 4
|
||||
? "Audio"
|
||||
: name || "-";
|
||||
|
||||
const color =
|
||||
type === 1
|
||||
? "bg-blue-100 text-blue-600"
|
||||
: type === 2
|
||||
? "bg-red-100 text-red-600"
|
||||
: type === 3
|
||||
? "bg-green-100 text-green-600"
|
||||
: type === 4
|
||||
? "bg-yellow-100 text-yellow-600"
|
||||
: "bg-gray-200 text-gray-600";
|
||||
|
||||
return (
|
||||
<Badge className={`${color} whitespace-nowrap rounded-full px-3`}>
|
||||
{label}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "creatorGroupLevelName",
|
||||
header: t("source", { defaultValue: "Source" }),
|
||||
|
|
@ -187,6 +223,32 @@ const useTableColumns = () => {
|
|||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
const typeId = Number(row.original.fileTypeId);
|
||||
|
||||
// mapping route detail
|
||||
const detailRoute =
|
||||
typeId === 1
|
||||
? `/contributor/content/satker/image/detail/${row.original.id}`
|
||||
: typeId === 2
|
||||
? `/contributor/content/satker/video/detail/${row.original.id}`
|
||||
: typeId === 3
|
||||
? `/contributor/content/satker/text/detail/${row.original.id}`
|
||||
: typeId === 4
|
||||
? `/contributor/content/satker/audio/detail/${row.original.id}`
|
||||
: `/contributor/content/satker/detail/${row.original.id}`;
|
||||
|
||||
// mapping route update
|
||||
const updateRoute =
|
||||
typeId === 1
|
||||
? `/contributor/content/satker/image/update/${row.original.id}`
|
||||
: typeId === 2
|
||||
? `/contributor/content/satker/video/update/${row.original.id}`
|
||||
: typeId === 3
|
||||
? `/contributor/content/satker/text/update/${row.original.id}`
|
||||
: typeId === 4
|
||||
? `/contributor/content/satker/audio/update/${row.original.id}`
|
||||
: `/contributor/content/satker/update/${row.original.id}`;
|
||||
|
||||
async function doDelete(id: any) {
|
||||
const data = { id };
|
||||
const response = await deleteMedia(data);
|
||||
|
|
@ -257,16 +319,22 @@ const useTableColumns = () => {
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
{/* <Link
|
||||
href={`/contributor/content/satker/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={detailRoute}>
|
||||
<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>
|
||||
|
||||
{canEdit && (
|
||||
{/* {canEdit && (
|
||||
<Link
|
||||
href={`/contributor/content/satker/update/${row.original.id}`}
|
||||
>
|
||||
|
|
@ -275,6 +343,14 @@ const useTableColumns = () => {
|
|||
Edit
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
)} */}
|
||||
{canEdit && (
|
||||
<Link href={updateRoute}>
|
||||
<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
|
||||
|
|
|
|||
|
|
@ -48,11 +48,9 @@ const TableSatker = () => {
|
|||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
|
|
@ -60,15 +58,10 @@ const TableSatker = () => {
|
|||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
|
||||
const [showData, setShowData] = React.useState("10");
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
||||
// gunakan ref untuk debounce search
|
||||
const searchTimeoutRef = React.useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// === FILTER STATES ===
|
||||
const [categories, setCategories] = React.useState<any[]>([]);
|
||||
const [selectedCategories, setSelectedCategories] = React.useState<number[]>(
|
||||
[]
|
||||
|
|
@ -80,7 +73,7 @@ const TableSatker = () => {
|
|||
const [filterByCreator, setFilterByCreator] = React.useState("");
|
||||
const [filterBySource, setFilterBySource] = React.useState("");
|
||||
const [filterByCreatorGroup, setFilterByCreatorGroup] = React.useState("");
|
||||
const [typeId, setTypeId] = React.useState<string>(""); // 1=image, 2=video, 3=text, 4=audio
|
||||
const [typeId, setTypeId] = React.useState<string>("");
|
||||
|
||||
const userLevelId = getCookiesDecrypt("ulie");
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormImageDetail from "@/components/form/content/image-detail-form";
|
||||
|
||||
const ImageDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormImageDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImageDetailPage;
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormImageDetail from "@/components/form/content/image-detail-form";
|
||||
import FormImageUpdate from "@/components/form/content/image-update-form";
|
||||
|
||||
const ImageUpdatePage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormImageUpdate />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImageUpdatePage;
|
||||
|
|
@ -59,15 +59,15 @@ const ReactTableVideoPage = () => {
|
|||
<CardTitle>
|
||||
<div className="flex items-center">
|
||||
<div className="flex-1 text-xl font-medium text-default-900">
|
||||
{t("video", { defaultValue: "Video" })}
|
||||
Satker
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<Link href={"/contributor/content/video/create"}>
|
||||
{/* <Link href={"/contributor/content/video/create"}>
|
||||
<Button color="primary" className="text-white">
|
||||
<UploadIcon size={18} className="mr-2" />
|
||||
{t("create-video", { defaultValue: "Create Video" })}
|
||||
</Button>
|
||||
</Link>
|
||||
</Link> */}
|
||||
{/* <Button color="primary" className="text-white ml-3">
|
||||
<UploadIcon />
|
||||
Unggah Video Dengan AI
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormImageDetail from "@/components/form/content/image-detail-form";
|
||||
import FormTeksDetail from "@/components/form/content/teks-detail-form";
|
||||
|
||||
const TeksDetailPage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormTeksDetail />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeksDetailPage;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormImageDetail from "@/components/form/content/image-detail-form";
|
||||
import FormImageUpdate from "@/components/form/content/image-update-form";
|
||||
import FormTeksUpdate from "@/components/form/content/teks-update-form";
|
||||
|
||||
const TeksUpdatePage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormTeksUpdate />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeksUpdatePage;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormImageDetail from "@/components/form/content/image-detail-form";
|
||||
import FormImageUpdate from "@/components/form/content/image-update-form";
|
||||
import FormVideoUpdate from "@/components/form/content/video-update-form";
|
||||
|
||||
const VideoUpdatePage = async () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormVideoUpdate />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoUpdatePage;
|
||||
|
|
@ -205,21 +205,6 @@ const Navbar = () => {
|
|||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!pathname) return;
|
||||
|
||||
if (
|
||||
pathname.startsWith("/_next") ||
|
||||
pathname.startsWith("/api") ||
|
||||
pathname.includes("favicon")
|
||||
)
|
||||
return;
|
||||
|
||||
if (!pathname.startsWith("/in")) {
|
||||
router.replace("/in");
|
||||
}
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<div className="bg-[#f7f7f7] dark:bg-black shadow-md sticky top-0 z-50">
|
||||
<div className="flex items-center justify-between px-4 lg:px-16 py-2 gap-3">
|
||||
|
|
|
|||
|
|
@ -100,6 +100,13 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
},
|
||||
...(!hideForRole14
|
||||
? [
|
||||
{
|
||||
href: "/contributor/content/satker",
|
||||
label: "satker",
|
||||
active: pathname.includes("/content/satker"),
|
||||
icon: "heroicons:credit-card",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
href: "/contributor/content/spit",
|
||||
label: "spit",
|
||||
|
|
|
|||
|
|
@ -7,31 +7,34 @@ const intlMiddleware = createMiddleware(routing);
|
|||
export default function middleware(request: NextRequest) {
|
||||
const { pathname } = request.nextUrl;
|
||||
|
||||
// Abaikan asset & API
|
||||
if (
|
||||
// Abaikan semua static file dan asset
|
||||
const isStaticAsset =
|
||||
pathname.startsWith("/api") ||
|
||||
pathname.startsWith("/_next") ||
|
||||
pathname.startsWith("/favicon") ||
|
||||
pathname.startsWith("/assets")
|
||||
) {
|
||||
pathname.startsWith("/assets") ||
|
||||
pathname.startsWith("/static") ||
|
||||
pathname.startsWith("/images") ||
|
||||
pathname.startsWith("/icons") ||
|
||||
pathname.match(/\.(png|jpg|jpeg|gif|webp|svg|ico)$/);
|
||||
|
||||
if (isStaticAsset) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
// Jika sudah mengandung /in → pakai next-intl
|
||||
// Jika sudah dalam /in jalankan intl middleware
|
||||
if (pathname.startsWith("/in")) {
|
||||
return intlMiddleware(request);
|
||||
}
|
||||
|
||||
// Jika TIDAK mengandung /in → selalu tambahkan /in
|
||||
// Contoh:
|
||||
// /image/detail/... → /in/image/detail/...
|
||||
// Redirect otomatis ke /in
|
||||
const url = request.nextUrl.clone();
|
||||
url.pathname = `/in${pathname}`;
|
||||
return NextResponse.redirect(url);
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: ["/((?!_next|api|favicon.ico|assets).*)"],
|
||||
matcher: ["/((?!_next|api|favicon.ico|assets|static|images|icons).*)"],
|
||||
};
|
||||
|
||||
// import createMiddleware from "next-intl/middleware";
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ export async function listDataSatker(
|
|||
title: string = ""
|
||||
) {
|
||||
return await httpGetInterceptor(
|
||||
`media/list?enablePage=1&sortBy=createdAt&sort=desc&isAllSatker=1` +
|
||||
`media/list?enablePage=1&sortBy=createdAt&sort=desc&isAllSatker=true` +
|
||||
`&size=${limit}` +
|
||||
`&page=${page}` +
|
||||
`&isForSelf=${isForSelf}` +
|
||||
|
|
|
|||
Loading…
Reference in New Issue