219 lines
6.8 KiB
TypeScript
219 lines
6.8 KiB
TypeScript
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 { copyFileSync, rmSync } from "node:fs";
|
|
import { useState } from "react";
|
|
import { Button, Container, Form, InputGroup, Row } from "react-bootstrap";
|
|
|
|
import { enhance } from "~/utils/db.server";
|
|
import { slugify } from "~/utils/slugs";
|
|
|
|
export const action = async ({
|
|
request,
|
|
}: ActionFunctionArgs) => {
|
|
const { dbe } = await enhance(request);
|
|
|
|
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 slug = String(parsedForm.get("slug"));
|
|
const manufacturer = Number(parsedForm.get("manufacturer"));
|
|
const style = Number(parsedForm.get("style"));
|
|
|
|
const name = String(parsedForm.get("name"));
|
|
const description = String(parsedForm.get("description"));
|
|
var link : string | null = String(parsedForm.get("link")) || null;
|
|
if(link == "") link = null;
|
|
|
|
const abv = Number(parsedForm.get("abv"));
|
|
var ibu : number | null = Number(parsedForm.get("ibu"));
|
|
if(ibu < 0) ibu = null;
|
|
|
|
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;
|
|
|
|
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
|
|
if(newFilename)
|
|
{
|
|
// Copy is required for docker container to work
|
|
copyFileSync(image.getFilePath(), "public" + newFilename);
|
|
rmSync(image.getFilePath(), {force: true});
|
|
}
|
|
|
|
const createdBeer = await dbe.beer.create({ data: {
|
|
slug: slug,
|
|
name: name,
|
|
description: description,
|
|
image: newFilename,
|
|
link: link,
|
|
abv: abv,
|
|
ibu: ibu,
|
|
glass: glass,
|
|
sugar: sugar,
|
|
lactose: lactose,
|
|
gluten: gluten,
|
|
organic: organic,
|
|
manufacturer: {connect: {id: manufacturer}},
|
|
style: {connect: {id: style}}
|
|
}
|
|
});
|
|
return redirect("/inventory/beer/" + createdBeer.slug);
|
|
}
|
|
catch(e){
|
|
console.log(e);
|
|
rmSync(image.getFilePath(), {force: true});
|
|
rmSync("public" + newFilename, {force: true});
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
export const loader = async ({
|
|
request,
|
|
} : LoaderFunctionArgs) => {
|
|
const { dbe } = await enhance(request);
|
|
|
|
const styles = await dbe.beerStyle.findMany({orderBy: {name: "asc"}});
|
|
const manufacturers = await dbe.manufacturer.findMany({orderBy: {name: "asc"}});
|
|
return json({styles, manufacturers});
|
|
}
|
|
|
|
export default function NewBeerRoute() {
|
|
var loaderData = useLoaderData<typeof loader>();
|
|
|
|
var [slug, setSlug] = useState("");
|
|
|
|
return (
|
|
<Container>
|
|
<Row>
|
|
<h1>Add Beer</h1>
|
|
<Form method="POST" encType="multipart/form-data">
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>Slug</Form.Label>
|
|
<Form.Control type="text" placeholder="Auto generated" value={slug} name="slug" plaintext readOnly/>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>Name</Form.Label>
|
|
<Form.Control type="text" placeholder="Blond" name="name" required onChange={(e) => {setSlug(slugify(e.target.value))}}/>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>Description</Form.Label>
|
|
<Form.Control as="textarea" type="text" name="description"/>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>Style</Form.Label>
|
|
<Form.Select name="style" required>
|
|
{loaderData.styles.map((style) => (
|
|
<option value={style.id}>
|
|
{style.name}
|
|
</option>
|
|
))}
|
|
</Form.Select>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>Manufacturer</Form.Label>
|
|
<Form.Select name="manufacturer" required>
|
|
{loaderData.manufacturers.map((manu) => (
|
|
<option value={manu.id}>
|
|
{manu.name}
|
|
</option>
|
|
))}
|
|
</Form.Select>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>ABV</Form.Label>
|
|
|
|
<InputGroup>
|
|
<Form.Control type="number" min={0} max={100} step={0.1} name="abv" defaultValue={0.0} required/>
|
|
<InputGroup.Text>%</InputGroup.Text>
|
|
</InputGroup>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>IBU</Form.Label>
|
|
<Form.Control type="number" min={-1} max={200} step={1} name="ibu" defaultValue={-1} required/>
|
|
<Form.Text>-1 = undefined</Form.Text>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>Glass</Form.Label>
|
|
<Form.Check
|
|
type="checkbox"
|
|
label="Has custom glass"
|
|
name="glass"
|
|
value={1}
|
|
/>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>Allergies</Form.Label>
|
|
<Form.Check
|
|
type="checkbox"
|
|
label="Sugar"
|
|
name="sugar"
|
|
value={1}
|
|
/>
|
|
<Form.Check
|
|
type="checkbox"
|
|
label="Gluten"
|
|
name="gluten"
|
|
value={1}
|
|
/>
|
|
<Form.Check
|
|
type="checkbox"
|
|
label="Lactose"
|
|
name="lactose"
|
|
value={1}
|
|
/>
|
|
<Form.Check
|
|
type="checkbox"
|
|
label="Organic"
|
|
name="organic"
|
|
value={1}
|
|
/>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>Link</Form.Label>
|
|
<Form.Control type="text" placeholder="https://untappd.com/..." name="link"/>
|
|
</Form.Group>
|
|
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>Image</Form.Label>
|
|
<Form.Control type="file" name="image" accept="image/*"/>
|
|
</Form.Group>
|
|
|
|
<Button variant="primary" type="submit">
|
|
Submit
|
|
</Button>
|
|
</Form>
|
|
</Row>
|
|
</Container>
|
|
);
|
|
} |