Compare commits

...

2 Commits

Author SHA1 Message Date
9a347c9206 Bar utility: Fix error 2025-11-21 17:20:54 +01:00
60ea4669ab Bar utility: some updates 2025-11-21 17:18:16 +01:00
2 changed files with 257 additions and 26 deletions

View File

@@ -5,15 +5,189 @@
"18+": ""
},
"offering": {
"test": {
"name": "Test drink",
"price": 700,
"id": "test"
"big-bar": {
"offering": {
"softdrinks": {
"name": "Softdrinks",
"price": 400,
"id": "softdrinks"
},
"test-2": {
"name": "Test drink 2",
"energy": {
"name": "Energy",
"price": 400,
"id": "energy"
},
"mate": {
"name": "Mate",
"price": 500,
"id": "test-2"
"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"
},
"small-bar": {
"offering": {
"softdrinks": {
"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';
interface FullConfig {
'offering': BarConfig,
'ages': Ages
'offering': Bars;
'ages': Ages;
}
interface Bars {
[name: string]: {
'offering': BarConfig;
'name': string;
'id': string;
}
}
interface Ages {
'18+': string,
'16-18': string
'18+': string;
'16-18': string;
}
interface BarConfig {
[id: string]: Offer;
[id: string]: Offer
}
interface Offer {
'name': string;
'price': number; // In cents
'depot'?: number; // In cents
'showLine'?: boolean;
'id': string;
}
@@ -33,8 +43,12 @@
'16-18': '',
'below': ''
} );
const offering: Ref<BarConfig> = ref( {} );
const offering: Ref<Bars> = ref( {} );
const selection: Ref<Selection> = ref( {} );
const selectedBar: Ref<string> = ref( '' );
const enableDepotReminder = ref( true );
let cashinInDepot = false;
fetch( '/bar-config.json' ).then( res => {
if ( res.status === 200 ) {
@@ -43,15 +57,22 @@
offering.value = data.offering;
ages.value = data.ages;
reset();
} );
} else {
alert( 'Failed to load' );
}
} );
const reset = () => {
const keys = Object.keys( offering.value );
const reset = ( skipCheck = true ) => {
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 => {
selection.value[ val ] = 0;
@@ -66,7 +87,11 @@
for ( let i = 0; i < keys.length; 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 && o > 0 )
cashinInDepot = true;
}
return totalPrice / 100;
@@ -83,17 +108,40 @@
<template>
<div class="bar-utility">
<h1>Bar utility</h1>
<p>Check ages! (18+: {{ ages[ '18+' ] }}, 16-18: {{ ages[ '16-18' ] }})</p>
<button @click="reset()">
<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>
<p>Total: CHF {{ total }}</p>
<table class="offering-wrapper">
</div>
<p>Check ages! (18+: {{ ages[ '18+' ] }}, 16-18: {{ ages[ '16-18' ] }})</p>
<p v-if="Object.keys( offering ).includes( selectedBar )">
Total: CHF {{ total }}
</p>
<table v-if="Object.keys( offering ).includes( selectedBar )" class="offering-wrapper">
<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>
<p>{{ offer.name }} (CHF {{ offer.price / 100 }})</p>
<p>
{{ offer.name }} (CHF {{ offer.price / 100 }}{{
offer.depot ? ' + ' + ( offer.depot / 100 ) : '' }})
</p>
</td>
<td>
<div>
@@ -120,7 +168,16 @@
flex-direction: column;
>.offering-wrapper {
border-collapse: collapse;
margin-bottom: 5vh;
.offering {
&.show-line {
>td {
border-bottom: solid 1px black;
}
}
>td {
padding: 5px;
p {