Subscriptions are now working and updating some parts of the view.

This commit is contained in:
John Shaver 2017-07-20 15:32:17 -07:00
parent 8687355932
commit 14ce6df7af
10 changed files with 430 additions and 127 deletions

View file

@ -3,10 +3,11 @@ import { getQueryParamByName } from './utils.js';
import ScoutOverviewCont from './containers/GetScoutData.js'; import ScoutOverviewCont from './containers/GetScoutData.js';
import ScoutOverview from './components/ScoutOverview.js'; import ScoutOverview from './components/ScoutOverview.js';
const ScoutView = ScoutOverviewCont(ScoutOverview);
class App extends Component { class App extends Component {
render() { render() {
const scoutID = getQueryParamByName("id", this.props.slug); const scoutID = getQueryParamByName("id", this.props.slug);
const ScoutView = ScoutOverviewCont(ScoutOverview);
return ( return (
<div className="App"> <div className="App">

View file

@ -1,5 +1,30 @@
import React from 'react'; import React from 'react';
import { gql, graphql } from 'react-apollo';
export default({id, number, description, additionalText}) => { export default({
return <div>{number}</div>; id,
number,
completed,
letter,
description,
additionalText,
scoutID,
mutate
}) => {
if(completed) {
return <div className='completed-achievement'>
{number}{letter}
</div>;
} else {
const variables = {
scoutID,
id,
date: (new Date(Date.now())).toISOString()
};
return <button onClick={() => mutate({variables})} className='achievement'>
{number}{letter}
</button>;
}
}; };

View file

@ -1,22 +1,55 @@
import React from 'react' import React from 'react';
import Achievement from './Achievement.js';
import CompleteAchievement from '../containers/CompleteAchievement.js';
import Achievement from "./Achievement.js"; const AchievementButton = CompleteAchievement(Achievement);
export default ({achievements, id, completed}) => { export default class AchievementList extends React.Component {
console.log("completed: ", completed);
if(!achievements) { componentWillMount() {
this.unsubscribe = this.props.subscribeToAchievements({
scoutID: this.props.scoutID,
adventureID: this.props.adventureID
});
}
render() {
const {
allAchievements,
completedAchievements,
scoutID
} = this.props;
const completedMap = completedAchievements.reduce((map, ach) => {
map[ach.achievement.id] = ach;
return map
}, {});
if(!allAchievements || !allAchievements.length) {
return <div>Loading...</div> return <div>Loading...</div>
} }
const list = [...achievements].sort((a, b) => { const list = [...allAchievements].sort((a, b) => {
if (a.number === b.number) if (a.number === b.number)
return a.letter > b.letter; return a.letter > b.letter;
return a.number > b.number; return a.number > b.number;
}).map(achievement => ( }).map(achievement => {
<Achievement key={achievement.id} {...achievement} /> const props = {
)); key: achievement.id,
completed: completedMap[achievement.id],
scoutID,
...achievement
};
return <AchievementButton {...props} />
});
return <div> return <div>
{list} {list}
</div> </div>
}
componentWillUnmount() {
this.unsubscribe();
}
} }

View file

@ -1,15 +1,28 @@
import React from 'react' import React from 'react'
import GetAchievements from "../containers/GetAchievementsForAdventure.js"; import GetAchievements from '../containers/GetAchievementsForAdventure.js';
import AchievementList from "./AchievementList.js"; import AchievementList from './AchievementList.js';
import {Card, CardHeader} from 'material-ui/Card';
export default ({id, name, number, isRequired, achievements, const AchievementListComp = GetAchievements(AchievementList);
completedAdventures, completedAchievements}) => {
const AchievementListComp = GetAchievements(AchievementList); export default ({
return <div> id,
<div>{name}</div> name,
<AchievementListComp adventureID={id} completed={completedAchievements}/> number,
</div> isRequired,
achievements,
completed,
scoutID
}) => {
const className = `adventure ${completed ? 'completed-adventure' :''}`;
return <Card className={className}>
<CardHeader title={name} />
<AchievementListComp
scoutID = {scoutID}
adventureID={id}
/>
</Card>
} }

View file

@ -1,15 +1,32 @@
import React from "react" import React from 'react';
import { splitFilter } from '../utils.js'; import { splitFilter } from '../utils.js';
import Adventure from './Adventure.js'; import Adventure from './Adventure.js';
export default ({ export default class AdventureList extends React.Component {
componentWillMount() {
this.unsubscribe = this.props.subscribeToAdventures({
scoutID: this.props.scoutID
});
}
render() {
const {
scoutID,
allAdventures, allAdventures,
completedAdventures completedAdventures
}) => { } = this.props;
if(!allAdventures) { console.log("completed!: ", completedAdventures);
if(!allAdventures || !allAdventures.length) {
return <div> Loading... </div> return <div> Loading... </div>
} }
const completedMap = completedAdventures.reduce((map, adv) => {
map[adv.adventure.id] = adv;
return map;
}, {});
const sortedAdventures = [...allAdventures].sort((a,b) => (a.number > b.number)); const sortedAdventures = [...allAdventures].sort((a,b) => (a.number > b.number));
const [ const [
@ -18,15 +35,28 @@ export default ({
] = splitFilter(sortedAdventures, a => a.required); ] = splitFilter(sortedAdventures, a => a.required);
const requiredAdventureList = requiredAdventures.map(adventure => { const requiredAdventureList = requiredAdventures.map(adventure => {
return <Adventure key={adventure.id} {...adventure} />; const props = {
key: adventure.id,
scoutID: scoutID,
completed: completedMap[adventure.id],
...adventure
}
return <Adventure {...props} />;
}); });
const optionalAdventureList = optionalAdventures.map(adventure => { const optionalAdventureList = optionalAdventures.map(adventure => {
return <Adventure key={adventure.id} {...adventure} />; console.log("ADVENTURE!: ", adventure);
const props = {
key: adventure.id,
scoutID: scoutID,
completed: completedMap[adventure.id],
...adventure
}
return <Adventure {...props} />;
}); });
return <div> return <div className="adventure-list" >
<div> <div >
{requiredAdventureList} {requiredAdventureList}
</div> </div>
<div> <div>
@ -35,5 +65,10 @@ export default ({
} }
</div> </div>
</div>; </div>;
}
componentWillUnmount() {
this.unsubscribe();
}
} }

View file

@ -3,25 +3,38 @@ import AllAdventures from '../containers/GetAllAdventures.js'
import AdventureList from './AdventureList.js'; import AdventureList from './AdventureList.js';
import AppBar from 'material-ui/AppBar'; import AppBar from 'material-ui/AppBar';
export default ({ const AdventureListComp = AllAdventures(AdventureList);
export default class ScoutOverview extends React.Component {
componentWillMount() {
this.unsubscribe = this.props.subscribeToData({
scoutID: this.props.scoutID
});
}
render() {
const {
scoutID, scoutID,
displayName, displayName,
advancementDeadline, advancementDeadline,
completedAdventures, } = this.props;
completedAchievements
}) => {
const appBarProps = { const appBarProps = {
title: displayName, title: displayName,
showMenuIconButton: false showMenuIconButton: false
} }
const AdventureListComp = AllAdventures(AdventureList);
console.log(displayName)
return ( return (
<div> <div>
<AppBar {...appBarProps} /> <AppBar {...appBarProps} />
<AdventureListComp <AdventureListComp
{...{scoutID, completedAdventures, completedAchievements}} scoutID = {scoutID}
/> />
</div> </div>
); );
}
componentWillUnmount() {
this.unsubscribe();
}
} }

View file

@ -0,0 +1,13 @@
import { gql, graphql } from 'react-apollo';
export default graphql(gql`
mutation MarkAchievementComplete($id:ID!, $scoutID:ID!, $date:DateTime!){
createCompletedAchievement(
completedAt: $date
achievementId: $id
scoutId: $scoutID
) {
id
}
}
`)

View file

@ -1,32 +1,106 @@
import { gql, graphql } from 'react-apollo'; import { gql, graphql } from 'react-apollo';
export default graphql(gql` export default graphql(gql`
query GetAchievementsForAdventure($adventureID:ID!){ query GetAchievementsForAdventure($adventureID:ID! $scoutID:ID!){
allAchievements(filter: { all: allAchievements(filter: {
adventure: { adventure: {id: $adventureID}
id: $adventureID }) {
id
number
letter
description
additionalText
}
completed: allCompletedAchievements(filter:{
scout: {id: $scoutID}
achievement: {
adventure: {id: $adventureID}
} }
}) { }) {
id, id
number, completedAt
letter, achievement {
description, id
additionalText }
} }
} }
`,{ `,{
options: ({adventureID}) => { options: ({adventureID, scoutID}) => ({variables: { adventureID, scoutID }}),
return {
variables: {
adventureID
}
};
},
props: ({ownProps, data}) => { props: ({ownProps, data}) => {
return data.allAchievements ? { const {
achievements: data.allAchievements, subscribeToMore,
...ownProps all,
} : {...ownProps} completed
} = data;
const subscribeToAchievements = params => {
return subscribeToMore({
document: gql`
subscription subscribeToCompAch($scoutID:ID!, $adventureID:ID!){
CompletedAchievement(filter: {
mutation_in: [UPDATED, CREATED, DELETED]
node: {
scout: {
id: $scoutID
}
achievement: {
adventure: {
id: $adventureID
}
}
}
}){
mutation
node {
id
completedAt
achievement {
id
}
}
previousValues {
id
}
}
}
`,
variables: {
scoutID: params.scoutID,
adventureID: params.adventureID
},
updateQuery: (prev, response) => {
const subscriptionData = response.subscriptionData.data.CompletedAchievement;
console.log("UPDATE! :", response);
let updatedAchievements;
const oldAchievements = prev.completed
if(subscriptionData.mutation === 'DELETED') {
updatedAchievements = oldAchievements.filter(ach => (
ach.id !== subscriptionData.previousValues.id
));
} else {
const updatedID = subscriptionData.node.id;
updatedAchievements = [...oldAchievements];
let index = oldAchievements.findIndex(adventure => (
adventure.id === updatedID
));
if(index === -1) index = updatedAchievements.length;
updatedAchievements[index] = subscriptionData.node;
}
return Object.assign({}, prev, {
completed: updatedAchievements
});
}
});
};
return {
allAchievements: all || [],
completedAchievements: completed || [],
subscribeToAchievements,
...ownProps
};
} }
}); });

View file

@ -1,22 +1,90 @@
import { gql, graphql } from 'react-apollo'; import { gql, graphql } from 'react-apollo';
export default graphql(gql` export default graphql(gql`
query GetAllAdventures{ query GetAllAdventures($scoutID:ID!){
allAdventures { allAdventures: allAdventures {
name, name
number, number
required, required
id id
} }
completedAdventures: allCompletedAdventures(filter:{
scout: { id: $scoutID }
}) {
id
signer { id }
adventure { id }
}
} }
`,{ `,{
props: ({ownProps, data}) => ( options: ({scoutID}) => ({variables: {scoutID}}),
data.allAdventures ? { props: ({ownProps, data}) => {
allAdventures: data.allAdventures, const {
subscribeToMore,
completedAdventures,
allAdventures
} = data;
const subscribeToAdventures = params => {
return subscribeToMore({
document: gql`
subscription subscribeToCompletedAdventures($scoutID:ID!){
CompletedAdventure(filter: {
mutation_in: [UPDATED, CREATED, DELETED]
node: {
scout: {
id: $scoutID
}
}
}){
mutation
node {
id
signer { id }
adventure { id }
}
}
}
`,
variables: {
scoutID: params.scoutID
},
updateQuery: (prev, {subscriptionData}) => {
console.log("SubscriptionData: ", subscriptionData);
if(!subscriptionData.data) {
return prev;
}
let updatedAdventures;
const updatedID = subscriptionData.node.id;
const oldAdventures = prev.completedAdventures;
if(subscriptionData.mutation === "DELETE") {
updatedAdventures = oldAdventures.filter(adventure => (
adventure.id !== updatedID
));
} else {
updatedAdventures = [...oldAdventures];
let index = oldAdventures.findIndex(adventure => (
adventure.id === updatedID
));
if(index === -1) index = updatedAdventures.length;
updatedAdventures[index] = subscriptionData;
}
return Object.assign({}, prev, {
completedAdventures: updatedAdventures
});
}
});
};
return {
allAdventures: allAdventures || [],
completedAdventures: completedAdventures || [],
subscribeToAdventures,
...ownProps ...ownProps
} : {...ownProps}) };
}
}); });

View file

@ -5,29 +5,57 @@ export default graphql(gql`
Scout(id: $scoutID) { Scout(id: $scoutID) {
displayName displayName
advancementDeadline advancementDeadline
completedAdventures {
id
name
}
completedAchievements {
id
number
letter
}
} }
} }
`,{ `,{
options : ({scoutID}) => ({variables: {scoutID}}), options : ({scoutID}) => ({variables: {scoutID}}),
props: ({ ownProps, data }) => ( name: 'scoutData',
data.Scout ? { props: ({ ownProps, data, scoutData }) => {
scoutID: ownProps.scoutID, const subscribeToData = params => {
displayName: data.Scout.displayName, return scoutData.subscribeToMore({
advancementDeadline: data.Scout.advancementDeadline, document: gql`
completedAdventures: data.Scout.completedAdventures, subscription subscribeToScoutData($scoutID:ID!){
completedAchievements: data.Scout.completedAchievements Scout(filter: {
} : { mutation_in: [UPDATED]
scoutID: ownProps.scoutID node: {
id: $scoutID
}
}) {
mutation
node {
displayName
advancementDeadline
}
}
}
`,
variables: {
scoutID: params.scoutID
},
updateQuery: (prev, {subscriptionData}) => {
if(!subscriptionData.data) {
console.log('no data!');
return prev;
}
console.log('data! : ', prev, ':', subscriptionData);
return Object.assign({}, prev, {
Scout: subscriptionData.data.Scout.node
});
}
});
};
return scoutData.Scout ? {
scoutID: ownProps.scoutID,
displayName: scoutData.Scout.displayName,
advancementDeadline: scoutData.Scout.advancementDeadline,
subscribeToData,
...ownProps
} : {
scoutID: ownProps.scoutID,
subscribeToData,
...ownProps
}
} }
)
}); });