Przebudowa - code review aplikaacji, podział na moduły.
This commit is contained in:
@@ -0,0 +1,353 @@
|
||||
import { endpoints } from "./config.js";
|
||||
import { trackEvent } from "./analytics.js";
|
||||
import { requireFullAccess } from "./access.js";
|
||||
import {
|
||||
buildBillRequestQueueMessage,
|
||||
buildWaiterCallQueueMessage,
|
||||
cacheOpenBills,
|
||||
ensureGuestActionAllowed,
|
||||
guestActionBlockedMessage,
|
||||
queueGuestAction,
|
||||
refreshGuestPendingActions,
|
||||
} from "./queue.js";
|
||||
import { showToast } from "./toast.js";
|
||||
import {
|
||||
getBillState,
|
||||
getHashParam,
|
||||
getTableParam,
|
||||
setBillState,
|
||||
} from "./state.js";
|
||||
|
||||
function sendApiSimulated(actionName, details) {
|
||||
console.log(`[SYMULACJA API] Akcja: ${actionName}`, details);
|
||||
// Przykładowe wysłanie docelowo:
|
||||
// if (window.socket && window.socket.readyState === WebSocket.OPEN) {
|
||||
// window.socket.send(JSON.stringify({ action: "sendUpstream", payload: { type: actionName, table: tableParam, ...details } }));
|
||||
// }
|
||||
}
|
||||
|
||||
export async function callWaiter(type) {
|
||||
if (type !== "order") return;
|
||||
|
||||
if (!(await ensureGuestActionAllowed("waiter_call"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const queued = await queueGuestAction("waiter_call", buildWaiterCallQueueMessage(), {
|
||||
waiterType: "order",
|
||||
});
|
||||
|
||||
if (!queued.ok) {
|
||||
if (queued.reason === "pending") {
|
||||
showToast(guestActionBlockedMessage("waiter_call"));
|
||||
} else {
|
||||
showToast("Nie udało się wysłać wezwania. Spróbuj ponownie za chwilę.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
trackEvent("waiter_call_requested", { waiterType: "order" });
|
||||
sendApiSimulated("CallWaiter_Order", { table: getTableParam() });
|
||||
showToast("Kelner wkrótce do Ciebie podejdzie!");
|
||||
}
|
||||
|
||||
export function openWaiterDialog() {
|
||||
requireFullAccess("waiter", () => {
|
||||
openWaiterDialogInternal();
|
||||
});
|
||||
}
|
||||
|
||||
export async function openWaiterDialogInternal() {
|
||||
if (!(await ensureGuestActionAllowed("waiter_call"))) {
|
||||
return;
|
||||
}
|
||||
document.getElementById("waiterModal").classList.add("active");
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
|
||||
export function closeWaiterDialog() {
|
||||
document.getElementById("waiterModal").classList.remove("active");
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
|
||||
export async function confirmCallWaiter() {
|
||||
closeWaiterDialog();
|
||||
await callWaiter("order");
|
||||
}
|
||||
|
||||
export async function proceedToBillPayment() {
|
||||
if (!(await ensureGuestActionAllowed("bill_request"))) {
|
||||
return;
|
||||
}
|
||||
goToStep("stepPayment");
|
||||
}
|
||||
|
||||
export function openBillDialog() {
|
||||
requireFullAccess("bill", () => {
|
||||
openBillDialogInternal();
|
||||
});
|
||||
}
|
||||
|
||||
export async function openBillDialogInternal() {
|
||||
await refreshGuestPendingActions();
|
||||
trackEvent("bill_dialog_opened");
|
||||
setBillState({ payment: "", doc: "", nip: "", company: null, selectedBillId: null });
|
||||
document.getElementById("billModal").classList.add("active");
|
||||
document.body.style.overflow = "hidden"; // Zablokuj scroll tła
|
||||
|
||||
document.getElementById("billLoading").classList.remove("hidden");
|
||||
document.getElementById("billListContainer").classList.add("hidden");
|
||||
goToStep("stepBillList");
|
||||
|
||||
try {
|
||||
const res = await fetch(`${endpoints.bills}?h=${encodeURIComponent(getHashParam())}`);
|
||||
const result = await res.json();
|
||||
|
||||
if (result.status === "success" && result.data.length > 0) {
|
||||
const bills = result.data;
|
||||
cacheOpenBills(bills);
|
||||
|
||||
if (bills.length === 1) {
|
||||
showBillReview(bills[0]);
|
||||
document.getElementById("btnBackToBills").style.display = "none";
|
||||
} else {
|
||||
renderBillList(bills);
|
||||
document.getElementById("btnBackToBills").style.display = "block";
|
||||
}
|
||||
} else {
|
||||
document.getElementById("billLoading").innerHTML = "Brak otwartych rachunków do opłacenia.";
|
||||
}
|
||||
} catch (err) {
|
||||
document.getElementById("billLoading").innerHTML = "Błąd pobierania rachunków.";
|
||||
}
|
||||
}
|
||||
|
||||
function renderBillList(bills) {
|
||||
document.getElementById("billLoading").classList.add("hidden");
|
||||
document.getElementById("billListContainer").classList.remove("hidden");
|
||||
|
||||
const container = document.getElementById("billListItems");
|
||||
container.innerHTML = "";
|
||||
|
||||
bills.forEach((b) => {
|
||||
const div = document.createElement("div");
|
||||
div.className = "option-card";
|
||||
div.style.flexDirection = "row";
|
||||
div.style.justifyContent = "space-between";
|
||||
div.style.padding = "15px";
|
||||
div.onclick = () => showBillReview(b);
|
||||
|
||||
const numerFormat = b.numer ? `#${b.numer}` : "Rachunek";
|
||||
div.innerHTML = `
|
||||
<div>
|
||||
<div style="font-weight:bold;">${numerFormat}</div>
|
||||
<div style="font-size:12px; color:var(--text-muted);">${b.opis}</div>
|
||||
</div>
|
||||
<div style="font-weight:bold; color:var(--primary);">${b.suma.toFixed(2)} PLN</div>
|
||||
`;
|
||||
container.appendChild(div);
|
||||
});
|
||||
}
|
||||
|
||||
export function goBackToBillList() {
|
||||
goToStep("stepBillList");
|
||||
}
|
||||
|
||||
export function showBillReview(bill) {
|
||||
const billState = getBillState();
|
||||
billState.selectedBillId = bill.id;
|
||||
|
||||
const content = document.getElementById("billReviewContent");
|
||||
content.innerHTML = "";
|
||||
|
||||
bill.pozycje.forEach((p) => {
|
||||
const div = document.createElement("div");
|
||||
div.style.display = "flex";
|
||||
div.style.justifyContent = "space-between";
|
||||
div.style.marginBottom = "8px";
|
||||
div.style.borderBottom = "1px solid rgba(255,255,255,0.05)";
|
||||
div.style.paddingBottom = "8px";
|
||||
|
||||
div.innerHTML = `
|
||||
<div style="flex:1;">
|
||||
<div style="font-weight:600; font-size: 14px;">${p.nazwa}</div>
|
||||
<div style="font-size:12px; color:var(--text-muted);">${p.ilosc} x ${p.cena.toFixed(2)} PLN</div>
|
||||
</div>
|
||||
<div style="font-weight:600;">${p.wartosc.toFixed(2)} PLN</div>
|
||||
`;
|
||||
content.appendChild(div);
|
||||
});
|
||||
|
||||
document.getElementById("billTotalAmount").textContent = bill.suma.toFixed(2) + " PLN";
|
||||
goToStep("stepBillReview");
|
||||
}
|
||||
|
||||
export function closeBillDialog() {
|
||||
document.getElementById("billModal").classList.remove("active");
|
||||
document.body.style.overflow = ""; // Odblokuj scroll tła
|
||||
}
|
||||
|
||||
export function goToStep(stepId) {
|
||||
document.querySelectorAll(".step").forEach((el) => el.classList.remove("active"));
|
||||
document.getElementById(stepId).classList.add("active");
|
||||
}
|
||||
|
||||
export function selectPayment(method) {
|
||||
getBillState().payment = method;
|
||||
goToStep("stepDocument");
|
||||
}
|
||||
|
||||
export async function selectDocument(docType) {
|
||||
const billState = getBillState();
|
||||
billState.doc = docType;
|
||||
if (docType === "paragon") {
|
||||
if (!(await ensureGuestActionAllowed("bill_request"))) {
|
||||
return;
|
||||
}
|
||||
const queued = await queueGuestAction("bill_request", buildBillRequestQueueMessage("paragon"), {
|
||||
payment: billState.payment || null,
|
||||
docType: "paragon",
|
||||
});
|
||||
if (!queued.ok) {
|
||||
if (queued.reason === "pending") {
|
||||
showToast(guestActionBlockedMessage("bill_request"));
|
||||
} else {
|
||||
showToast("Nie udało się wysłać prośby o rachunek. Spróbuj ponownie za chwilę.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
trackEvent("bill_request_sent", { docType: "paragon" });
|
||||
closeBillDialog();
|
||||
sendApiSimulated("CallWaiter_Bill", {
|
||||
table: getTableParam(),
|
||||
billId: billState.selectedBillId,
|
||||
payment: billState.payment,
|
||||
doc: "paragon",
|
||||
});
|
||||
showToast("Kelner przyniesie paragon do opłacenia!");
|
||||
} else {
|
||||
goToStep("stepNIP");
|
||||
document.getElementById("nipInput").value = "";
|
||||
setTimeout(() => document.getElementById("nipInput").focus(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchGUS() {
|
||||
const nip = document.getElementById("nipInput").value.replace(/[\s-]/g, "");
|
||||
if (nip.length < 10) {
|
||||
alert("Wprowadź poprawny numer NIP.");
|
||||
return;
|
||||
}
|
||||
const btn = document.getElementById("btnGUS");
|
||||
btn.textContent = "Szukam...";
|
||||
btn.disabled = true;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${endpoints.gusLookup}?nip=${encodeURIComponent(nip)}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status && result.data) {
|
||||
const data = result.data;
|
||||
|
||||
let fullStreet = data.street || "";
|
||||
if (data.propertyNumber) fullStreet += " " + data.propertyNumber;
|
||||
if (data.apartmentNumber) fullStreet += "/" + data.apartmentNumber;
|
||||
|
||||
const billState = getBillState();
|
||||
billState.nip = nip;
|
||||
billState.company = {
|
||||
name: data.name,
|
||||
street: fullStreet.trim(),
|
||||
zip: data.zipCode,
|
||||
city: data.city,
|
||||
nip: data.nip,
|
||||
};
|
||||
|
||||
document.getElementById("cmpName").value = billState.company.name;
|
||||
document.getElementById("cmpStreet").value = billState.company.street;
|
||||
document.getElementById("cmpZip").value = billState.company.zip;
|
||||
document.getElementById("cmpCity").value = billState.company.city;
|
||||
document.getElementById("cmpNip").value = "NIP: " + billState.company.nip;
|
||||
|
||||
// reset do readonly
|
||||
document.getElementById("cmpName").readOnly = true;
|
||||
document.getElementById("cmpStreet").readOnly = true;
|
||||
document.getElementById("cmpZip").readOnly = true;
|
||||
document.getElementById("cmpCity").readOnly = true;
|
||||
document.getElementById("btnEditCompany").textContent = "Popraw ręcznie";
|
||||
|
||||
goToStep("stepVerify");
|
||||
} else {
|
||||
alert("Nie udało się pobrać danych z GUS dla podanego NIP-u.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Błąd pobierania danych z GUS:", error);
|
||||
alert("Błąd połączenia z API GUS.");
|
||||
} finally {
|
||||
btn.textContent = "Pobierz z GUS";
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
export function editCompanyData() {
|
||||
const n = document.getElementById("cmpName");
|
||||
const s = document.getElementById("cmpStreet");
|
||||
const z = document.getElementById("cmpZip");
|
||||
const c = document.getElementById("cmpCity");
|
||||
const btn = document.getElementById("btnEditCompany");
|
||||
|
||||
if (n.readOnly) {
|
||||
n.readOnly = false;
|
||||
s.readOnly = false;
|
||||
z.readOnly = false;
|
||||
c.readOnly = false;
|
||||
n.focus();
|
||||
btn.textContent = "Zakończ edycję";
|
||||
} else {
|
||||
n.readOnly = true;
|
||||
s.readOnly = true;
|
||||
z.readOnly = true;
|
||||
c.readOnly = true;
|
||||
btn.textContent = "Popraw ręcznie";
|
||||
}
|
||||
}
|
||||
|
||||
export async function confirmInvoice() {
|
||||
const billState = getBillState();
|
||||
billState.company.name = document.getElementById("cmpName").value;
|
||||
billState.company.street = document.getElementById("cmpStreet").value;
|
||||
billState.company.zip = document.getElementById("cmpZip").value;
|
||||
billState.company.city = document.getElementById("cmpCity").value;
|
||||
|
||||
if (!(await ensureGuestActionAllowed("bill_request"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const queued = await queueGuestAction("bill_request", buildBillRequestQueueMessage("faktura"), {
|
||||
payment: billState.payment || null,
|
||||
docType: "faktura",
|
||||
nip: billState.nip || null,
|
||||
company: billState.company || null,
|
||||
});
|
||||
|
||||
if (!queued.ok) {
|
||||
if (queued.reason === "pending") {
|
||||
showToast(guestActionBlockedMessage("bill_request"));
|
||||
} else {
|
||||
showToast("Nie udało się wysłać prośby o rachunek. Spróbuj ponownie za chwilę.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
closeBillDialog();
|
||||
trackEvent("bill_request_sent", { docType: "faktura" });
|
||||
sendApiSimulated("CallWaiter_Bill", {
|
||||
table: getTableParam(),
|
||||
billId: billState.selectedBillId,
|
||||
payment: billState.payment,
|
||||
doc: "faktura",
|
||||
nip: billState.nip,
|
||||
company: billState.company,
|
||||
});
|
||||
showToast("Dziękujemy! Prośba o fakturę została wysłana.");
|
||||
}
|
||||
Reference in New Issue
Block a user