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