BugTitleForm.tsx

  1import React, { useState } from 'react';
  2import { Link } from 'react-router-dom';
  3
  4import { Button, makeStyles, Typography } from '@material-ui/core';
  5
  6import { TimelineDocument } from '../../pages/bug/TimelineQuery.generated';
  7import IfLoggedIn from '../IfLoggedIn/IfLoggedIn';
  8import Author from 'src/components/Author';
  9import Date from 'src/components/Date';
 10import { BugFragment } from 'src/pages/bug/Bug.generated';
 11
 12import BugTitleInput from './BugTitleInput';
 13import { useSetTitleMutation } from './SetTitle.generated';
 14
 15/**
 16 * Css in JS styles
 17 */
 18const useStyles = makeStyles((theme) => ({
 19  header: {
 20    display: 'flex',
 21    flexDirection: 'column',
 22  },
 23  headerTitle: {
 24    display: 'flex',
 25    flexDirection: 'row',
 26    justifyContent: 'space-between',
 27  },
 28  readOnlyTitle: {
 29    ...theme.typography.h5,
 30  },
 31  readOnlyId: {
 32    ...theme.typography.subtitle1,
 33    marginLeft: theme.spacing(1),
 34  },
 35  editButtonContainer: {
 36    display: 'flex',
 37    flexDirection: 'row',
 38    justifyContent: 'flex-start',
 39    alignItems: 'center',
 40    minWidth: 200,
 41    marginLeft: theme.spacing(2),
 42  },
 43  greenButton: {
 44    marginLeft: theme.spacing(1),
 45    backgroundColor: theme.palette.success.main,
 46    color: theme.palette.success.contrastText,
 47    '&:hover': {
 48      backgroundColor: theme.palette.success.dark,
 49      color: theme.palette.primary.contrastText,
 50    },
 51  },
 52  saveButton: {
 53    marginRight: theme.spacing(1),
 54  },
 55}));
 56
 57interface Props {
 58  bug: BugFragment;
 59}
 60
 61/**
 62 * Component for bug title change
 63 * @param bug Selected bug in list page
 64 */
 65function BugTitleForm({ bug }: Props) {
 66  const [bugTitleEdition, setbugTitleEdition] = useState(false);
 67  const [setTitle, { loading, error }] = useSetTitleMutation();
 68  const [issueTitle, setIssueTitle] = useState(bug.title);
 69  const classes = useStyles();
 70  let issueTitleInput: any;
 71
 72  function isFormValid() {
 73    if (issueTitleInput) {
 74      return issueTitleInput.value.length > 0;
 75    } else {
 76      return false;
 77    }
 78  }
 79
 80  function submitNewTitle() {
 81    if (!isFormValid()) return;
 82    setTitle({
 83      variables: {
 84        input: {
 85          prefix: bug.humanId,
 86          title: issueTitleInput.value,
 87        },
 88      },
 89      refetchQueries: [
 90        // TODO: update the cache instead of refetching
 91        {
 92          query: TimelineDocument,
 93          variables: {
 94            id: bug.id,
 95            first: 100,
 96          },
 97        },
 98      ],
 99      awaitRefetchQueries: true,
100    }).then(() => setbugTitleEdition(false));
101  }
102
103  function cancelChange() {
104    setIssueTitle(bug.title);
105    setbugTitleEdition(false);
106  }
107
108  function editableBugTitle() {
109    return (
110      <form className={classes.headerTitle} onSubmit={submitNewTitle}>
111        <BugTitleInput
112          inputRef={(node) => {
113            issueTitleInput = node;
114          }}
115          label="Title"
116          variant="outlined"
117          fullWidth
118          margin="dense"
119          value={issueTitle}
120          onChange={(event: any) => setIssueTitle(event.target.value)}
121        />
122        <div className={classes.editButtonContainer}>
123          <Button
124            className={classes.saveButton}
125            size="small"
126            variant="contained"
127            type="submit"
128            disabled={issueTitle.length === 0}
129          >
130            Save
131          </Button>
132          <Button size="small" onClick={() => cancelChange()}>
133            Cancel
134          </Button>
135        </div>
136      </form>
137    );
138  }
139
140  function readonlyBugTitle() {
141    return (
142      <div className={classes.headerTitle}>
143        <div>
144          <span className={classes.readOnlyTitle}>{bug.title}</span>
145          <span className={classes.readOnlyId}>{bug.humanId}</span>
146        </div>
147        <IfLoggedIn>
148          {() => (
149            <div className={classes.editButtonContainer}>
150              <Button
151                size="small"
152                variant="contained"
153                onClick={() => setbugTitleEdition(!bugTitleEdition)}
154              >
155                Edit
156              </Button>
157              <Button
158                className={classes.greenButton}
159                size="small"
160                variant="contained"
161                component={Link}
162                to="/new"
163              >
164                New bug
165              </Button>
166            </div>
167          )}
168        </IfLoggedIn>
169      </div>
170    );
171  }
172
173  if (loading) return <div>Loading...</div>;
174  if (error) return <div>Error</div>;
175
176  return (
177    <div className={classes.header}>
178      {bugTitleEdition ? editableBugTitle() : readonlyBugTitle()}
179      <div className="classes.headerSubtitle">
180        <Typography color={'textSecondary'}>
181          <Author author={bug.author} />
182          {' opened this bug '}
183          <Date date={bug.createdAt} />
184        </Typography>
185      </div>
186    </div>
187  );
188}
189
190export default BugTitleForm;