diff --git a/AGENTS.md b/AGENTS.md index ff334a9..a3f878d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,10 @@ Beer-inventory project for home use. +The project has three aspects. + - The website, which people can visit to see the current inventory of drinks. They can see in which section a drink is stored. + - The Admin website, which is part of the main website but only to logged in admin users. Which allows updating drinks, inventory, and adding or editing data. + - The scanner, which is a raspberry pi with touchscreen display and a USB barcode scanner. This is next to the fridge, and people use it to scan a drink to remove it from the inventory. + Used technology: - remix.run (now known as react router) - prisma diff --git a/app/components/filters/drink.filter.tsx b/app/components/filters/drink.filter.tsx index 7c7f7b6..e0b29c5 100644 --- a/app/components/filters/drink.filter.tsx +++ b/app/components/filters/drink.filter.tsx @@ -2,7 +2,7 @@ import { useSubmit } from '@remix-run/react'; import { BeerStyle, Manufacturer, WineStyle } from '@zenstackhq/runtime/models'; import { useRef, useState } from 'react'; -import { Form, Col, Row } from 'react-bootstrap'; +import { Button, Form, Col, Row } from 'react-bootstrap'; interface Arguments { beerStyles: BeerStyle[]; @@ -20,11 +20,28 @@ function DrinkFilter(arg : Arguments) { const showSodaFilter = arg.searchParams.has("drink", "Soda"); const showCocktailFilter = arg.searchParams.has("drink", "Cocktail"); - const form = useRef(null); + const form = useRef(null); + const drinkTypes = ["Beer", "Wine", "Soda", "Cocktail"]; + const [beerStyleExpanded, setBeerStyleExpanded] = useState(false); + const [wineStyleExpanded, setWineStyleExpanded] = useState(false); - const submitAfterRender = function(){ - setTimeout(() => submit(form.current), 10); - } + const toggleDrinkType = (drinkType: string) => { + const params = new URLSearchParams(arg.searchParams.toString()); + const values = params.getAll("drink"); + + if (values.includes(drinkType)) { + params.delete("drink"); + values.filter((value) => value !== drinkType).forEach((value) => params.append("drink", value)); + } else { + params.append("drink", drinkType); + } + + if (params.get("abv") === "all") { + params.delete("abv"); + } + + submit(params, { method: "get", replace: true }); + }; const handleFormChange = (event: React.ChangeEvent) => { const formData = new FormData(event.currentTarget); @@ -37,6 +54,8 @@ function DrinkFilter(arg : Arguments) { } const abvSelection = arg.searchParams.get("abv") || "all"; + const selectedBeerStyleCount = arg.searchParams.getAll("beerstyle").length; + const selectedWineStyleCount = arg.searchParams.getAll("winestyle").length; const abvOptions = [ { value: "all", label: "All" }, { value: "alcohol-free", label: "Alcohol free" }, @@ -87,17 +106,24 @@ function DrinkFilter(arg : Arguments) { Drink Type - { ["Beer", "Wine", "Soda", "Cocktail"].map(key => ( - +
+ {drinkTypes.map((key) => ( +
+ +
+ ))} +
+ {arg.searchParams.getAll("drink").map((drinkValue) => ( + ))} -
Alcohol Percentage @@ -119,34 +145,67 @@ function DrinkFilter(arg : Arguments) { { showBeerFilter ? ( <> - Beer style - { arg.beerStyles.map(style => ( - - ))} +
+ Beer style {selectedBeerStyleCount > 0 ? ( {selectedBeerStyleCount} selected) : ''} + +
+ {beerStyleExpanded ? ( +
+ { arg.beerStyles.map(style => ( + + ))} +
+ ) : ( +
Tap expand to show beer styles
+ )}
) : ""} { showWineFilter ? ( - Wine style - { arg.wineStyles.map(style => ( - - ))} - +
+ Wine style {selectedWineStyleCount > 0 ? ( {selectedWineStyleCount} selected) : ''} + +
+ {wineStyleExpanded ? ( +
+ { arg.wineStyles.map(style => ( + + ))} +
+ ) : ( +
Tap expand to show wine styles
+ )} +
) : ""} { showSodaFilter ? ( diff --git a/app/root.tsx b/app/root.tsx index 8a94a87..014a88b 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -83,7 +83,7 @@ export function ErrorBoundary() { const hourly = window.setInterval(() => { tryRefresh(); - }, 60 * 60 * 1000); + }, 15 * 60 * 1000); // Every 15 minutes return () => { window.removeEventListener("online", handleOnline); @@ -120,7 +120,7 @@ export function ErrorBoundary() { > Try refresh now -
Status: {isOnline ? "Online" : "Offline"}. Will retry automatically every hour.
+
Status: {isOnline ? "Online" : "Offline"}. Will retry automatically every 15 minutes.
@@ -159,7 +159,7 @@ export function ErrorBoundary() { > Try refresh now -
Status: {isOnline ? "Online" : "Offline"}. Will retry automatically every hour.
+
Status: {isOnline ? "Online" : "Offline"}. Will retry automatically every 15 minutes.
diff --git a/app/routes/scan/layout.tsx b/app/routes/scan/layout.tsx index d660e83..a1cb165 100644 --- a/app/routes/scan/layout.tsx +++ b/app/routes/scan/layout.tsx @@ -41,7 +41,7 @@ export default function InventoryLayout() { setCheckouts(newCheckouts); } - }, 5000); + }, 30000); return () => clearTimeout(timer); }); diff --git a/app/routes/scan/route.tsx b/app/routes/scan/route.tsx index d69cb0f..5992927 100644 --- a/app/routes/scan/route.tsx +++ b/app/routes/scan/route.tsx @@ -1,8 +1,8 @@ import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node"; import { json, redirect } from "@remix-run/node"; -import { useActionData, useLoaderData } from "@remix-run/react"; +import { Form as RemixForm, useActionData, useLoaderData } from "@remix-run/react"; import { useEffect, useRef, useState } from "react"; -import { Col, Container, Form, Row, Table } from "react-bootstrap"; +import { Col, Container, Form as BootstrapForm, Row, Table } from "react-bootstrap"; import timeAgo from "~/utils/datetime"; import { enhance } from "~/utils/db.server"; @@ -16,7 +16,7 @@ export async function loader({ return redirect("/"); } - const history = await dbe.history.findMany({select: {id: true, checkoutAt: true, inventoryAfter: true, container: {select: {drink: true}}}, take: 10, orderBy: {checkoutAt: "desc"}}); + const history = await dbe.history.findMany({select: {id: true, checkoutAt: true, inventoryAfter: true, container: {select: {drink: true}}}, take: 5, orderBy: {checkoutAt: "desc"}}); return json({history}); } @@ -116,6 +116,10 @@ export default function ScanRoute() { return; } + if (inputRef.current) { + inputRef.current.value = ""; + } + setLastScanned(aData.lastScanned); setShowLastScanned(true); @@ -137,7 +141,7 @@ export default function ScanRoute() { Drink When - Amount left + # Left @@ -158,14 +162,15 @@ export default function ScanRoute() { {/* Hidden fullscreen toggle button - triggered by clicking the h3 headers */}