Skip to content

Commit

Permalink
Merge branch 'devel' of https://github.com/TelescopeJS/Telescope into…
Browse files Browse the repository at this point in the history
… devel
  • Loading branch information
SachaG committed Feb 2, 2017
2 parents d87c13a + 4d02453 commit a2f7592
Show file tree
Hide file tree
Showing 18 changed files with 287 additions and 114 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"lint": "eslint --cache --ext .jsx,js packages"
},
"dependencies": {
"analytics-node": "^2.1.1",
"apollo-client": "^0.8.1",
"babel-runtime": "^6.18.0",
"bcrypt": "^0.8.7",
Expand Down
108 changes: 84 additions & 24 deletions packages/nova-base-components/lib/posts/PostsPage.jsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,104 @@
import { Components, registerComponent, withDocument, withCurrentUser } from 'meteor/nova:core';
import React from 'react';
import { Components, registerComponent, withDocument, withCurrentUser, getActions, withMutation } from 'meteor/nova:core';
import Posts from 'meteor/nova:posts';
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

const PostsPage = (props) => {
class PostsPage extends Component {

render() {
if (this.props.loading) {

return <div className="posts-page"><Components.Loading/></div>

} else {

const post = this.props.document;

if (props.loading) {
const htmlBody = {__html: post.htmlBody};

return <div className="posts-page"><Components.Loading/></div>
return (
<div className="posts-page">
<Components.HeadTags url={Posts.getLink(post)} title={post.title} image={post.thumbnailUrl} description={post.excerpt} />

<Components.PostsItem post={post} currentUser={this.props.currentUser} />

} else {
{post.htmlBody ? <div className="posts-page-body" dangerouslySetInnerHTML={htmlBody}></div> : null}

const post = props.document;
<Components.PostsCommentsThread terms={{postId: post._id}} />

const htmlBody = {__html: post.htmlBody};

return (
<div className="posts-page">
<Components.HeadTags url={Posts.getLink(post)} title={post.title} image={post.thumbnailUrl} description={post.excerpt} />
</div>
);

}
}

// triggered after the component did mount on the client
async componentDidMount() {
try {

// destructure the relevant props
const {
// from the parent component, used in withDocument, GraphQL HOC
documentId,
// from connect, Redux HOC
setViewed,
postsViewed,
// from withMutation, GraphQL HOC
increasePostViewCount,
} = this.props;

// a post id has been found & it's has not been seen yet on this client session
if (documentId && !postsViewed.includes(documentId)) {

<Components.PostsItem post={post} currentUser={props.currentUser} />

{post.htmlBody ? <div className="posts-page-body" dangerouslySetInnerHTML={htmlBody}></div> : null}

<Components.PostsCommentsThread terms={{postId: post._id}} />

</div>
)
// trigger the asynchronous mutation with postId as an argument
await increasePostViewCount({postId: documentId});

// once the mutation is done, update the redux store
setViewed(documentId);
}

} catch(error) {
console.log(error); // eslint-disable-line
}
}
};
}

PostsPage.displayName = "PostsPage";

PostsPage.propTypes = {
document: React.PropTypes.object
documentId: PropTypes.string,
document: PropTypes.object,
postsViewed: PropTypes.array,
setViewed: PropTypes.func,
increasePostViewCount: PropTypes.func,
}

const options = {
const queryOptions = {
collection: Posts,
queryName: 'postsSingleQuery',
fragmentName: 'PostsPage',
};

registerComponent('PostsPage', PostsPage, withCurrentUser, [withDocument, options]);
const mutationOptions = {
name: 'increasePostViewCount',
args: {postId: 'String'},
};

const mapStateToProps = state => ({ postsViewed: state.postsViewed });
const mapDispatchToProps = dispatch => bindActionCreators(getActions().postsViewed, dispatch);

registerComponent(
// component name used by Nova
'PostsPage',
// React component
PostsPage,
// HOC to give access to the current user
withCurrentUser,
// HOC to load the data of the document, based on queryOptions & a documentId props
[withDocument, queryOptions],
// HOC to provide a single mutation, based on mutationOptions
withMutation(mutationOptions),
// HOC to give access to the redux store & related actions
connect(mapStateToProps, mapDispatchToProps)
);
5 changes: 3 additions & 2 deletions packages/nova-categories/lib/client.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Categories from './modules.js';
import Categories, { getCategories, getCategoriesAsOptions } from './modules.js';

export default Categories;
export { getCategories, getCategoriesAsOptions };
export default Categories;
4 changes: 2 additions & 2 deletions packages/nova-categories/lib/modules.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Categories from './collection.js';

import './schema.js';
export { getCategories, getCategoriesAsOptions } from './schema.js';
import './helpers.js';
import './callbacks.js';
import './parameters.js';
Expand All @@ -9,4 +9,4 @@ import './permissions.js';
import './resolvers.js';
import './mutations.js';

export default Categories;
export default Categories;
5 changes: 3 additions & 2 deletions packages/nova-categories/lib/server.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Categories from './modules.js';
import Categories, { getCategories, getCategoriesAsOptions } from './modules.js';

import './server/load_categories.js';

export default Categories;
export { getCategories, getCategoriesAsOptions };
export default Categories;
47 changes: 47 additions & 0 deletions packages/nova-events/lib/callbacks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { addCallback, getSetting } from 'meteor/nova:core';
import { sendGoogleAnalyticsRequest, mutationAnalyticsAsync } from './helpers';
import Analytics from 'analytics-node';

// add client-side callback: log a ga request on page view
addCallback('router.onUpdate', sendGoogleAnalyticsRequest);


// get the segment write key from the settings
const useSegment = getSetting('useSegment');
const writeKey = getSetting('segmentWriteKey');

// the settings obviously tells to use segment
// and segment write key is defined & isn't the placeholder from sample_settings.json
if (useSegment && writeKey && writeKey !== '456bar') {
const analyticsInstance = new Analytics(writeKey);

// generate callbacks on collection ...
['users', 'posts', 'comments', 'categories'].map(collection => {
// ... for each common mutation
return ['new', 'edit', 'remove'].map(mutation => {

const hook = `${collection}.${mutation}`;

addCallback(`${hook}.async`, function AnalyticsTracking(...args) {

// a note on what's happenning below:
// the first argument is always the document we are interested in
// the second to last argument is always the current user
// on edit.async, the argument on index 1 is always the previous document
// see nova:lib/mutations.js for more informations

// remove unnecessary 'previousDocument' if operating on a collection.edit hook
if (hook.includes('edit')) {
args.splice(1,1);
}

const [document, currentUser, ...rest] = args; // eslint-disable-line no-unused-vars

return mutationAnalyticsAsync(analyticsInstance, hook, document, currentUser);
});

// return the hook name, used for debug
return hook;
});
});
}
7 changes: 5 additions & 2 deletions packages/nova-events/lib/client.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import Events from './collection.js';
import { initGoogleAnalytics } from './helpers.js';
import './callbacks.js';

import './client/analytics.js';
// init google analytics on the client module
initGoogleAnalytics();

export default Events;
export default Events;
40 changes: 0 additions & 40 deletions packages/nova-events/lib/client/analytics.js

This file was deleted.

35 changes: 0 additions & 35 deletions packages/nova-events/lib/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,41 +28,6 @@ Events.schema = new SimpleSchema({
}
});

// Meteor.startup(function(){
// // needs to happen after every fields are added
// Events.internationalize();
// });

Events.attachSchema(Events.schema);

if (Meteor.isServer) {
Events.log = function (event) {

// if event is supposed to be unique, check if it has already been logged
if (!!event.unique && !!Events.findOne({name: event.name})) {
return;
}

event.createdAt = new Date();

Events.insert(event);

};
}

Events.track = function(event, properties){
// console.log('trackevent: ', event, properties);
properties = properties || {};
//TODO
// add event to an Events collection for logging and buffering purposes
// if(Meteor.isClient){
// if(typeof mixpanel !== 'undefined' && typeof mixpanel.track !== 'undefined'){
// mixpanel.track(event, properties);
// }
// if(typeof GoSquared !== 'undefined' && typeof GoSquared.DefaultTracker !== 'undefined'){
// GoSquared.DefaultTracker.TrackEvent(event, JSON.stringify(properties));
// }
// }
};

export default Events;
86 changes: 86 additions & 0 deletions packages/nova-events/lib/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { getSetting } from 'meteor/nova:core';

/*
We provide a special support for Google Analytics.
If you want to enable GA page viewing / tracking, go to
your settings file and update the "public > googleAnalyticsId"
field with your GA unique identifier (UA-xxx...).
*/

export const sendGoogleAnalyticsRequest = () => {
if (window && window.ga) {
window.ga('send', 'pageview', {
'page': window.location.pathname
});
}
};

export const initGoogleAnalytics = () => {

// get the google analytics id from the settings
const googleAnalyticsId = getSetting("googleAnalyticsId");

// the google analytics id exists & isn't the placeholder from sample_settings.json
if (googleAnalyticsId && googleAnalyticsId !== "foo123") {

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

const cookieDomain = document.domain === "localhost" ? "none" : "auto";

window.ga('create', googleAnalyticsId, cookieDomain);

// trigger first request once analytics are initialized
sendGoogleAnalyticsRequest();
}
};

/*
We provide a special support for Segment, using analytics-node
See https://segment.com/docs/sources/server/node/
*/

export const mutationAnalyticsAsync = (analytics, hook, document, user) => {

if (hook.includes('users')) {
// if the mutation is related to users, use analytics.identify
// see https://segment.com/docs/sources/server/node/#identify

// note: on users.new.async, user is undefined
const userId = user ? user._id : document._id;

const data = {
userId,
traits: document,
};

// uncomment for debug
// console.log(`// dispatching identify on "${hook}" (user ${userId})`);
// console.log(data);

analytics.identify(data);

} else {
// else use analytics.track
// see https://segment.com/docs/sources/server/node/#track

const data = {
userId: user._id,
event: hook,
properties: document,
};

// uncomment for debug
// console.log(`// dispatching track on "${hook}"`);
// console.log(data);

analytics.track(data);
}
}
Loading

0 comments on commit a2f7592

Please sign in to comment.