#11 Refactor: Introduce apollo reactive variables for global state
Use it to streamline entangle the delete dialog(s) from the list(s)
This commit is contained in:
parent
42dc7f285d
commit
fc8bc6724b
87
redaktions-app/package-lock.json
generated
87
redaktions-app/package-lock.json
generated
|
@ -5,20 +5,21 @@
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/client": {
|
"@apollo/client": {
|
||||||
"version": "3.1.3",
|
"version": "3.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.3.6.tgz",
|
||||||
"integrity": "sha512-zXMiaj+dX0sgXIwEV5d/PI6B8SZT2bqlKNjZWcEXRY7NjESF5J3nd4v8KOsrhHe+A3YhNv63tIl35Sq7uf41Pg==",
|
"integrity": "sha512-XSm/STyNS8aHdDigLLACKNMHwI0qaQmEHWHtTP+jHe/E1wZRnn66VZMMgwKLy2V4uHISHfmiZ4KpUKDPeJAKqg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@graphql-typed-document-node/core": "^3.0.0",
|
||||||
"@types/zen-observable": "^0.8.0",
|
"@types/zen-observable": "^0.8.0",
|
||||||
"@wry/context": "^0.5.2",
|
"@wry/context": "^0.5.2",
|
||||||
"@wry/equality": "^0.2.0",
|
"@wry/equality": "^0.3.0",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
"graphql-tag": "^2.11.0",
|
"graphql-tag": "^2.11.0",
|
||||||
"hoist-non-react-statics": "^3.3.2",
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
"optimism": "^0.12.1",
|
"optimism": "^0.13.1",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"symbol-observable": "^1.2.0",
|
"symbol-observable": "^2.0.0",
|
||||||
"ts-invariant": "^0.4.4",
|
"ts-invariant": "^0.6.0",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^1.10.0",
|
||||||
"zen-observable": "^0.8.14"
|
"zen-observable": "^0.8.14"
|
||||||
}
|
}
|
||||||
|
@ -1171,6 +1172,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
|
||||||
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
|
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
|
||||||
},
|
},
|
||||||
|
"@graphql-typed-document-node/core": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg=="
|
||||||
|
},
|
||||||
"@hapi/address": {
|
"@hapi/address": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
|
||||||
|
@ -2066,6 +2072,11 @@
|
||||||
"@types/jest": "*"
|
"@types/jest": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/ungap__global-this": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ungap__global-this/-/ungap__global-this-0.3.1.tgz",
|
||||||
|
"integrity": "sha512-+/DsiV4CxXl6ZWefwHZDXSe1Slitz21tom38qPCaG0DYCS1NnDPIQDTKcmQ/tvK/edJUKkmuIDBJbmKDiB0r/g=="
|
||||||
|
},
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "13.0.10",
|
"version": "13.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.10.tgz",
|
||||||
|
@ -2080,9 +2091,9 @@
|
||||||
"integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw=="
|
"integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw=="
|
||||||
},
|
},
|
||||||
"@types/zen-observable": {
|
"@types/zen-observable": {
|
||||||
"version": "0.8.0",
|
"version": "0.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.2.tgz",
|
||||||
"integrity": "sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg=="
|
"integrity": "sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg=="
|
||||||
},
|
},
|
||||||
"@typescript-eslint/eslint-plugin": {
|
"@typescript-eslint/eslint-plugin": {
|
||||||
"version": "2.34.0",
|
"version": "2.34.0",
|
||||||
|
@ -2138,6 +2149,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@ungap/global-this": {
|
||||||
|
"version": "0.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ungap/global-this/-/global-this-0.4.3.tgz",
|
||||||
|
"integrity": "sha512-MuHEpDBurNVeD6mV9xBcAN2wfTwuaFQhHuhWkJuXmyVJ5P5sBCw+nnFpdfb0tAvgWkfefWCsAoAsh7MTUr3LPg=="
|
||||||
|
},
|
||||||
"@webassemblyjs/ast": {
|
"@webassemblyjs/ast": {
|
||||||
"version": "1.8.5",
|
"version": "1.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
|
||||||
|
@ -2297,19 +2313,33 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@wry/context": {
|
"@wry/context": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@wry/context/-/context-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/@wry/context/-/context-0.5.3.tgz",
|
||||||
"integrity": "sha512-B/JLuRZ/vbEKHRUiGj6xiMojST1kHhu4WcreLfNN7q9DqQFrb97cWgf/kiYsPSUCAMVN0HzfFc8XjJdzgZzfjw==",
|
"integrity": "sha512-n0uKHiWpf2ArHhmcHcUsKA+Dj0gtye/h56VmsDcoMRuK/ZPFeHKi8ck5L/ftqtF12ZbQR9l8xMPV7y+xybaRDA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.14.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@wry/equality": {
|
"@wry/equality": {
|
||||||
"version": "0.2.0",
|
"version": "0.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.3.1.tgz",
|
||||||
"integrity": "sha512-Y4d+WH6hs+KZJUC8YKLYGarjGekBrhslDbf/R20oV+AakHPINSitHfDRQz3EGcEWc1luXYNUvMhawWtZVWNGvQ==",
|
"integrity": "sha512-8/Ftr3jUZ4EXhACfSwPIfNsE8V6WKesdjp+Dxi78Bej6qlasAxiz0/F8j0miACRj9CL4vC5Y5FsfwwEYAuhWbg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.14.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@xtuc/ieee754": {
|
"@xtuc/ieee754": {
|
||||||
|
@ -9607,7 +9637,6 @@
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.3.tgz",
|
||||||
"integrity": "sha512-bRGF/eg2qNQ8BwagPLkHiqrz+W00PYtGY5Xl33I0Of1BTm7arksZO1JxssPTlti0qw127CxuWxm637ipn0eZ9g==",
|
"integrity": "sha512-bRGF/eg2qNQ8BwagPLkHiqrz+W00PYtGY5Xl33I0Of1BTm7arksZO1JxssPTlti0qw127CxuWxm637ipn0eZ9g==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"clsx": "^1.1.0",
|
"clsx": "^1.1.0",
|
||||||
"hoist-non-react-statics": "^3.3.0"
|
"hoist-non-react-statics": "^3.3.0"
|
||||||
|
@ -9909,9 +9938,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optimism": {
|
"optimism": {
|
||||||
"version": "0.12.1",
|
"version": "0.13.2",
|
||||||
"resolved": "https://registry.npmjs.org/optimism/-/optimism-0.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/optimism/-/optimism-0.13.2.tgz",
|
||||||
"integrity": "sha512-t8I7HM1dw0SECitBYAqFOVHoBAHEQBTeKjIL9y9ImHzAVkdyPK4ifTgM4VJRDtTUY4r/u5Eqxs4XcGPHaoPkeQ==",
|
"integrity": "sha512-kJkpDUEs/Rp8HsAYYlDzyvQHlT6YZa95P+2GGNR8p/VvsIkt6NilAk7oeTvMRKCq7BeclB7+bmdIexog2859GQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@wry/context": "^0.5.2"
|
"@wry/context": "^0.5.2"
|
||||||
}
|
}
|
||||||
|
@ -13378,9 +13407,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"symbol-observable": {
|
"symbol-observable": {
|
||||||
"version": "1.2.0",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz",
|
||||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
"integrity": "sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA=="
|
||||||
},
|
},
|
||||||
"symbol-tree": {
|
"symbol-tree": {
|
||||||
"version": "3.2.4",
|
"version": "3.2.4",
|
||||||
|
@ -13704,10 +13733,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ts-invariant": {
|
"ts-invariant": {
|
||||||
"version": "0.4.4",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.6.0.tgz",
|
||||||
"integrity": "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==",
|
"integrity": "sha512-caoafsfgb8QxdrKzFfjKt627m4i8KTtfAiji0DYJfWI4A/S9ORNNpzYuD9br64kyKFgxn9UNaLLbSupam84mCA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@types/ungap__global-this": "^0.3.1",
|
||||||
|
"@ungap/global-this": "^0.4.2",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.1.3",
|
"@apollo/client": "^3.2",
|
||||||
"@material-ui/core": "^4.11.0",
|
"@material-ui/core": "^4.11.0",
|
||||||
"@material-ui/icons": "^4.9.1",
|
"@material-ui/icons": "^4.9.1",
|
||||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||||
|
|
|
@ -19,4 +19,5 @@ const authLink = setContext((_, { headers }) => {
|
||||||
export const client = new ApolloClient({
|
export const client = new ApolloClient({
|
||||||
cache: new InMemoryCache(),
|
cache: new InMemoryCache(),
|
||||||
link: authLink.concat(httpLink),
|
link: authLink.concat(httpLink),
|
||||||
|
connectToDevTools: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Paper, Typography} from "@material-ui/core";
|
import {Paper, Typography} from "@material-ui/core";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {makeStyles} from "@material-ui/core/styles";
|
import {makeStyles} from "@material-ui/core/styles";
|
||||||
import {Reference, useMutation, useQuery} from "@apollo/client";
|
import {useMutation, useQuery} from "@apollo/client";
|
||||||
import AddCard from "./AddCard";
|
import AddCard from "./AddCard";
|
||||||
import AccordionWithEdit from "./AccordionWithEdit";
|
import AccordionWithEdit from "./AccordionWithEdit";
|
||||||
import {
|
import {
|
||||||
|
@ -12,18 +12,19 @@ import {
|
||||||
} from "../backend/queries/category";
|
} from "../backend/queries/category";
|
||||||
import ChangeCategoryDialog, {ChangeCategoryDialogContent} from "./ChangeCategoryDialog";
|
import ChangeCategoryDialog, {ChangeCategoryDialogContent} from "./ChangeCategoryDialog";
|
||||||
import {useSnackbar} from "notistack";
|
import {useSnackbar} from "notistack";
|
||||||
import DeleteConfirmationDialog, {DeleteConfirmationDialogContent} from "./DeleteConfirmationDialog";
|
|
||||||
import {
|
import {
|
||||||
ADD_CATEGORY,
|
ADD_CATEGORY,
|
||||||
AddCategoryResponse,
|
AddCategoryResponse,
|
||||||
AddCategoryVariables,
|
AddCategoryVariables,
|
||||||
DELETE_CATEGORY,
|
|
||||||
DeleteCategoryResponse,
|
|
||||||
DeleteCategoryVariables,
|
|
||||||
EDIT_CATEGORY,
|
EDIT_CATEGORY,
|
||||||
EditCategoryResponse,
|
EditCategoryResponse,
|
||||||
EditCategoryVariables
|
EditCategoryVariables
|
||||||
} from "../backend/mutations/category";
|
} from "../backend/mutations/category";
|
||||||
|
import DeleteCategoryDialog, {
|
||||||
|
deleteCategoryDialogId,
|
||||||
|
deleteCategoryDialogOpen,
|
||||||
|
deleteCategoryDialogTitle
|
||||||
|
} from "./DeleteCategoryDialog";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
|
@ -39,19 +40,11 @@ const emptyChangeCategoryDialog: ChangeCategoryDialogContent = {
|
||||||
details: "",
|
details: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyDeleteConfirmationDialogContent: DeleteConfirmationDialogContent = {
|
|
||||||
id: "",
|
|
||||||
type: "Kategorie",
|
|
||||||
title: "",
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function CategoryList() {
|
export default function CategoryList() {
|
||||||
const [changeDialogOpen, setChangeDialogOpen] = useState(false);
|
const [changeDialogOpen, setChangeDialogOpen] = useState(false);
|
||||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
||||||
const [dialogTitle, setDialogTitle] = useState("");
|
const [dialogTitle, setDialogTitle] = useState("");
|
||||||
const [dialogConfirmButtonText, setDialogConfirmButtonText] = useState("");
|
const [dialogConfirmButtonText, setDialogConfirmButtonText] = useState("");
|
||||||
const [changeDialogContent, setChangeDialogContent] = useState(emptyChangeCategoryDialog);
|
const [changeDialogContent, setChangeDialogContent] = useState(emptyChangeCategoryDialog);
|
||||||
const [deleteDialogContent, setDeleteDialogContent] = useState(emptyDeleteConfirmationDialogContent);
|
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
const categories = useQuery<GetAllCategoriesResponse, null>(GET_ALL_CATEGORIES).data?.allCategories.nodes;
|
const categories = useQuery<GetAllCategoriesResponse, null>(GET_ALL_CATEGORIES).data?.allCategories.nodes;
|
||||||
const [editCategory, {loading: editLoading}] = useMutation<EditCategoryResponse, EditCategoryVariables>(EDIT_CATEGORY, {
|
const [editCategory, {loading: editLoading}] = useMutation<EditCategoryResponse, EditCategoryVariables>(EDIT_CATEGORY, {
|
||||||
|
@ -90,28 +83,7 @@ export default function CategoryList() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const [deleteCategory, {loading: deleteLoading}] = useMutation<DeleteCategoryResponse, DeleteCategoryVariables>(DELETE_CATEGORY, {
|
|
||||||
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, { variant: "error"}),
|
|
||||||
onCompleted: (response) => {
|
|
||||||
if (response.deleteCategory) {
|
|
||||||
enqueueSnackbar("Kategorie erfolgreich gelöscht.", { variant: "success"})
|
|
||||||
setDeleteDialogOpen(false);
|
|
||||||
} else {
|
|
||||||
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", { variant: "error"})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
update: (cache, { data }) => {
|
|
||||||
const idToRemove = data?.deleteCategory?.category.id;
|
|
||||||
cache.modify({
|
|
||||||
fields: {
|
|
||||||
allCategories(existingCategoriesRef: { nodes: Array<Reference>} = { nodes: []}, {readField}) {
|
|
||||||
console.log("existingCategory: ", existingCategoriesRef)
|
|
||||||
return {nodes: existingCategoriesRef.nodes.filter(categoryRef => readField('id', categoryRef) !== idToRemove)};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const loading = editLoading || addLoading;
|
const loading = editLoading || addLoading;
|
||||||
|
@ -139,12 +111,9 @@ export default function CategoryList() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteButtonClick = (category: BasicCategoryResponse) => {
|
const handleDeleteButtonClick = (category: BasicCategoryResponse) => {
|
||||||
setDeleteDialogContent({
|
deleteCategoryDialogTitle(category.title);
|
||||||
...deleteDialogContent,
|
deleteCategoryDialogId(category.id);
|
||||||
id: category.id,
|
deleteCategoryDialogOpen(true);
|
||||||
title: category.title,
|
|
||||||
});
|
|
||||||
setDeleteDialogOpen(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDialogContentChange = (content: ChangeCategoryDialogContent) => {
|
const handleDialogContentChange = (content: ChangeCategoryDialogContent) => {
|
||||||
|
@ -170,14 +139,6 @@ export default function CategoryList() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteConfirmButtonClick = () => {
|
|
||||||
deleteCategory({
|
|
||||||
variables: {
|
|
||||||
id: deleteDialogContent.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper className={classes.root}>
|
<Paper className={classes.root}>
|
||||||
<Typography component={"h2"} variant="h6" color="primary" gutterBottom>Kategorien</Typography>
|
<Typography component={"h2"} variant="h6" color="primary" gutterBottom>Kategorien</Typography>
|
||||||
|
@ -200,13 +161,7 @@ export default function CategoryList() {
|
||||||
handleConfirmButtonClick={handleChangeConfirmButtonClick}
|
handleConfirmButtonClick={handleChangeConfirmButtonClick}
|
||||||
handleClose={() => setChangeDialogOpen(false)}
|
handleClose={() => setChangeDialogOpen(false)}
|
||||||
/>
|
/>
|
||||||
<DeleteConfirmationDialog
|
<DeleteCategoryDialog/>
|
||||||
content={deleteDialogContent}
|
|
||||||
open={deleteDialogOpen}
|
|
||||||
loading={deleteLoading}
|
|
||||||
handleConfirmButtonClick={handleDeleteConfirmButtonClick}
|
|
||||||
handleClose={() => setDeleteDialogOpen(false)}
|
|
||||||
/>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
60
redaktions-app/src/components/DeleteCategoryDialog.tsx
Normal file
60
redaktions-app/src/components/DeleteCategoryDialog.tsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {makeVar, Reference, useMutation, useReactiveVar} from "@apollo/client";
|
||||||
|
import DeleteConfirmationDialog from "./DeleteConfirmationDialog";
|
||||||
|
import {useSnackbar} from "notistack";
|
||||||
|
import {DELETE_CATEGORY, DeleteCategoryResponse, DeleteCategoryVariables} from "../backend/mutations/category";
|
||||||
|
|
||||||
|
|
||||||
|
export const deleteCategoryDialogId = makeVar<string>("");
|
||||||
|
export const deleteCategoryDialogTitle = makeVar<string>("");
|
||||||
|
export const deleteCategoryDialogOpen = makeVar<boolean>(false);
|
||||||
|
|
||||||
|
export default function DeleteCategoryDialog() {
|
||||||
|
const {enqueueSnackbar} = useSnackbar();
|
||||||
|
const [deleteCategory, {loading}] = useMutation<DeleteCategoryResponse, DeleteCategoryVariables>(DELETE_CATEGORY, {
|
||||||
|
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, {variant: "error"}),
|
||||||
|
onCompleted: (response) => {
|
||||||
|
if (response.deleteCategory) {
|
||||||
|
enqueueSnackbar("Kategorie erfolgreich gelöscht.", {variant: "success"})
|
||||||
|
deleteCategoryDialogOpen(false);
|
||||||
|
} else {
|
||||||
|
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", {variant: "error"})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: (cache, {data}) => {
|
||||||
|
const idToRemove = data?.deleteCategory?.category.id;
|
||||||
|
cache.modify({
|
||||||
|
fields: {
|
||||||
|
allCategories(existingCategoriesRef: { nodes: Array<Reference> } = {nodes: []}, {readField}) {
|
||||||
|
console.log("existingCategory: ", existingCategoriesRef)
|
||||||
|
return {nodes: existingCategoriesRef.nodes.filter(categoryRef => readField('id', categoryRef) !== idToRemove)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const open = useReactiveVar(deleteCategoryDialogOpen);
|
||||||
|
const title = useReactiveVar(deleteCategoryDialogTitle);
|
||||||
|
const id = useReactiveVar(deleteCategoryDialogId);
|
||||||
|
|
||||||
|
const handleConfirmButtonClick = () => {
|
||||||
|
deleteCategory({
|
||||||
|
variables: {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DeleteConfirmationDialog
|
||||||
|
open={open}
|
||||||
|
type={"Kategorie"}
|
||||||
|
title={title}
|
||||||
|
onConfirmButtonClick={handleConfirmButtonClick}
|
||||||
|
onClose={() => deleteCategoryDialogOpen(false)}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -6,43 +6,38 @@ import {Button, DialogActions, DialogContentText} from "@material-ui/core";
|
||||||
import ButtonWithSpinner from "./ButtonWithSpinner";
|
import ButtonWithSpinner from "./ButtonWithSpinner";
|
||||||
|
|
||||||
|
|
||||||
export interface DeleteConfirmationDialogContent {
|
interface DeleteConfirmationDialogProps {
|
||||||
id: string,
|
open: boolean,
|
||||||
type: string,
|
type: string,
|
||||||
title: string,
|
title: string,
|
||||||
}
|
|
||||||
|
|
||||||
interface DeleteConfirmationDialogProps {
|
|
||||||
content: DeleteConfirmationDialogContent,
|
|
||||||
open: boolean,
|
|
||||||
loading?: boolean,
|
loading?: boolean,
|
||||||
|
|
||||||
handleConfirmButtonClick(): void,
|
onConfirmButtonClick(): void,
|
||||||
|
|
||||||
handleClose(): void,
|
onClose(): void,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DeleteConfirmationDialog(props: DeleteConfirmationDialogProps) {
|
export default function DeleteConfirmationDialog(props: DeleteConfirmationDialogProps) {
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={props.open}
|
open={props.open}
|
||||||
onClose={props.handleClose}
|
onClose={props.onClose}
|
||||||
aria-labelledby="alert-dialog-title"
|
aria-labelledby="alert-dialog-title"
|
||||||
aria-describedby="alert-dialog-description"
|
aria-describedby="alert-dialog-description"
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">{props.content.type} löschen?</DialogTitle>
|
<DialogTitle id="alert-dialog-title">{props.type} löschen?</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText id="alert-dialog-description">
|
<DialogContentText id="alert-dialog-description">
|
||||||
Möchten Sie die {props.content.type}
|
Möchten Sie die {props.type}
|
||||||
"{props.content.title}"
|
"{props.title}"
|
||||||
wirklich löschen?
|
wirklich löschen?
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={props.handleClose} color="primary">
|
<Button onClick={props.onClose} color="primary">
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</Button>
|
</Button>
|
||||||
<ButtonWithSpinner onClick={props.handleConfirmButtonClick} autoFocus loading={props.loading}>
|
<ButtonWithSpinner onClick={props.onConfirmButtonClick} autoFocus loading={props.loading}>
|
||||||
Löschen
|
Löschen
|
||||||
</ButtonWithSpinner>
|
</ButtonWithSpinner>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
|
59
redaktions-app/src/components/DeleteQuestionDialog.tsx
Normal file
59
redaktions-app/src/components/DeleteQuestionDialog.tsx
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {makeVar, Reference, useMutation, useReactiveVar} from "@apollo/client";
|
||||||
|
import DeleteConfirmationDialog from "./DeleteConfirmationDialog";
|
||||||
|
import {DELETE_QUESTION, DeleteQuestionResponse, DeleteQuestionVariables} from "../backend/mutations/question";
|
||||||
|
import {useSnackbar} from "notistack";
|
||||||
|
|
||||||
|
|
||||||
|
export const deleteQuestionDialogId = makeVar<string>("");
|
||||||
|
export const deleteQuestionDialogTitle = makeVar<string>("");
|
||||||
|
export const deleteQuestionDialogOpen = makeVar<boolean>(false);
|
||||||
|
|
||||||
|
export default function DeleteQuestionDialog() {
|
||||||
|
const {enqueueSnackbar} = useSnackbar();
|
||||||
|
const [deleteQuestion, {loading}] = useMutation<DeleteQuestionResponse, DeleteQuestionVariables>(DELETE_QUESTION, {
|
||||||
|
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, {variant: "error"}),
|
||||||
|
onCompleted: (response) => {
|
||||||
|
if (response.deleteQuestion) {
|
||||||
|
enqueueSnackbar("Frage erfolgreich gelöscht.", {variant: "success"})
|
||||||
|
deleteQuestionDialogOpen(false);
|
||||||
|
} else {
|
||||||
|
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", {variant: "error"})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: (cache, {data}) => {
|
||||||
|
const idToRemove = data?.deleteQuestion?.question.id;
|
||||||
|
cache.modify({
|
||||||
|
fields: {
|
||||||
|
allQuestions(existingQuestionsRef: { nodes: Array<Reference> } = {nodes: []}, {readField}) {
|
||||||
|
return {nodes: existingQuestionsRef.nodes.filter(questionRef => readField('id', questionRef) !== idToRemove)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const open = useReactiveVar(deleteQuestionDialogOpen);
|
||||||
|
const title = useReactiveVar(deleteQuestionDialogTitle);
|
||||||
|
const id = useReactiveVar(deleteQuestionDialogId);
|
||||||
|
|
||||||
|
const handleConfirmButtonClick = () => {
|
||||||
|
deleteQuestion({
|
||||||
|
variables: {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DeleteConfirmationDialog
|
||||||
|
open={open}
|
||||||
|
type={"Frage"}
|
||||||
|
title={title}
|
||||||
|
onConfirmButtonClick={handleConfirmButtonClick}
|
||||||
|
onClose={() => deleteQuestionDialogOpen(false)}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Paper, Typography} from "@material-ui/core";
|
import {Paper, Typography} from "@material-ui/core";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {makeStyles} from "@material-ui/core/styles";
|
import {makeStyles} from "@material-ui/core/styles";
|
||||||
import {Reference, useMutation, useQuery} from "@apollo/client";
|
import {useMutation, useQuery} from "@apollo/client";
|
||||||
import AddCard from "./AddCard";
|
import AddCard from "./AddCard";
|
||||||
import AccordionWithEdit from "./AccordionWithEdit";
|
import AccordionWithEdit from "./AccordionWithEdit";
|
||||||
import {
|
import {
|
||||||
|
@ -16,15 +16,12 @@ import {
|
||||||
ADD_QUESTION,
|
ADD_QUESTION,
|
||||||
AddQuestionResponse,
|
AddQuestionResponse,
|
||||||
AddQuestionVariables,
|
AddQuestionVariables,
|
||||||
DELETE_QUESTION,
|
|
||||||
DeleteQuestionResponse,
|
|
||||||
DeleteQuestionVariables,
|
|
||||||
EDIT_QUESTION,
|
EDIT_QUESTION,
|
||||||
EditQuestionResponse,
|
EditQuestionResponse,
|
||||||
EditQuestionVariables
|
EditQuestionVariables
|
||||||
} from "../backend/mutations/question";
|
} from "../backend/mutations/question";
|
||||||
import {useSnackbar} from 'notistack';
|
import {useSnackbar} from 'notistack';
|
||||||
import DeleteConfirmationDialog, {DeleteConfirmationDialogContent} from "./DeleteConfirmationDialog";
|
import DeleteQuestionDialog, {deleteQuestionDialogId, deleteQuestionDialogOpen, deleteQuestionDialogTitle} from "./DeleteQuestionDialog";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
|
@ -41,47 +38,39 @@ const emptyChangeQuestionDialog: ChangeQuestionDialogContent = {
|
||||||
categoryId: null,
|
categoryId: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyDeleteConfirmationDialogContent: DeleteConfirmationDialogContent = {
|
|
||||||
id: "",
|
|
||||||
type: "Frage",
|
|
||||||
title: "",
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function QuestionList() {
|
export default function QuestionList() {
|
||||||
const [changeDialogOpen, setChangeDialogOpen] = useState(false);
|
const [changeDialogOpen, setChangeDialogOpen] = useState(false);
|
||||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
||||||
const [dialogTitle, setDialogTitle] = useState("");
|
const [dialogTitle, setDialogTitle] = useState("");
|
||||||
const [dialogConfirmButtonText, setDialogConfirmButtonText] = useState("");
|
const [dialogConfirmButtonText, setDialogConfirmButtonText] = useState("");
|
||||||
const [changeDialogContent, setChangeDialogContent] = useState(emptyChangeQuestionDialog);
|
const [changeDialogContent, setChangeDialogContent] = useState(emptyChangeQuestionDialog);
|
||||||
const [deleteDialogContent, setDeleteDialogContent] = useState(emptyDeleteConfirmationDialogContent);
|
const {enqueueSnackbar} = useSnackbar();
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
|
||||||
const questions = useQuery<GetAllQuestionsResponse, null>(GET_ALL_QUESTIONS).data?.allQuestions.nodes;
|
const questions = useQuery<GetAllQuestionsResponse, null>(GET_ALL_QUESTIONS).data?.allQuestions.nodes;
|
||||||
const categories = useQuery<GetAllCategoriesResponse, null>(GET_ALL_CATEGORIES).data?.allCategories.nodes;
|
const categories = useQuery<GetAllCategoriesResponse, null>(GET_ALL_CATEGORIES).data?.allCategories.nodes;
|
||||||
const [editQuestion, {loading: editLoading}] = useMutation<EditQuestionResponse, EditQuestionVariables>(EDIT_QUESTION, {
|
const [editQuestion, {loading: editLoading}] = useMutation<EditQuestionResponse, EditQuestionVariables>(EDIT_QUESTION, {
|
||||||
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, { variant: "error"}),
|
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, {variant: "error"}),
|
||||||
onCompleted: (response) => {
|
|
||||||
if (response.updateQuestion) {
|
|
||||||
enqueueSnackbar("Frage erfolgreich geändert.", { variant: "success"})
|
|
||||||
setChangeDialogOpen(false);
|
|
||||||
} else {
|
|
||||||
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", { variant: "error"})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const [addQuestion, {loading: addLoading}] = useMutation<AddQuestionResponse, AddQuestionVariables>(ADD_QUESTION, {
|
|
||||||
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, { variant: "error"}),
|
|
||||||
onCompleted: (response) => {
|
onCompleted: (response) => {
|
||||||
if (response.createQuestion) {
|
if (response.updateQuestion) {
|
||||||
enqueueSnackbar("Frage erfolgreich hinzugefügt.", { variant: "success"})
|
enqueueSnackbar("Frage erfolgreich geändert.", {variant: "success"})
|
||||||
setChangeDialogOpen(false);
|
setChangeDialogOpen(false);
|
||||||
} else {
|
} else {
|
||||||
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", { variant: "error"})
|
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", {variant: "error"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const [addQuestion, {loading: addLoading}] = useMutation<AddQuestionResponse, AddQuestionVariables>(ADD_QUESTION, {
|
||||||
|
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, {variant: "error"}),
|
||||||
|
onCompleted: (response) => {
|
||||||
|
if (response.createQuestion) {
|
||||||
|
enqueueSnackbar("Frage erfolgreich hinzugefügt.", {variant: "success"})
|
||||||
|
setChangeDialogOpen(false);
|
||||||
|
} else {
|
||||||
|
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", {variant: "error"})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update: (cache, { data }) => {
|
update: (cache, {data}) => {
|
||||||
cache.modify({
|
cache.modify({
|
||||||
fields: {
|
fields: {
|
||||||
allQuestions(existingQuestions = { nodes: []}) {
|
allQuestions(existingQuestions = {nodes: []}) {
|
||||||
const newQuestionRef = cache.writeFragment<BasicQuestionResponse | undefined>({
|
const newQuestionRef = cache.writeFragment<BasicQuestionResponse | undefined>({
|
||||||
data: data?.createQuestion?.question,
|
data: data?.createQuestion?.question,
|
||||||
fragment: BasicQuestionFragment,
|
fragment: BasicQuestionFragment,
|
||||||
|
@ -93,27 +82,6 @@ export default function QuestionList() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const [deleteQuestion, {loading: deleteLoading}] = useMutation<DeleteQuestionResponse, DeleteQuestionVariables>(DELETE_QUESTION, {
|
|
||||||
onError: (e) => enqueueSnackbar(`Ein Fehler ist aufgetreten: ${e.message}`, { variant: "error"}),
|
|
||||||
onCompleted: (response) => {
|
|
||||||
if (response.deleteQuestion) {
|
|
||||||
enqueueSnackbar("Frage erfolgreich gelöscht.", { variant: "success"})
|
|
||||||
setDeleteDialogOpen(false);
|
|
||||||
} else {
|
|
||||||
enqueueSnackbar("Ein Fehler ist aufgetreten, versuche es erneut.", { variant: "error"})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
update: (cache, { data }) => {
|
|
||||||
const idToRemove = data?.deleteQuestion?.question.id;
|
|
||||||
cache.modify({
|
|
||||||
fields: {
|
|
||||||
allQuestions(existingQuestionsRef: { nodes: Array<Reference>} = { nodes: []}, {readField}) {
|
|
||||||
return {nodes: existingQuestionsRef.nodes.filter(questionRef => readField('id', questionRef) !== idToRemove)};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const loading = editLoading || addLoading;
|
const loading = editLoading || addLoading;
|
||||||
|
@ -142,12 +110,9 @@ export default function QuestionList() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteButtonClick = (question: BasicQuestionResponse) => {
|
const handleDeleteButtonClick = (question: BasicQuestionResponse) => {
|
||||||
setDeleteDialogContent({
|
deleteQuestionDialogTitle(question.title);
|
||||||
...deleteDialogContent,
|
deleteQuestionDialogId(question.id);
|
||||||
id: question.id,
|
deleteQuestionDialogOpen(true);
|
||||||
title: question.title,
|
|
||||||
});
|
|
||||||
setDeleteDialogOpen(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDialogContentChange = (content: ChangeQuestionDialogContent) => {
|
const handleDialogContentChange = (content: ChangeQuestionDialogContent) => {
|
||||||
|
@ -175,25 +140,17 @@ export default function QuestionList() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteConfirmButtonClick = () => {
|
|
||||||
deleteQuestion({
|
|
||||||
variables: {
|
|
||||||
id: deleteDialogContent.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper className={classes.root}>
|
<Paper className={classes.root}>
|
||||||
<Typography component={"h2"} variant="h6" color="primary" gutterBottom>Fragen</Typography>
|
<Typography component={"h2"} variant="h6" color="primary" gutterBottom>Fragen</Typography>
|
||||||
{questions?.map(question => <AccordionWithEdit
|
{questions?.map(question => <AccordionWithEdit
|
||||||
key={question.id}
|
key={question.id}
|
||||||
title={question.title}
|
title={question.title}
|
||||||
subTitle={question.categoryByCategoryRowId?.title}
|
subTitle={question.categoryByCategoryRowId?.title}
|
||||||
description={question.description}
|
description={question.description}
|
||||||
onEditButtonClick={() => handleEditButtonClick(question)}
|
onEditButtonClick={() => handleEditButtonClick(question)}
|
||||||
onDeleteButtonClick={() => handleDeleteButtonClick(question)}
|
onDeleteButtonClick={() => handleDeleteButtonClick(question)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<AddCard handleClick={handleAddClick}/>
|
<AddCard handleClick={handleAddClick}/>
|
||||||
<ChangeQuestionDialog
|
<ChangeQuestionDialog
|
||||||
|
@ -207,13 +164,7 @@ export default function QuestionList() {
|
||||||
handleConfirmButtonClick={handleChangeConfirmButtonClick}
|
handleConfirmButtonClick={handleChangeConfirmButtonClick}
|
||||||
handleClose={() => setChangeDialogOpen(false)}
|
handleClose={() => setChangeDialogOpen(false)}
|
||||||
/>
|
/>
|
||||||
<DeleteConfirmationDialog
|
<DeleteQuestionDialog/>
|
||||||
content={deleteDialogContent}
|
|
||||||
open={deleteDialogOpen}
|
|
||||||
loading={deleteLoading}
|
|
||||||
handleConfirmButtonClick={handleDeleteConfirmButtonClick}
|
|
||||||
handleClose={() => setDeleteDialogOpen(false)}
|
|
||||||
/>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue