995 lines
37 KiB
PHP
995 lines
37 KiB
PHP
<?php
|
|
require_once 'db/config.php';
|
|
$settings = [];
|
|
try {
|
|
$rows = db()->query("SELECT * FROM settings")->fetchAll(PDO::FETCH_ASSOC);
|
|
foreach ($rows as $r) {
|
|
$settings[$r['key']] = $r['value'];
|
|
}
|
|
} catch (Exception $e) {
|
|
// Fallback if DB fails
|
|
}
|
|
|
|
$title = $settings['customer_display_greeting_title'] ?? 'Welcome';
|
|
$subtitle = $settings['customer_display_greeting_text'] ?? 'We are ready to serve you.';
|
|
$slides = [];
|
|
if (!empty($settings['display_slide_1'])) $slides[] = $settings['display_slide_1'];
|
|
if (!empty($settings['display_slide_2'])) $slides[] = $settings['display_slide_2'];
|
|
if (!empty($settings['display_slide_3'])) $slides[] = $settings['display_slide_3'];
|
|
|
|
// Fallbacks
|
|
if (empty($slides)) {
|
|
$slides = [
|
|
'https://images.unsplash.com/photo-1441986300917-64674bd600d8?q=80&w=1920&auto=format&fit=crop',
|
|
'https://images.unsplash.com/photo-1472851294608-415170d4e897?q=80&w=1920&auto=format&fit=crop',
|
|
'https://images.unsplash.com/photo-1556742049-0cfed4f7a07d?q=80&w=1920&auto=format&fit=crop',
|
|
'https://images.unsplash.com/photo-1528698827591-e19ccd7bc23d?q=80&w=1920&auto=format&fit=crop'
|
|
];
|
|
}
|
|
|
|
$footerBrand = 'Meezan Accounting System';
|
|
$footerPoweredBy = 'omanapps.cloud';
|
|
$footerWhatsapp = '+96899359472';
|
|
$footerEmail = 'aalabry@gmail.com';
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Customer Display | Meezan Accounting System</title>
|
|
<meta name="description" content="Customer-facing POS display with a live basket, payment summary, and transaction totals.">
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?= time() ?>">
|
|
<style>
|
|
html, body {
|
|
height: 100%;
|
|
}
|
|
body {
|
|
background:
|
|
radial-gradient(circle at top left, rgba(59, 130, 246, 0.16), transparent 26%),
|
|
radial-gradient(circle at top right, rgba(15, 23, 42, 0.09), transparent 28%),
|
|
linear-gradient(180deg, #f8fbff 0%, var(--bg) 100%);
|
|
color: var(--text);
|
|
min-height: 100vh;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
transition: background-color 0.3s, color 0.3s;
|
|
}
|
|
.header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: 1rem 1.35rem;
|
|
background: rgba(255, 255, 255, 0.88);
|
|
border-bottom: 1px solid rgba(226, 232, 240, 0.9);
|
|
backdrop-filter: blur(22px);
|
|
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.06);
|
|
}
|
|
.brand-wrap {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.9rem;
|
|
min-width: 0;
|
|
}
|
|
.brand-mark {
|
|
width: 52px;
|
|
height: 52px;
|
|
border-radius: 16px;
|
|
display: grid;
|
|
place-items: center;
|
|
background: linear-gradient(135deg, var(--accent), #0ea5e9);
|
|
color: #fff;
|
|
font-size: 1.35rem;
|
|
box-shadow: 0 14px 34px rgba(59, 130, 246, 0.25);
|
|
flex-shrink: 0;
|
|
}
|
|
.brand-title {
|
|
font-size: 1.2rem;
|
|
font-weight: 800;
|
|
color: var(--primary);
|
|
letter-spacing: -0.02em;
|
|
}
|
|
.brand-subtitle {
|
|
font-size: 0.92rem;
|
|
color: var(--text-muted);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.header-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
gap: 0.75rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
.status-chip,
|
|
.customer-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.55rem;
|
|
padding: 0.7rem 0.95rem;
|
|
border-radius: 999px;
|
|
background: rgba(255, 255, 255, 0.92);
|
|
border: 1px solid rgba(203, 213, 225, 0.95);
|
|
box-shadow: 0 10px 22px rgba(15, 23, 42, 0.06);
|
|
color: var(--text);
|
|
font-weight: 600;
|
|
}
|
|
.status-chip {
|
|
color: var(--accent);
|
|
}
|
|
.customer-chip {
|
|
min-width: 150px;
|
|
justify-content: center;
|
|
}
|
|
.fullscreen-btn {
|
|
width: 46px;
|
|
height: 46px;
|
|
border-radius: 14px;
|
|
border: 1px solid rgba(203, 213, 225, 0.95);
|
|
background: rgba(255, 255, 255, 0.92);
|
|
color: var(--primary);
|
|
box-shadow: 0 10px 22px rgba(15, 23, 42, 0.06);
|
|
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
|
|
}
|
|
.fullscreen-btn:hover {
|
|
transform: translateY(-1px);
|
|
border-color: rgba(59, 130, 246, 0.45);
|
|
box-shadow: 0 14px 26px rgba(15, 23, 42, 0.08);
|
|
}
|
|
#activeCart,
|
|
#welcomeScreen {
|
|
flex: 1 1 auto;
|
|
min-height: 0;
|
|
}
|
|
.content {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1.7fr) minmax(320px, 0.95fr);
|
|
gap: 1.25rem;
|
|
padding: 1.25rem;
|
|
overflow: hidden;
|
|
}
|
|
.items-section,
|
|
.summary-card,
|
|
.grand-total {
|
|
border-radius: 26px;
|
|
border: 1px solid rgba(226, 232, 240, 0.9);
|
|
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.08);
|
|
}
|
|
.items-section {
|
|
background: rgba(255, 255, 255, 0.9);
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 0;
|
|
}
|
|
.section-head {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-end;
|
|
gap: 1rem;
|
|
padding: 1.4rem 1.5rem 1.1rem;
|
|
border-bottom: 1px solid rgba(226, 232, 240, 0.85);
|
|
background: linear-gradient(180deg, rgba(248, 250, 252, 0.9), rgba(255, 255, 255, 0.7));
|
|
}
|
|
.section-kicker {
|
|
font-size: 0.78rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
color: var(--accent);
|
|
margin-bottom: 0.45rem;
|
|
}
|
|
.section-title {
|
|
margin: 0;
|
|
font-size: clamp(1.45rem, 2vw, 2rem);
|
|
font-weight: 800;
|
|
letter-spacing: -0.03em;
|
|
color: var(--primary);
|
|
}
|
|
.section-summary {
|
|
padding: 0.7rem 0.95rem;
|
|
border-radius: 999px;
|
|
background: rgba(59, 130, 246, 0.08);
|
|
color: var(--accent);
|
|
font-weight: 700;
|
|
white-space: nowrap;
|
|
}
|
|
.items-list {
|
|
flex: 1;
|
|
min-height: 0;
|
|
overflow-y: auto;
|
|
padding: 1rem 1.1rem 1.2rem;
|
|
}
|
|
.cart-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: 1rem 1.15rem;
|
|
margin-bottom: 0.85rem;
|
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.94), rgba(248, 250, 252, 0.94));
|
|
border: 1px solid rgba(226, 232, 240, 0.9);
|
|
border-radius: 22px;
|
|
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.05);
|
|
}
|
|
.item-copy {
|
|
min-width: 0;
|
|
}
|
|
.item-name {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.12rem;
|
|
font-size: clamp(1rem, 1.3vw, 1.2rem);
|
|
font-weight: 800;
|
|
color: var(--primary);
|
|
word-break: break-word;
|
|
}
|
|
.item-name-primary {
|
|
color: var(--primary);
|
|
font-weight: 800;
|
|
line-height: 1.12;
|
|
}
|
|
.item-name-secondary {
|
|
color: var(--text-muted);
|
|
font-size: 0.82em;
|
|
font-weight: 600;
|
|
line-height: 1.08;
|
|
}
|
|
.item-name-ar {
|
|
direction: rtl;
|
|
}
|
|
.item-name-en {
|
|
direction: ltr;
|
|
}
|
|
.item-details {
|
|
color: var(--text-muted);
|
|
font-size: clamp(0.88rem, 1vw, 0.98rem);
|
|
margin-top: 0.3rem;
|
|
}
|
|
.item-price {
|
|
font-size: clamp(1rem, 1.35vw, 1.3rem);
|
|
font-weight: 800;
|
|
color: var(--accent);
|
|
white-space: nowrap;
|
|
text-align: end;
|
|
}
|
|
.totals-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
}
|
|
.summary-card {
|
|
background: rgba(255, 255, 255, 0.92);
|
|
padding: 1.45rem 1.45rem 1.3rem;
|
|
}
|
|
.summary-eyebrow {
|
|
font-size: 0.78rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
color: var(--accent);
|
|
margin-bottom: 0.7rem;
|
|
}
|
|
.summary-heading {
|
|
margin: 0;
|
|
font-size: clamp(1.2rem, 1.8vw, 1.55rem);
|
|
font-weight: 800;
|
|
letter-spacing: -0.03em;
|
|
color: var(--primary);
|
|
max-width: 18ch;
|
|
}
|
|
.summary-stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: 0.8rem;
|
|
margin: 1.15rem 0 1.25rem;
|
|
}
|
|
.stat-pill {
|
|
padding: 0.95rem 1rem;
|
|
border-radius: 20px;
|
|
background: linear-gradient(180deg, rgba(248, 250, 252, 0.95), rgba(255, 255, 255, 0.92));
|
|
border: 1px solid rgba(226, 232, 240, 0.9);
|
|
}
|
|
.stat-label {
|
|
display: block;
|
|
font-size: 0.82rem;
|
|
color: var(--text-muted);
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
.stat-value {
|
|
display: block;
|
|
font-size: clamp(1.1rem, 1.5vw, 1.45rem);
|
|
font-weight: 800;
|
|
color: var(--primary);
|
|
}
|
|
.total-rows {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0;
|
|
}
|
|
.total-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: 0.95rem 0;
|
|
font-size: clamp(1rem, 1.2vw, 1.08rem);
|
|
color: var(--text-muted);
|
|
border-bottom: 1px solid rgba(226, 232, 240, 0.85);
|
|
}
|
|
.total-row span:last-child {
|
|
font-weight: 700;
|
|
color: var(--text);
|
|
text-align: end;
|
|
}
|
|
.total-row:last-child {
|
|
border-bottom: 0;
|
|
padding-bottom: 0;
|
|
}
|
|
.total-row.text-danger span:last-child {
|
|
color: #dc2626;
|
|
}
|
|
.total-row.text-success span:last-child {
|
|
color: #059669;
|
|
}
|
|
.grand-total {
|
|
background: linear-gradient(135deg, var(--primary), var(--accent));
|
|
color: white;
|
|
padding: 1.35rem 1.45rem 1.45rem;
|
|
margin-top: auto;
|
|
box-shadow: 0 20px 50px rgba(15, 23, 42, 0.18);
|
|
}
|
|
.grand-total-top {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
gap: 1rem;
|
|
margin-bottom: 0.9rem;
|
|
}
|
|
.grand-total-label {
|
|
font-size: 0.82rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.16em;
|
|
text-transform: uppercase;
|
|
opacity: 0.78;
|
|
}
|
|
.grand-total-note {
|
|
margin-top: 0.45rem;
|
|
font-size: 0.96rem;
|
|
opacity: 0.88;
|
|
}
|
|
.grand-total-currency {
|
|
padding: 0.48rem 0.8rem;
|
|
border-radius: 999px;
|
|
background: rgba(255, 255, 255, 0.16);
|
|
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
font-weight: 800;
|
|
letter-spacing: 0.08em;
|
|
white-space: nowrap;
|
|
}
|
|
.grand-total-amount {
|
|
font-size: clamp(2.6rem, 5.2vw, 4.65rem);
|
|
font-weight: 800;
|
|
line-height: 1.02;
|
|
letter-spacing: -0.05em;
|
|
word-break: break-word;
|
|
}
|
|
.display-footer {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 0.9rem 1.2rem;
|
|
flex-wrap: wrap;
|
|
padding: 0.95rem 1.3rem 1rem;
|
|
background: rgba(255, 255, 255, 0.84);
|
|
border-top: 1px solid rgba(226, 232, 240, 0.9);
|
|
backdrop-filter: blur(22px);
|
|
box-shadow: 0 -10px 24px rgba(15, 23, 42, 0.04);
|
|
}
|
|
.footer-brand {
|
|
font-weight: 800;
|
|
color: var(--primary);
|
|
letter-spacing: -0.02em;
|
|
}
|
|
.footer-meta {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: flex-end;
|
|
gap: 0.7rem;
|
|
}
|
|
.footer-pill {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
padding: 0.55rem 0.8rem;
|
|
border-radius: 999px;
|
|
background: rgba(248, 250, 252, 0.96);
|
|
border: 1px solid rgba(226, 232, 240, 0.92);
|
|
color: var(--text);
|
|
font-weight: 600;
|
|
font-size: 0.92rem;
|
|
}
|
|
.footer-pill i {
|
|
color: var(--accent);
|
|
}
|
|
.welcome-screen {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin: 1.25rem;
|
|
border-radius: 28px;
|
|
overflow: hidden;
|
|
text-align: center;
|
|
color: white;
|
|
background: #0f172a;
|
|
box-shadow: 0 20px 50px rgba(15, 23, 42, 0.18);
|
|
}
|
|
.slideshow-bg {
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: 1;
|
|
}
|
|
.slideshow-bg::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(135deg, rgba(2, 6, 23, 0.86), rgba(15, 23, 42, 0.62), rgba(59, 130, 246, 0.28));
|
|
z-index: 2;
|
|
}
|
|
.slide {
|
|
position: absolute;
|
|
inset: 0;
|
|
background-size: cover;
|
|
background-position: center;
|
|
opacity: 0;
|
|
transform: scale(1.08);
|
|
transition: opacity 2s ease-in-out, transform 10s ease;
|
|
}
|
|
.slide.active {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
z-index: 1;
|
|
}
|
|
.welcome-content {
|
|
position: relative;
|
|
z-index: 10;
|
|
max-width: min(760px, calc(100% - 3rem));
|
|
padding: 2.25rem 2.4rem;
|
|
border-radius: 28px;
|
|
background: rgba(15, 23, 42, 0.34);
|
|
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
backdrop-filter: blur(16px);
|
|
box-shadow: 0 16px 40px rgba(2, 6, 23, 0.2);
|
|
animation: fadeIn 1s ease-out;
|
|
}
|
|
.welcome-tag {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.55rem 0.9rem;
|
|
border-radius: 999px;
|
|
margin-bottom: 1.1rem;
|
|
background: rgba(255, 255, 255, 0.12);
|
|
border: 1px solid rgba(255, 255, 255, 0.16);
|
|
font-size: 0.9rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
.welcome-logo {
|
|
max-height: 14vh;
|
|
max-width: min(260px, 58vw);
|
|
margin-bottom: 1.35rem;
|
|
filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.32));
|
|
}
|
|
.welcome-icon {
|
|
font-size: 11vmin;
|
|
margin-bottom: 1rem;
|
|
color: rgba(255, 255, 255, 0.84);
|
|
text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
|
|
}
|
|
.welcome-title {
|
|
margin: 0;
|
|
font-size: clamp(2rem, 4vw, 3.3rem);
|
|
font-weight: 800;
|
|
letter-spacing: -0.04em;
|
|
}
|
|
.welcome-subtitle {
|
|
margin: 1rem auto 0;
|
|
max-width: 28ch;
|
|
font-size: clamp(1rem, 1.7vw, 1.45rem);
|
|
color: rgba(255, 255, 255, 0.82);
|
|
}
|
|
@keyframes fadeIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(18px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
::-webkit-scrollbar-track {
|
|
background: rgba(226, 232, 240, 0.45);
|
|
border-radius: 999px;
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background: rgba(148, 163, 184, 0.7);
|
|
border-radius: 999px;
|
|
}
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: rgba(100, 116, 139, 0.95);
|
|
}
|
|
@media (max-width: 1200px) {
|
|
.content {
|
|
grid-template-columns: minmax(0, 1.45fr) 320px;
|
|
}
|
|
}
|
|
@media (max-width: 992px) {
|
|
body {
|
|
overflow: auto;
|
|
}
|
|
.header,
|
|
.display-footer {
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
}
|
|
.content {
|
|
grid-template-columns: 1fr;
|
|
padding: 1rem;
|
|
overflow: visible;
|
|
}
|
|
.welcome-screen {
|
|
margin: 1rem;
|
|
min-height: 62vh;
|
|
}
|
|
.summary-heading {
|
|
max-width: none;
|
|
}
|
|
}
|
|
@media (max-height: 820px) {
|
|
.header {
|
|
padding-top: 0.9rem;
|
|
padding-bottom: 0.9rem;
|
|
}
|
|
.content {
|
|
padding-top: 1rem;
|
|
padding-bottom: 1rem;
|
|
}
|
|
.section-head {
|
|
padding-top: 1.15rem;
|
|
padding-bottom: 0.95rem;
|
|
}
|
|
.summary-card,
|
|
.grand-total {
|
|
padding-top: 1.15rem;
|
|
padding-bottom: 1.15rem;
|
|
}
|
|
.grand-total-amount {
|
|
font-size: clamp(2.3rem, 4.5vw, 3.9rem);
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header class="header">
|
|
<div class="brand-wrap">
|
|
<div class="brand-mark">
|
|
<i class="bi bi-display"></i>
|
|
</div>
|
|
<div>
|
|
<div class="brand-title">Customer Display</div>
|
|
<div class="brand-subtitle">Live order summary for the customer-facing screen</div>
|
|
</div>
|
|
</div>
|
|
<div class="header-actions">
|
|
<div id="debugInfo" class="status-chip" style="display: none;">
|
|
<i class="bi bi-bag-check"></i>
|
|
<span id="debugInfoText">Items: 0</span>
|
|
</div>
|
|
<div class="customer-chip">
|
|
<i class="bi bi-person-circle"></i>
|
|
<span id="customerName">Welcome</span>
|
|
</div>
|
|
<button onclick="toggleFullScreen()" class="fullscreen-btn" title="Toggle Fullscreen" aria-label="Toggle Fullscreen">
|
|
<i class="bi bi-arrows-fullscreen"></i>
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<div id="activeCart" class="content" style="display: none;">
|
|
<section class="items-section" aria-label="Current basket items">
|
|
<div class="section-head">
|
|
<div>
|
|
<div class="section-kicker" id="sectionKicker">Current Basket</div>
|
|
<h1 class="section-title" id="sectionTitle">Order Items</h1>
|
|
</div>
|
|
<div class="section-summary" id="sectionSummaryText">0 items • 0 qty</div>
|
|
</div>
|
|
<div id="itemsList" class="items-list"></div>
|
|
</section>
|
|
|
|
<aside class="totals-section" aria-label="Payment summary">
|
|
<div class="summary-card">
|
|
<div class="summary-eyebrow" id="summaryEyebrow">Payment Summary</div>
|
|
<h2 class="summary-heading" id="summaryHeading">Clean, balanced totals with less visual weight.</h2>
|
|
|
|
<div class="summary-stats">
|
|
<div class="stat-pill">
|
|
<span class="stat-label" id="labelItemsStat">Items</span>
|
|
<span class="stat-value" id="displayItemCount">0</span>
|
|
</div>
|
|
<div class="stat-pill">
|
|
<span class="stat-label" id="labelQuantityStat">Quantity</span>
|
|
<span class="stat-value" id="displayQuantity">0</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="total-rows">
|
|
<div class="total-row">
|
|
<span id="labelSubtotal">Subtotal</span>
|
|
<span id="displaySubtotal">OMR 0.000</span>
|
|
</div>
|
|
<div id="displayTaxRow" class="total-row text-muted">
|
|
<span id="labelVAT">VAT</span>
|
|
<span id="displayTax">OMR 0.000</span>
|
|
</div>
|
|
<div id="displayDiscountRow" class="total-row text-danger" style="display: none;">
|
|
<span id="labelDiscount">Discount</span>
|
|
<span id="displayDiscount">- OMR 0.000</span>
|
|
</div>
|
|
<div id="displayLoyaltyRow" class="total-row text-success" style="display: none;">
|
|
<span id="labelLoyalty">Loyalty Redeemed</span>
|
|
<span id="displayLoyalty">- OMR 0.000</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grand-total">
|
|
<div class="grand-total-top">
|
|
<div>
|
|
<div class="grand-total-label" id="labelTotal">Total to Pay</div>
|
|
<div class="grand-total-note" id="labelTotalNote">Please review before payment</div>
|
|
</div>
|
|
<div class="grand-total-currency" id="displayCurrency">OMR</div>
|
|
</div>
|
|
<div class="grand-total-amount"><span id="displayTotalValue">0.000</span></div>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
|
|
<div id="welcomeScreen" class="welcome-screen">
|
|
<div class="slideshow-bg" id="slideshow">
|
|
<?php foreach ($slides as $i => $url): ?>
|
|
<div class="slide <?= $i === 0 ? 'active' : '' ?>" style="background-image: url('<?= htmlspecialchars($url) ?>');"></div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<div class="welcome-content">
|
|
<div class="welcome-tag"><i class="bi bi-stars"></i> <?= htmlspecialchars($footerBrand) ?></div>
|
|
<?php if (!empty($settings['company_logo']) && file_exists($settings['company_logo'])): ?>
|
|
<img src="<?= htmlspecialchars($settings['company_logo']) ?>?v=<?= time() ?>" alt="Store Logo" class="welcome-logo">
|
|
<?php elseif (file_exists('uploads/logo.png')): ?>
|
|
<img src="uploads/logo.png?v=<?= time() ?>" alt="Store Logo" class="welcome-logo">
|
|
<?php else: ?>
|
|
<div class="welcome-icon"><i class="bi bi-shop"></i></div>
|
|
<?php endif; ?>
|
|
<h1 class="welcome-title"><?= htmlspecialchars($title) ?></h1>
|
|
<p class="welcome-subtitle"><?= htmlspecialchars($subtitle) ?></p>
|
|
</div>
|
|
</div>
|
|
|
|
<footer class="display-footer">
|
|
<div class="footer-brand"><?= htmlspecialchars($footerBrand) ?></div>
|
|
<div class="footer-meta">
|
|
<span class="footer-pill"><i class="bi bi-globe2"></i> Powered By: <?= htmlspecialchars($footerPoweredBy) ?></span>
|
|
<span class="footer-pill"><i class="bi bi-whatsapp"></i> WhatsApp: <?= htmlspecialchars($footerWhatsapp) ?></span>
|
|
<span class="footer-pill"><i class="bi bi-envelope"></i> Email: <?= htmlspecialchars($footerEmail) ?></span>
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
let lastTimestamp = 0;
|
|
let currentCurrency = 'OMR';
|
|
|
|
function formatMoney(amount) {
|
|
return currentCurrency + ' ' + parseFloat(amount || 0).toFixed(3);
|
|
}
|
|
|
|
function formatMoneyValue(amount) {
|
|
return parseFloat(amount || 0).toFixed(3);
|
|
}
|
|
|
|
function formatQuantity(value) {
|
|
const qty = parseFloat(value || 0);
|
|
return Number.isInteger(qty) ? qty.toFixed(0) : qty.toFixed(2);
|
|
}
|
|
|
|
function decodeHtmlText(value) {
|
|
const textarea = document.createElement('textarea');
|
|
textarea.innerHTML = String(value ?? '');
|
|
return textarea.value;
|
|
}
|
|
|
|
function hasArabicText(value) {
|
|
return /[-ۿ]/.test(String(value || ''));
|
|
}
|
|
|
|
function normalizeNameText(value) {
|
|
return decodeHtmlText(String(value ?? '').replace(/<[^>]*>/g, ' '))
|
|
.replace(/\s+/g, ' ')
|
|
.trim();
|
|
}
|
|
|
|
function extractItemNameLines(item, isAr) {
|
|
const directLines = [
|
|
normalizeNameText(item.nameAr || item.name_ar || ''),
|
|
normalizeNameText(item.nameEn || item.name_en || '')
|
|
].filter(Boolean);
|
|
|
|
if (directLines.length > 0) {
|
|
return [...new Set(directLines)];
|
|
}
|
|
|
|
const rawName = String(item.name || '').trim();
|
|
if (!rawName) {
|
|
return [isAr ? 'صنف' : 'Item'];
|
|
}
|
|
|
|
const parsedLines = decodeHtmlText(
|
|
rawName
|
|
.replace(/<\s*br\s*\/?\s*>/gi, '\n')
|
|
.replace(/<\/\s*(div|p|li|tr|td|h[1-6])\s*>/gi, '\n')
|
|
.replace(/<[^>]*>/g, '')
|
|
)
|
|
.split(/\n+/)
|
|
.map(line => line.replace(/\s+/g, ' ').trim())
|
|
.filter(Boolean);
|
|
|
|
const uniqueLines = [...new Set(parsedLines)];
|
|
if (uniqueLines.length > 0) {
|
|
return uniqueLines.slice(0, 2);
|
|
}
|
|
|
|
const fallback = normalizeNameText(rawName);
|
|
return [fallback || (isAr ? 'صنف' : 'Item')];
|
|
}
|
|
|
|
function renderItemName(container, item, isAr) {
|
|
container.textContent = '';
|
|
const nameLines = extractItemNameLines(item, isAr);
|
|
|
|
nameLines.forEach((line, index) => {
|
|
const lineEl = document.createElement('div');
|
|
const arabicLine = hasArabicText(line);
|
|
lineEl.className = index === 0
|
|
? (arabicLine ? 'item-name-primary item-name-ar' : 'item-name-primary item-name-en')
|
|
: (arabicLine ? 'item-name-secondary item-name-ar' : 'item-name-secondary item-name-en');
|
|
lineEl.textContent = line;
|
|
container.appendChild(lineEl);
|
|
});
|
|
}
|
|
|
|
function maximizeWindow() {
|
|
try {
|
|
window.moveTo(0, 0);
|
|
window.resizeTo(screen.availWidth, screen.availHeight);
|
|
window.focus();
|
|
} catch (e) {}
|
|
}
|
|
|
|
function setLanguageLabels(isAr) {
|
|
if (isAr) {
|
|
document.getElementById('sectionKicker').innerText = 'السلة الحالية';
|
|
document.getElementById('sectionTitle').innerText = 'الأصناف المختارة';
|
|
document.getElementById('summaryEyebrow').innerText = 'ملخص الدفع';
|
|
document.getElementById('summaryHeading').innerText = 'عرض أوضح ومتوازن لإجمالي الطلب.';
|
|
document.getElementById('labelItemsStat').innerText = 'الأصناف';
|
|
document.getElementById('labelQuantityStat').innerText = 'الكمية';
|
|
document.getElementById('labelSubtotal').innerText = 'المجموع قبل الضريبة';
|
|
document.getElementById('labelVAT').innerText = 'الضريبة';
|
|
document.getElementById('labelDiscount').innerText = 'الخصم';
|
|
document.getElementById('labelLoyalty').innerText = 'استخدام الولاء';
|
|
document.getElementById('labelTotal').innerText = 'الإجمالي المطلوب';
|
|
document.getElementById('labelTotalNote').innerText = 'يرجى مراجعة الفاتورة قبل الدفع';
|
|
} else {
|
|
document.getElementById('sectionKicker').innerText = 'Current Basket';
|
|
document.getElementById('sectionTitle').innerText = 'Order Items';
|
|
document.getElementById('summaryEyebrow').innerText = 'Payment Summary';
|
|
document.getElementById('summaryHeading').innerText = 'Clean, balanced totals with less visual weight.';
|
|
document.getElementById('labelItemsStat').innerText = 'Items';
|
|
document.getElementById('labelQuantityStat').innerText = 'Quantity';
|
|
document.getElementById('labelSubtotal').innerText = 'Subtotal';
|
|
document.getElementById('labelVAT').innerText = 'VAT';
|
|
document.getElementById('labelDiscount').innerText = 'Discount';
|
|
document.getElementById('labelLoyalty').innerText = 'Loyalty Redeemed';
|
|
document.getElementById('labelTotal').innerText = 'Total to Pay';
|
|
document.getElementById('labelTotalNote').innerText = 'Please review before payment';
|
|
}
|
|
}
|
|
|
|
function updateDisplay(data) {
|
|
if (!data) return;
|
|
lastTimestamp = data.timestamp || 0;
|
|
currentCurrency = data.currency || 'OMR';
|
|
|
|
const items = Array.isArray(data.items) ? data.items : [];
|
|
const isAr = items.some(item => hasArabicText([
|
|
item.nameAr,
|
|
item.name_ar,
|
|
item.name,
|
|
item.nameEn,
|
|
item.name_en
|
|
].filter(Boolean).join(' ')));
|
|
setLanguageLabels(isAr);
|
|
|
|
const totalQuantity = items.reduce((sum, item) => {
|
|
return sum + (parseFloat(item.quantity || item.qty) || 0);
|
|
}, 0);
|
|
|
|
const itemLabel = isAr ? 'صنف' : 'items';
|
|
const qtyLabel = isAr ? 'كمية' : 'qty';
|
|
document.getElementById('sectionSummaryText').innerText = `${items.length} ${itemLabel} • ${formatQuantity(totalQuantity)} ${qtyLabel}`;
|
|
document.getElementById('displayItemCount').innerText = items.length;
|
|
document.getElementById('displayQuantity').innerText = formatQuantity(totalQuantity);
|
|
document.getElementById('debugInfoText').innerText = (isAr ? 'الأصناف: ' : 'Items: ') + items.length;
|
|
|
|
if (items.length > 0) {
|
|
document.getElementById('welcomeScreen').style.display = 'none';
|
|
document.getElementById('activeCart').style.display = 'grid';
|
|
document.getElementById('debugInfo').style.display = 'inline-flex';
|
|
} else {
|
|
document.getElementById('welcomeScreen').style.display = 'flex';
|
|
document.getElementById('activeCart').style.display = 'none';
|
|
document.getElementById('debugInfo').style.display = 'none';
|
|
document.getElementById('customerName').innerText = isAr ? 'أهلاً وسهلاً' : 'Welcome';
|
|
return;
|
|
}
|
|
|
|
if (data.customerName || data.customer_name) {
|
|
document.getElementById('customerName').innerText = data.customerName || data.customer_name;
|
|
} else {
|
|
document.getElementById('customerName').innerText = isAr ? 'أهلاً وسهلاً' : 'Welcome';
|
|
}
|
|
|
|
const list = document.getElementById('itemsList');
|
|
list.innerHTML = '';
|
|
|
|
items.forEach(item => {
|
|
const qty = parseFloat(item.quantity || item.qty) || 0;
|
|
const price = parseFloat(item.price) || 0;
|
|
const total = item.total ? parseFloat(item.total) : (qty * price);
|
|
const itemDiscount = parseFloat(item.discount) || 0;
|
|
|
|
let details = `${formatQuantity(qty)} x ${formatMoney(price)}`;
|
|
if (itemDiscount > 0) {
|
|
details += isAr
|
|
? ` • خصم ${formatMoney(itemDiscount)}`
|
|
: ` • Disc ${formatMoney(itemDiscount)}`;
|
|
}
|
|
|
|
const row = document.createElement('div');
|
|
row.className = 'cart-item';
|
|
|
|
const copy = document.createElement('div');
|
|
copy.className = 'item-copy';
|
|
|
|
const name = document.createElement('div');
|
|
name.className = 'item-name';
|
|
renderItemName(name, item, isAr);
|
|
|
|
const detail = document.createElement('div');
|
|
detail.className = 'item-details';
|
|
detail.textContent = details;
|
|
|
|
const priceTag = document.createElement('div');
|
|
priceTag.className = 'item-price';
|
|
priceTag.textContent = formatMoney(total);
|
|
|
|
copy.appendChild(name);
|
|
copy.appendChild(detail);
|
|
row.appendChild(copy);
|
|
row.appendChild(priceTag);
|
|
list.appendChild(row);
|
|
});
|
|
|
|
list.scrollTop = list.scrollHeight;
|
|
|
|
const vat = parseFloat(data.vat) || 0;
|
|
const subtotal = parseFloat(data.subtotal) || 0;
|
|
const subtotalBeforeVat = Math.max(subtotal - vat, 0);
|
|
|
|
document.getElementById('displaySubtotal').innerText = formatMoney(subtotalBeforeVat);
|
|
document.getElementById('displayTax').innerText = formatMoney(vat);
|
|
|
|
const discount = parseFloat(data.discount) || 0;
|
|
if (discount > 0) {
|
|
document.getElementById('displayDiscountRow').style.display = 'flex';
|
|
document.getElementById('displayDiscount').innerText = '- ' + formatMoney(discount);
|
|
} else {
|
|
document.getElementById('displayDiscountRow').style.display = 'none';
|
|
}
|
|
|
|
const loyalty = parseFloat(data.loyalty) || 0;
|
|
if (loyalty > 0) {
|
|
document.getElementById('displayLoyaltyRow').style.display = 'flex';
|
|
document.getElementById('displayLoyalty').innerText = '- ' + formatMoney(loyalty);
|
|
} else {
|
|
document.getElementById('displayLoyaltyRow').style.display = 'none';
|
|
}
|
|
|
|
document.getElementById('displayCurrency').innerText = currentCurrency;
|
|
document.getElementById('displayTotalValue').innerText = formatMoneyValue(data.total || 0);
|
|
}
|
|
|
|
window.addEventListener('storage', (e) => {
|
|
if (e.key === 'pos_cart_update') {
|
|
try {
|
|
const data = JSON.parse(e.newValue);
|
|
updateDisplay(data);
|
|
} catch (err) {
|
|
console.error('Error parsing cart data', err);
|
|
}
|
|
}
|
|
});
|
|
|
|
setInterval(() => {
|
|
const stored = localStorage.getItem('pos_cart_update');
|
|
if (stored) {
|
|
try {
|
|
const data = JSON.parse(stored);
|
|
if (data.timestamp && data.timestamp !== lastTimestamp) {
|
|
updateDisplay(data);
|
|
}
|
|
} catch (e) {}
|
|
}
|
|
}, 1000);
|
|
|
|
const stored = localStorage.getItem('pos_cart_update');
|
|
if (stored) {
|
|
try {
|
|
updateDisplay(JSON.parse(stored));
|
|
} catch (e) {}
|
|
}
|
|
|
|
function toggleFullScreen() {
|
|
if (!document.fullscreenElement) {
|
|
document.documentElement.requestFullscreen();
|
|
} else if (document.exitFullscreen) {
|
|
document.exitFullscreen();
|
|
}
|
|
}
|
|
|
|
window.addEventListener('load', () => {
|
|
maximizeWindow();
|
|
setTimeout(maximizeWindow, 250);
|
|
|
|
const slides = document.querySelectorAll('.slide');
|
|
let currentSlide = 0;
|
|
if (slides.length > 0) {
|
|
setInterval(() => {
|
|
slides[currentSlide].classList.remove('active');
|
|
currentSlide = (currentSlide + 1) % slides.length;
|
|
slides[currentSlide].classList.add('active');
|
|
}, 6000);
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|