#11 Add ChangeCategoryDialog w/o logic
For this the ChangeQuestionDialog was refactored to reuse several sub-components
This commit is contained in:
parent
ea21617cf8
commit
57c338b7ef
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
36
redaktions-app/src/components/CategorySelectionMenu.tsx
Normal file
36
redaktions-app/src/components/CategorySelectionMenu.tsx
Normal 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>
|
||||
);
|
||||
}
|
48
redaktions-app/src/components/ChangeCategoryDialog.tsx
Normal file
48
redaktions-app/src/components/ChangeCategoryDialog.tsx
Normal 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>
|
||||
);
|
||||
}
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
22
redaktions-app/src/components/DialogActionBar.tsx
Normal file
22
redaktions-app/src/components/DialogActionBar.tsx
Normal 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>;
|
||||
}
|
47
redaktions-app/src/components/DialogTitleAndDetails.tsx
Normal file
47
redaktions-app/src/components/DialogTitleAndDetails.tsx
Normal 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>
|
||||
)
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue