fix: create content imgae
This commit is contained in:
parent
b8827ba8a8
commit
377c22e083
|
|
@ -60,13 +60,13 @@ import {
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
type StatusFilter = string[];
|
type StatusFilter = string[];
|
||||||
|
|
||||||
const ContentTable = () => {
|
const ContentTable = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||||
const [totalData, setTotalData] = React.useState<number>(1);
|
const [totalData, setTotalData] = React.useState<number>(1);
|
||||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||||
|
|
@ -85,7 +85,6 @@ const ContentTable = () => {
|
||||||
const [limit, setLimit] = React.useState(10);
|
const [limit, setLimit] = React.useState(10);
|
||||||
const userId = getCookiesDecrypt("uie");
|
const userId = getCookiesDecrypt("uie");
|
||||||
const userLevelId = getCookiesDecrypt("ulie");
|
const userLevelId = getCookiesDecrypt("ulie");
|
||||||
|
|
||||||
const [categories, setCategories] = React.useState<string[]>();
|
const [categories, setCategories] = React.useState<string[]>();
|
||||||
const [categoryFilter, setCategoryFilter] = React.useState<string[]>([]);
|
const [categoryFilter, setCategoryFilter] = React.useState<string[]>([]);
|
||||||
const [statusFilter, setStatusFilter] = React.useState<StatusFilter>([]);
|
const [statusFilter, setStatusFilter] = React.useState<StatusFilter>([]);
|
||||||
|
|
@ -95,8 +94,8 @@ const ContentTable = () => {
|
||||||
const [fileTypeFilter, setFileTypeFilter] = React.useState<string[]>([]);
|
const [fileTypeFilter, setFileTypeFilter] = React.useState<string[]>([]);
|
||||||
const [filterBySource, setFilterBySource] = React.useState<string>("");
|
const [filterBySource, setFilterBySource] = React.useState<string>("");
|
||||||
const [search, setSearch] = React.useState("");
|
const [search, setSearch] = React.useState("");
|
||||||
|
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
|
const t = useTranslations("Form");
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
|
|
@ -179,7 +178,7 @@ const ContentTable = () => {
|
||||||
</InputGroupText>
|
</InputGroupText>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
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"
|
className="bg-transparent dark:border-secondary dark:placeholder-white/80 dark:focus:border-secondary dark:text-white"
|
||||||
value={search}
|
value={search}
|
||||||
onChange={handleSearch}
|
onChange={handleSearch}
|
||||||
|
|
@ -211,14 +210,14 @@ const ContentTable = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full lg:w-[180px]">
|
<SelectTrigger className="w-full lg:w-[180px]">
|
||||||
<SelectValue placeholder="Select a Filter" />
|
<SelectValue placeholder={t("selectFilter")} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectLabel>Filter</SelectLabel>
|
<SelectLabel>Filter</SelectLabel>
|
||||||
<SelectItem value="1">Foto</SelectItem>
|
<SelectItem value="1">{t("image")}</SelectItem>
|
||||||
<SelectItem value="2">Audio Visual</SelectItem>
|
<SelectItem value="2">{t("audio-visual")}</SelectItem>
|
||||||
<SelectItem value="3">Teks</SelectItem>
|
<SelectItem value="3">{t("text")}</SelectItem>
|
||||||
<SelectItem value="4">Audio</SelectItem>
|
<SelectItem value="4">Audio</SelectItem>
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ import {
|
||||||
import { getCookiesDecrypt } from "@/lib/utils";
|
import { getCookiesDecrypt } from "@/lib/utils";
|
||||||
import { useDropzone } from "react-dropzone";
|
import { useDropzone } from "react-dropzone";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { CloudUpload } from "lucide-react";
|
import { CloudUpload, X } from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { error, loading } from "@/config/swal";
|
import { error, loading } from "@/config/swal";
|
||||||
import { Item } from "@radix-ui/react-dropdown-menu";
|
import { Item } from "@radix-ui/react-dropdown-menu";
|
||||||
|
|
@ -95,14 +95,12 @@ export default function FormImage() {
|
||||||
const scheduleType = Cookies.get("scheduleType");
|
const scheduleType = Cookies.get("scheduleType");
|
||||||
const roleId = getCookiesDecrypt("urie");
|
const roleId = getCookiesDecrypt("urie");
|
||||||
const [selectedFileType, setSelectedFileType] = useState("original");
|
const [selectedFileType, setSelectedFileType] = useState("original");
|
||||||
|
|
||||||
const [categories, setCategories] = useState<Category[]>([]);
|
const [categories, setCategories] = useState<Category[]>([]);
|
||||||
const [selectedCategory, setSelectedCategory] = useState<any>();
|
const [selectedCategory, setSelectedCategory] = useState<any>();
|
||||||
const [tags, setTags] = useState<any[]>([]);
|
const [tags, setTags] = useState<any[]>([]);
|
||||||
const [thumbnail, setThumbnail] = useState<File | null>(null);
|
const [thumbnail, setThumbnail] = useState<File | null>(null);
|
||||||
const [preview, setPreview] = useState<string | null>(null);
|
const [preview, setPreview] = useState<string | null>(null);
|
||||||
const [selectedLanguage, setSelectedLanguage] = useState("");
|
const [selectedLanguage, setSelectedLanguage] = useState("");
|
||||||
|
|
||||||
const [selectedSEO, setSelectedSEO] = useState<string>("");
|
const [selectedSEO, setSelectedSEO] = useState<string>("");
|
||||||
const [title, setTitle] = useState<string>("");
|
const [title, setTitle] = useState<string>("");
|
||||||
const [selectedAdvConfig, setSelectedAdvConfig] = useState<string>("");
|
const [selectedAdvConfig, setSelectedAdvConfig] = useState<string>("");
|
||||||
|
|
@ -119,18 +117,14 @@ export default function FormImage() {
|
||||||
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
const [selectedMainKeyword, setSelectedMainKeyword] = useState("");
|
||||||
const [selectedWritingStyle, setSelectedWritingStyle] =
|
const [selectedWritingStyle, setSelectedWritingStyle] =
|
||||||
useState("professional");
|
useState("professional");
|
||||||
const [editorContent, setEditorContent] = useState(""); // Untuk original editor
|
const [editorContent, setEditorContent] = useState("");
|
||||||
const [rewriteEditorContent, setRewriteEditorContent] = useState("");
|
const [rewriteEditorContent, setRewriteEditorContent] = useState("");
|
||||||
const [selectedSize, setSelectedSize] = useState("");
|
const [selectedSize, setSelectedSize] = useState("");
|
||||||
const [detailData, setDetailData] = useState<any>(null);
|
const [detailData, setDetailData] = useState<any>(null);
|
||||||
const [articleImages, setArticleImages] = useState<string[]>([]);
|
const [articleImages, setArticleImages] = useState<string[]>([]);
|
||||||
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
|
const [isSwitchOn, setIsSwitchOn] = useState<boolean>(false);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const [content, setContent] = useState("");
|
|
||||||
|
|
||||||
const [isContentRewriteClicked, setIsContentRewriteClicked] = useState(false);
|
const [isContentRewriteClicked, setIsContentRewriteClicked] = useState(false);
|
||||||
|
|
||||||
const [selectedTarget, setSelectedTarget] = useState("");
|
const [selectedTarget, setSelectedTarget] = useState("");
|
||||||
const [unitSelection, setUnitSelection] = useState({
|
const [unitSelection, setUnitSelection] = useState({
|
||||||
allUnit: false,
|
allUnit: false,
|
||||||
|
|
@ -147,7 +141,6 @@ export default function FormImage() {
|
||||||
const [isStartUpload, setIsStartUpload] = useState(false);
|
const [isStartUpload, setIsStartUpload] = useState(false);
|
||||||
const [counterProgress, setCounterProgress] = useState(0);
|
const [counterProgress, setCounterProgress] = useState(0);
|
||||||
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
const [showRewriteEditor, setShowRewriteEditor] = useState(false);
|
||||||
|
|
||||||
const [files, setFiles] = useState<FileWithPreview[]>([]);
|
const [files, setFiles] = useState<FileWithPreview[]>([]);
|
||||||
const [filesTemp, setFilesTemp] = useState<File[]>([]);
|
const [filesTemp, setFilesTemp] = useState<File[]>([]);
|
||||||
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
const [publishedFor, setPublishedFor] = useState<string[]>([]);
|
||||||
|
|
@ -1246,6 +1239,7 @@ export default function FormImage() {
|
||||||
name="files"
|
name="files"
|
||||||
render={({ field }) => {
|
render={({ field }) => {
|
||||||
const maxSize = 100 * 1024 * 1024;
|
const maxSize = 100 * 1024 * 1024;
|
||||||
|
const [previews, setPreviews] = useState<string[]>([]);
|
||||||
|
|
||||||
const { getRootProps, getInputProps, fileRejections } =
|
const { getRootProps, getInputProps, fileRejections } =
|
||||||
useDropzone({
|
useDropzone({
|
||||||
|
|
@ -1254,12 +1248,40 @@ export default function FormImage() {
|
||||||
"image/png": [".png"],
|
"image/png": [".png"],
|
||||||
},
|
},
|
||||||
maxSize,
|
maxSize,
|
||||||
multiple: false,
|
multiple: true, // <- Set true jika ingin lebih dari satu
|
||||||
onDrop: (acceptedFiles) => {
|
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 (
|
return (
|
||||||
<div className="py-3 space-y-2">
|
<div className="py-3 space-y-2">
|
||||||
<Label>
|
<Label>
|
||||||
|
|
@ -1281,28 +1303,52 @@ export default function FormImage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{field.value && field.value.length > 0 && (
|
{field.value && field.value.length > 0 && (
|
||||||
<>
|
<div className="mt-3 space-y-3">
|
||||||
<ul className="mt-2 text-sm">
|
{field.value.map((file: File, idx: number) => (
|
||||||
{field.value.map((file, idx) => (
|
<div
|
||||||
<li key={idx}>
|
key={idx}
|
||||||
{file.name} (
|
className="flex items-center gap-4 border p-2 rounded-md relative"
|
||||||
{(file.size / (1024 * 1024)).toFixed(2)} MB)
|
>
|
||||||
</li>
|
<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>
|
||||||
))}
|
))}
|
||||||
</ul>
|
<div className="flex justify-end">
|
||||||
<div className="flex justify-end mt-2">
|
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
color="destructive"
|
variant="default"
|
||||||
onClick={() => field.onChange([])}
|
onClick={() => {
|
||||||
|
field.onChange([]);
|
||||||
|
previews.forEach((url) =>
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
);
|
||||||
|
setPreviews([]);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t("remove-all", {
|
{t("remove-all", {
|
||||||
defaultValue: "Remove All",
|
defaultValue: "Remove All",
|
||||||
})}
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{errors.files?.message && (
|
{errors.files?.message && (
|
||||||
|
|
|
||||||
|
|
@ -836,7 +836,7 @@
|
||||||
"output-task": "Task Output",
|
"output-task": "Task Output",
|
||||||
"attachment": "Attachment",
|
"attachment": "Attachment",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
"audio-visual": "Audio Visual",
|
"audio-visual": "Video",
|
||||||
"text": "Text",
|
"text": "Text",
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
"voice-note": "Voice Note",
|
"voice-note": "Voice Note",
|
||||||
|
|
@ -855,7 +855,9 @@
|
||||||
"coverage-area": "Coverage Area",
|
"coverage-area": "Coverage Area",
|
||||||
"only": "Only .jpg, .jpeg, .png files are allowed",
|
"only": "Only .jpg, .jpeg, .png files are allowed",
|
||||||
"size": "File too large. Max 100MB",
|
"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."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -856,6 +856,9 @@
|
||||||
"coverage-area": "Cakupan Wilayah",
|
"coverage-area": "Cakupan Wilayah",
|
||||||
"only": "Hanya file .jpg, .jpeg, .png yang diizinkan",
|
"only": "Hanya file .jpg, .jpeg, .png yang diizinkan",
|
||||||
"size": "File terlalu besar. Maksimal 100MB",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue