BugTitleForm.tsx

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