2024-11-15 10:53:04 +00:00
|
|
|
"use client";
|
|
|
|
|
import {
|
|
|
|
|
Button,
|
|
|
|
|
Input,
|
|
|
|
|
Select,
|
|
|
|
|
SelectItem,
|
|
|
|
|
SelectSection,
|
2025-02-13 08:25:39 +00:00
|
|
|
} from "@heroui/react";
|
2024-11-15 10:53:04 +00:00
|
|
|
import { FormEvent, useState } from "react";
|
|
|
|
|
import { Controller, useForm } from "react-hook-form";
|
|
|
|
|
import * as z from "zod";
|
|
|
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
|
|
|
import { close, error, loading } from "@/config/swal";
|
|
|
|
|
import {
|
|
|
|
|
generateDataArticle,
|
|
|
|
|
getGenerateKeywords,
|
|
|
|
|
getGenerateTitle,
|
|
|
|
|
} from "@/service/generate-article";
|
|
|
|
|
|
|
|
|
|
const writingStyle = [
|
|
|
|
|
{
|
|
|
|
|
id: 1,
|
|
|
|
|
name: "Friendly",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 1,
|
|
|
|
|
name: "Professional",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 3,
|
|
|
|
|
name: "Informational",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 4,
|
|
|
|
|
name: "Neutral",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 5,
|
|
|
|
|
name: "Witty",
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const articleSize = [
|
|
|
|
|
{
|
|
|
|
|
id: 1,
|
|
|
|
|
name: "News (300 - 900 words)",
|
|
|
|
|
value: "News",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 2,
|
|
|
|
|
name: "Info (900 - 2000 words)",
|
|
|
|
|
value: "Info",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 3,
|
|
|
|
|
name: "Detail (2000 - 5000 words)",
|
|
|
|
|
value: "Detail",
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const singleArticleSchema = z.object({
|
|
|
|
|
mainKeyword: z.string().min(2, {
|
|
|
|
|
message: "Main Keyword must be at least 2 characters.",
|
|
|
|
|
}),
|
|
|
|
|
title: z.string().min(2, {
|
2024-11-22 10:59:58 +00:00
|
|
|
message: "Title Keyword must be at least 2 characters.",
|
2024-11-15 10:53:04 +00:00
|
|
|
}),
|
|
|
|
|
additionalKeyword: z.string().min(2, {
|
2024-11-22 10:59:58 +00:00
|
|
|
message: "Additional Keyword must be at least 2 characters.",
|
2024-11-15 10:53:04 +00:00
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export default function GenerateSingleArticle(props: {
|
|
|
|
|
articleId: (data: number) => void;
|
|
|
|
|
}) {
|
|
|
|
|
const [selectedWritingSyle, setSelectedWritingStyle] =
|
|
|
|
|
useState("Informational");
|
|
|
|
|
const [selectedArticleSize, setSelectedArticleSize] = useState("News");
|
|
|
|
|
const [selectedLanguage, setSelectedLanguage] = useState("id");
|
|
|
|
|
|
|
|
|
|
const formOptions = { resolver: zodResolver(singleArticleSchema) };
|
|
|
|
|
type UserSettingSchema = z.infer<typeof singleArticleSchema>;
|
|
|
|
|
const {
|
|
|
|
|
register,
|
|
|
|
|
control,
|
|
|
|
|
handleSubmit,
|
|
|
|
|
formState: { errors },
|
|
|
|
|
setValue,
|
|
|
|
|
getValues,
|
|
|
|
|
} = useForm<UserSettingSchema>(formOptions);
|
|
|
|
|
|
|
|
|
|
const generateAll = async (keyword: string | undefined) => {
|
|
|
|
|
if (keyword) {
|
|
|
|
|
generateTitle(keyword);
|
|
|
|
|
generateKeywords(keyword);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const generateTitle = async (keyword: string | undefined) => {
|
|
|
|
|
if (keyword) {
|
|
|
|
|
loading();
|
|
|
|
|
const req = {
|
|
|
|
|
keyword: keyword,
|
|
|
|
|
style: selectedWritingSyle,
|
|
|
|
|
website: "None",
|
|
|
|
|
connectToWeb: true,
|
|
|
|
|
lang: selectedLanguage,
|
|
|
|
|
pointOfView: "None",
|
|
|
|
|
clientId: "",
|
|
|
|
|
};
|
|
|
|
|
const res = await getGenerateTitle(req);
|
|
|
|
|
const data = res?.data?.data;
|
|
|
|
|
setValue("title", data);
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const generateKeywords = async (keyword: string | undefined) => {
|
|
|
|
|
if (keyword) {
|
|
|
|
|
const req = {
|
|
|
|
|
keyword: keyword,
|
|
|
|
|
style: selectedWritingSyle,
|
|
|
|
|
website: "None",
|
|
|
|
|
connectToWeb: true,
|
|
|
|
|
lang: selectedLanguage,
|
|
|
|
|
pointOfView: "0",
|
|
|
|
|
clientId: "",
|
|
|
|
|
};
|
|
|
|
|
loading();
|
|
|
|
|
const res = await getGenerateKeywords(req);
|
|
|
|
|
const data = res?.data?.data;
|
|
|
|
|
setValue("additionalKeyword", data);
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onSubmit = async (values: z.infer<typeof singleArticleSchema>) => {
|
|
|
|
|
loading();
|
|
|
|
|
const request = {
|
|
|
|
|
advConfig: "",
|
|
|
|
|
style: selectedWritingSyle,
|
|
|
|
|
website: "None",
|
|
|
|
|
connectToWeb: true,
|
|
|
|
|
lang: selectedLanguage,
|
|
|
|
|
pointOfView: "None",
|
|
|
|
|
title: values.title,
|
|
|
|
|
imageSource: "Web",
|
|
|
|
|
mainKeyword: values.mainKeyword,
|
|
|
|
|
additionalKeywords: values.additionalKeyword,
|
|
|
|
|
targetCountry: null,
|
|
|
|
|
articleSize: selectedArticleSize,
|
|
|
|
|
projectId: 2,
|
|
|
|
|
createdBy: "123123",
|
|
|
|
|
clientId: "humasClientIdtest",
|
|
|
|
|
};
|
|
|
|
|
console.log("reqq", request);
|
|
|
|
|
const res = await generateDataArticle(request);
|
|
|
|
|
close();
|
|
|
|
|
console.log("res", res?.data?.data);
|
|
|
|
|
if (res?.error) {
|
|
|
|
|
error("Error");
|
|
|
|
|
}
|
|
|
|
|
props.articleId(res?.data?.data?.id);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<fieldset>
|
|
|
|
|
<form
|
|
|
|
|
className="flex flex-col gap-2 w-full"
|
|
|
|
|
onSubmit={handleSubmit(onSubmit)}
|
|
|
|
|
>
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-5 w-full">
|
|
|
|
|
<Select
|
|
|
|
|
label="Writing Style"
|
|
|
|
|
variant="bordered"
|
|
|
|
|
labelPlacement="outside"
|
|
|
|
|
placeholder=""
|
|
|
|
|
selectedKeys={[selectedWritingSyle]}
|
|
|
|
|
onChange={(e) =>
|
|
|
|
|
e.target.value !== ""
|
|
|
|
|
? setSelectedWritingStyle(e.target.value)
|
|
|
|
|
: ""
|
|
|
|
|
}
|
|
|
|
|
className="w-full"
|
|
|
|
|
>
|
|
|
|
|
<SelectSection>
|
|
|
|
|
{writingStyle.map((style) => (
|
|
|
|
|
<SelectItem key={style.name}>{style.name}</SelectItem>
|
|
|
|
|
))}
|
|
|
|
|
</SelectSection>
|
|
|
|
|
</Select>
|
|
|
|
|
<Select
|
|
|
|
|
label="Article Size"
|
|
|
|
|
variant="bordered"
|
|
|
|
|
labelPlacement="outside"
|
|
|
|
|
placeholder=""
|
|
|
|
|
selectedKeys={[selectedArticleSize]}
|
|
|
|
|
onChange={(e) =>
|
|
|
|
|
e.target.value !== ""
|
|
|
|
|
? setSelectedArticleSize(e.target.value)
|
|
|
|
|
: ""
|
|
|
|
|
}
|
|
|
|
|
className="w-full"
|
|
|
|
|
>
|
|
|
|
|
<SelectSection>
|
|
|
|
|
{articleSize.map((size) => (
|
|
|
|
|
<SelectItem key={size.value}>{size.name}</SelectItem>
|
|
|
|
|
))}
|
|
|
|
|
</SelectSection>
|
|
|
|
|
</Select>
|
|
|
|
|
<Select
|
|
|
|
|
label="Language"
|
|
|
|
|
variant="bordered"
|
|
|
|
|
labelPlacement="outside"
|
|
|
|
|
placeholder=""
|
|
|
|
|
selectedKeys={[selectedLanguage]}
|
|
|
|
|
onChange={(e) =>
|
|
|
|
|
e.target.value !== "" ? setSelectedLanguage(e.target.value) : ""
|
|
|
|
|
}
|
|
|
|
|
className="w-full"
|
|
|
|
|
>
|
|
|
|
|
<SelectSection>
|
|
|
|
|
<SelectItem key="id">Indonesia</SelectItem>
|
|
|
|
|
<SelectItem key="en">English</SelectItem>
|
|
|
|
|
</SelectSection>
|
|
|
|
|
</Select>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex flex-col gap-3 mt-3">
|
|
|
|
|
<div className="flex flex-row gap-2 items-center">
|
|
|
|
|
<p className="text-sm">Main Keyword</p>
|
|
|
|
|
<Button
|
|
|
|
|
color="primary"
|
|
|
|
|
size="sm"
|
|
|
|
|
onPress={() => generateAll(getValues("mainKeyword"))}
|
|
|
|
|
>
|
|
|
|
|
Process
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
<Controller
|
|
|
|
|
control={control}
|
|
|
|
|
name="mainKeyword"
|
|
|
|
|
render={({ field: { onChange, value } }) => (
|
|
|
|
|
<Input
|
|
|
|
|
type="text"
|
|
|
|
|
id="mainKeyword"
|
|
|
|
|
placeholder=""
|
|
|
|
|
label=""
|
|
|
|
|
value={value}
|
|
|
|
|
onChange={onChange}
|
|
|
|
|
labelPlacement="outside"
|
|
|
|
|
className="w-full"
|
|
|
|
|
variant="bordered"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
{errors.mainKeyword && (
|
|
|
|
|
<p className="text-red-400 text-sm">
|
|
|
|
|
{errors.mainKeyword?.message}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
<div className="flex flex-row gap-2 items-center">
|
|
|
|
|
<p className="text-sm">Title</p>
|
|
|
|
|
<Button
|
|
|
|
|
color="primary"
|
|
|
|
|
size="sm"
|
2024-12-06 06:30:16 +00:00
|
|
|
onPress={() => generateTitle(getValues("mainKeyword"))}
|
2024-11-15 10:53:04 +00:00
|
|
|
>
|
|
|
|
|
Generate
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
<Controller
|
|
|
|
|
control={control}
|
|
|
|
|
name="title"
|
|
|
|
|
render={({ field: { onChange, value } }) => (
|
|
|
|
|
<Input
|
|
|
|
|
type="text"
|
|
|
|
|
id="title"
|
|
|
|
|
placeholder=""
|
|
|
|
|
label=""
|
|
|
|
|
value={value}
|
|
|
|
|
onChange={onChange}
|
|
|
|
|
labelPlacement="outside"
|
|
|
|
|
className="w-full"
|
|
|
|
|
variant="bordered"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
{errors.title && (
|
|
|
|
|
<p className="text-red-400 text-sm">{errors.title?.message}</p>
|
|
|
|
|
)}
|
|
|
|
|
<div className="flex flex-row gap-2 items-center">
|
|
|
|
|
<p className="text-sm">Additional Keyword</p>
|
|
|
|
|
<Button
|
|
|
|
|
color="primary"
|
|
|
|
|
size="sm"
|
2024-12-06 06:30:16 +00:00
|
|
|
onPress={() => generateKeywords(getValues("mainKeyword"))}
|
2024-11-15 10:53:04 +00:00
|
|
|
>
|
|
|
|
|
Generate
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
<Controller
|
|
|
|
|
control={control}
|
|
|
|
|
name="additionalKeyword"
|
|
|
|
|
render={({ field: { onChange, value } }) => (
|
|
|
|
|
<Input
|
|
|
|
|
type="text"
|
|
|
|
|
id="additionalKeyword"
|
|
|
|
|
placeholder=""
|
|
|
|
|
label=""
|
|
|
|
|
value={value}
|
|
|
|
|
onChange={onChange}
|
|
|
|
|
labelPlacement="outside"
|
|
|
|
|
className="w-full"
|
|
|
|
|
variant="bordered"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
{errors.additionalKeyword && (
|
|
|
|
|
<p className="text-red-400 text-sm">
|
|
|
|
|
{errors.additionalKeyword?.message}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
<Button
|
|
|
|
|
color="primary"
|
|
|
|
|
className="my-5 w-full py-5 text-xs md:text-base"
|
|
|
|
|
type="submit"
|
|
|
|
|
>
|
|
|
|
|
Generate
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</fieldset>
|
|
|
|
|
);
|
|
|
|
|
}
|