Minor Update 26/02/2025
This commit is contained in:
parent
492552d373
commit
167f0f4e0a
16
db.json
Normal file
16
db.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"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" }
|
||||
]
|
||||
}
|
||||
BIN
public/c1.png
Normal file
BIN
public/c1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 MiB |
BIN
public/c2.jpg
Normal file
BIN
public/c2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 859 KiB |
BIN
public/c3.jpg
Normal file
BIN
public/c3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 499 KiB |
56
src/api/queueApi.js
Normal file
56
src/api/queueApi.js
Normal file
@ -0,0 +1,56 @@
|
||||
import axios from "axios";
|
||||
|
||||
const API_URL = "http://localhost:5000/queue";
|
||||
|
||||
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 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 updateCustomerStatus = async (operatorId, customerId, updatedData) => {
|
||||
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;
|
||||
} catch (error) {
|
||||
console.error("Error updating customer status", error);
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
@ -2,7 +2,7 @@ import { Container } from "react-bootstrap";
|
||||
|
||||
const AdminFooter = () => {
|
||||
return (
|
||||
<footer className="bg-dark text-center text-light py-3 mt-auto">
|
||||
<footer className="bg-light text-center py-3 mt-auto shadow-sm" style={{ borderTop: "1px solid #D3D3D3" }}>
|
||||
<Container>
|
||||
<p className="mb-0">© {new Date().getFullYear()} Admin Dashboard</p>
|
||||
</Container>
|
||||
|
||||
@ -2,7 +2,7 @@ import { Navbar, Container } from "react-bootstrap";
|
||||
|
||||
const AdminNavbar = () => {
|
||||
return (
|
||||
<Navbar bg="dark" variant="dark" expand="lg">
|
||||
<Navbar bg="light" variant="light" expand="lg" className="shadow-sm">
|
||||
<Container>
|
||||
<Navbar.Brand href="/admin">Admin Dashboard</Navbar.Brand>
|
||||
</Container>
|
||||
|
||||
@ -11,33 +11,33 @@ const AdminSidebar = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="d-flex flex-column bg-dark text-white vh-100 p-3" style={{ width: "250px" }}>
|
||||
<div className="d-flex flex-column bg-light p-3" style={{ width: "250px", borderRight: "1px solid #D3D3D3" }}>
|
||||
<h5 className="mb-4">Admin Menu</h5>
|
||||
|
||||
{/* Antrian Menu */}
|
||||
<div>
|
||||
<button
|
||||
onClick={() => toggleMenu("antrian")}
|
||||
className="btn btn-secondary w-100 text-start mb-2 d-flex align-items-center justify-content-between"
|
||||
className="btn btn-light shadow-sm w-100 text-start mb-2 d-flex align-items-center justify-content-between"
|
||||
>
|
||||
<span><FaList className="me-2" /> Antrian</span>
|
||||
{openMenu === "antrian" ? <FaChevronDown /> : <FaChevronRight />}
|
||||
</button>
|
||||
{openMenu === "antrian" && (
|
||||
<div className="ms-3 my-2 d-grid gap-2">
|
||||
<NavLink to="/admin/queue-list" className="btn btn-outline-light d-flex align-items-center">
|
||||
<NavLink to="/admin/queue-list" className="btn btn-light shadow-sm d-flex align-items-center">
|
||||
<FaList className="me-2" /> Daftar Antrian
|
||||
</NavLink>
|
||||
<NavLink to="/admin/call-queue" className="btn btn-outline-light d-flex align-items-center">
|
||||
<NavLink to="/admin/call-queue" className="btn btn-light shadow-sm d-flex align-items-center">
|
||||
<FaPhone className="me-2" /> Panggil Antrian
|
||||
</NavLink>
|
||||
{/* <NavLink to="/admin/queue-report" className="btn btn-outline-light d-flex align-items-center">
|
||||
{/* <NavLink to="/admin/queue-report" className="btn btn-light shadow-sm d-flex align-items-center">
|
||||
<FaChartBar className="me-2" /> Laporan Antrian
|
||||
</NavLink> */}
|
||||
<NavLink to="/admin/queue-settings-display" className="btn btn-outline-light d-flex align-items-center">
|
||||
<NavLink to="/admin/queue-settings-display" className="btn btn-light shadow-sm d-flex align-items-center">
|
||||
<FaCog className="me-2" /> Pengaturan Layar
|
||||
</NavLink>
|
||||
<NavLink to="/admin/queue-settings-menu" className="btn btn-outline-light d-flex align-items-center">
|
||||
<NavLink to="/admin/queue-settings-menu" className="btn btn-light shadow-sm d-flex align-items-center">
|
||||
<FaTools className="me-2" /> Pengaturan Menu
|
||||
</NavLink>
|
||||
</div>
|
||||
@ -48,7 +48,7 @@ const AdminSidebar = () => {
|
||||
<div>
|
||||
<button
|
||||
onClick={() => toggleMenu("monitor")}
|
||||
className="btn btn-secondary w-100 text-start mb-2 d-flex align-items-center justify-content-between"
|
||||
className="btn btn-light shadow-sm w-100 text-start mb-2 d-flex align-items-center justify-content-between"
|
||||
>
|
||||
<span><FaTv className="me-2" /> Monitor</span>
|
||||
{openMenu === "monitor" ? <FaChevronDown /> : <FaChevronRight />}
|
||||
@ -57,13 +57,13 @@ const AdminSidebar = () => {
|
||||
<div className="ms-3 my-2 d-grid gap-2">
|
||||
<button
|
||||
onClick={() => window.open("/queue-display", "_blank")}
|
||||
className="btn btn-outline-light d-flex align-items-center"
|
||||
className="btn btn-light shadow-sm d-flex align-items-center"
|
||||
>
|
||||
<FaTv className="me-2" /> Tampilan Antrian
|
||||
</button>
|
||||
<button
|
||||
onClick={() => window.open("/queue-menu", "_blank")}
|
||||
className="btn btn-outline-light d-flex align-items-center"
|
||||
className="btn btn-light shadow-sm d-flex align-items-center"
|
||||
>
|
||||
<FaThList className="me-2" /> Menu Antrian
|
||||
</button>
|
||||
|
||||
@ -42,11 +42,11 @@ const QueueDisplay = () => {
|
||||
style={{ borderRadius: "10px" }}
|
||||
>
|
||||
<div className="flex-grow-1">
|
||||
<h3>Pandawa24Jam</h3>
|
||||
<p>Call Center: 081234567891</p>
|
||||
<h5>Pandawa24Jam</h5>
|
||||
<p>CS: 081234567891</p>
|
||||
</div>
|
||||
<div className="position-absolute top-50 end-0 translate-middle-y me-3">
|
||||
<h2 className="mb-0">{currentTime.toLocaleTimeString()}</h2>
|
||||
<h4 className="mb-0">{currentTime.toLocaleTimeString()}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -20,6 +20,9 @@ const ServiceSelection = () => {
|
||||
|
||||
const handleServiceSelect = (serviceId) => {
|
||||
setSelectedService(services.find(service => service.id === serviceId));
|
||||
if (!enableForm) {
|
||||
handleSubmit(new Event("submit"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
@ -50,13 +53,8 @@ const ServiceSelection = () => {
|
||||
return (
|
||||
<Col key={service.id} md={6} className="mb-3">
|
||||
<Card
|
||||
className={`h-100 ${isSelected ? "bg-primary text-white border-primary shadow-sm" : "bg-light"}`}
|
||||
onClick={() => {
|
||||
handleServiceSelect(service.id);
|
||||
if (!enableForm) {
|
||||
handleSubmit(new Event("submit"));
|
||||
}
|
||||
}}
|
||||
className={`h-100 shadow rounded-3 ${isSelected ? "bg-primary text-white border-primary" : "bg-light"}`}
|
||||
onClick={() => handleServiceSelect(service.id)}
|
||||
>
|
||||
<Card.Body className="d-flex flex-column justify-content-center align-items-center">
|
||||
{service.icon}
|
||||
@ -82,7 +80,7 @@ const ServiceSelection = () => {
|
||||
Beri tanda centang untuk mengisi form
|
||||
</p>
|
||||
</div>
|
||||
<Card className={`flex-grow-1 ${enableForm ? "" : "bg-secondary bg-opacity-10"}`}>
|
||||
<Card className={`flex-grow-1 shadow rounded-3 ${enableForm ? "" : "bg-secondary bg-opacity-10"}`}>
|
||||
<Card.Body className="d-flex flex-column">
|
||||
<Form onSubmit={handleSubmit} className="flex-grow-1 d-flex flex-column">
|
||||
<Form.Group className="mb-3" controlId="formName">
|
||||
@ -115,34 +113,18 @@ const ServiceSelection = () => {
|
||||
</Card>
|
||||
<div className="d-flex flex-grow-1 my-3 align-items-center justify-content-center">
|
||||
<Carousel>
|
||||
<Carousel.Item interval={3000}>
|
||||
<img className="d-block w-100" src="https://images.unsplash.com/photo-1519389950473-47ba0277781c?w=800&h=400&fit=crop" alt="First slide" height={400} />
|
||||
<Carousel.Caption>
|
||||
<h3>First Slide Label</h3>
|
||||
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
|
||||
</Carousel.Caption>
|
||||
</Carousel.Item>
|
||||
<Carousel.Item interval={3000}>
|
||||
<img className="d-block w-100" src="https://images.unsplash.com/photo-1519389950473-47ba0277781c?w=800&h=400&fit=crop" alt="Second slide" height={400} />
|
||||
<Carousel.Caption>
|
||||
<h3>Second Slide Label</h3>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
|
||||
</Carousel.Caption>
|
||||
</Carousel.Item>
|
||||
<Carousel.Item interval={3000}>
|
||||
<img className="d-block w-100" src="https://images.unsplash.com/photo-1519389950473-47ba0277781c?w=800&h=400&fit=crop" alt="Third slide" height={400} />
|
||||
<Carousel.Caption>
|
||||
<h3>Third Slide Label</h3>
|
||||
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>
|
||||
</Carousel.Caption>
|
||||
{["c1.png", "c2.jpg", "c3.jpg"].map((image, index) => (
|
||||
<Carousel.Item key={index} interval={3000}>
|
||||
<img className="d-block w-100" src={`/public/${image}`} alt={`Slide ${index + 1}`} height={300} />
|
||||
</Carousel.Item>
|
||||
))}
|
||||
</Carousel>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
) : (
|
||||
<Container className="d-flex justify-content-center align-items-center vh-100">
|
||||
<Card className="p-4 text-center" style={{ maxWidth: "400px", width: "100%" }}>
|
||||
<Card className="p-4 text-center shadow-lg rounded-3" style={{ maxWidth: "400px", width: "100%" }}>
|
||||
<Card.Body>
|
||||
<Card.Title className="fw-bold fs-3">Tiket Antrian</Card.Title>
|
||||
<hr />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user