Bar utility: some updates

This commit is contained in:
2025-11-21 17:18:16 +01:00
parent 669cc620bf
commit 60ea4669ab
2 changed files with 256 additions and 26 deletions

View File

@@ -5,15 +5,189 @@
"18+": "" "18+": ""
}, },
"offering": { "offering": {
"test": { "big-bar": {
"name": "Test drink", "offering": {
"price": 700, "softdrinks": {
"id": "test" "name": "Softdrinks",
"price": 400,
"id": "softdrinks"
},
"energy": {
"name": "Energy",
"price": 400,
"id": "energy"
},
"mate": {
"name": "Mate",
"price": 500,
"id": "mate",
"depot": 200
},
"sparkly-water": {
"name": "Mineralwasser mit",
"price": 300,
"id": "sparkly-water",
"showLine": true
},
"rose": {
"name": "Rosé",
"price": 1500,
"id": "rose",
"depot": 200
},
"red": {
"name": "Rotwein",
"price": 2000,
"id": "red",
"depot": 200
},
"wine-glasses": {
"name": "Weingläser",
"price": 0,
"id": "wine-glasses",
"depot": 200
},
"appenzeller": {
"name": "Appenzeller Vollmond",
"price": 500,
"id": "appenzeller",
"depot": 200
},
"feldschloesschen": {
"name": "Feldschlösschen",
"price": 500,
"id": "feldschloesschen",
"depot": 200
},
"sommersby": {
"name": "Sommersby",
"price": 500,
"id": "sommersby",
"depot": 200
},
"jever-fun": {
"name": "Jever Fun",
"price": 400,
"id": "jever-fun",
"depot": 200
},
"trojka-ice": {
"name": "Trojka Ice",
"price": 600,
"id": "trojka-ice",
"depot": 200,
"showLine": true
},
"vodka-red-energy": {
"name": "Vodka Rot Energy",
"price": 800,
"id": "vodka-red-energy"
},
"vodka-green-citro": {
"name": "Vodka Grün Citro",
"price": 800,
"id": "vodka-green-citro"
},
"vodka-white-energy": {
"name": "Vodka White Energy",
"price": 900,
"id": "vodka-white-energy"
},
"gin-tonic": {
"name": "Gin Tonic",
"price": 900,
"id": "gin-tonic"
},
"rum-cola": {
"name": "Rum Cola",
"price": 900,
"id": "rum-cola"
},
"whiskey-cola": {
"name": "Whiskey Cola",
"price": 900,
"id": "whiskey-cola"
},
"mate-mit-schuss": {
"name": "Mate mit Schuss",
"price": 1200,
"id": "mate-mit-schuss",
"depot": 200,
"showLine": true
},
"poseidon": {
"name": "Poseidon",
"price": 900,
"id": "poseidon"
},
"arielle": {
"name": "Arielle",
"price": 900,
"id": "arielle"
},
"pearl-driver": {
"name": "Pearl Driver",
"price": 400,
"id": "pearl-driver"
}
},
"name": "Poseidon's Quelle",
"id": "big-bar"
}, },
"test-2": { "small-bar": {
"name": "Test drink 2", "offering": {
"price": 500, "softdrinks": {
"id": "test-2" "name": "Softdrinks (Alle)",
"price": 300,
"id": "softdrinks",
"showLine": true
},
"appenzeller": {
"name": "Appenzeller Vollmond",
"price": 500,
"id": "appenzeller",
"depot": 200
},
"feldschloesschen": {
"name": "Feldschlösschen",
"price": 500,
"id": "feldschloesschen",
"depot": 200
},
"sommersby": {
"name": "Sommersby",
"price": 500,
"id": "sommersby",
"depot": 200
},
"jever-fun": {
"name": "Jever Fun",
"price": 400,
"id": "jever-fun",
"depot": 200,
"showLine": true
},
"rose": {
"name": "Rosé",
"price": 1500,
"id": "rose",
"depot": 200
},
"red": {
"name": "Rotwein",
"price": 2000,
"id": "red",
"depot": 200
},
"wine-glasses": {
"name": "Weingläser",
"price": 0,
"id": "wine-glasses",
"depot": 200
}
},
"name": "Seepferdchenbar",
"id": "small-bar"
} }
} }
} }

View File

@@ -5,22 +5,32 @@
} from 'vue'; } from 'vue';
interface FullConfig { interface FullConfig {
'offering': BarConfig, 'offering': Bars;
'ages': Ages 'ages': Ages;
}
interface Bars {
[name: string]: {
'offering': BarConfig;
'name': string;
'id': string;
}
} }
interface Ages { interface Ages {
'18+': string, '18+': string;
'16-18': string '16-18': string;
} }
interface BarConfig { interface BarConfig {
[id: string]: Offer; [id: string]: Offer
} }
interface Offer { interface Offer {
'name': string; 'name': string;
'price': number; // In cents 'price': number; // In cents
'depot'?: number; // In cents
'showLine'?: boolean;
'id': string; 'id': string;
} }
@@ -33,8 +43,12 @@
'16-18': '', '16-18': '',
'below': '' 'below': ''
} ); } );
const offering: Ref<BarConfig> = ref( {} ); const offering: Ref<Bars> = ref( {} );
const selection: Ref<Selection> = ref( {} ); const selection: Ref<Selection> = ref( {} );
const selectedBar: Ref<string> = ref( '' );
const enableDepotReminder = ref( true );
let cashinInDepot = false;
fetch( '/bar-config.json' ).then( res => { fetch( '/bar-config.json' ).then( res => {
if ( res.status === 200 ) { if ( res.status === 200 ) {
@@ -43,15 +57,22 @@
offering.value = data.offering; offering.value = data.offering;
ages.value = data.ages; ages.value = data.ages;
reset();
} ); } );
} else { } else {
alert( 'Failed to load' ); alert( 'Failed to load' );
} }
} ); } );
const reset = () => { const reset = ( skipCheck = true ) => {
const keys = Object.keys( offering.value ); if ( !skipCheck && !Object.keys( offering.value ).includes( selectedBar.value ) ) return;
if ( cashinInDepot && enableDepotReminder.value ) alert( 'Hand out chips for depot' );
cashinInDepot = false;
const keys = Object.keys( offering.value[ selectedBar.value ].offering );
selection.value = {};
keys.forEach( val => { keys.forEach( val => {
selection.value[ val ] = 0; selection.value[ val ] = 0;
@@ -66,7 +87,10 @@
for ( let i = 0; i < keys.length; i++ ) { for ( let i = 0; i < keys.length; i++ ) {
const o = selection.value[ keys[ i ] ]; const o = selection.value[ keys[ i ] ];
totalPrice += o * offering.value[ keys[ i ] ].price; totalPrice += o * offering.value[ selectedBar.value ].offering[ keys[ i ] ].price;
totalPrice += o * ( offering.value[ selectedBar.value ].offering[ keys[ i ] ].depot ?? 0 );
if ( offering.value[ selectedBar.value ].offering[ keys[ i ] ].depot ?? 0 > 0 ) cashinInDepot = true;
} }
return totalPrice / 100; return totalPrice / 100;
@@ -83,17 +107,40 @@
<template> <template>
<div class="bar-utility"> <div class="bar-utility">
<h1>Bar utility</h1> <div style="margin: 0">
<label> Depot chips reminder</label>
<input v-model="enableDepotReminder" type="checkbox">
</div>
<h1 style="margin: 15px;">
Bar utility
</h1>
<div>
<label for="bar-select">Select bar </label>
<select id="bar-select" v-model="selectedBar" @change="reset()">
<option v-for="bar in Object.values( offering )" :key="bar.id" :value="bar.id">
{{ bar.name }}
</option>
</select>
<button @click="reset( false )">
Reset
</button>
</div>
<p>Check ages! (18+: {{ ages[ '18+' ] }}, 16-18: {{ ages[ '16-18' ] }})</p> <p>Check ages! (18+: {{ ages[ '18+' ] }}, 16-18: {{ ages[ '16-18' ] }})</p>
<button @click="reset()"> <p v-if="Object.keys( offering ).includes( selectedBar )">
Reset Total: CHF {{ total }}
</button> </p>
<p>Total: CHF {{ total }}</p> <table v-if="Object.keys( offering ).includes( selectedBar )" class="offering-wrapper">
<table class="offering-wrapper">
<tbody> <tbody>
<tr v-for="offer in offering" :key="offer.id" class="offering"> <tr
v-for="offer in offering[ selectedBar ].offering"
:key="offer.id"
:class="[ 'offering', offer.showLine ? 'show-line' : '' ]"
>
<td> <td>
<p>{{ offer.name }} (CHF {{ offer.price / 100 }})</p> <p>
{{ offer.name }} (CHF {{ offer.price / 100 }}{{
offer.depot ? ' + ' + ( offer.depot / 100 ) : '' }})
</p>
</td> </td>
<td> <td>
<div> <div>
@@ -120,7 +167,16 @@
flex-direction: column; flex-direction: column;
>.offering-wrapper { >.offering-wrapper {
border-collapse: collapse;
margin-bottom: 5vh;
.offering { .offering {
&.show-line {
>td {
border-bottom: solid 1px black;
}
}
>td { >td {
padding: 5px; padding: 5px;
p { p {