diff --git a/.env b/.env
index 223030e..345a9b1 100644
--- a/.env
+++ b/.env
@@ -1 +1 @@
-VITE_API_URL = http://localhost:3000/queue
\ No newline at end of file
+VITE_API_URL = http://localhost:3000
\ No newline at end of file
diff --git a/db.json b/db.json
index 25e1eb3..983ca76 100644
--- a/db.json
+++ b/db.json
@@ -1,16 +1,115 @@
{
- "queue": [
- { "id": 1, "number": "P001", "counter": 1, "service": "Siap Print", "customer": { "name": "John Doe", "phone": "081234567890" }, "startTime": "2025-02-26T08:00:00", "endTime": null, "status": "waiting" },
- { "id": 2, "number": "D001", "counter": 2, "service": "Design", "customer": { "name": "Jane Smith", "phone": "081298765432" }, "startTime": "2025-02-26T08:05:00", "endTime": null, "status": "called" },
- { "id": 3, "number": "F001", "counter": 3, "service": "Fotocopy", "customer": { "name": "Emily Davis", "phone": "081678901234" }, "startTime": "2025-02-26T08:30:00", "endTime": "2025-02-26T08:45:00", "status": "completed" },
- { "id": 4, "number": "R001", "counter": 4, "service": "Retur Barang", "customer": { "name": "Sophia Lee", "phone": "081789012345" }, "startTime": "2025-02-26T08:35:00", "endTime": null, "status": "called" },
- { "id": 5, "number": "O001", "counter": 5, "service": "Online Pickup", "customer": { "name": "Daniel Martinez", "phone": "081890123456" }, "startTime": "2025-02-26T08:40:00", "endTime": null, "status": "waiting" },
- { "id": 6, "number": "T001", "counter": 6, "service": "Tamu", "customer": { "name": "Henry Adams", "phone": "081901234567" }, "startTime": "2025-02-26T08:50:00", "endTime": null, "status": "waiting" },
- { "id": 7, "number": "P002", "counter": 1, "service": "Siap Print", "customer": { "name": "James Thompson", "phone": "081234567891" }, "startTime": "2025-02-26T09:00:00", "endTime": null, "status": "waiting" },
- { "id": 8, "number": "D002", "counter": 2, "service": "Design", "customer": { "name": "Benjamin Clark", "phone": "081456789013" }, "startTime": "2025-02-26T09:10:00", "endTime": "2025-02-26T09:20:00", "status": "completed" },
- { "id": 9, "number": "F002", "counter": 3, "service": "Fotocopy", "customer": { "name": "Olivia Brown", "phone": "081567890124" }, "startTime": "2025-02-26T09:15:00", "endTime": null, "status": "waiting" },
- { "id": 10, "number": "R002", "counter": 4, "service": "Retur Barang", "customer": { "name": "William White", "phone": "081678901235" }, "startTime": "2025-02-26T09:20:00", "endTime": null, "status": "called" },
- { "id": 11, "number": "O002", "counter": 5, "service": "Online Pickup", "customer": { "name": "Sophia Harris", "phone": "081789012346" }, "startTime": "2025-02-26T09:25:00", "endTime": null, "status": "waiting" },
- { "id": 12, "number": "T002", "counter": 6, "service": "Tamu", "customer": { "name": "Alexander Nelson", "phone": "081890123457" }, "startTime": "2025-02-26T09:30:00", "endTime": null, "status": "waiting" }
+ "operators": [
+ {
+ "id": "O001",
+ "name": "Rina Wijaya",
+ "email": "rina@example.com",
+ "queues": [
+ {
+ "queue_id": "Q12345",
+ "customer": {
+ "id": "C001",
+ "name": "Budi Santoso",
+ "phone": "+628123456789",
+ "email": "budi@example.com"
+ },
+ "service": {
+ "id": "J0001",
+ "name": "siap_print"
+ },
+ "status": "In Progress",
+ "created_at": "2025-02-27T08:30:00Z"
+ },
+ {
+ "queue_id": "Q12346",
+ "customer": {
+ "id": "C002",
+ "name": "Siti Aminah",
+ "phone": "+628987654321",
+ "email": "siti@example.com"
+ },
+ "service": {
+ "id": "J0001",
+ "name": "siap_print"
+ },
+ "status": "Waiting",
+ "created_at": "2025-02-27T09:00:00Z"
+ }
+ ]
+ },
+ {
+ "id": "O002",
+ "name": "Doni Saputra",
+ "email": "doni@example.com",
+ "queues": [
+ {
+ "queue_id": "Q12347",
+ "customer": {
+ "id": "C003",
+ "name": "Ahmad Fauzi",
+ "phone": "+6285566778899",
+ "email": "ahmad@example.com"
+ },
+ "service": {
+ "id": "J0002",
+ "name": "design"
+ },
+ "status": "Completed",
+ "created_at": "2025-02-27T09:30:00Z"
+ },
+ {
+ "queue_id": "Q12348",
+ "customer": {
+ "id": "C004",
+ "name": "Lina Kusuma",
+ "phone": "+6289988776655",
+ "email": "lina@example.com"
+ },
+ "service": {
+ "id": "J0003",
+ "name": "fotocopy"
+ },
+ "status": "In Progress",
+ "created_at": "2025-02-27T10:00:00Z"
+ }
+ ]
+ },
+ {
+ "id": "O003",
+ "name": "Sari Ningsih",
+ "email": "sari@example.com",
+ "queues": [
+ {
+ "queue_id": "Q12349",
+ "customer": {
+ "id": "j000",
+ "name": "Rudi Hartono",
+ "phone": "+6287711223344",
+ "email": "rudi@example.com"
+ },
+ "service": {
+ "id": "J0002",
+ "name": "design"
+ },
+ "status": "Waiting",
+ "created_at": "2025-02-27T10:30:00Z"
+ },
+ {
+ "queue_id": "Q12350",
+ "customer": {
+ "id": "C006",
+ "name": "Dewi Anggraini",
+ "phone": "+6286677889900",
+ "email": "dewi@example.com"
+ },
+ "service": {
+ "id": "J0001",
+ "name": "siap_print"
+ },
+ "status": "Completed",
+ "created_at": "2025-02-27T11:00:00Z"
+ }
+ ]
+ }
]
}
diff --git a/package-lock.json b/package-lock.json
index a1b3cf0..01f6a05 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "0.0.0",
"dependencies": {
"@reduxjs/toolkit": "^2.6.0",
- "axios": "^1.7.9",
+ "axios": "^1.8.1",
"bcryptjs": "^3.0.2",
"bootstrap": "^5.3.3",
"cors": "^2.8.5",
@@ -1772,9 +1772,9 @@
}
},
"node_modules/axios": {
- "version": "1.7.9",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
- "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.1.tgz",
+ "integrity": "sha512-NN+fvwH/kV01dYUQ3PTOZns4LWtWhOFCAhQ/pHb88WQ1hNe5V/dvFwc4VJcDL11LT9xSX0QtsR8sWUuyOuOq7g==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
@@ -6220,9 +6220,9 @@
}
},
"axios": {
- "version": "1.7.9",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
- "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.1.tgz",
+ "integrity": "sha512-NN+fvwH/kV01dYUQ3PTOZns4LWtWhOFCAhQ/pHb88WQ1hNe5V/dvFwc4VJcDL11LT9xSX0QtsR8sWUuyOuOq7g==",
"requires": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
diff --git a/package.json b/package.json
index 030ff14..d9f8607 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
},
"dependencies": {
"@reduxjs/toolkit": "^2.6.0",
- "axios": "^1.7.9",
+ "axios": "^1.8.1",
"bcryptjs": "^3.0.2",
"bootstrap": "^5.3.3",
"cors": "^2.8.5",
diff --git a/src/api/queueApi.js b/src/api/queueApi.js
index 0773931..2ba5fac 100644
--- a/src/api/queueApi.js
+++ b/src/api/queueApi.js
@@ -1,56 +1,35 @@
import axios from "axios";
-const API_URL = "http://localhost:5000/queue";
+const API_URL = import.meta.env.VITE_API_URL;
-export const fetchOperators = async () => {
- try {
- const response = await axios.get(API_URL);
- return response.data;
- } catch (error) {
- console.error("Error fetching operators", error);
- return [];
- }
+export const fetchQueues = async () => {
+ try {
+ const response = await axios.get(`${API_URL}/operators`);
+ return response.data;
+ } catch (error) {
+ console.error("Error fetching queues:", error);
+ return [];
+ }
};
-export const addCustomerToOperator = async (operatorId, customerData) => {
- try {
- const response = await axios.get(`${API_URL}/${operatorId}`);
- const operator = response.data;
-
- operator.customers.push(customerData);
-
- const updateResponse = await axios.put(`${API_URL}/${operatorId}`, operator);
- return updateResponse.data;
- } catch (error) {
- console.error("Error adding customer", error);
- }
+export const updateQueueStatus = async (queueId, status) => {
+ try {
+ const response = await axios.put(`${API_URL}/queues/${queueId}`, {
+ status,
+ });
+ return response.data;
+ } catch (error) {
+ console.error("Error updating queue status:", error);
+ return null;
+ }
};
-export const updateCustomerStatus = async (operatorId, customerId, updatedData) => {
+export const createQueue = async (customerData) => {
try {
- const response = await axios.get(`${API_URL}/${operatorId}`);
- const operator = response.data;
-
- operator.customers = operator.customers.map(customer =>
- customer.id === customerId ? { ...customer, ...updatedData } : customer
- );
-
- const updateResponse = await axios.put(`${API_URL}/${operatorId}`, operator);
- return updateResponse.data;
+ const response = await axios.post(`${API_URL}/queues`, customerData);
+ return response.data;
} catch (error) {
- console.error("Error updating customer status", error);
+ console.error("Error creating queue:", error);
+ return null;
}
-};
-
-export const deleteCustomerFromOperator = async (operatorId, customerId) => {
- try {
- const response = await axios.get(`${API_URL}/${operatorId}`);
- const operator = response.data;
-
- operator.customers = operator.customers.filter(customer => customer.id !== customerId);
-
- await axios.put(`${API_URL}/${operatorId}`, operator);
- } catch (error) {
- console.error("Error deleting customer", error);
- }
-};
+ };
diff --git a/src/components/Admin/AdminSidebar.jsx b/src/components/Admin/AdminSidebar.jsx
index 9aea3b6..2def27b 100644
--- a/src/components/Admin/AdminSidebar.jsx
+++ b/src/components/Admin/AdminSidebar.jsx
@@ -28,9 +28,9 @@ const AdminSidebar = () => {
Daftar Antrian
-
+ {/*
Panggil Antrian
-
+ */}
{/*
Laporan Antrian
*/}
diff --git a/src/components/Admin/QueueActions.jsx b/src/components/Admin/QueueActions.jsx
index 25cab5f..fea1539 100644
--- a/src/components/Admin/QueueActions.jsx
+++ b/src/components/Admin/QueueActions.jsx
@@ -1,29 +1,29 @@
const queueData = [
- { id: 1, name: "John Doe", phone: "08123456789", service: "Siap Print", serviceId: "J0001", locket: "01", startAt: "10:30 AM", completedAt: "10:30 AM", queueNumber: "001", status: "Menunggu", called: false, active: true, audio: "Default"},
- { id: 2, name: "Jane Smith", phone: "08234567890", service: "Design", serviceId: "J0002", locket: "04", startAt: "11:15 AM", completedAt: "11:15 AM", queueNumber: "002", status: "Dilayani", called: false, active: true, audio: "Beep"},
- { id: 3, name: "Michael Johnson", phone: "08345678901", service: "FotoCopy", serviceId: "J0003", locket: "08", startAt: "11:50 AM", completedAt: "11:50 AM", queueNumber: "003", status: "Selesai", called: false, active: true, audio: "Bell"},
- { id: 4, name: "Emily Brown", phone: "08456789012", service: "Tamu", serviceId: "J0006", locket: "02", startAt: "12:10 PM", completedAt: "12:10 PM", queueNumber: "004", status: "Menunggu", called: false, active: true, audio: "Chime"},
- { id: 5, name: "David Wilson", phone: "08567890123", service: "Online", serviceId: "J0005", locket: "05", startAt: "12:50 PM", completedAt: "12:50 PM", queueNumber: "005", status: "Dilayani", called: false, active: true, audio: "Ding"},
- { id: 6, name: "Sophia Martinez", phone: "08678901234", service: "Online", serviceId: "J0005", locket: "06", startAt: "01:30 PM", completedAt: "01:30 PM", queueNumber: "006", status: "Selesai", called: false, active: true, audio: "Ping"},
- { id: 7, name: "James Anderson", phone: "08789012345", service: "Siap Print", serviceId: "J0001", locket: "03", startAt: "02:15 PM", completedAt: "02:15 PM", queueNumber: "007", status: "Menunggu", called: false, active: true, audio: "Chirp"},
- { id: 8, name: "Olivia Thomas", phone: "08890123456", service: "Design", serviceId: "J0002", locket: "07", startAt: "02:50 PM", completedAt: "02:50 PM", queueNumber: "008", status: "Dilayani", called: false, active: true, audio: "Ring"},
- { id: 9, name: "Liam White", phone: "08901234567", service: "FotoCopy", serviceId: "J0003", locket: "09", startAt: "03:20 PM", completedAt: "03:20 PM", queueNumber: "009", status: "Selesai", called: false, active: true, audio: "Tone"},
- { id: 10, name: "Emma Harris", phone: "08012345678", service: "Siap Print", serviceId: "J0001", locket: "10", startAt: "03:50 PM", completedAt: "03:50 PM", queueNumber: "010", status: "Menunggu", called: false, active: true, audio: "Alarm" },
- { id: 11, name: "John Doe", phone: "08123456789", service: "Siap Print", serviceId: "J0001", locket: "01", startAt: "10:30 AM", completedAt: "10:30 AM", queueNumber: "001", status: "Menunggu", called: false, active: true, audio: "Default"},
- { id: 12, name: "Jane Smith", phone: "08234567890", service: "Design", serviceId: "J0002", locket: "04", startAt: "11:15 AM", completedAt: "11:15 AM", queueNumber: "002", status: "Dilayani", called: false, active: true, audio: "Beep"},
- { id: 13, name: "Michael Johnson", phone: "08345678901", service: "FotoCopy", serviceId: "J0003", locket: "08", startAt: "11:50 AM", completedAt: "11:50 AM", queueNumber: "003", status: "Selesai", called: false, active: true, audio: "Bell"},
- { id: 14, name: "Emily Brown", phone: "08456789012", service: "Online", serviceId: "J0005", locket: "02", startAt: "12:10 PM", completedAt: "12:10 PM", queueNumber: "004", status: "Menunggu", called: false, active: true, audio: "Chime"},
- { id: 15, name: "David Wilson", phone: "08567890123", service: "Design", serviceId: "J0002", locket: "05", startAt: "12:50 PM", completedAt: "12:50 PM", queueNumber: "005", status: "Dilayani", called: false, active: true, audio: "Ding"},
- { id: 16, name: "John Doe", phone: "08123456789", service: "Online", serviceId: "J0005", locket: "01", startAt: "10:30 AM", completedAt: "10:30 AM", queueNumber: "001", status: "Menunggu", called: false, active: true, audio: "Default"},
- { id: 17, name: "Jane Smith", phone: "08234567890", service: "Design", serviceId: "J0002", locket: "04", startAt: "11:15 AM", completedAt: "11:15 AM", queueNumber: "002", status: "Dilayani", called: false, active: true, audio: "Beep"},
- { id: 18, name: "Michael Johnson", phone: "08345678901", service: "Retur", serviceId: "J0004", locket: "08", startAt: "11:50 AM", completedAt: "11:50 AM", queueNumber: "003", status: "Selesai", called: false, active: true, audio: "Bell"},
- { id: 19, name: "Emily Brown", phone: "08456789012", service: "Online", serviceId: "J0005", locket: "02", startAt: "12:10 PM", completedAt: "12:10 PM", queueNumber: "004", status: "Menunggu", called: false, active: true, audio: "Chime"},
- { id: 20, name: "David Wilson", phone: "08567890123", service: "Design", serviceId: "J0002", locket: "05", startAt: "12:50 PM", completedAt: "12:50 PM", queueNumber: "005", status: "Dilayani", called: false, active: true, audio: "Ding"},
- { id: 21, name: "Sophia Martinez", phone: "08678901234", service: "Retur", serviceId: "J0004", locket: "06", startAt: "01:30 PM", completedAt: "01:30 PM", queueNumber: "006", status: "Selesai", called: false, active: true, audio: "Ping"},
- { id: 22, name: "James Anderson", phone: "08789012345", service: "Online", serviceId: "J0005", locket: "03", startAt: "02:15 PM", completedAt: "02:15 PM", queueNumber: "007", status: "Menunggu", called: false, active: true, audio: "Chirp"},
- { id: 23, name: "Olivia Thomas", phone: "08890123456", service: "Design", serviceId: "J0002", locket: "07", startAt: "02:50 PM", completedAt: "02:50 PM", queueNumber: "008", status: "Dilayani", called: false, active: true, audio: "Ring"},
- { id: 24, name: "Liam White", phone: "08901234567", service: "Tamu", serviceId: "J0006", locket: "09", startAt: "03:20 PM", completedAt: "03:20 PM", queueNumber: "009", status: "Selesai", called: false, active: true, audio: "Tone"},
- { id: 25, name: "Emma Harris", phone: "08012345678", service: "Siap Print", serviceId: "J0001", locket: "10", startAt: "03:50 PM", completedAt: "03:50 PM", queueNumber: "010", status: "Menunggu", called: false, active: true, audio: "Alarm"},
+ { id: 1, name: "John Doe", phone: "08123456789", service: "Siap Print", serviceId: "J0001", locket: "loket 01", startAt: "10:30 AM", completedAt: "10:30 AM", queueNumber: "001", status: "Menunggu", called: false, active: true},
+ { id: 2, name: "Jane Smith", phone: "08234567890", service: "Design", serviceId: "J0002", locket: "loket 04", startAt: "11:15 AM", completedAt: "11:15 AM", queueNumber: "002", status: "Menunggu", called: false, active: true},
+ { id: 3, name: "Michael Johnson", phone: "08345678901", service: "FotoCopy", serviceId: "J0003", locket: "loket 08", startAt: "11:50 AM", completedAt: "11:50 AM", queueNumber: "003", status: "Menunggu", called: false, active: true},
+ { id: 4, name: "Emily Brown", phone: "08456789012", service: "Tamu", serviceId: "J0006", locket: "loket 02", startAt: "12:10 PM", completedAt: "12:10 PM", queueNumber: "004", status: "Menunggu", called: false, active: true},
+ { id: 5, name: "David Wilson", phone: "08567890123", service: "Online", serviceId: "J0005", locket: "loket 05", startAt: "04:00 PM", completedAt: "12:50 PM", queueNumber: "005", status: "Menunggu", called: false, active: true},
+ { id: 6, name: "Sophia Martinez", phone: "08678901234", service: "Online", serviceId: "J0005", locket: "loket 06", startAt: "01:30 PM", completedAt: "01:30 PM", queueNumber: "006", status: "Menunggu", called: false, active: true},
+ { id: 7, name: "James Anderson", phone: "08789012345", service: "Siap Print", serviceId: "J0001", locket: "loket 03", startAt: "02:15 PM", completedAt: "02:15 PM", queueNumber: "007", status: "Menunggu", called: false, active: true},
+ { id: 8, name: "Olivia Thomas", phone: "08890123456", service: "Design", serviceId: "J0002", locket: "loket 07", startAt: "02:50 PM", completedAt: "02:50 PM", queueNumber: "008", status: "Menunggu", called: false, active: true},
+ { id: 9, name: "Liam White", phone: "08901234567", service: "FotoCopy", serviceId: "J0003", locket: "loket 09", startAt: "03:20 PM", completedAt: "03:20 PM", queueNumber: "009", status: "Menunggu", called: false, active: true},
+ { id: 10, name: "Emma Harris", phone: "08012345678", service: "Siap Print", serviceId: "J0001", locket: "loket 10", startAt: "03:50 PM", completedAt: "03:50 PM", queueNumber: "010", status: "Menunggu", called: false, active: true},
+ { id: 11, name: "John Doe", phone: "08123456789", service: "Siap Print", serviceId: "J0001", locket: "loket 01", startAt: "10:30 AM", completedAt: "10:30 AM", queueNumber: "001", status: "Menunggu", called: false, active: true},
+ { id: 12, name: "Jane Smith", phone: "08234567890", service: "Design", serviceId: "J0002", locket: "loket 04", startAt: "11:15 AM", completedAt: "11:15 AM", queueNumber: "002", status: "Menunggu", called: false, active: true},
+ { id: 13, name: "Michael Johnson", phone: "08345678901", service: "FotoCopy", serviceId: "J0003", locket: "loket 08", startAt: "11:50 AM", completedAt: "11:50 AM", queueNumber: "003", status: "Menunggu", called: false, active: true},
+ { id: 14, name: "Emily Brown", phone: "08456789012", service: "Online", serviceId: "J0005", locket: "loket 02", startAt: "12:10 PM", completedAt: "12:10 PM", queueNumber: "004", status: "Menunggu", called: false, active: true},
+ { id: 15, name: "David Wilson", phone: "08567890123", service: "Design", serviceId: "J0002", locket: "loket 05", startAt: "04:00 PM", completedAt: "12:50 PM", queueNumber: "005", status: "Menunggu", called: false, active: true},
+ { id: 16, name: "John Doe", phone: "08123456789", service: "Online", serviceId: "J0005", locket: "loket 01", startAt: "10:30 AM", completedAt: "10:30 AM", queueNumber: "001", status: "Menunggu", called: false, active: true},
+ { id: 17, name: "Jane Smith", phone: "08234567890", service: "Design", serviceId: "J0002", locket: "loket 04", startAt: "11:15 AM", completedAt: "11:15 AM", queueNumber: "002", status: "Menunggu", called: false, active: true},
+ { id: 18, name: "Michael Johnson", phone: "08345678901", service: "Retur", serviceId: "J0004", locket: "loket 08", startAt: "11:50 AM", completedAt: "11:50 AM", queueNumber: "003", status: "Menunggu", called: false, active: true},
+ { id: 19, name: "Emily Brown", phone: "08456789012", service: "Online", serviceId: "J0005", locket: "loket 02", startAt: "12:10 PM", completedAt: "12:10 PM", queueNumber: "004", status: "Menunggu", called: false, active: true},
+ { id: 20, name: "David Wilson", phone: "08567890123", service: "Design", serviceId: "J0002", locket: "loket 05", startAt: "04:00 PM", completedAt: "12:50 PM", queueNumber: "005", status: "Menunggu", called: false, active: true},
+ { id: 21, name: "Sophia Martinez", phone: "08678901234", service: "Retur", serviceId: "J0004", locket: "loket 06", startAt: "01:30 PM", completedAt: "01:30 PM", queueNumber: "006", status: "Menunggu", called: false, active: true},
+ { id: 22, name: "James Anderson", phone: "08789012345", service: "Online", serviceId: "J0005", locket: "loket 03", startAt: "02:15 PM", completedAt: "02:15 PM", queueNumber: "007", status: "Menunggu", called: false, active: true},
+ { id: 23, name: "Olivia Thomas", phone: "08890123456", service: "Design", serviceId: "J0002", locket: "loket 07", startAt: "02:50 PM", completedAt: "02:50 PM", queueNumber: "008", status: "Menunggu", called: false, active: true},
+ { id: 24, name: "Liam White", phone: "08901234567", service: "Tamu", serviceId: "J0006", locket: "loket 09", startAt: "03:20 PM", completedAt: "03:20 PM", queueNumber: "009", status: "Menunggu", called: false, active: true},
+ { id: 25, name: "Emma Harris", phone: "08012345678", service: "Siap Print", serviceId: "J0001", locket: "loket 10", startAt: "03:50 PM", completedAt: "03:50 PM", queueNumber: "010", status: "Menunggu", called: false, active: true},
];
export const getQueueSettingsData = () => {
@@ -61,10 +61,21 @@ export const toggleServiceStatus = (id) => {
};
export const getFilteredQueueData = (callQueueView = false) => {
- if (callQueueView) {
- return queueData.filter((item) => item.status === "Menunggu");
- }
- return queueData;
+ let filteredQueue = queueData.filter((item) =>
+ callQueueView ? item.status === "Menunggu" : true
+ );
+
+ // Urutkan berdasarkan status "Menunggu" terlebih dahulu, lalu berdasarkan startAt
+ filteredQueue.sort((a, b) => {
+ if (a.status === "Menunggu" && b.status !== "Menunggu") return -1;
+ if (b.status === "Menunggu" && a.status !== "Menunggu") return 1;
+
+ const timeA = new Date(`1970/01/01 ${a.startAt}`);
+ const timeB = new Date(`1970/01/01 ${b.startAt}`);
+ return timeA - timeB;
+ });
+
+ return filteredQueue;
};
export const getQueueDisplayData = () => {
@@ -79,9 +90,6 @@ export const getQueueDisplayData = () => {
}));
};
-
-
-// QueueActions.js
import { useState } from "react";
export const useQueueData = (settingsView, callQueueView) => {
@@ -113,7 +121,7 @@ export const useQueueData = (settingsView, callQueueView) => {
searchQuery,
setSearchQuery,
setCurrentPage,
- indexOfFirstItem, // ✅ Tambahkan ini
+ indexOfFirstItem,
};
};
diff --git a/src/components/Admin/QueueTable.jsx b/src/components/Admin/QueueTable.jsx
index 4e221d8..08e2dce 100644
--- a/src/components/Admin/QueueTable.jsx
+++ b/src/components/Admin/QueueTable.jsx
@@ -1,142 +1,143 @@
-import { Table, Button, Form, Pagination, InputGroup, FormControl } from "react-bootstrap";
+import { useState } from "react";
+import { Card, Table, Button, Form, Pagination, InputGroup, FormControl, Modal } from "react-bootstrap";
import { FaSearch } from "react-icons/fa";
-import { handleCall, toggleServiceStatus, handleDelete, handleEdit, useQueueData } from "./QueueActions";
+import { handleCall, useQueueData } from "./QueueActions";
// eslint-disable-next-line react/prop-types
-const QueueTable = ({ showActions = true, reportView = false, settingsView = false, displayView = false, callQueueView = false }) => {
-
- const { currentItems, currentPage, totalPages, searchQuery, setSearchQuery, setCurrentPage, indexOfFirstItem } = useQueueData(settingsView, callQueueView);
+const QueueTable = ({ settingsView = false, displayView = false }) => {
+ const { currentItems, currentPage, totalPages, searchQuery, setSearchQuery, setCurrentPage, indexOfFirstItem } = useQueueData(settingsView);
+
+ // State untuk modal
+ const [showModal, setShowModal] = useState(false);
+ const [selectedQueue, setSelectedQueue] = useState(null);
+ const [selectedLocket, setSelectedLocket] = useState("");
+
+ // Data loket operator (bisa diganti dengan API)
+ const availableLockets = ["Loket 1", "Loket 2", "Loket 3", "Loket 4", "Loket 5", "Loket 6", "Loket 7", "Loket 8", "Loket 9"];
+
+ // Fungsi membuka modal dan menyimpan antrian yang dipilih
+ const handleOpenModal = (queue) => {
+ setSelectedQueue(queue);
+ setShowModal(true);
+ };
+
+ // Fungsi menutup modal
+ const handleCloseModal = () => {
+ setShowModal(false);
+ setSelectedQueue(null);
+ setSelectedLocket("");
+ };
+
+ // Fungsi memilih loket dan panggil antrian
+ const handleSelectLocket = () => {
+ if (selectedLocket) {
+ handleCall(selectedQueue.id, selectedLocket); // Panggil dengan loket
+ handleCloseModal(); // Tutup modal setelah memilih
+ }
+ };
return (
<>
- {(callQueueView || reportView || (!settingsView && !displayView)) && (
-
-
-
-
- setSearchQuery(e.target.value)}
- />
-
- )}
-
-
-
- | # |
- {displayView ? (
- <>
- Pengaturan Suara |
- Video Komersil |
- Aksi |
- >
- ) : settingsView ? (
- <>
- Nama Layanan |
- ID Layanan |
- Status |
- Aksi |
- >
- ) : reportView ? (
- <>
- Nama |
- No. Telepon |
- Layanan |
- Loket |
- Cetak Antrian |
- Selesai Antrian |
- Aksi |
- >
- ) : (
- <>
- Nama |
- Layanan |
- Kode Layanan |
- Nomor Antrian |
- Loket |
- Status |
- {showActions && Aksi | }
- >
- )}
-
-
-
- {currentItems.map((item, index) => (
-
- | {index + 1 + indexOfFirstItem} |
- {displayView ? (
- <>
-
-
-
-
-
-
- |
- {item.video} |
-
-
-
-
- |
- >
- ) : settingsView ? (
- <>
- {item.service} |
- {item.serviceId} |
- {item.active ? "Aktif" : "Nonaktif"} |
-
-
- |
- >
- ) : reportView ? (
- <>
- {item.name} |
- {item.phone} |
- {item.service} |
- {item.locket} |
- {item.startAt} |
- {item.completedAt} |
-
-
-
- |
- >
- ) : (
- <>
- {item.name} |
- {item.service} |
- {item.serviceId} |
- {item.queueNumber} |
- {item.status === "Dilayani" ? item.locket : "-"} |
- {item.status} |
- {showActions && (
+
+
+ {(!settingsView && !displayView) && (
+
+
+
+
+ setSearchQuery(e.target.value)}
+ />
+
+ )}
+
+ setCurrentPage(prev => Math.max(prev - 1, 1))} disabled={currentPage === 1} />
+ {[...Array(totalPages)].map((_, index) => (
+ setCurrentPage(index + 1)}>
+ {index + 1}
+
+ ))}
+ setCurrentPage(prev => Math.min(prev + 1, totalPages))} disabled={currentPage === totalPages} />
+
+
+
+
+
+
+
+
+ | # |
+ Nama |
+ Layanan |
+ Kode Layanan |
+ Nomor Antrian |
+ Pengambilan |
+ Loket |
+ Status |
+ Aksi |
+
+
+
+ {currentItems.map((item, index) => (
+
+ | {index + 1 + indexOfFirstItem} |
+ {item.name} |
+ {item.service} |
+ {item.serviceId} |
+ {item.queueNumber} |
+ {item.startAt} |
+ {item.status === "Dilayani" ? item.locket : "-"} |
+ {item.status} |
- |
- )}
- >
- )}
-
- ))}
-
-
-
- setCurrentPage(prev => Math.max(prev - 1, 1))} disabled={currentPage === 1} />
- {[...Array(totalPages)].map((_, index) => (
- setCurrentPage(index + 1)}>
- {index + 1}
-
- ))}
- setCurrentPage(prev => Math.min(prev + 1, totalPages))} disabled={currentPage === totalPages} />
-
+
+ ))}
+ {Array.from({ length: Math.max(0, 10 - currentItems.length) }).map((_, index) => (
+
+ | |
+
+ ))}
+
+
+
+
+
+
+ {/* Modal untuk memilih loket */}
+
+
+ Pilih Loket Operator
+
+
+ setSelectedLocket(e.target.value)}
+ />
+ ))}
+
+
+
+
+ Batal
+
+
+ Panggil
+
+
+
>
);
};
diff --git a/src/components/Admin/TestQueueActions.jsx b/src/components/Admin/TestQueueActions.jsx
new file mode 100644
index 0000000..bdafbc7
--- /dev/null
+++ b/src/components/Admin/TestQueueActions.jsx
@@ -0,0 +1,30 @@
+
+// FILE INI UNTUK TEST TAMPILAN DATA DENGAN API
+
+import { fetchQueues, updateQueueStatus } from "../../api/queueApi";
+
+export const getProcessedQueues = async () => {
+ const data = await fetchQueues();
+
+ // Ubah struktur data jika diperlukan
+ const processedData = data.map((operator) => ({
+ operatorId: operator.id,
+ operatorName: operator.name,
+ queues: operator.queues.map((queue) => ({
+ id: queue.queue_id,
+ customerName: queue.customer.name,
+ customerEmail: queue.customer.email,
+ customerPhone: queue.customer.phone,
+ serviceId: queue.service.id,
+ serviceName: queue.service.name,
+ status: queue.status,
+ createdAt: queue.created_at,
+ })),
+ }));
+
+ return processedData;
+};
+
+export const changeQueueStatus = async (queueId, newStatus) => {
+ return await updateQueueStatus(queueId, newStatus);
+};
diff --git a/src/components/Admin/TestQueueTable.jsx b/src/components/Admin/TestQueueTable.jsx
new file mode 100644
index 0000000..2f71cc6
--- /dev/null
+++ b/src/components/Admin/TestQueueTable.jsx
@@ -0,0 +1,133 @@
+
+// FILE INI UNTUK TEST TAMPILAN DATA DENGAN API
+
+import { useEffect, useState } from "react";
+import { getProcessedQueues } from "./TestQueueActions";
+import { Card, Table, Container, Button, Modal, ListGroup } from "react-bootstrap";
+
+const TestQueueTable = () => {
+ const [queues, setQueues] = useState([]);
+ const [selectedQueue, setSelectedQueue] = useState(null);
+ const [showModal, setShowModal] = useState(false);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ const data = await getProcessedQueues();
+ // Flatten data agar tidak dikelompokkan per operator
+ const allQueues = data.flatMap((operator) =>
+ operator.queues.map((queue) => ({
+ ...queue,
+ operatorName: operator.operatorName, // Menyimpan nama operator di setiap antrian
+ }))
+ );
+ // Sort data: Prioritaskan yang Waiting dan urutkan berdasarkan createdAt
+ allQueues.sort((a, b) => {
+ if (a.status === "Waiting" && b.status !== "Waiting") return -1;
+ if (a.status !== "Waiting" && b.status === "Waiting") return 1;
+ return new Date(a.createdAt) - new Date(b.createdAt);
+ });
+ setQueues(allQueues);
+ };
+ fetchData();
+ }, []);
+
+ // Data dummy untuk loket operator yang tersedia
+ const availableCounters = [
+ { id: "LKT001", name: "Loket 1" },
+ { id: "LKT002", name: "Loket 2" },
+ { id: "LKT003", name: "Loket 3" },
+ ];
+
+ // Handler untuk membuka modal dan memilih queue
+ const handleCallQueue = (queue) => {
+ setSelectedQueue(queue);
+ setShowModal(true);
+ };
+
+ return (
+
+
+
+ List Antrian
+
+
+
+
+
+ | Customer |
+ Email |
+ Phone |
+ Service |
+ Status |
+ Created At |
+ Action |
+
+
+
+ {queues.length > 0 ? (
+ queues.map((queue) => (
+
+ | {queue.customerName} |
+ {queue.customerEmail} |
+ {queue.customerPhone} |
+ {queue.serviceName} |
+
+
+ {queue.status}
+
+ |
+ {new Date(queue.createdAt).toLocaleString()} |
+
+ {queue.status !== "In Progress" && queue.status !== "Completed" && (
+ handleCallQueue(queue)}
+ >
+ Panggil Antrian
+
+ )}
+ |
+
+ ))
+ ) : (
+
+ |
+ No queues available
+ |
+
+ )}
+
+
+
+
+
+ {/* Modal Pilih Loket */}
+ setShowModal(false)} centered>
+
+ Pilih Loket Operator
+
+
+ Memanggil antrian {selectedQueue?.customerName}
+
+ {availableCounters.map((counter) => (
+
+ {counter.name}
+
+ ))}
+
+
+
+
+ );
+};
+
+export default TestQueueTable;
diff --git a/src/components/Display/QueueDisplay.jsx b/src/components/Display/QueueDisplay.jsx
index ecc0997..7e3710d 100644
--- a/src/components/Display/QueueDisplay.jsx
+++ b/src/components/Display/QueueDisplay.jsx
@@ -80,19 +80,53 @@ const QueueDisplay = () => {
{/* Loket Antrian */}
-
-
-
+
+
+
+
+
+ List Antrian Layanan
+
+
+
+
+
List Antrian Layanan
-
-
-
- List Antrian Layanan
-
-
-
-
+ data antrian
+
+
+
+
+ List Antrian Layanan
+ data antrian
+
+
+
+
+ List Antrian Layanan
+ data antrian
+
+
+
+
+ List Antrian Layanan
+ data antrian
+
+
+
+
+ List Antrian Layanan
+ data antrian
+
+
+
+
+ List Antrian Layanan
+ data antrian
+
+
+
diff --git a/src/components/Display/ServiceSelection.jsx b/src/components/Display/ServiceSelection.jsx
index d0f66ad..4558f0e 100644
--- a/src/components/Display/ServiceSelection.jsx
+++ b/src/components/Display/ServiceSelection.jsx
@@ -1,5 +1,5 @@
import { Container, Card, Button, Row, Col, Form, Carousel } from 'react-bootstrap';
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
import { FaPrint, FaPalette, FaFileAlt, FaUndo, FaTruck, FaUser } from 'react-icons/fa';
const services = [
@@ -18,15 +18,17 @@ const ServiceSelection = () => {
const [ticket, setTicket] = useState(null);
const [enableForm, setEnableForm] = useState(false);
+ useEffect(() => {
+ if (selectedService && !enableForm) {
+ generateTicket();
+ }
+ }, [selectedService]);
+
const handleServiceSelect = (serviceId) => {
setSelectedService(services.find(service => service.id === serviceId));
- if (!enableForm) {
- handleSubmit(new Event("submit"));
- }
};
- const handleSubmit = (e) => {
- e.preventDefault();
+ const generateTicket = () => {
if (selectedService) {
const queueNumber = `${selectedService.id}-${Math.floor(1000 + Math.random() * 9000)}`;
const newTicket = {
@@ -41,31 +43,35 @@ const ServiceSelection = () => {
}
};
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ generateTicket();
+ };
+
return (
{!ticket ? (
- Pilih Layanan
+
+
Pilih Layanan
+
- {services.map(service => {
- const isSelected = selectedService?.id === service.id;
- return (
-
- handleServiceSelect(service.id)}
- >
-
- {service.icon}
-
- {service.name}
-
-
-
-
- );
- })}
+ {services.map(service => (
+
+ handleServiceSelect(service.id)}
+ >
+
+ {service.icon}
+
+ {service.name}
+
+
+
+
+ ))}
@@ -91,7 +97,6 @@ const ServiceSelection = () => {
value={name}
onChange={(e) => setName(e.target.value)}
disabled={!enableForm}
- className={`border ${enableForm ? "border-primary" : "border-secondary"} ${enableForm ? "" : "bg-light text-secondary"}`}
/>
@@ -102,7 +107,6 @@ const ServiceSelection = () => {
value={phone}
onChange={(e) => setPhone(e.target.value)}
disabled={!enableForm}
- className={`border ${enableForm ? "border-primary" : "border-secondary"} ${enableForm ? "" : "bg-light text-secondary"}`}
/>
@@ -111,11 +115,11 @@ const ServiceSelection = () => {
-
-
+
+
{["c1.png", "c2.jpg", "c3.jpg"].map((image, index) => (
-
-
+
+
))}
diff --git a/src/components/Display/TestQueueDisplay.jsx b/src/components/Display/TestQueueDisplay.jsx
new file mode 100644
index 0000000..d6b5773
--- /dev/null
+++ b/src/components/Display/TestQueueDisplay.jsx
@@ -0,0 +1,45 @@
+
+// FILE INI UNTUK TEST TAMPILAN DATA DENGAN API
+
+import { useEffect, useState } from "react";
+import { getProcessedQueues } from "../Admin/TestQueueActions";
+import { Card, Container } from "react-bootstrap";
+
+const TestQueueDisplay = () => {
+ const [queues, setQueues] = useState([]);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ const data = await getProcessedQueues();
+ // Ambil hanya antrian yang masih berlangsung atau menunggu, lalu urutkan
+ const sortedQueues = data
+ .flatMap((operator) => operator.queues)
+ .filter((queue) => queue.status !== "Completed")
+ .sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
+
+ setQueues(sortedQueues);
+ };
+
+ fetchData();
+ const interval = setInterval(fetchData, 2000); // Auto-refresh tiap 5 detik
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+ Layar Antrian
+ {queues.length > 0 ? (
+
+ {queues[0].id}
+ {queues[0].customerName}
+ {queues[0].serviceName}
+
+ ) : (
+ Tidak ada antrian aktif
+ )}
+
+ );
+};
+
+export default TestQueueDisplay;
+
diff --git a/src/components/Display/TestServiceSelection.jsx b/src/components/Display/TestServiceSelection.jsx
new file mode 100644
index 0000000..1322dd7
--- /dev/null
+++ b/src/components/Display/TestServiceSelection.jsx
@@ -0,0 +1,34 @@
+
+// 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";
+
+const ServiceSelection = () => {
+ const [queues, setQueues] = useState([]);
+
+ useEffect(() => {
+ getProcessedQueues().then(setQueues);
+ }, []);
+
+ return (
+
+
+ {queues.map((operator) => (
+
+ {operator.operatorName}
+
+ {operator.queues.map((queue) => (
+ - {queue.serviceName}
+ ))}
+
+
+ ))}
+
+
+ );
+};
+
+export default ServiceSelection;
+
diff --git a/src/pages/Admin/CallQueuePage.jsx b/src/pages/Admin/CallQueuePage.jsx
index 1dbb1b1..4038b1d 100644
--- a/src/pages/Admin/CallQueuePage.jsx
+++ b/src/pages/Admin/CallQueuePage.jsx
@@ -1,10 +1,10 @@
-import QueueTable from "../../components/Admin/QueueTable";
+import TestQueueTable from "../../components/Admin/TestQueueTable";
const CallQueuePage = () => {
return (
Panggil Atrian Page
-
+
)
}
diff --git a/src/pages/Admin/QueueListPage.jsx b/src/pages/Admin/QueueListPage.jsx
index b6419cc..7360d7a 100644
--- a/src/pages/Admin/QueueListPage.jsx
+++ b/src/pages/Admin/QueueListPage.jsx
@@ -1,11 +1,14 @@
+import TestQueueTable from "../../components/Admin/TestQueueTable";
import QueueTable from "../../components/Admin/QueueTable";
const QueueListPage = () => {
return (
-
Daftar Antrian
-
+
+ {/* INI ADALAH UNTUK TEST DATA DENGAN API */}
+
+
);
};
diff --git a/src/pages/Display/QueueDisplayPage.jsx b/src/pages/Display/QueueDisplayPage.jsx
index 5f823a7..1d485fc 100644
--- a/src/pages/Display/QueueDisplayPage.jsx
+++ b/src/pages/Display/QueueDisplayPage.jsx
@@ -1,8 +1,10 @@
+import TestQueueDisplay from "../../components/Display/TestQueueDisplay"
import QueueDisplay from "../../components/Display/QueueDisplay"
const QueueDisplayPage = () => {
return (
<>
+ {/*
INI ADALAH UNTUK TEST DATA DENGAN API */}
>
)
diff --git a/src/pages/Display/QueueMenuPage.jsx b/src/pages/Display/QueueMenuPage.jsx
index e16510a..c4b7385 100644
--- a/src/pages/Display/QueueMenuPage.jsx
+++ b/src/pages/Display/QueueMenuPage.jsx
@@ -1,8 +1,10 @@
+import TestServiceSelection from "../../components/Display/TestServiceSelection"
import ServiceSelection from "../../components/Display/ServiceSelection"
const QueueMenuPage = () => {
return (
<>
+ {/*
INI ADALAH UNTUK TEST DATA DENGAN API */}
>
)
diff --git a/src/routes/AppRoutes.jsx b/src/routes/AppRoutes.jsx
index bccf1ae..4bc503b 100644
--- a/src/routes/AppRoutes.jsx
+++ b/src/routes/AppRoutes.jsx
@@ -1,8 +1,8 @@
import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router-dom";
import AdminLayout from "../layouts/AdminLayout";
import QueueListPage from "../pages/admin/QueueListPage";
-import CallQueuePage from "../pages/admin/CallQueuePage";
-import QueueReportPage from "../pages/admin/QueueReportPage";
+// import CallQueuePage from "../pages/admin/CallQueuePage";
+// import QueueReportPage from "../pages/admin/QueueReportPage";
import QueueSettingsDisplayPage from "../pages/admin/QueueSettingsDisplayPage";
import QueueSettingsMenuPage from "../pages/admin/QueueSettingsMenuPage";
import QueueDisplayPage from "../pages/display/QueueDisplayPage";
@@ -18,8 +18,8 @@ const AppRoutes = () => {
{/* Rute untuk Admin */}
}>
} />
-
} />
-
} />
+ {/*
} />
+
} /> */}
} />
} />