diff --git a/.env b/.env index 345a9b1..2e4ecf3 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -VITE_API_URL = http://localhost:3000 \ No newline at end of file +VITE_API_URL = http://localhost:3000 +VITE_API_TEST_URL = http://localhost:3001 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 01f6a05..885f5d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.7", "express-validator": "^7.2.1", + "idb": "^8.0.2", "jsonwebtoken": "^9.0.2", "react": "^19.0.0", "react-bootstrap": "^2.10.9", @@ -3038,6 +3039,12 @@ "node": ">= 0.4" } }, + "node_modules/idb": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/idb/-/idb-8.0.2.tgz", + "integrity": "sha512-CX70rYhx7GDDQzwwQMDwF6kDRQi5vVs6khHUumDrMecBylKkwvZ8HWvKV08AGb7VbpoGCWUQ4aHzNDgoUiOIUg==", + "license": "ISC" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -7088,6 +7095,11 @@ "function-bind": "^1.1.2" } }, + "idb": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/idb/-/idb-8.0.2.tgz", + "integrity": "sha512-CX70rYhx7GDDQzwwQMDwF6kDRQi5vVs6khHUumDrMecBylKkwvZ8HWvKV08AGb7VbpoGCWUQ4aHzNDgoUiOIUg==" + }, "ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", diff --git a/package.json b/package.json index d9f8607..cb5297d 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.7", "express-validator": "^7.2.1", + "idb": "^8.0.2", "jsonwebtoken": "^9.0.2", "react": "^19.0.0", "react-bootstrap": "^2.10.9", diff --git a/queueapp.zip b/queueapp.zip new file mode 100644 index 0000000..51ad225 Binary files /dev/null and b/queueapp.zip differ diff --git a/src/api/queueApi.js b/src/api/queueApi.js index 2ba5fac..3e7def6 100644 --- a/src/api/queueApi.js +++ b/src/api/queueApi.js @@ -24,7 +24,7 @@ export const updateQueueStatus = async (queueId, status) => { } }; -export const createQueue = async (customerData) => { +export const createTicketApi = async (customerData) => { try { const response = await axios.post(`${API_URL}/queues`, customerData); return response.data; diff --git a/src/components/Admin/AdminSidebar.jsx b/src/components/Admin/AdminSidebar.jsx index 2def27b..a818629 100644 --- a/src/components/Admin/AdminSidebar.jsx +++ b/src/components/Admin/AdminSidebar.jsx @@ -34,12 +34,12 @@ const AdminSidebar = () => { {/* Laporan Antrian */} - + {/* Pengaturan Layar Pengaturan Menu - + */} )} diff --git a/src/components/Admin/TestQueueActions.jsx b/src/components/Admin/TestQueueActions.jsx index bdafbc7..d23b295 100644 --- a/src/components/Admin/TestQueueActions.jsx +++ b/src/components/Admin/TestQueueActions.jsx @@ -1,7 +1,6 @@ - // FILE INI UNTUK TEST TAMPILAN DATA DENGAN API -import { fetchQueues, updateQueueStatus } from "../../api/queueApi"; +import { fetchQueues, updateQueueStatus, createTicketApi } from "../../api/queueApi"; export const getProcessedQueues = async () => { const data = await fetchQueues(); @@ -28,3 +27,7 @@ export const getProcessedQueues = async () => { export const changeQueueStatus = async (queueId, newStatus) => { return await updateQueueStatus(queueId, newStatus); }; + +export const createTicket = async (ticketData) => { + return await createTicketApi(ticketData); +}; diff --git a/src/components/Admin/TestQueueTable.jsx b/src/components/Admin/TestQueueTable.jsx index 2f71cc6..786c31a 100644 --- a/src/components/Admin/TestQueueTable.jsx +++ b/src/components/Admin/TestQueueTable.jsx @@ -45,7 +45,7 @@ const TestQueueTable = () => { }; return ( - + List Antrian @@ -85,7 +85,7 @@ const TestQueueTable = () => { {new Date(queue.createdAt).toLocaleString()} - + {queue.status !== "In Progress" && queue.status !== "Completed" && ( { const [queues, setQueues] = useState([]); + const [currentTime, setCurrentTime] = useState(new Date()); useEffect(() => { const fetchData = async () => { @@ -25,21 +24,81 @@ const TestQueueDisplay = () => { return () => clearInterval(interval); }, []); + useEffect(() => { + const interval = setInterval(() => { + setCurrentTime(new Date()); + }, 1000); + + return () => clearInterval(interval); + }, []); + return ( - - Layar Antrian - {queues.length > 0 ? ( - - {queues[0].id} - {queues[0].customerName} - {queues[0].serviceName} + + + + + + Pandawa24Jam + CS: 081234567891 + + + {currentTime.toLocaleTimeString()} + + + {queues.length > 0 ? ( + + {queues[0].id} + {queues[0].customerName} + {queues[0].serviceName} + + ) : ( + Tidak ada antrian aktif + )} + + + + + + + + + + + + + List Layanan antrian + + + + {Array.from(new Set(queues.map((queue) => queue.serviceName))).map((serviceName, index) => ( + + {serviceName} + {queues + .filter((q) => q.serviceName === serviceName) + .sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt)) + .map((q, i) => ( + {q.serviceId} - {q.id} - {new Date(q.createdAt).toLocaleTimeString()} + ))} + + ))} + - ) : ( - Tidak ada antrian aktif - )} + + ); }; export default TestQueueDisplay; - diff --git a/src/components/Display/TestServiceSelection.jsx b/src/components/Display/TestServiceSelection.jsx index 1322dd7..b3e12d8 100644 --- a/src/components/Display/TestServiceSelection.jsx +++ b/src/components/Display/TestServiceSelection.jsx @@ -1,34 +1,155 @@ - -// FILE INI UNTUK TEST TAMPILAN DATA DENGAN API - import { useEffect, useState } from "react"; -import { getProcessedQueues } from "../Admin/TestQueueActions"; -import { Container, Card, Row, Col, Table } from "react-bootstrap"; +import { getProcessedQueues, createTicket } from "../Admin/TestQueueActions"; +import { Container, Card, Row, Col, Form, Button, Carousel } from "react-bootstrap"; +import { FaPrint, FaPalette, FaFileAlt, FaUndo, FaTruck, FaUser } from 'react-icons/fa'; + +const services = [ + { id: "j0001", name: "Siap Print", icon: }, + { id: "j0002", name: "Design/Edit/Kreatif", icon: }, + { id: "j0003", name: "FotoCopy/Jilid/Scan", icon: }, + { id: "j0004", name: "Retur Penjualan", icon: }, + { id: "j0005", name: "Online Pickup", icon: }, + { id: "j0006", name: "Tamu", icon: } +]; const ServiceSelection = () => { + const [selectedService, setSelectedService] = useState(null); + const [name, setName] = useState(""); + const [phone, setPhone] = useState(""); + const [ticket, setTicket] = useState(null); + const [enableForm, setEnableForm] = useState(false); const [queues, setQueues] = useState([]); useEffect(() => { + if (selectedService && !enableForm) { + generateTicket(); + } getProcessedQueues().then(setQueues); - }, []); + }, [selectedService]); + + const handleServiceSelect = (serviceId) => { + setSelectedService(services.find(service => service.id === serviceId)); + }; + + const generateTicket = async () => { + if (selectedService) { + const queueNumber = `${selectedService.id}-${Math.floor(1000 + Math.random() * 9000)}`; + const newTicket = { + number: queueNumber, + serviceId: selectedService.id, + service: selectedService.name, + name: enableForm ? name : "-", + phone: enableForm ? phone : "-", + }; + + try { + const response = await createTicket(newTicket); + setTicket(response.data); + } catch (error) { + console.error(error); + } + } + }; + + const handleSubmit = (e) => { + e.preventDefault(); + generateTicket(); + }; return ( - - - {queues.map((operator) => ( - - {operator.operatorName} - - {operator.queues.map((queue) => ( - {queue.serviceName} - ))} - - - ))} - + + {!ticket ? ( + + + + {services.map(service => ( + + handleServiceSelect(service.id)} + > + + {service.icon} + + {service.name} + + + + + ))} + + + + + + + Data Diri + setEnableForm(!enableForm)} + style={{ transform: "scale(1.5)" }} + /> + + Beri tanda centang untuk mengisi form + + + + + Nama + setName(e.target.value)} + disabled={!enableForm} + className={enableForm ? "bg-light text-dark" : "bg-dark text-muted"} + /> + + + No Telepon + setPhone(e.target.value)} + disabled={!enableForm} + className={enableForm ? "bg-light text-dark" : "bg-dark text-muted"} + /> + + + Submit + + + + + + + {["c1.png", "c2.jpg", "c3.jpg"].map((image, index) => ( + + + + ))} + + + + + ) : ( + + + + Tiket Antrian + + {ticket.number} + Layanan : {ticket.service} + Nama : {ticket.name} + No Telepon : {ticket.phone} + window.print()}>Cetak Tiket + + + + )} ); }; export default ServiceSelection; - diff --git a/src/pages/Admin/QueueListPage.jsx b/src/pages/Admin/QueueListPage.jsx index 7360d7a..2cd9e5f 100644 --- a/src/pages/Admin/QueueListPage.jsx +++ b/src/pages/Admin/QueueListPage.jsx @@ -1,14 +1,16 @@ import TestQueueTable from "../../components/Admin/TestQueueTable"; -import QueueTable from "../../components/Admin/QueueTable"; +// import QueueTable from "../../components/Admin/QueueTable"; +// import TestComponent from "../../components/test"; const QueueListPage = () => { return ( - {/* INI ADALAH UNTUK TEST DATA DENGAN API */} - - + + {/* Atas Data dengan API bawah Data Static */} + {/* + */} ); }; diff --git a/src/pages/Display/QueueDisplayPage.jsx b/src/pages/Display/QueueDisplayPage.jsx index 1d485fc..34ecc90 100644 --- a/src/pages/Display/QueueDisplayPage.jsx +++ b/src/pages/Display/QueueDisplayPage.jsx @@ -1,11 +1,12 @@ import TestQueueDisplay from "../../components/Display/TestQueueDisplay" -import QueueDisplay from "../../components/Display/QueueDisplay" +// import QueueDisplay from "../../components/Display/QueueDisplay" const QueueDisplayPage = () => { return ( <> - {/* INI ADALAH UNTUK TEST DATA DENGAN API */} - + + {/* Atas Data dengan API bawah Data Static */} + {/* */} > ) } diff --git a/src/pages/Display/QueueMenuPage.jsx b/src/pages/Display/QueueMenuPage.jsx index c4b7385..3535c59 100644 --- a/src/pages/Display/QueueMenuPage.jsx +++ b/src/pages/Display/QueueMenuPage.jsx @@ -1,11 +1,12 @@ import TestServiceSelection from "../../components/Display/TestServiceSelection" -import ServiceSelection from "../../components/Display/ServiceSelection" +// import ServiceSelection from "../../components/Display/ServiceSelection" const QueueMenuPage = () => { return ( <> - {/* INI ADALAH UNTUK TEST DATA DENGAN API */} - + + {/* Atas Data dengan API bawah Data Static */} + {/* */} > ) } diff --git a/src/routes/AppRoutes.jsx b/src/routes/AppRoutes.jsx index 4bc503b..cd00bb7 100644 --- a/src/routes/AppRoutes.jsx +++ b/src/routes/AppRoutes.jsx @@ -13,7 +13,7 @@ const AppRoutes = () => { {/* Redirect default ke queue-list */} - } /> + } /> {/* Rute untuk Admin */} }>
{queues[0].serviceName}
CS: 081234567891
Tidak ada antrian aktif
+ Beri tanda centang untuk mengisi form +