When a card hits `accepted` the items section bumps base font to 1.25rem and modifier/note lines to 1.15rem + medium weight; the muted grey on modifiers drops to inherited color. All via Vue `:style` bindings — class-based CSS rules lose to lnbits' upstream `!important` on Quasar typography utilities (even with our own `!important`), so inline wins without an arms race. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
83 lines
2.7 KiB
JavaScript
83 lines
2.7 KiB
JavaScript
window.app = Vue.createApp({
|
|
el: '#vue',
|
|
mixins: [windowMixin],
|
|
data() {
|
|
return {
|
|
restaurant: window.RESTAURANT_BOOTSTRAP || {},
|
|
active: [],
|
|
pollHandle: null,
|
|
activeStatuses: ['paid', 'accepted', 'ready']
|
|
}
|
|
},
|
|
computed: {
|
|
invoicekey() {
|
|
const w = this.g.user.wallets.find((w) => w.id === this.restaurant.wallet)
|
|
return (w && w.inkey) || (this.g.user.wallets[0] && this.g.user.wallets[0].inkey)
|
|
},
|
|
adminkey() {
|
|
const w = this.g.user.wallets.find((w) => w.id === this.restaurant.wallet)
|
|
return (w && w.adminkey) || (this.g.user.wallets[0] && this.g.user.wallets[0].adminkey)
|
|
}
|
|
},
|
|
methods: {
|
|
statusColor(status) {
|
|
return {paid: 'positive', accepted: 'blue', ready: 'amber'}[status] || 'grey'
|
|
},
|
|
cookingMode(order) {
|
|
return order && order.status === 'accepted'
|
|
},
|
|
cardClass(order) {
|
|
// Visually escalate as orders age. >5min = highlight; >15min = alarm.
|
|
//
|
|
// Pair every pale `bg-{color}-1` with an explicit dark text color
|
|
// — otherwise on LNbits dark mode the q-card inherits light text
|
|
// and renders white-on-cream, which is unreadable. The non-
|
|
// highlighted branch (default theme) returns '' so the q-card
|
|
// keeps its theme-aware defaults.
|
|
const ageSec = (Date.now() - new Date(order.time).getTime()) / 1000
|
|
if (order.status === 'ready') return 'bg-amber-1 text-grey-9'
|
|
if (ageSec > 900) return 'bg-red-1 text-grey-9'
|
|
if (ageSec > 300) return 'bg-orange-1 text-grey-9'
|
|
return ''
|
|
},
|
|
async fetchActive() {
|
|
try {
|
|
const {data: orders} = await RestaurantAPI.listOrders(
|
|
this.invoicekey,
|
|
this.restaurant.id,
|
|
this.activeStatuses
|
|
)
|
|
// Hydrate items per card.
|
|
for (const o of orders) {
|
|
try {
|
|
const {data} = await RestaurantAPI.getOrder(o.id)
|
|
o._items = data.items
|
|
} catch (e) {
|
|
o._items = []
|
|
}
|
|
}
|
|
// Newest at the bottom-right (left-to-right reading order in kitchen).
|
|
this.active = orders.sort(
|
|
(a, b) => new Date(a.time).getTime() - new Date(b.time).getTime()
|
|
)
|
|
} catch (err) {
|
|
LNbits.utils.notifyApiError(err)
|
|
}
|
|
},
|
|
async transition(order, newStatus) {
|
|
try {
|
|
await RestaurantAPI.transitionOrder(this.adminkey, order.id, newStatus)
|
|
await this.fetchActive()
|
|
} catch (err) {
|
|
LNbits.utils.notifyApiError(err)
|
|
}
|
|
}
|
|
},
|
|
async created() {
|
|
await this.fetchActive()
|
|
this.pollHandle = setInterval(() => this.fetchActive(), 5000)
|
|
},
|
|
beforeUnmount() {
|
|
if (this.pollHandle) clearInterval(this.pollHandle)
|
|
}
|
|
})
|