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;