#11 Refactor queries and mutations

* Use more apollo naming convention
* Take care of possible null/undefined fields in responses
This commit is contained in:
Christoph Lienhard 2020-12-28 21:22:32 +01:00
parent 57c338b7ef
commit b6358c357b
Signed by: christoph.lienhard
GPG key ID: 6B98870DDC270884
18 changed files with 150 additions and 97 deletions

View file

@ -1,10 +1,10 @@
import {MockedResponse} from "@apollo/client/testing";
import {loginMutation, LoginMutationResponse} from "./login";
import {LOGIN, LoginResponse} from "./login";
export const loginMock: Array<MockedResponse<LoginMutationResponse>> = [
export const loginMock: Array<MockedResponse<LoginResponse>> = [
{
request: {
query: loginMutation,
query: LOGIN,
variables: {
email: "test@email.com",
password: "password",
@ -20,7 +20,7 @@ export const loginMock: Array<MockedResponse<LoginMutationResponse>> = [
},
{
request: {
query: loginMutation,
query: LOGIN,
variables: {
email: "test@email.com",
password: "wrong-password",
@ -29,7 +29,7 @@ export const loginMock: Array<MockedResponse<LoginMutationResponse>> = [
result: {
data: {
authenticate: {
jwtToken: null
jwtToken: undefined
}
}
},

View file

@ -1,19 +1,19 @@
import {gql} from "@apollo/client";
export const loginMutation = gql`
export const LOGIN = gql`
mutation Login($email: String!, $password: String!) {
authenticate(input: {email: $email, password: $password}) {
jwtToken
}
}`
export interface LoginMutationVariables {
export interface LoginVariables {
email: string,
password: string
}
export interface LoginMutationResponse {
export interface LoginResponse {
authenticate: {
jwtToken: string | null
jwtToken?: string
}
}

View file

@ -0,0 +1,23 @@
import {MockedResponse} from "@apollo/client/testing";
import {LoginResponse} from "./login";
import {EDIT_QUESTION} from "./question";
export const loginMock: Array<MockedResponse<LoginResponse>> = [
{
request: {
query: EDIT_QUESTION,
variables: {
email: "test@email.com",
password: "password",
}
},
result: {
errors: [
// {
// message: "Authorization header is not of the correct bearer scheme format."
// }
]
},
},
]

View file

@ -0,0 +1,27 @@
import {gql} from "@apollo/client";
import {GetQuestionResponse} from "../queries/question";
export const EDIT_QUESTION = gql`
mutation UpdateQuestion($nodeId: ID!, $text: String, $description: String, $categoryId: Int) {
updateQuestion(input: {nodeId: $nodeId, questionPatch: {categoryId: $categoryId, description: $description, text: $text}}) {
question {
nodeId
text
description
categoryByCategoryId {
nodeId
title
}
}
}
}
`
export interface EditQuestionVariables {
nodeId: string,
text?: string,
description?: string,
categoryId?: number,
}
export interface EditQuestionResponse extends GetQuestionResponse {}

View file

@ -1,6 +1,6 @@
import {gql} from "@apollo/client";
export const registerMutation = gql`
export const SIGN_UP = gql`
mutation CreateAccount($firstName: String!, $lastName: String!, $email: String!, $password: String!) {
registerPerson(input: {firstName: $firstName, lastName: $lastName, email: $email, password: $password}) {
person {
@ -10,14 +10,14 @@ export const registerMutation = gql`
}
`
export interface RegisterMutationVariables {
export interface SignUpVariables {
firstName: string,
lastName: string,
email: string,
password: string,
}
export interface RegisterMutationResponse {
export interface SignUpResponse {
registerPerson: {
person: {
nodeId: string

View file

@ -1,25 +0,0 @@
import {gql} from "@apollo/client";
export const allCategoriesQuery = gql`
query AllQuestions {
allCategories {
nodes {
nodeId
title
description
}
}
}
`
export interface AllCategoriesQueryResponse {
allCategories: {
nodes: Array<GqlCategory>
}
}
export interface GqlCategory {
nodeId: string,
title: string,
description: string,
}

View file

@ -1,35 +0,0 @@
import {gql} from "@apollo/client";
export const allQuestionsQuery = gql`
query AllQuestions {
allQuestions {
nodes {
nodeId
text
description
categoryByCategoryId {
nodeId
title
}
}
}
}
`
export interface AllQuestionsQueryResponse {
allQuestions: {
nodes: Array<GqlQuestion>
}
}
export interface GqlQuestion {
nodeId: string,
text: string,
description: string,
categoryByCategoryId: AllQuestionsCategoryNode
}
interface AllQuestionsCategoryNode {
nodeId: string,
title: string,
}

View file

@ -0,0 +1,27 @@
import {gql} from "@apollo/client";
export const GET_ALL_CATEGORIES = gql`
query AllCategories {
allCategories {
nodes {
nodeId
id
title
description
}
}
}
`
export interface GetAllCategoriesResponse {
allCategories: {
nodes: Array<GetCategoryResponse>
}
}
export interface GetCategoryResponse {
nodeId: string,
id: number,
title: string,
description?: string,
}

View file

@ -0,0 +1,36 @@
import {gql} from "@apollo/client";
export const GET_ALL_QUESTIONS = gql`
query AllQuestions {
allQuestions {
nodes {
nodeId
text
description
categoryByCategoryId {
nodeId
title
}
}
}
}
`
export interface GetAllQuestionsResponse {
allQuestions: {
nodes: Array<GetQuestionResponse>
}
}
export interface GetQuestionResponse {
nodeId: string,
text: string,
description?: string,
categoryByCategoryId?: GetQuestionsCategoryResponse
}
interface GetQuestionsCategoryResponse {
nodeId: string,
id: number,
title: string,
}

View file

@ -34,7 +34,7 @@ const useStyles = makeStyles((theme: Theme) =>
interface QuestionProps {
key: string,
title: string,
description: string,
description?: string,
subTitle?: string,
onEditButtonClick?(): void,
onDeleteButtonClick?(): void,

View file

@ -4,7 +4,7 @@ import {makeStyles} from "@material-ui/core/styles";
import {useQuery} from "@apollo/client";
import AddCard from "./AddCard";
import AccordionWithEdit from "./AccordionWithEdit";
import {allCategoriesQuery, AllCategoriesQueryResponse, GqlCategory} from "../backend/queries/allCategories";
import {GET_ALL_CATEGORIES, GetAllCategoriesResponse, GetCategoryResponse} from "../backend/queries/category";
import ChangeCategoryDialog, {ChangeCategoryDialogContent} from "./ChangeCategoryDialog";
const useStyles = makeStyles((theme) => ({
@ -22,7 +22,7 @@ const emptyChangeCategoryDialog: ChangeCategoryDialogContent = {
}
export default function CategoryList() {
const {data} = useQuery<AllCategoriesQueryResponse, null>(allCategoriesQuery);
const {data} = useQuery<GetAllCategoriesResponse, null>(GET_ALL_CATEGORIES);
const [dialogOpen, setDialogOpen] = useState(false);
const [dialogTitle, setDialogTitle] = useState("");
const [dialogConfirmButtonText, setDialogConfirmButtonText] = useState("");
@ -38,7 +38,7 @@ export default function CategoryList() {
setDialogOpen(true);
}
const handleEditButtonClick = (category: GqlCategory) => {
const handleEditButtonClick = (category: GetCategoryResponse) => {
setDialogTitle("Kategorie bearbeiten");
setDialogConfirmButtonText("Speichern")
if (dialogContent.id !== category.nodeId) {

View file

@ -1,11 +1,11 @@
import React, {ChangeEvent} from 'react';
import {FormControl, InputLabel, MenuItem, Select} from "@material-ui/core";
import {GqlCategory} from "../backend/queries/allCategories";
import {GetCategoryResponse} from "../backend/queries/category";
interface CategorySelectionMenuProps {
selectedCategoryId?: string
categories?: Array<GqlCategory>,
categories?: Array<GetCategoryResponse>,
handleCategoryChange(categoryId: string): void
}

View file

@ -9,7 +9,7 @@ import {DialogTitleAndDetails} from "./DialogTitleAndDetails";
export interface ChangeCategoryDialogContent {
id: string
title: string,
details: string,
details?: string,
}
interface ChangeCategoryDialogProps {

View file

@ -2,7 +2,7 @@ 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 {GqlCategory} from "../backend/queries/allCategories";
import {GetCategoryResponse} from "../backend/queries/category";
import CategorySelectionMenu from "./CategorySelectionMenu";
import {DialogActionBar} from "./DialogActionBar";
import {DialogTitleAndDetails} from "./DialogTitleAndDetails";
@ -11,8 +11,8 @@ import {DialogTitleAndDetails} from "./DialogTitleAndDetails";
export interface ChangeQuestionDialogContent {
id: string
title: string,
details: string,
categoryId: string,
details?: string,
categoryId?: string,
}
interface ChangeQuestionDialogProps {
@ -20,7 +20,7 @@ interface ChangeQuestionDialogProps {
confirmButtonText: string,
open: boolean,
content: ChangeQuestionDialogContent,
categories?: Array<GqlCategory>,
categories?: Array<GetCategoryResponse>,
handleContentChange(content: ChangeQuestionDialogContent): void

View file

@ -10,7 +10,7 @@ const useStyles = makeStyles((theme) => ({
interface DialogTitleAndDetailsProps {
title: string,
details: string,
details?: string,
handleTitleChange(newTitle: string): void,

View file

@ -4,9 +4,9 @@ import {makeStyles} from "@material-ui/core/styles";
import {useQuery} from "@apollo/client";
import AddCard from "./AddCard";
import AccordionWithEdit from "./AccordionWithEdit";
import {allQuestionsQuery, AllQuestionsQueryResponse, GqlQuestion} from "../backend/queries/allQuestions";
import {GET_ALL_QUESTIONS, GetAllQuestionsResponse, GetQuestionResponse} from "../backend/queries/question";
import ChangeQuestionDialog, {ChangeQuestionDialogContent} from "./ChangeQuestionDialog";
import {allCategoriesQuery, AllCategoriesQueryResponse} from "../backend/queries/allCategories";
import {GET_ALL_CATEGORIES, GetAllCategoriesResponse} from "../backend/queries/category";
const useStyles = makeStyles((theme) => ({
root: {
@ -28,8 +28,8 @@ export default function QuestionList() {
const [dialogTitle, setDialogTitle] = useState("");
const [dialogConfirmButtonText, setDialogConfirmButtonText] = useState("");
const [dialogContent, setDialogContent] = useState(emptyChangeQuestionDialog);
const questions = useQuery<AllQuestionsQueryResponse, null>(allQuestionsQuery).data?.allQuestions.nodes;
const categories = useQuery<AllCategoriesQueryResponse, null>(allCategoriesQuery).data?.allCategories.nodes;
const questions = useQuery<GetAllQuestionsResponse, null>(GET_ALL_QUESTIONS).data?.allQuestions.nodes;
const categories = useQuery<GetAllCategoriesResponse, null>(GET_ALL_CATEGORIES).data?.allCategories.nodes;
const classes = useStyles();
const handleAddClick = () => {
@ -41,7 +41,7 @@ export default function QuestionList() {
setDialogOpen(true);
}
const handleEditButtonClick = (question: GqlQuestion) => {
const handleEditButtonClick = (question: GetQuestionResponse) => {
setDialogTitle("Frage bearbeiten");
setDialogConfirmButtonText("Speichern")
if (dialogContent.id !== question.nodeId) {
@ -49,7 +49,7 @@ export default function QuestionList() {
id: question.nodeId,
title: question.text,
details: question.description,
categoryId: question.categoryByCategoryId.nodeId,
categoryId: question.categoryByCategoryId?.nodeId,
})
}
setDialogOpen(true);
@ -66,7 +66,7 @@ export default function QuestionList() {
return <AccordionWithEdit
key={question.nodeId}
title={question.text}
subTitle={question.categoryByCategoryId.title}
subTitle={question.categoryByCategoryId?.title}
description={question.description}
onEditButtonClick={() => handleEditButtonClick(question)}
/>;

View file

@ -15,7 +15,7 @@ import Container from '@material-ui/core/Container';
import {useMutation} from "@apollo/client";
import ButtonWithSpinner from "./ButtonWithSpinner";
import {Copyright} from "./Copyright";
import {loginMutation, LoginMutationResponse, LoginMutationVariables} from "../backend/mutations/login";
import {LOGIN, LoginResponse, LoginVariables} from "../backend/mutations/login";
const useStyles = makeStyles((theme) => ({
paper: {
@ -48,8 +48,8 @@ export default function SignIn() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [login, {loading}] = useMutation<LoginMutationResponse, LoginMutationVariables>(
loginMutation,
const [login, {loading}] = useMutation<LoginResponse, LoginVariables>(
LOGIN,
{
onCompleted(data) {
if (data.authenticate.jwtToken) {

View file

@ -14,7 +14,7 @@ import {useMutation} from "@apollo/client";
import ButtonWithSpinner from "./ButtonWithSpinner";
import {errorHandler, SignUpError} from "./SignUpErrorHandler";
import {Alert} from "@material-ui/lab";
import {registerMutation, RegisterMutationResponse, RegisterMutationVariables} from "../backend/mutations/signUp";
import {SIGN_UP, SignUpResponse, SignUpVariables} from "../backend/mutations/signUp";
const useStyles = makeStyles((theme) => ({
@ -50,8 +50,8 @@ export default function SignUp() {
const [lastName, setLastName] = useState("");
const [error, setError] = useState<SignUpError | undefined>(undefined)
const history = useHistory();
const [createAccount, {loading}] = useMutation<RegisterMutationResponse, RegisterMutationVariables>(
registerMutation,
const [createAccount, {loading}] = useMutation<SignUpResponse, SignUpVariables>(
SIGN_UP,
{
onCompleted() {
history.push("/login?recent-sign-up-success=true")