Compare commits

...

5 Commits

Author SHA1 Message Date
mmmchimps f5eaf97083 feat: make burger menu toggable on touch devices 2023-01-26 17:41:47 +01:00
mmmchimps cdbbd64cdd doc: some doc 2023-01-25 01:32:22 +01:00
mmmchimps 8c5f2d7bc2 feat: success message, form, and much more 2023-01-25 01:30:27 +01:00
mmmchimps bdadf65e46 feat: fill finish and reset buttons with some life 2023-01-24 16:05:51 +01:00
mmmchimps dd76eacb82 feat: fill input fields from local storage! 2023-01-24 15:09:20 +01:00
10 changed files with 286 additions and 87 deletions

View File

@ -1,9 +0,0 @@
export default class inventoryAPI {
static async save(drinks) {
localStorage.setItem("inventory", JSON.stringify(drinks));
}
static async load() {
return JSON.parse(localStorage.getItem("inventory") || "[]");
}
}

View File

@ -1,6 +1,7 @@
<script lang="ts">
import { onMount } from "svelte";
import { inventory } from "../stores/inventory"
import { drinks } from "../stores/drinks";
import inventoryApi from "../stores/api";
export let drinkName: string;
@ -8,6 +9,15 @@
let amountBottles: number;
const saveInventory = () => {
// If there is not a timestamp entry yet, create one.
if ( !$inventory.some(item => "timestamp" in item)) {
let _unixTime = Date.now();
let _date = new Date(_unixTime).toLocaleDateString();
let _time = new Date(_unixTime).toLocaleTimeString();
$inventory = [{
timestamp: _date + " um " + _time
}, ...$inventory];
}
// Check if a drink is already in the inventory. If yes, then update the amounts. If not, add it.
if ($inventory.some(item => item.name === drinkName)) {
$inventory.forEach(item => {
@ -27,8 +37,22 @@
...$inventory,
];
}
console.log($inventory);
inventoryApi.save($inventory);
};
const loadAmountsFromInventory = () => {
$inventory.forEach(item => {
if (item.name === drinkName) {
amountContainers = item.amountContainers;
amountBottles = item.amountBottles;
}
});
}
onMount(async () => {
loadAmountsFromInventory();
})
</script>
<div class="box">

84
src/lib/Finish.svelte Normal file
View File

@ -0,0 +1,84 @@
<script lang="ts">
import inventoryApi from "../stores/api";
import { inventory } from "../stores/inventory";
import Success from "./Success.svelte";
export let finishKind = "";
let windowIsVisible = "";
let name = "";
let comment = "";
let successWindow;
export const showWindow = () => windowIsVisible = "is-active";
const closeWindow = () => {
windowIsVisible = "";
};
</script>
<div class="modal {windowIsVisible}">
<div class="modal-background"/>
<div class="modal-card">
{#if finishKind === "reset"}
<header class="modal-card-head">
<p class="modal-card-title">Inventur neu beginnen ❌</p>
<button class="delete" aria-label="close" on:click={closeWindow}></button>
</header>
<section class="modal-card-body">
<p>Bist du dir sicher, dass du die Inventur abbrechen willst? Damit werden alle bereits eingegebenen Werte zurückgesetzt.</p>
</section>
<footer class="modal-card-foot">
<button class="button is-danger" on:click={inventoryApi.reset}>Ja, Reset!</button>
<button class="button" on:click={closeWindow}>Abbrechen</button>
</footer>
{:else if finishKind === "finish"}
<!--Prevent saving empty inventories-->
{#if $inventory.length > 0}
<header class="modal-card-head">
<p class="modal-card-title">Inventur abschließen ✅</p>
<button class="delete" aria-label="close" on:click={closeWindow}></button>
</header>
<section class="modal-card-body">
<p>
Vielen Dank, dass du eine Inventur gemacht hast! 🫶
<br>
Bitte gib noch deinen <strong>Namen</strong> ein. Außerdem hast du hier noch Platz für irgendwelche <strong>Kommentare</strong> zu deiner Inventur.
</p>
<br>
<div class="field">
<input class="input is-primary" type="text" placeholder="Name" bind:value={name} />
</div>
<div class="field">
<textarea class="textarea is-info" placeholder="Kommentare" bind:value={comment} />
</div>
</section>
<footer class="modal-card-foot">
{#if name.length > 0}
<button class="button is-primary" on:click={() => {
// TODO: Hier muss dann der Request an das Backend rausgehen!
closeWindow();
successWindow.showWindow();
setTimeout(() => inventoryApi.reset(), 2000);
}}>Abschließen</button>
{:else}
<button class="button" disabled>Abschließen</button>
{/if}
<button class="button" on:click={closeWindow}>Abbrechen</button>
</footer>
{:else}
<section class="modal-card-body">
<p>Du hast noch gar keine Daten erfasst... 🤓</p>
</section>
<footer class="modal-card-foot">
<button class="button" on:click={closeWindow}>Zurück</button>
</footer>
{/if}
{/if}
</div>
</div>
<Success bind:this={successWindow} />

View File

@ -1,9 +1,10 @@
<script lang="ts">
import { inventory } from "../stores/inventory";
</script>
<article class="message is-info">
<div class="message-header">
<p>Hallo! Schön, dass du eine Inventur machen möchtest. :)</p>
<p>Hallo! Schön, dass du eine Inventur machen möchtest. 🙂</p>
</div>
<div class="message-body">
<p>
@ -11,18 +12,20 @@
<br>
Dein Fortschritt wird gespeichert, bis du mit Klick auf <span class="tag is-primary"><strong>Abschluss</strong></span> die Inventur abschließt.
<br>
Wenn du neu starten möchtest, klicke auf <span class="tag is-danger"><strong>Reset</strong></span>.
<br><br>
Zurück hierher kommst du, wenn du oben auf das Spartacus-Logo klickst.
</p>
</div>
</article>
{#if $inventory.some(item => "timestamp" in item)}
<article class="message is-link">
<div class="message-body">
<p>
Inventur begonnen am TBD
<!-- Wenn schon was im local storage liegt, sollte der Zeitpunkt der Erstellung hier genannt werden -->
Du hast <strong>am {$inventory.at(-1).timestamp}</strong> auf deinem aktuellen Gerät eine Inventur gestartet.
<br>
Klicke oben rechts auf <span class="tag is-danger"><strong>Reset</strong></span>, wenn du deinen Fortschritt löschen möchtest.
</p>
</div>
</article>
{/if}

View File

@ -2,12 +2,18 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<script lang="ts">
import { activeCategory, drinks } from "../stores/drinks.js";
import { onMount } from "svelte";
import Drink from "./Drink.svelte";
import Info from "./Info.svelte";
import { activeCategory, drinks, inventory } from "../stores/inventory.js";
import inventoryApi from "../stores/api";
$: filteredDrinks = $drinks.filter(drink => drink.type == $activeCategory);
onMount(async () => {
$inventory = await inventoryApi.load();
})
</script>
<section class="section">
@ -15,9 +21,24 @@
{#if $activeCategory == ""}
<Info />
{:else}
<div class="block">
<div class="subtitle">
{#if $activeCategory === "beer"}
<strong>Bier 🍺</strong>
{:else if $activeCategory === "fizzyDrink"}
<strong>Brause & Wasser 💧</strong>
{:else if $activeCategory === "wine"}
<strong>Wein 🍷</strong>
{:else}
<strong>Schnaps & Sirup 🥃</strong>
{/if}
</div>
</div>
<div class="block">
{#each filteredDrinks as drink (drink.name)}
<Drink drinkName={drink.name} />
{/each}
</div>
{/if}
</div>
</section>

View File

@ -2,13 +2,34 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<script lang="ts">
import { activeCategory } from "../stores/drinks";
import { activeCategory } from "../stores/inventory";
import { inventory } from "../stores/inventory";
import Finish from "./Finish.svelte";
let sparti_logo = "./src/assets/sparti_logo.png";
let resetOrFinish = "";
let modalWindow;
let burgerMenuActive = "";
const drinkCategories = [
{name: "beer", friendlyName: "Bier"},
{name: "fizzyDrink", friendlyName: "Brause & Wasser"},
{name: "wine", friendlyName: "Wein"},
{name: "spirit", friendlyName: "Schnaps & Sirup"},
]
const setActiveCategory = (category: string) => {
$activeCategory = category;
}
const setFinishKind = (kind: string) => {
resetOrFinish = kind;
}
const toggleBurgerMenu = () => {
burgerMenuActive = burgerMenuActive === "is-active" ? "" : "is-active"
}
</script>
<nav class="navbar is-light is-spaced has-shadow is-fixed-top">
@ -16,39 +37,56 @@
<a on:click={() => setActiveCategory("")} class="navbar-item">
<img src={sparti_logo} />
</a>
<a role="button" class="navbar-burger {burgerMenuActive}" on:click={toggleBurgerMenu} aria-label="menu" aria-expanded="false" data-target="spartacusNavbar">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu">
<div class="navbar-menu {burgerMenuActive}" id="spartacusNavbar">
<div class="navbar-start">
<a class="navbar-item" on:click={() => setActiveCategory("beer")}>
Bier
</a>
<a class="navbar-item" on:click={() => setActiveCategory("fizzyDrink")}>
Brause & Wasser
</a>
<a class="navbar-item" on:click={() => setActiveCategory("wine")}>
Wein & Sekt
</a>
<a class="navbar-item" on:click={() => setActiveCategory("spirit")}>
Schnaps & Sirup
{#each drinkCategories as category (category.name)}
<a class="navbar-item" on:click={() => {
setActiveCategory(category.name);
toggleBurgerMenu();
}
}>
{category.friendlyName}
</a>
{/each}
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<a on:click={() => console.log("TBD")} class="button is-primary">
<a on:click={
() => {
setFinishKind("finish");
modalWindow.showWindow()
}
} class="button is-primary">
<strong>Abschluss</strong>
<!-- Hier sollte dann auch ein Name eingegeben werden -->
</a>
</div>
</div>
{#if $inventory.length > 0}
<div class="navbar-item">
<div class="buttons">
<a on:click={() => console.log("TBD")} class="button is-danger">
<a on:click={
() => {
setFinishKind("reset");
modalWindow.showWindow()
}
} class="button is-danger">
<strong>Reset</strong>
</a>
</div>
</div>
{/if}
</div>
</div>
</nav>
<Finish bind:this={modalWindow} finishKind={resetOrFinish} />

25
src/lib/Success.svelte Normal file
View File

@ -0,0 +1,25 @@
<script lang="ts">
let windowIsVisible = "";
export const showWindow = () => windowIsVisible = "is-active";
const closeWindow = () => {
windowIsVisible = "";
};
</script>
<div class="modal {windowIsVisible}">
<div class="modal-background"/>
<div class="card">
<div class="card-content">
<p class="title">
Inventur abgeschlossen. Danke! ✨
</p>
<p class="subtitle">
Die Seite wird gleich automatisch neu geladen...
</p>
<!--Just a small, decorative, indefinite progress bar-->
<progress class="progress is-small is-primary" />
</div>
</div>
</div>

14
src/stores/api.js Normal file
View File

@ -0,0 +1,14 @@
export default class inventoryApi {
static async save(drinks) {
localStorage.setItem("drinks", JSON.stringify(drinks));
}
static async load() {
return JSON.parse(localStorage.getItem("drinks") || "[]");
}
static async reset() {
localStorage.removeItem("drinks");
window.location.reload();
}
}

View File

@ -1,46 +0,0 @@
import { readable, writable } from "svelte/store"
export const drinks = readable([
// Biere
{ name: "Sternburg Export (0,5 l)", type: "beer" },
{ name: "PU (0,5 l)", type: "beer" },
{ name: "Gösser Radler (0,5 l)", type: "beer" },
{ name: "Paulaner Hefe alkoholfrei (0,5 l)", type: "beer" },
{ name: "Augustiner Lagerbier Hell (0,5 l)", type: "beer" },
{ name: "Störtebeker Atlantik-Ale (0,33 l)", type: "beer" },
// Brause & Wasser
{ name: "Soli Mate (0,5 l)", type: "fizzyDrink" },
{ name: "Schneiders Spezi (0,5 l)", type: "fizzyDrink" },
{ name: "Proviant Cola (0,33 l)", type: "fizzyDrink" },
{ name: "Proviant Zitrone (0,33 l)", type: "fizzyDrink" },
{ name: "Proviant Orange (0,33 l)", type: "fizzyDrink" },
{ name: "Proviant Apfelschorle (0,33 l)", type: "fizzyDrink" },
{ name: "Proviant Rhabarber (0,33 l)", type: "fizzyDrink" },
{ name: "Märkisch Kristall Classic PET (0,5 l)", type: "fizzyDrink" },
{ name: "Märkisch Kristall Naturelle PET (0,5 l)", type: "fizzyDrink" },
{ name: "Afri Cola (1,0 l)", type: "fizzyDrink" },
{ name: "Tonic Water Bad Liebenwerder (1,0 l)", type: "fizzyDrink" },
{ name: "Bitter Lemon Bad Liebenwerder (1,0 l)", type: "fizzyDrink" },
{ name: "Ginger Ale Bad Liebenwerder (1,0 l)", type: "fizzyDrink" },
{ name: "ChariTea Black (0,33 l)", type: "fizzyDrink" },
{ name: "ChariTea Green (0,33 l)", type: "fizzyDrink" },
// Wein & Sekt
{ name: "OBC Cidre Stark (0,33 l)", type: "wine" },
{ name: "OBC Cidre Classic (0,33 l)", type: "wine" },
{ name: "Pinot Grigio (0,75 l)", type: "wine" },
{ name: "Rotwein Montepulciano (1,5 l)", type: "wine" },
{ name: "Lehmann Hausmarke Frizzante (0,75 l)", type: "wine" },
// Schnaps & Sirup
{ name: "Vodka Partisan Black (1,0 l)", type: "spirit" },
{ name: "Gordon's London Dry Gin (1,0 l)", type: "spirit" },
{ name: "Absinth Tabu Classic 55% (1,0 l)", type: "spirit" },
{ name: "Tequila Jose Cuervo Silver (1,0 l)", type: "spirit" },
{ name: "Havanna (1,0 l)", type: "spirit" },
{ name: "'51' Cachaca (1,0 l)", type: "spirit" },
{ name: "Berliner Luft (0,7 l)", type: "spirit" },
])
export const activeCategory = writable("")

View File

@ -1,3 +1,48 @@
import { writable } from "svelte/store"
import { readable, writable } from "svelte/store"
export const drinks = readable([
// Biere
{ name: "Sternburg Export (0,5 l)", type: "beer" },
{ name: "PU (0,5 l)", type: "beer" },
{ name: "Gösser Radler (0,5 l)", type: "beer" },
{ name: "Paulaner Hefe alkoholfrei (0,5 l)", type: "beer" },
{ name: "Augustiner Lagerbier Hell (0,5 l)", type: "beer" },
{ name: "Störtebeker Atlantik-Ale (0,33 l)", type: "beer" },
// Brause & Wasser
{ name: "Soli Mate (0,5 l)", type: "fizzyDrink" },
{ name: "Schneiders Spezi (0,5 l)", type: "fizzyDrink" },
{ name: "Proviant Cola (0,33 l)", type: "fizzyDrink" },
{ name: "Proviant Zitrone (0,33 l)", type: "fizzyDrink" },
{ name: "Proviant Orange (0,33 l)", type: "fizzyDrink" },
{ name: "Proviant Apfelschorle (0,33 l)", type: "fizzyDrink" },
{ name: "Proviant Rhabarber (0,33 l)", type: "fizzyDrink" },
{ name: "Märkisch Kristall Classic PET (0,5 l)", type: "fizzyDrink" },
{ name: "Märkisch Kristall Naturelle PET (0,5 l)", type: "fizzyDrink" },
{ name: "Afri Cola (1,0 l)", type: "fizzyDrink" },
{ name: "Tonic Water Bad Liebenwerder (1,0 l)", type: "fizzyDrink" },
{ name: "Bitter Lemon Bad Liebenwerder (1,0 l)", type: "fizzyDrink" },
{ name: "Ginger Ale Bad Liebenwerder (1,0 l)", type: "fizzyDrink" },
{ name: "ChariTea Black (0,33 l)", type: "fizzyDrink" },
{ name: "ChariTea Green (0,33 l)", type: "fizzyDrink" },
// Wein & Sekt
{ name: "OBC Cidre Stark (0,33 l)", type: "wine" },
{ name: "OBC Cidre Classic (0,33 l)", type: "wine" },
{ name: "Pinot Grigio (0,75 l)", type: "wine" },
{ name: "Rotwein Montepulciano (1,5 l)", type: "wine" },
{ name: "Lehmann Hausmarke Frizzante (0,75 l)", type: "wine" },
// Schnaps & Sirup
{ name: "Vodka Partisan Black (1,0 l)", type: "spirit" },
{ name: "Gordon's London Dry Gin (1,0 l)", type: "spirit" },
{ name: "Absinth Tabu Classic 55% (1,0 l)", type: "spirit" },
{ name: "Tequila Jose Cuervo Silver (1,0 l)", type: "spirit" },
{ name: "Havanna (1,0 l)", type: "spirit" },
{ name: "'51' Cachaca (1,0 l)", type: "spirit" },
{ name: "Berliner Luft (0,7 l)", type: "spirit" },
])
export const activeCategory = writable("")
export const inventory = writable([])