Files
beer-inventory/app/routes/admin/new/wine.tsx
T

243 lines
8.1 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 heavy_score : number | null = Number(parsedForm.get("heavy_score"));
if(heavy_score < 0) heavy_score = null;
var tannine_score : number | null = Number(parsedForm.get("tannine_score"));
if(tannine_score < 0) tannine_score = null;
var dry_score : number | null = Number(parsedForm.get("dry_score"));
if(dry_score < 0) dry_score = null;
var fresh_score : number | null = Number(parsedForm.get("fresh_score"));
if(fresh_score < 0) fresh_score = null;
var notes : string | null = String(parsedForm.get("notes")) || null;
if(notes == "") notes = null;
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 = "/wine/" + slug + "." + image.name.split('.').pop();
try{
// Move the file to the wines 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 createdWine = await dbe.wine.create({ data: {
slug: slug,
name: name,
description: description,
image: newFilename,
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}}
}
});
return redirect("/inventory/wine/" + createdWine.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.wineStyle.findMany({orderBy: {name: "asc"}});
const manufacturers = await dbe.manufacturer.findMany({orderBy: {name: "asc"}});
return json({styles, manufacturers});
}
export default function NewWineRoute() {
var loaderData = useLoaderData<typeof loader>();
var [slug, setSlug] = useState("");
return (
<Container>
<Row>
<h1>Add Wine</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="White delicious" 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>Heavy</Form.Label>
<Form.Range name="heavy_score" min={-1} max={5} step={1} defaultValue={-1}/>
<Form.Text>Left = undefined, then light (0) - bold (5) </Form.Text>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Tannine</Form.Label>
<Form.Range name="tannine_score" min={-1} max={5} step={1} defaultValue={-1}/>
<Form.Text>Left = undefined, then smooth (0) - tannic (5) </Form.Text>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Dryness</Form.Label>
<Form.Range name="dry_score" min={-1} max={5} step={1} defaultValue={-1}/>
<Form.Text>Left = undefined, then dry (0) - sweet (5) </Form.Text>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Freshness</Form.Label>
<Form.Range name="fresh_score" min={-1} max={5} step={1} defaultValue={-1}/>
<Form.Text>Left = undefined, then soft (0) - acidic (5) </Form.Text>
</Form.Group>
<Form.Group className="mb-3">
<Form.Label>Notes</Form.Label>
<Form.Control as="textarea" type="text" name="notes"/>
</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://vivino.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>
);
}