feat:update content-rewrite

This commit is contained in:
Anang Yusman 2025-06-03 13:46:06 +08:00
parent 649aa4c638
commit 882c77b96f
4 changed files with 148 additions and 52 deletions

View File

@ -8,12 +8,24 @@ import { useParams, useSearchParams } from "next/navigation";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Swal from "sweetalert2"; import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content"; import withReactContent from "sweetalert2-react-content";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select"; import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import * as z from "zod"; import * as z from "zod";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import CustomEditor from "@/components/editor/custom-editor"; import CustomEditor from "@/components/editor/custom-editor";
import { generateDataArticle, getDetailArticle } from "@/service/content/ai"; import {
generateDataArticle,
generateDataRewrite,
getDetailArticle,
} from "@/service/content/ai";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { close, error, loading } from "@/config/swal"; import { close, error, loading } from "@/config/swal";
import { saveContentRewrite } from "@/service/content/content"; import { saveContentRewrite } from "@/service/content/content";
@ -29,8 +41,13 @@ import { useTranslations } from "next-intl";
const imageSchema = z.object({ const imageSchema = z.object({
title: z.string().min(1, { message: "Judul diperlukan" }), title: z.string().min(1, { message: "Judul diperlukan" }),
mainKeyword: z.string().min(1, { message: "Keyword diperlukan" }), mainKeyword: z.string().min(1, { message: "Keyword diperlukan" }),
seo: z.string().min(1, { message: "Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter" }), seo: z.string().min(1, {
description: z.string().min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }), message:
"Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter",
}),
description: z
.string()
.min(2, { message: "Narasi Penugasan harus lebih dari 2 karakter." }),
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" }),
}); });
@ -73,8 +90,12 @@ const page = (props: any) => {
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
title: Yup.string().required("Judul tidak boleh kosong"), title: Yup.string().required("Judul tidak boleh kosong"),
mainKeyword: Yup.string().required("Keyword tidak boleh kosong"), mainKeyword: Yup.string().required("Keyword tidak boleh kosong"),
seo: Yup.string().required("Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter"), seo: Yup.string().required(
description: Yup.string().required("Narasi Penugasan harus lebih dari 2 karakter."), "Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter"
),
description: Yup.string().required(
"Narasi Penugasan harus lebih dari 2 karakter."
),
}); });
let componentMounted = true; let componentMounted = true;
@ -152,7 +173,10 @@ const page = (props: any) => {
useEffect(() => { useEffect(() => {
async function initState() { async function initState() {
setLoadingState(true); setLoadingState(true);
const response = await getDetail(id, states == "polda" ? "polda" : "mabes"); const response = await getDetail(
id,
states == "polda" ? "polda" : "mabes"
);
console.log("Detail dataaaa ::", response); console.log("Detail dataaaa ::", response);
if (response?.data?.data?.isActive == false) { if (response?.data?.data?.isActive == false) {
window.location.replace("/"); window.location.replace("/");
@ -174,7 +198,10 @@ const page = (props: any) => {
setMain({ setMain({
id: response?.data?.data?.files[0]?.id, id: response?.data?.data?.files[0]?.id,
type: response?.data?.data?.fileType.name, type: response?.data?.data?.fileType.name,
url: Number(response?.data?.data?.fileType?.id) == 4 ? response?.data?.data?.files[0]?.secondaryUrl : response?.data?.data?.files[0]?.url, url:
Number(response?.data?.data?.fileType?.id) == 4
? response?.data?.data?.files[0]?.secondaryUrl
: response?.data?.data?.files[0]?.url,
thumbnailFileUrl: response?.data?.data?.files[0]?.thumbnailFileUrl, thumbnailFileUrl: response?.data?.data?.files[0]?.thumbnailFileUrl,
names: response?.data?.data?.files[0]?.fileName, names: response?.data?.data?.files[0]?.fileName,
format: response?.data?.data?.files[0]?.format, format: response?.data?.data?.files[0]?.format,
@ -208,25 +235,17 @@ const page = (props: any) => {
const handleGenerateArtikel = async () => { const handleGenerateArtikel = async () => {
loading(); loading();
const request = { const request = {
advConfig: "", style: "friendly",
style: selectedWritingStyle, lang: "id",
website: "None", contextType: "text",
connectToWeb: true, urlContext: null,
lang: selectedLanguage, context: content?.description,
pointOfView: "None",
title: getValues("title"),
imageSource: "Web",
mainKeyword: getValues("mainKeyword"),
additionalKeywords: getValues("seo"),
targetCountry: null,
articleSize: selectedSize,
projectId: 2,
createdBy: roleId, createdBy: roleId,
// clientId: "ngDLPPiorplznw2jTqVe3YFCz5xqKfUJ", sentiment: "Humorous",
clientId: "mediahubClientId", clientId: "7QTW8cMojyayt6qnhqTOeJaBI70W4EaQ",
}; };
console.log("Request", request); console.log("Request", request);
const res = await generateDataArticle(request); const res = await generateDataRewrite(request);
close(); close();
if (res.error) { if (res.error) {
@ -272,7 +291,10 @@ const page = (props: any) => {
throw new Error("Timeout: Artikel belum selesai diproses."); throw new Error("Timeout: Artikel belum selesai diproses.");
}; };
const articleData = await waitForStatusUpdate(); const articleData = await waitForStatusUpdate();
const cleanArticleBody = articleData?.articleBody?.replace(/<img[^>]*>/g, ""); const cleanArticleBody = articleData?.articleBody?.replace(
/<img[^>]*>/g,
""
);
console.log("lalalala", cleanArticleBody); console.log("lalalala", cleanArticleBody);
const articleImagesData = articleData?.imagesUrl?.split(","); const articleImagesData = articleData?.imagesUrl?.split(",");
setValue("description", cleanArticleBody || ""); setValue("description", cleanArticleBody || "");
@ -302,7 +324,10 @@ const page = (props: any) => {
<div className="flex flex-col lg:flex-row gap-2"> <div className="flex flex-col lg:flex-row gap-2">
<div className="gap-1 flex flex-col mb-3"> <div className="gap-1 flex flex-col mb-3">
<p className="font-semibold">{t("language")}</p> <p className="font-semibold">{t("language")}</p>
<Select value={selectedLanguage} onValueChange={setSelectedLanguage}> <Select
value={selectedLanguage}
onValueChange={setSelectedLanguage}
>
<SelectTrigger className="w-full lg:w-[180px]"> <SelectTrigger className="w-full lg:w-[180px]">
<SelectValue placeholder={t("selectLanguage")} /> <SelectValue placeholder={t("selectLanguage")} />
</SelectTrigger> </SelectTrigger>
@ -317,7 +342,10 @@ const page = (props: any) => {
</div> </div>
<div className="gap-1 flex flex-col mb-3"> <div className="gap-1 flex flex-col mb-3">
<p className="font-semibold">{t("contextType")}</p> <p className="font-semibold">{t("contextType")}</p>
<Select value={selectedContextType} onValueChange={setSelectedContextType}> <Select
value={selectedContextType}
onValueChange={setSelectedContextType}
>
<SelectTrigger className="w-full lg:w-[180px]"> <SelectTrigger className="w-full lg:w-[180px]">
<SelectValue placeholder={t("selectContext")} /> <SelectValue placeholder={t("selectContext")} />
</SelectTrigger> </SelectTrigger>
@ -325,8 +353,12 @@ const page = (props: any) => {
<SelectGroup> <SelectGroup>
<SelectLabel>{t("selectContext")}</SelectLabel> <SelectLabel>{t("selectContext")}</SelectLabel>
<SelectItem value="text">{t("text")}</SelectItem> <SelectItem value="text">{t("text")}</SelectItem>
<SelectItem value="article">{t("article")}</SelectItem> <SelectItem value="article">
<SelectItem value="transcript">{t("transcript")}</SelectItem> {t("article")}
</SelectItem>
<SelectItem value="transcript">
{t("transcript")}
</SelectItem>
<SelectItem value="url">URL</SelectItem> <SelectItem value="url">URL</SelectItem>
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>
@ -334,7 +366,10 @@ const page = (props: any) => {
</div> </div>
<div className="gap-1 flex flex-col mb-3"> <div className="gap-1 flex flex-col mb-3">
<p className="font-semibold">{t("writingStyle")}</p> <p className="font-semibold">{t("writingStyle")}</p>
<Select value={selectedWritingStyle} onValueChange={setSelectedWritingStyle}> <Select
value={selectedWritingStyle}
onValueChange={setSelectedWritingStyle}
>
<SelectTrigger className="w-full lg:w-[180px]"> <SelectTrigger className="w-full lg:w-[180px]">
<SelectValue placeholder={t("selectWriting")} /> <SelectValue placeholder={t("selectWriting")} />
</SelectTrigger> </SelectTrigger>
@ -342,8 +377,12 @@ const page = (props: any) => {
<SelectGroup> <SelectGroup>
<SelectLabel>{t("selectWriting")}</SelectLabel> <SelectLabel>{t("selectWriting")}</SelectLabel>
<SelectItem value="firendly">Friendly</SelectItem> <SelectItem value="firendly">Friendly</SelectItem>
<SelectItem value="profesional">Profesional</SelectItem> <SelectItem value="profesional">
<SelectItem value="informational">Informational</SelectItem> Profesional
</SelectItem>
<SelectItem value="informational">
Informational
</SelectItem>
<SelectItem value="neutral">Neutral</SelectItem> <SelectItem value="neutral">Neutral</SelectItem>
<SelectItem value="witty">Witty</SelectItem> <SelectItem value="witty">Witty</SelectItem>
</SelectGroup> </SelectGroup>
@ -352,16 +391,25 @@ const page = (props: any) => {
</div> </div>
<div className="gap-1 flex flex-col mb-3"> <div className="gap-1 flex flex-col mb-3">
<p className="font-semibold">{t("articleSize")}</p> <p className="font-semibold">{t("articleSize")}</p>
<Select value={selectedSize} onValueChange={setSelectedSize}> <Select
value={selectedSize}
onValueChange={setSelectedSize}
>
<SelectTrigger className="w-full lg:w-[180px]"> <SelectTrigger className="w-full lg:w-[180px]">
<SelectValue placeholder={t("selectSize")} /> <SelectValue placeholder={t("selectSize")} />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
<SelectLabel>{t("selectSize")}</SelectLabel> <SelectLabel>{t("selectSize")}</SelectLabel>
<SelectItem value="news">News (300 - 900 words)</SelectItem> <SelectItem value="news">
<SelectItem value="info">Info (900 - 2000 words)</SelectItem> News (300 - 900 words)
<SelectItem value="detail">Detail (2000 - 5000 words)</SelectItem> </SelectItem>
<SelectItem value="info">
Info (900 - 2000 words)
</SelectItem>
<SelectItem value="detail">
Detail (2000 - 5000 words)
</SelectItem>
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>
</Select> </Select>
@ -372,7 +420,18 @@ const page = (props: any) => {
<Controller <Controller
control={control} control={control}
name="title" name="title"
render={({ field: { onChange, value } }) => <Input type="text" className={`w-full border py-3 rounded-lg ${errors.title ? "is-invalid" : ""}`} {...register("title")} id="title" value={value} onChange={onChange} />} render={({ field: { onChange, value } }) => (
<Input
type="text"
className={`w-full border py-3 rounded-lg ${
errors.title ? "is-invalid" : ""
}`}
{...register("title")}
id="title"
value={value}
onChange={onChange}
/>
)}
/> />
</div> </div>
<div className="mb-3"> <div className="mb-3">
@ -381,7 +440,16 @@ const page = (props: any) => {
control={control} control={control}
name="mainKeyword" name="mainKeyword"
render={({ field: { onChange, value } }) => ( render={({ field: { onChange, value } }) => (
<Input type="text" className={`w-full border py-3 rounded-lg ${errors.mainKeyword ? "is-invalid" : ""}`} {...register("mainKeyword")} id="mainKeyword" value={value} onChange={onChange} /> <Input
type="text"
className={`w-full border py-3 rounded-lg ${
errors.mainKeyword ? "is-invalid" : ""
}`}
{...register("mainKeyword")}
id="mainKeyword"
value={value}
onChange={onChange}
/>
)} )}
/> />
</div> </div>
@ -391,12 +459,22 @@ const page = (props: any) => {
control={control} control={control}
name="seo" name="seo"
render={({ field: { onChange, value } }) => ( render={({ field: { onChange, value } }) => (
<Textarea className="py-20" id="seo" placeholder="Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter" {...register("seo")} onChange={onChange} value={value} /> <Textarea
className="py-20"
id="seo"
placeholder="Tuliskan kata kunci atau frasa yang relevan dengan blog Anda, lalu tekan enter"
{...register("seo")}
onChange={onChange}
value={value}
/>
)} )}
/> />
</div> </div>
<div className="mb-4"> <div className="mb-4">
<a onClick={handleGenerateArtikel} className="text-blue-500 cursor-pointer hover:bg-blue-700 hover:text-white border border-blue-500 rounded-md p-2 text-sm lg:text-base"> <a
onClick={handleGenerateArtikel}
className="text-blue-500 cursor-pointer hover:bg-blue-700 hover:text-white border border-blue-500 rounded-md p-2 text-sm lg:text-base"
>
Generate Artikel Generate Artikel
</a> </a>
{isGeneratedArticle && ( {isGeneratedArticle && (
@ -426,14 +504,25 @@ const page = (props: any) => {
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 onChange={onChange} initialData={articleBody || value} /> <CustomEditor
onChange={onChange}
initialData={articleBody || value}
/>
) )
} }
/> />
{articleBody === null || articleBody === "" ? <p className="text-red-400 px-0 text-sm">Deskripsi tidak boleh kosong*</p> : ""} {articleBody === null || articleBody === "" ? (
<p className="text-red-400 px-0 text-sm">
Deskripsi tidak boleh kosong*
</p>
) : (
""
)}
</div> </div>
<div className="flex flex-row gap-3"> <div className="flex flex-row gap-3">
<Button <Button
@ -445,7 +534,10 @@ const page = (props: any) => {
> >
{t("back")} {t("back")}
</Button> </Button>
<Button type="submit" className="border border-blue-500 bg-blue-500 text-sm lg:text-base text-white"> <Button
type="submit"
className="border border-blue-500 bg-blue-500 text-sm lg:text-base text-white"
>
{t("save")} {t("save")}
</Button> </Button>
</div> </div>

View File

@ -283,7 +283,7 @@ const page = () => {
</p> </p>
</div> </div>
<Link <Link
href={`/content-management/rewrite/create/${image?.id}`} href={`/content-management/rewrite/create/${image?.mediaUploadId}`}
className="flex flex-row hover:text-red-800 gap-2" className="flex flex-row hover:text-red-800 gap-2"
> >
<Icon icon="jam:write" fontSize={25} /> <Icon icon="jam:write" fontSize={25} />

View File

@ -1,6 +1,10 @@
import { httpDeleteInterceptor, httpGetInterceptor, httpPostInterceptor } from "../http-config/http-interceptor-service"; import {
httpDeleteInterceptor,
httpGetInterceptor,
httpPostInterceptor,
} from "../http-config/http-interceptor-service";
export async function getDetail(id: any, state: any) { export async function getDetail(slug: any, state: any) {
const url = `media/public?slug=${id}&state=${state}`; const url = `media/public?slug=${slug}&state=${state}`;
return httpGetInterceptor(url); return httpGetInterceptor(url);
} }

View File

@ -228,10 +228,10 @@ export async function saveWishlist(data: { mediaUploadId: string }) {
export async function getPublicSuggestionList(slug: any) { export async function getPublicSuggestionList(slug: any) {
const url = `media/public/suggestion?mediaId=${slug}`; const url = `media/public/suggestion?mediaId=${slug}`;
const headers = { // const headers = {
"content-Type": "application/json", // "content-Type": "application/json",
}; // };
return httpGet(url, headers); return httpGetInterceptor(url);
} }
export async function getUserNotifications(page = 0, typeId: any) { export async function getUserNotifications(page = 0, typeId: any) {