diff --git a/package-lock.json b/package-lock.json
index e9896a3..dd9e91e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 596c593..cb25f19 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/public/sailor.png b/public/agents_images/sailor.png
similarity index 100%
rename from public/sailor.png
rename to public/agents_images/sailor.png
diff --git a/src/app/agents/page.tsx b/src/app/agents/page.tsx
index 36ecf9e..5674692 100644
--- a/src/app/agents/page.tsx
+++ b/src/app/agents/page.tsx
@@ -57,11 +57,11 @@ const AgentsPage = () => {
@@ -92,6 +92,9 @@ const AgentsPage = () => {
onUpdateAgent={() => {
refetch();
}}
+ onUploadImage={() => {
+ refetch();
+ }}
/>
diff --git a/src/app/api/upload_agent_image/route.ts b/src/app/api/upload_agent_image/route.ts
new file mode 100644
index 0000000..05842b5
--- /dev/null
+++ b/src/app/api/upload_agent_image/route.ts
@@ -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 });
+}
diff --git a/src/components/modals/agent_modal.tsx b/src/components/modals/agent_modal.tsx
index a1ba197..69c26ad 100644
--- a/src/components/modals/agent_modal.tsx
+++ b/src/components/modals/agent_modal.tsx
@@ -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();
+
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}
/>
+
+
+
{selectedImage && (
) : (
)}
diff --git a/src/components/modals/new_agent_modal.tsx b/src/components/modals/new_agent_modal.tsx
index 6fd2343..0a4325f 100644
--- a/src/components/modals/new_agent_modal.tsx
+++ b/src/components/modals/new_agent_modal.tsx
@@ -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: {
-
+
-
-
-
-
- {selectedImage && (
-

- )}
-