diff --git a/client/package-lock.json b/client/package-lock.json index c711ba3ca..74a742409 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -635,6 +635,15 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "axios": { + "version": "0.18.0", + "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "1.5.7", + "is-buffer": "1.1.6" + } + }, "axobject-query": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz", @@ -5051,6 +5060,28 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" }, + "history": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz", + "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==", + "requires": { + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "resolve-pathname": "2.2.0", + "value-equal": "0.4.0", + "warning": "3.0.0" + }, + "dependencies": { + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "1.4.0" + } + } + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -6430,6 +6461,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, + "lodash-es": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.10.tgz", + "integrity": "sha512-iesFYPmxYYGTcmQK0sL8bX3TGHyM6b2qREaB4kamHfQyfPJP0xgoGxp19nsH16nsfquLdiyKyX3mQkfiSGV8Rg==" + }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", @@ -8932,6 +8968,46 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.1.tgz", "integrity": "sha512-xXUbDAZkU08aAkjtUvldqbvI04ogv+a1XdHxvYuHPYKIVk/42BIOD0zSKTHAWV4+gDy3yGm283z2072rA2gdtw==" }, + "react-redux": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz", + "integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==", + "requires": { + "hoist-non-react-statics": "2.5.5", + "invariant": "2.2.4", + "lodash": "4.17.10", + "lodash-es": "4.17.10", + "loose-envify": "1.4.0", + "prop-types": "15.6.2" + } + }, + "react-router": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", + "integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==", + "requires": { + "history": "4.7.2", + "hoist-non-react-statics": "2.5.5", + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "path-to-regexp": "1.7.0", + "prop-types": "15.6.2", + "warning": "4.0.2" + } + }, + "react-router-dom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz", + "integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==", + "requires": { + "history": "4.7.2", + "invariant": "2.2.4", + "loose-envify": "1.4.0", + "prop-types": "15.6.2", + "react-router": "4.3.1", + "warning": "4.0.2" + } + }, "react-scripts": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.5.tgz", @@ -9096,6 +9172,15 @@ } } }, + "redux": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.0.tgz", + "integrity": "sha512-NnnHF0h0WVE/hXyrB6OlX67LYRuaf/rJcbWvnHHEPCF/Xa/AZpwhs/20WyqzQae5x4SD2F9nPObgBh2rxAgLiA==", + "requires": { + "loose-envify": "1.4.0", + "symbol-observable": "1.2.0" + } + }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", @@ -9320,6 +9405,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" }, + "resolve-pathname": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==" + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -10651,6 +10741,11 @@ "spdx-expression-parse": "3.0.0" } }, + "value-equal": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz", + "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -10687,6 +10782,14 @@ "makeerror": "1.0.11" } }, + "warning": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.2.tgz", + "integrity": "sha512-wbTp09q/9C+jJn4KKJfJfoS6VleK/Dti0yqWSm6KMvJ4MRCXFQNapHuJXutJIrWV0Cf4AhTdeIe4qdKHR1+Hug==", + "requires": { + "loose-envify": "1.4.0" + } + }, "watch": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz", diff --git a/client/package.json b/client/package.json index 1df1d0249..da93796b3 100644 --- a/client/package.json +++ b/client/package.json @@ -4,11 +4,15 @@ "private": true, "dependencies": { "apollo-boost": "^0.1.15", + "axios": "^0.18.0", "graphql": "^14.0.0", "react": "^16.4.2", "react-apollo": "^2.1.11", "react-dom": "^16.4.2", - "react-scripts": "1.1.5" + "react-redux": "^5.0.7", + "react-router-dom": "^4.3.1", + "react-scripts": "1.1.5", + "redux": "^4.0.0" }, "scripts": { "start": "react-scripts start", diff --git a/client/public/index.html b/client/public/index.html index ed0ebafa1..a611e4e0d 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -19,6 +19,12 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> + + + + + + React App diff --git a/client/src/App.js b/client/src/App.js index 9864ce2e0..360dc840e 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -2,6 +2,13 @@ import React, { Component } from 'react'; import ApolloClient from 'apollo-boost'; import {ApolloProvider} from 'react-apollo'; +import Navbar from './components/Navbar' +import { Route, BrowserRouter, Switch } from 'react-router-dom' +import Home from './components/Home' +import About from './components/About' +import Contact from './components/Contact' +import Post from './components/Post' + // Components import UserList from './components/UserList'; diff --git a/client/src/actions/postActions.js b/client/src/actions/postActions.js new file mode 100644 index 000000000..a3d838e2a --- /dev/null +++ b/client/src/actions/postActions.js @@ -0,0 +1,6 @@ +export const deletePost = (id) => { + return { + type: 'DELETE_POST', + id + } +} \ No newline at end of file diff --git a/client/src/components/About.js b/client/src/components/About.js new file mode 100644 index 000000000..5283ad55d --- /dev/null +++ b/client/src/components/About.js @@ -0,0 +1,14 @@ +import React from 'react' + +const About = () => { + return ( +
+
+

About

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Recusandae repudiandae repellat illo magni eligendi cupiditate voluptates eius nam voluptate. Incidunt nihil ullam quae quia officia quaerat, deserunt eligendi explicabo totam?

+
+
+ ) +} + +export default About diff --git a/client/src/components/Contact.js b/client/src/components/Contact.js new file mode 100644 index 000000000..07bdb5692 --- /dev/null +++ b/client/src/components/Contact.js @@ -0,0 +1,14 @@ +import React from 'react' + +const Contact = () => { + return ( +
+
+

Contact

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Recusandae repudiandae repellat illo magni eligendi cupiditate voluptates eius nam voluptate. Incidunt nihil ullam quae quia officia quaerat, deserunt eligendi explicabo totam?

+
+
+ ) +} + +export default Contact diff --git a/client/src/components/Home.js b/client/src/components/Home.js new file mode 100644 index 000000000..cb1f79b04 --- /dev/null +++ b/client/src/components/Home.js @@ -0,0 +1,44 @@ +import React, { Component } from 'react' +import { Link } from 'react-router-dom' +import Pokeball from '../pokeball.png' +import { connect } from 'react-redux' + +class Home extends Component { + render(){ + const { posts } = this.props + const postList = posts.length ? ( + posts.map(post => { + return ( +
+ A Pokeball +
+ + {post.title} + +

{post.body}

+
+
+ ) + }) + ) : ( +
No posts to show
+ ); + + return ( +
+
+

Home

+ {postList} +
+
+ ) + } +} + +const mapStateToProps = (state) => { + return { + posts: state.posts + } +} + +export default connect(mapStateToProps)(Home) \ No newline at end of file diff --git a/client/src/components/Navbar.js b/client/src/components/Navbar.js new file mode 100644 index 000000000..7c0dd514a --- /dev/null +++ b/client/src/components/Navbar.js @@ -0,0 +1,19 @@ +import React from 'react'; +import { Link, NavLink, withRouter } from 'react-router-dom' + +const Navbar = (props) => { + return ( + + ) +} + +export default withRouter(Navbar) \ No newline at end of file diff --git a/client/src/components/Post.js b/client/src/components/Post.js new file mode 100644 index 000000000..8ae8e1de1 --- /dev/null +++ b/client/src/components/Post.js @@ -0,0 +1,47 @@ +import React, { Component } from 'react' +import { connect } from 'react-redux' +import { deletePost } from '../actions/postActions' + +class Post extends Component { + handleClick = () => { + this.props.deletePost(this.props.post.id); + this.props.history.push('/'); + } + render() { + + const post = this.props.post ? ( +
+

{this.props.post.title}

+

{this.props.post.body}

+
+ +
+
+ ) : ( +
Loading post...
+ ); + + return ( +
+ {post} +
+ ) + } +} + +const mapStateToProps = (state, ownProps) => { + let id = ownProps.match.params.post_id; + return { + post: state.posts.find(post => post.id === id) + } +} + +const mapDispatchToProps = (dispatch) => { + return { + deletePost: (id) => dispatch(deletePost(id)) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(Post) diff --git a/client/src/components/UserList.js b/client/src/components/UserList.js index 984bd2a70..a9c54bc72 100644 --- a/client/src/components/UserList.js +++ b/client/src/components/UserList.js @@ -2,7 +2,16 @@ import React, { Component } from 'react'; import {graphql} from 'react-apollo'; import {getUsersQuery} from '../queries/queries'; +// components +import UserProfile from './UserProfile'; + class UserList extends Component { + constructor(props){ + super(props); + this.state = { + selected: null + } + } displayUsers(){ let data = this.props.data; @@ -11,7 +20,7 @@ class UserList extends Component { } else { return data.users.map(user => { return ( -
  • {user.alias}
  • +
  • {this.setState({ selected: user.id})}} >{user.alias}
  • ) }); } @@ -22,6 +31,7 @@ class UserList extends Component { + ); } diff --git a/client/src/components/UserProfile.js b/client/src/components/UserProfile.js new file mode 100644 index 000000000..dfc959e1a --- /dev/null +++ b/client/src/components/UserProfile.js @@ -0,0 +1,41 @@ +import React, { Component } from 'react'; +import {graphql} from 'react-apollo'; +import {getUserProfileQuery} from '../queries/queries'; + +class UserProfile extends Component { + + displayUserProfile(){ + const {user} = this.props.data; + console.log(user); + if(user){ + return( +
    +

    { user.alias }

    +

    { user.firstName }

    +

    { user.lastName }

    +

    { user.role.name }

    +
    + ); + } else { + return(
    No User selected...
    ); + } + } + + render() { + return ( +
    + {this.displayUserProfile()} +
    + ); + } +} + +export default graphql(getUserProfileQuery, { // What follows is the way to pass a parameter to a query. + options: (props) => { + return { + variables: { + id: props.userId + } + } + } +})(UserProfile); // This binds the querty to the component diff --git a/client/src/index.css b/client/src/index.css index d6c3cf961..74d96ab6c 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -2,3 +2,85 @@ body { background: #eee; font-family: "Arial"; } + +#main h1{ + color:#444; + text-align: center; +} + +#main{ + padding: 0px; + box-sizing: border-box; + width: 60%; + height: 100%; +} + +#user-list{ + color: black; + padding: 0; +} + +#user-list-li{ + color: pink; + display: inline-block; + margin: 12px; + padding: 10px; + border-radius: 4px; + border: 1px solid #889E4F; + box-shadow: 1px 2px 3px rgba(0,0,0,3); + cursor: pointer; + color: #880E4F; +} + +form{ + background: #fff; + padding: 20px; + position: fixed; + left: 0; + bottom: 0; + width: 50%; +} + +form .field{ + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 10px; +} + +form label{ + text-align: right; + padding: 6px; +} + +form input, form select{ + margin: 4px 0; + padding: 6px; + box-sizing: border-box; +} + +form button{ + color: #fff; + font-size: 2em; + background: #AD1457; + border: 0; + padding: 0 10px; + border-radius: 50%; + cursor: pointer; + position: absolute; + bottom: 10px; + left: 10px; +} + +#user-profile{ + position: fixed; + top: 0; + right: 0; + width: 40%; + height: 100%; + background: #AD1457; + padding: 30px; + overflow: auto; + box-shadow: -2px -3px 5px rgba(0,0,0,0.3); + box-sizing: border-box; + color: #fff; +} diff --git a/client/src/pokeball.png b/client/src/pokeball.png new file mode 100644 index 000000000..f5eff9cff Binary files /dev/null and b/client/src/pokeball.png differ diff --git a/client/src/queries/queries.js b/client/src/queries/queries.js index d13c1fbcb..67617aa5d 100644 --- a/client/src/queries/queries.js +++ b/client/src/queries/queries.js @@ -11,6 +11,21 @@ const getUsersQuery = gql` } } ` + +const getUserProfileQuery = gql` +query($id: ID){ + user (id: $id){ + id + alias + firstName + lastName + role { + name + } + } +} +` + const getRolesQuery = gql` { roles { @@ -28,4 +43,4 @@ mutation($alias: String!, $firstName:String, $lastName:String, $roleId:String!) } } ` -export {getUsersQuery, getRolesQuery, addUserMutation} +export {getUsersQuery, getRolesQuery, addUserMutation, getUserProfileQuery}