BugTitleForm.tsx

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