Skip to content

Commit 836462b

Browse files
authored
Merge pull request #4 from rwandaopensource/members-page
members page
2 parents d04719b + 29b70a8 commit 836462b

File tree

10 files changed

+239
-17
lines changed

10 files changed

+239
-17
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pids
1010
*.pid
1111
*.seed
1212
*.pid.lock
13-
13+
yarn.lock
1414
# Directory for instrumented libs generated by jscoverage/JSCover
1515
lib-cov
1616

public/index.html

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
<title>Rwanda Open Source - Home</title>
77
<link rel="icon" type="image/icon" href="./favicon.ico">
88
<meta charset='UTF-8' />
9+
<link rel="stylesheet" href=https://use.fontawesome.com/releases/v5.6.3/css/all.css
10+
integrity=sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/ crossorigin="anonymous">
11+
<link rel="stylesheet" href="//cdn.materialdesignicons.com/2.0.46/css/materialdesignicons.min.css">
12+
<script defer src="https://use.fontawesome.com/releases/v5.0.8/js/all.js"
13+
integrity="sha384-SlE991lGASHoBfWbelyBPLsUlwY1GwNDJo3jSJO04KZ33K2bwfV9YBauFfnzvynJ" crossorigin="anonymous">
14+
</script>
915
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
1016
<meta http-equiv='X-UA-Compatible' content='ie=edge' />
1117
</head>
@@ -14,4 +20,4 @@
1420
<div id="root"></div>
1521
</body>
1622

17-
</html>
23+
</html>

src/helpers/url.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
export const url = (() => {
33
const { host } = document.location;
44
if (/localhost/.test(host)) {
5-
return 'http://localhost:5000';
5+
return "http://localhost:5000";
66
}
77
if (/staging/.test(host)) {
8-
return 'https://api-staging.opensource.org.rw';
8+
return "https://api-staging.opensource.org.rw";
99
}
10-
return 'https://api.opensource.org.rw'
10+
return "https://api.opensource.org.rw";
1111
})();
1212

1313
export const homeStatsURL = `${url}/stats/home`;
14+
export const membersPageURL = `${url}/members`;

src/pages/Members.js

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React from "react";
2+
import Header from "../components/Header";
3+
import Footer from "../components/Footer";
4+
import { getMembers } from "./../redux/actions/members";
5+
import { connect } from "react-redux";
6+
import propTypes from "prop-types";
7+
8+
export class Members extends React.Component {
9+
constructor(props) {
10+
super(props);
11+
this.state = {};
12+
this.props.getMembers();
13+
document.title = "Rwanda Open Source - Members";
14+
}
15+
16+
render() {
17+
const { members, status } = this.props;
18+
return (
19+
<div className="page-container section">
20+
<Header />
21+
<h1 className="title is-4 has-text-centered">
22+
RWANDA OPEN SOURCE MEMBERS
23+
</h1>
24+
{status == 200 ? (
25+
<div className="container members">
26+
<div className="wrapper">
27+
{members.map((member) => (
28+
<div className="member" key={member.id}>
29+
<div className="member-card">
30+
<img className="member-image" src={member.profileURL} alt />
31+
<div className="card-content">
32+
<div className="member-details has-text-centered">
33+
<h3 className="name">{member.name}</h3>
34+
<p className="bio">{member.location}</p>
35+
</div>
36+
<div className="content">{member.bio}</div>
37+
</div>
38+
</div>
39+
</div>
40+
))}
41+
</div>
42+
<div className="buttons">
43+
<button className="button is-grey">
44+
<i className="fas fa-plus is-white fas-space"></i>Show more
45+
</button>
46+
</div>
47+
</div>
48+
) : (
49+
<div className="members-not-found"></div>
50+
)}
51+
<Footer />
52+
</div>
53+
);
54+
}
55+
}
56+
57+
Members.defaultProps = {
58+
members: [],
59+
status: 0,
60+
getMembers,
61+
};
62+
63+
Members.propTypes = {
64+
members: propTypes.array,
65+
status: propTypes.number,
66+
getMembers: propTypes.func,
67+
};
68+
69+
const mapStateToProps = ({ Members }) => ({
70+
members: Members.members,
71+
status: Members.status,
72+
});
73+
74+
const mapDispatchToProps = (dispatch) => ({
75+
getMembers: async () => getMembers(dispatch),
76+
});
77+
78+
export default connect(mapStateToProps, mapDispatchToProps)(Members);

src/pages/index.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
1-
import '../scss/index.scss';
2-
import React from 'react';
3-
import { BrowserRouter, Switch, Route } from 'react-router-dom';
4-
import Home from './Home';
5-
import NotFound from './NotFound';
1+
import "../scss/index.scss";
2+
import React from "react";
3+
import { BrowserRouter, Switch, Route } from "react-router-dom";
4+
import Home from "./Home";
5+
import NotFound from "./NotFound";
6+
import Members from "./Members";
67

78
class App extends React.Component {
89
constructor(props) {
9-
super(props)
10+
super(props);
1011
this.state = {};
1112
}
1213

1314
render() {
1415
return (
1516
<BrowserRouter>
1617
<Switch>
17-
<Route exact path='/' component={Home} />
18-
<Route path='*' component={NotFound} /> {/* this need needs to come after all other routes */}
18+
<Route exact path="/" component={Home} />
19+
<Route exact path="/members" component={Members} />
20+
<Route path="*" component={NotFound} />{" "}
21+
{/* this need needs to come after all other routes */}
1922
</Switch>
2023
</BrowserRouter>
21-
)
24+
);
2225
}
2326
}
2427

src/redux/actions/members.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { membersPageURL } from "../../helpers/url";
2+
3+
export const getMembers = async dispatch => {
4+
let status = 0;
5+
dispatch({ type: "MEMBERS_PENDING" });
6+
fetch(membersPageURL)
7+
.then(res => {
8+
status = res.status;
9+
return res.json();
10+
})
11+
.then(res => {
12+
dispatch({ type: "MEMBERS_FINISH", payload: { ...res, status } });
13+
})
14+
.catch(() => {
15+
dispatch({ type: "MEMBERS_FAIL", payload: { status: 500 } });
16+
});
17+
};

src/redux/reducers/index.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { combineReducers } from 'redux';
2-
import Home from './home';
1+
import { combineReducers } from "redux";
2+
import Home from "./home";
3+
import Members from "./members";
34

4-
export default combineReducers({ Home });
5+
export default combineReducers({ Home, Members });

src/redux/reducers/members.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const initialState = {
2+
members: [],
3+
status: 0,
4+
};
5+
6+
export default (state = initialState, action) => {
7+
const { type, payload } = action;
8+
switch (type) {
9+
case "MEMBERS_PENDING":
10+
return {
11+
...state,
12+
status: 1,
13+
};
14+
case "MEMBERS_FINISH":
15+
return {
16+
...state,
17+
...payload,
18+
};
19+
case "MEMBERS_FAIL":
20+
return {
21+
...state,
22+
...payload,
23+
};
24+
default:
25+
return state;
26+
}
27+
};

src/scss/index.scss

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
@import './header.scss';
66
@import './footer.scss';
77
@import './home.scss';
8+
@import './members.scss';

src/scss/members.scss

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
.title {
2+
margin-top: 2rem;
3+
}
4+
5+
.members-not-found {
6+
height: 50vh !important;
7+
}
8+
9+
.members {
10+
11+
.member-image {
12+
width: 100px;
13+
height: 100px;
14+
border-radius: 50%;
15+
margin: 0 auto;
16+
}
17+
18+
.member-card {
19+
-webkit-transition: all 200ms ease-in;
20+
-webkit-transform: scale(1);
21+
-ms-transition: all 200ms ease-in;
22+
-ms-transform: scale(1);
23+
-moz-transition: all 200ms ease-in;
24+
-moz-transform: scale(1);
25+
transition: all 200ms ease-in;
26+
transform: scale(1);
27+
display: flex;
28+
flex-flow: column;
29+
background-color: white;
30+
padding: 10px;
31+
}
32+
33+
.member-card:hover {
34+
cursor: pointer;
35+
z-index: 2;
36+
-webkit-transition: all 200ms ease-in;
37+
-webkit-transform: scale(1.05);
38+
-ms-transition: all 200ms ease-in;
39+
-ms-transform: scale(1.05);
40+
-moz-transition: all 200ms ease-in;
41+
-moz-transform: scale(1.05);
42+
transition: all 200ms ease-in;
43+
transform: scale(1.05);
44+
}
45+
46+
.wrapper {
47+
display: grid;
48+
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
49+
grid-gap: 10px;
50+
margin: 2rem;
51+
}
52+
53+
.content {
54+
text-align: left;
55+
font-size: 14px;
56+
color: #4a4a4aa6;
57+
}
58+
59+
.member-details {
60+
margin-bottom: 10px;
61+
62+
.name {
63+
font-weight: 600;
64+
}
65+
66+
.bio {
67+
font-size: 14px;
68+
opacity: 0.5;
69+
}
70+
}
71+
72+
.buttons {
73+
display: flex;
74+
justify-content: center;
75+
76+
.button {
77+
background-color: #C4C4C4;
78+
color: white;
79+
}
80+
81+
.fas-space {
82+
padding-right: 4px;
83+
color: $primary-background-color;
84+
85+
}
86+
}
87+
88+
}

0 commit comments

Comments
 (0)