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