Implement the (mostly) functional side of things
This commit is contained in:
parent
0f4955c5b5
commit
40f4520458
92
src/App.tsx
92
src/App.tsx
|
@ -1,26 +1,112 @@
|
||||||
|
import { Alert, Collapse, Rating, Typography } from "@mui/material";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import ButtonRow, { ActionProps } from "./components/ButtonRow";
|
import ButtonRow, { ActionProps } from "./components/ButtonRow";
|
||||||
import ReviewField from "./components/ReviewField";
|
import ReviewField, { ReviewFieldProps } from "./components/ReviewField";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const [rating, setNewRating] = useState<number | null>(0);
|
||||||
|
const [showAlert, changeAlert] = useState(false);
|
||||||
|
const [alertText, changeAlertText] = useState("");
|
||||||
|
|
||||||
|
const fields: ReviewFieldProps[] = [
|
||||||
|
{
|
||||||
|
name: "Name",
|
||||||
|
dynamicState: useState("")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Title",
|
||||||
|
dynamicState: useState("")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Content",
|
||||||
|
dynamicState: useState("")
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const clearValues = () => {
|
||||||
|
fields.forEach((field) => {
|
||||||
|
field.dynamicState[1]("");
|
||||||
|
});
|
||||||
|
|
||||||
|
setNewRating(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const showThenHide = async () => {
|
||||||
|
const response = await fetch("http://localhost:8080/post", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
rating: rating,
|
||||||
|
username: fields[0].dynamicState[0],
|
||||||
|
title: fields[1].dynamicState[0],
|
||||||
|
content: fields[2].dynamicState[0]
|
||||||
|
})
|
||||||
|
}).then((response) => response.json());
|
||||||
|
|
||||||
|
response.error ? changeAlertText(`${response.error.type}: ${response.error.message}`) : changeAlertText(`Success: ${response.message}`);
|
||||||
|
|
||||||
|
if (showAlert) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeAlert(true);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
changeAlert(false);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
const buttons: ActionProps[] = [
|
const buttons: ActionProps[] = [
|
||||||
{
|
{
|
||||||
name: "Cancel",
|
name: "Clear",
|
||||||
type: "outlined",
|
type: "outlined",
|
||||||
|
action: clearValues
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Submit",
|
name: "Submit",
|
||||||
type: "contained",
|
type: "contained",
|
||||||
|
action: showThenHide
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const alert = (
|
||||||
|
<Alert severity="info">
|
||||||
|
{alertText}
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ReviewField />
|
<Typography variant="h3">
|
||||||
|
Simple Review Client
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<Rating
|
||||||
|
name="review-rating"
|
||||||
|
precision={0.5}
|
||||||
|
size="large"
|
||||||
|
value={rating}
|
||||||
|
onChange={(event, newRating) => {
|
||||||
|
setNewRating(newRating);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<ReviewField fields={fields} />
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<ButtonRow buttons={buttons} />
|
<ButtonRow buttons={buttons} />
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<Collapse in={showAlert}>
|
||||||
|
{alert}
|
||||||
|
</Collapse>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import React, { ReactNode } from "react";
|
||||||
export interface ActionProps {
|
export interface ActionProps {
|
||||||
name: string;
|
name: string;
|
||||||
type: "outlined" | "text" | "contained";
|
type: "outlined" | "text" | "contained";
|
||||||
|
action?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ActionButtonProps {
|
interface ActionButtonProps {
|
||||||
|
@ -14,7 +15,15 @@ const ButtonRow = ({ buttons }: ActionButtonProps) => {
|
||||||
return (
|
return (
|
||||||
<Grid2 container spacing={2}>
|
<Grid2 container spacing={2}>
|
||||||
{buttons.map((button) => {
|
{buttons.map((button) => {
|
||||||
return <Button variant={button.type}>{button.name}</Button>;
|
return (
|
||||||
|
<Button
|
||||||
|
key={button.name}
|
||||||
|
variant={button.type}
|
||||||
|
onClick={button.action}
|
||||||
|
>
|
||||||
|
{button.name}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,15 +1,41 @@
|
||||||
import { Box, Grid2, TextField } from "@mui/material";
|
import { Box, Stack, TextField } from "@mui/material";
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
export interface ReviewFieldProps {
|
||||||
|
name: string;
|
||||||
|
dynamicState: [string, React.Dispatch<React.SetStateAction<string>>];
|
||||||
|
variant?: "outlined" | "filled" | "standard";
|
||||||
|
help?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReviewFieldOpts {
|
||||||
|
fields: ReviewFieldProps[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ReviewField = ({ fields }: ReviewFieldOpts) => {
|
||||||
|
|
||||||
const ReviewField = () => {
|
|
||||||
return (
|
return (
|
||||||
<Box component="form" noValidate autoComplete="off">
|
<Box component="form" noValidate autoComplete="off">
|
||||||
<Grid2 container spacing={4}>
|
<Stack spacing={1}>
|
||||||
<TextField id="username" label="Username" variant="outlined" />
|
{
|
||||||
<TextField id="rating" label="Rating" variant="outlined" />
|
fields.map((field) => {
|
||||||
<TextField id="title" label="Title" variant="outlined" />
|
return (
|
||||||
<TextField id="content" label="Content" variant="outlined" />
|
<TextField
|
||||||
</Grid2>
|
id={field.name}
|
||||||
|
key={field.name}
|
||||||
|
label={field.name}
|
||||||
|
value={field.dynamicState[0]}
|
||||||
|
onChange={(({ target }) => {
|
||||||
|
field.dynamicState[1](target.value);
|
||||||
|
})}
|
||||||
|
variant={field.variant ?? "outlined"}
|
||||||
|
helperText={field.help}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue