Dev/v1.0 (#1)
Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local> Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local> Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
const ACTIVE_STATION_KEY = 'qms_teller_active_station';
|
||||
|
||||
export function saveActiveStation({ stationId, stationName, branchId, branchName }) {
|
||||
sessionStorage.setItem(
|
||||
ACTIVE_STATION_KEY,
|
||||
JSON.stringify({
|
||||
stationId: Number(stationId),
|
||||
stationName,
|
||||
branchId: branchId != null ? Number(branchId) : null,
|
||||
branchName: branchName ?? null,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function getActiveStation(stationId) {
|
||||
try {
|
||||
const raw = sessionStorage.getItem(ACTIVE_STATION_KEY);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw);
|
||||
if (stationId != null && Number(parsed.stationId) !== Number(stationId)) {
|
||||
return null;
|
||||
}
|
||||
return parsed;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function clearActiveStation() {
|
||||
sessionStorage.removeItem(ACTIVE_STATION_KEY);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
const CALL_SOUND_URL = '/sounds/header-sound.mp3';
|
||||
|
||||
let sharedAudio = null;
|
||||
let unlocked = false;
|
||||
|
||||
function getCallAudio() {
|
||||
if (!sharedAudio) {
|
||||
sharedAudio = new Audio(CALL_SOUND_URL);
|
||||
sharedAudio.preload = 'auto';
|
||||
}
|
||||
return sharedAudio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call once after a user gesture (click/tap) so later plays are allowed.
|
||||
*/
|
||||
export function unlockQueueCallSound() {
|
||||
if (unlocked) return;
|
||||
try {
|
||||
const audio = getCallAudio();
|
||||
audio.muted = true;
|
||||
const playPromise = audio.play();
|
||||
if (playPromise?.then) {
|
||||
playPromise
|
||||
.then(() => {
|
||||
audio.pause();
|
||||
audio.currentTime = 0;
|
||||
audio.muted = false;
|
||||
unlocked = true;
|
||||
})
|
||||
.catch(() => {
|
||||
// Still mark unlocked so we keep trying on real calls.
|
||||
audio.muted = false;
|
||||
unlocked = true;
|
||||
});
|
||||
} else {
|
||||
audio.muted = false;
|
||||
unlocked = true;
|
||||
}
|
||||
} catch {
|
||||
unlocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the queue-call notification chime.
|
||||
* Safe to call repeatedly; restarts from the beginning each time.
|
||||
*/
|
||||
export function playQueueCallSound() {
|
||||
try {
|
||||
const audio = getCallAudio();
|
||||
audio.muted = false;
|
||||
audio.currentTime = 0;
|
||||
const playPromise = audio.play();
|
||||
if (playPromise?.catch) {
|
||||
playPromise.catch((error) => {
|
||||
console.warn('Could not play queue call sound:', error);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Could not play queue call sound:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a stable map of stationId -> ticket number for currently serving tickets.
|
||||
*/
|
||||
export function servingSnapshot(tickets) {
|
||||
const map = {};
|
||||
for (const ticket of tickets) {
|
||||
if (ticket?.station?.id != null && ticket?.number != null) {
|
||||
map[String(ticket.station.id)] = String(ticket.number);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any station got a new/different ticket number vs the previous snapshot.
|
||||
*/
|
||||
export function hasNewServingCall(previous, next) {
|
||||
if (!previous) return false;
|
||||
for (const [stationId, number] of Object.entries(next)) {
|
||||
if (previous[stationId] !== number) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
const TOKEN_KEY = 'teller_token';
|
||||
const USER_DATA_KEY = 'teller_userData';
|
||||
|
||||
/** Matches backend jwt.token-validity-time (PT30M). */
|
||||
const SESSION_MAX_AGE_SECONDS = 30 * 60;
|
||||
|
||||
function getCookie(name) {
|
||||
const prefix = `${encodeURIComponent(name)}=`;
|
||||
const parts = document.cookie ? document.cookie.split('; ') : [];
|
||||
|
||||
for (const part of parts) {
|
||||
if (part.startsWith(prefix)) {
|
||||
return decodeURIComponent(part.slice(prefix.length));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function setCookie(name, value, maxAgeSeconds = SESSION_MAX_AGE_SECONDS) {
|
||||
const secure = window.location.protocol === 'https:' ? '; Secure' : '';
|
||||
document.cookie = [
|
||||
`${encodeURIComponent(name)}=${encodeURIComponent(value)}`,
|
||||
'Path=/',
|
||||
`Max-Age=${maxAgeSeconds}`,
|
||||
'SameSite=Lax',
|
||||
secure,
|
||||
].join('; ');
|
||||
}
|
||||
|
||||
function removeCookie(name) {
|
||||
document.cookie = `${encodeURIComponent(name)}=; Path=/; Max-Age=0; SameSite=Lax`;
|
||||
}
|
||||
|
||||
export function getToken() {
|
||||
return getCookie(TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function setToken(token) {
|
||||
if (token == null || token === '') {
|
||||
removeCookie(TOKEN_KEY);
|
||||
return;
|
||||
}
|
||||
setCookie(TOKEN_KEY, token);
|
||||
}
|
||||
|
||||
export function getUserData() {
|
||||
const raw = getCookie(USER_DATA_KEY) ?? sessionStorage.getItem(USER_DATA_KEY);
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(raw);
|
||||
} catch {
|
||||
removeCookie(USER_DATA_KEY);
|
||||
sessionStorage.removeItem(USER_DATA_KEY);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function setUserData(userData) {
|
||||
if (userData == null) {
|
||||
removeCookie(USER_DATA_KEY);
|
||||
sessionStorage.removeItem(USER_DATA_KEY);
|
||||
return;
|
||||
}
|
||||
|
||||
const serialized = JSON.stringify(userData);
|
||||
setCookie(USER_DATA_KEY, serialized);
|
||||
sessionStorage.setItem(USER_DATA_KEY, serialized);
|
||||
}
|
||||
|
||||
export function setSession({ token, userData } = {}) {
|
||||
if (token !== undefined) {
|
||||
setToken(token);
|
||||
}
|
||||
if (userData !== undefined) {
|
||||
setUserData(userData);
|
||||
}
|
||||
}
|
||||
|
||||
export function clearSession() {
|
||||
removeCookie(TOKEN_KEY);
|
||||
removeCookie(USER_DATA_KEY);
|
||||
sessionStorage.removeItem(USER_DATA_KEY);
|
||||
}
|
||||
Reference in New Issue
Block a user