Skip to content

Commit f977375

Browse files
committed
add comments!
1 parent d6f9e76 commit f977375

19 files changed

+2285
-250
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
"babel-plugin-idx": "^2.4.0",
88
"babel-plugin-relay": "^5.0.0",
99
"change-case": "^3.1.0",
10-
"date-fns": "^1.30.1",
10+
"date-fns": "2.2.1",
11+
"email-reply-parser": "^1.2.1",
1112
"express": "^4.17.1",
1213
"feed": "^4.0.0",
1314
"firebase-admin": "^8.3.0",
1415
"firebase-functions": "^3.2.0",
1516
"graphql": "^14.4.2",
16-
"grommet": "^2.7.6",
17+
"grommet": "2.7.8",
1718
"grommet-icons": "^4.3.0",
1819
"highlightjs-graphql": "^1.0.1",
1920
"idx": "^2.5.6",

src/App.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import graphql from 'babel-plugin-relay/macro';
66
import {QueryRenderer, fetchQuery} from 'react-relay';
77
import Posts from './Posts';
88
import Post from './Post';
9+
import Comments from './Comments';
910
import {onegraphAuth} from './Environment';
1011
import {Route, Link, Switch} from 'react-router-dom';
1112
import idx from 'idx';
@@ -22,13 +23,23 @@ import type {Environment} from 'relay-runtime';
2223
import type {RelayNetworkError} from 'react-relay';
2324

2425
const theme = {
26+
name: 'onegraph',
27+
rounding: 4,
28+
spacing: 24,
2529
global: {
30+
colors: {
31+
brand: '#1997c6',
32+
'accent-1': '#3cc7b7',
33+
focus: 'rgba(60, 199, 183, 0.75)',
34+
},
2635
font: {
27-
family: 'Helvetica,Arial,sans-serif',
36+
family: 'Helvetica Neue,Helvetica,Arial,sans-serif',
2837
size: '14px',
2938
height: '20px',
3039
},
3140
},
41+
42+
date: '2019-09-13T16:24:04.000Z',
3243
};
3344

3445
const postsRootQuery = graphql`
@@ -45,7 +56,6 @@ const postsRootQuery = graphql`
4556
`;
4657

4758
const ErrorBox = ({error}: {error: Error}) => {
48-
console.log('e', error);
4959
// $FlowFixMe
5060
const relayError = idx(error, _ => _.source.errors[0].message);
5161
return (
@@ -90,7 +100,9 @@ export const postRootQuery = graphql`
90100
name
91101
}
92102
}
103+
id
93104
...Post_post
105+
...Comments_post
94106
}
95107
}
96108
}
@@ -115,7 +127,12 @@ const PostRoot = ({
115127
if (!post || !labels.map(l => l.name).includes('publish')) {
116128
return <ErrorBox error={new Error('Missing post.')} />;
117129
} else {
118-
return <Post post={post} />;
130+
return (
131+
<Box>
132+
<Post post={post} />
133+
<Comments post={post} postId={post.id} />
134+
</Box>
135+
);
119136
}
120137
};
121138

src/Comment.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// @flow
2+
3+
import React from 'react';
4+
import graphql from 'babel-plugin-relay/macro';
5+
import {createFragmentContainer, type RelayProp} from 'react-relay';
6+
import {PostBox, ReactionBar} from './Post';
7+
import type {Comment_comment} from './__generated__/Comment_comment.graphql';
8+
import LoadingSpinner from './loadingSpinner';
9+
import MarkdownRenderer from './MarkdownRenderer';
10+
import idx from 'idx';
11+
import {Box, Heading, Text, TextArea, Tabs, Tab} from 'grommet';
12+
import {formatDistance, format} from 'date-fns';
13+
import EmailReplyParser from 'email-reply-parser';
14+
15+
type Props = {
16+
relay: RelayProp,
17+
comment: Comment_comment,
18+
};
19+
20+
function Comment({comment, relay}: Props) {
21+
const source = comment.createdViaEmail
22+
? new EmailReplyParser().read(comment.body).getVisibleText()
23+
: comment.body;
24+
return (
25+
<PostBox key={comment.id}>
26+
<Box
27+
border={{
28+
size: 'xsmall',
29+
side: 'bottom',
30+
color: 'rgba(0,0,0,0.1)',
31+
}}
32+
pad="small"
33+
direction="row"
34+
align="center"
35+
gap="xsmall">
36+
<img
37+
width={24}
38+
height={24}
39+
style={{borderRadius: '50%'}}
40+
src={idx(comment, _ => _.author.avatarUrl)}
41+
/>
42+
<Text size="small">
43+
<a href={idx(comment, _ => _.author.url)}>
44+
{idx(comment, _ => _.author.name) ||
45+
idx(comment, _ => _.author.login)}
46+
</a>{' '}
47+
commented{' '}
48+
<span title={format(new Date(comment.createdAt), 'PPP, pp')}>
49+
{formatDistance(new Date(), new Date(comment.createdAt))} ago
50+
</span>
51+
</Text>
52+
</Box>
53+
<Box pad="medium">
54+
<MarkdownRenderer escapeHtml={true} source={source} />
55+
</Box>
56+
<ReactionBar
57+
reactionGroups={comment.reactionGroups}
58+
relay={relay}
59+
subjectId={comment.id}
60+
/>
61+
</PostBox>
62+
);
63+
}
64+
65+
export default createFragmentContainer(Comment, {
66+
comment: graphql`
67+
fragment Comment_comment on GitHubIssueComment {
68+
id
69+
body
70+
createdViaEmail
71+
author {
72+
... on GitHubUser {
73+
name
74+
avatarUrl
75+
login
76+
url
77+
}
78+
... on GitHubBot {
79+
avatarUrl
80+
login
81+
url
82+
}
83+
... on GitHubOrganization {
84+
name
85+
avatarUrl
86+
login
87+
url
88+
}
89+
... on GitHubMannequin {
90+
id
91+
login
92+
url
93+
}
94+
}
95+
createdAt
96+
reactionGroups {
97+
content
98+
viewerHasReacted
99+
users(first: 11) {
100+
totalCount
101+
nodes {
102+
login
103+
}
104+
}
105+
}
106+
}
107+
`,
108+
});

src/Comments.js

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// @flow
2+
3+
import React from 'react';
4+
import graphql from 'babel-plugin-relay/macro';
5+
import {
6+
commitMutation,
7+
createPaginationContainer,
8+
type RelayProp,
9+
} from 'react-relay';
10+
import {ConnectionHandler} from 'relay-runtime';
11+
import {PostBox, ReactionBar} from './Post';
12+
import type {Comments_post} from './__generated__/Comments_post.graphql';
13+
import LoadingSpinner from './loadingSpinner';
14+
import MarkdownRenderer from './MarkdownRenderer';
15+
import idx from 'idx';
16+
import {Box, Heading, Text, TextArea, Tabs, Tab, Button, Stack} from 'grommet';
17+
import {formatDistance, format} from 'date-fns';
18+
import Comment from './Comment';
19+
import {NotificationContext} from './Notifications';
20+
import UserContext from './UserContext';
21+
import GitHubLoginButton from './GitHubLoginButton';
22+
23+
type Props = {
24+
relay: RelayProp,
25+
post: Comments_post,
26+
postId: string,
27+
};
28+
29+
const addCommentMutation = graphql`
30+
mutation Comments_AddCommentMutation($input: GitHubAddCommentInput!) {
31+
gitHub {
32+
addComment(input: $input) {
33+
commentEdge {
34+
node {
35+
...Comment_comment
36+
}
37+
}
38+
}
39+
}
40+
}
41+
`;
42+
43+
function Comments({post, relay, postId}: Props) {
44+
const {error: notifyError} = React.useContext(NotificationContext);
45+
const {isLoggedIn, login} = React.useContext(UserContext);
46+
47+
const [comment, setComment] = React.useState('');
48+
const [saving, setSaving] = React.useState(false);
49+
50+
const comments = [];
51+
for (const edge of post.comments.edges || []) {
52+
if (edge && edge.node) {
53+
comments.push(edge.node);
54+
}
55+
}
56+
57+
const saveComment = () => {
58+
setSaving(true);
59+
commitMutation(relay.environment, {
60+
mutation: addCommentMutation,
61+
variables: {
62+
input: {
63+
body: comment,
64+
subjectId: postId,
65+
},
66+
},
67+
onCompleted: () => {
68+
setSaving(false);
69+
setComment('');
70+
},
71+
onError: err => notifyError('Error saving comment. Please try again.'),
72+
updater(store, data) {
73+
const newComment = store.get(
74+
data.gitHub.addComment.commentEdge.node.__id,
75+
);
76+
const post = store.get(postId);
77+
const ch = ConnectionHandler;
78+
const comments = ConnectionHandler.getConnection(
79+
post,
80+
'Comments_post_comments',
81+
);
82+
const edge = ConnectionHandler.createEdge(
83+
store,
84+
comments,
85+
newComment,
86+
'GitHubIssueComment',
87+
);
88+
ConnectionHandler.insertEdgeAfter(comments, edge);
89+
},
90+
});
91+
};
92+
93+
return (
94+
<Box id="comments">
95+
{comments.map(comment => {
96+
return <Comment comment={comment} />;
97+
})}
98+
<PostBox>
99+
<Stack
100+
guidingChild="first"
101+
interactiveChild={isLoggedIn ? 'first' : 'last'}
102+
anchor="center">
103+
<Box style={{opacity: isLoggedIn ? 1 : 0.3}}>
104+
<Tabs justify="start">
105+
<Tab title={<Text size="small">Write</Text>}>
106+
<Box pad="small" height="small">
107+
<TextArea
108+
disabled={saving}
109+
placeholder="Leave a comment (supports markdown)"
110+
value={comment}
111+
style={{height: '100%', fontWeight: 'normal'}}
112+
onChange={e => setComment(e.target.value)}
113+
/>
114+
</Box>
115+
</Tab>
116+
<Tab title={<Text size="small">Preview</Text>}>
117+
<Box pad="small" height={{min: 'small'}}>
118+
<MarkdownRenderer
119+
escapeHtml={true}
120+
source={comment.trim() ? comment : 'Nothing to preview.'}
121+
/>
122+
</Box>
123+
</Tab>
124+
</Tabs>
125+
<Box
126+
border={{
127+
size: 'xsmall',
128+
side: 'bottom',
129+
color: 'rgba(0,0,0,0.1)',
130+
}}>
131+
<Box pad="small" align="end">
132+
<Button
133+
fill={false}
134+
label="Comment"
135+
onClick={saveComment}
136+
disabled={saving}
137+
/>
138+
</Box>
139+
</Box>
140+
</Box>
141+
142+
<Box style={{visibility: isLoggedIn ? 'hidden' : 'visible'}}>
143+
<GitHubLoginButton onClick={login} label="Log in with GitHub" />
144+
</Box>
145+
</Stack>
146+
</PostBox>
147+
148+
<Box height="small" />
149+
</Box>
150+
);
151+
}
152+
153+
export default createPaginationContainer(
154+
Comments,
155+
{
156+
post: graphql`
157+
fragment Comments_post on GitHubIssue
158+
@argumentDefinitions(
159+
count: {type: "Int", defaultValue: 100}
160+
cursor: {type: "String"}
161+
) {
162+
comments(first: $count, after: $cursor)
163+
@connection(key: "Comments_post_comments") {
164+
edges {
165+
node {
166+
...Comment_comment
167+
}
168+
}
169+
}
170+
}
171+
`,
172+
},
173+
{
174+
direction: 'forward',
175+
getConnectionFromProps(props) {
176+
return props.comments;
177+
},
178+
getVariables(props, {count, cursor}, fragmentVariables) {
179+
return {
180+
count: count,
181+
cursor,
182+
// XXX: fix
183+
issueNumber: props.issue.number,
184+
};
185+
},
186+
query: graphql`
187+
query CommentsPaginationQuery(
188+
$count: Int!
189+
$cursor: String
190+
$issueNumber: Int!
191+
)
192+
@persistedQueryConfiguration(
193+
accessToken: {environmentVariable: "OG_GITHUB_TOKEN"}
194+
) {
195+
gitHub {
196+
repository(name: "onegraph-changelog", owner: "onegraph") {
197+
__typename
198+
issue(number: $issueNumber) {
199+
...Comments_post @arguments(count: $count, cursor: $cursor)
200+
}
201+
}
202+
}
203+
}
204+
`,
205+
},
206+
);

0 commit comments

Comments
 (0)