pull
This commit is contained in:
commit
32f9bf6098
|
|
@ -49,11 +49,11 @@ const columns: ColumnDef<any>[] = [
|
||||||
header: "Jumlah Amplifikasi",
|
header: "Jumlah Amplifikasi",
|
||||||
cell: ({ row }) => <span>{row.getValue("link")}</span>,
|
cell: ({ row }) => <span>{row.getValue("link")}</span>,
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// accessorKey: "status",
|
accessorKey: "status",
|
||||||
// header: "Status",
|
header: "Status",
|
||||||
// cell: ({ row }) => <span>{row.getValue("status")}</span>,
|
cell: ({ row }) => <span>{row.getValue("status")}</span>,
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "date",
|
accessorKey: "date",
|
||||||
header: "Tanggal Penarikan",
|
header: "Tanggal Penarikan",
|
||||||
|
|
@ -77,12 +77,12 @@ const columns: ColumnDef<any>[] = [
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="p-0" align="end">
|
<DropdownMenuContent className="p-0" align="end">
|
||||||
<Link
|
<Link href={`/admin/media-tracking/detail/${row.original.id}`}>
|
||||||
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 rounded-none">
|
||||||
<Eye className="w-4 h-4 me-1.5" />
|
<Eye className="w-4 h-4 me-1.5" />
|
||||||
Detail
|
View
|
||||||
|
{row.original.mediaUpload.fileType.secondaryName &&
|
||||||
|
row.original.mediaUpload.fileType.secondaryName.toLowerCase()}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ import { ChevronDownIcon } from "lucide-react";
|
||||||
import { getOperatorUser } from "@/service/management-user/management-user";
|
import { getOperatorUser } from "@/service/management-user/management-user";
|
||||||
|
|
||||||
const taskSchema = z.object({
|
const taskSchema = z.object({
|
||||||
message: z.string().optional(),
|
title: z.string().optional(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -275,7 +275,7 @@ export default function FormQuestionsReply() {
|
||||||
title: data.title,
|
title: data.title,
|
||||||
description: data.description,
|
description: data.description,
|
||||||
priorityId: selectedPriority,
|
priorityId: selectedPriority,
|
||||||
statusId: selectedStatus,
|
statusId: 1,
|
||||||
typeId: detailTickets?.typeId,
|
typeId: detailTickets?.typeId,
|
||||||
parentCommentId: detailTickets?.feedId,
|
parentCommentId: detailTickets?.feedId,
|
||||||
operatorTeam: selectedOperator.join(","),
|
operatorTeam: selectedOperator.join(","),
|
||||||
|
|
@ -507,7 +507,7 @@ export default function FormQuestionsReply() {
|
||||||
<Label>Judul</Label>
|
<Label>Judul</Label>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="message"
|
name="title"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Input
|
<Input
|
||||||
size="md"
|
size="md"
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import { uploadThumbnailBlog } from "@/service/blog/blog";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import {
|
import {
|
||||||
generateDataArticle,
|
generateDataArticle,
|
||||||
|
generateDataRewrite,
|
||||||
getDetailArticle,
|
getDetailArticle,
|
||||||
getGenerateKeywords,
|
getGenerateKeywords,
|
||||||
getGenerateTitle,
|
getGenerateTitle,
|
||||||
|
|
@ -55,6 +56,7 @@ 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 { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import { useParams } from "next/navigation";
|
||||||
|
|
||||||
interface FileWithPreview extends File {
|
interface FileWithPreview extends File {
|
||||||
preview: string;
|
preview: string;
|
||||||
|
|
@ -82,6 +84,10 @@ export default function FormAudio() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
type AudioSchema = z.infer<typeof audioSchema>;
|
type AudioSchema = z.infer<typeof audioSchema>;
|
||||||
|
const params = useParams();
|
||||||
|
const locale = params?.locale;
|
||||||
|
|
||||||
|
const [selectedFileType, setSelectedFileType] = useState("original");
|
||||||
|
|
||||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
const taskId = Cookies.get("taskId");
|
const taskId = Cookies.get("taskId");
|
||||||
|
|
@ -97,6 +103,11 @@ export default function FormAudio() {
|
||||||
const [preview, setPreview] = useState<string | null>(null);
|
const [preview, setPreview] = useState<string | null>(null);
|
||||||
const [selectedLanguage, setSelectedLanguage] = useState("");
|
const [selectedLanguage, setSelectedLanguage] = useState("");
|
||||||
|
|
||||||
|
const [selectedWritingStyle, setSelectedWritingStyle] =
|
||||||
|
useState("professional");
|
||||||
|
const [editorContent, setEditorContent] = useState(""); // Untuk original editor
|
||||||
|
const [rewriteEditorContent, setRewriteEditorContent] = useState("");
|
||||||
|
|
||||||
const [selectedSEO, setSelectedSEO] = useState<string>("");
|
const [selectedSEO, setSelectedSEO] = useState<string>("");
|
||||||
const [title, setTitle] = useState<string>("");
|
const [title, setTitle] = useState<string>("");
|
||||||
const [selectedAdvConfig, setSelectedAdvConfig] = useState<string>("");
|
const [selectedAdvConfig, setSelectedAdvConfig] = useState<string>("");
|
||||||
|
|
@ -111,7 +122,6 @@ export default function FormAudio() {
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
||||||
const [selectedWritingStyle, setSelectedWritingStyle] = useState("");
|
|
||||||
const [selectedSize, setSelectedSize] = useState("");
|
const [selectedSize, setSelectedSize] = useState("");
|
||||||
const [detailData, setDetailData] = useState<any>(null);
|
const [detailData, setDetailData] = useState<any>(null);
|
||||||
const [articleImages, setArticleImages] = useState<string[]>([]);
|
const [articleImages, setArticleImages] = useState<string[]>([]);
|
||||||
|
|
@ -133,6 +143,8 @@ export default function FormAudio() {
|
||||||
const [isStartUpload, setIsStartUpload] = useState(false);
|
const [isStartUpload, setIsStartUpload] = useState(false);
|
||||||
const [counterProgress, setCounterProgress] = useState(0);
|
const [counterProgress, setCounterProgress] = useState(0);
|
||||||
|
|
||||||
|
const [isContentRewriteClicked, setIsContentRewriteClicked] = useState(false);
|
||||||
|
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
||||||
const [files, setFiles] = useState<FileWithPreview[]>([]);
|
const [files, setFiles] = useState<FileWithPreview[]>([]);
|
||||||
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
||||||
|
|
||||||
|
|
@ -155,15 +167,11 @@ export default function FormAudio() {
|
||||||
|
|
||||||
const audioSchema = z.object({
|
const audioSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
description: z
|
description: z.string().optional(),
|
||||||
.string()
|
descriptionOri: z.string().optional(), // Original editor
|
||||||
.min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." })
|
rewriteDescription: z.string().optional(), // Rewrite editor
|
||||||
.or(
|
|
||||||
z.literal(articleBody || "").refine((val) => val.length > 0, {
|
|
||||||
message: "Deskripsi diperlukan.",
|
|
||||||
})
|
|
||||||
),
|
|
||||||
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
||||||
|
|
||||||
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -175,6 +183,11 @@ export default function FormAudio() {
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<AudioSchema>({
|
} = useForm<AudioSchema>({
|
||||||
resolver: zodResolver(audioSchema),
|
resolver: zodResolver(audioSchema),
|
||||||
|
defaultValues: {
|
||||||
|
description: "",
|
||||||
|
descriptionOri: "",
|
||||||
|
rewriteDescription: "",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const doGenerateMainKeyword = async () => {
|
const doGenerateMainKeyword = async () => {
|
||||||
|
|
@ -437,12 +450,24 @@ export default function FormAudio() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (articleBody) {
|
||||||
|
// Set ke dua field jika rewrite juga aktif
|
||||||
|
setValue("description", articleBody);
|
||||||
|
setValue("rewriteDescription", articleBody);
|
||||||
|
}
|
||||||
|
}, [articleBody, setValue]);
|
||||||
|
|
||||||
const save = async (data: AudioSchema) => {
|
const save = async (data: AudioSchema) => {
|
||||||
loading();
|
loading();
|
||||||
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 = isSwitchOn
|
||||||
if (!finalDescription.trim()) {
|
? data.description
|
||||||
|
: selectedFileType === "rewrite"
|
||||||
|
? data.rewriteDescription
|
||||||
|
: data.descriptionOri;
|
||||||
|
if (!finalDescription?.trim()) {
|
||||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -719,6 +744,45 @@ export default function FormAudio() {
|
||||||
}
|
}
|
||||||
}, [title, getValues, setValue]);
|
}, [title, getValues, setValue]);
|
||||||
|
|
||||||
|
const handleRewriteClick = async () => {
|
||||||
|
setIsContentRewriteClicked(true);
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
style: selectedWritingStyle,
|
||||||
|
lang: "id",
|
||||||
|
contextType: "text",
|
||||||
|
urlContext: null,
|
||||||
|
context: editorContent, // Ambil isi editor original
|
||||||
|
createdBy: roleId,
|
||||||
|
sentiment: "Humorous",
|
||||||
|
clientId: "7QTW8cMojyayt6qnhqTOeJaBI70W4EaQ",
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await generateDataRewrite(request);
|
||||||
|
close();
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
console.error(res.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newArticleId = res?.data?.data?.id;
|
||||||
|
setIsGeneratedArticle(true);
|
||||||
|
|
||||||
|
setArticleIds((prevIds: string[]) => {
|
||||||
|
if (prevIds.length < 3) {
|
||||||
|
return [...prevIds, newArticleId];
|
||||||
|
} else {
|
||||||
|
const updatedIds = [...prevIds];
|
||||||
|
updatedIds[2] = newArticleId;
|
||||||
|
return updatedIds;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Cookies.set("nulisAIArticleIdTemp", JSON.stringify(articleIds));
|
||||||
|
setShowRewriteEditor(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="flex flex-col lg:flex-row gap-10">
|
<div className="flex flex-col lg:flex-row gap-10">
|
||||||
|
|
@ -911,7 +975,7 @@ export default function FormAudio() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<Label>{t("special-instructions")} (Optional)</Label>
|
<Label>{t("special-instructions")}(Optional)</Label>
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -940,7 +1004,7 @@ export default function FormAudio() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isGeneratedArticle && (
|
{isGeneratedArticle && (
|
||||||
<div className="mt-3 pb-0 flex flex-row ">
|
<div className="mt-3 pb-0 flex flex-row">
|
||||||
{articleIds.map((id: string, index: number) => (
|
{articleIds.map((id: string, index: number) => (
|
||||||
<p
|
<p
|
||||||
key={index}
|
key={index}
|
||||||
|
|
@ -960,27 +1024,23 @@ export default function FormAudio() {
|
||||||
<div className="pt-3">
|
<div className="pt-3">
|
||||||
<div className="flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-between items-center">
|
||||||
{selectedArticleId && (
|
{selectedArticleId && (
|
||||||
<Link
|
|
||||||
href={`/contributor/content/audio/update-seo/${selectedArticleId}`}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
className="mb-2"
|
className="mb-2"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={"outline"}
|
variant={"outline"}
|
||||||
color="primary"
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
const url = `/${locale}/contributor/content/image/update-seo/${selectedArticleId}`;
|
||||||
|
window.open(url, "_blank", "noopener,noreferrer");
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t("update")}
|
{t("update")}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="py-3 space-y-2">
|
||||||
)}
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label>{t("description")}</Label>
|
<Label>{t("description")}</Label>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -988,11 +1048,16 @@ export default function FormAudio() {
|
||||||
render={({ field: { onChange, value } }) =>
|
render={({ field: { onChange, value } }) =>
|
||||||
isLoadingData ? (
|
isLoadingData ? (
|
||||||
<div className="flex justify-center items-center h-40">
|
<div className="flex justify-center items-center h-40">
|
||||||
<p className="text-gray-500">Loading Proses Data...</p>
|
<p className="text-gray-500">
|
||||||
|
Loading Proses Data...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<CustomEditor
|
<CustomEditor
|
||||||
onChange={onChange}
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setEditorContent(value);
|
||||||
|
}}
|
||||||
initialData={articleBody || value}
|
initialData={articleBody || value}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
@ -1004,6 +1069,110 @@ export default function FormAudio() {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!isSwitchOn && (
|
||||||
|
<>
|
||||||
|
<RadioGroup
|
||||||
|
onValueChange={(value) => setSelectedFileType(value)}
|
||||||
|
value={selectedFileType}
|
||||||
|
className=" grid-cols-1"
|
||||||
|
>
|
||||||
|
<div className="">
|
||||||
|
<RadioGroupItem value="original" id="original-file" />
|
||||||
|
<Label htmlFor="original-file">
|
||||||
|
Select Original Description
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<div className="py-3 space-y-2">
|
||||||
|
<Label>{t("description")}</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="descriptionOri"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<CustomEditor
|
||||||
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setEditorContent(value);
|
||||||
|
}}
|
||||||
|
initialData={value}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-sm font-semibold">Content Rewrite</p>
|
||||||
|
<div className="my-2">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
onClick={handleRewriteClick}
|
||||||
|
className="bg-blue-500 text-white py-2 px-4 rounded"
|
||||||
|
>
|
||||||
|
Content Rewrite
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showRewriteEditor && (
|
||||||
|
<div>
|
||||||
|
{isGeneratedArticle && (
|
||||||
|
<div className="mt-3 pb-0 flex flex-row ">
|
||||||
|
{articleIds.map((id: string, index: number) => (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
key={index}
|
||||||
|
className={`mr-3 px-3 py-2 rounded-md ${
|
||||||
|
selectedArticleId === id
|
||||||
|
? "bg-green-500 text-white"
|
||||||
|
: "border-2 border-green-500 bg-white text-green-500 hover:bg-green-500 hover:text-white hover:border-green-500"
|
||||||
|
}`}
|
||||||
|
onClick={() => handleArticleIdClick(id)}
|
||||||
|
>
|
||||||
|
{"Narasi " + (index + 1)}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex items-center space-x-2 mt-3">
|
||||||
|
<RadioGroupItem value="rewrite" id="rewrite-file" />
|
||||||
|
<Label htmlFor="rewrite-file">
|
||||||
|
Select Description Rewrite
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<div className="py-3 space-y-2">
|
||||||
|
<Label>{t("file-rewrite")}</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="rewriteDescription"
|
||||||
|
render={({ field: { onChange, value } }) =>
|
||||||
|
isLoadingData ? (
|
||||||
|
<div className="flex justify-center items-center h-40">
|
||||||
|
<p className="text-gray-500">
|
||||||
|
Loading Proses Data...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<CustomEditor
|
||||||
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setRewriteEditorContent(value);
|
||||||
|
}}
|
||||||
|
initialData={articleBody || value}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</RadioGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="py-3 space-y-2">
|
<div className="py-3 space-y-2">
|
||||||
<Label>{t("select-file")}</Label>
|
<Label>{t("select-file")}</Label>
|
||||||
{/* <Input
|
{/* <Input
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import { uploadThumbnailBlog } from "@/service/blog/blog";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import {
|
import {
|
||||||
generateDataArticle,
|
generateDataArticle,
|
||||||
|
generateDataRewrite,
|
||||||
getDetailArticle,
|
getDetailArticle,
|
||||||
getGenerateKeywords,
|
getGenerateKeywords,
|
||||||
getGenerateTitle,
|
getGenerateTitle,
|
||||||
|
|
@ -94,6 +95,7 @@ export default function FormImage() {
|
||||||
const scheduleId = Cookies.get("scheduleId");
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
const scheduleType = Cookies.get("scheduleType");
|
const scheduleType = Cookies.get("scheduleType");
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const [selectedFileType, setSelectedFileType] = useState("original");
|
||||||
|
|
||||||
const [categories, setCategories] = useState<Category[]>([]);
|
const [categories, setCategories] = useState<Category[]>([]);
|
||||||
const [selectedCategory, setSelectedCategory] = useState<any>();
|
const [selectedCategory, setSelectedCategory] = useState<any>();
|
||||||
|
|
@ -116,7 +118,10 @@ export default function FormImage() {
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
||||||
const [selectedWritingStyle, setSelectedWritingStyle] = useState("");
|
const [selectedWritingStyle, setSelectedWritingStyle] =
|
||||||
|
useState("professional");
|
||||||
|
const [editorContent, setEditorContent] = useState(""); // Untuk original editor
|
||||||
|
const [rewriteEditorContent, setRewriteEditorContent] = useState("");
|
||||||
const [selectedSize, setSelectedSize] = useState("");
|
const [selectedSize, setSelectedSize] = useState("");
|
||||||
const [detailData, setDetailData] = useState<any>(null);
|
const [detailData, setDetailData] = useState<any>(null);
|
||||||
const [articleImages, setArticleImages] = useState<string[]>([]);
|
const [articleImages, setArticleImages] = useState<string[]>([]);
|
||||||
|
|
@ -125,6 +130,8 @@ export default function FormImage() {
|
||||||
|
|
||||||
const [content, setContent] = useState("");
|
const [content, setContent] = useState("");
|
||||||
|
|
||||||
|
const [isContentRewriteClicked, setIsContentRewriteClicked] = useState(false);
|
||||||
|
|
||||||
const [selectedTarget, setSelectedTarget] = useState("");
|
const [selectedTarget, setSelectedTarget] = useState("");
|
||||||
const [unitSelection, setUnitSelection] = useState({
|
const [unitSelection, setUnitSelection] = useState({
|
||||||
allUnit: false,
|
allUnit: false,
|
||||||
|
|
@ -140,6 +147,7 @@ export default function FormImage() {
|
||||||
let uploadPersen = 0;
|
let uploadPersen = 0;
|
||||||
const [isStartUpload, setIsStartUpload] = useState(false);
|
const [isStartUpload, setIsStartUpload] = useState(false);
|
||||||
const [counterProgress, setCounterProgress] = useState(0);
|
const [counterProgress, setCounterProgress] = useState(0);
|
||||||
|
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
||||||
|
|
||||||
const [files, setFiles] = useState<FileWithPreview[]>([]);
|
const [files, setFiles] = useState<FileWithPreview[]>([]);
|
||||||
const [filesTemp, setFilesTemp] = useState<File[]>([]);
|
const [filesTemp, setFilesTemp] = useState<File[]>([]);
|
||||||
|
|
@ -164,16 +172,10 @@ export default function FormImage() {
|
||||||
|
|
||||||
const imageSchema = z.object({
|
const imageSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
description: z
|
description: z.string().optional(),
|
||||||
.string()
|
descriptionOri: z.string().optional(),
|
||||||
.min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." })
|
rewriteDescription: z.string().optional(),
|
||||||
.or(
|
|
||||||
z.literal(articleBody || "").refine((val) => val.length > 0, {
|
|
||||||
message: "Deskripsi diperlukan.",
|
|
||||||
})
|
|
||||||
),
|
|
||||||
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
||||||
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
@ -184,6 +186,11 @@ export default function FormImage() {
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<ImageSchema>({
|
} = useForm<ImageSchema>({
|
||||||
resolver: zodResolver(imageSchema),
|
resolver: zodResolver(imageSchema),
|
||||||
|
defaultValues: {
|
||||||
|
description: "",
|
||||||
|
descriptionOri: "",
|
||||||
|
rewriteDescription: "",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const doGenerateMainKeyword = async () => {
|
const doGenerateMainKeyword = async () => {
|
||||||
|
|
@ -446,13 +453,25 @@ export default function FormImage() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (articleBody) {
|
||||||
|
setValue("description", articleBody);
|
||||||
|
setValue("rewriteDescription", articleBody);
|
||||||
|
}
|
||||||
|
}, [articleBody, setValue]);
|
||||||
|
|
||||||
const save = async (data: ImageSchema) => {
|
const save = async (data: ImageSchema) => {
|
||||||
loading();
|
loading();
|
||||||
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;
|
||||||
|
const finalDescription = isSwitchOn
|
||||||
|
? data.description
|
||||||
|
: selectedFileType === "rewrite"
|
||||||
|
? data.rewriteDescription
|
||||||
|
: data.descriptionOri;
|
||||||
|
|
||||||
if (!finalDescription.trim()) {
|
if (!finalDescription?.trim()) {
|
||||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -716,6 +735,45 @@ export default function FormImage() {
|
||||||
}
|
}
|
||||||
}, [title, getValues, setValue]);
|
}, [title, getValues, setValue]);
|
||||||
|
|
||||||
|
const handleRewriteClick = async () => {
|
||||||
|
setIsContentRewriteClicked(true);
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
style: selectedWritingStyle,
|
||||||
|
lang: "id",
|
||||||
|
contextType: "text",
|
||||||
|
urlContext: null,
|
||||||
|
context: editorContent, // Ambil isi editor original
|
||||||
|
createdBy: roleId,
|
||||||
|
sentiment: "Humorous",
|
||||||
|
clientId: "7QTW8cMojyayt6qnhqTOeJaBI70W4EaQ",
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await generateDataRewrite(request);
|
||||||
|
close();
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
console.error(res.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newArticleId = res?.data?.data?.id;
|
||||||
|
setIsGeneratedArticle(true);
|
||||||
|
|
||||||
|
setArticleIds((prevIds: string[]) => {
|
||||||
|
if (prevIds.length < 3) {
|
||||||
|
return [...prevIds, newArticleId];
|
||||||
|
} else {
|
||||||
|
const updatedIds = [...prevIds];
|
||||||
|
updatedIds[2] = newArticleId;
|
||||||
|
return updatedIds;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Cookies.set("nulisAIArticleIdTemp", JSON.stringify(articleIds));
|
||||||
|
setShowRewriteEditor(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="flex flex-col lg:flex-row gap-10">
|
<div className="flex flex-col lg:flex-row gap-10">
|
||||||
|
|
@ -930,6 +988,7 @@ export default function FormImage() {
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleGenerateArtikel}
|
onClick={handleGenerateArtikel}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
Generate Article
|
Generate Article
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -972,8 +1031,6 @@ export default function FormImage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="py-3 space-y-2">
|
<div className="py-3 space-y-2">
|
||||||
<Label>{t("description")}</Label>
|
<Label>{t("description")}</Label>
|
||||||
<Controller
|
<Controller
|
||||||
|
|
@ -982,11 +1039,16 @@ export default function FormImage() {
|
||||||
render={({ field: { onChange, value } }) =>
|
render={({ field: { onChange, value } }) =>
|
||||||
isLoadingData ? (
|
isLoadingData ? (
|
||||||
<div className="flex justify-center items-center h-40">
|
<div className="flex justify-center items-center h-40">
|
||||||
<p className="text-gray-500">Loading Proses Data...</p>
|
<p className="text-gray-500">
|
||||||
|
Loading Proses Data...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<CustomEditor
|
<CustomEditor
|
||||||
onChange={onChange}
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setEditorContent(value);
|
||||||
|
}}
|
||||||
initialData={articleBody || value}
|
initialData={articleBody || value}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
@ -998,6 +1060,110 @@ export default function FormImage() {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!isSwitchOn && (
|
||||||
|
<>
|
||||||
|
<RadioGroup
|
||||||
|
onValueChange={(value) => setSelectedFileType(value)}
|
||||||
|
value={selectedFileType}
|
||||||
|
className=" grid-cols-1"
|
||||||
|
>
|
||||||
|
<div className="">
|
||||||
|
<RadioGroupItem value="original" id="original-file" />
|
||||||
|
<Label htmlFor="original-file">
|
||||||
|
Select Original Description
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<div className="py-3 space-y-2">
|
||||||
|
<Label>{t("description")}</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="descriptionOri"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<CustomEditor
|
||||||
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setEditorContent(value);
|
||||||
|
}}
|
||||||
|
initialData={value}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-sm font-semibold">Content Rewrite</p>
|
||||||
|
<div className="my-2">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
onClick={handleRewriteClick}
|
||||||
|
className="bg-blue-500 text-white py-2 px-4 rounded"
|
||||||
|
>
|
||||||
|
Content Rewrite
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showRewriteEditor && (
|
||||||
|
<div>
|
||||||
|
{isGeneratedArticle && (
|
||||||
|
<div className="mt-3 pb-0 flex flex-row ">
|
||||||
|
{articleIds.map((id: string, index: number) => (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
key={index}
|
||||||
|
className={`mr-3 px-3 py-2 rounded-md ${
|
||||||
|
selectedArticleId === id
|
||||||
|
? "bg-green-500 text-white"
|
||||||
|
: "border-2 border-green-500 bg-white text-green-500 hover:bg-green-500 hover:text-white hover:border-green-500"
|
||||||
|
}`}
|
||||||
|
onClick={() => handleArticleIdClick(id)}
|
||||||
|
>
|
||||||
|
{"Narasi " + (index + 1)}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex items-center space-x-2 mt-3">
|
||||||
|
<RadioGroupItem value="rewrite" id="rewrite-file" />
|
||||||
|
<Label htmlFor="rewrite-file">
|
||||||
|
Select Description Rewrite
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<div className="py-3 space-y-2">
|
||||||
|
<Label>{t("file-rewrite")}</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="rewriteDescription"
|
||||||
|
render={({ field: { onChange, value } }) =>
|
||||||
|
isLoadingData ? (
|
||||||
|
<div className="flex justify-center items-center h-40">
|
||||||
|
<p className="text-gray-500">
|
||||||
|
Loading Proses Data...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<CustomEditor
|
||||||
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setRewriteEditorContent(value);
|
||||||
|
}}
|
||||||
|
initialData={articleBody || value}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</RadioGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="py-3 space-y-2">
|
<div className="py-3 space-y-2">
|
||||||
<Label>{t("select-file")}</Label>
|
<Label>{t("select-file")}</Label>
|
||||||
{/* <Input
|
{/* <Input
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ export default function FormConvertSPIT() {
|
||||||
const { id } = useParams() as { id: string };
|
const { id } = useParams() as { id: string };
|
||||||
console.log(id);
|
console.log(id);
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
// type ImageSchema = z.infer<typeof imageSchema>;
|
type ImageSchema = z.infer<typeof imageSchema>;
|
||||||
|
|
||||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
const taskId = Cookies.get("taskId");
|
const taskId = Cookies.get("taskId");
|
||||||
|
|
@ -165,24 +165,10 @@ export default function FormConvertSPIT() {
|
||||||
|
|
||||||
const imageSchema = z.object({
|
const imageSchema = z.object({
|
||||||
contentTitle: z.string().min(1, { message: "Judul diperlukan" }),
|
contentTitle: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
contentDescription: z
|
contentDescription: z.string().optional(),
|
||||||
.string()
|
|
||||||
.min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }),
|
|
||||||
contentCreator: z.string().min(1, { message: "Creator diperlukan" }),
|
|
||||||
contentRewriteDescription: z.string().optional(),
|
contentRewriteDescription: z.string().optional(),
|
||||||
|
contentCreator: z.string().min(1, { message: "Creator diperlukan" }),
|
||||||
});
|
});
|
||||||
// .refine(
|
|
||||||
// (data) => {
|
|
||||||
// if (isContentRewriteClicked) {
|
|
||||||
// return detail?.contentRewriteDescription?.trim().length > 0;
|
|
||||||
// }
|
|
||||||
// return true;
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// path: ["contentRewriteDescription"],
|
|
||||||
// message: "File hasil rewrite wajib diisi",
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
|
|
||||||
const options: Option[] = [
|
const options: Option[] = [
|
||||||
{ id: "all", label: "SEMUA" },
|
{ id: "all", label: "SEMUA" },
|
||||||
|
|
@ -194,33 +180,39 @@ export default function FormConvertSPIT() {
|
||||||
|
|
||||||
let fileTypeId = "1";
|
let fileTypeId = "1";
|
||||||
|
|
||||||
// const {
|
const {
|
||||||
// control,
|
control,
|
||||||
// handleSubmit,
|
handleSubmit,
|
||||||
// setValue,
|
setValue,
|
||||||
// formState: { errors },
|
formState: { errors },
|
||||||
// } = useForm<ImageSchema>({
|
} = useForm<ImageSchema>({
|
||||||
// resolver: zodResolver(imageSchema),
|
|
||||||
// defaultValues: {
|
|
||||||
// contentTitle: detail?.contentTitle || "",
|
|
||||||
// contentDescription: detail?.contentDescription || "",
|
|
||||||
// contentCreator: detail?.contentCreator || "",
|
|
||||||
// contentRewriteDescription: detail?.contentRewriteDescription || "",
|
|
||||||
// // dll
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof imageSchema>>({
|
|
||||||
resolver: zodResolver(imageSchema),
|
resolver: zodResolver(imageSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
contentTitle: detail?.contentTitle || "",
|
contentTitle: detail?.contentTitle || "",
|
||||||
contentDescription: detail?.contentDescription || "",
|
contentDescription: detail?.contentDescription || "",
|
||||||
contentCreator: detail?.contentCreator || "",
|
contentCreator: detail?.contentCreator || "",
|
||||||
|
contentRewriteDescription: detail?.contentRewriteDescription || "",
|
||||||
// dll
|
// dll
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// const form = useForm<z.infer<typeof imageSchema>>({
|
||||||
|
// resolver: zodResolver(imageSchema),
|
||||||
|
// defaultValues: {
|
||||||
|
// contentTitle: detail?.contentTitle || "",
|
||||||
|
// contentDescription: detail?.contentDescription || "",
|
||||||
|
// contentCreator: detail?.contentCreator || "",
|
||||||
|
|
||||||
|
// // dll
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (articleBody) {
|
||||||
|
setValue("contentRewriteDescription", articleBody);
|
||||||
|
}
|
||||||
|
}, [articleBody, setValue]);
|
||||||
|
|
||||||
const handleRemoveTag = (index: any) => {
|
const handleRemoveTag = (index: any) => {
|
||||||
setTags((prevTags) => prevTags.filter((_, i) => i !== index));
|
setTags((prevTags) => prevTags.filter((_, i) => i !== index));
|
||||||
};
|
};
|
||||||
|
|
@ -237,10 +229,10 @@ export default function FormConvertSPIT() {
|
||||||
setSelectedFiles((prevImages) => prevImages.filter((_, i) => i !== index));
|
setSelectedFiles((prevImages) => prevImages.filter((_, i) => i !== index));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDirectSave = () => {
|
// const handleDirectSave = () => {
|
||||||
const values = form.getValues();
|
// const values = form.getValues();
|
||||||
onSubmit(values);
|
// onSubmit(values);
|
||||||
};
|
// };
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function initState() {
|
async function initState() {
|
||||||
|
|
@ -274,7 +266,7 @@ export default function FormConvertSPIT() {
|
||||||
|
|
||||||
const getCategories = async () => {
|
const getCategories = async () => {
|
||||||
try {
|
try {
|
||||||
const category = await listCategory(fileTypeId);
|
const category = await listEnableCategory(fileTypeId);
|
||||||
const resCategory: Category[] = category?.data?.data?.content;
|
const resCategory: Category[] = category?.data?.data?.content;
|
||||||
|
|
||||||
setCategories(resCategory);
|
setCategories(resCategory);
|
||||||
|
|
@ -346,10 +338,10 @@ export default function FormConvertSPIT() {
|
||||||
setDetail(details);
|
setDetail(details);
|
||||||
setFiles(details?.contentList);
|
setFiles(details?.contentList);
|
||||||
setupPlacementCheck(details?.contentList?.length);
|
setupPlacementCheck(details?.contentList?.length);
|
||||||
form.setValue("contentTitle", details?.contentTitle || "");
|
setValue("contentTitle", details?.contentTitle || "");
|
||||||
form.setValue("contentDescription", details?.contentDescription || "");
|
setValue("contentDescription", details?.contentDescription || "");
|
||||||
form.setValue("contentCreator", details?.contentCreator || "");
|
setValue("contentCreator", details?.contentCreator || "");
|
||||||
form.setValue(
|
setValue(
|
||||||
"contentRewriteDescription",
|
"contentRewriteDescription",
|
||||||
details?.contentRewriteDescription || ""
|
details?.contentRewriteDescription || ""
|
||||||
);
|
);
|
||||||
|
|
@ -471,12 +463,7 @@ export default function FormConvertSPIT() {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const save = async (data: {
|
const save = async (data: ImageSchema) => {
|
||||||
contentTitle: string;
|
|
||||||
contentDescription: string;
|
|
||||||
contentRewriteDescription?: string;
|
|
||||||
contentCreator: string;
|
|
||||||
}): Promise<void> => {
|
|
||||||
const temp = [];
|
const temp = [];
|
||||||
for (const element of detail.contentList) {
|
for (const element of detail.contentList) {
|
||||||
temp.push([]);
|
temp.push([]);
|
||||||
|
|
@ -514,7 +501,7 @@ export default function FormConvertSPIT() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = async (data: z.infer<typeof imageSchema>) => {
|
const onSubmit = (data: ImageSchema) => {
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Simpan Data",
|
title: "Simpan Data",
|
||||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||||
|
|
@ -671,8 +658,7 @@ export default function FormConvertSPIT() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form {...form}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
||||||
{detail !== undefined ? (
|
{detail !== undefined ? (
|
||||||
<div className="flex flex-col lg:flex-row gap-10">
|
<div className="flex flex-col lg:flex-row gap-10">
|
||||||
<Card className="w-full lg:w-8/12">
|
<Card className="w-full lg:w-8/12">
|
||||||
|
|
@ -683,7 +669,7 @@ export default function FormConvertSPIT() {
|
||||||
<div className="space-y-2 py-3">
|
<div className="space-y-2 py-3">
|
||||||
<Label>{t("title")}</Label>
|
<Label>{t("title")}</Label>
|
||||||
<Controller
|
<Controller
|
||||||
control={form.control}
|
control={control}
|
||||||
name="contentTitle"
|
name="contentTitle"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -737,15 +723,9 @@ export default function FormConvertSPIT() {
|
||||||
<div className="py-3 space-y-2">
|
<div className="py-3 space-y-2">
|
||||||
<Label>{t("description")}</Label>
|
<Label>{t("description")}</Label>
|
||||||
<Controller
|
<Controller
|
||||||
control={form.control}
|
control={control}
|
||||||
name="contentDescription"
|
name="contentDescription"
|
||||||
render={({ field: { onChange, value } }) => (
|
render={({ field: { onChange, value } }) => (
|
||||||
// <JoditEditor
|
|
||||||
// ref={editor}
|
|
||||||
// value={detail?.contentDescription}
|
|
||||||
// onChange={onChange}
|
|
||||||
// className="dark:text-black"
|
|
||||||
// />
|
|
||||||
<CustomEditor
|
<CustomEditor
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
initialData={detail?.contentDescription}
|
initialData={detail?.contentDescription}
|
||||||
|
|
@ -807,10 +787,7 @@ export default function FormConvertSPIT() {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center space-x-2 mt-3">
|
<div className="flex items-center space-x-2 mt-3">
|
||||||
<RadioGroupItem
|
<RadioGroupItem value="rewrite" id="rewrite-file" />
|
||||||
value="rewrite"
|
|
||||||
id="rewrite-file"
|
|
||||||
/>
|
|
||||||
<Label htmlFor="rewrite-file">
|
<Label htmlFor="rewrite-file">
|
||||||
Select File Rewrite
|
Select File Rewrite
|
||||||
</Label>
|
</Label>
|
||||||
|
|
@ -818,7 +795,7 @@ export default function FormConvertSPIT() {
|
||||||
<div className="py-3 space-y-2">
|
<div className="py-3 space-y-2">
|
||||||
<Label>{t("file-rewrite")}</Label>
|
<Label>{t("file-rewrite")}</Label>
|
||||||
<Controller
|
<Controller
|
||||||
control={form.control}
|
control={control}
|
||||||
name="contentRewriteDescription"
|
name="contentRewriteDescription"
|
||||||
render={({ field: { onChange, value } }) =>
|
render={({ field: { onChange, value } }) =>
|
||||||
isLoadingData ? (
|
isLoadingData ? (
|
||||||
|
|
@ -830,11 +807,7 @@ export default function FormConvertSPIT() {
|
||||||
) : (
|
) : (
|
||||||
<CustomEditor
|
<CustomEditor
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
initialData={
|
initialData={articleBody || value}
|
||||||
articleBody ||
|
|
||||||
detail?.contentRewriteDescription ||
|
|
||||||
value
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -983,9 +956,7 @@ export default function FormConvertSPIT() {
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="terms"
|
id="terms"
|
||||||
checked={filePlacements[index]?.includes(
|
checked={filePlacements[index]?.includes("mabes")}
|
||||||
"mabes"
|
|
||||||
)}
|
|
||||||
onCheckedChange={(e) =>
|
onCheckedChange={(e) =>
|
||||||
setupPlacement(index, "mabes", Boolean(e))
|
setupPlacement(index, "mabes", Boolean(e))
|
||||||
}
|
}
|
||||||
|
|
@ -1000,9 +971,7 @@ export default function FormConvertSPIT() {
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="terms"
|
id="terms"
|
||||||
checked={filePlacements[index]?.includes(
|
checked={filePlacements[index]?.includes("polda")}
|
||||||
"polda"
|
|
||||||
)}
|
|
||||||
onCheckedChange={(e) =>
|
onCheckedChange={(e) =>
|
||||||
setupPlacement(index, "polda", Boolean(e))
|
setupPlacement(index, "polda", Boolean(e))
|
||||||
}
|
}
|
||||||
|
|
@ -1049,7 +1018,7 @@ export default function FormConvertSPIT() {
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>{t("creator")}</Label>
|
<Label>{t("creator")}</Label>
|
||||||
<Controller
|
<Controller
|
||||||
control={form.control}
|
control={control}
|
||||||
name="contentCreator"
|
name="contentCreator"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -1099,10 +1068,7 @@ export default function FormConvertSPIT() {
|
||||||
<div className="flex flex-col gap-3 space-y-2">
|
<div className="flex flex-col gap-3 space-y-2">
|
||||||
<Label>{t("publish-target")}</Label>
|
<Label>{t("publish-target")}</Label>
|
||||||
{options.map((option) => (
|
{options.map((option) => (
|
||||||
<div
|
<div key={option.id} className="flex gap-2 items-center">
|
||||||
key={option.id}
|
|
||||||
className="flex gap-2 items-center"
|
|
||||||
>
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id={option.id}
|
id={option.id}
|
||||||
checked={
|
checked={
|
||||||
|
|
@ -1144,7 +1110,6 @@ export default function FormConvertSPIT() {
|
||||||
""
|
""
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import * as z from "zod";
|
||||||
import { Upload } from "tus-js-client";
|
import { Upload } from "tus-js-client";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import { redirect, useRouter } from "next/navigation";
|
import { redirect, useParams, useRouter } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
|
|
@ -40,6 +40,7 @@ import { uploadThumbnailBlog } from "@/service/blog/blog";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import {
|
import {
|
||||||
generateDataArticle,
|
generateDataArticle,
|
||||||
|
generateDataRewrite,
|
||||||
getDetailArticle,
|
getDetailArticle,
|
||||||
getGenerateKeywords,
|
getGenerateKeywords,
|
||||||
getGenerateTitle,
|
getGenerateTitle,
|
||||||
|
|
@ -83,11 +84,15 @@ export default function FormTeks() {
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
type TeksSchema = z.infer<typeof teksSchema>;
|
type TeksSchema = z.infer<typeof teksSchema>;
|
||||||
|
|
||||||
|
const params = useParams();
|
||||||
|
const locale = params?.locale;
|
||||||
|
|
||||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
const taskId = Cookies.get("taskId");
|
const taskId = Cookies.get("taskId");
|
||||||
const scheduleId = Cookies.get("scheduleId");
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
const scheduleType = Cookies.get("scheduleType");
|
const scheduleType = Cookies.get("scheduleType");
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const [selectedFileType, setSelectedFileType] = useState("original");
|
||||||
|
|
||||||
const [categories, setCategories] = useState<Category[]>([]);
|
const [categories, setCategories] = useState<Category[]>([]);
|
||||||
const [selectedCategory, setSelectedCategory] = useState<any>();
|
const [selectedCategory, setSelectedCategory] = useState<any>();
|
||||||
|
|
@ -102,6 +107,10 @@ export default function FormTeks() {
|
||||||
const [editingArticleId, setEditingArticleId] = useState<string | null>(null);
|
const [editingArticleId, setEditingArticleId] = useState<string | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const [isLoadingData, setIsLoadingData] = useState<boolean>(false);
|
const [isLoadingData, setIsLoadingData] = useState<boolean>(false);
|
||||||
|
const [selectedWritingStyle, setSelectedWritingStyle] =
|
||||||
|
useState("professional");
|
||||||
|
const [editorContent, setEditorContent] = useState(""); // Untuk original editor
|
||||||
|
const [rewriteEditorContent, setRewriteEditorContent] = useState("");
|
||||||
|
|
||||||
const [articleIds, setArticleIds] = useState<string[]>([]);
|
const [articleIds, setArticleIds] = useState<string[]>([]);
|
||||||
const [isGeneratedArticle, setIsGeneratedArticle] = useState(false);
|
const [isGeneratedArticle, setIsGeneratedArticle] = useState(false);
|
||||||
|
|
@ -109,8 +118,9 @@ export default function FormTeks() {
|
||||||
const [selectedArticleId, setSelectedArticleId] = useState<string | null>(
|
const [selectedArticleId, setSelectedArticleId] = useState<string | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
const [isContentRewriteClicked, setIsContentRewriteClicked] = useState(false);
|
||||||
|
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
||||||
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
||||||
const [selectedWritingStyle, setSelectedWritingStyle] = useState("");
|
|
||||||
const [selectedSize, setSelectedSize] = useState("");
|
const [selectedSize, setSelectedSize] = useState("");
|
||||||
const [detailData, setDetailData] = useState<any>(null);
|
const [detailData, setDetailData] = useState<any>(null);
|
||||||
const [articleImages, setArticleImages] = useState<string[]>([]);
|
const [articleImages, setArticleImages] = useState<string[]>([]);
|
||||||
|
|
@ -157,14 +167,9 @@ export default function FormTeks() {
|
||||||
|
|
||||||
const teksSchema = z.object({
|
const teksSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
description: z
|
description: z.string().optional(),
|
||||||
.string()
|
descriptionOri: z.string().optional(), // Original editor
|
||||||
.min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." })
|
rewriteDescription: z.string().optional(),
|
||||||
.or(
|
|
||||||
z.literal(articleBody || "").refine((val) => val.length > 0, {
|
|
||||||
message: "Deskripsi diperlukan.",
|
|
||||||
})
|
|
||||||
),
|
|
||||||
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
||||||
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
});
|
});
|
||||||
|
|
@ -177,6 +182,11 @@ export default function FormTeks() {
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<TeksSchema>({
|
} = useForm<TeksSchema>({
|
||||||
resolver: zodResolver(teksSchema),
|
resolver: zodResolver(teksSchema),
|
||||||
|
defaultValues: {
|
||||||
|
description: "",
|
||||||
|
descriptionOri: "",
|
||||||
|
rewriteDescription: "",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const doGenerateMainKeyword = async () => {
|
const doGenerateMainKeyword = async () => {
|
||||||
|
|
@ -439,12 +449,26 @@ export default function FormTeks() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (articleBody) {
|
||||||
|
// Set ke dua field jika rewrite juga aktif
|
||||||
|
setValue("description", articleBody);
|
||||||
|
setValue("rewriteDescription", articleBody);
|
||||||
|
}
|
||||||
|
}, [articleBody, setValue]);
|
||||||
|
|
||||||
const save = async (data: TeksSchema) => {
|
const save = async (data: TeksSchema) => {
|
||||||
loading();
|
loading();
|
||||||
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;
|
|
||||||
if (!finalDescription.trim()) {
|
const finalDescription = isSwitchOn
|
||||||
|
? data.description
|
||||||
|
: selectedFileType === "rewrite"
|
||||||
|
? data.rewriteDescription
|
||||||
|
: data.descriptionOri;
|
||||||
|
|
||||||
|
if (!finalDescription?.trim()) {
|
||||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -709,6 +733,45 @@ export default function FormTeks() {
|
||||||
}
|
}
|
||||||
}, [title, getValues, setValue]);
|
}, [title, getValues, setValue]);
|
||||||
|
|
||||||
|
const handleRewriteClick = async () => {
|
||||||
|
setIsContentRewriteClicked(true);
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
style: selectedWritingStyle,
|
||||||
|
lang: "id",
|
||||||
|
contextType: "text",
|
||||||
|
urlContext: null,
|
||||||
|
context: editorContent, // Ambil isi editor original
|
||||||
|
createdBy: roleId,
|
||||||
|
sentiment: "Humorous",
|
||||||
|
clientId: "7QTW8cMojyayt6qnhqTOeJaBI70W4EaQ",
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await generateDataRewrite(request);
|
||||||
|
close();
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
console.error(res.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newArticleId = res?.data?.data?.id;
|
||||||
|
setIsGeneratedArticle(true);
|
||||||
|
|
||||||
|
setArticleIds((prevIds: string[]) => {
|
||||||
|
if (prevIds.length < 3) {
|
||||||
|
return [...prevIds, newArticleId];
|
||||||
|
} else {
|
||||||
|
const updatedIds = [...prevIds];
|
||||||
|
updatedIds[2] = newArticleId;
|
||||||
|
return updatedIds;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Cookies.set("nulisAIArticleIdTemp", JSON.stringify(articleIds));
|
||||||
|
setShowRewriteEditor(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="flex flex-col lg:flex-row gap-10">
|
<div className="flex flex-col lg:flex-row gap-10">
|
||||||
|
|
@ -901,7 +964,7 @@ export default function FormTeks() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<Label>{t("special-instructions")} (Optional)</Label>
|
<Label>{t("special-instructions")}(Optional)</Label>
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -923,13 +986,14 @@ export default function FormTeks() {
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleGenerateArtikel}
|
onClick={handleGenerateArtikel}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
Generate Article
|
Generate Article
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isGeneratedArticle && (
|
{isGeneratedArticle && (
|
||||||
<div className="mt-3 pb-0 flex flex-row ">
|
<div className="mt-3 pb-0 flex flex-row">
|
||||||
{articleIds.map((id: string, index: number) => (
|
{articleIds.map((id: string, index: number) => (
|
||||||
<p
|
<p
|
||||||
key={index}
|
key={index}
|
||||||
|
|
@ -949,27 +1013,23 @@ export default function FormTeks() {
|
||||||
<div className="pt-3">
|
<div className="pt-3">
|
||||||
<div className="flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-between items-center">
|
||||||
{selectedArticleId && (
|
{selectedArticleId && (
|
||||||
<Link
|
|
||||||
href={`/contributor/content/teks/update-seo/${selectedArticleId}`}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
className="mb-2"
|
className="mb-2"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={"outline"}
|
variant={"outline"}
|
||||||
color="primary"
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
const url = `/${locale}/contributor/content/image/update-seo/${selectedArticleId}`;
|
||||||
|
window.open(url, "_blank", "noopener,noreferrer");
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t("update")}
|
{t("update")}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="py-3 space-y-2">
|
||||||
)}
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label>{t("description")}</Label>
|
<Label>{t("description")}</Label>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -977,11 +1037,16 @@ export default function FormTeks() {
|
||||||
render={({ field: { onChange, value } }) =>
|
render={({ field: { onChange, value } }) =>
|
||||||
isLoadingData ? (
|
isLoadingData ? (
|
||||||
<div className="flex justify-center items-center h-40">
|
<div className="flex justify-center items-center h-40">
|
||||||
<p className="text-gray-500">Loading Proses Data...</p>
|
<p className="text-gray-500">
|
||||||
|
Loading Proses Data...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<CustomEditor
|
<CustomEditor
|
||||||
onChange={onChange}
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setEditorContent(value);
|
||||||
|
}}
|
||||||
initialData={articleBody || value}
|
initialData={articleBody || value}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
@ -993,6 +1058,110 @@ export default function FormTeks() {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!isSwitchOn && (
|
||||||
|
<>
|
||||||
|
<RadioGroup
|
||||||
|
onValueChange={(value) => setSelectedFileType(value)}
|
||||||
|
value={selectedFileType}
|
||||||
|
className=" grid-cols-1"
|
||||||
|
>
|
||||||
|
<div className="">
|
||||||
|
<RadioGroupItem value="original" id="original-file" />
|
||||||
|
<Label htmlFor="original-file">
|
||||||
|
Select Original Description
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<div className="py-3 space-y-2">
|
||||||
|
<Label>{t("description")}</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="descriptionOri"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<CustomEditor
|
||||||
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setEditorContent(value);
|
||||||
|
}}
|
||||||
|
initialData={value}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-sm font-semibold">Content Rewrite</p>
|
||||||
|
<div className="my-2">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
onClick={handleRewriteClick}
|
||||||
|
className="bg-blue-500 text-white py-2 px-4 rounded"
|
||||||
|
>
|
||||||
|
Content Rewrite
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showRewriteEditor && (
|
||||||
|
<div>
|
||||||
|
{isGeneratedArticle && (
|
||||||
|
<div className="mt-3 pb-0 flex flex-row ">
|
||||||
|
{articleIds.map((id: string, index: number) => (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
key={index}
|
||||||
|
className={`mr-3 px-3 py-2 rounded-md ${
|
||||||
|
selectedArticleId === id
|
||||||
|
? "bg-green-500 text-white"
|
||||||
|
: "border-2 border-green-500 bg-white text-green-500 hover:bg-green-500 hover:text-white hover:border-green-500"
|
||||||
|
}`}
|
||||||
|
onClick={() => handleArticleIdClick(id)}
|
||||||
|
>
|
||||||
|
{"Narasi " + (index + 1)}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex items-center space-x-2 mt-3">
|
||||||
|
<RadioGroupItem value="rewrite" id="rewrite-file" />
|
||||||
|
<Label htmlFor="rewrite-file">
|
||||||
|
Select Description Rewrite
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<div className="py-3 space-y-2">
|
||||||
|
<Label>{t("file-rewrite")}</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="rewriteDescription"
|
||||||
|
render={({ field: { onChange, value } }) =>
|
||||||
|
isLoadingData ? (
|
||||||
|
<div className="flex justify-center items-center h-40">
|
||||||
|
<p className="text-gray-500">
|
||||||
|
Loading Proses Data...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<CustomEditor
|
||||||
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setRewriteEditorContent(value);
|
||||||
|
}}
|
||||||
|
initialData={articleBody || value}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</RadioGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="py-3 space-y-2">
|
<div className="py-3 space-y-2">
|
||||||
<Label>{t("select-file")}</Label>
|
<Label>{t("select-file")}</Label>
|
||||||
{/* <Input
|
{/* <Input
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import * as z from "zod";
|
||||||
import { Upload } from "tus-js-client";
|
import { Upload } from "tus-js-client";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
import withReactContent from "sweetalert2-react-content";
|
import withReactContent from "sweetalert2-react-content";
|
||||||
import { redirect, useRouter } from "next/navigation";
|
import { redirect, useParams, useRouter } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
|
|
@ -40,6 +40,7 @@ import { uploadThumbnailBlog } from "@/service/blog/blog";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import {
|
import {
|
||||||
generateDataArticle,
|
generateDataArticle,
|
||||||
|
generateDataRewrite,
|
||||||
getDetailArticle,
|
getDetailArticle,
|
||||||
getGenerateKeywords,
|
getGenerateKeywords,
|
||||||
getGenerateTitle,
|
getGenerateTitle,
|
||||||
|
|
@ -82,12 +83,15 @@ export default function FormVideo() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
type VideoSchema = z.infer<typeof videoSchema>;
|
type VideoSchema = z.infer<typeof videoSchema>;
|
||||||
|
const params = useParams();
|
||||||
|
const locale = params?.locale;
|
||||||
|
|
||||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||||
const taskId = Cookies.get("taskId");
|
const taskId = Cookies.get("taskId");
|
||||||
const scheduleId = Cookies.get("scheduleId");
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
const scheduleType = Cookies.get("scheduleType");
|
const scheduleType = Cookies.get("scheduleType");
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const [selectedFileType, setSelectedFileType] = useState("original");
|
||||||
|
|
||||||
const t = useTranslations("Form");
|
const t = useTranslations("Form");
|
||||||
const [categories, setCategories] = useState<Category[]>([]);
|
const [categories, setCategories] = useState<Category[]>([]);
|
||||||
|
|
@ -97,6 +101,11 @@ export default function FormVideo() {
|
||||||
const [preview, setPreview] = useState<string | null>(null);
|
const [preview, setPreview] = useState<string | null>(null);
|
||||||
const [selectedLanguage, setSelectedLanguage] = useState("");
|
const [selectedLanguage, setSelectedLanguage] = useState("");
|
||||||
|
|
||||||
|
const [selectedWritingStyle, setSelectedWritingStyle] =
|
||||||
|
useState("professional");
|
||||||
|
const [editorContent, setEditorContent] = useState(""); // Untuk original editor
|
||||||
|
const [rewriteEditorContent, setRewriteEditorContent] = useState("");
|
||||||
|
|
||||||
const [selectedSEO, setSelectedSEO] = useState<string>("");
|
const [selectedSEO, setSelectedSEO] = useState<string>("");
|
||||||
const [title, setTitle] = useState<string>("");
|
const [title, setTitle] = useState<string>("");
|
||||||
const [selectedAdvConfig, setSelectedAdvConfig] = useState<string>("");
|
const [selectedAdvConfig, setSelectedAdvConfig] = useState<string>("");
|
||||||
|
|
@ -111,13 +120,17 @@ export default function FormVideo() {
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
||||||
const [selectedWritingStyle, setSelectedWritingStyle] = useState("");
|
// const [selectedWritingStyle, setSelectedWritingStyle] = useState("");
|
||||||
const [selectedSize, setSelectedSize] = useState("");
|
const [selectedSize, setSelectedSize] = useState("");
|
||||||
const [detailData, setDetailData] = useState<any>(null);
|
const [detailData, setDetailData] = useState<any>(null);
|
||||||
const [articleImages, setArticleImages] = useState<string[]>([]);
|
const [articleImages, setArticleImages] = useState<string[]>([]);
|
||||||
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
|
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
||||||
|
|
||||||
|
const [isContentRewriteClicked, setIsContentRewriteClicked] = useState(false);
|
||||||
|
|
||||||
const [selectedTarget, setSelectedTarget] = useState("");
|
const [selectedTarget, setSelectedTarget] = useState("");
|
||||||
const [unitSelection, setUnitSelection] = useState({
|
const [unitSelection, setUnitSelection] = useState({
|
||||||
allUnit: false,
|
allUnit: false,
|
||||||
|
|
@ -155,14 +168,9 @@ export default function FormVideo() {
|
||||||
|
|
||||||
const videoSchema = z.object({
|
const videoSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
description: z
|
description: z.string().optional(),
|
||||||
.string()
|
descriptionOri: z.string().optional(), // Original editor
|
||||||
.min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." })
|
rewriteDescription: z.string().optional(),
|
||||||
.or(
|
|
||||||
z.literal(articleBody || "").refine((val) => val.length > 0, {
|
|
||||||
message: "Deskripsi diperlukan.",
|
|
||||||
})
|
|
||||||
),
|
|
||||||
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
creatorName: z.string().min(1, { message: "Creator diperlukan" }),
|
||||||
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
// tags: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
});
|
});
|
||||||
|
|
@ -175,6 +183,11 @@ export default function FormVideo() {
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<VideoSchema>({
|
} = useForm<VideoSchema>({
|
||||||
resolver: zodResolver(videoSchema),
|
resolver: zodResolver(videoSchema),
|
||||||
|
defaultValues: {
|
||||||
|
description: "",
|
||||||
|
descriptionOri: "",
|
||||||
|
rewriteDescription: "",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const doGenerateMainKeyword = async () => {
|
const doGenerateMainKeyword = async () => {
|
||||||
|
|
@ -437,15 +450,30 @@ export default function FormVideo() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (articleBody) {
|
||||||
|
// Set ke dua field jika rewrite juga aktif
|
||||||
|
setValue("description", articleBody);
|
||||||
|
setValue("rewriteDescription", articleBody);
|
||||||
|
}
|
||||||
|
}, [articleBody, setValue]);
|
||||||
|
|
||||||
const save = async (data: VideoSchema) => {
|
const save = async (data: VideoSchema) => {
|
||||||
loading();
|
loading();
|
||||||
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()) {
|
const finalDescription = isSwitchOn
|
||||||
|
? data.description
|
||||||
|
: selectedFileType === "rewrite"
|
||||||
|
? data.rewriteDescription
|
||||||
|
: data.descriptionOri;
|
||||||
|
|
||||||
|
if (!finalDescription?.trim()) {
|
||||||
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
MySwal.fire("Error", "Deskripsi tidak boleh kosong.", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let requestData: {
|
let requestData: {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
|
@ -726,6 +754,45 @@ export default function FormVideo() {
|
||||||
}
|
}
|
||||||
}, [title, getValues, setValue]);
|
}, [title, getValues, setValue]);
|
||||||
|
|
||||||
|
const handleRewriteClick = async () => {
|
||||||
|
setIsContentRewriteClicked(true);
|
||||||
|
|
||||||
|
const request = {
|
||||||
|
style: selectedWritingStyle,
|
||||||
|
lang: "id",
|
||||||
|
contextType: "text",
|
||||||
|
urlContext: null,
|
||||||
|
context: editorContent, // Ambil isi editor original
|
||||||
|
createdBy: roleId,
|
||||||
|
sentiment: "Humorous",
|
||||||
|
clientId: "7QTW8cMojyayt6qnhqTOeJaBI70W4EaQ",
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await generateDataRewrite(request);
|
||||||
|
close();
|
||||||
|
|
||||||
|
if (res?.error) {
|
||||||
|
console.error(res.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newArticleId = res?.data?.data?.id;
|
||||||
|
setIsGeneratedArticle(true);
|
||||||
|
|
||||||
|
setArticleIds((prevIds: string[]) => {
|
||||||
|
if (prevIds.length < 3) {
|
||||||
|
return [...prevIds, newArticleId];
|
||||||
|
} else {
|
||||||
|
const updatedIds = [...prevIds];
|
||||||
|
updatedIds[2] = newArticleId;
|
||||||
|
return updatedIds;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Cookies.set("nulisAIArticleIdTemp", JSON.stringify(articleIds));
|
||||||
|
setShowRewriteEditor(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="flex flex-col lg:flex-row gap-10">
|
<div className="flex flex-col lg:flex-row gap-10">
|
||||||
|
|
@ -917,7 +984,7 @@ export default function FormVideo() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<Label>{t("special-instructions")} (Optional)</Label>
|
<Label>{t("special-instructions")}(Optional)</Label>
|
||||||
<div className="mt-3">
|
<div className="mt-3">
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -939,13 +1006,14 @@ export default function FormVideo() {
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={handleGenerateArtikel}
|
onClick={handleGenerateArtikel}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
Generate Article
|
Generate Article
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isGeneratedArticle && (
|
{isGeneratedArticle && (
|
||||||
<div className="mt-3 pb-0 flex flex-row ">
|
<div className="mt-3 pb-0 flex flex-row">
|
||||||
{articleIds.map((id: string, index: number) => (
|
{articleIds.map((id: string, index: number) => (
|
||||||
<p
|
<p
|
||||||
key={index}
|
key={index}
|
||||||
|
|
@ -965,27 +1033,23 @@ export default function FormVideo() {
|
||||||
<div className="pt-3">
|
<div className="pt-3">
|
||||||
<div className="flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-between items-center">
|
||||||
{selectedArticleId && (
|
{selectedArticleId && (
|
||||||
<Link
|
|
||||||
href={`/contributor/content/video/update-seo/${selectedArticleId}`}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
className="mb-2"
|
className="mb-2"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={"outline"}
|
variant={"outline"}
|
||||||
color="primary"
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
const url = `/${locale}/contributor/content/image/update-seo/${selectedArticleId}`;
|
||||||
|
window.open(url, "_blank", "noopener,noreferrer");
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t("update")}
|
{t("update")}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="py-3 space-y-2">
|
||||||
)}
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label>{t("description")}</Label>
|
<Label>{t("description")}</Label>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
|
|
@ -993,11 +1057,16 @@ export default function FormVideo() {
|
||||||
render={({ field: { onChange, value } }) =>
|
render={({ field: { onChange, value } }) =>
|
||||||
isLoadingData ? (
|
isLoadingData ? (
|
||||||
<div className="flex justify-center items-center h-40">
|
<div className="flex justify-center items-center h-40">
|
||||||
<p className="text-gray-500">Loading Proses Data...</p>
|
<p className="text-gray-500">
|
||||||
|
Loading Proses Data...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<CustomEditor
|
<CustomEditor
|
||||||
onChange={onChange}
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setEditorContent(value);
|
||||||
|
}}
|
||||||
initialData={articleBody || value}
|
initialData={articleBody || value}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
@ -1009,6 +1078,110 @@ export default function FormVideo() {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!isSwitchOn && (
|
||||||
|
<>
|
||||||
|
<RadioGroup
|
||||||
|
onValueChange={(value) => setSelectedFileType(value)}
|
||||||
|
value={selectedFileType}
|
||||||
|
className=" grid-cols-1"
|
||||||
|
>
|
||||||
|
<div className="">
|
||||||
|
<RadioGroupItem value="original" id="original-file" />
|
||||||
|
<Label htmlFor="original-file">
|
||||||
|
Select Original Description
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<div className="py-3 space-y-2">
|
||||||
|
<Label>{t("description")}</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="descriptionOri"
|
||||||
|
render={({ field: { onChange, value } }) => (
|
||||||
|
<CustomEditor
|
||||||
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setEditorContent(value);
|
||||||
|
}}
|
||||||
|
initialData={value}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{errors.description?.message && (
|
||||||
|
<p className="text-red-400 text-sm">
|
||||||
|
{errors.description.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-sm font-semibold">Content Rewrite</p>
|
||||||
|
<div className="my-2">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
onClick={handleRewriteClick}
|
||||||
|
className="bg-blue-500 text-white py-2 px-4 rounded"
|
||||||
|
>
|
||||||
|
Content Rewrite
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showRewriteEditor && (
|
||||||
|
<div>
|
||||||
|
{isGeneratedArticle && (
|
||||||
|
<div className="mt-3 pb-0 flex flex-row ">
|
||||||
|
{articleIds.map((id: string, index: number) => (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
key={index}
|
||||||
|
className={`mr-3 px-3 py-2 rounded-md ${
|
||||||
|
selectedArticleId === id
|
||||||
|
? "bg-green-500 text-white"
|
||||||
|
: "border-2 border-green-500 bg-white text-green-500 hover:bg-green-500 hover:text-white hover:border-green-500"
|
||||||
|
}`}
|
||||||
|
onClick={() => handleArticleIdClick(id)}
|
||||||
|
>
|
||||||
|
{"Narasi " + (index + 1)}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex items-center space-x-2 mt-3">
|
||||||
|
<RadioGroupItem value="rewrite" id="rewrite-file" />
|
||||||
|
<Label htmlFor="rewrite-file">
|
||||||
|
Select Description Rewrite
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<div className="py-3 space-y-2">
|
||||||
|
<Label>{t("file-rewrite")}</Label>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="rewriteDescription"
|
||||||
|
render={({ field: { onChange, value } }) =>
|
||||||
|
isLoadingData ? (
|
||||||
|
<div className="flex justify-center items-center h-40">
|
||||||
|
<p className="text-gray-500">
|
||||||
|
Loading Proses Data...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<CustomEditor
|
||||||
|
onChange={(value: any) => {
|
||||||
|
onChange(value);
|
||||||
|
setRewriteEditorContent(value);
|
||||||
|
}}
|
||||||
|
initialData={articleBody || value}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</RadioGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="py-3 space-y-2">
|
<div className="py-3 space-y-2">
|
||||||
<Label>{t("select-file")}</Label>
|
<Label>{t("select-file")}</Label>
|
||||||
{/* <Input
|
{/* <Input
|
||||||
|
|
|
||||||
80
lib/menus.ts
80
lib/menus.ts
|
|
@ -3627,20 +3627,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
groupLabel: "",
|
// groupLabel: "",
|
||||||
id: "contest",
|
// id: "contest",
|
||||||
menus: [
|
// menus: [
|
||||||
{
|
// {
|
||||||
id: "contest",
|
// id: "contest",
|
||||||
href: "/shared/contest",
|
// href: "/shared/contest",
|
||||||
label: t("contest"),
|
// label: t("contest"),
|
||||||
active: pathname.includes("/contest"),
|
// active: pathname.includes("/contest"),
|
||||||
icon: "ic:outline-emoji-events",
|
// icon: "ic:outline-emoji-events",
|
||||||
submenus: [],
|
// submenus: [],
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
groupLabel: "",
|
groupLabel: "",
|
||||||
id: "communication",
|
id: "communication",
|
||||||
|
|
@ -3896,16 +3896,16 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
icon: "material-symbols:map-search-outline",
|
icon: "material-symbols:map-search-outline",
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
href: "/admin/media-tracking/media-online",
|
href: "/admin/media-tracking/tracking-berita",
|
||||||
label: "Media Online",
|
label: "Tracking Beritra",
|
||||||
active: pathname === "/media-tracking/media-online",
|
active: pathname === "/admin/media-tracking/tracking-berita",
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/admin/media-tracking/tb-news",
|
href: "/admin/media-tracking/results",
|
||||||
label: "Tracking Berita Hari Ini",
|
label: "Hasil",
|
||||||
active: pathname === "/media-tracking/news",
|
active: pathname === "/admin/media-tracking/results",
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
|
|
@ -4079,20 +4079,20 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// groupLabel: "",
|
groupLabel: "",
|
||||||
// id: "performance-satker",
|
id: "performance-satker",
|
||||||
// menus: [
|
menus: [
|
||||||
// {
|
{
|
||||||
// id: "performance-polres",
|
id: "performance-polres",
|
||||||
// href: "/admin/performance-satker",
|
href: "/admin/performance-satker",
|
||||||
// label: t("performance-satker"),
|
label: t("performance-satker"),
|
||||||
// active: pathname.includes("/admin/performance-satker"),
|
active: pathname.includes("/admin/performance-satker"),
|
||||||
// icon: "ant-design:signal-filled",
|
icon: "ant-design:signal-filled",
|
||||||
// submenus: [],
|
submenus: [],
|
||||||
// },
|
},
|
||||||
// ],
|
],
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
groupLabel: "",
|
groupLabel: "",
|
||||||
id: "media-tracking",
|
id: "media-tracking",
|
||||||
|
|
@ -4105,16 +4105,16 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
||||||
icon: "material-symbols:map-search-outline",
|
icon: "material-symbols:map-search-outline",
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
href: "/admin/media-tracking/media-online",
|
href: "/admin/media-tracking/tracking-berita",
|
||||||
label: "Media Online",
|
label: "Tracking Beritra",
|
||||||
active: pathname === "/media-tracking/media-online",
|
active: pathname === "/admin/media-tracking/tracking-berita",
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/admin/media-tracking/tb-news",
|
href: "/admin/media-tracking/results",
|
||||||
label: "Tracking Berita Hari Ini",
|
label: "Hasil",
|
||||||
active: pathname === "/media-tracking/news",
|
active: pathname === "/admin/media-tracking/results",
|
||||||
icon: "heroicons:arrow-trending-up",
|
icon: "heroicons:arrow-trending-up",
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue