Skip to content

Commit 3027be4

Browse files
authored
Add edit to comments (codesandbox#3665)
* add edit ability * small ui fies * fix ts
1 parent ec2c936 commit 3027be4

File tree

5 files changed

+156
-30
lines changed

5 files changed

+156
-30
lines changed

packages/app/src/app/overmind/effects/fakeGql/comments/mutations.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ export const updateReply: Query<
137137
UpdateReplyResponse,
138138
UpdateReplyVariables
139139
> = gql`
140-
mutation updateReply($replyId: String!, $commentId: String!) {
140+
mutation updateReply(
141+
$replyId: String!
142+
$commentId: String!
143+
$comment: String!
144+
) {
141145
updateReply(replyId: $replyId, commentId: $commentId, comment: $comment) {
142146
id
143147
replies {

packages/app/src/app/overmind/namespaces/editor/actions.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,7 +1479,7 @@ export const updateComment: AsyncAction<{
14791479
id: string;
14801480
data: {
14811481
comment?: string;
1482-
isResolved: boolean;
1482+
isResolved?: boolean;
14831483
};
14841484
}> = async ({ effects, state }, { id, data }) => {
14851485
if (!state.editor.currentSandbox) {
@@ -1493,7 +1493,7 @@ export const updateComment: AsyncAction<{
14931493
currentComment &&
14941494
state.editor.comments[sandboxId][id].id === currentComment.id;
14951495

1496-
if ('isResolved' in data) {
1496+
if ('isResolved' in data && data.isResolved) {
14971497
state.editor.comments[sandboxId][id].isResolved = data.isResolved;
14981498
if (updateIsCurrent && currentComment) {
14991499
currentComment.isResolved = data.isResolved;
@@ -1587,9 +1587,12 @@ export const updateReply: AsyncAction<{
15871587
});
15881588
} catch (error) {
15891589
effects.notificationToast.error(
1590-
'Unable to update your comment, please try again'
1590+
'Unable to update your reply, please try again'
15911591
);
1592-
state.editor.comments[sandboxId][commentId] = old;
1592+
state.editor.comments[sandboxId][commentId] = {
1593+
...old,
1594+
replies: old.replies,
1595+
};
15931596
}
15941597
};
15951598

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/Comments/Dialog/Comment.tsx renamed to packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/Comments/Dialog/Markdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Text, Element, Link } from '@codesandbox/components';
55
import css from '@styled-system/css';
66
import { Code } from './Code';
77

8-
export const Comment = ({ source }) => {
8+
export const Markdown = ({ source }) => {
99
const { state } = useOvermind();
1010
const privateSandbox =
1111
state.editor.currentSandbox.privacy === 1 ||

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/Comments/Dialog/Reply.tsx

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import { formatDistance } from 'date-fns';
33
import css from '@styled-system/css';
44
import {
55
Element,
6+
Button,
67
Stack,
78
Avatar,
89
Text,
910
Link,
1011
Menu,
12+
Textarea,
1113
} from '@codesandbox/components';
1214
import { useOvermind } from 'app/overmind';
13-
import { Comment } from './Comment';
15+
import { Markdown } from './Markdown';
1416

1517
type ReplyProps = {
1618
id: string;
@@ -28,6 +30,8 @@ export const Reply = ({
2830
content,
2931
}: ReplyProps) => {
3032
const { state, actions } = useOvermind();
33+
const [edit, setEdit] = useState(false);
34+
const [value, setValue] = useState(content);
3135
return (
3236
<>
3337
<Element key={id} marginLeft={4} marginRight={2} paddingTop={6}>
@@ -65,15 +69,17 @@ export const Reply = ({
6569
>
6670
Delete
6771
</Menu.Item>
68-
<Menu.Item>Edit</Menu.Item>
72+
<Menu.Item onSelect={() => setEdit(true)}>
73+
Edit Reply
74+
</Menu.Item>
6975
</Menu.List>
7076
</Menu>
7177
</Stack>
7278
)}
7379
</Stack>
7480
</Element>
7581
<Element
76-
as="p"
82+
as={edit ? 'div' : 'p'}
7783
marginY={0}
7884
marginX={4}
7985
paddingBottom={6}
@@ -82,7 +88,45 @@ export const Reply = ({
8288
borderColor: 'sideBar.border',
8389
})}
8490
>
85-
<Comment source={content} />
91+
{!edit ? (
92+
<Markdown source={content} />
93+
) : (
94+
<>
95+
<Element marginBottom={2}>
96+
<Textarea
97+
autosize
98+
value={value}
99+
onChange={e => setValue(e.target.value)}
100+
/>
101+
</Element>
102+
<Element
103+
css={css({
104+
display: 'grid',
105+
gridTemplateColumns: '1fr 1fr',
106+
gridGap: 2,
107+
})}
108+
>
109+
<Button variant="link" onClick={() => setEdit(false)}>
110+
Cancel
111+
</Button>
112+
113+
<Button
114+
variant="secondary"
115+
disabled={!value}
116+
onClick={async () => {
117+
await actions.editor.updateReply({
118+
replyId: id,
119+
commentId,
120+
comment: value,
121+
});
122+
setEdit(false);
123+
}}
124+
>
125+
Save
126+
</Button>
127+
</Element>
128+
</>
129+
)}
86130
</Element>
87131
</>
88132
);

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/Comments/Dialog/index.tsx

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ import {
1212
Text,
1313
Link,
1414
IconButton,
15+
Button,
16+
Menu,
1517
} from '@codesandbox/components';
1618
import { useOvermind } from 'app/overmind';
17-
import { Comment } from './Comment';
19+
import { Markdown } from './Markdown';
1820
import { Reply } from './Reply';
1921

2022
export const CommentDialog = props =>
@@ -23,7 +25,10 @@ export const CommentDialog = props =>
2325
export const Dialog = props => {
2426
const { state, actions } = useOvermind();
2527
const [value, setValue] = useState('');
28+
29+
const [edit, setEdit] = useState(false);
2630
const comment = state.editor.currentComment;
31+
const [editValue, setEditValue] = useState(comment.originalMessage.content);
2732
const [position, setPosition] = useState({
2833
x: props.x || 200,
2934
y: props.y || 100,
@@ -110,26 +115,57 @@ export const Dialog = props => {
110115

111116
{comment && (
112117
<>
113-
<Stack gap={2} align="center" paddingX={4} marginBottom={4}>
114-
<Avatar user={comment.originalMessage.author} />
115-
<Stack direction="vertical" justify="center" gap={1}>
116-
<Link
117-
size={3}
118-
weight="bold"
119-
href={`/u/${comment.originalMessage.author.username}`}
120-
variant="body"
121-
>
122-
{comment.originalMessage.author.username}
123-
</Link>
124-
<Text size={2} variant="muted">
125-
{formatDistance(new Date(comment.insertedAt), new Date(), {
126-
addSuffix: true,
127-
})}
128-
</Text>
118+
<Stack
119+
align="flex-start"
120+
justify="space-between"
121+
marginBottom={4}
122+
marginLeft={4}
123+
marginRight={2}
124+
>
125+
<Stack gap={2} align="center">
126+
<Avatar user={comment.originalMessage.author} />
127+
<Stack direction="vertical" justify="center" gap={1}>
128+
<Link
129+
size={3}
130+
weight="bold"
131+
href={`/u/${comment.originalMessage.author.username}`}
132+
variant="body"
133+
>
134+
{comment.originalMessage.author.username}
135+
</Link>
136+
<Text size={2} variant="muted">
137+
{formatDistance(new Date(comment.insertedAt), new Date(), {
138+
addSuffix: true,
139+
})}
140+
</Text>
141+
</Stack>
129142
</Stack>
143+
{state.user.id === comment.originalMessage.author.id && (
144+
<Stack align="center">
145+
<Menu>
146+
<Menu.IconButton
147+
name="more"
148+
title="Comment actions"
149+
size={3}
150+
/>
151+
<Menu.List>
152+
<Menu.Item
153+
onSelect={() =>
154+
actions.editor.deleteComment({ id: comment.id })
155+
}
156+
>
157+
Delete
158+
</Menu.Item>
159+
<Menu.Item onSelect={() => setEdit(true)}>
160+
Edit Comment
161+
</Menu.Item>
162+
</Menu.List>
163+
</Menu>
164+
</Stack>
165+
)}
130166
</Stack>
131167
<Element
132-
as="p"
168+
as={edit ? 'div' : 'p'}
133169
marginY={0}
134170
marginX={4}
135171
paddingBottom={6}
@@ -138,7 +174,46 @@ export const Dialog = props => {
138174
borderColor: 'sideBar.border',
139175
})}
140176
>
141-
<Comment source={comment.originalMessage.content} />
177+
{!edit ? (
178+
<Markdown source={comment.originalMessage.content} />
179+
) : (
180+
<>
181+
<Element marginBottom={2}>
182+
<Textarea
183+
autosize
184+
value={editValue}
185+
onChange={e => setEditValue(e.target.value)}
186+
/>
187+
</Element>
188+
<Element
189+
css={css({
190+
display: 'grid',
191+
gridTemplateColumns: '1fr 1fr',
192+
gridGap: 2,
193+
})}
194+
>
195+
<Button variant="link" onClick={() => setEdit(false)}>
196+
Cancel
197+
</Button>
198+
199+
<Button
200+
disabled={!editValue}
201+
variant="secondary"
202+
onClick={async () => {
203+
await actions.editor.updateComment({
204+
id: comment.id,
205+
data: {
206+
comment: editValue,
207+
},
208+
});
209+
setEdit(false);
210+
}}
211+
>
212+
Save
213+
</Button>
214+
</Element>
215+
</>
216+
)}
142217
</Element>
143218
</>
144219
)}

0 commit comments

Comments
 (0)