fix:handle empty file placement & target publish spit
This commit is contained in:
parent
933bbc402b
commit
504101b91c
|
|
@ -28,13 +28,13 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
import {
|
import {
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
FileText,
|
FileText,
|
||||||
Image,
|
Image,
|
||||||
Loader2,
|
Loader2,
|
||||||
Save,
|
Save,
|
||||||
Trash2,
|
Trash2,
|
||||||
Edit3,
|
Edit3,
|
||||||
Globe,
|
Globe,
|
||||||
Users,
|
Users,
|
||||||
|
|
@ -42,7 +42,7 @@ import {
|
||||||
Eye,
|
Eye,
|
||||||
Settings,
|
Settings,
|
||||||
CheckCircle,
|
CheckCircle,
|
||||||
XCircle
|
XCircle,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
// Swiper
|
// Swiper
|
||||||
|
|
@ -62,10 +62,7 @@ import {
|
||||||
getTagsBySubCategoryId,
|
getTagsBySubCategoryId,
|
||||||
listEnableCategory,
|
listEnableCategory,
|
||||||
} from "@/service/content/content";
|
} from "@/service/content/content";
|
||||||
import {
|
import { generateDataRewrite, getDetailArticle } from "@/service/content/ai";
|
||||||
generateDataRewrite,
|
|
||||||
getDetailArticle,
|
|
||||||
} from "@/service/content/ai";
|
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { getCookiesDecrypt } from "@/lib/utils";
|
import { getCookiesDecrypt } from "@/lib/utils";
|
||||||
|
|
@ -150,14 +147,14 @@ const PLACEMENT_OPTIONS = [
|
||||||
// Dynamic imports
|
// Dynamic imports
|
||||||
const CustomEditor = dynamic(
|
const CustomEditor = dynamic(
|
||||||
() => import("@/components/editor/custom-editor"),
|
() => import("@/components/editor/custom-editor"),
|
||||||
{
|
{
|
||||||
ssr: false,
|
ssr: false,
|
||||||
loading: () => (
|
loading: () => (
|
||||||
<div className="flex items-center justify-center h-32 border rounded-md bg-muted/50">
|
<div className="flex items-center justify-center h-32 border rounded-md bg-muted/50">
|
||||||
<Loader2 className="h-6 w-6 animate-spin" />
|
<Loader2 className="h-6 w-6 animate-spin" />
|
||||||
<span className="ml-2">Loading editor...</span>
|
<span className="ml-2">Loading editor...</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -190,24 +187,31 @@ export default function FormConvertSPIT() {
|
||||||
const [isDeleting, setIsDeleting] = useState(false);
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
const [detail, setDetail] = useState<Detail | null>(null);
|
const [detail, setDetail] = useState<Detail | null>(null);
|
||||||
const [categories, setCategories] = useState<Category[]>([]);
|
const [categories, setCategories] = useState<Category[]>([]);
|
||||||
const [selectedCategoryId, setSelectedCategoryId] = useState<number | null>(null);
|
const [selectedCategoryId, setSelectedCategoryId] = useState<number | null>(
|
||||||
const [selectedFileType, setSelectedFileType] = useState<"original" | "rewrite">("original");
|
null
|
||||||
const [selectedWritingStyle, setSelectedWritingStyle] = useState("professional");
|
);
|
||||||
|
const [selectedFileType, setSelectedFileType] = useState<
|
||||||
|
"original" | "rewrite"
|
||||||
|
>("original");
|
||||||
|
const [selectedWritingStyle, setSelectedWritingStyle] =
|
||||||
|
useState("professional");
|
||||||
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
||||||
const [isGeneratingRewrite, setIsGeneratingRewrite] = useState(false);
|
const [isGeneratingRewrite, setIsGeneratingRewrite] = useState(false);
|
||||||
const [isLoadingRewrite, setIsLoadingRewrite] = useState(false);
|
const [isLoadingRewrite, setIsLoadingRewrite] = useState(false);
|
||||||
|
|
||||||
// Media state
|
// Media state
|
||||||
const [detailThumb, setDetailThumb] = useState<string[]>([]);
|
const [detailThumb, setDetailThumb] = useState<string[]>([]);
|
||||||
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
|
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
|
||||||
const [files, setFiles] = useState<FileType[]>([]);
|
const [files, setFiles] = useState<FileType[]>([]);
|
||||||
const [filePlacements, setFilePlacements] = useState<string[][]>([]);
|
const [filePlacements, setFilePlacements] = useState<string[][]>([]);
|
||||||
|
|
||||||
// Content rewrite state
|
// Content rewrite state
|
||||||
const [articleIds, setArticleIds] = useState<string[]>([]);
|
const [articleIds, setArticleIds] = useState<string[]>([]);
|
||||||
const [selectedArticleId, setSelectedArticleId] = useState<string | null>(null);
|
const [selectedArticleId, setSelectedArticleId] = useState<string | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
const [articleBody, setArticleBody] = useState<string>("");
|
const [articleBody, setArticleBody] = useState<string>("");
|
||||||
|
|
||||||
// Form data state
|
// Form data state
|
||||||
const [tags, setTags] = useState<string[]>([]);
|
const [tags, setTags] = useState<string[]>([]);
|
||||||
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
||||||
|
|
@ -262,7 +266,7 @@ export default function FormConvertSPIT() {
|
||||||
// Auto-select "Pers Rilis" category if schedule type is 3
|
// Auto-select "Pers Rilis" category if schedule type is 3
|
||||||
const scheduleId = Cookies.get("scheduleId");
|
const scheduleId = Cookies.get("scheduleId");
|
||||||
const scheduleType = Cookies.get("scheduleType");
|
const scheduleType = Cookies.get("scheduleType");
|
||||||
|
|
||||||
if (scheduleId && scheduleType === "3") {
|
if (scheduleId && scheduleType === "3") {
|
||||||
const persRilisCategory = categories.find((cat: Category) =>
|
const persRilisCategory = categories.find((cat: Category) =>
|
||||||
cat.name.toLowerCase().includes("pers rilis")
|
cat.name.toLowerCase().includes("pers rilis")
|
||||||
|
|
@ -281,7 +285,7 @@ export default function FormConvertSPIT() {
|
||||||
try {
|
try {
|
||||||
const response = await getTagsBySubCategoryId(categoryId);
|
const response = await getTagsBySubCategoryId(categoryId);
|
||||||
if (response?.data?.data?.length > 0) {
|
if (response?.data?.data?.length > 0) {
|
||||||
const tagsMerge = [...tags, response?.data?.data]
|
const tagsMerge = [...tags, response?.data?.data];
|
||||||
setTags(tagsMerge);
|
setTags(tagsMerge);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -293,7 +297,7 @@ export default function FormConvertSPIT() {
|
||||||
try {
|
try {
|
||||||
const response = await detailSPIT(id);
|
const response = await detailSPIT(id);
|
||||||
const details = response?.data?.data;
|
const details = response?.data?.data;
|
||||||
|
|
||||||
if (!details) {
|
if (!details) {
|
||||||
throw new Error("Detail not found");
|
throw new Error("Detail not found");
|
||||||
}
|
}
|
||||||
|
|
@ -301,11 +305,11 @@ export default function FormConvertSPIT() {
|
||||||
setDetail(details);
|
setDetail(details);
|
||||||
setFiles(details.contentList || []);
|
setFiles(details.contentList || []);
|
||||||
setDetailThumb(
|
setDetailThumb(
|
||||||
(details.contentList || []).map((file: FileType) =>
|
(details.contentList || []).map(
|
||||||
file.contentFile || "default-image.jpg"
|
(file: FileType) => file.contentFile || "default-image.jpg"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize file placements
|
// Initialize file placements
|
||||||
const fileCount = details.contentList?.length || 0;
|
const fileCount = details.contentList?.length || 0;
|
||||||
setFilePlacements(Array(fileCount).fill([]));
|
setFilePlacements(Array(fileCount).fill([]));
|
||||||
|
|
@ -314,7 +318,10 @@ export default function FormConvertSPIT() {
|
||||||
setValue("contentTitle", details.contentTitle || "");
|
setValue("contentTitle", details.contentTitle || "");
|
||||||
setValue("contentDescription", details.contentDescription || "");
|
setValue("contentDescription", details.contentDescription || "");
|
||||||
setValue("contentCreator", details.contentCreator || "");
|
setValue("contentCreator", details.contentCreator || "");
|
||||||
setValue("contentRewriteDescription", details.contentRewriteDescription || "");
|
setValue(
|
||||||
|
"contentRewriteDescription",
|
||||||
|
details.contentRewriteDescription || ""
|
||||||
|
);
|
||||||
|
|
||||||
// Set category
|
// Set category
|
||||||
if (details.categoryId) {
|
if (details.categoryId) {
|
||||||
|
|
@ -324,7 +331,9 @@ export default function FormConvertSPIT() {
|
||||||
|
|
||||||
// Set tags
|
// Set tags
|
||||||
if (details.contentTag) {
|
if (details.contentTag) {
|
||||||
const initialTags = details.contentTag.split(",").map((tag: string) => tag.trim());
|
const initialTags = details.contentTag
|
||||||
|
.split(",")
|
||||||
|
.map((tag: string) => tag.trim());
|
||||||
setTags(initialTags);
|
setTags(initialTags);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -365,13 +374,13 @@ export default function FormConvertSPIT() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await generateDataRewrite(request);
|
const response = await generateDataRewrite(request);
|
||||||
|
|
||||||
if (response?.error) {
|
if (response?.error) {
|
||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newArticleId = response?.data?.data?.id;
|
const newArticleId = response?.data?.data?.id;
|
||||||
setArticleIds(prev => {
|
setArticleIds((prev) => {
|
||||||
const updated = [...prev];
|
const updated = [...prev];
|
||||||
if (updated.length < 3) {
|
if (updated.length < 3) {
|
||||||
updated.push(newArticleId);
|
updated.push(newArticleId);
|
||||||
|
|
@ -405,23 +414,26 @@ export default function FormConvertSPIT() {
|
||||||
try {
|
try {
|
||||||
setIsLoadingRewrite(true);
|
setIsLoadingRewrite(true);
|
||||||
setSelectedArticleId(articleId);
|
setSelectedArticleId(articleId);
|
||||||
|
|
||||||
let retryCount = 0;
|
let retryCount = 0;
|
||||||
const maxRetries = 20;
|
const maxRetries = 20;
|
||||||
|
|
||||||
while (retryCount < maxRetries) {
|
while (retryCount < maxRetries) {
|
||||||
const response = await getDetailArticle(articleId);
|
const response = await getDetailArticle(articleId);
|
||||||
const articleData = response?.data?.data;
|
const articleData = response?.data?.data;
|
||||||
|
|
||||||
if (articleData?.status === 2) {
|
if (articleData?.status === 2) {
|
||||||
const cleanArticleBody = articleData.articleBody?.replace(/<img[^>]*>/g, "");
|
const cleanArticleBody = articleData.articleBody?.replace(
|
||||||
|
/<img[^>]*>/g,
|
||||||
|
""
|
||||||
|
);
|
||||||
setArticleBody(cleanArticleBody || "");
|
setArticleBody(cleanArticleBody || "");
|
||||||
setValue("contentRewriteDescription", cleanArticleBody || "");
|
setValue("contentRewriteDescription", cleanArticleBody || "");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
retryCount++;
|
retryCount++;
|
||||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retryCount >= maxRetries) {
|
if (retryCount >= maxRetries) {
|
||||||
|
|
@ -444,40 +456,46 @@ export default function FormConvertSPIT() {
|
||||||
if (e.key === "Enter" && inputRef.current?.value.trim()) {
|
if (e.key === "Enter" && inputRef.current?.value.trim()) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const newTag = inputRef.current.value.trim();
|
const newTag = inputRef.current.value.trim();
|
||||||
|
|
||||||
if (!tags.includes(newTag)) {
|
if (!tags.includes(newTag)) {
|
||||||
setTags(prev => [...prev, newTag]);
|
setTags((prev) => [...prev, newTag]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inputRef.current.value = "";
|
inputRef.current.value = "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveTag = (index: number) => {
|
const handleRemoveTag = (index: number) => {
|
||||||
setTags(prev => prev.filter((_, i) => i !== index));
|
setTags((prev) => prev.filter((_, i) => i !== index));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePublishTargetChange = (optionId: string) => {
|
const handlePublishTargetChange = (optionId: string) => {
|
||||||
if (optionId === "all") {
|
if (optionId === "all") {
|
||||||
setPublishedFor(prev =>
|
setPublishedFor((prev) =>
|
||||||
prev.length === PUBLISH_OPTIONS.filter(opt => opt.id !== "all").length
|
prev.length === PUBLISH_OPTIONS.filter((opt) => opt.id !== "all").length
|
||||||
? []
|
? []
|
||||||
: PUBLISH_OPTIONS.filter(opt => opt.id !== "all").map(opt => opt.id)
|
: PUBLISH_OPTIONS.filter((opt) => opt.id !== "all").map(
|
||||||
|
(opt) => opt.id
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
setPublishedFor(prev =>
|
setPublishedFor((prev) =>
|
||||||
prev.includes(optionId)
|
prev.includes(optionId)
|
||||||
? prev.filter(id => id !== optionId && id !== "all")
|
? prev.filter((id) => id !== optionId && id !== "all")
|
||||||
: [...prev.filter(id => id !== "all"), optionId]
|
: [...prev.filter((id) => id !== "all"), optionId]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFilePlacementChange = (fileIndex: number, placement: string, checked: boolean) => {
|
const handleFilePlacementChange = (
|
||||||
setFilePlacements(prev => {
|
fileIndex: number,
|
||||||
|
placement: string,
|
||||||
|
checked: boolean
|
||||||
|
) => {
|
||||||
|
setFilePlacements((prev) => {
|
||||||
const updated = [...prev];
|
const updated = [...prev];
|
||||||
const currentPlacements = updated[fileIndex] || [];
|
const currentPlacements = updated[fileIndex] || [];
|
||||||
|
|
||||||
if (checked) {
|
if (checked) {
|
||||||
if (placement === "all") {
|
if (placement === "all") {
|
||||||
updated[fileIndex] = ["all", "mabes", "polda", "international"];
|
updated[fileIndex] = ["all", "mabes", "polda", "international"];
|
||||||
|
|
@ -492,25 +510,27 @@ export default function FormConvertSPIT() {
|
||||||
if (placement === "all") {
|
if (placement === "all") {
|
||||||
updated[fileIndex] = [];
|
updated[fileIndex] = [];
|
||||||
} else {
|
} else {
|
||||||
const newPlacements = currentPlacements.filter(p => p !== placement);
|
const newPlacements = currentPlacements.filter(
|
||||||
|
(p) => p !== placement
|
||||||
|
);
|
||||||
if (newPlacements.length === 3 && newPlacements.includes("all")) {
|
if (newPlacements.length === 3 && newPlacements.includes("all")) {
|
||||||
updated[fileIndex] = newPlacements.filter(p => p !== "all");
|
updated[fileIndex] = newPlacements.filter((p) => p !== "all");
|
||||||
} else {
|
} else {
|
||||||
updated[fileIndex] = newPlacements;
|
updated[fileIndex] = newPlacements;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectAllPlacements = (placement: string, checked: boolean) => {
|
const handleSelectAllPlacements = (placement: string, checked: boolean) => {
|
||||||
setFilePlacements(prev =>
|
setFilePlacements((prev) =>
|
||||||
prev.map(filePlacements =>
|
prev.map((filePlacements) =>
|
||||||
checked
|
checked
|
||||||
? Array.from(new Set([...filePlacements, placement]))
|
? Array.from(new Set([...filePlacements, placement]))
|
||||||
: filePlacements.filter(p => p !== placement)
|
: filePlacements.filter((p) => p !== placement)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
@ -520,7 +540,7 @@ export default function FormConvertSPIT() {
|
||||||
console.log("filePlacements : ", filePlacements);
|
console.log("filePlacements : ", filePlacements);
|
||||||
for (let i = 0; i < filePlacements.length; i++) {
|
for (let i = 0; i < filePlacements.length; i++) {
|
||||||
if (filePlacements[i].length > 0) {
|
if (filePlacements[i].length > 0) {
|
||||||
const placements = filePlacements[i];
|
const placements = filePlacements[i];
|
||||||
placementData.push({
|
placementData.push({
|
||||||
mediaFileId: files[i].contentId,
|
mediaFileId: files[i].contentId,
|
||||||
placements: placements.join(","),
|
placements: placements.join(","),
|
||||||
|
|
@ -530,15 +550,38 @@ export default function FormConvertSPIT() {
|
||||||
return placementData;
|
return placementData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkPlacement = (data: any) => {
|
||||||
|
let temp = true;
|
||||||
|
for (const element of data) {
|
||||||
|
if (element.length < 1) {
|
||||||
|
temp = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
};
|
||||||
|
|
||||||
// Form submission
|
// Form submission
|
||||||
const onSubmit = async (data: FormData) => {
|
const onSubmit = async (data: FormData) => {
|
||||||
|
if (!checkPlacement(filePlacements)) {
|
||||||
|
error("Select File Placement");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publishedFor.length < 1) {
|
||||||
|
error("Select Publish Target");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
|
|
||||||
const description = selectedFileType === "original"
|
const description =
|
||||||
? data.contentDescription
|
selectedFileType === "original"
|
||||||
: data.contentRewriteDescription;
|
? data.contentDescription
|
||||||
|
: data.contentRewriteDescription;
|
||||||
|
|
||||||
const requestData = {
|
const requestData = {
|
||||||
spitId: id,
|
spitId: id,
|
||||||
title: data.contentTitle,
|
title: data.contentTitle,
|
||||||
|
|
@ -552,7 +595,7 @@ export default function FormConvertSPIT() {
|
||||||
};
|
};
|
||||||
|
|
||||||
await convertSPIT(requestData);
|
await convertSPIT(requestData);
|
||||||
|
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
text: "Data saved successfully",
|
text: "Data saved successfully",
|
||||||
|
|
@ -590,7 +633,7 @@ export default function FormConvertSPIT() {
|
||||||
try {
|
try {
|
||||||
setIsDeleting(true);
|
setIsDeleting(true);
|
||||||
await deleteSPIT(id);
|
await deleteSPIT(id);
|
||||||
|
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
text: "Content deleted successfully",
|
text: "Content deleted successfully",
|
||||||
|
|
@ -630,17 +673,15 @@ export default function FormConvertSPIT() {
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-3xl font-bold tracking-tight">SPIT Convert Form</h1>
|
<h1 className="text-3xl font-bold tracking-tight">
|
||||||
|
SPIT Convert Form
|
||||||
|
</h1>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
Convert and manage your SPIT content
|
Convert and manage your SPIT content
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button
|
<Button variant="outline" size="sm" onClick={() => router.back()}>
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => router.back()}
|
|
||||||
>
|
|
||||||
<XCircle className="h-4 w-4 mr-2" />
|
<XCircle className="h-4 w-4 mr-2" />
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -734,7 +775,9 @@ export default function FormConvertSPIT() {
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
value={selectedFileType}
|
value={selectedFileType}
|
||||||
onValueChange={(value: "original" | "rewrite") => setSelectedFileType(value)}
|
onValueChange={(value: "original" | "rewrite") =>
|
||||||
|
setSelectedFileType(value)
|
||||||
|
}
|
||||||
className="grid grid-cols-2 gap-4"
|
className="grid grid-cols-2 gap-4"
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
|
@ -789,7 +832,9 @@ export default function FormConvertSPIT() {
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleRewriteClick}
|
onClick={handleRewriteClick}
|
||||||
disabled={isGeneratingRewrite || !detail?.contentDescription}
|
disabled={
|
||||||
|
isGeneratingRewrite || !detail?.contentDescription
|
||||||
|
}
|
||||||
className="bg-blue-600 hover:bg-blue-700"
|
className="bg-blue-600 hover:bg-blue-700"
|
||||||
>
|
>
|
||||||
{isGeneratingRewrite ? (
|
{isGeneratingRewrite ? (
|
||||||
|
|
@ -809,14 +854,19 @@ export default function FormConvertSPIT() {
|
||||||
<Button
|
<Button
|
||||||
key={articleId}
|
key={articleId}
|
||||||
type="button"
|
type="button"
|
||||||
variant={selectedArticleId === articleId ? "default" : "outline"}
|
variant={
|
||||||
|
selectedArticleId === articleId
|
||||||
|
? "default"
|
||||||
|
: "outline"
|
||||||
|
}
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => handleArticleSelect(articleId)}
|
onClick={() => handleArticleSelect(articleId)}
|
||||||
disabled={isLoadingRewrite}
|
disabled={isLoadingRewrite}
|
||||||
>
|
>
|
||||||
{isLoadingRewrite && selectedArticleId === articleId && (
|
{isLoadingRewrite &&
|
||||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
selectedArticleId === articleId && (
|
||||||
)}
|
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||||
|
)}
|
||||||
Narrative {index + 1}
|
Narrative {index + 1}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
|
|
@ -870,7 +920,7 @@ export default function FormConvertSPIT() {
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
|
||||||
<Swiper
|
<Swiper
|
||||||
onSwiper={setThumbsSwiper}
|
onSwiper={setThumbsSwiper}
|
||||||
slidesPerView={8}
|
slidesPerView={8}
|
||||||
|
|
@ -906,14 +956,23 @@ export default function FormConvertSPIT() {
|
||||||
{files.length > 1 && (
|
{files.length > 1 && (
|
||||||
<div className="flex flex-wrap gap-4 p-4 bg-muted/50 rounded-lg">
|
<div className="flex flex-wrap gap-4 p-4 bg-muted/50 rounded-lg">
|
||||||
{PLACEMENT_OPTIONS.map((option) => (
|
{PLACEMENT_OPTIONS.map((option) => (
|
||||||
<div key={option.value} className="flex items-center space-x-2">
|
<div
|
||||||
|
key={option.value}
|
||||||
|
className="flex items-center space-x-2"
|
||||||
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id={`select-all-${option.value}`}
|
id={`select-all-${option.value}`}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
handleSelectAllPlacements(option.value, Boolean(checked))
|
handleSelectAllPlacements(
|
||||||
|
option.value,
|
||||||
|
Boolean(checked)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor={`select-all-${option.value}`} className="text-sm">
|
<Label
|
||||||
|
htmlFor={`select-all-${option.value}`}
|
||||||
|
className="text-sm"
|
||||||
|
>
|
||||||
All {option.label}
|
All {option.label}
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -936,12 +995,21 @@ export default function FormConvertSPIT() {
|
||||||
<p className="font-medium text-sm">{file.fileName}</p>
|
<p className="font-medium text-sm">{file.fileName}</p>
|
||||||
<div className="flex flex-wrap gap-3">
|
<div className="flex flex-wrap gap-3">
|
||||||
{PLACEMENT_OPTIONS.map((option) => (
|
{PLACEMENT_OPTIONS.map((option) => (
|
||||||
<div key={option.value} className="flex items-center space-x-2">
|
<div
|
||||||
|
key={option.value}
|
||||||
|
className="flex items-center space-x-2"
|
||||||
|
>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id={`${file.contentId}-${option.value}`}
|
id={`${file.contentId}-${option.value}`}
|
||||||
checked={filePlacements[index]?.includes(option.value)}
|
checked={filePlacements[index]?.includes(
|
||||||
|
option.value
|
||||||
|
)}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
handleFilePlacementChange(index, option.value, Boolean(checked))
|
handleFilePlacementChange(
|
||||||
|
index,
|
||||||
|
option.value,
|
||||||
|
Boolean(checked)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Label
|
<Label
|
||||||
|
|
@ -1067,10 +1135,14 @@ export default function FormConvertSPIT() {
|
||||||
id={option.id}
|
id={option.id}
|
||||||
checked={
|
checked={
|
||||||
option.id === "all"
|
option.id === "all"
|
||||||
? publishedFor.length === PUBLISH_OPTIONS.filter(opt => opt.id !== "all").length
|
? publishedFor.length ===
|
||||||
|
PUBLISH_OPTIONS.filter((opt) => opt.id !== "all")
|
||||||
|
.length
|
||||||
: publishedFor.includes(option.id)
|
: publishedFor.includes(option.id)
|
||||||
}
|
}
|
||||||
onCheckedChange={() => handlePublishTargetChange(option.id)}
|
onCheckedChange={() =>
|
||||||
|
handlePublishTargetChange(option.id)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor={option.id} className="text-sm">
|
<Label htmlFor={option.id} className="text-sm">
|
||||||
{option.label}
|
{option.label}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue