Skip to content

Commit

Permalink
feat: Basic UI structure
Browse files Browse the repository at this point in the history
  • Loading branch information
DafyddLlyr committed May 27, 2024
1 parent f220353 commit 51bfc1a
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 29 deletions.
27 changes: 0 additions & 27 deletions editor.planx.uk/src/@planx/components/List/Public.tsx

This file was deleted.

134 changes: 134 additions & 0 deletions editor.planx.uk/src/@planx/components/List/Public/Fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import Box from "@mui/material/Box";
import FormControl from "@mui/material/FormControl";
import FormLabel from "@mui/material/FormLabel";
import MenuItem from "@mui/material/MenuItem";
import RadioGroup from "@mui/material/RadioGroup";
import React from "react";
import SelectInput from "ui/editor/SelectInput";
import InputLabel from "ui/public/InputLabel";
import Input from "ui/shared/Input";
import InputRowLabel from "ui/shared/InputRowLabel";

import { DESCRIPTION_TEXT } from "../../shared/constants";
import BasicRadio from "../../shared/Radio/BasicRadio";
import type { NumberField, QuestionField, TextField } from "../model";

type Props<T> = T & { id: string };

export const TextFieldInput: React.FC<Props<TextField>> = ({
id,
data,
required,
}) => (
<InputLabel label={data.title} htmlFor={id}>
<Input
type={((type) => {
if (type === "email") return "email";
else if (type === "phone") return "tel";
return "text";
})(data.type)}
multiline={data.type && ["long", "extraLong"].includes(data.type)}
bordered
id={id}
rows={
data.type && ["long", "extraLong"].includes(data.type) ? 5 : undefined
}
name="text"
required={required}
inputProps={{
"aria-describedby": [
data.description ? DESCRIPTION_TEXT : "",
// TODO: When handling errors, revisit this
// formik.errors.text ? `${ERROR_MESSAGE}-${inputFieldId}` : "",
]
.filter(Boolean)
.join(" "),
}}
/>
</InputLabel>
);

export const NumberFieldInput: React.FC<Props<NumberField>> = ({
id,
data,
required,
}) => (
<InputLabel label={data.title} htmlFor={id}>
<Box sx={{ display: "flex", alignItems: "baseline" }}>
<Input
required={required}
bordered
name="value"
type="number"
// value={formik.values.value}
// onChange={formik.handleChange}
// errorMessage={formik.errors.value as string}
inputProps={{
"aria-describedby": [
data.description ? DESCRIPTION_TEXT : "",
// formik.errors.value ? `${ERROR_MESSAGE}-${props.id}` : "",
]
.filter(Boolean)
.join(" "),
}}
id={id}
/>
{data.units && <InputRowLabel>{data.units}</InputRowLabel>}
</Box>
</InputLabel>
);

export const RadioFieldInput: React.FC<Props<QuestionField>> = ({
id,
data,
}) => (
<FormControl sx={{ width: "100%" }} component="fieldset">
<FormLabel
component="legend"
id={`radio-buttons-group-label-${id}`}
sx={(theme) => ({
color: theme.palette.text.primary,
"&.Mui-focused": {
color: theme.palette.text.primary,
},
})}
>
{data.title}
</FormLabel>
{/* <ErrorWrapper id={props.id} error={formik.errors.selected?.id}> */}
<RadioGroup
aria-labelledby={`radio-buttons-group-label-${id}`}
name={`radio-buttons-group-${id}`}
sx={{ p: 1 }}
// value={formik.values.selected.id}
>
{data.options.map(({ id, data }) => (
<BasicRadio
id={id}
title={data.text}
onChange={() => console.log("change radio")}
/>
))}
</RadioGroup>
{/* </ErrorWrapper> */}
</FormControl>
);

export const SelectFieldInput: React.FC<Props<QuestionField>> = ({
id,
data,
required,
}) => (
<InputLabel label={data.title} htmlFor={id}>
<SelectInput id={id} bordered required={required}>
{data.options.map((option) => (
<MenuItem
key={option.id}
// value={option.data.text}
>
{option.data.text}
</MenuItem>
))}
</SelectInput>
</InputLabel>
);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { axe, setup } from "testUtils";

import ListComponent from "./Editor";
import ListComponent from "../Editor";

it("should not have any accessibility violations", async () => {
const { container } = setup(<ListComponent />);
Expand Down
97 changes: 97 additions & 0 deletions editor.planx.uk/src/@planx/components/List/Public/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import { styled } from "@mui/material/styles";
import Typography from "@mui/material/Typography";
import { PublicProps } from "@planx/components/ui";
import React from "react";
import InputRow from "ui/shared/InputRow";

import Card from "../../shared/Preview/Card";
import CardHeader from "../../shared/Preview/CardHeader";
import type { Field, List } from "../model";
import {
NumberFieldInput,
RadioFieldInput,
SelectFieldInput,
TextFieldInput,
} from "./Fields";

type Props = PublicProps<List>;

const ListCard = styled(Box)(({ theme }) => ({
padding: theme.spacing(2),
backgroundColor: theme.palette.background.paper,
border: "1px solid darkgray",
display: "flex",
flexDirection: "column",
gap: theme.spacing(2),
marginBottom: theme.spacing(2),
}));

/**
* Controller to return correct user input for field in schema
*/
const InputField: React.FC<Field & { index: number }> = (props) => {
const inputFieldId = `input-${props.type}-${props.index}`;

switch (props.type) {
case "text":
return <TextFieldInput id={inputFieldId} {...props} />;
case "number":
return <NumberFieldInput id={inputFieldId} {...props} />;
case "question":
if (props.data.options.length === 2) {
return <RadioFieldInput id={inputFieldId} {...props} />;
}
return <SelectFieldInput id={inputFieldId} {...props} />;
}
};

function ListComponent({
info,
policyRef,
howMeasured,
schema,
handleSubmit,
title,
description,
}: Props) {
// TODO: Track user state, allow items to be added and removed
// TODO: Track "active" index
// TODO: Validate min / max
// TODO: Validate user input against schema fields, track errors
// TODO: On submit generate a payload

return (
<Card handleSubmit={handleSubmit} isValid>
<CardHeader
title={title}
description={description}
info={info}
policyRef={policyRef}
howMeasured={howMeasured}
/>
<ListCard>
<Typography component="h3" variant="h3">
{schema.type} index
</Typography>
{schema.fields.map((field, i) => (
<InputRow key={i}>
<InputField {...field} index={i} />
</InputRow>
))}
<Box display="flex" gap={2}>
<Button variant="contained" color="primary">
Save
</Button>
<Button>Cancel</Button>
</Box>
</ListCard>
<Button variant="contained" color="secondary">
+ Add a new {schema.type.toLowerCase()} type
</Button>
</Card>
);
}

export default ListComponent;
4 changes: 3 additions & 1 deletion editor.planx.uk/src/ui/editor/SelectInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface Props extends SelectProps {
name?: string;
children?: ReactNode;
onChange?: SelectProps["onChange"];
bordered?: boolean;
}

const PREFIX = "SelectInput";
Expand Down Expand Up @@ -77,6 +78,7 @@ export default function SelectInput({
value,
name,
onChange,
bordered,
...props
}: Props): FCReturn {
return (
Expand All @@ -89,7 +91,7 @@ export default function SelectInput({
}}
onChange={onChange}
IconComponent={ArrowIcon}
input={<Input />}
input={<Input bordered={bordered} />}
inputProps={{
name,
classes: {
Expand Down

0 comments on commit 51bfc1a

Please sign in to comment.