Skip to content

Instantly share code, notes, and snippets.

@mattduggan
Last active April 25, 2018 15:27
Show Gist options
  • Save mattduggan/847aa249750341d3ce8819e55bbc8805 to your computer and use it in GitHub Desktop.
Save mattduggan/847aa249750341d3ce8819e55bbc8805 to your computer and use it in GitHub Desktop.
Activity Notifications
const ACTIVITY_INTERACTION = "ACTIVITY_INTERACTION";
// defined action to change AITs
function createActivityInteraction(interactionTime) {
return { type: ACTIVITY_INTERACTION, payload: { interactionTime } };
}
// define initial state of AITs
const INITIAL_STATE = {
previousInteraction: localstorage.getItem("[email protected]_interaction") || new Date(0).getTime(); // last time or epoch
currentInteraction: new Date().getTime()
}
// define epic (middleware) to handle the side effect of calculating NN from service response and store
// then pushing it over a channel
function activityEpic(action, store) {
action.ofType(GET_ACTIVITIES)
.switchMap(() => getActivities()
.map(data => {
getActivitiesSuccess(data);
// determine net new
const netNew = Object.values(store.activity.activities)
.reduce((sum, activity) => {
return activity.event_happened_at > store.previousInteraction;
}, 0);
// push NN
chrome.runtime.sendMessage("id", { type: NET_NEW, payload: netNew });
})
.catch(response => getActivitiesError(response.status))
);
}
// define case to handle AIT state changes from new action
// essentially, current -> previous, new -> current
function activityReducer(state = INITIAL_STATE, action) {
switch(action.type) {
case ACTIVITY_INTERACTION:
return {
previousInteraction: state.currentInteraction,
currentInteraction: action.payload.interactionTime
};
default:
return state;
}
}
// the view should subscribe to the AIT previous state to determine if they should show the indicator
class ContainerView {
@select(["activity", "activities"]);
readonly activities$: Observable<Array<IActivity>>;
@select(["activity", "previousInteraction"])
readonly previousInteraction$: Observable<String>;
ngOnInit() {
// trigger action to get activities
activityActions.getActivities();
// trigger action to set AIT when the user focuses on the window
window.addEventListener("focus", (event) => {
const currentInteraction = new Date().getTime();
localStorage.setItem("[email protected]_interaction", currentInteraction));
dispatch(createActivityInteraction(currentInteraction));
});
// for other documents which may have loaded the activity app to keep them in sync
// does not fire on the current document
window.addEventListener("storage", (event) => {
if (event.key === "[email protected]_interaction") {
dispatch(createActivityInteraction(event.newValue));
}
});
}
}
class PresentationView {
@Input() interactionTime: string;
@Input() activity: IActivity;
public isNetNew: boolean = false;
// listen for when the interaction time changes
ngOnChanges(changes) {
// net new if the activity happened sooner than the previous interaction
this.isNetNew = this.activity.event_happened_at > changes.interactionTime;
}
}
`
<container-view>
<presentation-view
*ngFor="let activity of activities$ | async"
[activity]="activity"
[interactionTime]="previousInteraction$"></presentation-view>
</container-view>
`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment