upload agent image action
This commit is contained in:
10
package-lock.json
generated
10
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
@@ -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>
|
||||
|
||||
42
src/app/api/upload_agent_image/route.ts
Normal file
42
src/app/api/upload_agent_image/route.ts
Normal 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 });
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user