1import React, { useState } from 'react';
2
3import IconButton from '@material-ui/core/IconButton';
4import Paper from '@material-ui/core/Paper';
5import Tooltip from '@material-ui/core/Tooltip/Tooltip';
6import { makeStyles } from '@material-ui/core/styles';
7import EditIcon from '@material-ui/icons/Edit';
8import HistoryIcon from '@material-ui/icons/History';
9
10import Author, { Avatar } from 'src/components/Author';
11import Content from 'src/components/Content';
12import Date from 'src/components/Date';
13import IfLoggedIn from 'src/components/IfLoggedIn/IfLoggedIn';
14
15import { BugFragment } from './Bug.generated';
16import EditCommentForm from './EditCommentForm';
17import { AddCommentFragment } from './MessageCommentFragment.generated';
18import { CreateFragment } from './MessageCreateFragment.generated';
19import MessageHistoryDialog from './MessageHistoryDialog';
20
21const useStyles = makeStyles((theme) => ({
22 author: {
23 fontWeight: 'bold',
24 },
25 container: {
26 display: 'flex',
27 },
28 avatar: {
29 marginTop: 2,
30 },
31 bubble: {
32 flex: 1,
33 marginLeft: theme.spacing(1),
34 minWidth: 0,
35 },
36 header: {
37 ...theme.typography.body1,
38 padding: '0.5rem 1rem',
39 borderBottom: `1px solid ${theme.palette.divider}`,
40 display: 'flex',
41 borderTopRightRadius: theme.shape.borderRadius,
42 borderTopLeftRadius: theme.shape.borderRadius,
43 backgroundColor: theme.palette.info.main,
44 color: theme.palette.info.contrastText,
45 },
46 title: {
47 flex: 1,
48 },
49 tag: {
50 ...theme.typography.button,
51 color: '#888',
52 border: '#ddd solid 1px',
53 padding: '0 0.5rem',
54 fontSize: '0.75rem',
55 borderRadius: 2,
56 marginLeft: '0.5rem',
57 },
58 body: {
59 ...theme.typography.body2,
60 padding: '0.5rem',
61 },
62 headerActions: {
63 color: theme.palette.info.contrastText,
64 padding: '0rem',
65 marginLeft: theme.spacing(1),
66 fontSize: '0.75rem',
67 '&:hover': {
68 backgroundColor: 'inherit',
69 },
70 },
71}));
72
73type HistBtnProps = {
74 bugId: string;
75 commentId: string;
76};
77function HistoryMenuToggleButton({ bugId, commentId }: HistBtnProps) {
78 const classes = useStyles();
79 const [open, setOpen] = React.useState(false);
80
81 const handleClickOpen = () => {
82 setOpen(true);
83 };
84
85 const handleClose = () => {
86 setOpen(false);
87 };
88
89 return (
90 <div>
91 <IconButton
92 aria-label="more"
93 aria-controls="long-menu"
94 aria-haspopup="true"
95 onClick={handleClickOpen}
96 className={classes.headerActions}
97 >
98 <HistoryIcon />
99 </IconButton>
100 {
101 // Render CustomizedDialogs on open to prevent fetching the history
102 // before opening the history menu.
103 open && (
104 <MessageHistoryDialog
105 bugId={bugId}
106 commentId={commentId}
107 open={open}
108 onClose={handleClose}
109 />
110 )
111 }
112 </div>
113 );
114}
115
116type Props = {
117 bug: BugFragment;
118 op: AddCommentFragment | CreateFragment;
119};
120function Message({ bug, op }: Props) {
121 const classes = useStyles();
122 const [editMode, switchToEditMode] = useState(false);
123 const [comment, setComment] = useState(op);
124
125 const editComment = (id: String) => {
126 switchToEditMode(true);
127 };
128
129 function readMessageView() {
130 return (
131 <Paper elevation={1} className={classes.bubble}>
132 <header className={classes.header}>
133 <div className={classes.title}>
134 <Author className={classes.author} author={comment.author} />
135 <span> commented </span>
136 <Date date={comment.createdAt} />
137 </div>
138 {comment.edited && (
139 <HistoryMenuToggleButton bugId={bug.id} commentId={comment.id} />
140 )}
141 <IfLoggedIn>
142 {() => (
143 <Tooltip title="Edit Message" placement="top" arrow={true}>
144 <IconButton
145 disableRipple
146 className={classes.headerActions}
147 aria-label="edit message"
148 onClick={() => editComment(comment.id)}
149 >
150 <EditIcon />
151 </IconButton>
152 </Tooltip>
153 )}
154 </IfLoggedIn>
155 </header>
156 <section className={classes.body}>
157 <Content markdown={comment.message} />
158 </section>
159 </Paper>
160 );
161 }
162
163 function editMessageView() {
164 const cancelEdition = () => {
165 switchToEditMode(false);
166 };
167
168 const onPostSubmit = (comment: AddCommentFragment | CreateFragment) => {
169 setComment(comment);
170 switchToEditMode(false);
171 };
172
173 return (
174 <div className={classes.bubble}>
175 <EditCommentForm
176 bug={bug}
177 onCancel={cancelEdition}
178 onPostSubmit={onPostSubmit}
179 comment={comment}
180 />
181 </div>
182 );
183 }
184
185 return (
186 <article className={classes.container}>
187 <Avatar author={comment.author} className={classes.avatar} />
188 {editMode ? editMessageView() : readMessageView()}
189 </article>
190 );
191}
192
193export default Message;