Phase 2: scaffold Waiter PWA — React+Vite, PWA manifest, all pages and components
This commit is contained in:
88
waiter_pwa/src/pages/TableListPage.jsx
Normal file
88
waiter_pwa/src/pages/TableListPage.jsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import TableCard from '../components/TableCard'
|
||||
import ConnectionBanner from '../components/ConnectionBanner'
|
||||
import useAuthStore from '../store/authStore'
|
||||
import client from '../api/client'
|
||||
|
||||
const FILTERS = ['all', 'mine', 'free']
|
||||
const FILTER_LABELS = { all: 'Όλα', mine: 'Δικά μου', free: 'Ελεύθερα' }
|
||||
|
||||
export default function TableListPage() {
|
||||
const { user, logout } = useAuthStore()
|
||||
const [tables, setTables] = useState([])
|
||||
const [orders, setOrders] = useState([])
|
||||
const [filter, setFilter] = useState('all')
|
||||
const [offline, setOffline] = useState(false)
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(() => {
|
||||
const handler = () => setOffline(true)
|
||||
window.addEventListener('backend-offline', handler)
|
||||
return () => window.removeEventListener('backend-offline', handler)
|
||||
}, [])
|
||||
|
||||
async function load() {
|
||||
try {
|
||||
const [tablesRes, ordersRes] = await Promise.all([
|
||||
client.get('/api/tables/'),
|
||||
client.get('/api/orders/my'),
|
||||
])
|
||||
setTables(tablesRes.data)
|
||||
setOrders(ordersRes.data)
|
||||
setOffline(false)
|
||||
} catch {}
|
||||
}
|
||||
|
||||
useEffect(() => { load() }, [])
|
||||
|
||||
function getOrder(tableId) {
|
||||
return orders.find(o => o.table_id === tableId && ['open', 'partially_paid'].includes(o.status))
|
||||
}
|
||||
|
||||
const filtered = tables.filter(t => {
|
||||
const order = getOrder(t.id)
|
||||
if (filter === 'free') return !order
|
||||
if (filter === 'mine') return order && order.waiters?.some(w => w.waiter_id === user?.id)
|
||||
return true
|
||||
})
|
||||
|
||||
function handleLogout() {
|
||||
logout()
|
||||
navigate('/login')
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
<header className="top-bar">
|
||||
<span className="top-bar__title">Τραπέζια</span>
|
||||
<span className="top-bar__user">{user?.username}</span>
|
||||
<button className="icon-btn" onClick={handleLogout} title="Αποσύνδεση">⏏</button>
|
||||
</header>
|
||||
|
||||
{offline && <ConnectionBanner />}
|
||||
|
||||
<div className="filter-tabs">
|
||||
{FILTERS.map(f => (
|
||||
<button key={f} className={`filter-tab ${filter === f ? 'filter-tab--active' : ''}`} onClick={() => setFilter(f)}>
|
||||
{FILTER_LABELS[f]}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="table-grid">
|
||||
{filtered.map(t => (
|
||||
<TableCard
|
||||
key={t.id}
|
||||
table={t}
|
||||
order={getOrder(t.id)}
|
||||
currentUserId={user?.id}
|
||||
onClick={() => navigate(`/tables/${t.id}`)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<button className="fab" onClick={load} title="Ανανέωση">↺</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user