feat: initial commit — local services (backend + manager dashboard + waiter PWA)
Includes all work to date: - local_backend: FastAPI backend with products, orders, tables, shifts, cloud sync - manager_dashboard: React manager UI with product/category management, reports, settings - waiter_pwa: React PWA for waiter devices - Category reparent endpoint and UI - Waiter domain: local_ip sent on heartbeat, waiter_domain persisted from cloud response - QR code modal in AppInfoTab for waiter domain - Product form: number input spinners removed, category pre-selected on new product - Category row: count badge moved to far right Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import { create } from 'zustand'
|
||||
|
||||
const useAuthStore = create((set) => ({
|
||||
user: null,
|
||||
token: localStorage.getItem('manager_token') || null,
|
||||
savedUsername: localStorage.getItem('manager_username') || null,
|
||||
locked: sessionStorage.getItem('manager_locked') === 'true',
|
||||
|
||||
login(user, token) {
|
||||
localStorage.setItem('manager_token', token)
|
||||
localStorage.setItem('manager_username', user.username)
|
||||
sessionStorage.removeItem('manager_locked')
|
||||
set({ user, token, savedUsername: user.username, locked: false })
|
||||
},
|
||||
|
||||
// Restores user after a page refresh without touching the lock state.
|
||||
rehydrate(user, token) {
|
||||
set({ user, token, savedUsername: user.username })
|
||||
},
|
||||
|
||||
logout() {
|
||||
localStorage.removeItem('manager_token')
|
||||
localStorage.removeItem('manager_username')
|
||||
localStorage.removeItem('manager_lock_timeout')
|
||||
sessionStorage.removeItem('manager_locked')
|
||||
set({ user: null, token: null, savedUsername: null, locked: false })
|
||||
},
|
||||
|
||||
lock() {
|
||||
sessionStorage.setItem('manager_locked', 'true')
|
||||
set({ locked: true })
|
||||
},
|
||||
|
||||
unlock(user, token) {
|
||||
localStorage.setItem('manager_token', token)
|
||||
sessionStorage.removeItem('manager_locked')
|
||||
set({ user, token, locked: false })
|
||||
},
|
||||
|
||||
updateUser(updatedUser) {
|
||||
localStorage.setItem('manager_username', updatedUser.username)
|
||||
set({ user: updatedUser })
|
||||
},
|
||||
}))
|
||||
|
||||
export default useAuthStore
|
||||
@@ -0,0 +1,94 @@
|
||||
import { create } from 'zustand'
|
||||
import { persist } from 'zustand/middleware'
|
||||
|
||||
// Mirrors waiter_pwa/src/store/tableColourStore.js — same localStorage key so both apps share state.
|
||||
|
||||
export const DEFAULT_COLOURS = {
|
||||
light: {
|
||||
free: {
|
||||
cardBg: '#d6d6d6',
|
||||
badgeBg: '#e3e3e3',
|
||||
nameText: '#3b485e',
|
||||
badgeText: '#adadad',
|
||||
},
|
||||
mine: {
|
||||
cardBg: '#e83030',
|
||||
badgeBg: 'rgba(255,255,255,0.40)',
|
||||
nameText: '#ffffff',
|
||||
badgeText: '#ffffff',
|
||||
},
|
||||
open: {
|
||||
cardBg: '#ffbb29',
|
||||
badgeBg: 'rgba(255,255,255,0.25)',
|
||||
nameText: '#ffffff',
|
||||
badgeText: '#ffffff',
|
||||
},
|
||||
partially_paid: {
|
||||
cardBg: '#e89230',
|
||||
badgeBg: 'rgba(255,255,255,0.25)',
|
||||
nameText: '#ffffff',
|
||||
badgeText: '#ffffff',
|
||||
},
|
||||
paid: {
|
||||
cardBg: '#79ad38',
|
||||
badgeBg: 'rgba(255,255,255,0.25)',
|
||||
nameText: '#ffffff',
|
||||
badgeText: '#ffffff',
|
||||
},
|
||||
},
|
||||
dark: {
|
||||
free: {
|
||||
cardBg: '#243044',
|
||||
badgeBg: 'rgba(26,35,50,0.50)',
|
||||
nameText: '#ffffff',
|
||||
badgeText: '#adadad',
|
||||
},
|
||||
mine: {
|
||||
cardBg: '#e83030',
|
||||
badgeBg: 'rgba(255,255,255,0.40)',
|
||||
nameText: '#ffffff',
|
||||
badgeText: '#ffffff',
|
||||
},
|
||||
open: {
|
||||
cardBg: '#ffbb29',
|
||||
badgeBg: 'rgba(255,255,255,0.25)',
|
||||
nameText: '#ffffff',
|
||||
badgeText: '#ffffff',
|
||||
},
|
||||
partially_paid: {
|
||||
cardBg: '#e89230',
|
||||
badgeBg: 'rgba(255,255,255,0.25)',
|
||||
nameText: '#ffffff',
|
||||
badgeText: '#ffffff',
|
||||
},
|
||||
paid: {
|
||||
cardBg: '#79ad38',
|
||||
badgeBg: 'rgba(255,255,255,0.25)',
|
||||
nameText: '#ffffff',
|
||||
badgeText: '#ffffff',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const useTableColourStore = create(persist(
|
||||
(set) => ({
|
||||
colours: DEFAULT_COLOURS,
|
||||
setColour: (mode, status, slot, value) =>
|
||||
set(s => ({
|
||||
colours: {
|
||||
...s.colours,
|
||||
[mode]: {
|
||||
...s.colours[mode],
|
||||
[status]: {
|
||||
...s.colours[mode][status],
|
||||
[slot]: value,
|
||||
},
|
||||
},
|
||||
},
|
||||
})),
|
||||
resetAll: () => set({ colours: DEFAULT_COLOURS }),
|
||||
}),
|
||||
{ name: 'pos-table-colours' }
|
||||
))
|
||||
|
||||
export default useTableColourStore
|
||||
Reference in New Issue
Block a user