Clean imports, add suggestions and recommendations
This commit is contained in:
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
) : ""}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -60,5 +60,7 @@ export function containerTypeToString(type: ContainerType){
|
||||
return "PET";
|
||||
case "WineBottle":
|
||||
return "Wine bottle";
|
||||
case "Keg":
|
||||
return "Keg";
|
||||
}
|
||||
}
|
||||
+4
-8
@@ -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,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { UserType } from "@prisma/client";
|
||||
import type { LoaderFunctionArgs } from "@remix-run/node";
|
||||
import {
|
||||
json,
|
||||
redirect,
|
||||
useLoaderData
|
||||
} from "@remix-run/react";
|
||||
|
||||
@@ -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,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";
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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,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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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,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";
|
||||
|
||||
@@ -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,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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
@@ -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,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";
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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({
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user