#11 Add ChangeCategoryDialog w/o logic

For this the ChangeQuestionDialog was refactored to reuse several sub-components
This commit is contained in:
Christoph Lienhard 2020-12-28 20:13:57 +01:00
parent ea21617cf8
commit 57c338b7ef
Signed by: christoph.lienhard
GPG key ID: 6B98870DDC270884
7 changed files with 242 additions and 102 deletions

View file

@ -1,10 +1,11 @@
import {Paper, Typography} from "@material-ui/core";
import React from "react";
import React, {useState} from "react";
import {makeStyles} from "@material-ui/core/styles";
import {useQuery} from "@apollo/client";
import AddCard from "./AddCard";
import AccordionWithEdit from "./AccordionWithEdit";
import {allCategoriesQuery, AllCategoriesQueryResponse} from "../backend/queries/allCategories";
import {allCategoriesQuery, AllCategoriesQueryResponse, GqlCategory} from "../backend/queries/allCategories";
import ChangeCategoryDialog, {ChangeCategoryDialogContent} from "./ChangeCategoryDialog";
const useStyles = makeStyles((theme) => ({
root: {
@ -14,19 +15,68 @@ const useStyles = makeStyles((theme) => ({
},
}));
const emptyChangeCategoryDialog: ChangeCategoryDialogContent = {
id: "",
title: "",
details: "",
}
export default function CategoryList() {
const {data} = useQuery<AllCategoriesQueryResponse, null>(allCategoriesQuery);
const [dialogOpen, setDialogOpen] = useState(false);
const [dialogTitle, setDialogTitle] = useState("");
const [dialogConfirmButtonText, setDialogConfirmButtonText] = useState("");
const [dialogContent, setDialogContent] = useState(emptyChangeCategoryDialog);
const classes = useStyles();
const handleAddClick = () => {
setDialogTitle("Neue Kategorie erstellen");
setDialogConfirmButtonText("Erstellen");
if (dialogContent.id !== "") {
setDialogContent(emptyChangeCategoryDialog);
}
setDialogOpen(true);
}
const handleEditButtonClick = (category: GqlCategory) => {
setDialogTitle("Kategorie bearbeiten");
setDialogConfirmButtonText("Speichern")
if (dialogContent.id !== category.nodeId) {
setDialogContent({
id: category.nodeId,
title: category.title,
details: category.description,
})
}
setDialogOpen(true);
};
const handleDialogContentChange = (content: ChangeCategoryDialogContent) => {
setDialogContent(content)
}
return (
<Paper className={classes.root}>
<Typography component={"h2"} variant="h6" color="primary" gutterBottom>Kategorien</Typography>
{data?.allCategories.nodes.map(category => <AccordionWithEdit
key={category.nodeId}
title={category.title}
description={category.description}/>
key={category.nodeId}
title={category.title}
description={category.description}
onEditButtonClick={() => handleEditButtonClick(category)}
/>
)}
<AddCard/>
<AddCard handleClick={handleAddClick}/>
<ChangeCategoryDialog
title={dialogTitle}
confirmButtonText={dialogConfirmButtonText}
open={dialogOpen}
content={dialogContent}
handleContentChange={handleDialogContentChange}
handleConfirmButtonClick={() => {
console.log("go for category mutation");
setDialogOpen(false);
}}
handleClose={() => setDialogOpen(false)}/>
</Paper>
)
}

View file

@ -0,0 +1,36 @@
import React, {ChangeEvent} from 'react';
import {FormControl, InputLabel, MenuItem, Select} from "@material-ui/core";
import {GqlCategory} from "../backend/queries/allCategories";
interface CategorySelectionMenuProps {
selectedCategoryId?: string
categories?: Array<GqlCategory>,
handleCategoryChange(categoryId: string): void
}
export default function CategorySelectionMenu(props: CategorySelectionMenuProps) {
const onCategoryIdChange = (e: ChangeEvent<{ name?: string, value: unknown }>) => {
const newValue = e.target.value as string;
props.handleCategoryChange(newValue);
}
return (
<FormControl fullWidth variant="outlined">
<InputLabel>Kategorie</InputLabel>
<Select
value={props.selectedCategoryId ? props.selectedCategoryId : ""}
label="Kategorie"
onChange={onCategoryIdChange}
>
<MenuItem value={""}>
<em>None</em>
</MenuItem>
{props.categories?.map(category => <MenuItem key={category.nodeId} value={category.nodeId}>
{category.title}
</MenuItem>)}
</Select>
</FormControl>
);
}

View file

@ -0,0 +1,48 @@
import React from 'react';
import Dialog from '@material-ui/core/Dialog';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import {DialogActionBar} from "./DialogActionBar";
import {DialogTitleAndDetails} from "./DialogTitleAndDetails";
export interface ChangeCategoryDialogContent {
id: string
title: string,
details: string,
}
interface ChangeCategoryDialogProps {
title: string,
confirmButtonText: string,
open: boolean,
content: ChangeCategoryDialogContent,
handleContentChange(content: ChangeCategoryDialogContent): void
handleConfirmButtonClick(): void,
handleClose(): void,
}
export default function ChangeCategoryDialog(props: ChangeCategoryDialogProps) {
return (
<Dialog open={props.open} onClose={props.handleClose} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">{props.title}</DialogTitle>
<DialogContent>
<DialogTitleAndDetails
title={props.content.title}
details={props.content.details}
handleTitleChange={newTitle => props.handleContentChange({...props.content, title: newTitle})}
handleDetailsChange={newDetails => props.handleContentChange({...props.content, details: newDetails})}
/>
</DialogContent>
<DialogActionBar
onCancelButtonClick={props.handleClose}
onConfirmButtonClick={props.handleConfirmButtonClick}
confirmButtonText={props.confirmButtonText}
/>
</Dialog>
);
}

View file

@ -1,13 +1,11 @@
import React, {ChangeEvent} from 'react';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import React from 'react';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import {makeStyles} from "@material-ui/core/styles";
import {FormControl, InputLabel, MenuItem, Select} from "@material-ui/core";
import {GqlCategory} from "../backend/queries/allCategories";
import CategorySelectionMenu from "./CategorySelectionMenu";
import {DialogActionBar} from "./DialogActionBar";
import {DialogTitleAndDetails} from "./DialogTitleAndDetails";
export interface ChangeQuestionDialogContent {
@ -17,111 +15,46 @@ export interface ChangeQuestionDialogContent {
categoryId: string,
}
export const emptyChangeQuestionDialogContent: ChangeQuestionDialogContent = {
id: "",
title: "",
details: "",
categoryId: "",
}
interface ChangeQuestionDialogProps {
title: string,
confirmButtonText: string,
open: boolean,
content: ChangeQuestionDialogContent,
categories?: Array<GqlCategory>,
content?: ChangeQuestionDialogContent,
handleContentChange?(content: ChangeQuestionDialogContent): void
handleContentChange(content: ChangeQuestionDialogContent): void
handleConfirmButtonClick(): void,
handleClose(): void,
}
const useStyles = makeStyles((theme) => ({
textField: {
marginBottom: theme.spacing(2),
},
formControl: {},
}));
export default function ChangeQuestionDialog(props: ChangeQuestionDialogProps) {
const classes = useStyles();
const content = props.content ? props.content : emptyChangeQuestionDialogContent;
const onTitleChange = (e: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
const newValue = e.target.value;
props.handleContentChange?.({
...content,
title: newValue,
});
}
const onDetailsChange = (e: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
const newValue = e.target.value;
props.handleContentChange?.({
...content,
details: newValue,
});
}
const onCategoryIdChange = (e: ChangeEvent<{ name?: string, value: unknown }>) => {
const newValue = e.target.value as string;
props.handleContentChange?.({
...content,
categoryId: newValue,
});
}
return (
<Dialog open={props.open} onClose={props.handleClose} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">{props.title}</DialogTitle>
<DialogContent>
<TextField
className={classes.textField}
id="title"
label="Zusammenfassung"
fullWidth
variant="outlined"
value={content.title}
onChange={onTitleChange}
<DialogTitleAndDetails
title={props.content.title}
details={props.content.details}
handleTitleChange={newTitle => props.handleContentChange({...props.content, title: newTitle})}
handleDetailsChange={newDetails => props.handleContentChange({...props.content, details: newDetails})}
/>
<TextField
className={classes.textField}
multiline
rows={4}
id="description"
label="Details"
fullWidth
variant="outlined"
value={content.details}
onChange={onDetailsChange}
<CategorySelectionMenu
selectedCategoryId={props.content.categoryId}
categories={props.categories}
handleCategoryChange={(categoryId) => props.handleContentChange({
...props.content,
categoryId: categoryId,
})}
/>
<FormControl fullWidth variant="outlined" className={classes.formControl}>
<InputLabel>Kategorie</InputLabel>
<Select
value={content.categoryId}
label="Kategorie"
onChange={onCategoryIdChange}
>
<MenuItem value={undefined}>
<em>None</em>
</MenuItem>
{props.categories?.map(category => <MenuItem key={category.nodeId} value={category.nodeId}>
{category.title}
</MenuItem>)}
</Select>
</FormControl>
</DialogContent>
<DialogActions>
<Button onClick={props.handleClose} color="primary">
Abbrechen
</Button>
<Button onClick={props.handleConfirmButtonClick} color="primary">
{props.confirmButtonText}
</Button>
</DialogActions>
<DialogActionBar
onCancelButtonClick={props.handleClose}
onConfirmButtonClick={props.handleConfirmButtonClick}
confirmButtonText={props.confirmButtonText}
/>
</Dialog>
);
}

View file

@ -0,0 +1,22 @@
import DialogActions from "@material-ui/core/DialogActions";
import Button from "@material-ui/core/Button";
import React from "react";
interface DialogActionBarProps {
confirmButtonText?: string,
onCancelButtonClick?(): void,
onConfirmButtonClick?(): void,
}
export function DialogActionBar(props: DialogActionBarProps) {
return <DialogActions>
<Button onClick={props.onCancelButtonClick} color="primary">
Abbrechen
</Button>
<Button onClick={props.onConfirmButtonClick} color="primary">
{props.confirmButtonText ? props.confirmButtonText : "Ok"}
</Button>
</DialogActions>;
}

View file

@ -0,0 +1,47 @@
import {makeStyles} from "@material-ui/core/styles";
import React from "react";
import TextField from "@material-ui/core/TextField";
const useStyles = makeStyles((theme) => ({
textField: {
marginBottom: theme.spacing(2),
}
}));
interface DialogTitleAndDetailsProps {
title: string,
details: string,
handleTitleChange(newTitle: string): void,
handleDetailsChange(newDetails: string): void,
}
export function DialogTitleAndDetails(props: DialogTitleAndDetailsProps) {
const classes = useStyles();
return (
<React.Fragment>
<TextField
className={classes.textField}
id="title"
label="Zusammenfassung"
fullWidth
variant="outlined"
value={props.title}
onChange={e => props.handleTitleChange(e.target.value)}
/>
<TextField
className={classes.textField}
multiline
rows={4}
id="description"
label="Details"
fullWidth
variant="outlined"
value={props.details}
onChange={e => props.handleDetailsChange(e.target.value)}
/>
</React.Fragment>
)
}

View file

@ -5,10 +5,7 @@ import {useQuery} from "@apollo/client";
import AddCard from "./AddCard";
import AccordionWithEdit from "./AccordionWithEdit";
import {allQuestionsQuery, AllQuestionsQueryResponse, GqlQuestion} from "../backend/queries/allQuestions";
import ChangeQuestionDialog, {
ChangeQuestionDialogContent,
emptyChangeQuestionDialogContent
} from "./ChangeQuestionDialog";
import ChangeQuestionDialog, {ChangeQuestionDialogContent} from "./ChangeQuestionDialog";
import {allCategoriesQuery, AllCategoriesQueryResponse} from "../backend/queries/allCategories";
const useStyles = makeStyles((theme) => ({
@ -19,11 +16,18 @@ const useStyles = makeStyles((theme) => ({
},
}));
const emptyChangeQuestionDialog: ChangeQuestionDialogContent = {
id: "",
title: "",
details: "",
categoryId: "",
}
export default function QuestionList() {
const [dialogOpen, setDialogOpen] = useState(false);
const [dialogTitle, setDialogTitle] = useState("");
const [dialogConfirmButtonText, setDialogConfirmButtonText] = useState("");
const [dialogContent, setDialogContent] = useState(emptyChangeQuestionDialogContent);
const [dialogContent, setDialogContent] = useState(emptyChangeQuestionDialog);
const questions = useQuery<AllQuestionsQueryResponse, null>(allQuestionsQuery).data?.allQuestions.nodes;
const categories = useQuery<AllCategoriesQueryResponse, null>(allCategoriesQuery).data?.allCategories.nodes;
const classes = useStyles();
@ -32,7 +36,7 @@ export default function QuestionList() {
setDialogTitle("Neue Frage erstellen");
setDialogConfirmButtonText("Erstellen");
if (dialogContent.id !== "") {
setDialogContent(emptyChangeQuestionDialogContent);
setDialogContent(emptyChangeQuestionDialog);
}
setDialogOpen(true);
}