feat:magazine edit

This commit is contained in:
Rama Priyanto 2025-01-21 18:20:58 +07:00
parent d64ce7fc14
commit 471539804c
4 changed files with 281 additions and 47 deletions

View File

@ -33,7 +33,7 @@ import {
PptIcon,
WordIcon,
} from "@/components/icons/globals";
import { createMagazine } from "@/service/magazine";
import { createMagazine, uploadMagazineFile } from "@/service/magazine";
// const CustomEditor = dynamic(
// () => {
@ -85,11 +85,6 @@ export default function NewCreateMagazineForm() {
const router = useRouter();
const editor = useRef(null);
const [files, setFiles] = useState<FileWithPreview[]>([]);
const [useAi, setUseAI] = useState(false);
const [listCategory, setListCategory] = useState<CategoryType[]>([]);
const [tag, setTag] = useState("");
const [thumbnailImg, setThumbnailImg] = useState<File[]>([]);
const [selectedMainImage, setSelectedMainImage] = useState<number>();
const { getRootProps, getInputProps } = useDropzone({
onDrop: (acceptedFiles) => {
@ -160,28 +155,23 @@ export default function NewCreateMagazineForm() {
// rows: values.rows,
};
console.log("formd", formData);
// const response = await createMagazine(formData);
const response = await createMagazine(formData);
// if (response?.error) {
// error(response.message);
// return false;
// }
// const magazineId = response?.data?.data?.id;
// if (files?.length > 0) {
// const formFiles = new FormData();
if (response?.error) {
error(response.message);
return false;
}
const magazineId = response?.data?.data?.id;
if (files?.length > 0) {
const formFiles = new FormData();
// for (const element of files) {
// formFiles.append("file", element);
// const resFile = await uploadArticleFile(magazineId, formFiles);
// }
// }
// if (thumbnailImg?.length > 0) {
// const formFiles = new FormData();
// formFiles.append("file", thumbnailImg[0]);
// const resFile = await uploadArticleThumbnail(magazineId, formFiles);
// }
for (let i = 0; i < files.length; i++) {
formFiles.append("files", files[i]);
formFiles.append("title", values.rows[i].title);
formFiles.append("file", values.rows[i].description);
const resFile = await uploadMagazineFile(magazineId, formFiles);
}
}
close();
successSubmit("/admin/magazine");
@ -310,6 +300,7 @@ export default function NewCreateMagazineForm() {
<Button
className=" border-none rounded-full"
variant="bordered"
color="danger"
onClick={() => handleRemoveFile(file)}
>
<TimesIcon />

View File

@ -29,12 +29,14 @@ import Link from "next/link";
import {
CsvIcon,
ExcelIcon,
FileIcon,
PdfIcon,
PptIcon,
WordIcon,
} from "@/components/icons/globals";
import {
createMagazine,
deleteMagazineFiles,
getMagazineById,
updateMagazine,
uploadMagazineFile,
@ -93,6 +95,7 @@ export default function EditMagazineForm(props: { isDetail: boolean }) {
const router = useRouter();
const editor = useRef(null);
const [files, setFiles] = useState<FileWithPreview[]>([]);
const [detailfiles, setDetailFiles] = useState<any>([]);
const { getRootProps, getInputProps } = useDropzone({
onDrop: (acceptedFiles) => {
@ -144,6 +147,8 @@ export default function EditMagazineForm(props: { isDetail: boolean }) {
const data = res?.data?.data;
setValue("title", data?.title);
setValue("description", data?.description);
setDetailFiles(data?.files);
console.log("datasss", data);
};
@ -222,31 +227,38 @@ export default function EditMagazineForm(props: { isDetail: boolean }) {
setValue("slug", generateSlug(watchTitle));
}, [watchTitle]);
const renderPreview = (file: File) => {
if (file.type === "application/pdf") {
const renderPreview = (file: File, fileName?: string) => {
const fileType = fileName?.split(".")[fileName?.split(".").length - 1];
if (file.type === "application/pdf" || fileType == "pdf") {
return <PdfIcon size={60} />;
} else if (file.type === "text/csv") {
} else if (file.type === "text/csv" || fileType == "csv") {
return <CsvIcon size={60} />;
} else if (
file.type ===
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" ||
file.type === "application/msword"
file.type === "application/msword" ||
fileType == "doc" ||
fileType == "docx"
) {
return <WordIcon size={60} />;
} else if (
file.type ===
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
file.type === "application/vnd.ms-excel"
file.type === "application/vnd.ms-excel" ||
fileType == "xls" ||
fileType == "xlsx"
) {
return <ExcelIcon size={60} />;
} else if (
file.type ===
"application/vnd.openxmlformats-officedocument.presentationml.presentation" ||
file.type === "application/vnd.ms-powerpoint"
file.type === "application/vnd.ms-powerpoint" ||
fileType == "ppt" ||
fileType == "pptx"
) {
return <PptIcon size={60} />;
} else {
return "unknown";
return <FileIcon size={60} />;
}
};
@ -319,6 +331,7 @@ export default function EditMagazineForm(props: { isDetail: boolean }) {
<Button
className=" border-none rounded-full"
variant="bordered"
color="danger"
onClick={() => handleRemoveFile(file)}
>
<TimesIcon />
@ -326,6 +339,43 @@ export default function EditMagazineForm(props: { isDetail: boolean }) {
</div>
));
const handleDeleteFile = (id: number) => {
MySwal.fire({
title: "Hapus File",
text: "",
icon: "warning",
showCancelButton: true,
cancelButtonColor: "#d33",
confirmButtonColor: "#3085d6",
confirmButtonText: "Hapus",
}).then((result) => {
if (result.isConfirmed) {
deleteFile(id);
}
});
};
const deleteFile = async (id: number) => {
loading();
const res = await deleteMagazineFiles(id);
if (res?.error) {
error(res.message);
return false;
}
close();
initFetch();
MySwal.fire({
title: "Sukses",
icon: "success",
confirmButtonColor: "#3085d6",
confirmButtonText: "OK",
}).then((result) => {
if (result.isConfirmed) {
}
});
};
return (
<form
className="flex flex-row gap-8 text-black"
@ -411,8 +461,8 @@ export default function EditMagazineForm(props: { isDetail: boolean }) {
)}
<p className="text-sm mt-3">File Media</p>
<Fragment>
{!isDetail && (
{!isDetail && (
<Fragment>
<div {...getRootProps({ className: "dropzone" })} className="mb-2">
<input {...getInputProps()} />
<div className=" w-full text-center border-dashed border border-default-200 dark:border-default-300 rounded-md py-[52px] flex items-center flex-col">
@ -426,21 +476,190 @@ export default function EditMagazineForm(props: { isDetail: boolean }) {
</div>
</div>
</div>
)}
<div className="grid grid-cols-2 gap-2">
{files.length ? (
<Fragment>
{fileList}
{files.length ? (
<Fragment>
<div className="grid grid-cols-2 gap-2">{fileList}</div>
{files.length > 1 && (
<div className=" flex justify-between gap-2">
<Button onPress={() => setFiles([])} size="sm">
Hapus Semua
{/* {files.length > 1 && (
<div className=" flex justify-between gap-2">
<Button onPress={() => setFiles([])} size="sm">
Hapus Semua
</Button>
</div>
)} */}
</Fragment>
) : null}
{detailfiles?.map((file: any, index: number) => (
<div
key={file.fileName + index}
className=" flex justify-between border p-3 rounded-md"
>
<div className="flex gap-3 grow">
<div className="file-preview">
{renderPreview(file, file.fileName)}
</div>
<div className="flex flex-col gap-1 grow">
<p className="text-sm font-semibold">Nama File</p>
<div className="flex flex-row gap-2 items-center">
<p className=" text-sm text-card-foreground">
{file.fileName}
</p>
<p className=" text-xs font-light text-muted-foreground">
{Math.round(file.size / 100) / 10 > 1000 ? (
<>
{(Math.round(file.size / 100) / 10000).toFixed(1)}
</>
) : (
<>{(Math.round(file.size / 100) / 10).toFixed(1)}</>
)}
{" kb"}
</p>
</div>
<p className="text-sm font-semibold">Judul</p>
<Input
type="text"
id="title"
placeholder=""
label=""
isReadOnly
value={file.title}
onValueChange={(e) =>
setValue(`rows.${index}.title`, e)
}
labelPlacement="outside"
className="w-full "
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
variant="bordered"
/>
<p className="text-sm font-semibold">Deskripsi</p>
<Textarea
type="text"
id="title"
placeholder=""
label=""
value={file.description}
onValueChange={(e) =>
setValue(`rows.${index}.description`, e)
}
isReadOnly
labelPlacement="outside"
className="w-full "
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
variant="bordered"
/>
</div>
</div>
<Button
className=" border-none rounded-full"
variant="bordered"
color="danger"
onClick={() => handleDeleteFile(file?.id)}
>
<TimesIcon />
</Button>
</div>
)}
</Fragment>
) : null}
</Fragment>
))}
</div>
</Fragment>
)}
{isDetail && (
<div className="grid grid-cols-2 gap-2">
{detailfiles?.map((file: any, index: number) => (
<div
key={file.fileName + index}
className=" flex justify-between border p-3 rounded-md"
>
<div className="flex gap-3 grow">
<div className="file-preview">
{renderPreview(file, file.fileName)}
</div>
<div className="flex flex-col gap-1 grow">
<p className="text-sm font-semibold">Nama File</p>
<div className="flex flex-row gap-2 items-center">
<p className=" text-sm text-card-foreground">
{file.fileName}
</p>
<p className=" text-xs font-light text-muted-foreground">
{Math.round(file.size / 100) / 10 > 1000 ? (
<>
{(Math.round(file.size / 100) / 10000).toFixed(1)}
</>
) : (
<>{(Math.round(file.size / 100) / 10).toFixed(1)}</>
)}
{" kb"}
</p>
</div>
<p className="text-sm font-semibold">Judul</p>
<Input
type="text"
id="title"
placeholder=""
label=""
isReadOnly
value={file.title}
onValueChange={(e) => setValue(`rows.${index}.title`, e)}
labelPlacement="outside"
className="w-full "
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
variant="bordered"
/>
<p className="text-sm font-semibold">Deskripsi</p>
<Textarea
type="text"
id="title"
placeholder=""
label=""
value={file.description}
onValueChange={(e) =>
setValue(`rows.${index}.description`, e)
}
isReadOnly
labelPlacement="outside"
className="w-full "
classNames={{
inputWrapper: [
"border-1 rounded-lg",
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
],
}}
variant="bordered"
/>
</div>
</div>
{/* <Button
className=" border-none rounded-full"
variant="bordered"
color="danger"
onClick={() => handleRemoveFile(file)}
>
<TimesIcon />
</Button> */}
</div>
))}
</div>
)}
<div className="flex flex-row gap-3 mt-3">
{!isDetail && (
<Button color="primary" type="submit">

View File

@ -128,3 +128,23 @@ export const PptIcon = ({
/>
</svg>
);
export const FileIcon = ({
size,
height = 24,
width = 24,
fill = "currentColor",
...props
}: IconSvgProps) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size || width}
height={size || height}
{...props}
viewBox="0 0 15 15"
>
<path
fill="currentColor"
d="m10.5.5l.354-.354L10.707 0H10.5zm3 3h.5v-.207l-.146-.147zm-1 10.5h-10v1h10zM2 13.5v-12H1v12zM2.5 1h8V0h-8zM13 3.5v10h1v-10zM10.146.854l3 3l.708-.708l-3-3zM2.5 14a.5.5 0 0 1-.5-.5H1A1.5 1.5 0 0 0 2.5 15zm10 1a1.5 1.5 0 0 0 1.5-1.5h-1a.5.5 0 0 1-.5.5zM2 1.5a.5.5 0 0 1 .5-.5V0A1.5 1.5 0 0 0 1 1.5z"
/>
</svg>
);

View File

@ -56,3 +56,7 @@ export async function uploadMagazineFile(id: string, data: any) {
};
return await httpPost(`/magazine-files/${id}`, headers, data);
}
export async function deleteMagazineFiles(id: number) {
return await httpDeleteInterceptor(`magazine-files/${id}`);
}