file upload and store
This commit is contained in:
@@ -4,10 +4,12 @@ const path = require("path");
|
||||
const fs = require("fs");
|
||||
const multer = require("multer");
|
||||
const defineAttachment = require("../../models/attachments");
|
||||
const defineCaseAttachment = require("../../models/caseAttachments");
|
||||
const { DataTypes } = require("sequelize");
|
||||
|
||||
module.exports = function (sequelize) {
|
||||
const Attachment = defineAttachment(sequelize, DataTypes);
|
||||
const CaseAttachment = defineCaseAttachment(sequelize, DataTypes);
|
||||
|
||||
// Create uploads folder if it does not exist
|
||||
const uploadDir = path.join(__dirname, "../../public/uploads");
|
||||
@@ -45,7 +47,9 @@ module.exports = function (sequelize) {
|
||||
const upload = multer({ storage });
|
||||
|
||||
router.post("/", upload.array("files", 10), async (req, res) => {
|
||||
const t = await sequelize.transaction();
|
||||
try {
|
||||
const caseId = req.query.parentCaseId;
|
||||
const files = req.files;
|
||||
if (files.length === 0) {
|
||||
return res.status(400).json({ error: "No files uploaded" });
|
||||
@@ -58,10 +62,19 @@ module.exports = function (sequelize) {
|
||||
path: `${protocol}://${host}/uploads/${file.filename}`,
|
||||
}));
|
||||
|
||||
const newAttachments = await Attachment.bulkCreate(attachmentsData);
|
||||
const newAttachments = await Attachment.bulkCreate(attachmentsData, {
|
||||
transaction: t,
|
||||
});
|
||||
|
||||
const caseAttachmentsData = newAttachments.map((attachment) => ({
|
||||
caseId: caseId,
|
||||
attachmentId: attachment.id,
|
||||
}));
|
||||
await CaseAttachment.bulkCreate(caseAttachmentsData, { transaction: t });
|
||||
await t.commit();
|
||||
res.json(newAttachments);
|
||||
} catch (error) {
|
||||
await t.rollback();
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,18 +11,60 @@ export default function AttachmentsEditor({
|
||||
attachments = [],
|
||||
onAttachmentDelete,
|
||||
}: Props) {
|
||||
let images = [];
|
||||
let others = [];
|
||||
|
||||
attachments.forEach((attachment) => {
|
||||
let path = attachment.path;
|
||||
let extension = path.substring(path.lastIndexOf(".") + 1).toLowerCase();
|
||||
if (
|
||||
extension === "png" ||
|
||||
extension === "jpg" ||
|
||||
extension === "jpeg" ||
|
||||
extension === "gif" ||
|
||||
extension === "bmp" ||
|
||||
extension === "svg"
|
||||
) {
|
||||
images.push(attachment);
|
||||
} else {
|
||||
others.push(attachment);
|
||||
}
|
||||
});
|
||||
return (
|
||||
<>
|
||||
{attachments.map((attachment, index) => (
|
||||
{images.map((image, index) => (
|
||||
<div key={index} className="flex">
|
||||
<Image alt={attachment.title} src={attachment.path} className="object-cover h-40 w-40"/>
|
||||
<Image
|
||||
alt={image.title}
|
||||
src={image.path}
|
||||
className="object-cover h-40 w-40"
|
||||
/>
|
||||
<div className="mt-3 ms-1">
|
||||
<Tooltip content="Delete this image file" placement="left">
|
||||
<Button
|
||||
isIconOnly
|
||||
size="sm"
|
||||
className="bg-transparent rounded-full"
|
||||
onPress={() => onAttachmentDelete(image.id)}
|
||||
>
|
||||
<Trash size={16} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{others.map((file, index) => (
|
||||
<div key={index} className="flex">
|
||||
<div>{file.title}</div>
|
||||
<div>{file.path}</div>
|
||||
<div className="mt-3 ms-1">
|
||||
<Tooltip content="Delete this attachment file" placement="left">
|
||||
<Button
|
||||
isIconOnly
|
||||
size="sm"
|
||||
className="bg-transparent rounded-full"
|
||||
onPress={() => onAttachmentDelete(attachment.id)}
|
||||
onPress={() => onAttachmentDelete(file.id)}
|
||||
>
|
||||
<Trash size={16} />
|
||||
</Button>
|
||||
|
||||
@@ -245,15 +245,23 @@ export default function Page({
|
||||
});
|
||||
};
|
||||
|
||||
const handleFileUpload = async (event) => {
|
||||
const files = event.target.files;
|
||||
const handleDrop = (event) => {
|
||||
event.preventDefault();
|
||||
handleFileUpload(event.dataTransfer.files);
|
||||
};
|
||||
|
||||
const handleInput = (event) => {
|
||||
handleFileUpload(event.target.files);
|
||||
};
|
||||
|
||||
const handleFileUpload = async (files) => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
formData.append("files", files[i]);
|
||||
}
|
||||
|
||||
const url = `${apiServer}/attachments`;
|
||||
const url = `${apiServer}/attachments?parentCaseId=${params.caseId}`;
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
@@ -284,6 +292,21 @@ export default function Page({
|
||||
|
||||
return (
|
||||
<div className="p-5">
|
||||
<div className="mt-6">
|
||||
<Button
|
||||
color="primary"
|
||||
isLoading={isUpdating}
|
||||
onPress={async () => {
|
||||
setIsUpdating(true);
|
||||
await updateCase(testCase);
|
||||
setTimeout(() => {
|
||||
setIsUpdating(false);
|
||||
}, 1000);
|
||||
}}
|
||||
>
|
||||
{isUpdating ? "Updating..." : "Update"}
|
||||
</Button>
|
||||
</div>
|
||||
<h6>Basic</h6>
|
||||
<Input
|
||||
size="sm"
|
||||
@@ -458,7 +481,11 @@ export default function Page({
|
||||
attachments={testCase.Attachments}
|
||||
onAttachmentDelete={(id) => console.log(id)}
|
||||
/>
|
||||
<div className="flex items-center justify-center w-96 mt-3">
|
||||
<div
|
||||
className="flex items-center justify-center w-96 mt-3"
|
||||
onDrop={handleDrop}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
>
|
||||
<label
|
||||
htmlFor="dropzone-file"
|
||||
className="flex flex-col items-center justify-center w-full h-32 border-2 border-gray-200 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-bray-800 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:bg-gray-600"
|
||||
@@ -477,27 +504,11 @@ export default function Page({
|
||||
id="dropzone-file"
|
||||
type="file"
|
||||
className="hidden"
|
||||
onChange={handleFileUpload}
|
||||
onChange={handleInput}
|
||||
multiple
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="mt-6">
|
||||
<Button
|
||||
color="primary"
|
||||
isLoading={isUpdating}
|
||||
onPress={async () => {
|
||||
setIsUpdating(true);
|
||||
await updateCase(testCase);
|
||||
setTimeout(() => {
|
||||
setIsUpdating(false);
|
||||
}, 1000);
|
||||
}}
|
||||
>
|
||||
{isUpdating ? "Updating..." : "Update"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user