├── .meteor
├── .gitignore
├── release
├── platforms
├── .id
├── .finished-upgraders
├── packages
└── versions
├── .babelrc
├── client
└── main.js
├── .gitignore
├── imports
├── client
│ ├── modules
│ │ └── core
│ │ │ ├── reducers
│ │ │ ├── index.js
│ │ │ └── core.js
│ │ │ ├── actions
│ │ │ ├── index.js
│ │ │ └── toast.js
│ │ │ ├── index.js
│ │ │ ├── containers
│ │ │ ├── mainLayout.js
│ │ │ ├── view_home.js
│ │ │ └── toast.js
│ │ │ ├── routes.js
│ │ │ └── components
│ │ │ ├── toast.js
│ │ │ ├── mainLayout.js
│ │ │ └── view_home.js
│ ├── main.js
│ └── configs
│ │ └── context.js
├── lib
│ └── collections.js
└── server
│ ├── main.js
│ └── api
│ ├── mediaGallery
│ └── schema.js
│ ├── poi
│ └── schema.js
│ ├── schema.js
│ └── destination
│ └── schema.js
├── server
└── main.js
├── package.json
└── README.md
/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@1.4.1.1
2 |
--------------------------------------------------------------------------------
/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [ "meteor" ]
3 | }
--------------------------------------------------------------------------------
/client/main.js:
--------------------------------------------------------------------------------
1 | import '../imports/client/main';
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | settings.json
3 | startup.sh
4 | .idea/
--------------------------------------------------------------------------------
/imports/client/modules/core/reducers/index.js:
--------------------------------------------------------------------------------
1 |
2 | import core from './core';
3 |
4 | export default {
5 | core
6 | };
--------------------------------------------------------------------------------
/server/main.js:
--------------------------------------------------------------------------------
1 | import { Meteor } from 'meteor/meteor';
2 | import '/imports/server/main';
3 |
4 | Meteor.startup(() => {
5 |
6 | });
7 |
--------------------------------------------------------------------------------
/imports/client/modules/core/actions/index.js:
--------------------------------------------------------------------------------
1 | import toast from './toast';
2 |
3 |
4 | const actions = {
5 | toast
6 | };
7 |
8 |
9 | export default actions;
10 |
--------------------------------------------------------------------------------
/imports/client/modules/core/index.js:
--------------------------------------------------------------------------------
1 |
2 | import routes from './routes';
3 | import actions from './actions';
4 | import reducers from './reducers';
5 |
6 |
7 | export default {
8 | routes,
9 | actions,
10 | reducers
11 | };
--------------------------------------------------------------------------------
/imports/lib/collections.js:
--------------------------------------------------------------------------------
1 | import {Mongo} from 'meteor/mongo';
2 |
3 | export const MediaGallery = new Mongo.Collection('mediaGallery');
4 | export const Destination = new Mongo.Collection('destination');
5 | export const Poi = new Mongo.Collection('poi');
6 |
--------------------------------------------------------------------------------
/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | 7n1xegljkhlggns11a
--------------------------------------------------------------------------------
/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 | 1.2.0-standard-minifiers-package
10 | 1.2.0-meteor-platform-split
11 | 1.2.0-cordova-changes
12 | 1.2.0-breaking-changes
13 | 1.3.0-split-minifiers-package
14 | 1.4.0-remove-old-dev-bundle-link
15 | 1.4.1-add-shell-server-package
--------------------------------------------------------------------------------
/imports/client/main.js:
--------------------------------------------------------------------------------
1 | import {initContext} from './configs/context';
2 | import {createApp} from 'mantra-core';
3 | import injectTapEventPlugin from 'react-tap-event-plugin';
4 |
5 |
6 | //modules
7 | import coreModule from './modules/core';
8 |
9 |
10 | const reducers = ({
11 | ...coreModule.reducers
12 | });
13 |
14 |
15 | // init context
16 | const context = initContext({ reducers });
17 |
18 | //create client
19 | const app = createApp(context);
20 | app.loadModule(coreModule);
21 |
22 | app.init();
23 | injectTapEventPlugin();
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/imports/client/modules/core/containers/mainLayout.js:
--------------------------------------------------------------------------------
1 | import {useDeps, composeAll, compose} from 'mantra-core';
2 | import mainLayout from '../components/mainLayout';
3 |
4 |
5 | const onPropsChange = ({ context }, onData) => {
6 | //we need to pass the Store & Client to get ApolloProvider working...
7 | const { Client, Store } = context();
8 | onData(null, {
9 | client: Client,
10 | store: Store
11 | });
12 | };
13 |
14 |
15 | export default composeAll(
16 | compose(onPropsChange),
17 | useDeps()
18 | )(mainLayout);
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/imports/server/main.js:
--------------------------------------------------------------------------------
1 |
2 | import {Schema} from './api/schema';
3 | import {Resolvers} from './api/schema';
4 | //import Connectors from './data/connectors';
5 | import { createApolloServer } from 'meteor/apollo';
6 | import { makeExecutableSchema } from 'graphql-tools';
7 |
8 |
9 |
10 | const executableSchema = makeExecutableSchema({
11 | typeDefs: Schema,
12 | resolvers: Resolvers,
13 | //connectors: Connectors,
14 | printErrors: true, // optional
15 | allowUndefinedInResolve: true // optional
16 | });
17 |
18 |
19 | createApolloServer({
20 | graphiql: true,
21 | pretty: true,
22 | schema: executableSchema
23 | });
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/imports/client/modules/core/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {FlowRouter} from 'meteor/kadira:flow-router';
3 | import {mount} from 'react-mounter';
4 |
5 | //mainLayout is the main view...
6 | import MainLayout from './containers/mainLayout';
7 | import Home from './containers/view_home';
8 |
9 |
10 |
11 | export default function (injectDeps) {
12 |
13 | const MainLayoutCtx = injectDeps(MainLayout);
14 |
15 |
16 | // Move these as a module and call this from a main file
17 | FlowRouter.route('/home', {
18 | name: 'home',
19 | action({}) {
20 | mount(MainLayoutCtx, {
21 | content: () => ()
22 | });
23 | }
24 | });
25 |
26 | };
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/imports/client/modules/core/reducers/core.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | const initialState = {
4 | //important to set defaults...
5 | toastOpen: false,
6 | message: "",
7 | someMediaImage: { name: "", cdnUrl: "" }
8 | };
9 |
10 |
11 | export function core(state = initialState, action = {}) {
12 | //picks up a dispatched event.. and updates the Redux State accordingly...
13 | switch (action.type) {
14 | case "TOAST_SWITCH":
15 | return {
16 | ...state,
17 | toastOpen: action.toastOpen,
18 | message: action.message
19 | };
20 | case "UPDATE_MEDIA":
21 | return {
22 | ...state,
23 | someMediaImage: action.someMediaImage
24 | };
25 | default:
26 | return state;
27 | }
28 | }
29 |
30 |
31 | export default core;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "maps",
3 | "private": true,
4 | "scripts": {
5 | "start": "meteor run"
6 | },
7 | "dependencies": {
8 | "apollo-client": "^0.4.12",
9 | "apollo-server": "^0.2.5",
10 | "body-parser": "^1.15.2",
11 | "express": "^4.14.0",
12 | "graphql": "^0.6.2",
13 | "graphql-tag": "^0.1.11",
14 | "graphql-tools": "^0.6.5",
15 | "lodash": "^4.15.0",
16 | "mantra-core": "^1.7.0",
17 | "material-ui": "^0.15.4",
18 | "meteor-node-stubs": "~0.2.0",
19 | "react": "^15.3.0",
20 | "react-apollo": "^0.4.7",
21 | "react-dom": "^15.3.0",
22 | "react-if": "^2.1.0",
23 | "react-komposer-plus": "^2.2.3",
24 | "react-mounter": "^1.2.0",
25 | "react-redux": "^4.4.5",
26 | "react-tap-event-plugin": "^1.0.0",
27 | "redux": "^3.5.2",
28 | "redux-logger": "^2.6.1",
29 | "redux-thunk": "^2.1.0"
30 | },
31 | "devDependencies": {
32 | "babel-preset-meteor": "^6.12.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/imports/server/api/mediaGallery/schema.js:
--------------------------------------------------------------------------------
1 | import { MediaGallery } from '/imports/lib/collections';
2 | import {check} from 'meteor/check';
3 |
4 |
5 | export const schema = [`
6 |
7 | type MediaImage {
8 | _id: String
9 | name: String
10 | cdnUrl: String
11 | originalUrl: String
12 | size: Int
13 | uuid: String
14 | }
15 |
16 | `];
17 |
18 |
19 | export const resolvers = {
20 | Query: {
21 | async allMediaImages(root, args) {
22 | return MediaGallery.find().fetch();
23 | },
24 | async mediaImage(root, args) {
25 | return MediaGallery.find().fetch();
26 | }
27 | },
28 | Mutation: {
29 | async addMediaImage(root, { name, cdnUrl }) {
30 | check(name, String);
31 | check(cdnUrl, String);
32 | console.log("in mutation....");
33 | const id = MediaGallery.insert({ name: name, cdnUrl: cdnUrl });
34 | return MediaGallery.findOne(id);
35 | }
36 | }
37 | };
--------------------------------------------------------------------------------
/imports/server/api/poi/schema.js:
--------------------------------------------------------------------------------
1 | import { Poi, MediaGallery } from '/imports/lib/collections';
2 | import {check} from 'meteor/check';
3 |
4 |
5 | export const schema = [`
6 |
7 | type Poi {
8 | _id: String
9 | type: String
10 | region: String
11 | title: String
12 | subtitle: String
13 | shortDescription: String
14 | description: String
15 | phone: String
16 | mail: String
17 | iconName: String
18 | lat: Float
19 | lng: Float
20 | mainImage: MediaImage
21 | }
22 |
23 | `];
24 |
25 |
26 | export const resolvers = {
27 | Query: {
28 | async allPois(root, {}) {
29 | //get the pois
30 | return Poi.find().fetch();
31 | },
32 | async poiForRegion(root, {region}) {
33 | //get the pois for the provided region...
34 | return Poi.find({region: region}).fetch();
35 | }
36 | },
37 | Poi: {
38 | mainImage: ({mainImage}) => mainImage
39 | }
40 | };
--------------------------------------------------------------------------------
/imports/server/api/schema.js:
--------------------------------------------------------------------------------
1 | import { merge } from 'lodash';
2 |
3 |
4 | import { schema as mediaGallerySchema, resolvers as mediaGalleryResolver } from './mediaGallery/schema';
5 | import { schema as poiSchema, resolvers as poiResolver } from './poi/schema';
6 | import { schema as destinationSchema, resolvers as destinationResolver } from './destination/schema';
7 |
8 |
9 | const rootSchema = [`
10 |
11 | type Query {
12 | allMediaImages: [MediaImage]
13 | mediaImage(id: String): MediaImage
14 | allPois: [Poi]
15 | poiForRegion(region: String): [Poi]
16 | destination(slug: String): Destination
17 | }
18 |
19 | type Mutation {
20 | addMediaImage(name: String, cdnUrl: String): MediaImage
21 | }
22 |
23 | schema {
24 | query: Query
25 | mutation: Mutation
26 | }
27 |
28 | `];
29 |
30 | export const Schema = [...rootSchema, ...mediaGallerySchema, ...poiSchema, ...destinationSchema];
31 | export const Resolvers = merge(mediaGalleryResolver, poiResolver, destinationResolver);
32 |
33 |
--------------------------------------------------------------------------------
/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-base@1.0.4 # Packages every Meteor app needs to have
8 | mobile-experience@1.0.4 # Packages for a great mobile UX
9 | mongo@1.1.12 # The database Meteor supports right now
10 | blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views
11 | reactive-var@1.0.10 # Reactive variable for tracker
12 | jquery@1.11.9 # Helpful client-side library
13 | tracker@1.1.0 # Meteor's client-side reactive programming library
14 |
15 | standard-minifier-css@1.2.0 # CSS minifier run for production mode
16 | standard-minifier-js@1.2.0 # JS minifier run for production mode
17 | es5-shim@4.6.14 # ECMAScript 5 compatibility for older browsers.
18 | ecmascript@0.5.8 # Enable ECMAScript2015+ syntax in app code
19 |
20 | shell-server@0.2.1
21 | kadira:flow-router
22 | apollo@0.1.0-beta_3
--------------------------------------------------------------------------------
/imports/server/api/destination/schema.js:
--------------------------------------------------------------------------------
1 | import { Poi, Destination } from '/imports/lib/collections';
2 | import {check} from 'meteor/check';
3 |
4 |
5 | export const schema = [`
6 |
7 | type GroundImage {
8 | image: String
9 | north: Float
10 | south: Float
11 | east: Float
12 | west: Float
13 | }
14 |
15 | type Destination {
16 | _id: String
17 | slug: String
18 | title: String
19 | subtitle: String
20 | mainImage: MediaImage
21 | groundImage: GroundImage
22 | pois: [Poi]
23 | }
24 |
25 | `];
26 |
27 |
28 | export const resolvers = {
29 | Query: {
30 | async destination(root, { slug }) {
31 | console.log(slug);
32 | console.log(Destination.findOne({slug: slug}));
33 | return Destination.findOne({slug: slug});
34 | }
35 | },
36 | Destination: {
37 | groundImage: ({ groundImage }) => groundImage,
38 | mainImage: ({mainImage}) => mainImage,
39 | pois: ({slug}) => {
40 | console.log(slug);
41 | return Poi.find({region: slug}).fetch();
42 | }
43 | }
44 | };
--------------------------------------------------------------------------------
/imports/client/modules/core/components/toast.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import Snackbar from 'material-ui/Snackbar';
3 |
4 |
5 |
6 | const Toast = ({toastOpen, message, closeToast}) => {
7 |
8 | const _closeToast = () => {
9 | // the => means the scope of variables belongs this component
10 | closeToast();
11 |
12 | //this call the action
13 | //which then dispatches an event..
14 | //which is picked up by the reducer, which updates the state.
15 | //state is passed as a prop (toastOpen / message) from the container..
16 | //phew...
17 | };
18 |
19 |
20 | return (
21 |
22 |
28 |
29 | );
30 | };
31 |
32 |
33 |
34 | Toast.propTypes = {
35 | allPois: React.PropTypes.array,
36 | hasErrors: React.PropTypes.bool,
37 | loading: React.PropTypes.bool,
38 | toastOpen: React.PropTypes.bool,
39 | message: PropTypes.string,
40 | closeToast: PropTypes.func
41 | };
42 |
43 |
44 | export default Toast;
45 |
--------------------------------------------------------------------------------
/imports/client/configs/context.js:
--------------------------------------------------------------------------------
1 | import * as Collections from '/imports/lib/collections';
2 | import {Meteor} from 'meteor/meteor';
3 | import { meteorClientConfig } from 'meteor/apollo';
4 | import ApolloClient from 'apollo-client';
5 | import {FlowRouter} from 'meteor/kadira:flow-router';
6 | import {ReactiveDict} from 'meteor/reactive-dict';
7 | import {Tracker} from 'meteor/tracker';
8 |
9 |
10 | //redux stuff
11 | import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
12 | import createLogger from 'redux-logger'
13 | import ReduxThunk from 'redux-thunk'
14 |
15 |
16 | export function initContext({ reducers }) {
17 |
18 | //powered by the Meteor Atmosphere Package.. "meteorClientConfig"
19 | const Client = new ApolloClient(meteorClientConfig());
20 |
21 | const reducer = combineReducers({
22 | ...reducers,
23 | apollo: Client.reducer()
24 | });
25 |
26 |
27 | // put all Redux middleware here
28 | const middleware = [
29 | createLogger(),
30 | Client.middleware(),
31 | ReduxThunk
32 | ];
33 |
34 |
35 | let Store = createStore(reducer, {}, compose(
36 | applyMiddleware(...middleware),
37 | window.devToolsExtension ? window.devToolsExtension() : f => f
38 | ));
39 |
40 |
41 | return {
42 | Meteor,
43 | FlowRouter,
44 | Collections,
45 | Tracker,
46 | Client,
47 | Store,
48 | dispatch: Store.dispatch
49 | };
50 | }
51 |
--------------------------------------------------------------------------------
/imports/client/modules/core/containers/view_home.js:
--------------------------------------------------------------------------------
1 | import {useDeps} from 'mantra-core';
2 | import {withRedux, composeAll} from 'react-komposer-plus';
3 | import { graphql } from 'react-apollo';
4 | import gql from 'graphql-tag';
5 | import view_home from '../components/view_home';
6 |
7 |
8 |
9 | const ADD_MEDIA_IMAGE = gql`
10 | mutation addMediaImageMutation ($name: String!, $cdnUrl: String!){
11 | addMediaImage(
12 | name: $name, cdnUrl: $cdnUrl)
13 | {
14 | _id
15 | name
16 | cdnUrl
17 | }
18 | }`;
19 |
20 |
21 | const WITH_ADD_MEDIA_IMAGE = graphql(ADD_MEDIA_IMAGE, {
22 | //we are returning the mutation as a prop.
23 | //this will then be passed to the action
24 | props: ({ ownProps, mutate }) => ({
25 | addMediaImageMutation(variables ) {
26 | return mutate({
27 | variables: {...variables}
28 | });
29 | }
30 | })
31 | });
32 |
33 |
34 | const mapStateToProps = ({ core }) => ({
35 | someMediaImage: core.someMediaImage
36 | });
37 |
38 |
39 | export const depsMapper = (context, actions) => ({
40 | openToast: actions.toast.openToast,
41 | addMediaImage: actions.toast.addMediaImage,
42 | context: () => context
43 | });
44 |
45 |
46 | //interesting to note.. the order of these matter.. withRedux before useDeps
47 | export default composeAll(
48 | withRedux(mapStateToProps),
49 | useDeps(depsMapper),
50 | WITH_ADD_MEDIA_IMAGE
51 | )(view_home);
--------------------------------------------------------------------------------
/imports/client/modules/core/actions/toast.js:
--------------------------------------------------------------------------------
1 | export default {
2 | openToast({Meteor, Store}) {
3 | console.log('dispatching toast...');
4 | //this will be picked up by the reducer...
5 | return Store.dispatch({
6 | type: 'TOAST_SWITCH',
7 | toastOpen: true,
8 | message: 'I am an over complex TOAST instance...'
9 | });
10 | },
11 | closeToast({Meteor, Store}) {
12 | //this will be picked up by the reducer...
13 | return Store.dispatch({
14 | type: 'TOAST_SWITCH',
15 | toastOpen: false,
16 | message: 'Toast begone....'
17 | });
18 | },
19 | addMediaImage({}, mutation, variables) {
20 | return (dispatch, getState) => {
21 | //not sure if this is 100% correct.. but it works.
22 | //this is Thunk in action
23 | //we wait for the result.. and then auto dispatch to a listening reducer to update the state
24 |
25 | mutation(variables).then((result) => {
26 | if (result.data) {
27 | console.log(result);
28 | // if the mutation yields data, dispatch an action with that data
29 | return dispatch ({
30 | type: "UPDATE_MEDIA",
31 | someMediaImage: result.data.addMediaImage //the mutation returns this object..
32 | });
33 | }
34 | });
35 | };
36 | }
37 | };
--------------------------------------------------------------------------------
/imports/client/modules/core/components/mainLayout.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import { ApolloProvider } from 'react-apollo';
3 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
4 | import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
5 | import getMuiTheme from 'material-ui/styles/getMuiTheme'
6 |
7 |
8 | const lightMuiTheme = getMuiTheme(lightBaseTheme);
9 |
10 | /**
11 | * A lot of interesting stuff happening here to get MUI and Redux
12 | * working with the app with the help of Providers below
13 | */
14 |
15 | const propTypes = {
16 | nav: PropTypes.func,
17 | content: PropTypes.func.isRequired,
18 | footer: PropTypes.func,
19 | client: PropTypes.object,
20 | store: PropTypes.object
21 | };
22 |
23 |
24 | const Layout = ({
25 | content = () => null,
26 | nav = () => null,
27 | footer = () => null,
28 | client,
29 | store
30 | }) => (
31 |
32 |
33 |
34 |
37 |
38 |
39 | {content()}
40 |
41 |
42 |
44 |
45 |
46 |
47 | );
48 |
49 | Layout.propTypes = propTypes;
50 | Layout.displayName = "Main Layout";
51 |
52 | export default Layout;
53 |
--------------------------------------------------------------------------------
/imports/client/modules/core/containers/toast.js:
--------------------------------------------------------------------------------
1 | import {useDeps} from 'mantra-core';
2 | import {withRedux, composeAll} from 'react-komposer-plus';
3 | import { graphql } from 'react-apollo';
4 | import gql from 'graphql-tag';
5 | import toast from '../components/toast';
6 |
7 |
8 | /**
9 | *
10 | * Notice the react-komposer-plus package.. this has some handy Redux stuff.
11 | * Which means we stay away from using Redux Connect() in the ComposeAll function
12 | *
13 | * We use the new GraphQL connector to handle the main query
14 | * http://docs.apollostack.com/apollo-client/react.html
15 | */
16 |
17 |
18 |
19 | const GET_POIS = gql`
20 | query allPois {
21 | allPois {
22 | _id
23 | type
24 | region
25 | }
26 | }`;
27 |
28 | //we can define the exact props we want.. this is a good habit
29 | //instead of just dumping a data object to the component
30 | const GET_POIS_WITH_PROPS = graphql(GET_POIS, {
31 | props: ({ ownProps, data }) => {
32 | if (data.loading) return { loading: true };
33 | if (data.error) return { hasErrors: true };
34 | return {
35 | allPois: data.allPois
36 | };
37 | }
38 | });
39 |
40 |
41 |
42 | const mapStateToProps = ({ core }) => ({
43 | toastOpen: core.toastOpen,
44 | message: core.message
45 | });
46 |
47 |
48 | //sending te actions and context to the component
49 | const mapDepsToProps = (context, actions) => ({
50 | closeToast: actions.toast.closeToast,
51 | context: () => context
52 | });
53 |
54 |
55 |
56 | export default composeAll(
57 | withRedux(mapStateToProps),
58 | useDeps(mapDepsToProps),
59 | GET_POIS_WITH_PROPS
60 | )(toast);
61 |
62 |
--------------------------------------------------------------------------------
/.meteor/versions:
--------------------------------------------------------------------------------
1 | accounts-base@1.2.11
2 | allow-deny@1.0.5
3 | apollo@0.1.0-beta_3
4 | autoupdate@1.3.11
5 | babel-compiler@6.9.1
6 | babel-runtime@0.1.11
7 | base64@1.0.9
8 | binary-heap@1.0.9
9 | blaze@2.1.8
10 | blaze-html-templates@1.0.4
11 | blaze-tools@1.0.9
12 | boilerplate-generator@1.0.9
13 | caching-compiler@1.1.7
14 | caching-html-compiler@1.0.6
15 | callback-hook@1.0.9
16 | check@1.2.3
17 | ddp@1.2.5
18 | ddp-client@1.3.1
19 | ddp-common@1.2.6
20 | ddp-rate-limiter@1.0.5
21 | ddp-server@1.3.10
22 | deps@1.0.12
23 | diff-sequence@1.0.6
24 | ecmascript@0.5.8
25 | ecmascript-runtime@0.3.14
26 | ejson@1.0.12
27 | es5-shim@4.6.14
28 | fastclick@1.0.12
29 | geojson-utils@1.0.9
30 | hot-code-push@1.0.4
31 | html-tools@1.0.10
32 | htmljs@1.0.10
33 | http@1.2.9
34 | id-map@1.0.8
35 | jquery@1.11.9
36 | kadira:flow-router@2.12.1
37 | launch-screen@1.0.12
38 | livedata@1.0.18
39 | localstorage@1.0.11
40 | logging@1.1.15
41 | meteor@1.2.17
42 | meteor-base@1.0.4
43 | minifier-css@1.2.14
44 | minifier-js@1.2.14
45 | minimongo@1.0.17
46 | mobile-experience@1.0.4
47 | mobile-status-bar@1.0.12
48 | modules@0.7.6
49 | modules-runtime@0.7.6
50 | mongo@1.1.12
51 | mongo-id@1.0.5
52 | npm-mongo@1.5.48
53 | observe-sequence@1.0.12
54 | ordered-dict@1.0.8
55 | promise@0.8.4
56 | random@1.0.10
57 | rate-limit@1.0.5
58 | reactive-dict@1.1.8
59 | reactive-var@1.0.10
60 | reload@1.1.10
61 | retry@1.0.8
62 | routepolicy@1.0.11
63 | service-configuration@1.0.10
64 | shell-server@0.2.1
65 | spacebars@1.0.12
66 | spacebars-compiler@1.0.12
67 | standard-minifier-css@1.2.0
68 | standard-minifier-js@1.2.0
69 | templating@1.2.14
70 | templating-tools@1.0.4
71 | tmeasday:check-npm-versions@0.3.1
72 | tracker@1.1.0
73 | ui@1.0.11
74 | underscore@1.0.9
75 | url@1.0.10
76 | webapp@1.3.11
77 | webapp-hashing@1.0.9
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Apollo, Redux, Mantra and Meteor
2 |
3 |
4 | ## An overcomplex attempt to trigger some Toast
5 |
6 |
7 | [Snackbars and Toast](https://material.google.com/components/snackbars-toasts.html) are nice simple UI experiences. The Material UI Snackbar is simple enough to manage via State.
8 |
9 | ```
10 |
16 | ```
17 |
18 | However.. it's important to geek out. Today we have new opportunities to overcomplicate even the simplest of features. So let's wire up some Toast to a Redux State.. managed by Apollo.. and use Mantra to organize the codebase... on Meteor. Just because ;)
19 |
20 |
21 | ### Modules
22 |
23 | There is a single module here..
24 |
25 | * **core**: Which is where the Toast is managed. You will find some basic redux state to switch the toast on / off. There is also a mutation to add a MediaImage object to a collection.
26 |
27 |
28 | ### GraphQL Schema
29 |
30 | Check out the Schema set up on the server.. A lot of the schema is not used in this simple demo app. But there is a clear example of splitting down a schema into separate files.
31 |
32 |
33 |
34 |
35 | ### What happened to ReduxToast v1?
36 |
37 | Great question.. it was a work of art. However, the recent updates to react-apollo introduced the new GraphQL container, which put a spanner in the works to pass props / state and actions to a component.
38 |
39 | This latest Toast adventure manages to get everything working again (for now).
40 |
41 |
42 | ### Obvious Disclaimer
43 |
44 |
45 | This is basic striped down code.. to showcase how I got the various parts working together. Still work in progress, and it's safe to assume a few improvements are still to come.
46 |
47 | The whole redux / mantra / apollo mix has been a very confusing learning curve on Meteor. And it's still a maturing stack
48 |
49 | I think the idea here is to let Redux handle the local state / domain and send all props to components via Connect(). Not really leveraging MinMongo on the client. Redux / apollo provides some nice features to manage the fetching / caching / updating of the State. This feature set is going to improve moving forward with Apollo.
50 |
51 |
52 | If you find this helpful... please follow me.
53 |
54 | [@gavin_payne](https://twitter.com/gavin_payne)
55 |
56 |
--------------------------------------------------------------------------------
/imports/client/modules/core/components/view_home.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import RaisedButton from 'material-ui/RaisedButton';
3 | import Toast from '../containers/toast';
4 | import {Card, CardMedia, CardTitle} from 'material-ui/Card';
5 | import { If, Then, Else } from 'react-if';
6 |
7 |
8 |
9 | const View_Home = ({openToast, addMediaImageMutation, addMediaImage, context, someMediaImage}) => {
10 |
11 | //I do love functions in ES6
12 | const _goToast = () => {
13 | // the => means the scope of variables belongs to this component
14 | openToast(); //calls the Action.
15 | };
16 |
17 |
18 | const _goMutate = () => {
19 |
20 | //dispatch is in the Mantra context..
21 | const { dispatch } = context();
22 |
23 | //im gonna mutate...
24 | //looks like we have to pass the mutation to the action here...
25 | //this function then uses the Thunk middleware..(i think)
26 |
27 | const variables = {
28 | name: "I am the MUTATION....",
29 | cdnUrl: "https://img.ifcdn.com/images/d1e8e77fe0ff800ec3e84c701d0145aa10824ad8f558cd543f25421dbcdbc9c0_1.jpg"
30 | };
31 |
32 |
33 | //we don't call the function here.. just pass it plus variables to the action
34 | //we do however dispatch.. this triggers the thunk
35 | return dispatch(addMediaImage(addMediaImageMutation, variables));
36 | };
37 |
38 | return (
39 |
40 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | {() => // will only be evaluated if the condition fails.
61 | Waiting for MUTATION to happen...
62 | }
63 |
64 |
65 |
66 |
67 | );
68 |
69 | };
70 |
71 | View_Home.propTypes = {
72 | openToast: React.PropTypes.func, //action
73 | addMediaImageMutation: React.PropTypes.func, //the mutation
74 | addMediaImage: React.PropTypes.func, //action
75 | someMediaImage: React.PropTypes.object //state
76 | };
77 |
78 |
79 | View_Home.displayName = "View Home";
80 | export default View_Home;
--------------------------------------------------------------------------------