feat(waiter): configurable server/venue layer for native app and plain-HTTP browser mode
New waiter_pwa/src/config/server.js is the single place that knows where the backend is. Served by the venue's server (https domain or http://<LAN IP>) nothing changes: same-origin URLs and the original storage keys, so existing installs keep their token and unsynced offline queue. With an active venue (native app, or dev builds with VITE_SERVER_URL) URLs become absolute and all venue data is namespaced by siteId: token/savedUsername keys, the Dexie DB (pos_snapshot__<siteId>, which also covers the WS cursor), favorites and table-view prefs. Switching venue reloads the app. - api client baseURL, WebSocket and SSE URLs routed through the layer - product images / waiter avatars rendered via assetUrl() - service-worker update prompt skipped in native builds - InstallAppBanner: shown only in plain-HTTP browser mode and only when VITE_APP_DOWNLOAD_URL is set at build time (dismiss for 7 days) - VITE_SERVER_URL override is DEV-only (a URL-controlled server in prod would let a crafted link capture PINs) - pack README: rule CS-8 on never assuming same-origin Verified with Playwright/Edge against a local backend: prod build same-origin, prod build via LAN IP over plain HTTP (insecure context, no SW, banner shown), and dev build pointed at the backend by URL - all three log in, reach /tables and receive the WebSocket 'ready' frame; storage keys and IndexedDB names are as expected. Lint: no new problems (103 before/after). Build passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { useState } from 'react'
|
||||
import { deliveryMode } from '../config/server'
|
||||
|
||||
// Shown only in plain-HTTP browser mode (http://<LAN IP>), where the page can't
|
||||
// work offline after a reload and can't be installed as a real PWA. Hidden until
|
||||
// an app download link exists (VITE_APP_DOWNLOAD_URL at build time).
|
||||
const DOWNLOAD_URL = import.meta.env.VITE_APP_DOWNLOAD_URL || ''
|
||||
const DISMISS_KEY = 'install-banner-dismissed-until'
|
||||
const DISMISS_DAYS = 7
|
||||
|
||||
function isDismissed() {
|
||||
try {
|
||||
return Number(localStorage.getItem(DISMISS_KEY) || 0) > Date.now()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export default function InstallAppBanner() {
|
||||
const [hidden, setHidden] = useState(isDismissed)
|
||||
|
||||
if (!DOWNLOAD_URL || hidden || deliveryMode() !== 'plain-web') return null
|
||||
|
||||
function dismiss() {
|
||||
try {
|
||||
localStorage.setItem(DISMISS_KEY, String(Date.now() + DISMISS_DAYS * 86_400_000))
|
||||
} catch {
|
||||
// storage unavailable — banner just reappears next load
|
||||
}
|
||||
setHidden(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
position: 'fixed',
|
||||
bottom: 80,
|
||||
left: 12,
|
||||
right: 12,
|
||||
zIndex: 9998,
|
||||
background: 'var(--bg2)',
|
||||
border: '1px solid var(--accent)',
|
||||
borderRadius: 16,
|
||||
padding: '12px 14px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
boxShadow: '0 8px 32px rgba(0,0,0,0.4)',
|
||||
}}>
|
||||
<span style={{ flex: 1, fontSize: 13, color: 'var(--text)', lineHeight: 1.35 }}>
|
||||
Για γρηγορότερη και πιο σταθερή λειτουργία, εγκαταστήστε την εφαρμογή.
|
||||
</span>
|
||||
<a
|
||||
href={DOWNLOAD_URL}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
style={{
|
||||
background: 'var(--accent)',
|
||||
color: '#0f172a',
|
||||
borderRadius: 10,
|
||||
padding: '8px 14px',
|
||||
fontSize: 14,
|
||||
fontWeight: 700,
|
||||
textDecoration: 'none',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
Εγκατάσταση
|
||||
</a>
|
||||
<button
|
||||
onClick={dismiss}
|
||||
aria-label="Κλείσιμο"
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
color: 'var(--muted)',
|
||||
fontSize: 20,
|
||||
lineHeight: 1,
|
||||
padding: 4,
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user