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