Merge branch 'dev-1' of https://gitlab.com/hanifsalafi/new-netidhub-public
This commit is contained in:
commit
8b6d4ae00f
|
|
@ -66,7 +66,10 @@ const useTableColumns = () => {
|
||||||
accessorKey: "createdAt",
|
accessorKey: "createdAt",
|
||||||
header: "Upload Date",
|
header: "Upload Date",
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const createdAt = row.getValue("createdAt") as string | number | undefined;
|
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")
|
||||||
|
|
@ -98,7 +101,8 @@ const useTableColumns = () => {
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const isPublish = row.original.isPublish;
|
const isPublish = row.original.isPublish;
|
||||||
const isPublishOnPolda = row.original.isPublishOnPolda;
|
const isPublishOnPolda = row.original.isPublishOnPolda;
|
||||||
const creatorGroupParentLevelId = row.original.creatorGroupParentLevelId;
|
const creatorGroupParentLevelId =
|
||||||
|
row.original.creatorGroupParentLevelId;
|
||||||
|
|
||||||
let displayText = "-";
|
let displayText = "-";
|
||||||
if (isPublish && !isPublishOnPolda) {
|
if (isPublish && !isPublishOnPolda) {
|
||||||
|
|
@ -124,40 +128,101 @@ const useTableColumns = () => {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// accessorKey: "statusName",
|
||||||
|
// header: "Status",
|
||||||
|
// cell: ({ row }) => {
|
||||||
|
// const statusId = Number(row.original?.statusId);
|
||||||
|
// const reviewedAtLevel = row.original?.reviewedAtLevel || "";
|
||||||
|
// const creatorGroupLevelId = Number(row.original?.creatorGroupLevelId);
|
||||||
|
// const needApprovalFromLevel = Number(row.original?.needApprovalFromLevel);
|
||||||
|
|
||||||
|
// const userHasReviewed = reviewedAtLevel.includes(`:${userLevelId}:`);
|
||||||
|
// const isCreator = creatorGroupLevelId === Number(userLevelId);
|
||||||
|
|
||||||
|
// const isWaitingForReview = statusId === 2 && !userHasReviewed && !isCreator;
|
||||||
|
// const isApprovalNeeded = statusId === 1 && needApprovalFromLevel === Number(userLevelId);
|
||||||
|
|
||||||
|
// const label =
|
||||||
|
// isWaitingForReview || isApprovalNeeded
|
||||||
|
// ? "Menunggu Review"
|
||||||
|
// : statusId === 2
|
||||||
|
// ? "Diterima"
|
||||||
|
// : row.original?.statusName;
|
||||||
|
|
||||||
|
// const colors: Record<string, string> = {
|
||||||
|
// "Menunggu Review": "bg-orange-100 text-orange-600",
|
||||||
|
// Diterima: "bg-green-100 text-green-600",
|
||||||
|
// default: "bg-red-200 text-red-600",
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const statusStyles = colors[label] || colors.default;
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <Badge className={cn("rounded-full px-5 w-full whitespace-nowrap", statusStyles)}>
|
||||||
|
// {label}
|
||||||
|
// </Badge>
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
accessorKey: "statusName",
|
accessorKey: "statusName",
|
||||||
header: "Status",
|
header: "Status",
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const statusId = Number(row.original?.statusId);
|
const {
|
||||||
const reviewedAtLevel = row.original?.reviewedAtLevel || "";
|
statusId,
|
||||||
const creatorGroupLevelId = Number(row.original?.creatorGroupLevelId);
|
statusName,
|
||||||
const needApprovalFromLevel = Number(row.original?.needApprovalFromLevel);
|
isPublish,
|
||||||
|
reviewedAtLevel = "",
|
||||||
|
creatorGroupLevelId,
|
||||||
|
needApprovalFromLevel,
|
||||||
|
} = row.original;
|
||||||
|
|
||||||
|
const userLevelId = Number(getCookiesDecrypt("ulie"));
|
||||||
|
|
||||||
const userHasReviewed = reviewedAtLevel.includes(`:${userLevelId}:`);
|
const userHasReviewed = reviewedAtLevel.includes(`:${userLevelId}:`);
|
||||||
const isCreator = creatorGroupLevelId === Number(userLevelId);
|
const isCreator = Number(creatorGroupLevelId) === userLevelId;
|
||||||
|
|
||||||
const isWaitingForReview = statusId === 2 && !userHasReviewed && !isCreator;
|
|
||||||
const isApprovalNeeded = statusId === 1 && needApprovalFromLevel === Number(userLevelId);
|
|
||||||
|
|
||||||
const label =
|
if (isPublish) {
|
||||||
isWaitingForReview || isApprovalNeeded
|
return (
|
||||||
? "Menunggu Review"
|
<div className="flex items-center justify-center w-full h-full">
|
||||||
: statusId === 2
|
<Badge className="flex items-center justify-center min-w-[120px] rounded-full px-5 py-1 bg-green-100 text-green-700 text-center whitespace-nowrap">
|
||||||
? "Diterima"
|
Published
|
||||||
: row.original?.statusName;
|
</Badge>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let label = statusName || "Menunggu Review";
|
||||||
|
|
||||||
|
if (statusId === 2 && !userHasReviewed && !isCreator) {
|
||||||
|
label = "Menunggu Review";
|
||||||
|
} else if (statusId === 1 && needApprovalFromLevel === userLevelId) {
|
||||||
|
label = "Menunggu Review";
|
||||||
|
} else if (statusId === 2) {
|
||||||
|
label = "Diterima";
|
||||||
|
}
|
||||||
|
|
||||||
const colors: Record<string, string> = {
|
const colors: Record<string, string> = {
|
||||||
"Menunggu Review": "bg-orange-100 text-orange-600",
|
"Menunggu Review": "bg-orange-100 text-orange-600",
|
||||||
Diterima: "bg-green-100 text-green-600",
|
Diterima: "bg-blue-100 text-blue-600",
|
||||||
default: "bg-red-200 text-red-600",
|
Published: "bg-green-100 text-green-700",
|
||||||
|
Unknown: "bg-gray-100 text-gray-600",
|
||||||
|
default: "bg-gray-100 text-gray-600",
|
||||||
};
|
};
|
||||||
|
|
||||||
const statusStyles = colors[label] || colors.default;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Badge className={cn("rounded-full px-5 w-full whitespace-nowrap", statusStyles)}>
|
<div className="flex items-center justify-center w-full h-full">
|
||||||
|
<Badge
|
||||||
|
className={cn(
|
||||||
|
"flex items-center justify-center min-w-[120px] rounded-full px-5 py-1 text-center whitespace-nowrap",
|
||||||
|
colors[label] || colors.default
|
||||||
|
)}
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -215,7 +280,9 @@ const useTableColumns = () => {
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (userLevelId !== undefined && roleId !== undefined) {
|
if (userLevelId !== undefined && roleId !== undefined) {
|
||||||
setIsMabesApprover(Number(userLevelId) === 216 && Number(roleId) === 3);
|
setIsMabesApprover(
|
||||||
|
Number(userLevelId) === 216 && Number(roleId) === 3
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [userLevelId, roleId]);
|
}, [userLevelId, roleId]);
|
||||||
|
|
||||||
|
|
@ -224,7 +291,7 @@ const useTableColumns = () => {
|
||||||
<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 cursor-pointer"
|
||||||
>
|
>
|
||||||
<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" />
|
||||||
|
|
@ -235,14 +302,14 @@ const useTableColumns = () => {
|
||||||
href={`/admin/content/image/detail/${row.original.id}`}
|
href={`/admin/content/image/detail/${row.original.id}`}
|
||||||
className="hover:text-black"
|
className="hover:text-black"
|
||||||
>
|
>
|
||||||
<DropdownMenuItem className="p-2 border-b text-default-700 rounded-none">
|
<DropdownMenuItem className="p-2 border-b text-default-700 rounded-none cursor-pointer hover:bg-slate-200">
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
View
|
View
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
{/* {(Number(row.original.uploadedById) === Number(userId) || isMabesApprover) && ( */}
|
{/* {(Number(row.original.uploadedById) === Number(userId) || isMabesApprover) && ( */}
|
||||||
<Link href={`/admin/content/image/update/${row.original.id}`}>
|
<Link href={`/admin/content/image/update/${row.original.id}`}>
|
||||||
<DropdownMenuItem className="p-2 border-b text-default-700 rounded-none">
|
<DropdownMenuItem className="p-2 border-b text-default-700 rounded-none cursor-pointer hover:bg-slate-200">
|
||||||
<SquarePen className="w-4 h-4 me-1.5" />
|
<SquarePen className="w-4 h-4 me-1.5" />
|
||||||
Edit
|
Edit
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
@ -250,7 +317,7 @@ const useTableColumns = () => {
|
||||||
{/* )} */}
|
{/* )} */}
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() => handleDeleteMedia(row.original.id)}
|
onClick={() => handleDeleteMedia(row.original.id)}
|
||||||
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-white rounded-none"
|
className="p-2 border-b text-destructive bg-destructive/30 focus:bg-destructive focus:text-white rounded-none cursor-pointer"
|
||||||
>
|
>
|
||||||
<Trash2 className="w-4 h-4 me-1.5" />
|
<Trash2 className="w-4 h-4 me-1.5" />
|
||||||
Delete
|
Delete
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ const usePendingApprovalColumns = () => {
|
||||||
<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 cursor-pointer"
|
||||||
>
|
>
|
||||||
<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" />
|
||||||
|
|
@ -187,7 +187,7 @@ const usePendingApprovalColumns = () => {
|
||||||
href={`/admin/content/image/detail/${row.original.id}`}
|
href={`/admin/content/image/detail/${row.original.id}`}
|
||||||
className="hover:text-black"
|
className="hover:text-black"
|
||||||
>
|
>
|
||||||
<DropdownMenuItem className="p-2 border-b text-default-700 group rounded-none">
|
<DropdownMenuItem className="p-2 border-b text-default-700 group rounded-none cursor-pointer hover:bg-slate-200">
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
View
|
View
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ const TableImage = () => {
|
||||||
const [columnVisibility, setColumnVisibility] =
|
const [columnVisibility, setColumnVisibility] =
|
||||||
React.useState<VisibilityState>({});
|
React.useState<VisibilityState>({});
|
||||||
const [rowSelection, setRowSelection] = React.useState({});
|
const [rowSelection, setRowSelection] = React.useState({});
|
||||||
const [showData, setShowData] = React.useState("50");
|
const [showData, setShowData] = React.useState("10");
|
||||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||||
pageIndex: 0,
|
pageIndex: 0,
|
||||||
pageSize: Number(showData),
|
pageSize: Number(showData),
|
||||||
|
|
@ -235,7 +235,7 @@ const TableImage = () => {
|
||||||
totalPage: Number(showData),
|
totalPage: Number(showData),
|
||||||
title: search || undefined,
|
title: search || undefined,
|
||||||
categoryId: categoryFilter ? Number(categoryFilter) : undefined,
|
categoryId: categoryFilter ? Number(categoryFilter) : undefined,
|
||||||
typeId: 1, // image content typeoriginalRows
|
typeId: 1,
|
||||||
statusId: statusFilter?.length > 0 ? Number(statusFilter[0]) : undefined,
|
statusId: statusFilter?.length > 0 ? Number(statusFilter[0]) : undefined,
|
||||||
startDate: formattedStartDate || undefined,
|
startDate: formattedStartDate || undefined,
|
||||||
endDate: formattedEndDate || undefined,
|
endDate: formattedEndDate || undefined,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ const ReactTableImagePage = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-none">
|
<div className="flex-none">
|
||||||
<Link href={"/admin/content/image/create"}>
|
<Link href={"/admin/content/image/create"}>
|
||||||
<Button color="primary" className="text-white shadow-sm hover:shadow-md transition-shadow">
|
<Button color="primary" className="text-white shadow-sm hover:shadow-md transition-shadow cursor-pointer">
|
||||||
<UploadIcon size={18} className="mr-2" />
|
<UploadIcon size={18} className="mr-2" />
|
||||||
Create Image
|
Create Image
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -323,12 +323,8 @@ export default function FormImageDetail() {
|
||||||
try {
|
try {
|
||||||
const response = await getArticleDetail(Number(id));
|
const response = await getArticleDetail(Number(id));
|
||||||
const details = response?.data?.data;
|
const details = response?.data?.data;
|
||||||
console.log("detail", details);
|
|
||||||
|
|
||||||
// Map the new API response to the expected format
|
|
||||||
const mappedDetail: Detail = {
|
const mappedDetail: Detail = {
|
||||||
...details,
|
...details,
|
||||||
// Map legacy fields for backward compatibility
|
|
||||||
category:
|
category:
|
||||||
details.categories && details.categories.length > 0
|
details.categories && details.categories.length > 0
|
||||||
? {
|
? {
|
||||||
|
|
@ -339,19 +335,17 @@ export default function FormImageDetail() {
|
||||||
creatorName: details.createdByName,
|
creatorName: details.createdByName,
|
||||||
thumbnailLink: details.thumbnailUrl,
|
thumbnailLink: details.thumbnailUrl,
|
||||||
statusName: getStatusName(details.statusId),
|
statusName: getStatusName(details.statusId),
|
||||||
needApprovalFromLevel: 0, // This might need to be updated based on your business logic
|
needApprovalFromLevel: 0,
|
||||||
uploadedById: details.createdById,
|
uploadedById: details.createdById,
|
||||||
files: details.files || [],
|
files: details.files || [],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Map files from new API structure to expected format
|
|
||||||
const mappedFiles = (mappedDetail.files || []).map((file: any) => ({
|
const mappedFiles = (mappedDetail.files || []).map((file: any) => ({
|
||||||
id: file.id,
|
id: file.id,
|
||||||
url: file.fileUrl || file.url,
|
url: file.fileUrl || file.url,
|
||||||
thumbnailFileUrl:
|
thumbnailFileUrl:
|
||||||
file.fileThumbnail || file.thumbnailFileUrl || file.fileUrl,
|
file.fileThumbnail || file.thumbnailFileUrl || file.fileUrl,
|
||||||
fileName: file.fileName || file.fileName,
|
fileName: file.fileName || file.fileName,
|
||||||
// Keep original API fields for reference
|
|
||||||
...file,
|
...file,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -360,7 +354,7 @@ export default function FormImageDetail() {
|
||||||
|
|
||||||
if (mappedFiles && mappedFiles.length > 0) {
|
if (mappedFiles && mappedFiles.length > 0) {
|
||||||
setMain({
|
setMain({
|
||||||
type: "image", // Default type for articles
|
type: "image",
|
||||||
url: mappedFiles[0]?.url || mappedDetail.thumbnailUrl,
|
url: mappedFiles[0]?.url || mappedDetail.thumbnailUrl,
|
||||||
names: mappedFiles[0]?.fileName || "image",
|
names: mappedFiles[0]?.fileName || "image",
|
||||||
format: getFileExtension(mappedFiles[0]?.fileName || "jpg"),
|
format: getFileExtension(mappedFiles[0]?.fileName || "jpg"),
|
||||||
|
|
@ -368,19 +362,22 @@ export default function FormImageDetail() {
|
||||||
setupPlacementCheck(mappedFiles.length);
|
setupPlacementCheck(mappedFiles.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the selected target to the category ID from details
|
|
||||||
setSelectedTarget(String(mappedDetail.categoryId));
|
setSelectedTarget(String(mappedDetail.categoryId));
|
||||||
|
|
||||||
const fileUrls = mappedFiles.map(
|
const fileUrls = (mappedFiles || []).map(
|
||||||
(file: any) =>
|
(file) => file.thumbnailFileUrl || file.url || "default-image.jpg"
|
||||||
file.thumbnailFileUrl ||
|
|
||||||
file.url ||
|
|
||||||
mappedDetail.thumbnailUrl ||
|
|
||||||
"default-image.jpg"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
setDetailThumb(fileUrls);
|
setDetailThumb(fileUrls);
|
||||||
|
|
||||||
// Note: You might need to update this API call as well
|
if (details?.publishedForObject?.length > 0) {
|
||||||
|
const publisherIds = details.publishedForObject
|
||||||
|
.map((obj: any) => Number(obj.id))
|
||||||
|
.filter((id: number) => id === 5 || id === 6);
|
||||||
|
|
||||||
|
setSelectedPublishers(publisherIds);
|
||||||
|
}
|
||||||
|
|
||||||
const approvals = await getDataApprovalByMediaUpload(mappedDetail.id);
|
const approvals = await getDataApprovalByMediaUpload(mappedDetail.id);
|
||||||
setApproval(approvals?.data?.data);
|
setApproval(approvals?.data?.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -391,7 +388,6 @@ export default function FormImageDetail() {
|
||||||
initState();
|
initState();
|
||||||
}, [refresh, setValue]);
|
}, [refresh, setValue]);
|
||||||
|
|
||||||
// Helper function to get status name from status ID
|
|
||||||
const getStatusName = (statusId: number): string => {
|
const getStatusName = (statusId: number): string => {
|
||||||
const statusMap: { [key: number]: string } = {
|
const statusMap: { [key: number]: string } = {
|
||||||
1: "Menunggu Review",
|
1: "Menunggu Review",
|
||||||
|
|
@ -669,7 +665,7 @@ export default function FormImageDetail() {
|
||||||
navigation={false}
|
navigation={false}
|
||||||
className="h-[480px] object-cover w-full"
|
className="h-[480px] object-cover w-full"
|
||||||
>
|
>
|
||||||
{detailThumb?.map((data: any, index: number) => (
|
{/* {detailThumb?.map((data: any, index: number) => (
|
||||||
<SwiperSlide key={index}>
|
<SwiperSlide key={index}>
|
||||||
<img
|
<img
|
||||||
className="h-[480px] max-w-[600px] rounded-md object-cover mx-auto border-2"
|
className="h-[480px] max-w-[600px] rounded-md object-cover mx-auto border-2"
|
||||||
|
|
@ -677,6 +673,15 @@ export default function FormImageDetail() {
|
||||||
alt={`Image ${index + 1}`}
|
alt={`Image ${index + 1}`}
|
||||||
/>
|
/>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
|
))} */}
|
||||||
|
{detailThumb?.map((url: string, index: number) => (
|
||||||
|
<SwiperSlide key={index}>
|
||||||
|
<img
|
||||||
|
src={url}
|
||||||
|
alt={`Image ${index + 1}`}
|
||||||
|
className="h-[480px] max-w-[600px] rounded-md object-cover mx-auto border-2"
|
||||||
|
/>
|
||||||
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
<div className="mt-2 mx-auto min-w-fit max-w-[600px]">
|
<div className="mt-2 mx-auto min-w-fit max-w-[600px]">
|
||||||
|
|
@ -761,24 +766,34 @@ export default function FormImageDetail() {
|
||||||
<div className="flex flex-col gap-2 space-y-2">
|
<div className="flex flex-col gap-2 space-y-2">
|
||||||
<Label>Publish Target</Label>
|
<Label>Publish Target</Label>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<Checkbox
|
{/* <Checkbox
|
||||||
id="5"
|
id="5"
|
||||||
checked={selectedPublishers.includes(5)}
|
checked={selectedPublishers.includes(5)}
|
||||||
onChange={() => handleCheckboxChange(5)}
|
onChange={() => handleCheckboxChange(5)}
|
||||||
className="border"
|
className="border"
|
||||||
|
/> */}
|
||||||
|
<Checkbox
|
||||||
|
id="5"
|
||||||
|
checked={selectedPublishers.includes(5)}
|
||||||
|
disabled
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Label htmlFor="5">UMUM</Label>
|
<Label htmlFor="5">UMUM</Label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<Checkbox
|
{/* <Checkbox
|
||||||
id="6"
|
id="6"
|
||||||
checked={selectedPublishers.includes(6)}
|
checked={selectedPublishers.includes(6)}
|
||||||
onChange={() => handleCheckboxChange(6)}
|
onChange={() => handleCheckboxChange(6)}
|
||||||
className="border"
|
className="border"
|
||||||
|
/> */}
|
||||||
|
<Checkbox
|
||||||
|
id="6"
|
||||||
|
checked={selectedPublishers.includes(6)}
|
||||||
|
disabled
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="6">JOURNALIS</Label>
|
<Label htmlFor="6">JOURNALIS</Label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -847,7 +862,7 @@ export default function FormImageDetail() {
|
||||||
)} */}
|
)} */}
|
||||||
|
|
||||||
<Dialog open={modalOpen} onOpenChange={setModalOpen}>
|
<Dialog open={modalOpen} onOpenChange={setModalOpen}>
|
||||||
<DialogContent className="max-h-[600px]">
|
<DialogContent className="max-h-[600px] w-full">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Leave Comment</DialogTitle>
|
<DialogTitle>Leave Comment</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
@ -859,7 +874,7 @@ export default function FormImageDetail() {
|
||||||
className="flex flex-row gap-5 items-center w-full"
|
className="flex flex-row gap-5 items-center w-full"
|
||||||
>
|
>
|
||||||
<div className="w-[200px] h-[100px] flex justify-center items-center">
|
<div className="w-[200px] h-[100px] flex justify-center items-center">
|
||||||
<img
|
{/* <img
|
||||||
key={index}
|
key={index}
|
||||||
alt={file.fileAlt || `files-${index + 1}`}
|
alt={file.fileAlt || `files-${index + 1}`}
|
||||||
src={file.url}
|
src={file.url}
|
||||||
|
|
@ -867,6 +882,19 @@ export default function FormImageDetail() {
|
||||||
className={`h-[100px] object-cover ${
|
className={`h-[100px] object-cover ${
|
||||||
portraitMap[index] ? "w-auto" : "!w-[200px]"
|
portraitMap[index] ? "w-auto" : "!w-[200px]"
|
||||||
}`}
|
}`}
|
||||||
|
/> */}
|
||||||
|
<img
|
||||||
|
alt={file.fileAlt || `files-${index + 1}`}
|
||||||
|
src={
|
||||||
|
file.fileUrl ||
|
||||||
|
file.url ||
|
||||||
|
file.fileThumbnail ||
|
||||||
|
file.thumbnailFileUrl
|
||||||
|
}
|
||||||
|
onLoad={(e) => handleImageLoad(e, index)}
|
||||||
|
className={`h-[100px] object-contain ${
|
||||||
|
portraitMap[index] ? "w-auto" : "w-[200px]"
|
||||||
|
}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2 w-full">
|
<div className="flex flex-col gap-2 w-full">
|
||||||
|
|
|
||||||
|
|
@ -378,6 +378,7 @@ export default function FormImage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await generateDataArticle(request);
|
const res = await generateDataArticle(request);
|
||||||
|
console.log("AI RESPONSE FULL:", res);
|
||||||
close();
|
close();
|
||||||
|
|
||||||
if (res?.error) {
|
if (res?.error) {
|
||||||
|
|
@ -385,7 +386,12 @@ export default function FormImage() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newArticleId = res?.data?.data?.id;
|
// const newArticleId = res?.data?.data?.id;
|
||||||
|
const newArticleId =
|
||||||
|
res?.data?.data?.id ||
|
||||||
|
res?.data?.data?.articleId ||
|
||||||
|
res?.data?.data?.uuid;
|
||||||
|
|
||||||
setIsGeneratedArticle(true);
|
setIsGeneratedArticle(true);
|
||||||
|
|
||||||
setArticleIds((prevIds: string[]) => {
|
setArticleIds((prevIds: string[]) => {
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ export default function SignUp() {
|
||||||
|
|
||||||
// Kontributor (sementara ikut umum)
|
// Kontributor (sementara ikut umum)
|
||||||
if (role === "kontributor") {
|
if (role === "kontributor") {
|
||||||
await handleCreateUserUmum(e);
|
await handleCreateUserKontributor(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,6 +134,59 @@ export default function SignUp() {
|
||||||
return password.length >= 8;
|
return password.length >= 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCreateUserKontributor = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!firstNameKontributor.trim() || !lastNameKontributor.trim()) {
|
||||||
|
MySwal.fire(
|
||||||
|
"Peringatan",
|
||||||
|
"Nama depan dan belakang wajib diisi",
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEmail(email)) {
|
||||||
|
MySwal.fire("Peringatan", "Email tidak valid", "warning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validatePassword(kontributorPassword)) {
|
||||||
|
MySwal.fire("Peringatan", "Password minimal 8 karakter", "warning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fullName = `${firstNameKontributor} ${lastNameKontributor}`;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
address: "",
|
||||||
|
clientId: "78356d32-52fa-4dfc-b836-6cebf4e3eead",
|
||||||
|
email,
|
||||||
|
fullName,
|
||||||
|
password: kontributorPassword,
|
||||||
|
phoneNumber: whatsappKontributor,
|
||||||
|
username: fullName.toLowerCase().replace(/\s+/g, "-"),
|
||||||
|
userLevelId: 1,
|
||||||
|
userRoleId: 5, // MISAL role kontributor
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
|
const res = await createUser(payload);
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
MySwal.fire("Gagal", res?.message || "Gagal mendaftar", "error");
|
||||||
|
} else {
|
||||||
|
MySwal.fire("Berhasil", "Akun kontributor berhasil dibuat", "success");
|
||||||
|
router.push("/auth");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
MySwal.fire("Error", "Terjadi kesalahan server", "error");
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleCreateUserUmum = async (e: React.FormEvent) => {
|
const handleCreateUserUmum = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -323,7 +323,7 @@ function Card({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-[26px] px-4 space-y-2">
|
<div className="py-[26px] px-4 space-y-2">
|
||||||
<div className="flex items-center gap-2 text-xs font-semibold flex-wrap">
|
<div className="flex justify-between items-center gap-2 text-xs font-semibold flex-row">
|
||||||
<span className="bg-emerald-600 text-white px-2 py-0.5 rounded">
|
<span className="bg-emerald-600 text-white px-2 py-0.5 rounded">
|
||||||
{item.clientName}
|
{item.clientName}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -329,15 +329,7 @@ export default function MediaUpdate() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function SafeImage({
|
function SafeImage({ src, alt }: { src?: string; alt?: string }) {
|
||||||
src,
|
|
||||||
alt,
|
|
||||||
href,
|
|
||||||
}: {
|
|
||||||
src?: string;
|
|
||||||
alt?: string;
|
|
||||||
href: string;
|
|
||||||
}) {
|
|
||||||
const [imgSrc, setImgSrc] = useState(src || DEFAULT_IMAGE);
|
const [imgSrc, setImgSrc] = useState(src || DEFAULT_IMAGE);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -345,7 +337,6 @@ export default function MediaUpdate() {
|
||||||
}, [src]);
|
}, [src]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={href}>
|
|
||||||
<Image
|
<Image
|
||||||
src={imgSrc}
|
src={imgSrc}
|
||||||
alt={alt || "Image"}
|
alt={alt || "Image"}
|
||||||
|
|
@ -353,7 +344,6 @@ export default function MediaUpdate() {
|
||||||
className="object-cover cursor-pointer hover:opacity-90 transition-opacity"
|
className="object-cover cursor-pointer hover:opacity-90 transition-opacity"
|
||||||
onError={() => setImgSrc(DEFAULT_IMAGE)}
|
onError={() => setImgSrc(DEFAULT_IMAGE)}
|
||||||
/>
|
/>
|
||||||
</Link>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -504,7 +494,6 @@ export default function MediaUpdate() {
|
||||||
<SafeImage
|
<SafeImage
|
||||||
src={item.smallThumbnailLink}
|
src={item.smallThumbnailLink}
|
||||||
alt={item.title}
|
alt={item.title}
|
||||||
href={getLink(item)}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* <Image
|
{/* <Image
|
||||||
|
|
@ -519,9 +508,9 @@ export default function MediaUpdate() {
|
||||||
|
|
||||||
{/* Caption / info */}
|
{/* Caption / info */}
|
||||||
<div className="p-3">
|
<div className="p-3">
|
||||||
<div className="flex items-center gap-2 text-xs font-semibold flex-wrap mb-2">
|
<div className="flex items-center gap-2 text-xs font-semibold flex-row justify-between mb-2">
|
||||||
<span className="text-xs text-white px-2 py-0.5 rounded bg-emerald-600">
|
<span className="text-xs text-white px-2 py-0.5 rounded bg-emerald-600">
|
||||||
{item.clientName || "Tanpa Kategori"}
|
{item.clientName}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-orange-600">
|
<span className="text-orange-600">
|
||||||
{item.categories
|
{item.categories
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ export default function Navbar() {
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowProfileMenu((prev) => !prev)}
|
onClick={() => setShowProfileMenu((prev) => !prev)}
|
||||||
className="flex items-center gap-2 border-2 py-1 px-3 rounded-lg hover:bg-gray-50"
|
className="flex items-center gap-2 border-2 py-1 px-3 rounded-lg hover:bg-gray-50 cursor-pointer"
|
||||||
>
|
>
|
||||||
<div className="w-9 h-9 rounded-full overflow-hidden border">
|
<div className="w-9 h-9 rounded-full overflow-hidden border">
|
||||||
<Image
|
<Image
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue