refactor: Move the tracking model into commons

This commit is contained in:
Alexander Polynomdivision 2018-10-15 16:30:40 +02:00
parent 2963e089d8
commit 22ded2ec38
7 changed files with 59 additions and 63 deletions

16
common/models/tracker.ts Normal file
View File

@ -0,0 +1,16 @@
export enum TrackerEvent {
LOG_IN = "LOG_IN",
LOG_OUT = "LOG_OUT",
START_LEARNING = "START_LEARNING",
CANCEL_LEARNING = "CANCEL_LEARNING",
FINISH_LEARNING = "FINISH_LEARNING",
};
export interface ITrackerRequest {
session: string;
event: TrackerEvent;
};
export type ITrackerDBModel = ITrackerRequest & {
timestamp: number;
};

View File

@ -24,8 +24,8 @@ prod: node_modules clean
dev: node_modules clean dev: node_modules clean
@echo Building with parcel @echo Building with parcel
NODE_ENV=development ./node_modules/.bin/parcel build --out-dir dist/app --public-url /app/ src/index.hbs NODE_ENV=development ./node_modules/.bin/parcel build --out-dir dist/app --public-url /app/ --no-autoinstall src/index.hbs
NODE_ENV=development ./node_modules/.bin/parcel build --out-dir dist src/lost.html src/error.html NODE_ENV=development ./node_modules/.bin/parcel build --out-dir dist --no-autoinstall src/lost.html src/error.html
chmod 604 -R dist/app/* chmod 604 -R dist/app/*
chmod 604 dist/error.html dist/lost.html chmod 604 dist/error.html dist/lost.html

View File

@ -0,0 +1,21 @@
import { TrackerEvent } from "../models/tracker";
import { BACKEND_URL } from "../config.in";
// Sends a tracker event to the remote API
// @event: The kind of event to track
export function trackAction(event: TrackerEvent) {
// Get the tracker ID
const sid = window.sessionStorage.getItem("tracker_session");
fetch(`${BACKEND_URL}/api/tracker`, {
headers: new Headers({
"Content-Type": "application/json",
}),
method: "POST",
body: JSON.stringify({
session: sid,
event,
}),
});
};

View File

@ -14,11 +14,13 @@ import SummaryPage from "../containers/SummaryPage";
import WelcomePage from "../pages/intro"; import WelcomePage from "../pages/intro";
import RegisterPage from "../containers/Register"; import RegisterPage from "../containers/Register";
import VocabPage from "../containers/VocabPage"; import VocabPage from "../containers/VocabPage";
import Drawer from "../containers/Drawer"; import Drawer from "../containers/Drawer";
import { trackAction } from "../api/tracker";
import { BACKEND_URL } from "../config.in"; import { BACKEND_URL } from "../config.in";
import { TrackerEvent } from "../models/tracker";
import { ILevel } from "../models/level"; import { ILevel } from "../models/level";
import { TopTen } from "../models/learner"; import { TopTen } from "../models/learner";
import { IVocab } from "../models/vocab"; import { IVocab } from "../models/vocab";
@ -56,16 +58,7 @@ export default class Application extends React.Component<IProps> {
checkAuthStatus = (token: string): Promise<IUser> => { checkAuthStatus = (token: string): Promise<IUser> => {
// Track the end of a review // Track the end of a review
fetch(`${BACKEND_URL}/api/tracker`, { trackAction(TrackerEvent.LOG_IN);
headers: new Headers({
"Content-Type": "application/json",
}),
method: "POST",
body: JSON.stringify({
session: window.sessionStorage.getItem("tracker_session"),
event: "LOG_IN",
}),
});
return new Promise((res, rej) => { return new Promise((res, rej) => {
fetch(`${BACKEND_URL}/api/user/me`, { fetch(`${BACKEND_URL}/api/user/me`, {
@ -161,16 +154,7 @@ export default class Application extends React.Component<IProps> {
}); });
// Track the end of a review // Track the end of a review
fetch(`${BACKEND_URL}/api/tracker`, { trackAction(TrackerEvent.FINISH_LEARNING);
headers: new Headers({
"Content-Type": "application/json",
}),
method: "POST",
body: JSON.stringify({
session: window.sessionStorage.getItem("tracker_session"),
event: "FINISH_LEARNING",
}),
});
} }
getReviewQueue = (): Promise<IVocab[]> => { getReviewQueue = (): Promise<IVocab[]> => {
@ -300,16 +284,7 @@ export default class Application extends React.Component<IProps> {
login = (username: string, password: string): Promise<IUser | IResponse> => { login = (username: string, password: string): Promise<IUser | IResponse> => {
// Track the login // Track the login
fetch(`${BACKEND_URL}/api/tracker`, { trackAction(TrackerEvent.LOG_IN);
headers: new Headers({
"Content-Type": "application/json",
}),
method: "POST",
body: JSON.stringify({
session: window.sessionStorage.getItem("tracker_session"),
event: "LOG_IN",
}),
});
return new Promise((res, rej) => { return new Promise((res, rej) => {
fetch(`${BACKEND_URL}/api/login`, { fetch(`${BACKEND_URL}/api/login`, {
@ -344,16 +319,7 @@ export default class Application extends React.Component<IProps> {
logout = () => { logout = () => {
// Track the logout // Track the logout
fetch(`${BACKEND_URL}/api/tracker`, { trackAction(TrackerEvent.LOG_OUT);
headers: new Headers({
"Content-Type": "application/json",
}),
method: "POST",
body: JSON.stringify({
session: window.sessionStorage.getItem("tracker_session"),
event: "LOG_OUT",
}),
});
// NOTE: No promise, since we don't care about the result // NOTE: No promise, since we don't care about the result
fetch(`${BACKEND_URL}/api/user/logout`, { fetch(`${BACKEND_URL}/api/user/logout`, {

View File

@ -0,0 +1 @@
../../../common/models/tracker.ts

View File

@ -20,6 +20,9 @@ import { withRouter } from "react-router-dom";
import VocabularyData from "../components/VocabularyData"; import VocabularyData from "../components/VocabularyData";
import { TrackerEvent } from "../models/tracker";
import { trackAction } from "../api/tracker";
import { IVocab, VocabType } from "../models/vocab"; import { IVocab, VocabType } from "../models/vocab";
interface IProps { interface IProps {
@ -100,6 +103,10 @@ const LevelPageWithRouter = withRouter(
} }
cancelLevel = () => { cancelLevel = () => {
// Track the cancellation of a level
trackAction(TrackerEvent.CANCEL_LEARNING);
// Close the dialog and go to the dashboard
this.closeLeave(); this.closeLeave();
this.props.history.push("/dashboard"); this.props.history.push("/dashboard");
} }

View File

@ -27,6 +27,9 @@ import {
} from "../models/vocab"; } from "../models/vocab";
import { ReviewType, IReviewMetadata } from "../models/review"; import { ReviewType, IReviewMetadata } from "../models/review";
import { TrackerEvent } from "../models/tracker";
import { trackAction } from "../api/tracker";
//@ts-ignore //@ts-ignore
import lev from "js-levenshtein"; import lev from "js-levenshtein";
import { import {
@ -104,16 +107,7 @@ const ReviewPageWithRouter = withRouter(
}[reviewType]; }[reviewType];
// Track the start of a session // Track the start of a session
fetch(`${BACKEND_URL}/api/tracker`, { trackAction(TrackerEvent.START_LEARNING);
headers: new Headers({
"Content-Type": "application/json",
}),
method: "POST",
body: JSON.stringify({
session: window.sessionStorage.getItem("tracker_session"),
event: "START_LEARNING",
}),
});
getVocab().then((res: IVocab[]) => { getVocab().then((res: IVocab[]) => {
// Check if we received any vocabulary // Check if we received any vocabulary
@ -158,16 +152,7 @@ const ReviewPageWithRouter = withRouter(
this.closeDialog(); this.closeDialog();
// Track the cancellation of a learning session // Track the cancellation of a learning session
fetch(`${BACKEND_URL}/api/tracker`, { trackAction(TrackerEvent.CANCEL_LEARNING);
headers: new Headers({
"Content-Type": "application/json",
}),
method: "POST",
body: JSON.stringify({
session: window.sessionStorage.getItem("tracker_session"),
event: "CANCEL_LEARNING",
}),
});
// Show the drawer button again // Show the drawer button again
this.props.drawerButtonState(true); this.props.drawerButtonState(true);