diff --git a/app/components/cards/drink.page.tsx b/app/components/cards/drink.page.tsx index 3d25f03..f609b2c 100644 --- a/app/components/cards/drink.page.tsx +++ b/app/components/cards/drink.page.tsx @@ -1,7 +1,8 @@ import { Manufacturer } from '@zenstackhq/runtime/models'; -import { Col, Container, Image, Row, Table } from 'react-bootstrap'; -import { ContainerWithSection, DrinkComposite, isDrinkWithContainersAndSection, isDrinkWithManufacturer, isDrinkWithStyle } from '~/models/types'; +import { Alert, Badge, Col, Container, Image, Row, Table } from 'react-bootstrap'; +import { ContainerWithSection, DrinkComposite, containerTypeToString, isBeer, isDrinkWithContainersAndSection, isDrinkWithManufacturer, isDrinkWithStyle } from '~/models/types'; +import { volume } from '~/utils/conversions'; interface Arguments { drink: DrinkComposite @@ -10,8 +11,10 @@ interface Arguments { function DrinkPage(arg:Arguments) { var borderColor = "#bbb"; + var style = (<>); if(isDrinkWithStyle(arg.drink)){ borderColor = "#" + arg.drink.style.color; + style = ({arg.drink.style.name}); } var manufacturer: Manufacturer | undefined = undefined; @@ -19,40 +22,48 @@ function DrinkPage(arg:Arguments) { manufacturer = arg.drink.manufacturer; } + var glass = false; + var ibu = (<>); + if(isBeer(arg.drink)){ + glass = arg.drink.glass; + if(arg.drink.ibu) + ibu = ( 45 ? "warning" : "secondary"}>IBU: {arg.drink.ibu}); + } + var containers : ContainerWithSection[] = []; var totalinventory = 0; + var containerWithMultiplePortions = false; if(isDrinkWithContainersAndSection(arg.drink)){ containers = arg.drink.containers; containers.map((container) => { totalinventory += container.inventory; + + if((container.portions || 0) > 1){ + containerWithMultiplePortions = true; + } }) } return ( + {glass ? ( + + There is a glass available for this beer! + + ): ""} +

{arg.drink.name}

- ABV: {arg.drink.abv}% {arg.drink.gluten ? "" : " | Gluten-free"} {arg.drink.organic ? " | Organic" : ""} + 0 ? "warning" : "secondary"}>ABV: {arg.drink.abv}% {style} {ibu} {arg.drink.sugar ? "" : Sugar-free} {arg.drink.gluten ? "" : Gluten-free} {arg.drink.organic ? Organic : ""}

{arg.drink.description}

- - - - - - - - - - -
@@ -69,6 +80,7 @@ function DrinkPage(arg:Arguments) { Section Container + Volume Amount @@ -76,13 +88,19 @@ function DrinkPage(arg:Arguments) { {containers.map((container) => ( {container.section.name} - {container.type} + {containerTypeToString(container.type)} + {volume(container.volume)} {container.inventory} ))} )} + {containerWithMultiplePortions ? ( + + This drink contains multiple portions! These should be scanned only when the container is empty! + + ) : ""} { manufacturer ? ( diff --git a/app/components/filters/drink.filter.tsx b/app/components/filters/drink.filter.tsx index ae9e68e..f5cce6b 100644 --- a/app/components/filters/drink.filter.tsx +++ b/app/components/filters/drink.filter.tsx @@ -90,7 +90,7 @@ function DrinkFilter(arg : Arguments) { Drink - { ["Gluten-free", "Organic"].map(key => ( + { ["Sugar-free", "Gluten-free", "Organic"].map(key => ( []}}; + if(searchParams.has("sugar-free")){ + whereBase.delegate_aux_drink.AND.push({NOT: {sugar: true}}); + } if(searchParams.has("gluten-free")){ whereBase.delegate_aux_drink.AND.push({NOT: {gluten: true}}); } diff --git a/app/models/drinks.server.ts b/app/models/drinks.server.ts index aeb82c3..182aa95 100644 --- a/app/models/drinks.server.ts +++ b/app/models/drinks.server.ts @@ -5,6 +5,9 @@ import { DrinkType, Manufacturer } from "@prisma/client"; export async function findIdFromSlug(slug:string | undefined) : Promise { if(slug){ + const id = Number(slug); + if(id) return id; + const drink = await db.drink.findUnique({where: {slug: slug}, select: {id: true}}); return drink?.id; } diff --git a/app/models/types.tsx b/app/models/types.tsx index b13e1f5..154d72d 100644 --- a/app/models/types.tsx +++ b/app/models/types.tsx @@ -14,7 +14,7 @@ export type DrinkWithManufacturer = Drink & { manufacturer: Manufacturer} export type BeerWithStyle = Beer & { style : BeerStyle } export type WineWithStyle = Wine & { style : WineStyle } -export type DrinkComposite = Drink | BeerWithStyle | WineWithStyle | Soda | Cocktail | DrinkWithManufacturer | DrinkWithContainers +export type DrinkComposite = Drink | Beer | Wine | BeerWithStyle | WineWithStyle | Soda | Cocktail | DrinkWithManufacturer | DrinkWithContainers export function isDrinkWithContainers(drink:DrinkComposite) : drink is DrinkWithContainers{ return ((drink as { containers: Container[]}).containers != undefined) || ((drink as { containers: ContainerWithSection[]}).containers != undefined); @@ -43,10 +43,15 @@ export function isDrinkWithStyle(drink:DrinkComposite) : drink is WineWithStyle return beerstyle || winestyle; } +export function isBeer(drink:DrinkComposite) : drink is Beer { + const beer = (drink as Beer).ibu != undefined; + return beer; +} + export function containerTypeToString(type: ContainerType){ switch(type){ case "BeerBottle": - return "Beer"; + return "Beer bottle"; case "Can": return "Can"; case "Carton": @@ -54,6 +59,6 @@ export function containerTypeToString(type: ContainerType){ case "PlasticBottle": return "PET"; case "WineBottle": - return "Wine"; + return "Wine bottle"; } } \ No newline at end of file diff --git a/app/routes/admin/edit/beer.$id.tsx b/app/routes/admin/edit/beer.$id.tsx new file mode 100644 index 0000000..562df32 --- /dev/null +++ b/app/routes/admin/edit/beer.$id.tsx @@ -0,0 +1,201 @@ +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, InputGroup } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const form = await request.formData(); + + const slug = String(form.get("slug")); + const manufacturer = Number(form.get("manufacturer")); + const style = Number(form.get("style")); + + const name = String(form.get("name")); + const description = String(form.get("description")); + var link : string | null = String(form.get("link")) || null; + if(link == "") link = null; + + const abv = Number(form.get("abv")); + const ibu = Number(form.get("ibu")); + + const glass = form.has("glass") ? true : false; + + const sugar = form.has("sugar") ? true : false; + const gluten = form.has("gluten") ? true : false; + const lactose = form.has("lactose") ? true : false; + const organic = form.has("organic") ? true : false; + + try{ + await dbe.beer.update({ data: { + slug: slug, + name: name, + description: description, + link: link, + abv: abv, + ibu: ibu, + glass: glass, + sugar: sugar, + lactose: lactose, + gluten: gluten, + organic: organic, + manufacturer: {connect: {id: manufacturer}}, + style: {connect: {id: style}} + }, where: {id: id} + }); + return redirect("/inventory/beer/" + id); + } + catch(e){ + console.log(e); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const styles = await dbe.beerStyle.findMany({orderBy: {name: "asc"}}); + const manufacturers = await dbe.manufacturer.findMany({orderBy: {name: "asc"}}); + + const beer = await dbe.beer.findUnique({where: {id: id}}); + + if(!beer) return redirect("/admin/edit/beer"); + + return json({styles, manufacturers, beer}); +} + +export default function EditBeerRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit beer ({loaderData.beer.id})

+
+ + + ID + + + + + Slug + + + + + Name + + + + + Description + + + + + Style + + {loaderData.styles.map((style) => ( + + ))} + + + + + Manufacturer + + {loaderData.manufacturers.map((manu) => ( + + ))} + + + + + ABV + + + + % + + + + + IBU + + + + + Glass + + + + + Allergies + + + + + + + + Link + + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/beer.tsx b/app/routes/admin/edit/beer.tsx new file mode 100644 index 0000000..130cecf --- /dev/null +++ b/app/routes/admin/edit/beer.tsx @@ -0,0 +1,62 @@ +import { LoaderFunctionArgs, json } from "@remix-run/node"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Col, Button, ListGroup, Badge } from "react-bootstrap"; +import { LinkContainer } from "react-router-bootstrap"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + //const beers = await dbe.beer.findMany({select: {id: true, name: true, _count: {select: {containers: true}}},orderBy: {name: "asc"}}); + const beers = await dbe.beer.findMany({select: {id: true, slug: true, name: true, containers: true},orderBy: {name: "asc"}}); + return json({beers}); +} + +export default function EditBeerRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit beer

+ + + + {loaderData.beers.map((beer) => ( + + {beer.name} {beer.containers.length} Containers +
+ { beer.containers.length <= 0 ? ( + + + + ) : "" } + + + + + + + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/beerstyle.$id.tsx b/app/routes/admin/edit/beerstyle.$id.tsx new file mode 100644 index 0000000..b3a62c3 --- /dev/null +++ b/app/routes/admin/edit/beerstyle.$id.tsx @@ -0,0 +1,75 @@ +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 { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const form = await request.formData(); + const name = String(form.get("name")); + const color = String(form.get("color")).replaceAll("#", ""); + + try{ + await dbe.beerStyle.update({ data: {name: name, color: color}, where: {id: id} }); + return redirect("/admin/edit/beerstyle"); + } + catch(e){ + console.log(e); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const style = await dbe.beerStyle.findUnique({where: {id: id}}); + + if(!style) return redirect("/admin/edit/beerstyle"); + + return json({style}); +} + +export default function EditBeerStyleRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit Beer style ({loaderData.style.id})

+
+ + ID + + + + + Style + + + + + Color + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/beerstyle.tsx b/app/routes/admin/edit/beerstyle.tsx new file mode 100644 index 0000000..24658a0 --- /dev/null +++ b/app/routes/admin/edit/beerstyle.tsx @@ -0,0 +1,53 @@ +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 { LinkContainer } from "react-router-bootstrap"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const beerstyles = await dbe.beerStyle.findMany({select: {id: true, name: true, color: true, _count: {select: {beers: true}}},orderBy: {name: "asc"}}); + return json({beerstyles}); +} + +export default function EditBeerStyleRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit Beerstyle

+ + + + {loaderData.beerstyles.map((style) => ( + + {style.name} {style._count.beers} Beers +
+ { style._count.beers <= 0 ? ( + + + + ) : "" } + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/cocktail.$id.tsx b/app/routes/admin/edit/cocktail.$id.tsx new file mode 100644 index 0000000..636698d --- /dev/null +++ b/app/routes/admin/edit/cocktail.$id.tsx @@ -0,0 +1,180 @@ +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, InputGroup } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const form = await request.formData(); + + const slug = String(form.get("slug")); + const manufacturer = Number(form.get("manufacturer")); + + const name = String(form.get("name")); + const description = String(form.get("description")); + var link : string | null = String(form.get("link")) || null; + if(link == "") link = null; + + const abv = Number(form.get("abv")); + + const mix = form.has("mix") ? true : false; + + const sugar = form.has("sugar") ? true : false; + const gluten = form.has("gluten") ? true : false; + const lactose = form.has("lactose") ? true : false; + const organic = form.has("organic") ? true : false; + + try{ + await dbe.cocktail.update({ data: { + slug: slug, + name: name, + description: description, + link: link, + abv: abv, + mix: mix, + sugar: sugar, + lactose: lactose, + gluten: gluten, + organic: organic, + manufacturer: {connect: {id: manufacturer}} + }, where: {id: id} + }); + return redirect("/inventory/cocktail/" + id); + } + catch(e){ + console.log(e); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const manufacturers = await dbe.manufacturer.findMany({orderBy: {name: "asc"}}); + + const cocktail = await dbe.cocktail.findUnique({where: {id: id}}); + + if(!cocktail) return redirect("/admin/edit/cocktail"); + + return json({manufacturers, cocktail}); +} + +export default function EditCocktailRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit cocktail ({loaderData.cocktail.id})

+
+ + + ID + + + + + Slug + + + + + Name + + + + + Description + + + + + Manufacturer + + {loaderData.manufacturers.map((manu) => ( + + ))} + + + + + ABV + + + + % + + + + + Cocktail specific + + + + + Allergies + + + + + + + + Link + + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/cocktail.tsx b/app/routes/admin/edit/cocktail.tsx new file mode 100644 index 0000000..939b576 --- /dev/null +++ b/app/routes/admin/edit/cocktail.tsx @@ -0,0 +1,62 @@ +import { LoaderFunctionArgs, json } from "@remix-run/node"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Col, Button, ListGroup, Badge } from "react-bootstrap"; +import { LinkContainer } from "react-router-bootstrap"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + //const cocktails = await dbe.cocktail.findMany({select: {id: true, name: true, _count: {select: {containers: true}}},orderBy: {name: "asc"}}); + const cocktails = await dbe.cocktail.findMany({select: {id: true, slug: true, name: true, containers: true},orderBy: {name: "asc"}}); + return json({cocktails}); +} + +export default function EditCocktailRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit cocktail

+ + + + {loaderData.cocktails.map((cocktail) => ( + + {cocktail.name} {cocktail.containers.length} Containers +
+ { cocktail.containers.length <= 0 ? ( + + + + ) : "" } + + + + + + + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/container.$id.tsx b/app/routes/admin/edit/container.$id.tsx new file mode 100644 index 0000000..cbb712a --- /dev/null +++ b/app/routes/admin/edit/container.$id.tsx @@ -0,0 +1,157 @@ +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 { enhance } from "~/utils/db.server"; +import { ContainerType } from "@prisma/client"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const form = await request.formData(); + + var barcode : string | null = String(form.get("barcode")) || null; + if(barcode == "") barcode = null; + + //const drink = Number(form.get("drink")); + const section = Number(form.get("section")); + + const type = form.get("type") as ContainerType; + const volume = Number(form.get("volume")); + const portions = Number(form.get("portions")); + const price = Number(form.get("price")); + const inventory = Number(form.get("inventory")); + + try{ + const updatedContainer = await dbe.container.update({ data: { + barcode: barcode, + type: type, + volume: volume, + portions: portions, + price: price, + inventory: inventory, + //drink: {connect: {id: drink}}, + section: {connect: {id: section}} + }, select: {drink: {select: {slug: true, type: true}}}, + where: {id: id} + }); + return redirect("/inventory/" + updatedContainer.drink.type.toLowerCase() + "/" + updatedContainer.drink.slug); + } + catch(e){ + + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const drinks = await dbe.drink.findMany({orderBy: {name: "asc"}}); + const sections = await dbe.section.findMany({orderBy: {name: "asc"}}); + + const container = await dbe.container.findUnique({where: {id: id}}); + + if(!container) return redirect("/admin/edit/container"); + + return json({drinks, sections, container}); +} + +export default function EditContainerRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit Container ({loaderData.container.id})

+
+ + ID + + + + + Barcode + + + + + Drink + + {loaderData.drinks.map((drink) => ( + + ))} + + + + + Section + + {loaderData.sections.map((section) => ( + + ))} + + + + + Container type + + + + + + + + + + + Volume + + + + ml + + + + + Portions + + + + + Price + + + + + + + + + Inventory + + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/container.tsx b/app/routes/admin/edit/container.tsx new file mode 100644 index 0000000..389da2e --- /dev/null +++ b/app/routes/admin/edit/container.tsx @@ -0,0 +1,55 @@ +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 { LinkContainer } from "react-router-bootstrap"; +import { containerTypeToString } from "~/models/types"; +import { volume } from "~/utils/conversions"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const containers = await dbe.container.findMany({select: {id: true, drink: true, barcode: true, type: true, volume: true, inventory: true},orderBy: {drink: {name: "asc"}}}); + return json({containers}); +} + +export default function EditContainerRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit container

+ + + + {loaderData.containers.map((container) => ( + + {container.drink.name} - {containerTypeToString(container.type)} {volume(container.volume)} {container.inventory} inventory +
+ { container.inventory <= 0 ? ( + + + + ) : "" } + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/country.$code.tsx b/app/routes/admin/edit/country.$code.tsx new file mode 100644 index 0000000..5177e97 --- /dev/null +++ b/app/routes/admin/edit/country.$code.tsx @@ -0,0 +1,69 @@ +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 { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const code = params.code; + + const form = await request.formData(); + const name = String(form.get("name")); + + try{ + await dbe.country.update({ data: {name: name}, where: {code: code}}); + return redirect("/admin/edit/country"); + } + catch(e){ + + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const code = params.code; + + const country = await dbe.country.findUnique({where: {code: code}}); + + if(!country) return redirect("/admin/edit/country"); + + return json({country}); +} + +export default function EditCountryRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit country ({loaderData.country.code})

+
+ + Code + + + + + Country + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/country.tsx b/app/routes/admin/edit/country.tsx new file mode 100644 index 0000000..8cda032 --- /dev/null +++ b/app/routes/admin/edit/country.tsx @@ -0,0 +1,53 @@ +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 { LinkContainer } from "react-router-bootstrap"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const countries = await dbe.country.findMany({select: {name: true, code: true, _count: {select: {manufacturers: true}}},orderBy: {name: "asc"}}); + return json({countries}); +} + +export default function EditCountryRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit country

+ + + + {loaderData.countries.map((country) => ( + + {country.name} ({country.code}) {country._count.manufacturers} Manufactureres +
+ { country._count.manufacturers <= 0 ? ( + + + + ) : "" } + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/image/beer.$id.tsx b/app/routes/admin/edit/image/beer.$id.tsx new file mode 100644 index 0000000..4fad076 --- /dev/null +++ b/app/routes/admin/edit/image/beer.$id.tsx @@ -0,0 +1,102 @@ +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 { renameSync, rmSync } from "node:fs"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Button, Form, Image } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const uploadHandler = unstable_composeUploadHandlers( + unstable_createFileUploadHandler({ + file: ({ filename }) => filename.toLowerCase().replaceAll(" ", "_") + }), + // parse everything else into memory + unstable_createMemoryUploadHandler() + ); + const parsedForm = await unstable_parseMultipartFormData( + request, + uploadHandler + ); + + const image = parsedForm.get("image") as NodeOnDiskFile; + + const beer = await dbe.beer.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!beer) return redirect("/admin/edit/beer"); + + const newFilename = "/beers/" + beer.name.toLowerCase().replaceAll(" ", "_") + "." + image.name.split('.').pop(); + + try{ + // Remove old image + if(beer.image) rmSync("public"+ beer.image, {force: true}); + + // Move the file to the beers folder with the slug as name + renameSync(image.getFilePath(), "public" + newFilename); + + await dbe.beer.update({data: {image: newFilename}, where: {id: id}}); + + return redirect("/inventory/beer/" + id); + } + catch(e){ + console.log(e); + rmSync(image.getFilePath(), {force: true}); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const beer = await dbe.beer.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!beer) return redirect("/admin/edit/beer"); + + return json({beer}); +} + +export default function EditBeerImageRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit beer image ({loaderData.beer.name})

+ +
+ + + Image + + + + +
+
+ +

Current image

+ { loaderData.beer.image ? ( + <> +

{loaderData.beer.image}

+ + + ) : "No current image" } +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/image/cocktail.$id.tsx b/app/routes/admin/edit/image/cocktail.$id.tsx new file mode 100644 index 0000000..608ce75 --- /dev/null +++ b/app/routes/admin/edit/image/cocktail.$id.tsx @@ -0,0 +1,102 @@ +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 { renameSync, rmSync } from "node:fs"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Button, Form, Image } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const uploadHandler = unstable_composeUploadHandlers( + unstable_createFileUploadHandler({ + file: ({ filename }) => filename.toLowerCase().replaceAll(" ", "_") + }), + // parse everything else into memory + unstable_createMemoryUploadHandler() + ); + const parsedForm = await unstable_parseMultipartFormData( + request, + uploadHandler + ); + + const image = parsedForm.get("image") as NodeOnDiskFile; + + const cocktail = await dbe.cocktail.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!cocktail) return redirect("/admin/edit/cocktail"); + + const newFilename = "/cocktails/" + cocktail.name.toLowerCase().replaceAll(" ", "_") + "." + image.name.split('.').pop(); + + try{ + // Remove old image + if(cocktail.image) rmSync("public"+ cocktail.image, {force: true}); + + // Move the file to the cocktails folder with the slug as name + renameSync(image.getFilePath(), "public" + newFilename); + + await dbe.cocktail.update({data: {image: newFilename}, where: {id: id}}); + + return redirect("/inventory/cocktail/" + id); + } + catch(e){ + console.log(e); + rmSync(image.getFilePath(), {force: true}); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const cocktail = await dbe.cocktail.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!cocktail) return redirect("/admin/edit/cocktail"); + + return json({cocktail}); +} + +export default function EditCocktailImageRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit cocktail image ({loaderData.cocktail.name})

+ +
+ + + Image + + + + +
+
+ +

Current image

+ { loaderData.cocktail.image ? ( + <> +

{loaderData.cocktail.image}

+ + + ) : "No current image" } +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/image/manufacturer.$id.tsx b/app/routes/admin/edit/image/manufacturer.$id.tsx new file mode 100644 index 0000000..4624e0b --- /dev/null +++ b/app/routes/admin/edit/image/manufacturer.$id.tsx @@ -0,0 +1,102 @@ +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 { renameSync, rmSync } from "node:fs"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Button, Form, Image } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const uploadHandler = unstable_composeUploadHandlers( + unstable_createFileUploadHandler({ + file: ({ filename }) => filename.toLowerCase().replaceAll(" ", "_") + }), + // parse everything else into memory + unstable_createMemoryUploadHandler() + ); + const parsedForm = await unstable_parseMultipartFormData( + request, + uploadHandler + ); + + const image = parsedForm.get("image") as NodeOnDiskFile; + + const manufacturer = await dbe.manufacturer.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!manufacturer) return redirect("/admin/edit/manufacturer"); + + const newFilename = "/manufacturers/" + manufacturer.name.toLowerCase().replaceAll(" ", "_") + "." + image.name.split('.').pop(); + + try{ + // Remove old image + if(manufacturer.image) rmSync("public"+ manufacturer.image, {force: true}); + + // Move the file to the manufacturers folder with the slug as name + renameSync(image.getFilePath(), "public" + newFilename); + + await dbe.manufacturer.update({data: {image: newFilename}, where: {id: id}}); + + return redirect("/inventory/manufacturer/" + id); + } + catch(e){ + console.log(e); + rmSync(image.getFilePath(), {force: true}); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const manufacturer = await dbe.manufacturer.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!manufacturer) return redirect("/admin/edit/manufacturer"); + + return json({manufacturer}); +} + +export default function EditManufacturerImageRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit Manufacturer image ({loaderData.manufacturer.name})

+ +
+ + + Image + + + + +
+
+ +

Current image

+ { loaderData.manufacturer.image ? ( + <> +

{loaderData.manufacturer.image}

+ + + ) : "No current image" } +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/image/soda.$id.tsx b/app/routes/admin/edit/image/soda.$id.tsx new file mode 100644 index 0000000..e9ca425 --- /dev/null +++ b/app/routes/admin/edit/image/soda.$id.tsx @@ -0,0 +1,102 @@ +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 { renameSync, rmSync } from "node:fs"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Button, Form, Image } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const uploadHandler = unstable_composeUploadHandlers( + unstable_createFileUploadHandler({ + file: ({ filename }) => filename.toLowerCase().replaceAll(" ", "_") + }), + // parse everything else into memory + unstable_createMemoryUploadHandler() + ); + const parsedForm = await unstable_parseMultipartFormData( + request, + uploadHandler + ); + + const image = parsedForm.get("image") as NodeOnDiskFile; + + const soda = await dbe.soda.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!soda) return redirect("/admin/edit/soda"); + + const newFilename = "/soda/" + soda.name.toLowerCase().replaceAll(" ", "_") + "." + image.name.split('.').pop(); + + try{ + // Remove old image + if(soda.image) rmSync("public"+ soda.image, {force: true}); + + // Move the file to the sodas folder with the slug as name + renameSync(image.getFilePath(), "public" + newFilename); + + await dbe.soda.update({data: {image: newFilename}, where: {id: id}}); + + return redirect("/inventory/soda/" + id); + } + catch(e){ + console.log(e); + rmSync(image.getFilePath(), {force: true}); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const soda = await dbe.soda.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!soda) return redirect("/admin/edit/soda"); + + return json({soda}); +} + +export default function EditSodaImageRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit soda image ({loaderData.soda.name})

+ +
+ + + Image + + + + +
+
+ +

Current image

+ { loaderData.soda.image ? ( + <> +

{loaderData.soda.image}

+ + + ) : "No current image" } +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/image/wine.$id.tsx b/app/routes/admin/edit/image/wine.$id.tsx new file mode 100644 index 0000000..5a00830 --- /dev/null +++ b/app/routes/admin/edit/image/wine.$id.tsx @@ -0,0 +1,102 @@ +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 { renameSync, rmSync } from "node:fs"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Button, Form, Image } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const uploadHandler = unstable_composeUploadHandlers( + unstable_createFileUploadHandler({ + file: ({ filename }) => filename.toLowerCase().replaceAll(" ", "_") + }), + // parse everything else into memory + unstable_createMemoryUploadHandler() + ); + const parsedForm = await unstable_parseMultipartFormData( + request, + uploadHandler + ); + + const image = parsedForm.get("image") as NodeOnDiskFile; + + const wine = await dbe.wine.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!wine) return redirect("/admin/edit/wine"); + + const newFilename = "/wine/" + wine.name.toLowerCase().replaceAll(" ", "_") + "." + image.name.split('.').pop(); + + try{ + // Remove old image + if(wine.image) rmSync("public"+ wine.image, {force: true}); + + // Move the file to the wines folder with the slug as name + renameSync(image.getFilePath(), "public" + newFilename); + + await dbe.wine.update({data: {image: newFilename}, where: {id: id}}); + + return redirect("/inventory/wine/" + id); + } + catch(e){ + console.log(e); + rmSync(image.getFilePath(), {force: true}); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const wine = await dbe.wine.findUnique({select: {image: true, name: true}, where: {id: id}}); + + if(!wine) return redirect("/admin/edit/wine"); + + return json({wine}); +} + +export default function EditWineImageRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit wine image ({loaderData.wine.name})

+ +
+ + + Image + + + + +
+
+ +

Current image

+ { loaderData.wine.image ? ( + <> +

{loaderData.wine.image}

+ + + ) : "No current image" } +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/manufacturer.$id.tsx b/app/routes/admin/edit/manufacturer.$id.tsx new file mode 100644 index 0000000..ab9b96d --- /dev/null +++ b/app/routes/admin/edit/manufacturer.$id.tsx @@ -0,0 +1,89 @@ +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 } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const form = await request.formData(); + const country = String(form.get("country")); + const name = String(form.get("name")); + const description = String(form.get("description")); + + try{ + await dbe.manufacturer.update({data: {name: name, description: description, country: {connect: {code: country}}}, where: {id: id} }); + return redirect("/inventory/manufacturer/" + id); + } + catch(e){ + console.log(e); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const countries = await dbe.country.findMany({orderBy: {name: "asc"}}); + const manufacturer = await dbe.manufacturer.findUnique({where: {id: id}}); + + if(!manufacturer) return redirect("/admin/edit/manufacturer"); + + return json({manufacturer, countries}); +} + +export default function NewManufacturerRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit Manufacturer ({loaderData.manufacturer.id})

+
+ + ID + + + + + Country + + {loaderData.countries.map((country) => ( + + ))} + + + + + Name + + + + + Description + + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/manufacturer.tsx b/app/routes/admin/edit/manufacturer.tsx new file mode 100644 index 0000000..fe04f68 --- /dev/null +++ b/app/routes/admin/edit/manufacturer.tsx @@ -0,0 +1,58 @@ +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 { LinkContainer } from "react-router-bootstrap"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const manufacturers = await dbe.manufacturer.findMany({select: {id: true, name: true, _count: {select: {drinks: true}}},orderBy: {name: "asc"}}); + return json({manufacturers}); +} + +export default function EditManufacturerRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit manufacturer

+ + + + {loaderData.manufacturers.map((manufacturer) => ( + + {manufacturer.name} {manufacturer._count.drinks} Drinks +
+ { manufacturer._count.drinks <= 0 ? ( + + + + ) : "" } + + + + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/beer.$id.tsx b/app/routes/admin/edit/remove/beer.$id.tsx new file mode 100644 index 0000000..347c850 --- /dev/null +++ b/app/routes/admin/edit/remove/beer.$id.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + await dbe.beer.delete({where: {id: id}}); + return redirect("/admin/edit/beer"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/beerstyle.$id.tsx b/app/routes/admin/edit/remove/beerstyle.$id.tsx new file mode 100644 index 0000000..e05bf92 --- /dev/null +++ b/app/routes/admin/edit/remove/beerstyle.$id.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + await dbe.beerStyle.delete({where: {id: id}}); + return redirect("/admin/edit/beerstyle"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/cocktail.$id.tsx b/app/routes/admin/edit/remove/cocktail.$id.tsx new file mode 100644 index 0000000..aad51ed --- /dev/null +++ b/app/routes/admin/edit/remove/cocktail.$id.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + await dbe.cocktail.delete({where: {id: id}}); + return redirect("/admin/edit/cocktail"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/container.$id.tsx b/app/routes/admin/edit/remove/container.$id.tsx new file mode 100644 index 0000000..e42ed40 --- /dev/null +++ b/app/routes/admin/edit/remove/container.$id.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + await dbe.container.delete({where: {id: id}}); + return redirect("/admin/edit/container"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/country.$code.tsx b/app/routes/admin/edit/remove/country.$code.tsx new file mode 100644 index 0000000..4b56db8 --- /dev/null +++ b/app/routes/admin/edit/remove/country.$code.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const code = params.code; + + await dbe.country.delete({where: {code: code}}); + return redirect("/admin/edit/country"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/manufacturer.$id.tsx b/app/routes/admin/edit/remove/manufacturer.$id.tsx new file mode 100644 index 0000000..b1aa652 --- /dev/null +++ b/app/routes/admin/edit/remove/manufacturer.$id.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + await dbe.manufacturer.delete({where: {id: id}}); + return redirect("/admin/edit/manufacturer"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/section.$id.tsx b/app/routes/admin/edit/remove/section.$id.tsx new file mode 100644 index 0000000..2f55372 --- /dev/null +++ b/app/routes/admin/edit/remove/section.$id.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + await dbe.section.delete({where: {id: id}}); + return redirect("/admin/edit/section"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/soda.$id.tsx b/app/routes/admin/edit/remove/soda.$id.tsx new file mode 100644 index 0000000..93f5ae5 --- /dev/null +++ b/app/routes/admin/edit/remove/soda.$id.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + await dbe.soda.delete({where: {id: id}}); + return redirect("/admin/edit/soda"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/wine.$id.tsx b/app/routes/admin/edit/remove/wine.$id.tsx new file mode 100644 index 0000000..0c40529 --- /dev/null +++ b/app/routes/admin/edit/remove/wine.$id.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + await dbe.wine.delete({where: {id: id}}); + return redirect("/admin/edit/wine"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/remove/winestyle.$id.tsx b/app/routes/admin/edit/remove/winestyle.$id.tsx new file mode 100644 index 0000000..e2a6f10 --- /dev/null +++ b/app/routes/admin/edit/remove/winestyle.$id.tsx @@ -0,0 +1,15 @@ +import { LoaderFunctionArgs, redirect } from "@remix-run/node"; + +import { enhance } from "~/utils/db.server"; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + await dbe.wineStyle.delete({where: {id: id}}); + return redirect("/admin/edit/winestyle"); +} \ No newline at end of file diff --git a/app/routes/admin/edit/route.tsx b/app/routes/admin/edit/route.tsx new file mode 100644 index 0000000..94ceceb --- /dev/null +++ b/app/routes/admin/edit/route.tsx @@ -0,0 +1,22 @@ +import { Link } from "@remix-run/react"; +import { ListGroup } from "react-bootstrap"; + +export default function AdminRoute() { + return ( +
+

Edit or remove

+ + country + section + beer style + wine style + manufacturer + beer + wine + soda + cocktail + container + +
+ ); + } \ No newline at end of file diff --git a/app/routes/admin/edit/section.$id.tsx b/app/routes/admin/edit/section.$id.tsx new file mode 100644 index 0000000..3390399 --- /dev/null +++ b/app/routes/admin/edit/section.$id.tsx @@ -0,0 +1,68 @@ +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 { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const form = await request.formData(); + const name = String(form.get("name")); + + try{ + await dbe.section.update({ data: {name: name}, where: {id: id} }); + return redirect("/admin/edit/section"); + } + catch(e){ + + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const section = await dbe.section.findUnique({where: {id: id}}); + + if(!section) return redirect("/admin/edit/section"); + + return json({section}); +} + +export default function EditSectionRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit Section ({loaderData.section.id})

+
+ + ID + + + + Section + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/section.tsx b/app/routes/admin/edit/section.tsx new file mode 100644 index 0000000..0d60c0d --- /dev/null +++ b/app/routes/admin/edit/section.tsx @@ -0,0 +1,53 @@ +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 { LinkContainer } from "react-router-bootstrap"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const sections = await dbe.section.findMany({select: {name: true, id: true, _count: {select: {containers: true}}}, orderBy: {name: "asc"}}); + return json({sections}); +} + +export default function EditSectionRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit section

+ + + + {loaderData.sections.map((section) => ( + + {section.name} {section._count.containers} Containers +
+ { section._count.containers <= 0 ? ( + + + + ) : "" } + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/soda.$id.tsx b/app/routes/admin/edit/soda.$id.tsx new file mode 100644 index 0000000..09c880b --- /dev/null +++ b/app/routes/admin/edit/soda.$id.tsx @@ -0,0 +1,180 @@ +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, InputGroup } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const form = await request.formData(); + + const slug = String(form.get("slug")); + const manufacturer = Number(form.get("manufacturer")); + + const name = String(form.get("name")); + const description = String(form.get("description")); + var link : string | null = String(form.get("link")) || null; + if(link == "") link = null; + + const abv = Number(form.get("abv")); + + const carbonated = form.has("carbonated") ? true : false; + + const sugar = form.has("sugar") ? true : false; + const gluten = form.has("gluten") ? true : false; + const lactose = form.has("lactose") ? true : false; + const organic = form.has("organic") ? true : false; + + try{ + await dbe.soda.update({ data: { + slug: slug, + name: name, + description: description, + link: link, + abv: abv, + carbonated: carbonated, + sugar: sugar, + lactose: lactose, + gluten: gluten, + organic: organic, + manufacturer: {connect: {id: manufacturer}} + }, where: { id: id} + }); + return redirect("/inventory/soda/" + id); + } + catch(e){ + console.log(e); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const manufacturers = await dbe.manufacturer.findMany({orderBy: {name: "asc"}}); + + const soda = await dbe.soda.findUnique({where: {id: id}}); + + if(!soda) return redirect("/admin/edit/soda"); + + return json({manufacturers, soda}); +} + +export default function EditSodaRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit soda ({loaderData.soda.id})

+
+ + + ID + + + + + Slug + + + + + Name + + + + + Description + + + + + Manufacturer + + {loaderData.manufacturers.map((manu) => ( + + ))} + + + + + ABV + + + + % + + + + + Soda specific + + + + + Allergies + + + + + + + + Link + + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/soda.tsx b/app/routes/admin/edit/soda.tsx new file mode 100644 index 0000000..962c24a --- /dev/null +++ b/app/routes/admin/edit/soda.tsx @@ -0,0 +1,62 @@ +import { LoaderFunctionArgs, json } from "@remix-run/node"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Col, Button, ListGroup, Badge } from "react-bootstrap"; +import { LinkContainer } from "react-router-bootstrap"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + //const sodas = await dbe.soda.findMany({select: {id: true, name: true, _count: {select: {containers: true}}},orderBy: {name: "asc"}}); + const sodas = await dbe.soda.findMany({select: {id: true, slug: true, name: true, containers: true},orderBy: {name: "asc"}}); + return json({sodas}); +} + +export default function EditSodaRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit soda

+ + + + {loaderData.sodas.map((soda) => ( + + {soda.name} {soda.containers.length} Containers +
+ { soda.containers.length <= 0 ? ( + + + + ) : "" } + + + + + + + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/wine.$id.tsx b/app/routes/admin/edit/wine.$id.tsx new file mode 100644 index 0000000..995b3e1 --- /dev/null +++ b/app/routes/admin/edit/wine.$id.tsx @@ -0,0 +1,227 @@ +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, InputGroup } from "react-bootstrap"; + +import { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const form = await request.formData(); + + const slug = String(form.get("slug")); + const manufacturer = Number(form.get("manufacturer")); + const style = Number(form.get("style")); + + const name = String(form.get("name")); + const description = String(form.get("description")); + var link : string | null = String(form.get("link")) || null; + if(link == "") link = null; + + const abv = Number(form.get("abv")); + + var heavy_score : number | null = Number(form.get("heavy_score")); + if(heavy_score < 0) heavy_score = null; + var tannine_score : number | null = Number(form.get("tannine_score")); + if(tannine_score < 0) tannine_score = null; + var dry_score : number | null = Number(form.get("dry_score")); + if(dry_score < 0) dry_score = null; + var fresh_score : number | null = Number(form.get("fresh_score")); + if(fresh_score < 0) fresh_score = null; + + var notes : string | null = String(form.get("notes")) || null; + if(notes == "") notes = null; + + const sugar = form.has("sugar") ? true : false; + const gluten = form.has("gluten") ? true : false; + const lactose = form.has("lactose") ? true : false; + const organic = form.has("organic") ? true : false; + + + try{ + await dbe.wine.update({ data: { + slug: slug, + name: name, + description: description, + link: link, + abv: abv, + heavy_score: heavy_score, + tannine_score: tannine_score, + dry_score: dry_score, + fresh_score: fresh_score, + notes: notes, + sugar: sugar, + lactose: lactose, + gluten: gluten, + organic: organic, + manufacturer: {connect: {id: manufacturer}}, + style: {connect: {id: style}} + }, where: {id: id} + }); + return redirect("/inventory/wine/" + id); + } + catch(e){ + console.log(e); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const styles = await dbe.wineStyle.findMany({orderBy: {name: "asc"}}); + const manufacturers = await dbe.manufacturer.findMany({orderBy: {name: "asc"}}); + + const wine = await dbe.wine.findUnique({where: {id: id}}); + + if(!wine) return redirect("/admin/edit/wine"); + + return json({styles, manufacturers, wine}); +} + +export default function EditWineRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit wine ({loaderData.wine.id})

+
+ + + ID + + + + + Slug + + + + + Name + + + + + Description + + + + + Style + + {loaderData.styles.map((style) => ( + + ))} + + + + + Manufacturer + + {loaderData.manufacturers.map((manu) => ( + + ))} + + + + + ABV + + + + % + + + + + Heavy + + Left = undefined, then light (0) - bold (5) + + + + Tannine + + Left = undefined, then smooth (0) - tannic (5) + + + + Dryness + + Left = undefined, then dry (0) - sweet (5) + + + + Freshness + + Left = undefined, then soft (0) - acidic (5) + + + + Notes + + + + + Allergies + + + + + + + + Link + + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/wine.tsx b/app/routes/admin/edit/wine.tsx new file mode 100644 index 0000000..6c7272a --- /dev/null +++ b/app/routes/admin/edit/wine.tsx @@ -0,0 +1,62 @@ +import { LoaderFunctionArgs, json } from "@remix-run/node"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Col, Button, ListGroup, Badge } from "react-bootstrap"; +import { LinkContainer } from "react-router-bootstrap"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + //const wines = await dbe.wine.findMany({select: {id: true, name: true, _count: {select: {containers: true}}},orderBy: {name: "asc"}}); + const wines = await dbe.wine.findMany({select: {id: true, slug: true, name: true, containers: true}, orderBy: {name: "asc"}}); + return json({wines}); +} + +export default function EditWineRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit wine

+ + + + {loaderData.wines.map((wine) => ( + + {wine.name} {wine.containers.length} Containers +
+ { wine.containers.length <= 0 ? ( + + + + ) : "" } + + + + + + + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/winestyle.$id.tsx b/app/routes/admin/edit/winestyle.$id.tsx new file mode 100644 index 0000000..f276d42 --- /dev/null +++ b/app/routes/admin/edit/winestyle.$id.tsx @@ -0,0 +1,75 @@ +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 { enhance } from "~/utils/db.server"; + +export const action = async ({ + request, + params +}: ActionFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const form = await request.formData(); + const name = String(form.get("name")); + const color = String(form.get("color")).replaceAll("#", ""); + + try{ + await dbe.wineStyle.update({ data: {name: name, color: color}, where: {id: id} }); + return redirect("/admin/edit/winestyle"); + } + catch(e){ + console.log(e); + } + + return null; +}; + +export const loader = async ({ + request, + params +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const id = Number(params.id); + + const style = await dbe.wineStyle.findUnique({where: {id: id}}); + + if(!style) return redirect("/admin/edit/winestyle"); + + return json({style}); +} + +export default function EditWineStyleRoute() { + var loaderData = useLoaderData(); + + return ( + + +

Edit Wine style ({loaderData.style.id})

+
+ + ID + + + + + Style + + + + + Color + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/winestyle.tsx b/app/routes/admin/edit/winestyle.tsx new file mode 100644 index 0000000..c6ddbbe --- /dev/null +++ b/app/routes/admin/edit/winestyle.tsx @@ -0,0 +1,51 @@ +import { LoaderFunctionArgs, json } from "@remix-run/node"; +import { useLoaderData } from "@remix-run/react"; +import { Container, Row, Col, Button, ListGroup, Badge } from "react-bootstrap"; +import { LinkContainer } from "react-router-bootstrap"; + +import { enhance } from "~/utils/db.server"; + + +export const loader = async ({ + request, +} : LoaderFunctionArgs) => { + const { dbe } = await enhance(request); + + const winestyles = await dbe.wineStyle.findMany({select: {id: true, name: true, color: true, _count: {select: {wines: true}}},orderBy: {name: "asc"}}); + return json({winestyles}); +} + +export default function EditWineStyleRoute() { + var loaderData = useLoaderData(); + + return ( + +

Edit Winestyle

+ + + + {loaderData.winestyles.map((style) => ( + + {style.name} {style._count.wines} Wines +
+ { style._count.wines <= 0 ? ( + + + + ) : "" } + + + +
+
+ ))} +
+ +
+
+ ); +} \ No newline at end of file diff --git a/app/routes/admin/edit/checkout.tsx b/app/routes/admin/manage/checkout.tsx similarity index 100% rename from app/routes/admin/edit/checkout.tsx rename to app/routes/admin/manage/checkout.tsx diff --git a/app/routes/admin/edit/inventory.tsx b/app/routes/admin/manage/inventory.tsx similarity index 100% rename from app/routes/admin/edit/inventory.tsx rename to app/routes/admin/manage/inventory.tsx diff --git a/app/routes/admin/new/beer.tsx b/app/routes/admin/new/beer.tsx index 525e8d0..9a7f828 100644 --- a/app/routes/admin/new/beer.tsx +++ b/app/routes/admin/new/beer.tsx @@ -35,17 +35,22 @@ export const action = async ({ const abv = Number(parsedForm.get("abv")); const ibu = Number(parsedForm.get("ibu")); + const glass = parsedForm.has("glass") ? true : false; + + const sugar = parsedForm.has("sugar") ? true : false; const gluten = parsedForm.has("gluten") ? true : false; const lactose = parsedForm.has("lactose") ? true : false; const organic = parsedForm.has("organic") ? true : false; const image = parsedForm.get("image") as NodeOnDiskFile; - const newFilename = "/beers/" + slug + "." + image.name.split('.').pop(); + var newFilename = null; + if(image.size > 0) + newFilename = "/beers/" + slug + "." + image.name.split('.').pop(); try{ // Move the file to the beers folder with the slug as name - renameSync(image.getFilePath(), "public" + newFilename); + if(newFilename) renameSync(image.getFilePath(), "public" + newFilename); const createdBeer = await dbe.beer.create({ data: { slug: slug, @@ -55,6 +60,8 @@ export const action = async ({ link: link, abv: abv, ibu: ibu, + glass: glass, + sugar: sugar, lactose: lactose, gluten: gluten, organic: organic, @@ -94,7 +101,7 @@ export default function NewBeerRoute() { Slug - + @@ -143,8 +150,24 @@ export default function NewBeerRoute() { + + Glass + + + Allergies + Image - +