Skip to content

Commit df73727

Browse files
committed
13-Implementing the Issues Feature: Server-Side Filter
1 parent 0f261b1 commit df73727

File tree

4 files changed

+196
-80
lines changed

4 files changed

+196
-80
lines changed

package-lock.json

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"react-apollo": "^2.2.4",
1515
"react-dom": "^16.6.0",
1616
"react-router-dom": "^4.3.1",
17-
"react-scripts": "2.0.5"
17+
"react-scripts": "2.0.5",
18+
"recompose": "^0.30.0"
1819
},
1920
"scripts": {
2021
"start": "react-scripts start",

src/Issue/IssueList/index.js

Lines changed: 108 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,16 @@
11
import React from 'react';
22
import { Query } from 'react-apollo';
3-
import gql from 'graphql-tag';
3+
import { withState } from 'recompose';
44

5+
import { GET_ISSUES_OF_REPOSITORY } from './queries';
56
import IssueItem from '../IssueItem';
67
import Loading from '../../Loading';
78
import ErrorMessage from '../../Error';
9+
import FetchMore from '../../FetchMore';
810
import { ButtonUnobtrusive } from '../../Button';
911

1012
import './style.css';
1113

12-
const GET_ISSUES_OF_REPOSITORY = gql`
13-
query($repositoryOwner: String!, $repositoryName: String!) {
14-
repository(name: $repositoryName, owner: $repositoryOwner) {
15-
issues(first: 5) {
16-
edges {
17-
node {
18-
id
19-
number
20-
state
21-
title
22-
url
23-
bodyHTML
24-
}
25-
}
26-
}
27-
}
28-
}
29-
`;
30-
3114
const ISSUE_STATES = {
3215
NONE: 'NONE',
3316
OPEN: 'OPEN',
@@ -48,75 +31,121 @@ const TRANSITION_STATE = {
4831

4932
const isShow = issueState => issueState !== ISSUE_STATES.NONE;
5033

51-
class Issues extends React.Component {
52-
state = {
53-
issueState: ISSUE_STATES.NONE,
54-
};
34+
const updateQuery = (previousResult, { fetchMoreResult }) => {
35+
if (!fetchMoreResult) {
36+
return previousResult;
37+
}
5538

56-
onChangeIssueState = nextIssueState => {
57-
this.setState({ issueState: nextIssueState });
39+
return {
40+
...previousResult,
41+
repository: {
42+
...previousResult.repository,
43+
issues: {
44+
...previousResult.repository.issues,
45+
...fetchMoreResult.repository.issues,
46+
edges: [
47+
...previousResult.repository.issues.edges,
48+
...fetchMoreResult.repository.issues.edges,
49+
],
50+
},
51+
},
5852
};
53+
};
54+
55+
const Issues = ({
56+
repositoryOwner,
57+
repositoryName,
58+
issueState,
59+
onChangeIssueState,
60+
}) => (
61+
<div className="Issues">
62+
<ButtonUnobtrusive
63+
onClick={() => onChangeIssueState(TRANSITION_STATE[issueState])}
64+
>
65+
{TRANSITION_LABELS[issueState]}
66+
</ButtonUnobtrusive>
67+
68+
{isShow(issueState) && (
69+
<Query
70+
query={GET_ISSUES_OF_REPOSITORY}
71+
variables={{
72+
repositoryOwner,
73+
repositoryName,
74+
issueState,
75+
}}
76+
notifyOnNetworkStatusChange={true}
77+
>
78+
{({ data, loading, error, fetchMore }) => {
79+
if (error) {
80+
return <ErrorMessage error={error} />;
81+
}
5982

60-
render() {
61-
const { issueState } = this.state;
62-
const { repositoryOwner, repositoryName } = this.props;
83+
const { repository } = data;
6384

64-
return (
65-
<div className="Issues">
66-
<ButtonUnobtrusive
67-
onClick={() =>
68-
this.onChangeIssueState(TRANSITION_STATE[issueState])
85+
if (loading && !repository) {
86+
return <Loading />;
87+
}
88+
89+
const filteredRepository = {
90+
issues: {
91+
edges: repository.issues.edges.filter(
92+
issue => issue.node.state === issueState,
93+
),
94+
},
95+
};
96+
97+
if (!filteredRepository.issues.edges.length) {
98+
return <div className="IssueList">No issues ...</div>;
6999
}
70-
>
71-
{TRANSITION_LABELS[issueState]}
72-
</ButtonUnobtrusive>
73-
74-
{isShow(issueState) && (
75-
<Query
76-
query={GET_ISSUES_OF_REPOSITORY}
77-
variables={{
78-
repositoryOwner,
79-
repositoryName,
80-
}}
81-
>
82-
{({ data, loading, error }) => {
83-
if (error) {
84-
return <ErrorMessage error={error} />;
85-
}
86-
87-
const { repository } = data;
88-
89-
if (loading && !repository) {
90-
return <Loading />;
91-
}
92-
93-
const filteredRepository = {
94-
issues: {
95-
edges: repository.issues.edges.filter(
96-
issue => issue.node.state === issueState,
97-
),
98-
},
99-
};
100-
101-
if (!filteredRepository.issues.edges.length) {
102-
return <div className="IssueList">No issues ...</div>;
103-
}
104-
105-
return <IssueList issues={filteredRepository.issues} />;
106-
}}
107-
</Query>
108-
)}
109-
</div>
110-
);
111-
}
112-
}
113100

114-
const IssueList = ({ issues }) => (
101+
return (
102+
<IssueList
103+
issues={repository.issues}
104+
loading={loading}
105+
repositoryOwner={repositoryOwner}
106+
repositoryName={repositoryName}
107+
issueState={issueState}
108+
fetchMore={fetchMore}
109+
/>
110+
);
111+
}}
112+
</Query>
113+
)}
114+
</div>
115+
);
116+
117+
const IssueList = ({
118+
issues,
119+
loading,
120+
repositoryOwner,
121+
repositoryName,
122+
issueState,
123+
fetchMore,
124+
}) => (
115125
<div className="IssueList">
116126
{issues.edges.map(({ node }) => (
117127
<IssueItem key={node.id} issue={node} />
118128
))}
129+
130+
<FetchMore
131+
loading={loading}
132+
hasNextPage={issues.pageInfo.hasNextPage}
133+
variables={{
134+
cursor: issues.pageInfo.endCursor,
135+
repositoryOwner,
136+
repositoryName,
137+
issueState,
138+
}}
139+
updateQuery={updateQuery}
140+
fetchMore={fetchMore}
141+
>
142+
Issues
143+
</FetchMore>
119144
</div>
120145
);
121146

122-
export default Issues;
147+
export default withState(
148+
'issueState',
149+
'onChangeIssueState',
150+
ISSUE_STATES.NONE,
151+
)(Issues);

src/Issue/IssueList/queries.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import gql from 'graphql-tag';
2+
3+
export const GET_ISSUES_OF_REPOSITORY = gql`
4+
query(
5+
$repositoryOwner: String!
6+
$repositoryName: String!
7+
$issueState: IssueState!
8+
$cursor: String
9+
) {
10+
repository(name: $repositoryName, owner: $repositoryOwner) {
11+
issues(first: 5, states: [$issueState], after: $cursor) {
12+
edges {
13+
node {
14+
id
15+
number
16+
state
17+
title
18+
url
19+
bodyHTML
20+
}
21+
}
22+
pageInfo {
23+
endCursor
24+
hasNextPage
25+
}
26+
}
27+
}
28+
}
29+
`;

0 commit comments

Comments
 (0)