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