upload agent image action

This commit is contained in:
Eng. Elias
2024-03-02 01:47:33 +04:00
parent 2316c57340
commit 0b164fd510
7 changed files with 140 additions and 23 deletions

10
package-lock.json generated
View File

@@ -23,7 +23,8 @@
"sweetalert2": "^11.10.5",
"sweetalert2-react-content": "^5.0.7",
"tw-elements": "^1.1.0",
"tw-elements-react": "^1.0.0-alpha2"
"tw-elements-react": "^1.0.0-alpha2",
"uuid": "^9.0.1"
},
"devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.1.0",
@@ -31,6 +32,7 @@
"@types/node": "^20.11.19",
"@types/react": "^18",
"@types/react-dom": "^18",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^6.7.3",
"@typescript-eslint/parser": "^6.7.3",
"autoprefixer": "^10.0.1",
@@ -1847,6 +1849,12 @@
"@types/node": "*"
}
},
"node_modules/@types/uuid": {
"version": "9.0.8",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
"integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz",

View File

@@ -25,7 +25,8 @@
"sweetalert2": "^11.10.5",
"sweetalert2-react-content": "^5.0.7",
"tw-elements": "^1.1.0",
"tw-elements-react": "^1.0.0-alpha2"
"tw-elements-react": "^1.0.0-alpha2",
"uuid": "^9.0.1"
},
"devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.1.0",
@@ -33,6 +34,7 @@
"@types/node": "^20.11.19",
"@types/react": "^18",
"@types/react-dom": "^18",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^6.7.3",
"@typescript-eslint/parser": "^6.7.3",
"autoprefixer": "^10.0.1",

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -57,11 +57,11 @@ const AgentsPage = () => {
<div
className={`flex flex-col ${
i % 2 == 0 ? "lg:flex-row" : "lg:flex-row-reverse"
} rounded overflow-hidden h-auto min-h-40 border`}
} rounded overflow-hidden h-auto min-h-52 border`}
>
<img
className="block h-auto max-w-72 w-full lg:w-48 flex-none bg-cover"
src={agent.image ?? "/sailor.png"}
className="block max-w-72 w-full lg:w-48 flex-none bg-cover"
src={agent.image ?? "/agents_images/sailor.png"}
alt="Agent"
/>
<div className="rounded-b lg:rounded-b-none lg:rounded-r p-4 flex flex-col leading-normal w-100">
@@ -92,6 +92,9 @@ const AgentsPage = () => {
onUpdateAgent={() => {
refetch();
}}
onUploadImage={() => {
refetch();
}}
/>
</div>
</div>

View File

@@ -0,0 +1,42 @@
import path from "path";
import fs from "fs";
import { v4 as uuidv4 } from "uuid";
import { NextRequest, NextResponse } from "next/server";
import prisma from "@/utils/prisma";
export async function POST(request: NextRequest) {
const data = await request.formData();
const file: File | null = data.get("image") as unknown as File;
if (!file) {
return NextResponse.json({
success: false,
error: "There is no file or the file is corrupted",
});
}
// With the file data in the buffer, you can do whatever you want with it.
// For this, we'll just write it to the filesystem in a new location
const bytes = await file.arrayBuffer();
const buffer = Buffer.from(bytes);
const filename = `${uuidv4()}-${new Date().getTime()}-${file.name}`;
const storagePath = path.join(
process.cwd(),
"public",
"agents_images",
filename
);
fs.writeFileSync(storagePath, buffer, { flag: "w" });
const imageURL = `/agents_images/${filename}`;
await prisma.agent.update({
// @ts-ignore
where: { id: Number.parseInt(data.get("agent_id")) },
data: {
image: imageURL,
},
});
return NextResponse.json({ success: true, url: imageURL });
}

View File

@@ -29,8 +29,15 @@ export default function AgentModal(props: {
showModal: boolean;
setShowModal: Function;
onUpdateAgent: Function;
onUploadImage: Function;
}): JSX.Element {
const { agent, showModal, setShowModal, onUpdateAgent = () => {} } = props;
const {
agent,
showModal,
setShowModal,
onUpdateAgent = () => {},
onUploadImage = () => {},
} = props;
const [isEdit, setEdit] = useState(false);
@@ -40,6 +47,8 @@ export default function AgentModal(props: {
setTempAgent(agent);
}, [agent]);
const [imageFile, setImageFile] = useState<Blob>();
const [selectedImage, setSelectedImage] = useState<
string | ArrayBuffer | null
>(null);
@@ -53,10 +62,63 @@ export default function AgentModal(props: {
};
if (file) {
setImageFile(file);
reader.readAsDataURL(file);
}
};
const [uploadLoading, setUploadLoading] = useState(false);
const handleUploadImage = async () => {
setUploadLoading(true);
if (imageFile) {
const body = new FormData();
body.append("agent_id", agent.id as string);
body.append("image", imageFile);
const response = await fetch("/api/upload_agent_image", {
method: "POST",
body,
});
if (response.ok) {
response
.json()
.then((data) => {
if (data.success) {
setTempAgent({ ...tempAgent, image: data.url });
ReactSwal.fire({
title: "Finished",
text: "Agent image updated successfully",
icon: "success",
});
onUploadImage();
} else {
ReactSwal.fire({
title: "Error",
text: data.error,
icon: "error",
});
}
})
.catch((error) => {
ReactSwal.fire({
title: "Error",
text: error,
icon: "error",
});
})
.finally(() => {
setUploadLoading(false);
});
} else {
ReactSwal.fire({
title: "Error",
text: "An error occurred, try again.",
icon: "error",
});
setUploadLoading(false);
}
}
};
const [updateAgent] = useMutation(UPDATE_AGENT);
const [updateAgentLoading, setUpdateAgentLoading] = useState(false);
@@ -228,6 +290,20 @@ export default function AgentModal(props: {
accept="image/*"
onChange={handleImageChange}
/>
<div className="text-center py-1">
<Button
onClick={() => {
handleUploadImage();
}}
loading={uploadLoading}
disabled={uploadLoading || !selectedImage}
color="blue"
className="mx-auto"
placeholder={undefined}
>
Upload
</Button>
</div>
{selectedImage && (
<img
// @ts-ignore
@@ -239,8 +315,8 @@ export default function AgentModal(props: {
</>
) : (
<img
src={agent?.image ?? "/sailor.png"}
alt="Software Engineer"
src={tempAgent?.image ?? "/agents_images/sailor.png"}
alt="Agent Image"
className="w-7/12 mx-auto rounded-lg"
/>
)}

View File

@@ -15,7 +15,6 @@ import {
TESelect,
TETextarea,
} from "tw-elements-react";
import TWFileInput from "../inputs/file";
import { Button, Switch } from "@material-tailwind/react";
import { useMutation } from "@apollo/client";
import { CREATE_AGENT } from "@/utils/graphql_queries";
@@ -93,7 +92,7 @@ function NewAgentModal(props: {
</TEModalHeader>
<TEModalBody>
<div className="sm:flex">
<div className="sm:w-1/2">
<div className="sm:w-1/2 mx-auto">
<div className="mb-4">
<label className="font-bold text-lg">Role:</label>
<TEInput
@@ -181,19 +180,6 @@ function NewAgentModal(props: {
/>
</div>
</div>
<div className="m-4 sm:w-1/2">
<label className="font-bold mx-2">Agent Image: </label>
<TWFileInput accept="image/*" onChange={handleImageChange} />
{selectedImage && (
<img
// @ts-ignore
src={selectedImage}
alt="Agent Image"
className="mx-auto my-3 max-w-72 h-auto"
/>
)}
</div>
</div>
</TEModalBody>