From 4a2dfc6a846deb6fa192b8870be427e482a89a92 Mon Sep 17 00:00:00 2001 From: kennyboy55 Date: Tue, 25 Jun 2024 20:04:14 +0200 Subject: [PATCH] Graph colors, page titles and many more fixes --- app/components/filters/drink.filter.tsx | 31 ++++++++------- app/models/history.chart.server.ts | 16 ++++---- app/models/type.chart.server.ts | 29 +++++++------- app/root.tsx | 3 +- app/routes/admin/edit/checkout.tsx | 5 +++ app/routes/admin/edit/remove/checkout.$id.tsx | 15 ++++++++ app/routes/admin/layout.tsx | 6 ++- app/routes/inventory/beer.$beerslug.tsx | 9 ++++- .../inventory/cocktail.$cocktailslug.tsx | 9 ++++- app/routes/inventory/layout.tsx | 5 ++- app/routes/inventory/route.tsx | 2 +- app/routes/inventory/soda.$sodaslug.tsx | 9 ++++- app/routes/inventory/stats/route.tsx | 38 +++++++++++-------- app/routes/inventory/suggestions/route.tsx | 6 ++- app/routes/inventory/wine.$wineslug.tsx | 9 ++++- app/utils/arrays.ts | 16 ++++++++ app/utils/color.ts | 16 ++++++++ vite.config.ts | 1 + 18 files changed, 167 insertions(+), 58 deletions(-) create mode 100644 app/routes/admin/edit/remove/checkout.$id.tsx diff --git a/app/components/filters/drink.filter.tsx b/app/components/filters/drink.filter.tsx index 403757f..77b1a3e 100644 --- a/app/components/filters/drink.filter.tsx +++ b/app/components/filters/drink.filter.tsx @@ -110,19 +110,6 @@ const sliderIbu = () => ))} - - Drink - { ["Sugar-free", "Gluten-free", "Organic"].map(key => ( - - ))} - ABV {sliderAbv()} @@ -214,6 +201,19 @@ const sliderIbu = () => /> ) : ""} + + Drink + { ["Sugar-free", "Gluten-free", "Organic"].map(key => ( + + ))} + No Inventory + + + Results are updated live + + ); } diff --git a/app/models/history.chart.server.ts b/app/models/history.chart.server.ts index cd3383d..b179684 100644 --- a/app/models/history.chart.server.ts +++ b/app/models/history.chart.server.ts @@ -1,5 +1,5 @@ import { enhance } from "@zenstackhq/runtime"; -import { random_rgba } from "~/utils/color"; +import { drinkTypeToColor, random_rgba } from "~/utils/color"; import timeAgo from "~/utils/datetime"; import { db } from "~/utils/db.server"; import { randomRange } from "~/utils/random"; @@ -25,6 +25,7 @@ export async function generateMonthChartData(){ // History of specific drink const containersWithHistory = await dbe.container.findMany({ + orderBy: [{drink: {type: "asc"}}, {checkouts: {_count: "desc"}}], include: {drink: true, checkouts: {orderBy: {checkoutAt: "asc"}, where: {checkoutAt: {gte: dates[0]}}}} }) @@ -86,14 +87,14 @@ export async function generateMonthChartData(){ inventoryAfter[i] = totalInventory; } - let [color1] = random_rgba(1); + let color = drinkTypeToColor(container.drink.type); datasets.push({ type: 'bar', label: 'Checkouts ' + container.drink.name, data: checkouts, - borderColor: color1, - backgroundColor: color1, + borderColor: color, + backgroundColor: color, }); } @@ -126,6 +127,7 @@ export async function generateMonthChartData(){ // History of specific drink const containersWithHistory = await dbe.container.findMany({ + orderBy: [{drink: {type: "asc"}}, {checkouts: {_count: "desc"}}], include: {drink: true, checkouts: {orderBy: {checkoutAt: "asc"}, where: {checkoutAt: {gte: hours[0]}}}} }) @@ -187,14 +189,14 @@ export async function generateMonthChartData(){ inventoryAfter[i] = totalInventory; } - let [color1] = random_rgba(1); + let color = drinkTypeToColor(container.drink.type); datasets.push({ type: 'bar', label: 'Checkouts ' + container.drink.name, data: checkouts, - borderColor: color1, - backgroundColor: color1, + borderColor: color, + backgroundColor: color, }); } diff --git a/app/models/type.chart.server.ts b/app/models/type.chart.server.ts index 448954e..4ee0d0d 100644 --- a/app/models/type.chart.server.ts +++ b/app/models/type.chart.server.ts @@ -1,9 +1,8 @@ import { DrinkType } from "@prisma/client"; import { enhance } from "@zenstackhq/runtime"; -import { hexToRGB, random_rgba } from "~/utils/color"; -import timeAgo from "~/utils/datetime"; +import { sortArrays } from "~/utils/arrays"; +import { drinkTypeToColor, hexToRGB } from "~/utils/color"; import { db } from "~/utils/db.server"; -import { randomRange } from "~/utils/random"; export async function generateTypeInventoryChartData(){ const dbe = enhance(db); @@ -19,7 +18,7 @@ export async function generateTypeInventoryChartData(){ let typeT = DrinkType[type]; labels.push(type); - colors.push(random_rgba(1)[0]); + colors.push(drinkTypeToColor(typeT)); const aggregate = await dbe.container.aggregate({_sum: {inventory: true}, where: {drink: {type: typeT}}}); numset.push(aggregate._sum.inventory ?? 0); @@ -56,7 +55,7 @@ export async function generateTypeInventoryChartData(){ let colors : string[] = []; let numset : number[] = []; - const beerstyle = await dbe.beerStyle.findMany({}); + const beerstyle = await dbe.beerStyle.findMany({orderBy: {beers: {_count: "desc"}}}); for(let style of beerstyle){ labels.push(style.name); @@ -67,13 +66,15 @@ export async function generateTypeInventoryChartData(){ numset.push(reduced); } + let [sortedNumset, sortedColors, sortedLabels] = sortArrays([numset, colors, labels]); + const data = { - labels, + labels: sortedLabels, datasets: [{ type: 'doughnut', label: 'Inventory', - data: numset, - backgroundColor: colors, + data: sortedNumset, + backgroundColor: sortedColors, }] }; @@ -93,7 +94,7 @@ export async function generateTypeInventoryChartData(){ let typeT = DrinkType[type]; labels.push(type); - colors.push(random_rgba(1)[0]); + colors.push(drinkTypeToColor(typeT)); const aggregate = await dbe.history.aggregate({_count: {_all: true}, where: {container: {drink: {type: typeT}}}}); numset.push(aggregate._count._all ?? 0); @@ -130,7 +131,7 @@ export async function generateTypeInventoryChartData(){ let colors : string[] = []; let numset : number[] = []; - const beerstyle = await dbe.beerStyle.findMany({}); + const beerstyle = await dbe.beerStyle.findMany({orderBy: {beers: {_count: "desc"}}}); for(let style of beerstyle){ labels.push(style.name); @@ -141,13 +142,15 @@ export async function generateTypeInventoryChartData(){ numset.push(reduced); } + let [sortedNumset, sortedColors, sortedLabels] = sortArrays([numset, colors, labels]); + const data = { - labels, + labels: sortedLabels, datasets: [{ type: 'doughnut', label: 'Checked out', - data: numset, - backgroundColor: colors, + data: sortedNumset, + backgroundColor: sortedColors, }] }; diff --git a/app/root.tsx b/app/root.tsx index 460e3d0..9f5d2f4 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,6 +1,7 @@ import type { LinksFunction } from "@remix-run/node"; import { Links, + Meta, Outlet, Scripts, ScrollRestoration, @@ -29,7 +30,7 @@ function Document({ name="viewport" content="width=device-width, initial-scale=1" /> - {title} + diff --git a/app/routes/admin/edit/checkout.tsx b/app/routes/admin/edit/checkout.tsx index 0c1ed0d..7b52210 100644 --- a/app/routes/admin/edit/checkout.tsx +++ b/app/routes/admin/edit/checkout.tsx @@ -36,6 +36,11 @@ export default function EditContainerRoute() { {timeAgo(new Date(checkout.checkoutAt))} - {checkout.checkoutAt.slice(0,-5)} {checkout.inventoryAfter} left
+ + + diff --git a/app/routes/inventory/soda.$sodaslug.tsx b/app/routes/inventory/soda.$sodaslug.tsx index 4af4742..1b603cb 100644 --- a/app/routes/inventory/soda.$sodaslug.tsx +++ b/app/routes/inventory/soda.$sodaslug.tsx @@ -1,5 +1,6 @@ import type { - LoaderFunctionArgs + LoaderFunctionArgs, + MetaFunction } from "@remix-run/node"; import { json } from "@remix-run/node"; import { @@ -50,6 +51,12 @@ export default function SodaRoute() { ); } +export const meta: MetaFunction = ({ + data, +}) => { + return [{ title: data?.soda.name + " | K-FRIDGE" }]; +}; + export function ErrorBoundary() { const { sodaid } = useParams(); const error = useRouteError(); diff --git a/app/routes/inventory/stats/route.tsx b/app/routes/inventory/stats/route.tsx index c717c6c..b7172b3 100644 --- a/app/routes/inventory/stats/route.tsx +++ b/app/routes/inventory/stats/route.tsx @@ -14,6 +14,8 @@ import 'chart.js/auto'; import { db } from "~/utils/db.server"; import { generateBeerHistoryChartData, generateBeerInventoryChartData, generateTypeHistoryChartData, generateTypeInventoryChartData } from "~/models/type.chart.server"; +import { drinkTypeToColor } from "~/utils/color"; +import { DrinkType } from "@prisma/client"; function statsForContainers(containers : ContainerWithDrink[]){ var drinksInventory = 0; @@ -119,6 +121,10 @@ export const loader = async ({request} : LoaderFunctionArgs) => { return json({total, chartDataTotal, chartDataBeerTotal, statsLast24H, chartData24H, statsLastMonth, chartDataMonth, statsTotal, chartDataHistoryTotal, chartDataBeerHistoryTotal, history}); }; +export const meta: MetaFunction = ({}) => { + return [{ title: "Stats | K-FRIDGE" }]; +}; + export default function StatsRoute() { const loadData = useLoaderData(); @@ -208,19 +214,19 @@ export default function StatsRoute() { {loadData.total.drinksInventory} - # Beers + # Beers {loadData.total.beersInventory} - # Wines + # Wines {loadData.total.wineInventory} - # Sodas + # Sodas {loadData.total.sodaInventory} - # Cocktails + # Cocktails {loadData.total.cocktailInventory} @@ -273,19 +279,19 @@ export default function StatsRoute() { {loadData.statsTotal.drinksInventory} - # Beers + # Beers {loadData.statsTotal.beersInventory} - # Wines + # Wines {loadData.statsTotal.wineInventory} - # Sodas + # Sodas {loadData.statsTotal.sodaInventory} - # Cocktails + # Cocktails {loadData.statsTotal.cocktailInventory} @@ -338,19 +344,19 @@ export default function StatsRoute() { {loadData.statsLastMonth.drinksInventory} - # Beers + # Beers {loadData.statsLastMonth.beersInventory} - # Wines + # Wines {loadData.statsLastMonth.wineInventory} - # Sodas + # Sodas {loadData.statsLastMonth.sodaInventory} - # Cocktails + # Cocktails {loadData.statsLastMonth.cocktailInventory} @@ -394,19 +400,19 @@ export default function StatsRoute() { {loadData.statsLast24H.drinksInventory} - # Beers + # Beers {loadData.statsLast24H.beersInventory} - # Wines + # Wines {loadData.statsLast24H.wineInventory} - # Sodas + # Sodas {loadData.statsLast24H.sodaInventory} - # Cocktails + # Cocktails {loadData.statsLast24H.cocktailInventory} diff --git a/app/routes/inventory/suggestions/route.tsx b/app/routes/inventory/suggestions/route.tsx index e8aa573..e1fd368 100644 --- a/app/routes/inventory/suggestions/route.tsx +++ b/app/routes/inventory/suggestions/route.tsx @@ -1,4 +1,4 @@ -import { ActionFunctionArgs, EntryContext, LoaderFunctionArgs, json } from "@remix-run/node"; +import { ActionFunctionArgs, EntryContext, LoaderFunctionArgs, MetaFunction, json } from "@remix-run/node"; import { useLoaderData } from "@remix-run/react"; import { Button, Col, Container, Form, Row, Table } from "react-bootstrap"; import { LinkContainer } from "react-router-bootstrap"; @@ -44,6 +44,10 @@ export const loader = async ({request} : LoaderFunctionArgs) => { return json({suggestions, isAdmin}); }; +export const meta: MetaFunction = ({}) => { + return [{ title: "Suggestions | K-FRIDGE" }]; +}; + export default function SuggestionsRoute() { const loadData = useLoaderData(); diff --git a/app/routes/inventory/wine.$wineslug.tsx b/app/routes/inventory/wine.$wineslug.tsx index 3376dc1..410d330 100644 --- a/app/routes/inventory/wine.$wineslug.tsx +++ b/app/routes/inventory/wine.$wineslug.tsx @@ -1,5 +1,6 @@ import type { - LoaderFunctionArgs + LoaderFunctionArgs, + MetaFunction } from "@remix-run/node"; import { json } from "@remix-run/node"; import { @@ -50,6 +51,12 @@ export default function WineRoute() { ); } +export const meta: MetaFunction = ({ + data, +}) => { + return [{ title: data?.wine.name + " | K-FRIDGE" }]; +}; + export function ErrorBoundary() { const { wineid } = useParams(); const error = useRouteError(); diff --git a/app/utils/arrays.ts b/app/utils/arrays.ts index c657e4d..cad3cc4 100644 --- a/app/utils/arrays.ts +++ b/app/utils/arrays.ts @@ -5,4 +5,20 @@ export function shuffleArray(array : any[]) { array[i] = array[j]; array[j] = temp; } +} + +/** + * Sorts all arrays together with the first. Pass either a list of arrays, or a map. Any key is accepted. + * Array|Object arrays [sortableArray, ...otherArrays]; {sortableArray: [], secondaryArray: [], ...} + * Function comparator(?,?) -> int optional compareFunction, compatible with Array.sort(compareFunction) + */ +export function sortArrays(arrays : any[][], comparator = (a:any, b:any) => (a < b) ? 1 : (a > b) ? -1 : 0) { + let arrayKeys = Object.keys(arrays); + let sortableArray : (typeof arrays[0][0]) = Object.values(arrays)[0]; + let indexes = Object.keys(sortableArray); + let sortedIndexes = indexes.sort((a, b) => comparator(sortableArray[a], sortableArray[b])); + + let sortByIndexes = (array : any[], sortedIndexes : number[]) => sortedIndexes.map(sortedIndex => array[sortedIndex]); + + return arrayKeys.map(arrayIndex => sortByIndexes(arrays[arrayIndex], sortedIndexes)); } \ No newline at end of file diff --git a/app/utils/color.ts b/app/utils/color.ts index 8c20609..df27198 100644 --- a/app/utils/color.ts +++ b/app/utils/color.ts @@ -1,3 +1,5 @@ +import { DrinkType } from "@prisma/client"; + export function random_rgba(numShades : number) { let o = Math.round, r = Math.random, s = 155, m = 100; @@ -24,4 +26,18 @@ export function hexToRGB(hex : string, alpha : number) { } else { return "rgb(" + r + ", " + g + ", " + b + ")"; } +} + +export function drinkTypeToColor(type: DrinkType){ + switch(type){ + default: + case DrinkType.Beer: + return 'rgba(255, 164, 18, 1)'; + case DrinkType.Cocktail: + return 'rgba(83, 185, 219, 1)'; + case DrinkType.Soda: + return 'rgba(188, 71, 214, 1)'; + case DrinkType.Wine: + return 'rgba(178, 21, 58, 1)' + } } \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 0d1b9f5..bec423e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -107,6 +107,7 @@ export default defineConfig({ route("edit/checkout", "routes/admin/edit/checkout.tsx"); route("edit/checkout/:id", "routes/admin/edit/checkout.$id.tsx"); + route("remove/checkout/:id", "routes/admin/edit/remove/checkout.$id.tsx"); route("remove/checkouts/:containerid", "routes/admin/edit/remove/checkouts.$containerid.tsx"); route("remove/suggestion/:id", "routes/admin/edit/remove/suggestion.$id.tsx");