Add easy admin buttons and fix enum usage
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
|
||||
import { Manufacturer } from '@zenstackhq/runtime/models';
|
||||
import { Alert, Badge, Col, Container, Image, Row, Table } from 'react-bootstrap';
|
||||
import { Alert, Badge, Button, Col, Container, Image, Row, Table } from 'react-bootstrap';
|
||||
import { LinkContainer } from 'react-router-bootstrap';
|
||||
import { ContainerWithSection, DrinkComposite, containerTypeToString, isBeer, isDrinkWithContainersAndSection, isDrinkWithManufacturer, isDrinkWithStyle } from '~/models/types';
|
||||
import { volume } from '~/utils/conversions';
|
||||
|
||||
interface Arguments {
|
||||
drink: DrinkComposite
|
||||
isAdmin: boolean
|
||||
}
|
||||
|
||||
function DrinkPage(arg:Arguments) {
|
||||
@@ -44,6 +46,28 @@ function DrinkPage(arg:Arguments) {
|
||||
})
|
||||
}
|
||||
|
||||
var link = (<></>);
|
||||
if(arg.drink.link){
|
||||
var href = arg.drink.link;
|
||||
|
||||
var linktitle = "Open link";
|
||||
var linkcolor = "#6c757d";
|
||||
|
||||
if(href.includes("untappd")){
|
||||
linkcolor = "#ffc20b";
|
||||
linktitle = "Untappd";
|
||||
}
|
||||
if(href.includes("vivino")) {
|
||||
linkcolor = "#ba1628";
|
||||
linktitle = "Vivino";
|
||||
}
|
||||
|
||||
link = (
|
||||
<Button variant='dark' href={href} style={{backgroundColor: linkcolor}}>{linktitle}</Button>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{glass ? (
|
||||
@@ -52,17 +76,29 @@ function DrinkPage(arg:Arguments) {
|
||||
</Alert>
|
||||
): ""}
|
||||
|
||||
{arg.isAdmin ? (
|
||||
<Row className='my-3'>
|
||||
<Col>
|
||||
<LinkContainer to={"/admin/edit/" + arg.drink.type.toLowerCase() + "/" + arg.drink.id}><Button variant='primary'>Edit</Button></LinkContainer>
|
||||
<LinkContainer to={"/admin/edit/image/" + arg.drink.type.toLowerCase() + "/" + arg.drink.id}><Button variant='secondary'>Image</Button></LinkContainer>
|
||||
</Col>
|
||||
</Row>
|
||||
) : ""}
|
||||
|
||||
<div className="p-5 mb-4 bg-body-tertiary rounded-3 border" style={{ borderColor: `${borderColor}`, borderWidth: '2px' }} >
|
||||
<Container fluid>
|
||||
<Row>
|
||||
<Col md={11}>
|
||||
<Col md={10}>
|
||||
<h1 className="display-5 fw-bold">{arg.drink.name}</h1>
|
||||
<Badge bg={arg.drink.abv > 0 ? "warning" : "secondary"}>ABV: {arg.drink.abv}%</Badge> {style} {ibu} {arg.drink.sugar ? "" : <Badge bg="success">Sugar-free</Badge>} {arg.drink.gluten ? "" : <Badge bg="success">Gluten-free</Badge>} {arg.drink.organic ? <Badge bg="success">Organic</Badge> : ""}
|
||||
<p className="col-md-8 fs-4">{arg.drink.description}</p>
|
||||
<p className="fs-4">{arg.drink.description}</p>
|
||||
{link}
|
||||
</Col>
|
||||
<Col md={1}>
|
||||
<Image src={arg.drink.image ?? undefined} fluid rounded/>
|
||||
{arg.drink.image ? (
|
||||
<Col md={2}>
|
||||
<Image src={arg.drink.image} fluid rounded/>
|
||||
</Col>
|
||||
) : ""}
|
||||
</Row>
|
||||
|
||||
</Container>
|
||||
@@ -82,6 +118,9 @@ function DrinkPage(arg:Arguments) {
|
||||
<th>Container</th>
|
||||
<th>Volume</th>
|
||||
<th>Amount</th>
|
||||
{arg.isAdmin ? (
|
||||
<th>Edit</th>
|
||||
) : ""}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -91,6 +130,9 @@ function DrinkPage(arg:Arguments) {
|
||||
<td>{containerTypeToString(container.type)}</td>
|
||||
<td>{volume(container.volume)}</td>
|
||||
<td>{container.inventory}</td>
|
||||
{arg.isAdmin ? (
|
||||
<td><LinkContainer to={"/admin/edit/container/" + container.id}><Button variant='primary'>Edit</Button></LinkContainer></td>
|
||||
) : ""}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -106,14 +148,24 @@ function DrinkPage(arg:Arguments) {
|
||||
{ manufacturer ? (
|
||||
<Col md={6} className='mb-4'>
|
||||
<Container>
|
||||
{arg.isAdmin ? (
|
||||
<Row className='my-3'>
|
||||
<Col>
|
||||
<LinkContainer to={"/admin/edit/manufacturer/" + manufacturer.id}><Button variant='primary'>Edit</Button></LinkContainer>
|
||||
<LinkContainer to={"/admin/edit/image/manufacturer/" + manufacturer.id}><Button variant='secondary'>Image</Button></LinkContainer>
|
||||
</Col>
|
||||
</Row>
|
||||
) : ""}
|
||||
<Row className="p-5 bg-body-tertiary border rounded-3">
|
||||
<Col md={10}>
|
||||
<h2>{manufacturer.name} ({manufacturer.country_id})</h2>
|
||||
<p>{manufacturer.description}</p>
|
||||
</Col>
|
||||
{manufacturer.image ? (
|
||||
<Col md={2}>
|
||||
<Image src={manufacturer.image ?? undefined} fluid rounded/>
|
||||
<Image src={manufacturer.image} fluid rounded/>
|
||||
</Col>
|
||||
) : ""}
|
||||
</Row>
|
||||
</Container>
|
||||
</Col>
|
||||
|
||||
@@ -80,7 +80,7 @@ export default function EditCocktailRoute() {
|
||||
<Container>
|
||||
<Row>
|
||||
<h1>Edit cocktail ({loaderData.cocktail.id})</h1>
|
||||
<Form method="POST" encType="multipart/form-data">
|
||||
<Form method="POST">
|
||||
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>ID</Form.Label>
|
||||
|
||||
@@ -75,7 +75,7 @@ export default function EditContainerRoute() {
|
||||
<Container>
|
||||
<Row>
|
||||
<h1>Edit Container ({loaderData.container.id})</h1>
|
||||
<Form method="POST" encType="multipart/form-data">
|
||||
<Form method="POST">
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>ID</Form.Label>
|
||||
<Form.Control type="text" disabled value={loaderData.container.id}/>
|
||||
@@ -111,11 +111,11 @@ export default function EditContainerRoute() {
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>Container type</Form.Label>
|
||||
<Form.Select name="type" required>
|
||||
<option value={ContainerType.BeerBottle} selected={loaderData.container.type == ContainerType.BeerBottle}>Beer bottle</option>
|
||||
<option value={ContainerType.Can} selected={loaderData.container.type == ContainerType.Can}>Can</option>
|
||||
<option value={ContainerType.Carton} selected={loaderData.container.type == ContainerType.Carton}>Carton</option>
|
||||
<option value={ContainerType.PlasticBottle} selected={loaderData.container.type == ContainerType.PlasticBottle}>Plastic Bottle</option>
|
||||
<option value={ContainerType.WineBottle} selected={loaderData.container.type == ContainerType.WineBottle}>Wine bottle</option>
|
||||
<option value={"BeerBottle"} selected={loaderData.container.type == "BeerBottle"}>Beer bottle</option>
|
||||
<option value={"Can"} selected={loaderData.container.type == "Can"}>Can</option>
|
||||
<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>
|
||||
</Form.Select>
|
||||
</Form.Group>
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ export default function EditSodaRoute() {
|
||||
<Container>
|
||||
<Row>
|
||||
<h1>Edit soda ({loaderData.soda.id})</h1>
|
||||
<Form method="POST" encType="multipart/form-data">
|
||||
<Form method="POST">
|
||||
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>ID</Form.Label>
|
||||
|
||||
@@ -98,7 +98,7 @@ export default function EditWineRoute() {
|
||||
<Container>
|
||||
<Row>
|
||||
<h1>Edit wine ({loaderData.wine.id})</h1>
|
||||
<Form method="POST" encType="multipart/form-data">
|
||||
<Form method="POST">
|
||||
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>ID</Form.Label>
|
||||
|
||||
@@ -17,7 +17,7 @@ export async function loader({
|
||||
}
|
||||
|
||||
let user = session.get("user");
|
||||
if(user.type != UserType.Admin){
|
||||
if(user.type != "Admin"){
|
||||
return redirect("/");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ActionFunctionArgs } from "@remix-run/node";
|
||||
import { LoaderFunctionArgs, json, redirect } from "@remix-run/node";
|
||||
import { useLoaderData } from "@remix-run/react";
|
||||
import { isRouteErrorResponse, useLoaderData, useRouteError } from "@remix-run/react";
|
||||
import { Container, Row, Button, Form, Col, ListGroup, InputGroup } from "react-bootstrap";
|
||||
|
||||
import { enhance } from "~/utils/db.server";
|
||||
@@ -58,7 +58,7 @@ export default function NewContainerRoute() {
|
||||
<Container>
|
||||
<Row>
|
||||
<h1>Add Container</h1>
|
||||
<Form method="POST" encType="multipart/form-data">
|
||||
<Form method="POST">
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>Drink</Form.Label>
|
||||
<Form.Select name="drink" required>
|
||||
@@ -84,11 +84,11 @@ export default function NewContainerRoute() {
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>Container type</Form.Label>
|
||||
<Form.Select name="type" required>
|
||||
<option value={ContainerType.BeerBottle}>Beer bottle</option>
|
||||
<option value={ContainerType.Can}>Can</option>
|
||||
<option value={ContainerType.Carton}>Carton</option>
|
||||
<option value={ContainerType.PlasticBottle}>Plastic Bottle</option>
|
||||
<option value={ContainerType.WineBottle}>Wine bottle</option>
|
||||
<option value={"BeerBottle"}>Beer bottle</option>
|
||||
<option value={"Can"}>Can</option>
|
||||
<option value={"Carton"}>Carton</option>
|
||||
<option value={"PlasticBottle"}>Plastic Bottle</option>
|
||||
<option value={"WineBottle"}>Wine bottle</option>
|
||||
</Form.Select>
|
||||
</Form.Group>
|
||||
|
||||
|
||||
@@ -10,14 +10,15 @@ import {
|
||||
|
||||
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 { enhance } from "~/utils/db.server";
|
||||
|
||||
export const loader = async ({
|
||||
request,
|
||||
params,
|
||||
}: LoaderFunctionArgs) => {
|
||||
const dbe = enhance(db);
|
||||
const {dbe, session} = await enhance(request);
|
||||
|
||||
const beerid = await findIdFromSlug(params.beerslug);
|
||||
|
||||
@@ -30,14 +31,18 @@ export const loader = async ({
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
return json({ beer });
|
||||
|
||||
let user = session.get("user");
|
||||
let isAdmin = user?.type == "Admin";
|
||||
|
||||
return json({ beer , isAdmin: isAdmin});
|
||||
};
|
||||
|
||||
export default function BeerRoute() {
|
||||
const data = useLoaderData<typeof loader>();
|
||||
|
||||
return (
|
||||
<DrinkPage drink={data.beer}></DrinkPage>
|
||||
<DrinkPage drink={data.beer} isAdmin={data.isAdmin}></DrinkPage>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,34 +10,38 @@ import {
|
||||
|
||||
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 { enhance } from "~/utils/db.server";
|
||||
|
||||
export const loader = async ({
|
||||
request,
|
||||
params,
|
||||
}: LoaderFunctionArgs) => {
|
||||
const dbe = enhance(db);
|
||||
const {dbe, session} = await enhance(request);
|
||||
|
||||
const cocktailid = await findIdFromSlug(params.cocktailslug);
|
||||
const cocktailid = await findIdFromSlug(params.cocktailslug);
|
||||
|
||||
const cocktail = await dbe.cocktail.findUnique({
|
||||
where: { id: cocktailid },
|
||||
include: { manufacturer: true, containers: { include: { section: true}}}
|
||||
});
|
||||
if (!cocktail) {
|
||||
throw new Response("Cocktail not found.", {
|
||||
status: 404,
|
||||
const cocktail = await dbe.cocktail.findUnique({
|
||||
where: { id: cocktailid },
|
||||
include: { manufacturer: true, containers: { include: { section: true}}}
|
||||
});
|
||||
}
|
||||
return json({ cocktail });
|
||||
if (!cocktail) {
|
||||
throw new Response("Cocktail not found.", {
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
let user = session.get("user");
|
||||
let isAdmin = user?.type == "Admin";
|
||||
|
||||
return json({ cocktail , isAdmin: isAdmin});
|
||||
};
|
||||
|
||||
export default function CocktailRoute() {
|
||||
const data = useLoaderData<typeof loader>();
|
||||
|
||||
return (
|
||||
<DrinkPage drink={data.cocktail}></DrinkPage>
|
||||
<DrinkPage drink={data.cocktail} isAdmin={data.isAdmin}></DrinkPage>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ 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 { Image } from "react-bootstrap";
|
||||
import { Col, Container, Image, Row } from "react-bootstrap";
|
||||
|
||||
export const loader = async ({
|
||||
params,
|
||||
@@ -37,12 +37,16 @@ export default function ManufacturerRoute() {
|
||||
const data = useLoaderData<typeof loader>();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{data.man.name} ({data.man.country_id})</h1>
|
||||
<p>{data.man.description}</p>
|
||||
{data.man.image ? (
|
||||
<Image src={data.man.image}></Image>
|
||||
) : <></>}
|
||||
</div>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<h1>{data.man.name} ({data.man.country_id})</h1>
|
||||
<p>{data.man.description}</p>
|
||||
{data.man.image ? (
|
||||
<Image src={data.man.image}></Image>
|
||||
) : <></>}
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
@@ -10,35 +10,39 @@ import {
|
||||
|
||||
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 { enhance } from "~/utils/db.server";
|
||||
|
||||
export const loader = async ({
|
||||
request,
|
||||
params,
|
||||
}: LoaderFunctionArgs) => {
|
||||
const dbe = enhance(db);
|
||||
const {dbe, session} = await enhance(request);
|
||||
|
||||
const sodaid = await findIdFromSlug(params.sodaslug);
|
||||
const sodaid = await findIdFromSlug(params.sodaslug);
|
||||
|
||||
const soda = await dbe.soda.findUnique({
|
||||
where: { id: sodaid },
|
||||
include: { manufacturer: true, containers: { include: { section: true}}}
|
||||
});
|
||||
if (!soda) {
|
||||
throw new Response("Soda not found.", {
|
||||
status: 404,
|
||||
const soda = await dbe.soda.findUnique({
|
||||
where: { id: sodaid },
|
||||
include: { manufacturer: true, containers: { include: { section: true}}}
|
||||
});
|
||||
}
|
||||
return json({ soda });
|
||||
if (!soda) {
|
||||
throw new Response("Soda not found.", {
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
|
||||
let user = session.get("user");
|
||||
let isAdmin = user?.type == "Admin";
|
||||
|
||||
return json({ soda , isAdmin: isAdmin});
|
||||
};
|
||||
|
||||
export default function SodaRoute() {
|
||||
const data = useLoaderData<typeof loader>();
|
||||
const data = useLoaderData<typeof loader>();
|
||||
|
||||
return (
|
||||
<DrinkPage drink={data.soda}></DrinkPage>
|
||||
);
|
||||
return (
|
||||
<DrinkPage drink={data.soda} isAdmin={data.isAdmin}></DrinkPage>
|
||||
);
|
||||
}
|
||||
|
||||
export function ErrorBoundary() {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { LoaderFunctionArgs, json } from "@remix-run/node";
|
||||
import { useLoaderData } from "@remix-run/react";
|
||||
import { Link, useLoaderData } from "@remix-run/react";
|
||||
import { enhance } from "@zenstackhq/runtime";
|
||||
import { Col, Container, Row, Table } from "react-bootstrap";
|
||||
import { Button, Col, Container, Row, Table } from "react-bootstrap";
|
||||
import { LinkContainer } from "react-router-bootstrap";
|
||||
import { ContainerWithDrink } from "~/models/types";
|
||||
import timeAgo from "~/utils/datetime";
|
||||
|
||||
@@ -115,6 +116,7 @@ export default function StatsRoute() {
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Drink</th>
|
||||
<th>View</th>
|
||||
<th>When</th>
|
||||
<th>Amount left</th>
|
||||
</tr>
|
||||
@@ -123,6 +125,7 @@ export default function StatsRoute() {
|
||||
{loadData.history.map((entry) => (
|
||||
<tr key={entry.container.drink.slug}>
|
||||
<td>{entry.container.drink.name}</td>
|
||||
<td><LinkContainer to={"/inventory/" + entry.container.drink.type.toLowerCase() + "/" + entry.container.drink.slug}><Button variant="primary">View</Button></LinkContainer></td>
|
||||
<td>{timeAgo(new Date(entry.checkoutAt))}</td>
|
||||
<td>{entry.inventoryAfter}</td>
|
||||
</tr>
|
||||
|
||||
@@ -10,35 +10,38 @@ import {
|
||||
|
||||
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 { enhance } from "~/utils/db.server";
|
||||
|
||||
export const loader = async ({
|
||||
request,
|
||||
params,
|
||||
}: LoaderFunctionArgs) => {
|
||||
const dbe = enhance(db);
|
||||
const {dbe, session} = await enhance(request);
|
||||
|
||||
const wineid = await findIdFromSlug(params.wineslug);
|
||||
const wineid = await findIdFromSlug(params.wineslug);
|
||||
|
||||
const wine = await dbe.wine.findUnique({
|
||||
where: { id: wineid },
|
||||
include: { style: true, manufacturer: true, containers: { include: { section: true}}}
|
||||
});
|
||||
if (!wine) {
|
||||
throw new Response("Wine not found.", {
|
||||
status: 404,
|
||||
const wine = await dbe.wine.findUnique({
|
||||
where: { id: wineid },
|
||||
include: { style: true, manufacturer: true, containers: { include: { section: true}}}
|
||||
});
|
||||
}
|
||||
return json({ wine });
|
||||
if (!wine) {
|
||||
throw new Response("Wine not found.", {
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
let user = session.get("user");
|
||||
let isAdmin = user?.type == "Admin";
|
||||
|
||||
return json({ wine , isAdmin: isAdmin});
|
||||
};
|
||||
|
||||
export default function WineRoute() {
|
||||
const data = useLoaderData<typeof loader>();
|
||||
const data = useLoaderData<typeof loader>();
|
||||
|
||||
return (
|
||||
<DrinkPage drink={data.wine}></DrinkPage>
|
||||
);
|
||||
return (
|
||||
<DrinkPage drink={data.wine} isAdmin={data.isAdmin}></DrinkPage>
|
||||
);
|
||||
}
|
||||
|
||||
export function ErrorBoundary() {
|
||||
|
||||
Reference in New Issue
Block a user