DONE: queue management for customer side to get queue number, add logo to teller display, advertisement module

This commit is contained in:
ISMAIL MASSERAN
2026-07-23 10:50:35 +08:00
parent a671f7ad5c
commit 9bc06f1d5b
72 changed files with 13919 additions and 182 deletions
+6
View File
@@ -80,3 +80,9 @@ export function createTicket(input: {
export function getTicketById(ticketId: number | string) {
return request<Ticket>(`/api/v1/tickets/${ticketId}`);
}
export function getTicketsForDevice(deviceToken: string) {
return request<TicketResponse[]>(
`/api/v1/tickets/devices/${encodeURIComponent(deviceToken)}`
);
}
+67
View File
@@ -0,0 +1,67 @@
const DEFAULT_QR_SECRET = "qms-branch-qr-v1";
function getQrSecret() {
return process.env.QR_TOKEN_SECRET || DEFAULT_QR_SECRET;
}
function toBase64Url(bytes: Uint8Array) {
let binary = "";
bytes.forEach((byte) => {
binary += String.fromCharCode(byte);
});
return btoa(binary)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/g, "");
}
function fromBase64Url(token: string) {
const padded = token.replace(/-/g, "+").replace(/_/g, "/");
const padLength = (4 - (padded.length % 4)) % 4;
const base64 = padded + "=".repeat(padLength);
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i += 1) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
function xorBytes(bytes: Uint8Array, secret: string) {
const key = new TextEncoder().encode(secret);
return bytes.map((byte, index) => byte ^ key[index % key.length]);
}
export type BranchQrPayload = {
tenantCode: string;
branchId: number;
};
export function encodeBranchQrToken(
tenantCode: string,
branchId: number,
secret = getQrSecret()
) {
const plain = `v1:${tenantCode.trim().toUpperCase()}:${Number(branchId)}`;
const plainBytes = new TextEncoder().encode(plain);
return toBase64Url(xorBytes(plainBytes, secret));
}
export function decodeBranchQrToken(
token: string,
secret = getQrSecret()
): BranchQrPayload | null {
try {
const plain = new TextDecoder().decode(
xorBytes(fromBase64Url(token), secret)
);
const match = /^v1:([^:]+):(\d+)$/.exec(plain);
if (!match) return null;
return {
tenantCode: match[1],
branchId: Number(match[2]),
};
} catch {
return null;
}
}
+1 -2
View File
@@ -1,4 +1,3 @@
export const SERVER_URL =
process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8080";
export const SERVER_URL = process.env.NEXT_PUBLIC_API_URL;
export const DEVICE_TOKEN_KEY = "qms_device_token";