This commit is contained in:
hanif salafi 2025-08-29 14:22:18 +07:00
commit 66b592513e
5 changed files with 228 additions and 70 deletions

View File

@ -108,6 +108,66 @@ const ReportTable = () => {
const [previewData, setPreviewData] = React.useState<any>(null); const [previewData, setPreviewData] = React.useState<any>(null);
const [openDateDialog, setOpenDateDialog] = React.useState(false); const [openDateDialog, setOpenDateDialog] = React.useState(false);
const [reportDate, setReportDate] = React.useState(""); const [reportDate, setReportDate] = React.useState("");
const [startDate, setStartDate] = React.useState("");
const [endDate, setEndDate] = React.useState("");
// handleGenerateReport ubah sedikit
const handleGenerateReport = async () => {
if (!startDate || !endDate) {
MySwal.fire(
"Warning",
"Silakan pilih tanggal awal dan tanggal akhir terlebih dahulu",
"warning"
);
return;
}
if (new Date(startDate) > new Date(endDate)) {
MySwal.fire(
"Warning",
"Tanggal awal tidak boleh lebih besar dari tanggal akhir",
"warning"
);
return;
}
const title = `Report ${format(
new Date(startDate),
"dd-MM-yyyy"
)} - ${format(new Date(endDate), "dd-MM-yyyy")}`;
const requestData = {
title,
startDate,
endDate,
};
try {
const response = await saveReport(requestData);
if (response?.error) {
MySwal.fire(
"Error",
response?.message || "Gagal menyimpan laporan",
"error"
);
return;
}
MySwal.fire({
title: "Sukses",
text: "Laporan berhasil dibuat.",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then(() => {
fetchData();
setStartDate("");
setEndDate("");
});
} catch (error) {
console.error("Generate report error:", error);
MySwal.fire("Error", "Terjadi kesalahan saat membuat laporan", "error");
}
};
const handlePreview = (id: string) => { const handlePreview = (id: string) => {
const url = `https://new.netidhub.com/api/media/report/view?id=${id}`; const url = `https://new.netidhub.com/api/media/report/view?id=${id}`;
@ -247,49 +307,6 @@ const ReportTable = () => {
// } // }
// }; // };
const handleGenerateReport = async () => {
if (!reportDate) {
MySwal.fire(
"Warning",
"Silakan pilih tanggal laporan terlebih dahulu",
"warning"
);
return;
}
const title = `Report ${format(new Date(reportDate), "dd-MM-yyyy")}`;
const requestData = {
title,
date: reportDate,
};
try {
const response = await saveReport(requestData);
if (response?.error) {
MySwal.fire(
"Error",
response?.message || "Gagal menyimpan laporan",
"error"
);
return;
}
MySwal.fire({
title: "Sukses",
text: "Laporan berhasil dibuat.",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then(() => {
fetchData();
setReportDate("");
});
} catch (error) {
console.error("Generate report error:", error);
MySwal.fire("Error", "Terjadi kesalahan saat membuat laporan", "error");
}
};
return ( return (
<div> <div>
<Dialog open={openPreview} onOpenChange={setOpenPreview}> <Dialog open={openPreview} onOpenChange={setOpenPreview}>
@ -391,13 +408,13 @@ const ReportTable = () => {
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent <DropdownMenuContent
align="end" align="end"
className="w-64 h-[200px] overflow-y-auto" className="w-64 h-fit overflow-y-auto"
> >
<div className="flex flex-row justify-between my-1 mx-1"> <div className="flex flex-row justify-between my-1 mx-1">
<p>Filter</p> <p>Filter</p>
</div> </div>
<div className="mx-2 my-1"> <div className="mx-2 my-1">
<Label>{t("date", { defaultValue: "Date" })}</Label> <Label>Tanggal Generate</Label>
<Input <Input
type="date" type="date"
value={dateFilter} value={dateFilter}
@ -414,8 +431,8 @@ const ReportTable = () => {
className="max-w-sm" className="max-w-sm"
/> />
</div> */} </div> */}
<Label className="ml-2 mt-2">Status</Label> {/* <Label className="ml-2 mt-2">Status</Label> */}
<div className="flex items-center px-4 py-1"> {/* <div className="flex items-center px-4 py-1">
<input <input
type="checkbox" type="checkbox"
id="status-1" id="status-1"
@ -426,8 +443,8 @@ const ReportTable = () => {
<label htmlFor="status-1" className="text-sm"> <label htmlFor="status-1" className="text-sm">
{t("wait-review", { defaultValue: "Wait Review" })} {t("wait-review", { defaultValue: "Wait Review" })}
</label> </label>
</div> </div> */}
<div className="flex items-center px-4 py-1"> {/* <div className="flex items-center px-4 py-1">
<input <input
type="checkbox" type="checkbox"
id="status-2" id="status-2"
@ -438,7 +455,7 @@ const ReportTable = () => {
<label htmlFor="status-2" className="text-sm"> <label htmlFor="status-2" className="text-sm">
{t("acc", { defaultValue: "Acc" })} {t("acc", { defaultValue: "Acc" })}
</label> </label>
</div> </div> */}
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
</div> </div>
@ -528,16 +545,27 @@ const ReportTable = () => {
<Dialog open={openDateDialog} onOpenChange={setOpenDateDialog}> <Dialog open={openDateDialog} onOpenChange={setOpenDateDialog}>
<DialogContent className="sm:max-w-md"> <DialogContent className="sm:max-w-md">
<DialogHeader> <DialogHeader>
<DialogTitle>Pilih Tanggal Laporan</DialogTitle> <DialogTitle>Pilih Rentang Tanggal Laporan</DialogTitle>
</DialogHeader> </DialogHeader>
<div className="space-y-4"> <div className="space-y-4">
<Label htmlFor="reportDate">Tanggal</Label> <div>
<Input <Label htmlFor="startDate">Tanggal Awal</Label>
id="reportDate" <Input
type="date" id="startDate"
value={reportDate} type="date"
onChange={(e) => setReportDate(e.target.value)} value={startDate}
/> onChange={(e) => setStartDate(e.target.value)}
/>
</div>
<div>
<Label htmlFor="endDate">Tanggal Akhir</Label>
<Input
id="endDate"
type="date"
value={endDate}
onChange={(e) => setEndDate(e.target.value)}
/>
</div>
<div className="flex justify-end gap-2"> <div className="flex justify-end gap-2">
<Button <Button
variant="outline" variant="outline"

View File

@ -300,7 +300,7 @@ export default function ContentBlast(props: { type: string }) {
Untuk melihat Email Terkirim silahkan cek menu Sent! Untuk melihat Email Terkirim silahkan cek menu Sent!
</div> </div>
<DialogFooter className="flex justify-center"> <DialogFooter className="flex justify-center">
<Link {/* <Link
href={`/admin/broadcast/campaign-list/detail/${ href={`/admin/broadcast/campaign-list/detail/${
form.getValues("selected")[0]?.id form.getValues("selected")[0]?.id
}`} }`}
@ -308,7 +308,7 @@ export default function ContentBlast(props: { type: string }) {
<Button type="button" color="success"> <Button type="button" color="success">
Menu "Sent" Menu "Sent"
</Button> </Button>
</Link> </Link> */}
<Button <Button
type="button" type="button"

View File

@ -44,6 +44,7 @@ import { ChevronDownIcon } from "lucide-react";
import { getOperatorUser } from "@/service/management-user/management-user"; import { getOperatorUser } from "@/service/management-user/management-user";
import makeAnimated from "react-select/animated"; import makeAnimated from "react-select/animated";
import Select, { ActionMeta, MultiValue } from "react-select"; import Select, { ActionMeta, MultiValue } from "react-select";
import { Checkbox } from "@/components/ui/checkbox";
interface Option { interface Option {
id: string; id: string;
@ -114,6 +115,7 @@ export default function FormQuestionsForward() {
const [selectedOperator, setSelectedOperator] = useState<string[]>([]); const [selectedOperator, setSelectedOperator] = useState<string[]>([]);
const [options, setOptions] = useState<Option[]>([]); const [options, setOptions] = useState<Option[]>([]);
const animatedComponent = makeAnimated(); const animatedComponent = makeAnimated();
const [isCollaboration, setIsCollaboration] = useState(false);
const [selectedOption, setSelectedOption] = useState<Option[]>([]); const [selectedOption, setSelectedOption] = useState<Option[]>([]);
const [replies, setReplies] = useState([ const [replies, setReplies] = useState([
{ {
@ -199,6 +201,7 @@ export default function FormQuestionsForward() {
operatorTeam: selectedOperator.join(","), operatorTeam: selectedOperator.join(","),
isEscalation: true, isEscalation: true,
communicationTeam: selectedOption.map((item) => item.id).join(","), communicationTeam: selectedOption.map((item) => item.id).join(","),
isCollaboration: isCollaboration,
}; };
const response = await saveTicketsQuestion(payload); const response = await saveTicketsQuestion(payload);
@ -453,6 +456,14 @@ export default function FormQuestionsForward() {
/> />
</div> </div>
<div className="flex flex-row gap-2 px-3 py-3">
<Label className="">Bagikan Untuk Kolaborasi</Label>
<Checkbox
checked={isCollaboration}
onCheckedChange={(e: boolean) => setIsCollaboration(e)}
/>
</div>
<div className="flex justify-end mt-3 mr-3 py-3"> <div className="flex justify-end mt-3 mr-3 py-3">
<Button type="submit" color="primary"> <Button type="submit" color="primary">
Simpan Simpan

View File

@ -790,6 +790,117 @@ export default function FormConvertSPIT() {
{/* Content Editor */} {/* Content Editor */}
<Card> <Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Edit3 className="h-5 w-5" />
Content Editor
</CardTitle>
</CardHeader>
<CardContent className="space-y-8">
{/* Original Content */}
<div className="space-y-2">
<Label className="text-lg text-black">Original Content</Label>
<Controller
control={control}
name="contentDescription"
render={({ field }) => (
<CustomEditor
onChange={field.onChange}
initialData={field.value}
/>
)}
/>
</div>
{/* Content Rewrite */}
<div className="space-y-4">
<Label className="text-lg text-black">
Rewritten Content
</Label>
<div className="flex items-center justify-between">
<div className="space-y-2">
<Label>Writing Style</Label>
<Select
value={selectedWritingStyle}
onValueChange={setSelectedWritingStyle}
>
<SelectTrigger className="w-48">
<SelectValue placeholder="Select style" />
</SelectTrigger>
<SelectContent>
{WRITING_STYLES.map((style) => (
<SelectItem key={style.value} value={style.value}>
{style.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<Button
type="button"
onClick={handleRewriteClick}
disabled={
isGeneratingRewrite || !detail?.contentDescription
}
className="bg-blue-600 hover:bg-blue-700"
>
{isGeneratingRewrite ? (
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
) : (
<Edit3 className="h-4 w-4 mr-2" />
)}
Generate Rewrite
</Button>
</div>
{showRewriteEditor && (
<div className="space-y-4">
{articleIds.length > 0 && (
<div className="flex gap-2">
{articleIds.map((articleId, index) => (
<Button
key={articleId}
type="button"
variant={
selectedArticleId === articleId
? "default"
: "outline"
}
size="sm"
onClick={() => handleArticleSelect(articleId)}
disabled={isLoadingRewrite}
>
{isLoadingRewrite &&
selectedArticleId === articleId && (
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
)}
Narrative {index + 1}
</Button>
))}
</div>
)}
<div className="space-y-2">
<Label>Rewritten Content</Label>
<Controller
control={control}
name="contentRewriteDescription"
render={({ field }) => (
<CustomEditor
onChange={field.onChange}
initialData={articleBody || field.value}
/>
)}
/>
</div>
</div>
)}
</div>
</CardContent>
</Card>
{/* <Card>
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2">
<Edit3 className="h-5 w-5" /> <Edit3 className="h-5 w-5" />
@ -815,7 +926,7 @@ export default function FormConvertSPIT() {
</RadioGroup> </RadioGroup>
{/* Original Content */} {/* Original Content */}
{selectedFileType === "original" && ( {/* {selectedFileType === "original" && (
<div className="space-y-2"> <div className="space-y-2">
<Label>Content Description</Label> <Label>Content Description</Label>
<Controller <Controller
@ -829,10 +940,10 @@ export default function FormConvertSPIT() {
)} )}
/> />
</div> </div>
)} )} */}
{/* Content Rewrite */} {/* Content Rewrite */}
{selectedFileType === "rewrite" && ( {/* {selectedFileType === "rewrite" && (
<div className="space-y-4"> <div className="space-y-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="space-y-2"> <div className="space-y-2">
@ -915,7 +1026,7 @@ export default function FormConvertSPIT() {
</div> </div>
)} )}
</CardContent> </CardContent>
</Card> </Card> */}
{/* Media Files */} {/* Media Files */}
{detailThumb.length > 0 && ( {detailThumb.length > 0 && (
@ -1073,7 +1184,9 @@ export default function FormConvertSPIT() {
<div className="flex-1 space-y-3"> <div className="flex-1 space-y-3">
<p className="font-medium text-sm"> <p className="font-medium text-sm">
{file.fileName || file.contentFileName || `File ${file.contentId}`} {file.fileName ||
file.contentFileName ||
`File ${file.contentId}`}
</p> </p>
<div className="flex flex-wrap gap-3"> <div className="flex flex-wrap gap-3">
{PLACEMENT_OPTIONS.map((option) => ( {PLACEMENT_OPTIONS.map((option) => (
@ -1271,7 +1384,6 @@ export default function FormConvertSPIT() {
); );
} }
// "use client"; // "use client";
// import React, { ChangeEvent, useEffect, useRef, useState } from "react"; // import React, { ChangeEvent, useEffect, useRef, useState } from "react";
// import { useForm, Controller } from "react-hook-form"; // import { useForm, Controller } from "react-hook-form";
@ -2484,5 +2596,3 @@ export default function FormConvertSPIT() {
// </div> // </div>
// ); // );
// } // }

View File

@ -92,10 +92,19 @@ export default function InfoLainnyaModal({
className="max-h-[300px] w-auto object-contain border rounded" className="max-h-[300px] w-auto object-contain border rounded"
/> />
) : ( ) : (
// <iframe
// src={getIframeUrl(currentFile?.fileUrl || "")}
// title={`Lampiran ${currentIndex + 1}`}
// className="w-full max-w-2xl h-[300px] border rounded"
// onError={(e) => {
// (e.target as HTMLIFrameElement).style.display = "none";
// }}
// />
<iframe <iframe
src={getIframeUrl(currentFile?.fileUrl || "")} src={getIframeUrl(currentFile?.fileUrl || "")}
title={`Lampiran ${currentIndex + 1}`} title={`Lampiran ${currentIndex + 1}`}
className="w-full max-w-2xl h-[300px] border rounded" className="w-full max-w-2xl h-[500px] rounded overflow-hidden"
scrolling="no"
onError={(e) => { onError={(e) => {
(e.target as HTMLIFrameElement).style.display = "none"; (e.target as HTMLIFrameElement).style.display = "none";
}} }}