fix: create content imgae

This commit is contained in:
Sabda Yagra 2025-07-18 09:33:32 +07:00
parent b8827ba8a8
commit 377c22e083
4 changed files with 88 additions and 38 deletions

View File

@ -60,13 +60,13 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { useTranslations } from "next-intl";
type StatusFilter = string[];
const ContentTable = () => {
const router = useRouter();
const searchParams = useSearchParams();
const [dataTable, setDataTable] = React.useState<any[]>([]);
const [totalData, setTotalData] = React.useState<number>(1);
const [sorting, setSorting] = React.useState<SortingState>([]);
@ -85,7 +85,6 @@ const ContentTable = () => {
const [limit, setLimit] = React.useState(10);
const userId = getCookiesDecrypt("uie");
const userLevelId = getCookiesDecrypt("ulie");
const [categories, setCategories] = React.useState<string[]>();
const [categoryFilter, setCategoryFilter] = React.useState<string[]>([]);
const [statusFilter, setStatusFilter] = React.useState<StatusFilter>([]);
@ -95,8 +94,8 @@ const ContentTable = () => {
const [fileTypeFilter, setFileTypeFilter] = React.useState<string[]>([]);
const [filterBySource, setFilterBySource] = React.useState<string>("");
const [search, setSearch] = React.useState("");
const roleId = getCookiesDecrypt("urie");
const t = useTranslations("Form");
const table = useReactTable({
data: dataTable,
@ -165,8 +164,8 @@ const ContentTable = () => {
}
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearch(e.target.value);
table.getColumn("judul")?.setFilterValue(e.target.value);
setSearch(e.target.value);
table.getColumn("judul")?.setFilterValue(e.target.value);
};
return (
@ -179,7 +178,7 @@ const ContentTable = () => {
</InputGroupText>
<Input
type="text"
placeholder="Search Judul..."
placeholder={t("searchTitle")}
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
value={search}
onChange={handleSearch}
@ -211,14 +210,14 @@ const ContentTable = () => {
}}
>
<SelectTrigger className="w-full lg:w-[180px]">
<SelectValue placeholder="Select a Filter" />
<SelectValue placeholder={t("selectFilter")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Filter</SelectLabel>
<SelectItem value="1">Foto</SelectItem>
<SelectItem value="2">Audio Visual</SelectItem>
<SelectItem value="3">Teks</SelectItem>
<SelectItem value="1">{t("image")}</SelectItem>
<SelectItem value="2">{t("audio-visual")}</SelectItem>
<SelectItem value="3">{t("text")}</SelectItem>
<SelectItem value="4">Audio</SelectItem>
</SelectGroup>
</SelectContent>

View File

@ -48,7 +48,7 @@ import {
import { getCookiesDecrypt } from "@/lib/utils";
import { useDropzone } from "react-dropzone";
import { Icon } from "@iconify/react";
import { CloudUpload } from "lucide-react";
import { CloudUpload, X } from "lucide-react";
import Image from "next/image";
import { error, loading } from "@/config/swal";
import { Item } from "@radix-ui/react-dropdown-menu";
@ -95,14 +95,12 @@ export default function FormImage() {
const scheduleType = Cookies.get("scheduleType");
const roleId = getCookiesDecrypt("urie");
const [selectedFileType, setSelectedFileType] = useState("original");
const [categories, setCategories] = useState<Category[]>([]);
const [selectedCategory, setSelectedCategory] = useState<any>();
const [tags, setTags] = useState<any[]>([]);
const [thumbnail, setThumbnail] = useState<File | null>(null);
const [preview, setPreview] = useState<string | null>(null);
const [selectedLanguage, setSelectedLanguage] = useState("");
const [selectedSEO, setSelectedSEO] = useState<string>("");
const [title, setTitle] = useState<string>("");
const [selectedAdvConfig, setSelectedAdvConfig] = useState<string>("");
@ -119,18 +117,14 @@ export default function FormImage() {
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
const [selectedWritingStyle, setSelectedWritingStyle] =
useState("professional");
const [editorContent, setEditorContent] = useState(""); // Untuk original editor
const [editorContent, setEditorContent] = useState("");
const [rewriteEditorContent, setRewriteEditorContent] = useState("");
const [selectedSize, setSelectedSize] = useState("");
const [detailData, setDetailData] = useState<any>(null);
const [articleImages, setArticleImages] = useState<string[]>([]);
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
const inputRef = useRef<HTMLInputElement>(null);
const [content, setContent] = useState("");
const [isContentRewriteClicked, setIsContentRewriteClicked] = useState(false);
const [selectedTarget, setSelectedTarget] = useState("");
const [unitSelection, setUnitSelection] = useState({
allUnit: false,
@ -147,7 +141,6 @@ export default function FormImage() {
const [isStartUpload, setIsStartUpload] = useState(false);
const [counterProgress, setCounterProgress] = useState(0);
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
const [files, setFiles] = useState<FileWithPreview[]>([]);
const [filesTemp, setFilesTemp] = useState<File[]>([]);
const [publishedFor, setPublishedFor] = useState<string[]>([]);
@ -1246,6 +1239,7 @@ export default function FormImage() {
name="files"
render={({ field }) => {
const maxSize = 100 * 1024 * 1024;
const [previews, setPreviews] = useState<string[]>([]);
const { getRootProps, getInputProps, fileRejections } =
useDropzone({
@ -1254,12 +1248,40 @@ export default function FormImage() {
"image/png": [".png"],
},
maxSize,
multiple: false,
multiple: true, // <- Set true jika ingin lebih dari satu
onDrop: (acceptedFiles) => {
field.onChange(acceptedFiles);
const currentFiles = [
...(field.value || []),
...acceptedFiles,
];
field.onChange(currentFiles);
const newPreviews = acceptedFiles.map((file) =>
URL.createObjectURL(file)
);
setPreviews((prev) => [...prev, ...newPreviews]);
},
});
// Clean up URL on unmount
useEffect(() => {
return () => {
previews.forEach((url) => URL.revokeObjectURL(url));
};
}, [previews]);
const handleRemoveFile = (indexToRemove: number) => {
const updatedFiles = [...field.value];
updatedFiles.splice(indexToRemove, 1);
const updatedPreviews = [...previews];
URL.revokeObjectURL(updatedPreviews[indexToRemove]); // Clean up
updatedPreviews.splice(indexToRemove, 1);
field.onChange(updatedFiles);
setPreviews(updatedPreviews);
};
return (
<div className="py-3 space-y-2">
<Label>
@ -1281,28 +1303,52 @@ export default function FormImage() {
</div>
</div>
</div>
{field.value && field.value.length > 0 && (
<>
<ul className="mt-2 text-sm">
{field.value.map((file, idx) => (
<li key={idx}>
{file.name} (
{(file.size / (1024 * 1024)).toFixed(2)} MB)
</li>
))}
</ul>
<div className="flex justify-end mt-2">
<div className="mt-3 space-y-3">
{field.value.map((file: File, idx: number) => (
<div
key={idx}
className="flex items-center gap-4 border p-2 rounded-md relative"
>
<img
src={previews[idx]}
alt={`preview-${idx}`}
className="w-24 h-24 object-cover rounded border"
/>
<div className="flex-1 text-sm">
<div className="font-medium">{file.name}</div>
<div className="text-muted-foreground text-xs">
{(file.size / (1024 * 1024)).toFixed(2)} MB
</div>
</div>
<button
type="button"
className="absolute top-1 right-1 text-muted-foreground hover:text-red-500"
onClick={() => handleRemoveFile(idx)}
>
<X className="w-5 h-5" />
</button>
</div>
))}
<div className="flex justify-end">
<Button
type="button"
color="destructive"
onClick={() => field.onChange([])}
variant="default"
onClick={() => {
field.onChange([]);
previews.forEach((url) =>
URL.revokeObjectURL(url)
);
setPreviews([]);
}}
>
{t("remove-all", {
defaultValue: "Remove All",
})}
</Button>
</div>
</>
</div>
)}
{errors.files?.message && (

View File

@ -836,7 +836,7 @@
"output-task": "Task Output",
"attachment": "Attachment",
"image": "Image",
"audio-visual": "Audio Visual",
"audio-visual": "Video",
"text": "Text",
"audio": "Audio",
"voice-note": "Voice Note",
@ -855,7 +855,9 @@
"coverage-area": "Coverage Area",
"only": "Only .jpg, .jpeg, .png files are allowed",
"size": "File too large. Max 100MB",
"onlyVd": "Upload files with mp4 or mov Maximum size 100mb."
"onlyVd": "Upload files with mp4 or mov Maximum size 100mb.",
"searchTitle": "Find Title...",
"selectFilter": "Select a Filter",
"noResult": "No results."
}
}

View File

@ -856,6 +856,9 @@
"coverage-area": "Cakupan Wilayah",
"only": "Hanya file .jpg, .jpeg, .png yang diizinkan",
"size": "File terlalu besar. Maksimal 100MB",
"onlyVd": "Upload file dengan mp4 atau mov Ukuran maksimal 100mb."
"onlyVd": "Upload file dengan mp4 atau mov Ukuran maksimal 100mb.",
"searchTitle": "Cari Judul...",
"selectFilter": "Pilih Filter",
"noResult": "Tidak ada hasil"
}
}