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    if (bug.title === issueTitleInput.value) {
 83      cancelChange();
 84      return;
 85    }
 86    setTitle({
 87      variables: {
 88        input: {
 89          prefix: bug.humanId,
 90          title: issueTitleInput.value,
 91        },
 92      },
 93      refetchQueries: [
 94        // TODO: update the cache instead of refetching
 95        {
 96          query: TimelineDocument,
 97          variables: {
 98            id: bug.id,
 99            first: 100,
100          },
101        },
102      ],
103      awaitRefetchQueries: true,
104    }).then(() => setbugTitleEdition(false));
105  }
106
107  function cancelChange() {
108    setIssueTitle(bug.title);
109    setbugTitleEdition(false);
110  }
111
112  function editableBugTitle() {
113    return (
114      <form className={classes.headerTitle}>
115        <BugTitleInput
116          inputRef={(node) => {
117            issueTitleInput = node;
118          }}
119          label="Title"
120          variant="outlined"
121          fullWidth
122          margin="dense"
123          value={issueTitle}
124          onChange={(event: any) => setIssueTitle(event.target.value)}
125        />
126        <div className={classes.editButtonContainer}>
127          <Button
128            className={classes.saveButton}
129            size="small"
130            variant="contained"
131            onClick={() => submitNewTitle()}
132            disabled={issueTitle.length === 0}
133          >
134            Save
135          </Button>
136          <Button size="small" onClick={() => cancelChange()}>
137            Cancel
138          </Button>
139        </div>
140      </form>
141    );
142  }
143
144  function readonlyBugTitle() {
145    return (
146      <div className={classes.headerTitle}>
147        <div>
148          <span className={classes.readOnlyTitle}>{bug.title}</span>
149          <span className={classes.readOnlyId}>{bug.humanId}</span>
150        </div>
151        <IfLoggedIn>
152          {() => (
153            <div className={classes.editButtonContainer}>
154              <Button
155                size="small"
156                variant="contained"
157                onClick={() => setbugTitleEdition(!bugTitleEdition)}
158              >
159                Edit
160              </Button>
161              <Button
162                className={classes.greenButton}
163                size="small"
164                variant="contained"
165                component={Link}
166                to="/new"
167              >
168                New bug
169              </Button>
170            </div>
171          )}
172        </IfLoggedIn>
173      </div>
174    );
175  }
176
177  if (loading) return <div>Loading...</div>;
178  if (error) return <div>Error</div>;
179
180  return (
181    <div className={classes.header}>
182      {bugTitleEdition ? editableBugTitle() : readonlyBugTitle()}
183      <div className="classes.headerSubtitle">
184        <Typography color={'textSecondary'}>
185          <Author author={bug.author} />
186          {' opened this bug '}
187          <Date date={bug.createdAt} />
188        </Typography>
189      </div>
190    </div>
191  );
192}
193
194export default BugTitleForm;