diff --git a/public/photos/95753337.jpg b/public/photos/95753337.jpg
deleted file mode 100644
index 67b6222..0000000
Binary files a/public/photos/95753337.jpg and /dev/null differ
diff --git a/public/photos/95753393.jpg b/public/photos/95753393.jpg
deleted file mode 100644
index 67b6222..0000000
Binary files a/public/photos/95753393.jpg and /dev/null differ
diff --git a/src/components/screens/dashboard/Dashboard.tsx b/src/components/screens/dashboard/Dashboard.tsx
index 9ada980..6baf5f1 100644
--- a/src/components/screens/dashboard/Dashboard.tsx
+++ b/src/components/screens/dashboard/Dashboard.tsx
@@ -1,7 +1,7 @@
import { FC, useEffect, useState } from 'react';
import Layout from '@/components/layout/Layout';
-import { Box, Button, Center, Container, Divider, Flex, IconButton, Text, VStack } from '@chakra-ui/react';
-import { DeleteIcon } from '@chakra-ui/icons';
+import { Box, Button, Center, Container, Divider, Flex, IconButton, Input, InputGroup, InputRightAddon, Text, VStack, useClipboard } from '@chakra-ui/react';
+import { DeleteIcon, CopyIcon, CheckIcon } from '@chakra-ui/icons';
import { KeyService } from "@/service/key.service";
const Dashboard: FC = () => {
@@ -38,11 +38,11 @@ const Dashboard: FC = () => {
-
-
+
+
{apiKeys.map((apiKey, index) => (
-
- {apiKey}
+
+
}
@@ -59,4 +59,24 @@ const Dashboard: FC = () => {
);
};
+
+const InputWithClipboard: FC<{ apiKey: string }> = ({ apiKey }) => {
+ const { onCopy, hasCopied } = useClipboard(apiKey);
+
+ return (
+
+
+
+ : }
+ aria-label={hasCopied ? "Copied" : "Copy"}
+ />
+
+
+ );
+};
+
+
export default Dashboard;
diff --git a/src/components/ui/wagon/WagonItem.tsx b/src/components/ui/wagon/WagonItem.tsx
index cd5e22b..5cb8830 100644
--- a/src/components/ui/wagon/WagonItem.tsx
+++ b/src/components/ui/wagon/WagonItem.tsx
@@ -1,6 +1,6 @@
import { FC, useRef, useState } from "react";
import { IWagonDataSingle } from "@/interfaces/wagon.interface";
-import { Box, Button, Center, Flex, Link, Text, useToast, VStack } from "@chakra-ui/react";
+import { Box, Button, Center, Flex, Link, Text, useToast, VStack, useColorMode, useColorModeValue } from "@chakra-ui/react";
import { PhotoService } from "@/service/photo.service";
import QRCode from "qrcode.react";
import Barcode from "react-barcode";
@@ -10,6 +10,10 @@ export const WagonItem: FC = ({ Wagon }) => {
const toast = useToast();
const [showQRCode, setShowQRCode] = useState(false);
const [showBarcode, setShowBarcode] = useState(false);
+ const { colorMode } = useColorMode();
+ const bgColor = useColorModeValue('#FFFFFF', '#1a202c');
+ const lineColor = useColorModeValue('#000000', '#FFFFFF');
+
const handleFileInputChange = () => {
if (fileInputRef.current) {
@@ -92,12 +96,12 @@ export const WagonItem: FC = ({ Wagon }) => {
{showQRCode && (
-
+
)}
{showBarcode && (
-
+
)}
diff --git a/src/enums/httpMethod.enum.ts b/src/enums/httpMethod.enum.ts
new file mode 100644
index 0000000..9d14372
--- /dev/null
+++ b/src/enums/httpMethod.enum.ts
@@ -0,0 +1,11 @@
+export enum HttpMethod {
+ GET = "GET",
+ POST = "POST",
+ PUT = "PUT",
+ DELETE = "DELETE",
+ HEAD = "HEAD",
+ CONNECT = "CONNECT",
+ OPTIONS = "OPTIONS",
+ TRACE = "TRACE",
+ PATCH = "PATCH",
+}
diff --git a/src/interfaces/middleware.interface.ts b/src/interfaces/middleware.interface.ts
new file mode 100644
index 0000000..218894b
--- /dev/null
+++ b/src/interfaces/middleware.interface.ts
@@ -0,0 +1,6 @@
+import { NextApiRequest, NextApiResponse } from 'next';
+
+export interface IMiddlewareOptions {
+ req: NextApiRequest;
+ res: NextApiResponse;
+}
diff --git a/src/pages/api/keys.ts b/src/pages/api/keys.ts
index 30d7f1f..f6abb61 100644
--- a/src/pages/api/keys.ts
+++ b/src/pages/api/keys.ts
@@ -1,34 +1,67 @@
import { NextApiRequest, NextApiResponse } from 'next';
import { v4 as uuidv4 } from 'uuid';
import { createClient } from '@node-redis/client';
+import { HttpMethod } from '@/enums/httpMethod.enum';
+import { IMiddlewareOptions } from '@/interfaces/middleware.interface';
+import { Middlewares } from '@/types/middleware.type';
const client = createClient();
const redisKey = 'apiKeys';
+const middlewares: Middlewares = {
+ [HttpMethod.GET]: getKeys,
+ [HttpMethod.POST]: postKey,
+ [HttpMethod.DELETE]: deleteKey,
+}
+
+
+
+async function getKeys(options: IMiddlewareOptions) {
+ const { res } = options;
+ const elements = await client.sMembers(redisKey);
+ res.status(200).json(elements);
+}
+
+async function postKey(options: IMiddlewareOptions) {
+ const { res } = options;
+ await client.sAdd(redisKey, uuidv4());
+ res.status(200).end();
+}
+
+async function deleteKey(options: IMiddlewareOptions) {
+ const { res, req } = options;
+ const { apiKey } = req.query;
+ if (typeof apiKey === 'string') {
+ await client.sRem(redisKey, apiKey);
+ res.status(200).end();
+ } else {
+ res.status(400).json({ message: 'Invalid request' });
+ }
+}
+
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!client.isOpen) {
await client.connect();
}
- if (req.method === 'POST') {
- await client.sAdd(redisKey, uuidv4());
- res.status(200).end();
+ const method = req.method as HttpMethod;
- } else if (req.method === 'GET') {
- const elements = await client.sMembers(redisKey);
- res.status(200).json(elements);
- } else if (req.method === 'DELETE') {
- const { apiKey } = req.query;
- if (typeof apiKey === 'string') {
- await client.sRem(redisKey, apiKey);
- res.status(200).end();
-
- } else {
- res.status(400).json({ message: 'Invalid request' });
- }
- } else {
+ if (!Object.keys(middlewares).includes(method)) {
res.setHeader('Allow', ['POST', 'GET', 'DELETE']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
+
+ const middleware = middlewares[method];
+
+ if (!middleware) {
+ return res.status(500).end()
+ }
+
+ try {
+ await middleware({ req, res });
+ } catch (error) {
+ console.error(JSON.stringify(error));
+ return res.status(500).end();
+ }
}
diff --git a/src/pages/api/photo.ts b/src/pages/api/photo.ts
index af6142b..5478aa0 100644
--- a/src/pages/api/photo.ts
+++ b/src/pages/api/photo.ts
@@ -1,34 +1,38 @@
-import { NextApiHandler, NextApiRequest } from "next";
+import { NextApiRequest, NextApiResponse } from "next";
import formidable from "formidable";
import path from "path";
import fs from "fs/promises";
+import { HttpMethod } from '@/enums/httpMethod.enum';
+import { IMiddlewareOptions } from '@/interfaces/middleware.interface';
+import { Middlewares } from '@/types/middleware.type';
-export const config = {
- api: {
- bodyParser: false,
- },
-};
-const readFile = (
+const middlewares: Middlewares = {
+ [HttpMethod.POST]: postPhoto,
+ [HttpMethod.DELETE]: deletePhoto,
+}
+
+
+const readFile = async (
req: NextApiRequest,
saveLocally?: boolean,
): Promise<{ fields: formidable.Fields; files: formidable.Files }> => {
- const options: formidable.Options = {};
+ const formidableOptions: formidable.Options = {};
if (saveLocally) {
- options.uploadDir = path.join(process.cwd(), "/public/photos");
- options.filename = () => {
+ formidableOptions.uploadDir = path.join(process.cwd(), "/public/photos");
+ formidableOptions.filename = () => {
return `${req.query.VagonNumber as string}.jpg`;
};
}
- options.maxFileSize = 4000 * 1024 * 1024;
- const form = formidable(options);
+ formidableOptions.maxFileSize = 4000 * 1024 * 1024;
+ const form = formidable(formidableOptions);
return new Promise((resolve, reject) => {
form.parse(req, (err, fields, files) => {
if (err) reject(err);
resolve({ fields, files });
});
});
-};
+}
const deleteFile = async (req: NextApiRequest) => {
const { VagonNumber } = req.query;
@@ -38,29 +42,44 @@ const deleteFile = async (req: NextApiRequest) => {
} catch (error) {
throw new Error(`Error deleting file: ${error}`);
}
-};
+}
+
+
+async function postPhoto(options: IMiddlewareOptions) {
+ const { res, req } = options;
+ try {
+ await fs.readdir(path.join(process.cwd() + "/public", "/photos"));
+ } catch (error) {
+ await fs.mkdir(path.join(process.cwd() + "/public", "/photos"));
+ }
+ await readFile(req, true);
+ res.json({ done: "ok" });
+}
-const handler: NextApiHandler = async (req, res) => {
- const { method } = req;
+async function deletePhoto(options: IMiddlewareOptions) {
+ const { res, req } = options;
+ await deleteFile(req);
+ res.status(200).json({ message: "File deleted successfully" });
+}
- if (method === "DELETE") {
- try {
- await deleteFile(req);
- res.status(200).json({ message: "File deleted successfully" });
- } catch (error) {
- res.status(500).json({ message: error });
- }
- } else if (method === "POST") {
- try {
- await fs.readdir(path.join(process.cwd() + "/public", "/photos"));
- } catch (error) {
- await fs.mkdir(path.join(process.cwd() + "/public", "/photos"));
- }
- await readFile(req, true);
- res.json({ done: "ok" });
- } else {
- res.status(405).json({ message: "Method not supported" });
+
+export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ const method = req.method as HttpMethod;
+ if (!Object.keys(middlewares).includes(method)) {
+ res.setHeader('Allow', ['POST', 'GET', 'DELETE']);
+ res.status(405).end(`Method ${req.method} Not Allowed`);
+ }
+
+ const middleware = middlewares[method];
+
+ if (!middleware) {
+ return res.status(500).end()
}
-};
-export default handler;
+ try {
+ await middleware({ req, res });
+ } catch (error) {
+ console.error(JSON.stringify(error));
+ return res.status(500).end();
+ }
+}
diff --git a/src/pages/api/wagons.ts b/src/pages/api/wagons/[VagonNumber].ts
similarity index 85%
rename from src/pages/api/wagons.ts
rename to src/pages/api/wagons/[VagonNumber].ts
index 46e2868..157a471 100644
--- a/src/pages/api/wagons.ts
+++ b/src/pages/api/wagons/[VagonNumber].ts
@@ -1,6 +1,5 @@
import { NextApiRequest, NextApiResponse } from 'next';
import { WagonService } from '@/service/wagon.service';
-import { KeyService } from "@/service/key.service";
import { createClient } from "@node-redis/client";
@@ -24,11 +23,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const wagonNumber = query.VagonNumber as string;
- if (!wagonNumber) {
- const wagons = await WagonService.getAll();
- return res.status(200).json(wagons);
- }
-
const wagon = await WagonService.getOne(wagonNumber);
if (!wagon) {
diff --git a/src/pages/api/wagons/index.ts b/src/pages/api/wagons/index.ts
new file mode 100644
index 0000000..020f67f
--- /dev/null
+++ b/src/pages/api/wagons/index.ts
@@ -0,0 +1,31 @@
+import { NextApiRequest, NextApiResponse } from 'next';
+import { WagonService } from '@/service/wagon.service';
+import { createClient } from "@node-redis/client";
+
+
+export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ try {
+ const { query } = req;
+ const apiKey = query.apiKey as string;
+ const redisKey = 'apiKeys';
+
+ const client = createClient();
+
+ if (!client.isOpen) {
+ await client.connect();
+ }
+
+ const validation = await client.sIsMember(redisKey, apiKey);
+
+ if (!apiKey || !validation) {
+ return res.status(401).json({ error: 'Invalid API key' });
+ }
+
+ const wagons = await WagonService.getAll();
+ return res.status(200).json(wagons);
+
+ } catch (error) {
+ console.error('Error retrieving wagon:', error);
+ return res.status(500).json({ error: 'Internal server error' });
+ }
+}
diff --git a/src/types/middleware.type.ts b/src/types/middleware.type.ts
new file mode 100644
index 0000000..cb98f7a
--- /dev/null
+++ b/src/types/middleware.type.ts
@@ -0,0 +1,6 @@
+import { HttpMethod } from "@/enums/httpMethod.enum";
+import { IMiddlewareOptions } from "@/interfaces/middleware.interface";
+
+export type Middlewares = Partial<
+ Record any>
+>