Merge branch 'master' into gh-pages
This commit is contained in:
commit
b303df2c12
12 changed files with 143 additions and 25 deletions
10
README.md
10
README.md
|
@ -2,7 +2,13 @@ I created this project because a) I always wished there was a better way to
|
||||||
track the progress of my CubScouts in getting their ranks and b) I wanted to
|
track the progress of my CubScouts in getting their ranks and b) I wanted to
|
||||||
learn graphql with Apollo.
|
learn graphql with Apollo.
|
||||||
|
|
||||||
Right now there is a [demo](https://bobjohnbob.github.io/scouttracker/build/?id=cj54d5gqs6f4e0156y7x8tj0f) (unfortunately subscriptions with graph.cool seem to be somewhat unreliable, so it may not connect/update properly) where you can tick off achievements for a single scout's wolf adventures. I've mostly built this project to learn graphql so I started there, there-fore it's not pretty (yet) but that is what I'll start working on next. Currently the demo is subscribing to live updates from a graph.cool generated API to know which achievements are checked off.
|
Right now there is a
|
||||||
|
[demo](https://bobjohnbob.github.io/scouttracker/build/?id=cj54d5gqs6f4e0156y7x8tj0f)
|
||||||
|
(unfortunately subscriptions with graph.cool seem to be somewhat unreliable, so
|
||||||
|
it may not connect/update properly) where you can tick off achievements for a
|
||||||
|
single scout's wolf adventures. Currently the demo is subscribing to live updates
|
||||||
|
from a graph.cool generated API to know which achievements are checked off.
|
||||||
|
|
||||||
This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
|
This project was bootstrapped with [Create React
|
||||||
|
App](https://github.com/facebookincubator/create-react-app).
|
||||||
|
|
||||||
|
|
40
package-lock.json
generated
40
package-lock.json
generated
|
@ -778,6 +778,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
|
||||||
"integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc="
|
"integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc="
|
||||||
},
|
},
|
||||||
|
"brcast": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/brcast/-/brcast-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-Hm6AjEjr2hg5P/+tfAi7IARUW6mRNweni7ezt7vvOF53qn4++rdJoPsg8dDGS7KcwT2cRDucuFNMRYi3nkCD6Q=="
|
||||||
|
},
|
||||||
"brorand": {
|
"brorand": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
||||||
|
@ -1901,6 +1906,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
||||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
|
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
|
||||||
},
|
},
|
||||||
|
"fast-memoize": {
|
||||||
|
"version": "2.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.2.7.tgz",
|
||||||
|
"integrity": "sha1-8UXFwiA5zt8KHU/2ylkq0CaEcMo="
|
||||||
|
},
|
||||||
"fastparse": {
|
"fastparse": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",
|
||||||
|
@ -2618,6 +2628,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"glamor": {
|
||||||
|
"version": "2.20.30",
|
||||||
|
"resolved": "https://registry.npmjs.org/glamor/-/glamor-2.20.30.tgz",
|
||||||
|
"integrity": "sha512-loENOwfYk24QXdr4Ms3NUFl8cQN5SGJbIUCSnURx5NESb9/VdeNjH3r9XWzpmtTNr1iywcIfsgXdaesbHS7Dzg=="
|
||||||
|
},
|
||||||
|
"glamorous": {
|
||||||
|
"version": "3.23.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/glamorous/-/glamorous-3.23.5.tgz",
|
||||||
|
"integrity": "sha1-SfYTop9kze6AlIZ5xm281AhOX9U="
|
||||||
|
},
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "7.1.2",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||||
|
@ -2815,6 +2835,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz",
|
||||||
"integrity": "sha1-ZouTd26q5V696POtRkswekljYl4="
|
"integrity": "sha1-ZouTd26q5V696POtRkswekljYl4="
|
||||||
},
|
},
|
||||||
|
"html-element-attributes": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-element-attributes/-/html-element-attributes-1.3.0.tgz",
|
||||||
|
"integrity": "sha1-8G69/OIt6XnbggICZcrFQfsX1Pw="
|
||||||
|
},
|
||||||
"html-encoding-sniffer": {
|
"html-encoding-sniffer": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz",
|
||||||
|
@ -2830,6 +2855,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.2.tgz",
|
||||||
"integrity": "sha1-1zvD/0SJQkCIGM5gm/P7DqfvTrc="
|
"integrity": "sha1-1zvD/0SJQkCIGM5gm/P7DqfvTrc="
|
||||||
},
|
},
|
||||||
|
"html-tag-names": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-tag-names/-/html-tag-names-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-9lFolkxanIJnXv2ogoddyyqHXCI="
|
||||||
|
},
|
||||||
"html-webpack-plugin": {
|
"html-webpack-plugin": {
|
||||||
"version": "2.29.0",
|
"version": "2.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.29.0.tgz",
|
||||||
|
@ -5123,6 +5153,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.4.5.tgz",
|
||||||
"integrity": "sha1-4+iVoJcM8U7o+JAROvaBl6vz0LE="
|
"integrity": "sha1-4+iVoJcM8U7o+JAROvaBl6vz0LE="
|
||||||
},
|
},
|
||||||
|
"react-html-attributes": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-html-attributes/-/react-html-attributes-1.4.1.tgz",
|
||||||
|
"integrity": "sha1-l7XscQ2miDNZjIvm+JrENiFoQKU="
|
||||||
|
},
|
||||||
"react-router": {
|
"react-router": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.1.1.tgz",
|
||||||
|
@ -5754,6 +5789,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.1.0.tgz",
|
||||||
"integrity": "sha1-kswUuz2tiSjKVlbDPhmhnyCvXHo="
|
"integrity": "sha1-kswUuz2tiSjKVlbDPhmhnyCvXHo="
|
||||||
},
|
},
|
||||||
|
"svg-tag-names": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg-tag-names/-/svg-tag-names-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-lkGynvcQJe4JTHBD983efZn71Qo="
|
||||||
|
},
|
||||||
"svgo": {
|
"svgo": {
|
||||||
"version": "0.7.2",
|
"version": "0.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://bobjohnbob.github.io/scouttracker/build",
|
"homepage": "https://bobjohnbob.github.io/scouttracker/build",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"glamor": "^2.20.30",
|
||||||
|
"glamorous": "^3.23.5",
|
||||||
"material-ui": "^0.18.6",
|
"material-ui": "^0.18.6",
|
||||||
|
"prop-types": "^15.5.10",
|
||||||
"react": "^15.6.1",
|
"react": "^15.6.1",
|
||||||
"react-apollo": "^1.4.2",
|
"react-apollo": "^1.4.2",
|
||||||
"react-dom": "^15.6.1",
|
"react-dom": "^15.6.1",
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { gql, graphql } from 'react-apollo';
|
import { Div } from 'glamorous';
|
||||||
|
|
||||||
|
const blue = "#00BCD4";
|
||||||
|
const size = 2.6;
|
||||||
|
const size_rem = `${size}rem`;
|
||||||
|
const pad = "0.5rem";
|
||||||
|
|
||||||
export default({
|
export default({
|
||||||
id,
|
id,
|
||||||
|
@ -9,12 +14,36 @@ export default({
|
||||||
description,
|
description,
|
||||||
additionalText,
|
additionalText,
|
||||||
scoutID,
|
scoutID,
|
||||||
mutate
|
completeAchievement,
|
||||||
|
uncompleteAchievement
|
||||||
}) => {
|
}) => {
|
||||||
if(completed) {
|
if(completed) {
|
||||||
return <div className='completed-achievement'>
|
const variables = {
|
||||||
{number}{letter}
|
id: completed.id
|
||||||
</div>;
|
};
|
||||||
|
return <Div
|
||||||
|
onClick={()=>{uncompleteAchievement({variables})}}
|
||||||
|
fontSize={`${size/2}rem`}
|
||||||
|
border={`0.2rem solid ${blue}`}
|
||||||
|
display="inline-flex"
|
||||||
|
color="white"
|
||||||
|
backgroundColor={blue}
|
||||||
|
width={size_rem}
|
||||||
|
height={size_rem}
|
||||||
|
borderRadius={size_rem}
|
||||||
|
margin={pad}
|
||||||
|
cursor="pointer"
|
||||||
|
>
|
||||||
|
<Div
|
||||||
|
display="flex"
|
||||||
|
width={size_rem}
|
||||||
|
height={size_rem}
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="center"
|
||||||
|
>
|
||||||
|
<Div display="inline-flex">{number}{letter}</Div>
|
||||||
|
</Div>
|
||||||
|
</Div>
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const variables = {
|
const variables = {
|
||||||
|
@ -23,8 +52,28 @@ export default({
|
||||||
date: (new Date(Date.now())).toISOString()
|
date: (new Date(Date.now())).toISOString()
|
||||||
};
|
};
|
||||||
|
|
||||||
return <button onClick={() => mutate({variables})} className='achievement'>
|
return <Div
|
||||||
{number}{letter}
|
onClick={()=>{completeAchievement({variables})}}
|
||||||
</button>;
|
fontSize={`${size/2}rem`}
|
||||||
|
border={`0.15rem solid ${blue}`}
|
||||||
|
display="inline-flex"
|
||||||
|
color={blue}
|
||||||
|
width={size_rem}
|
||||||
|
height={size_rem}
|
||||||
|
borderRadius={size_rem}
|
||||||
|
margin={pad}
|
||||||
|
cursor="pointer"
|
||||||
|
>
|
||||||
|
<Div
|
||||||
|
display="flex"
|
||||||
|
width={size_rem}
|
||||||
|
height={size_rem}
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="center"
|
||||||
|
>
|
||||||
|
<Div display="inline-flex">{number}{letter}</Div>
|
||||||
|
</Div>
|
||||||
|
</Div>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {Div} from 'glamorous';
|
||||||
|
import { compose } from 'react-apollo';
|
||||||
import Achievement from './Achievement.js';
|
import Achievement from './Achievement.js';
|
||||||
import CompleteAchievement from '../containers/CompleteAchievement.js';
|
import CompleteAchievement from '../containers/CompleteAchievement.js';
|
||||||
|
import UncompleteAchievement from '../containers/UncompleteAchievement.js';
|
||||||
|
|
||||||
const AchievementButton = CompleteAchievement(Achievement);
|
const AchievementButton = compose(
|
||||||
|
CompleteAchievement,
|
||||||
|
UncompleteAchievement
|
||||||
|
)(Achievement);
|
||||||
|
|
||||||
export default class AchievementList extends React.Component {
|
export default class AchievementList extends React.Component {
|
||||||
|
|
||||||
|
@ -30,9 +36,13 @@ export default class AchievementList extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
const list = [...allAchievements].sort((a, b) => {
|
const list = [...allAchievements].sort((a, b) => {
|
||||||
if (a.number === b.number)
|
if (a.number === b.number) {
|
||||||
return a.letter > b.letter;
|
if(!a.letter) return -1;
|
||||||
return a.number > b.number;
|
if(!b.letter) return 1;
|
||||||
|
|
||||||
|
return a.letter.toLowerCase().localeCompare(b.letter.toLowerCase());
|
||||||
|
}
|
||||||
|
return a.number - b.number;
|
||||||
}).map(achievement => {
|
}).map(achievement => {
|
||||||
const props = {
|
const props = {
|
||||||
key: achievement.id,
|
key: achievement.id,
|
||||||
|
@ -43,9 +53,9 @@ export default class AchievementList extends React.Component {
|
||||||
return <AchievementButton {...props} />
|
return <AchievementButton {...props} />
|
||||||
});
|
});
|
||||||
|
|
||||||
return <div>
|
return <Div disply="flex" padding="0.5rem">
|
||||||
{list}
|
{list}
|
||||||
</div>
|
</Div>
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
|
|
@ -16,7 +16,6 @@ export default class AdventureList extends React.Component {
|
||||||
allAdventures,
|
allAdventures,
|
||||||
completedAdventures
|
completedAdventures
|
||||||
} = this.props;
|
} = this.props;
|
||||||
console.log("completed!: ", completedAdventures);
|
|
||||||
|
|
||||||
if(!allAdventures || !allAdventures.length) {
|
if(!allAdventures || !allAdventures.length) {
|
||||||
return <div> Loading... </div>
|
return <div> Loading... </div>
|
||||||
|
@ -27,7 +26,8 @@ export default class AdventureList extends React.Component {
|
||||||
return map;
|
return map;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const sortedAdventures = [...allAdventures].sort((a,b) => (a.number > b.number));
|
const newArray = [...allAdventures];
|
||||||
|
const sortedAdventures = newArray.sort((a,b) => (parseInt(a.number) - parseInt(b.number)));
|
||||||
|
|
||||||
const [
|
const [
|
||||||
requiredAdventures,
|
requiredAdventures,
|
||||||
|
@ -45,7 +45,6 @@ export default class AdventureList extends React.Component {
|
||||||
});
|
});
|
||||||
|
|
||||||
const optionalAdventureList = optionalAdventures.map(adventure => {
|
const optionalAdventureList = optionalAdventures.map(adventure => {
|
||||||
console.log("ADVENTURE!: ", adventure);
|
|
||||||
const props = {
|
const props = {
|
||||||
key: adventure.id,
|
key: adventure.id,
|
||||||
scoutID: scoutID,
|
scoutID: scoutID,
|
||||||
|
@ -61,7 +60,7 @@ export default class AdventureList extends React.Component {
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
//optionalAdventureList
|
optionalAdventureList
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
@ -17,7 +17,6 @@ export default class ScoutOverview extends React.Component {
|
||||||
const {
|
const {
|
||||||
scoutID,
|
scoutID,
|
||||||
displayName,
|
displayName,
|
||||||
advancementDeadline,
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const appBarProps = {
|
const appBarProps = {
|
||||||
title: displayName,
|
title: displayName,
|
||||||
|
|
|
@ -10,4 +10,6 @@ export default graphql(gql`
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`)
|
`, {
|
||||||
|
name: 'completeAchievement'
|
||||||
|
})
|
||||||
|
|
|
@ -70,7 +70,6 @@ export default graphql(gql`
|
||||||
},
|
},
|
||||||
updateQuery: (prev, response) => {
|
updateQuery: (prev, response) => {
|
||||||
const subscriptionData = response.subscriptionData.data.CompletedAchievement;
|
const subscriptionData = response.subscriptionData.data.CompletedAchievement;
|
||||||
console.log("UPDATE! :", response);
|
|
||||||
|
|
||||||
let updatedAchievements;
|
let updatedAchievements;
|
||||||
const oldAchievements = prev.completed
|
const oldAchievements = prev.completed
|
||||||
|
|
|
@ -49,7 +49,6 @@ export default graphql(gql`
|
||||||
scoutID: params.scoutID
|
scoutID: params.scoutID
|
||||||
},
|
},
|
||||||
updateQuery: (prev, {subscriptionData}) => {
|
updateQuery: (prev, {subscriptionData}) => {
|
||||||
console.log("SubscriptionData: ", subscriptionData);
|
|
||||||
if(!subscriptionData.data) {
|
if(!subscriptionData.data) {
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ export default graphql(gql`
|
||||||
},
|
},
|
||||||
updateQuery: (prev, {subscriptionData}) => {
|
updateQuery: (prev, {subscriptionData}) => {
|
||||||
if(!subscriptionData.data) {
|
if(!subscriptionData.data) {
|
||||||
console.log('no data!');
|
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
console.log('data! : ', prev, ':', subscriptionData);
|
console.log('data! : ', prev, ':', subscriptionData);
|
||||||
|
|
13
src/containers/UncompleteAchievement.js
Normal file
13
src/containers/UncompleteAchievement.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { gql, graphql } from 'react-apollo';
|
||||||
|
|
||||||
|
export default graphql(gql`
|
||||||
|
mutation UnmarkAchievementComplete($id:ID!){
|
||||||
|
deleteCompletedAchievement(
|
||||||
|
id: $id
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, {
|
||||||
|
name: 'uncompleteAchievement'
|
||||||
|
});
|
Loading…
Reference in a new issue