diff --git a/assets/js/app.js b/assets/js/app.js index 6609c34..d7c44a0 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -22,15 +22,20 @@ import "phoenix_html"; import React from "react"; import ReactDOM from "react-dom"; - +import { ApolloProvider } from 'react-apollo'; import Header from "./components/Header"; +import Gallery from "./components/Gallery"; +import client from "./client"; class App extends React.Component { render() { return ( -
-
-
+ +
+
+ +
+
); } } diff --git a/assets/js/client.js b/assets/js/client.js new file mode 100644 index 0000000..e27a8ca --- /dev/null +++ b/assets/js/client.js @@ -0,0 +1,12 @@ +import { ApolloClient } from 'apollo-client'; +import { HttpLink } from 'apollo-link-http'; +import { InMemoryCache } from 'apollo-cache-inmemory'; + +const client = new ApolloClient({ + link: new HttpLink({ + uri: "/api" + }), + cache: new InMemoryCache(), +}); + +export default client; diff --git a/assets/js/components/AddFace.js b/assets/js/components/AddFace.js new file mode 100644 index 0000000..e8aa84a --- /dev/null +++ b/assets/js/components/AddFace.js @@ -0,0 +1,65 @@ +import React from "react"; +import gql from "graphql-tag"; +import { Mutation } from "react-apollo"; + +import IMPORT_PERSON from "../queries/import_person"; +import LIST_PEOPLE from "../queries/list_people"; + +class AddFace extends React.Component { + // I extracted the cache updating logic from the JSX because there were too + // many nested braces and it was making me confused. + cacheUpdater(cache, { data: { importPerson } }) { + let { people } = cache.readQuery({ query: LIST_PEOPLE }); + + // If the person already exists in the cache then replace them with the new data. + let existingPersonIndex = people.findIndex(person => person.username === importPerson.username); + if (existingPersonIndex >= 0) { + people.splice(existingPersonIndex, 1, importPerson); + } + // Otherwise add them to the cache. + else { + people = people.concat([importPerson]); + } + + cache.writeQuery({ + query: LIST_PEOPLE, + data: { people: people } + }); + } + + render() { + let input; + + return ( + + {(importPerson, { data }) => ( +
+
+
+
Add Face
+
+
+
{ + e.preventDefault(); + importPerson({ variables: { username: input.value } }); + input.value = ""; + }}> +
+ + input = node} /> +
+ + +
+
+
+
+ )} +
+ ); + } +} + +export default AddFace; diff --git a/assets/js/components/Gallery.js b/assets/js/components/Gallery.js new file mode 100644 index 0000000..062e679 --- /dev/null +++ b/assets/js/components/Gallery.js @@ -0,0 +1,27 @@ +import React from "react"; +import gql from "graphql-tag"; +import { Query } from "react-apollo"; +import Person from "./Person"; +import AddFace from "./AddFace"; + +import LIST_PEOPLE from "../queries/list_people"; + +class Gallery extends React.Component { + render() { + return ( +
+ + {({ loading, error, data }) => { + if (loading) return null; + if (error) return `Error!: ${error}`; + + return data.people.map((person, key) => ()); + }} + + +
+ ); + } +} + +export default Gallery; diff --git a/assets/js/components/Header.js b/assets/js/components/Header.js index 7066b7e..0a17ef1 100644 --- a/assets/js/components/Header.js +++ b/assets/js/components/Header.js @@ -3,8 +3,8 @@ import React from "react"; class Header extends React.Component { render() { return ( -
-
+
+

Face Gallery

diff --git a/assets/js/components/Person.js b/assets/js/components/Person.js new file mode 100644 index 0000000..2435cd3 --- /dev/null +++ b/assets/js/components/Person.js @@ -0,0 +1,22 @@ +import React from "react"; + +class Person extends React.Component { + render() { + const person = this.props.person; + const githubUrl = `https://github.com/${person.username}`; + + return ( +
+
+ {person.name} +
+
{person.name}
+

{person.location}

+
+
+
+ ); + } +} + +export default Person; diff --git a/assets/js/queries/import_person.js b/assets/js/queries/import_person.js new file mode 100644 index 0000000..60435e7 --- /dev/null +++ b/assets/js/queries/import_person.js @@ -0,0 +1,12 @@ +import gql from "graphql-tag"; + +export default gql ` + mutation importPerson($username: String!) { + importPerson(username: $username) { + username, + name, + location, + avatarUrl + } + } +`; diff --git a/assets/js/queries/list_people.js b/assets/js/queries/list_people.js new file mode 100644 index 0000000..321cbb5 --- /dev/null +++ b/assets/js/queries/list_people.js @@ -0,0 +1,12 @@ +import gql from "graphql-tag"; + +export default gql ` + query { + people{ + username, + name, + location, + avatarUrl + } + } +`; diff --git a/assets/package.json b/assets/package.json index 3199825..dc5f42b 100644 --- a/assets/package.json +++ b/assets/package.json @@ -6,10 +6,14 @@ "watch": "brunch watch --stdin" }, "dependencies": { + "apollo-client-preset": "^1.0.8", "babel-preset-react": "^6.24.1", + "graphql": "^0.13.2", + "graphql-tag": "^2.8.0", "phoenix": "file:../deps/phoenix", "phoenix_html": "file:../deps/phoenix_html", "react": "^16.3.1", + "react-apollo": "^2.1.3", "react-dom": "^16.3.1", "yarn": "^1.5.1" }, diff --git a/assets/yarn.lock b/assets/yarn.lock index f724972..914229a 100644 --- a/assets/yarn.lock +++ b/assets/yarn.lock @@ -2,6 +2,18 @@ # yarn lockfile v1 +"@types/async@2.0.47": + version "2.0.47" + resolved "https://registry.yarnpkg.com/@types/async/-/async-2.0.47.tgz#f49ba1dd1f189486beb6e1d070a850f6ab4bd521" + +"@types/node@^9.4.6": + version "9.6.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.2.tgz#e49ac1adb458835e95ca6487bc20f916b37aff23" + +"@types/zen-observable@^0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.5.3.tgz#91b728599544efbb7386d8b6633693a3c2e7ade5" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -94,6 +106,75 @@ anysort@~1.0: dependencies: anymatch "~1.3.0" +apollo-cache-inmemory@^1.1.7: + version "1.1.12" + resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.1.12.tgz#ab489bf046b3e026556ab28bdebb6e010cac9531" + dependencies: + apollo-cache "^1.1.7" + apollo-utilities "^1.0.11" + graphql-anywhere "^4.1.8" + +apollo-cache@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.1.7.tgz#5817018a2fbfc05a21ba319bd17a3e7538110cc5" + dependencies: + apollo-utilities "^1.0.11" + +apollo-client-preset@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/apollo-client-preset/-/apollo-client-preset-1.0.8.tgz#23bd7176849d0d815f12c648774d009b258a449e" + dependencies: + apollo-cache-inmemory "^1.1.7" + apollo-client "^2.2.2" + apollo-link "^1.0.6" + apollo-link-http "^1.3.1" + graphql-tag "^2.4.2" + +apollo-client@^2.2.2: + version "2.2.8" + resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.2.8.tgz#b604d31ab2d2dd00db3105d8793b93ee02ce567e" + dependencies: + "@types/zen-observable" "^0.5.3" + apollo-cache "^1.1.7" + apollo-link "^1.0.0" + apollo-link-dedup "^1.0.0" + apollo-utilities "^1.0.11" + symbol-observable "^1.0.2" + zen-observable "^0.7.0" + optionalDependencies: + "@types/async" "2.0.47" + +apollo-link-dedup@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/apollo-link-dedup/-/apollo-link-dedup-1.0.8.tgz#8c3028cf32557bd040ab6ba8856f38067bdacead" + dependencies: + apollo-link "^1.2.1" + +apollo-link-http-common@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/apollo-link-http-common/-/apollo-link-http-common-0.2.3.tgz#82ae0d4ff0cdd7c5c8826411d9dd7f7d8049ca46" + dependencies: + apollo-link "^1.2.1" + +apollo-link-http@^1.3.1: + version "1.5.3" + resolved "https://registry.yarnpkg.com/apollo-link-http/-/apollo-link-http-1.5.3.tgz#3aa0d3ecfe5666ef0c360f359c425ff6ea1d285b" + dependencies: + apollo-link "^1.2.1" + apollo-link-http-common "^0.2.3" + +apollo-link@^1.0.0, apollo-link@^1.0.6, apollo-link@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.1.tgz#c120b16059f9bd93401b9f72b94d2f80f3f305d2" + dependencies: + "@types/node" "^9.4.6" + apollo-utilities "^1.0.0" + zen-observable-ts "^0.8.6" + +apollo-utilities@^1.0.0, apollo-utilities@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.0.11.tgz#cd36bfa6e5c04eea2caf0c204a0f38a0ad550802" + aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -1945,6 +2026,22 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.3: version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" +graphql-anywhere@^4.1.8: + version "4.1.8" + resolved "https://registry.yarnpkg.com/graphql-anywhere/-/graphql-anywhere-4.1.8.tgz#23882e6a16ec824febbe5bca40937cdd76c5acdc" + dependencies: + apollo-utilities "^1.0.11" + +graphql-tag@^2.4.2, graphql-tag@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.8.0.tgz#52cdea07a842154ec11a2e840c11b977f9b835ce" + +graphql@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.13.2.tgz#4c740ae3c222823e7004096f832e7b93b2108270" + dependencies: + iterall "^1.2.1" + growl@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" @@ -2021,6 +2118,10 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" +hoist-non-react-statics@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -2321,6 +2422,10 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" +iterall@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7" + js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" @@ -2432,7 +2537,7 @@ lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" -lodash@^4.17.4, lodash@^4.3.0: +lodash@4.17.5, lodash@^4.17.4, lodash@^4.3.0: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" @@ -3036,6 +3141,16 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-apollo@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-2.1.3.tgz#5eb02cdf18cc4bdeb615bda94baedb50354e94e5" + dependencies: + fbjs "^0.8.16" + hoist-non-react-statics "^2.5.0" + invariant "^2.2.2" + lodash "4.17.5" + prop-types "^15.6.0" + react-dom@^16.3.1: version "16.3.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.1.tgz#6a3c90a4fb62f915bdbcf6204422d93a7d4ca573" @@ -3515,6 +3630,10 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +symbol-observable@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + table@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" @@ -3779,3 +3898,13 @@ yargs@~3.10.0: yarn@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.5.1.tgz#e8680360e832ac89521eb80dad3a7bc27a40bab4" + +zen-observable-ts@^0.8.6: + version "0.8.8" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.8.tgz#1a586dc204fa5632a88057f879500e0d2ba06869" + dependencies: + zen-observable "^0.7.0" + +zen-observable@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.7.1.tgz#f84075c0ee085594d3566e1d6454207f126411b3"