Clean imports, add suggestions and recommendations

This commit is contained in:
2024-05-29 09:40:39 +02:00
parent 5113177e6d
commit c70090e0d5
42 changed files with 325 additions and 106 deletions
-1
View File
@@ -1,5 +1,4 @@
import { DrinkType } from '@prisma/client';
import { Link } from '@remix-run/react';
import { Badge, Card, ListGroup } from 'react-bootstrap';
import { DrinkComposite, isBeer, isDrinkWithContainers, isDrinkWithManufacturer, isDrinkWithStyle } from '~/models/types';
+14
View File
@@ -4,9 +4,11 @@ import { Alert, Badge, Button, Col, Container, Image, Row, Table } from 'react-b
import { LinkContainer } from 'react-router-bootstrap';
import { ContainerWithSection, DrinkComposite, containerTypeToString, isBeer, isDrinkWithContainersAndSection, isDrinkWithManufacturer, isDrinkWithStyle } from '~/models/types';
import { volume } from '~/utils/conversions';
import DrinkCard from './drink.card';
interface Arguments {
drink: DrinkComposite
recommendations: DrinkComposite[]
isAdmin: boolean
}
@@ -181,6 +183,18 @@ function DrinkPage(arg:Arguments) {
</Col>
) : ""}
</Row>
{arg.recommendations.length > 0 ? (
<>
<h3>Maybe also try</h3>
<Row xs={2} md={3} lg={4} className="g-4">
{arg.recommendations.map((drink) => (
<Col >
<DrinkCard drink={drink}></DrinkCard>
</Col>
))}
</Row>
</>
) : ""}
</Container>
);
}
+19 -5
View File
@@ -1,8 +1,8 @@
import { useSubmit } from '@remix-run/react';
import { BeerStyle, Manufacturer, WineStyle } from '@zenstackhq/runtime/models';
import { useEffect, useRef, useState } from 'react';
import { Button, Form, Col, Row } from 'react-bootstrap';
import { useRef, useState } from 'react';
import { Form, Col, Row } from 'react-bootstrap';
import ReactSlider from 'react-slider'
interface Arguments {
@@ -152,11 +152,25 @@ function DrinkFilter(arg : Arguments) {
<Form.Group controlId="soda-carbonated" className='mb-2'>
<Form.Label>Soda</Form.Label>
<Form.Check
type="checkbox"
label="Carbonated"
type="radio"
label="Both"
name="carbonated"
value={0}
defaultChecked={(arg.searchParams.get("carbonated") == "0" || !arg.searchParams.has("carbonated")) ? true : false}
/>
<Form.Check
type="radio"
label="Sparkling"
name="carbonated"
value={1}
defaultChecked={arg.searchParams.has("carbonated") ? true : false}
defaultChecked={arg.searchParams.get("carbonated") == "1" ? true : false}
/>
<Form.Check
type="radio"
label="Non-sparkling"
name="carbonated"
value={2}
defaultChecked={arg.searchParams.get("carbonated") == "2" ? true : false}
/>
</Form.Group>
) : ""}
+3 -1
View File
@@ -1,7 +1,6 @@
import {LinkContainer} from 'react-router-bootstrap'
import {Container, Nav, Navbar, NavDropdown} from 'react-bootstrap';
import { User } from '@zenstackhq/runtime/models';
import { Link } from '@remix-run/react';
import { UserType } from '@prisma/client';
export type HeaderData = {user?: (User)} & {loggedin: boolean};
@@ -38,6 +37,9 @@ function Header(data: Arguments) {
<LinkContainer to="/inventory/stats">
<Nav.Link>Stats</Nav.Link>
</LinkContainer>
<LinkContainer to="/inventory/suggestions">
<Nav.Link>Suggestions</Nav.Link>
</LinkContainer>
{ showScanButtons ? (
<LinkContainer to="/scan">
<Nav.Link>Scan</Nav.Link>
+6 -3
View File
@@ -64,7 +64,7 @@ export async function findDrinksFromSearch(searchParams: URLSearchParams) : Prom
let where = Object.assign({}, whereBase, {style: {}});
// Beer styles
// Wine styles
if(searchParams.has("winestyle")){
where.style = {id: {in: searchParams.getAll("winestyle").map(Number)}};
}
@@ -80,9 +80,12 @@ export async function findDrinksFromSearch(searchParams: URLSearchParams) : Prom
let where = whereBase;
// Carbonated
if(searchParams.has("carbonated")){
if(searchParams.get("carbonated") == "1"){
where = Object.assign({}, whereBase, {carbonated: true});
}
if(searchParams.get("carbonated") == "2"){
where = Object.assign({}, whereBase, {carbonated: false});
}
result = result.concat(await dbe.soda.findMany({
include: {manufacturer: true, containers: {include: {section: true, checkouts: true}}},
@@ -93,7 +96,7 @@ export async function findDrinksFromSearch(searchParams: URLSearchParams) : Prom
if(searchParams.has("drink", "Cocktail") || noDrinkSelected){
let where = whereBase;
// Carbonated
// Mix
if(searchParams.has("mix")){
where = Object.assign({}, whereBase, {mix: true});
}
+51
View File
@@ -2,6 +2,8 @@
import { enhance } from "@zenstackhq/runtime";
import { db } from "~/utils/db.server";
import { DrinkType, Manufacturer } from "@prisma/client";
import { ContainerWithSection, DrinkComposite } from "./types";
import { shuffleArray } from "~/utils/arrays";
export async function findIdFromSlug(slug:string | undefined) : Promise<number | undefined> {
if(slug){
@@ -32,5 +34,54 @@ export async function findManufacturersFromSearch(searchParams: URLSearchParams)
}));
}
return result;
}
export async function getMostCommonSection(containers : ContainerWithSection[]) : Promise<number> {
if(containers.length <= 0) return -1;
const container : ContainerWithSection = containers.reduce((previousValue: ContainerWithSection, currentValue: ContainerWithSection, currentIndex: number, array: ContainerWithSection[]) : ContainerWithSection => {
if(previousValue.inventory > currentValue.inventory) return previousValue;
return currentValue;
})
return container.section_id;
}
export async function findRecommendations(sectionId: number, numRecommendations: number, notId: number) : Promise<DrinkComposite[]> {
const dbe = enhance(db);
const drinksWithSameSection = await dbe.drink.findMany({include: {manufacturer: true, containers: true}, where: {id: {not: notId}, containers: {some: {section_id: sectionId}, every: {inventory: {gt: 0}}}}});
var result : DrinkComposite[] = [];
if(drinksWithSameSection.length > 0){
shuffleArray(drinksWithSameSection);
if(drinksWithSameSection.length <= numRecommendations){
result = drinksWithSameSection;
}
else{
for(var i = 0; i < numRecommendations; i++){
result.push(drinksWithSameSection[i])
}
}
}
else {
const completelyRandomDrinks = await dbe.drink.findMany({include: {manufacturer: true, containers: true}, where: {id: {not: notId}, containers: {every: {inventory: {gt: 0}}}}});
shuffleArray(completelyRandomDrinks);
if(completelyRandomDrinks.length <= numRecommendations){
result = completelyRandomDrinks;
}
else{
for(var i = 0; i < numRecommendations; i++){
result.push(completelyRandomDrinks[i])
}
}
}
return result;
}
+2
View File
@@ -60,5 +60,7 @@ export function containerTypeToString(type: ContainerType){
return "PET";
case "WineBottle":
return "Wine bottle";
case "Keg":
return "Keg";
}
}
+4 -8
View File
@@ -1,13 +1,11 @@
import type { LinksFunction, LoaderFunctionArgs } from "@remix-run/node";
import type { LinksFunction } from "@remix-run/node";
import {
Links,
Scripts,
Outlet,
useRouteError,
Scripts,
ScrollRestoration,
isRouteErrorResponse,
json,
useLoaderData,
ScrollRestoration
useRouteError
} from "@remix-run/react";
import type { PropsWithChildren } from "react";
@@ -17,9 +15,7 @@ export const links: LinksFunction = () => [
{ rel: "stylesheet", href: stylesheet },
];
import Header, { HeaderData } from "~/components/header";
import { Col, Container, Row } from "react-bootstrap";
import { getSession } from "./auth/session";
function Document({
children,
-2
View File
@@ -1,7 +1,5 @@
import { UserType } from "@prisma/client";
import type { LoaderFunctionArgs } from "@remix-run/node";
import {
json,
redirect,
useLoaderData
} from "@remix-run/react";
+2 -2
View File
@@ -1,7 +1,7 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json, redirect } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Container, Row, Col, Button, Form, ListGroup } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Button, Container, Form, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
+2 -4
View File
@@ -1,8 +1,6 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { countBy } from "lodash";
import { Container, Row, Col, Button, Form, ListGroup, Badge } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Badge, Button, Col, Container, ListGroup, Row } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { enhance } from "~/utils/db.server";
+3 -2
View File
@@ -1,10 +1,10 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json, redirect } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { Container, Row, Button, Form, Col, ListGroup, InputGroup } from "react-bootstrap";
import { Button, Container, Form, InputGroup, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
import { ContainerType } from "@prisma/client";
import { enhance } from "~/utils/db.server";
export const action = async ({
request,
@@ -116,6 +116,7 @@ export default function EditContainerRoute() {
<option value={"Carton"} selected={loaderData.container.type == "Carton"}>Carton</option>
<option value={"PlasticBottle"} selected={loaderData.container.type == "PlasticBottle"}>Plastic Bottle</option>
<option value={"WineBottle"} selected={loaderData.container.type == "WineBottle"}>Wine bottle</option>
<option value={"Keg"} selected={loaderData.container.type == "Keg"}>Keg</option>
</Form.Select>
</Form.Group>
+2 -4
View File
@@ -1,8 +1,6 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { countBy } from "lodash";
import { Container, Row, Col, Button, Form, ListGroup, Badge } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Badge, Button, Col, Container, ListGroup, Row } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { containerTypeToString } from "~/models/types";
import { volume } from "~/utils/conversions";
+2 -2
View File
@@ -1,7 +1,7 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json, redirect } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Container, Row, Col, Button, Form, ListGroup } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Button, Container, Form, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
+2 -4
View File
@@ -1,8 +1,6 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { countBy } from "lodash";
import { Container, Row, Col, Button, Form, ListGroup, Badge } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Badge, Button, Col, Container, ListGroup, Row } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { enhance } from "~/utils/db.server";
+2 -4
View File
@@ -1,8 +1,6 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { countBy } from "lodash";
import { Container, Row, Col, Button, Form, ListGroup, Badge } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Badge, Button, Col, Container, ListGroup, Row } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { enhance } from "~/utils/db.server";
+2 -2
View File
@@ -1,7 +1,7 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json, redirect } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Container, Row, Col, Button, Form, ListGroup } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Button, Container, Form, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
+2 -4
View File
@@ -1,8 +1,6 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { countBy } from "lodash";
import { Container, Row, Col, Button, Form, ListGroup, Badge } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Badge, Button, Col, Container, ListGroup, Row } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { enhance } from "~/utils/db.server";
+2 -2
View File
@@ -1,7 +1,7 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json, redirect } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Container, Row, Col, Button, Form, ListGroup } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Button, Container, Form, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
-1
View File
@@ -1,4 +1,3 @@
import { UserType } from "@prisma/client";
import { LoaderFunctionArgs, redirect } from "@remix-run/node";
import { Outlet, json, useLoaderData } from "@remix-run/react";
import { Container, Row } from "react-bootstrap";
-1
View File
@@ -2,7 +2,6 @@ import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { Button, Form } from "react-bootstrap";
import { containerTypeToString } from "~/models/types";
import { enhance } from "~/utils/db.server";
+2 -2
View File
@@ -1,8 +1,8 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, NodeOnDiskFile, json, redirect, unstable_composeUploadHandlers, unstable_createFileUploadHandler, unstable_createMemoryUploadHandler, unstable_parseMultipartFormData } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { renameSync, rmSync } from "node:fs";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Container, Row, Button, Form, Col, ListGroup, InputGroup } from "react-bootstrap";
import { Button, Container, Form, InputGroup, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
+2 -2
View File
@@ -1,8 +1,8 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, NodeOnDiskFile, json, redirect, unstable_composeUploadHandlers, unstable_createFileUploadHandler, unstable_createMemoryUploadHandler, unstable_parseMultipartFormData } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { renameSync, rmSync } from "node:fs";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Container, Row, Button, Form, Col, ListGroup, InputGroup } from "react-bootstrap";
import { Button, Container, Form, InputGroup, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
+4 -3
View File
@@ -1,10 +1,10 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, json, redirect } from "@remix-run/node";
import { isRouteErrorResponse, useLoaderData, useRouteError } from "@remix-run/react";
import { Container, Row, Button, Form, Col, ListGroup, InputGroup } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Button, Container, Form, InputGroup, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
import { ContainerType } from "@prisma/client";
import { enhance } from "~/utils/db.server";
export const action = async ({
request,
@@ -89,6 +89,7 @@ export default function NewContainerRoute() {
<option value={"Carton"}>Carton</option>
<option value={"PlasticBottle"}>Plastic Bottle</option>
<option value={"WineBottle"}>Wine bottle</option>
<option value={"Keg"}>Keg</option>
</Form.Select>
</Form.Group>
+2 -2
View File
@@ -1,8 +1,8 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, NodeOnDiskFile, json, redirect, unstable_composeUploadHandlers, unstable_createFileUploadHandler, unstable_createMemoryUploadHandler, unstable_parseMultipartFormData } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { renameSync, rmSync } from "node:fs";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Container, Row, Button, Form, Col, ListGroup, InputGroup } from "react-bootstrap";
import { Button, Container, Form, InputGroup, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
+2 -2
View File
@@ -1,8 +1,8 @@
import type { ActionFunctionArgs } from "@remix-run/node";
import { LoaderFunctionArgs, NodeOnDiskFile, json, redirect, unstable_composeUploadHandlers, unstable_createFileUploadHandler, unstable_createMemoryUploadHandler, unstable_parseMultipartFormData } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { renameSync, rmSync } from "node:fs";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Container, Row, Button, Form, Col, ListGroup, InputGroup } from "react-bootstrap";
import { Button, Container, Form, InputGroup, Row } from "react-bootstrap";
import { enhance } from "~/utils/db.server";
+5 -3
View File
@@ -11,7 +11,7 @@ import {
import DrinkPage from "~/components/cards/drink.page";
import { findIdFromSlug } from "~/models/drinks.server";
import { findIdFromSlug, findRecommendations, getMostCommonSection } from "~/models/drinks.server";
import { enhance } from "~/utils/db.server";
export const loader = async ({
@@ -32,17 +32,19 @@ export const loader = async ({
});
}
const recommendations = await findRecommendations(await getMostCommonSection(beer.containers), 2, beer.id);
let user = session.get("user");
let isAdmin = user?.type == "Admin";
return json({ beer , isAdmin: isAdmin});
return json({ beer , recommendations, isAdmin: isAdmin});
};
export default function BeerRoute() {
const data = useLoaderData<typeof loader>();
return (
<DrinkPage drink={data.beer} isAdmin={data.isAdmin}></DrinkPage>
<DrinkPage drink={data.beer} recommendations={data.recommendations} isAdmin={data.isAdmin}></DrinkPage>
);
}
@@ -10,7 +10,7 @@ import {
import DrinkPage from "~/components/cards/drink.page";
import { findIdFromSlug } from "~/models/drinks.server";
import { findIdFromSlug, findRecommendations, getMostCommonSection } from "~/models/drinks.server";
import { enhance } from "~/utils/db.server";
export const loader = async ({
@@ -31,17 +31,19 @@ params,
});
}
const recommendations = await findRecommendations(await getMostCommonSection(cocktail.containers), 2, cocktail.id);
let user = session.get("user");
let isAdmin = user?.type == "Admin";
return json({ cocktail , isAdmin: isAdmin});
return json({ cocktail, recommendations, isAdmin: isAdmin});
};
export default function CocktailRoute() {
const data = useLoaderData<typeof loader>();
return (
<DrinkPage drink={data.cocktail} isAdmin={data.isAdmin}></DrinkPage>
<DrinkPage drink={data.cocktail} recommendations={data.recommendations} isAdmin={data.isAdmin}></DrinkPage>
);
}
+7 -3
View File
@@ -3,6 +3,7 @@ import type {
LoaderFunctionArgs
} from "@remix-run/node";
import { redirect } from "@remix-run/node";
import { findIdFromSlug } from "~/models/drinks.server";
@@ -14,8 +15,10 @@ export const loader = async ({
}: LoaderFunctionArgs) => {
const {dbe, session} = await enhance(request);
var id = Number(params.id);
var id = await findIdFromSlug(params.id) || 0;
var type : DrinkType = "Beer";
var slug : string = params.id || "";
var drink;
@@ -31,11 +34,12 @@ export const loader = async ({
drink = await dbe.drink.findUnique({
where: { id: id },
select: {id: true, type: true}
select: {id: true, slug: true, type: true}
});
if(drink){
type = drink.type;
slug = drink.slug;
break;
}
@@ -52,5 +56,5 @@ export const loader = async ({
}
}
return redirect("/inventory/" + type.toLowerCase() + "/" + id);
return redirect("/inventory/" + type.toLowerCase() + "/" + slug);
};
+5 -9
View File
@@ -1,19 +1,15 @@
import type {
import type {
LoaderFunctionArgs
} from "@remix-run/node";
import { json } from "@remix-run/node";
import {
useLoaderData,
useParams,
isRouteErrorResponse,
useRouteError } from "@remix-run/react";
import {
useLoaderData
} from "@remix-run/react";
import DrinkPage from "~/components/cards/drink.page";
import { db } from "~/utils/db.server";
import { enhance } from "@zenstackhq/runtime";
import { findIdFromSlug } from "~/models/drinks.server";
import { Col, Container, Image, Row } from "react-bootstrap";
import { db } from "~/utils/db.server";
export const loader = async ({
params,
+5 -3
View File
@@ -10,7 +10,7 @@ import {
import DrinkPage from "~/components/cards/drink.page";
import { findIdFromSlug } from "~/models/drinks.server";
import { findIdFromSlug, findRecommendations, getMostCommonSection } from "~/models/drinks.server";
import { enhance } from "~/utils/db.server";
export const loader = async ({
@@ -31,17 +31,19 @@ params,
});
}
const recommendations = await findRecommendations(await getMostCommonSection(soda.containers), 2, soda.id);
let user = session.get("user");
let isAdmin = user?.type == "Admin";
return json({ soda , isAdmin: isAdmin});
return json({ soda , recommendations, isAdmin: isAdmin});
};
export default function SodaRoute() {
const data = useLoaderData<typeof loader>();
return (
<DrinkPage drink={data.soda} isAdmin={data.isAdmin}></DrinkPage>
<DrinkPage drink={data.soda} recommendations={data.recommendations} isAdmin={data.isAdmin}></DrinkPage>
);
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { LoaderFunctionArgs, json } from "@remix-run/node";
import { Link, useLoaderData } from "@remix-run/react";
import { useLoaderData } from "@remix-run/react";
import { enhance } from "@zenstackhq/runtime";
import { Button, Col, Container, Row, Table } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
+116
View File
@@ -0,0 +1,116 @@
import { ActionFunctionArgs, LoaderFunctionArgs, json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { Button, Col, Container, Form, Row, Table } from "react-bootstrap";
import timeAgo from "~/utils/datetime";
import { enhance } from "~/utils/db.server";
export const action = async ({
request
}: ActionFunctionArgs) => {
const { dbe } = await enhance(request);
const form = await request.formData();
const content = String(form.get("content"));
var name : string | null = String(form.get("name")) || null;
if(name == "") name = null;
if(content == "") return null;
try{
await dbe.suggestion.create({ data: {
name: name,
content: content
}
});
}
catch(e){
console.log(e);
}
return null;
};
export const loader = async ({request} : LoaderFunctionArgs) => {
const { dbe } = await enhance(request);
const suggestions = await dbe.suggestion.findMany({take: 15, orderBy: {createdAt: "desc"}});
return json({suggestions});
};
export default function SuggestionsRoute() {
const loadData = useLoaderData<typeof loader>();
return (
<Container>
<Row className="mt-3">
<Col key="stats-total" className="mb-3">
<h3>Make a suggestion</h3>
<p> Leave a suggestion about a drink, the website or anything really.</p>
<Form method="post" noValidate>
<Form.Group>
<Form.Label>
Your name:
</Form.Label>
<Form.Control
type="text"
name="name"
/>
</Form.Group>
<Form.Group>
<Form.Label>
Suggestion*:
</Form.Label>
<Form.Control
as="textarea"
type="text"
name="content"
required
/>
</Form.Group>
<Button variant="primary" className="mt-1" type="submit">
Submit
</Button>
</Form>
</Col>
</Row>
<Row className="mt-3">
{loadData.suggestions.length > 0 ? (
<Col xs={12}>
<h3>Suggestions</h3>
<Table striped>
<thead>
<tr>
<th>Name</th>
<th>Date</th>
<th>Suggestions</th>
</tr>
</thead>
<tbody>
{loadData.suggestions.map((entry) => (
<tr key={entry.id}>
<td>{entry.name ? (<>{entry.name}</>) : ( <><i>No name</i></> ) }</td>
<td>{timeAgo(new Date(entry.createdAt))}</td>
<td>{entry.content}</td>
</tr>
))}
</tbody>
</Table>
</Col>
) : (
<Col xs={12}>
<h3>Suggestions</h3>
No suggestions yet...
</Col>
)}
</Row>
</Container>
);
}
+6 -3
View File
@@ -10,7 +10,7 @@ import {
import DrinkPage from "~/components/cards/drink.page";
import { findIdFromSlug } from "~/models/drinks.server";
import { findIdFromSlug, findRecommendations, getMostCommonSection } from "~/models/drinks.server";
import { enhance } from "~/utils/db.server";
export const loader = async ({
@@ -30,17 +30,20 @@ params,
status: 404,
});
}
const recommendations = await findRecommendations(await getMostCommonSection(wine.containers), 2, wine.id);
let user = session.get("user");
let isAdmin = user?.type == "Admin";
return json({ wine , isAdmin: isAdmin});
return json({ wine , recommendations, isAdmin: isAdmin});
};
export default function WineRoute() {
const data = useLoaderData<typeof loader>();
return (
<DrinkPage drink={data.wine} isAdmin={data.isAdmin}></DrinkPage>
<DrinkPage drink={data.wine} recommendations={data.recommendations} isAdmin={data.isAdmin}></DrinkPage>
);
}
+7 -7
View File
@@ -1,12 +1,12 @@
import type {
ActionFunctionArgs,
LoaderFunctionArgs,
} from "@remix-run/node"; // or cloudflare/deno
import { json, redirect } from "@remix-run/node"; // or cloudflare/deno
import { useActionData, useLoaderData } from "@remix-run/react";
import { Button, Col, Container, Form, InputGroup, Row } from "react-bootstrap";
ActionFunctionArgs,
LoaderFunctionArgs,
} from "@remix-run/node"; // or cloudflare/deno
import { json, redirect } from "@remix-run/node"; // or cloudflare/deno
import { useActionData } from "@remix-run/react";
import { Button, Col, Container, Form, Row } from "react-bootstrap";
import { getSession, commitSession } from "~/auth/session";
import { commitSession, getSession } from "~/auth/session";
import { validateCredentials } from "~/auth/validate";
export async function loader({
+1 -1
View File
@@ -1,4 +1,4 @@
import { LoaderFunctionArgs, redirect, json } from "@remix-run/node";
import { LoaderFunctionArgs, json } from "@remix-run/node";
import { enhance } from "~/utils/db.server";
export async function loader({
+3 -5
View File
@@ -1,12 +1,10 @@
import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Button, Col, Container, Form, Row, Table } from "react-bootstrap";
import { useLoaderData } from "@remix-run/react";
import { Button, Container, Form, Row } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { getSession } from "~/auth/session";
import timeAgo from "~/utils/datetime";
import { db, enhance } from "~/utils/db.server";
import { enhance } from "~/utils/db.server";
export async function loader({
request,
+3 -4
View File
@@ -2,10 +2,9 @@ import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { useActionData, useLoaderData } from "@remix-run/react";
import { Col, Container, Form, Row, Table } from "react-bootstrap";
import { getSession } from "~/auth/session";
import timeAgo from "~/utils/datetime";
import { db, enhance } from "~/utils/db.server";
import { enhance } from "~/utils/db.server";
export async function loader({
request,
@@ -16,7 +15,7 @@ export async function loader({
return redirect("/");
}
const history = await dbe.history.findMany({select: {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: 10, orderBy: {checkoutAt: "desc"}});
return json({history});
}
@@ -93,7 +92,7 @@ export default function ScanRoute() {
</thead>
<tbody>
{lData.history.map((entry) => (
<tr key={entry.container.drink.slug}>
<tr key={entry.id}>
<td>{entry.container.drink.name}</td>
<td>{timeAgo(new Date(entry.checkoutAt))}</td>
<td>{entry.inventoryAfter}</td>
+8
View File
@@ -0,0 +1,8 @@
export function shuffleArray(array : any[]) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
+9
View File
@@ -32,6 +32,7 @@ enum ContainerType {
PlasticBottle
Can
Carton
Keg
}
/// @@delegate(type)
@@ -204,3 +205,11 @@ model Session {
user User? @relation(fields: [user_id], references: [id])
data String
}
/// @@allow('all', true)
model Suggestion {
id Int @id() @default(autoincrement())
createdAt DateTime @default(now())
name String?
content String
}
+10
View File
@@ -30,6 +30,7 @@ enum ContainerType {
PlasticBottle
Can
Carton
Keg
}
model Drink {
@@ -220,4 +221,13 @@ model Session {
@@allow('all', auth().id == user.id)
@@allow('all', auth().type == Admin)
}
model Suggestion {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
name String?
content String
@@allow('all', true)
}
+2 -1
View File
@@ -28,7 +28,8 @@ export default defineConfig({
route("cocktail/:cocktailslug", "routes/inventory/cocktail.$cocktailslug.tsx");
route("manufacturer/:id", "routes/inventory/manufacturer.$id.tsx");
route("stats", "routes/inventory/stats/route.tsx");
route("stats", "routes/inventory/stats/route.tsx");
route("suggestions", "routes/inventory/suggestions/route.tsx");
});