diff --git a/src/App.js b/src/App.js
index 771bea3..80a5ba0 100644
--- a/src/App.js
+++ b/src/App.js
@@ -3,10 +3,11 @@ import { getQueryParamByName } from './utils.js';
import ScoutOverviewCont from './containers/GetScoutData.js';
import ScoutOverview from './components/ScoutOverview.js';
+const ScoutView = ScoutOverviewCont(ScoutOverview);
+
class App extends Component {
render() {
const scoutID = getQueryParamByName("id", this.props.slug);
- const ScoutView = ScoutOverviewCont(ScoutOverview);
return (
diff --git a/src/components/Achievement.js b/src/components/Achievement.js
index 7aa9e8a..a3f9c58 100644
--- a/src/components/Achievement.js
+++ b/src/components/Achievement.js
@@ -1,5 +1,30 @@
import React from 'react';
+import { gql, graphql } from 'react-apollo';
-export default({id, number, description, additionalText}) => {
- return
{number}
;
+export default({
+ id,
+ number,
+ completed,
+ letter,
+ description,
+ additionalText,
+ scoutID,
+ mutate
+}) => {
+ if(completed) {
+ return
+ {number}{letter}
+
;
+ } else {
+
+ const variables = {
+ scoutID,
+ id,
+ date: (new Date(Date.now())).toISOString()
+ };
+
+ return
;
+ }
};
diff --git a/src/components/AchievementList.js b/src/components/AchievementList.js
index 56080d1..76fd7b6 100644
--- a/src/components/AchievementList.js
+++ b/src/components/AchievementList.js
@@ -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}) => {
- console.log("completed: ", completed);
- if(!achievements) {
- return
Loading...
+export default class AchievementList extends React.Component {
+
+ componentWillMount() {
+ this.unsubscribe = this.props.subscribeToAchievements({
+ scoutID: this.props.scoutID,
+ adventureID: this.props.adventureID
+ });
}
-
- const list = [...achievements].sort((a, b) => {
- if (a.number === b.number)
- return a.letter > b.letter;
- return a.number > b.number;
- }).map(achievement => (
-
- ));
-
- return
- {list}
-
+
+ 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
Loading...
+ }
+
+ const list = [...allAchievements].sort((a, b) => {
+ if (a.number === b.number)
+ return a.letter > b.letter;
+ return a.number > b.number;
+ }).map(achievement => {
+ const props = {
+ key: achievement.id,
+ completed: completedMap[achievement.id],
+ scoutID,
+ ...achievement
+ };
+ return
+ });
+
+ return
+ {list}
+
+ }
+
+ componentWillUnmount() {
+ this.unsubscribe();
+ }
+
}
diff --git a/src/components/Adventure.js b/src/components/Adventure.js
index d2f6727..da4b043 100644
--- a/src/components/Adventure.js
+++ b/src/components/Adventure.js
@@ -1,15 +1,28 @@
import React from 'react'
-import GetAchievements from "../containers/GetAchievementsForAdventure.js";
-import AchievementList from "./AchievementList.js";
+import GetAchievements from '../containers/GetAchievementsForAdventure.js';
+import AchievementList from './AchievementList.js';
+import {Card, CardHeader} from 'material-ui/Card';
-export default ({id, name, number, isRequired, achievements,
- completedAdventures, completedAchievements}) => {
+const AchievementListComp = GetAchievements(AchievementList);
- const AchievementListComp = GetAchievements(AchievementList);
- return
+export default ({
+ id,
+ name,
+ number,
+ isRequired,
+ achievements,
+ completed,
+ scoutID
+}) => {
+
+ const className = `adventure ${completed ? 'completed-adventure' :''}`;
+ return
+
+
+
}
diff --git a/src/components/AdventureList.js b/src/components/AdventureList.js
index 76439f8..180f9b9 100644
--- a/src/components/AdventureList.js
+++ b/src/components/AdventureList.js
@@ -1,39 +1,74 @@
-import React from "react"
+import React from 'react';
import { splitFilter } from '../utils.js';
import Adventure from './Adventure.js';
-export default ({
- allAdventures,
- completedAdventures
-}) => {
- if(!allAdventures) {
- return
Loading...
+export default class AdventureList extends React.Component {
+
+ componentWillMount() {
+ this.unsubscribe = this.props.subscribeToAdventures({
+ scoutID: this.props.scoutID
+ });
}
- const sortedAdventures = [...allAdventures].sort((a,b) => (a.number > b.number));
+ render() {
+ const {
+ scoutID,
+ allAdventures,
+ completedAdventures
+ } = this.props;
+ console.log("completed!: ", completedAdventures);
- const [
- requiredAdventures,
- optionalAdventures
- ] = splitFilter(sortedAdventures, a => a.required);
+ if(!allAdventures || !allAdventures.length) {
+ return
Loading...
+ }
- const requiredAdventureList = requiredAdventures.map(adventure => {
- return
;
- });
+ const completedMap = completedAdventures.reduce((map, adv) => {
+ map[adv.adventure.id] = adv;
+ return map;
+ }, {});
+
+ const sortedAdventures = [...allAdventures].sort((a,b) => (a.number > b.number));
- const optionalAdventureList = optionalAdventures.map(adventure => {
- return
;
- });
+ const [
+ requiredAdventures,
+ optionalAdventures
+ ] = splitFilter(sortedAdventures, a => a.required);
- return
-
- {requiredAdventureList}
-
-
- {
- //optionalAdventureList
+ const requiredAdventureList = requiredAdventures.map(adventure => {
+ const props = {
+ key: adventure.id,
+ scoutID: scoutID,
+ completed: completedMap[adventure.id],
+ ...adventure
}
-
-
;
+ return
;
+ });
+
+ const optionalAdventureList = optionalAdventures.map(adventure => {
+ console.log("ADVENTURE!: ", adventure);
+ const props = {
+ key: adventure.id,
+ scoutID: scoutID,
+ completed: completedMap[adventure.id],
+ ...adventure
+ }
+ return
;
+ });
+
+ return
+
+ {requiredAdventureList}
+
+
+ {
+ //optionalAdventureList
+ }
+
+
;
+ }
+
+ componentWillUnmount() {
+ this.unsubscribe();
+ }
}
diff --git a/src/components/ScoutOverview.js b/src/components/ScoutOverview.js
index b969bd0..dc6cfe2 100644
--- a/src/components/ScoutOverview.js
+++ b/src/components/ScoutOverview.js
@@ -3,25 +3,38 @@ import AllAdventures from '../containers/GetAllAdventures.js'
import AdventureList from './AdventureList.js';
import AppBar from 'material-ui/AppBar';
-export default ({
- scoutID,
- displayName,
- advancementDeadline,
- completedAdventures,
- completedAchievements
-}) => {
- const appBarProps = {
- title: displayName,
- showMenuIconButton: false
+const AdventureListComp = AllAdventures(AdventureList);
+
+export default class ScoutOverview extends React.Component {
+
+ componentWillMount() {
+ this.unsubscribe = this.props.subscribeToData({
+ scoutID: this.props.scoutID
+ });
}
- const AdventureListComp = AllAdventures(AdventureList);
- console.log(displayName)
- return (
-
- );
+
+ render() {
+ const {
+ scoutID,
+ displayName,
+ advancementDeadline,
+ } = this.props;
+ const appBarProps = {
+ title: displayName,
+ showMenuIconButton: false
+ }
+ return (
+
+ );
+ }
+
+ componentWillUnmount() {
+ this.unsubscribe();
+ }
+
}
diff --git a/src/containers/CompleteAchievement.js b/src/containers/CompleteAchievement.js
new file mode 100644
index 0000000..a289431
--- /dev/null
+++ b/src/containers/CompleteAchievement.js
@@ -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
+ }
+ }
+`)
diff --git a/src/containers/GetAchievementsForAdventure.js b/src/containers/GetAchievementsForAdventure.js
index 2df18ea..40423ce 100644
--- a/src/containers/GetAchievementsForAdventure.js
+++ b/src/containers/GetAchievementsForAdventure.js
@@ -1,32 +1,106 @@
import { gql, graphql } from 'react-apollo';
export default graphql(gql`
- query GetAchievementsForAdventure($adventureID:ID!){
- allAchievements(filter: {
- adventure: {
- id: $adventureID
+ query GetAchievementsForAdventure($adventureID:ID! $scoutID:ID!){
+ all: allAchievements(filter: {
+ adventure: {id: $adventureID}
+ }) {
+ id
+ number
+ letter
+ description
+ additionalText
+ }
+ completed: allCompletedAchievements(filter:{
+ scout: {id: $scoutID}
+ achievement: {
+ adventure: {id: $adventureID}
}
}) {
- id,
- number,
- letter,
- description,
- additionalText
+ id
+ completedAt
+ achievement {
+ id
+ }
}
}
`,{
- options: ({adventureID}) => {
- return {
- variables: {
- adventureID
- }
- };
- },
+ options: ({adventureID, scoutID}) => ({variables: { adventureID, scoutID }}),
props: ({ownProps, data}) => {
- return data.allAchievements ? {
- achievements: data.allAchievements,
- ...ownProps
- } : {...ownProps}
+ const {
+ subscribeToMore,
+ all,
+ 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
+ };
}
});
diff --git a/src/containers/GetAllAdventures.js b/src/containers/GetAllAdventures.js
index 504de45..2d0e6bf 100644
--- a/src/containers/GetAllAdventures.js
+++ b/src/containers/GetAllAdventures.js
@@ -1,22 +1,90 @@
import { gql, graphql } from 'react-apollo';
export default graphql(gql`
- query GetAllAdventures{
- allAdventures {
- name,
- number,
- required,
+ query GetAllAdventures($scoutID:ID!){
+ allAdventures: allAdventures {
+ name
+ number
+ required
id
}
+ completedAdventures: allCompletedAdventures(filter:{
+ scout: { id: $scoutID }
+ }) {
+ id
+ signer { id }
+ adventure { id }
+ }
}
`,{
- props: ({ownProps, data}) => (
- data.allAdventures ? {
- allAdventures: data.allAdventures,
+ options: ({scoutID}) => ({variables: {scoutID}}),
+ props: ({ownProps, data}) => {
+ 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})
+ };
+ }
});
-
-
-
-
diff --git a/src/containers/GetScoutData.js b/src/containers/GetScoutData.js
index 8f71292..575a189 100644
--- a/src/containers/GetScoutData.js
+++ b/src/containers/GetScoutData.js
@@ -5,29 +5,57 @@ export default graphql(gql`
Scout(id: $scoutID) {
displayName
advancementDeadline
- completedAdventures {
- id
- name
- }
- completedAchievements {
- id
- number
- letter
- }
}
}
`,{
options : ({scoutID}) => ({variables: {scoutID}}),
- props: ({ ownProps, data }) => (
- data.Scout ? {
+ name: 'scoutData',
+ props: ({ ownProps, data, scoutData }) => {
+ const subscribeToData = params => {
+ return scoutData.subscribeToMore({
+ document: gql`
+ subscription subscribeToScoutData($scoutID:ID!){
+ Scout(filter: {
+ mutation_in: [UPDATED]
+ 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: data.Scout.displayName,
- advancementDeadline: data.Scout.advancementDeadline,
- completedAdventures: data.Scout.completedAdventures,
- completedAchievements: data.Scout.completedAchievements
+ displayName: scoutData.Scout.displayName,
+ advancementDeadline: scoutData.Scout.advancementDeadline,
+ subscribeToData,
+ ...ownProps
} : {
- scoutID: ownProps.scoutID
+ scoutID: ownProps.scoutID,
+ subscribeToData,
+ ...ownProps
}
- )
+ }
});
+