212 lines
7.9 KiB
React
212 lines
7.9 KiB
React
import React, { useContext, useEffect, useState } from 'react';
|
|
import { Button, Table } from 'react-bootstrap';
|
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
|
import { useInterval } from '../../hooks/hooks.jsx';
|
|
import { fetchData } from '../../fetching/Fetch.js';
|
|
import { SERVER_URL } from '../../constants.js';
|
|
import { Link, useLocation, useParams } from 'react-router-dom';
|
|
import { UserContext } from '../../context/UserContext.jsx';
|
|
import { getActiveStation, saveActiveStation } from '../../utils/activeStation.js';
|
|
|
|
const styles = {
|
|
stationRow: {
|
|
backgroundColor: '#ADD8E6',
|
|
},
|
|
};
|
|
|
|
export default function ShowQueuesForTellerPage() {
|
|
const url = `${SERVER_URL}/api/v1/`;
|
|
const [tickets, setTickets] = useState([]);
|
|
const [usedUndo, setUsedUndo] = useState(false);
|
|
const [timedOut, setTimedOut] = useState(false);
|
|
const [stationLabel, setStationLabel] = useState(null);
|
|
|
|
const { stationId } = useParams();
|
|
const location = useLocation();
|
|
const { user } = useContext(UserContext);
|
|
const tenantCode = user?.tenantCode;
|
|
|
|
useEffect(() => {
|
|
fetchTicketsForTellerStation();
|
|
}, [stationId]);
|
|
|
|
useEffect(() => {
|
|
const fromNav = location.state;
|
|
if (fromNav?.station?.name) {
|
|
const next = {
|
|
stationId: Number(stationId),
|
|
stationName: fromNav.station.name,
|
|
branchId: fromNav.branch?.id ?? null,
|
|
branchName: fromNav.branch?.name ?? null,
|
|
};
|
|
saveActiveStation(next);
|
|
setStationLabel(next);
|
|
return;
|
|
}
|
|
|
|
const fromSession = getActiveStation(stationId);
|
|
if (fromSession?.stationName) {
|
|
setStationLabel(fromSession);
|
|
return;
|
|
}
|
|
|
|
if (!tenantCode) {
|
|
setStationLabel({ stationId: Number(stationId), stationName: `Station ${stationId}` });
|
|
return;
|
|
}
|
|
|
|
fetchData(`${url}branches/${encodeURIComponent(tenantCode)}`, 'GET')
|
|
.then(({ data, success }) => {
|
|
if (!success || !Array.isArray(data)) {
|
|
setStationLabel({
|
|
stationId: Number(stationId),
|
|
stationName: `Station ${stationId}`,
|
|
});
|
|
return;
|
|
}
|
|
|
|
for (const branch of data) {
|
|
const station = branch.tellerStations?.find(
|
|
(item) => Number(item.id) === Number(stationId)
|
|
);
|
|
if (station) {
|
|
const next = {
|
|
stationId: Number(stationId),
|
|
stationName: station.name,
|
|
branchId: branch.id,
|
|
branchName: branch.name,
|
|
};
|
|
saveActiveStation(next);
|
|
setStationLabel(next);
|
|
return;
|
|
}
|
|
}
|
|
|
|
setStationLabel({
|
|
stationId: Number(stationId),
|
|
stationName: `Station ${stationId}`,
|
|
});
|
|
})
|
|
.catch(() => {
|
|
setStationLabel({
|
|
stationId: Number(stationId),
|
|
stationName: `Station ${stationId}`,
|
|
});
|
|
});
|
|
}, [stationId, tenantCode, location.state, url]);
|
|
|
|
useInterval(fetchTicketsForTellerStation, 10000);
|
|
|
|
function fetchTicketsForTellerStation() {
|
|
fetchData(`${url}stations/${stationId}/tickets`, 'GET')
|
|
.then((response) => response.data)
|
|
.then(setTickets)
|
|
.catch(console.error);
|
|
}
|
|
|
|
function advanceQueue() {
|
|
fetchData(`${url}teller/advance-queue/${stationId}`, 'POST')
|
|
.then(fetchTicketsForTellerStation)
|
|
.then(() => setUsedUndo(false))
|
|
.then(timeOutTeller)
|
|
.catch(console.error);
|
|
}
|
|
|
|
function undoQueue() {
|
|
fetchData(`${url}teller/undo-queue/${stationId}`, 'POST')
|
|
.then(fetchTicketsForTellerStation)
|
|
.then(() => setUsedUndo(true))
|
|
.catch(console.error);
|
|
}
|
|
|
|
function timeOutTeller() {
|
|
setTimedOut(true);
|
|
setTimeout(() => setTimedOut(false), 5000);
|
|
// Can't advance more often than every 5 seconds.
|
|
}
|
|
|
|
const hasAssignedTicket = tickets.some((ticket) => ticket.station?.id == stationId);
|
|
|
|
return (
|
|
<div className="text-center mt-5">
|
|
<h1>Queues</h1>
|
|
{stationLabel ? (
|
|
<p className="mb-3" style={{ fontSize: '1.25rem', color: '#334257' }}>
|
|
<strong>{stationLabel.stationName}</strong>
|
|
{stationLabel.branchName ? (
|
|
<span className="text-muted"> · {stationLabel.branchName}</span>
|
|
) : null}
|
|
</p>
|
|
) : null}
|
|
<div className="d-flex gap-2 justify-content-center flex-wrap">
|
|
<Button
|
|
variant="primary"
|
|
style={{ backgroundColor: '#548CA8', color: 'white', borderColor: '#548CA8' }}
|
|
onClick={advanceQueue}
|
|
disabled={timedOut}
|
|
>
|
|
Nombor Giliran Seterusnya
|
|
</Button>
|
|
<Button
|
|
variant="primary"
|
|
style={{ backgroundColor: '#548CA8', color: 'white', borderColor: '#548CA8' }}
|
|
onClick={undoQueue}
|
|
disabled={usedUndo || !hasAssignedTicket}
|
|
>
|
|
Patah balik
|
|
</Button>
|
|
<Button
|
|
variant="primary"
|
|
style={{ backgroundColor: '#548CA8', color: 'white', borderColor: '#548CA8' }}
|
|
onClick={fetchTicketsForTellerStation}
|
|
>
|
|
Muat semula
|
|
</Button>
|
|
<Link to={`/display/${stationId}`} target="_blank" rel="noopener noreferrer">
|
|
<Button variant="secondary">Tiket semasa</Button>
|
|
</Link>
|
|
{tenantCode && stationLabel?.branchId ? (
|
|
<Link
|
|
to={`/display/branch/${encodeURIComponent(tenantCode)}/${stationLabel.branchId}`}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
<Button variant="secondary">Paparan TV</Button>
|
|
</Link>
|
|
) : null}
|
|
</div>
|
|
<div style={{ marginTop: '20px' }}>
|
|
<Table striped bordered hover>
|
|
<thead>
|
|
<tr>
|
|
<th>Nombor tiket</th>
|
|
<th>Perkhidmatan</th>
|
|
<th>Dibuat pada</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{tickets.map((ticket, index) => {
|
|
const createdAt = new Date(ticket.createdAt);
|
|
return (
|
|
<tr key={index}>
|
|
<td
|
|
style={
|
|
ticket.station?.id == stationId
|
|
? styles.stationRow
|
|
: {}
|
|
}
|
|
>
|
|
{ticket.number}
|
|
</td>
|
|
<td>{ticket.service.name}</td>
|
|
<td>{createdAt.toLocaleString()}</td>
|
|
</tr>
|
|
);
|
|
})}
|
|
</tbody>
|
|
</Table>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|