diff --git a/manager_dashboard/src/pages/Settings/tabs/AppInfoTab.jsx b/manager_dashboard/src/pages/Settings/tabs/AppInfoTab.jsx index 330fd6a..3a858df 100644 --- a/manager_dashboard/src/pages/Settings/tabs/AppInfoTab.jsx +++ b/manager_dashboard/src/pages/Settings/tabs/AppInfoTab.jsx @@ -302,7 +302,7 @@ function DataTransferSection() { } -function QRModal({ url, onClose }) { +function QRModal({ url, caption = 'Σαρώστε με το κινητό για σύνδεση στο σύστημα.', onClose }) { return (
-

- Σαρώστε με το κινητό για σύνδεση στο σύστημα. -

+

{caption}

) } +const IPV4 = /^\d{1,3}(\.\d{1,3}){3}$/ + +// Address phones use on the LAN. HOST_IP from the server wins; otherwise, if this +// dashboard was itself opened by IP (http://192.168.x.x:8081), that IP is the server. +function resolveLanIp(status) { + if (status?.lan_ip) return status.lan_ip + const host = window.location.hostname + return IPV4.test(host) && !host.startsWith('127.') ? host : null +} + +// Pairing URL: opens the waiter app when scanned with the phone camera, and the +// native app reads the same code (?pair=) to pair with this venue. +function waiterPairUrl(lanIp, siteId) { + return `http://${lanIp}/` + (siteId ? `?pair=${encodeURIComponent(siteId)}` : '') +} + function formatUptime(seconds) { const h = Math.floor(seconds / 3600) const m = Math.floor((seconds % 3600) / 60) @@ -334,7 +348,7 @@ export default function AppInfoTab() { const user = useAuthStore(s => s.user) const qc = useQueryClient() const [refreshing, setRefreshing] = useState(false) - const [qrOpen, setQrOpen] = useState(false) + const [qr, setQr] = useState(null) // { url, caption } | null const { data: status, isLoading } = useQuery({ queryKey: ['system-status'], queryFn: () => client.get('/api/system/status').then(r => r.data), @@ -414,13 +428,46 @@ export default function AppInfoTab() {
{new Date(status.expires_at).toLocaleDateString('el-GR')}
)} + {(() => { + const lanIp = resolveLanIp(status) + if (!lanIp) { + return ( + <> +
Τοπική πρόσβαση
+
+ Άγνωστη IP του server — ορίστε HOST_IP στο .env +
+ + ) + } + const pairUrl = waiterPairUrl(lanIp, status?.site_id) + return ( + <> +
Σερβιτόροι (WiFi)
+
+ http://{lanIp} + +
+
Διαχείριση (WiFi)
+
http://{lanIp}/manager
+ + ) + })()} {status?.waiter_domain && ( <>
Waiter Domain
{status.waiter_domain}
)} - {qrOpen && status?.waiter_domain && ( - setQrOpen(false)} /> - )} + {qr && setQr(null)} />} ) }