CommentForm.tsx

  1import React, { useState, useRef } from 'react';
  2
  3import Button from '@material-ui/core/Button';
  4import Paper from '@material-ui/core/Paper';
  5import Tab from '@material-ui/core/Tab';
  6import Tabs from '@material-ui/core/Tabs';
  7import TextField from '@material-ui/core/TextField';
  8import { makeStyles, Theme } from '@material-ui/core/styles';
  9
 10import Content from 'src/components/Content';
 11
 12import { useAddCommentMutation } from './CommentForm.generated';
 13import { TimelineDocument } from './TimelineQuery.generated';
 14
 15type StyleProps = { loading: boolean };
 16const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
 17  container: {
 18    margin: theme.spacing(2, 0),
 19    padding: theme.spacing(0, 2, 2, 2),
 20  },
 21  textarea: {},
 22  tabContent: {
 23    margin: theme.spacing(2, 0),
 24  },
 25  preview: {
 26    borderBottom: `solid 3px ${theme.palette.grey['200']}`,
 27    minHeight: '5rem',
 28  },
 29  actions: {
 30    display: 'flex',
 31    justifyContent: 'flex-end',
 32  },
 33}));
 34
 35type TabPanelProps = {
 36  children: React.ReactNode;
 37  value: number;
 38  index: number;
 39} & React.HTMLProps<HTMLDivElement>;
 40function TabPanel({ children, value, index, ...props }: TabPanelProps) {
 41  return (
 42    <div
 43      role="tabpanel"
 44      hidden={value !== index}
 45      id={`editor-tabpanel-${index}`}
 46      aria-labelledby={`editor-tab-${index}`}
 47      {...props}
 48    >
 49      {value === index && children}
 50    </div>
 51  );
 52}
 53
 54const a11yProps = (index: number) => ({
 55  id: `editor-tab-${index}`,
 56  'aria-controls': `editor-tabpanel-${index}`,
 57});
 58
 59type Props = {
 60  bugId: string;
 61};
 62
 63function CommentForm({ bugId }: Props) {
 64  const [addComment, { loading }] = useAddCommentMutation();
 65  const [input, setInput] = useState<string>('');
 66  const [tab, setTab] = useState(0);
 67  const classes = useStyles({ loading });
 68  const form = useRef<HTMLFormElement>(null);
 69
 70  const submit = () => {
 71    addComment({
 72      variables: {
 73        input: {
 74          prefix: bugId,
 75          message: input,
 76        },
 77      },
 78      refetchQueries: [
 79        // TODO: update the cache instead of refetching
 80        {
 81          query: TimelineDocument,
 82          variables: {
 83            id: bugId,
 84            first: 100,
 85          },
 86        },
 87      ],
 88      awaitRefetchQueries: true,
 89    }).then(() => setInput(''));
 90  };
 91
 92  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
 93    e.preventDefault();
 94    submit();
 95  };
 96
 97  const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
 98    // Submit on cmd/ctrl+enter
 99    if ((e.metaKey || e.altKey) && e.keyCode === 13) {
100      submit();
101    }
102  };
103
104  return (
105    <Paper className={classes.container}>
106      <form onSubmit={handleSubmit} ref={form}>
107        <Tabs value={tab} onChange={(_, t) => setTab(t)}>
108          <Tab label="Write" {...a11yProps(0)} />
109          <Tab label="Preview" {...a11yProps(1)} />
110        </Tabs>
111        <div className={classes.tabContent}>
112          <TabPanel value={tab} index={0}>
113            <TextField
114              onKeyDown={handleKeyDown}
115              fullWidth
116              label="Comment"
117              placeholder="Leave a comment"
118              className={classes.textarea}
119              multiline
120              value={input}
121              variant="filled"
122              rows="4" // TODO: rowsMin support
123              onChange={(e: any) => setInput(e.target.value)}
124              disabled={loading}
125            />
126          </TabPanel>
127          <TabPanel value={tab} index={1} className={classes.preview}>
128            <Content markdown={input} />
129          </TabPanel>
130        </div>
131        <div className={classes.actions}>
132          <Button
133            variant="contained"
134            color="primary"
135            type="submit"
136            disabled={loading}
137          >
138            Comment
139          </Button>
140        </div>
141      </form>
142    </Paper>
143  );
144}
145
146export default CommentForm;