Skip to content

Commit

Permalink
Add analytics data to CoursePlan route (#607)
Browse files Browse the repository at this point in the history
* Create analytics container and add it to route file (copied from old branch)

* Get newest doc to display as json

* Pretty print json

* Fix lint and type checks

* Require auth to access route

* Style page if no data shown

* Add timestamp of last analytics run

* Remove accidental commit

* Bug fix for non-cp users

* Refactor analytics retrieval to global-firestore-data

* Optimize code by only retrieving newest document from collection (and adding timestamp field)

* Change timestamp to date type

* Remove null check, add comment
  • Loading branch information
willespencer authored Dec 7, 2021
1 parent 812a089 commit 0a9384a
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 3 deletions.
94 changes: 94 additions & 0 deletions src/containers/Analytics.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<template>
<div>
<div class="body-container" :class="{ 'no-data': !hasData() }">
<top-bar />
<div class="timestamp" v-if="hasData()">Data last retrieved at: {{ analyticsTimestamp }}</div>
<pre class="analytics" v-if="hasData()">{{ analyticsData }}</pre>
<div class="back_to_home">
<a class="back_to_home_link" href="/login">Back to home</a>
</div>
<custom-footer />
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import CustomFooter from '@/components/Footer.vue';
import TopBar from '@/components/TopBar.vue';
import { retrieveAnalytics } from '@/global-firestore-data';
export default defineComponent({
components: { CustomFooter, TopBar },
mounted() {
this.retrieveData();
},
data() {
return {
analyticsData: '',
analyticsTimestamp: '',
};
},
methods: {
async retrieveData() {
const analyticsObject = await retrieveAnalytics();
this.analyticsData = analyticsObject.data;
this.analyticsTimestamp = analyticsObject.timestamp;
},
hasData() {
return this.analyticsData.length > 2;
},
},
});
</script>

<style scoped lang="scss">
.no-data {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.back_to_home {
font-size: 32px;
vertical-align: middle;
text-align: center;
color: #7b7d7e;
margin-bottom: 10rem;
margin-top: 6rem;
height: 100px;
@media (max-width: 1154px) {
margin-bottom: 3rem;
}
@media (max-width: 800px) {
margin-top: 8%;
font-size: 8vw;
margin-bottom: 0;
}
}
a.back_to_home_link {
color: #7b7d7e;
}
.body-container {
min-height: 100vh;
}
.timestamp {
font-size: 16px;
padding: 3.75rem 0 0 6.5rem;
margin-bottom: 1rem;
@media (max-width: 1154px) {
padding: 0 0 0 3.125rem;
}
}
.analytics {
font-size: 14px;
padding: 0 0 0 6.5rem;
@media (max-width: 1154px) {
padding: 0 0 0 3.125rem;
}
}
</style>
4 changes: 4 additions & 0 deletions src/firebase-frontend-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,7 @@ export const uniqueIncrementerCollection = db
export const onboardingDataCollection = db
.collection('user-onboarding-data')
.withConverter(getTypedFirestoreDataConverter<FirestoreOnboardingUserData>());

export const trackUsersCollection = db
.collection('track-users')
.withConverter(getTypedFirestoreDataConverter<FirestoreTrackUsersData>());
33 changes: 33 additions & 0 deletions src/global-firestore-data/analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { trackUsersCollection } from '../firebase-frontend-config';

type AnalyticsData = {
readonly data: string;
readonly timestamp: string;
};

const retrieveAnalytics = (): Promise<AnalyticsData> =>
trackUsersCollection
.orderBy('timestamp', 'desc')
.limit(1)
.get()
.then(querySnapshot => {
let newestDocData = {};
let newestDocDate = new Date(0);
querySnapshot.forEach(doc => {
const isoTimestamp = doc.id;
const date = new Date(isoTimestamp);
if (date.getTime() > newestDocDate.getTime()) {
newestDocDate = date;
newestDocData = doc.data();
}
});

const output = JSON.stringify(newestDocData, null, 2);

return {
data: output,
timestamp: newestDocDate.toLocaleString(),
};
});

export default retrieveAnalytics;
2 changes: 2 additions & 0 deletions src/global-firestore-data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ export {
updateRequirementChoices,
deleteCourseFromRequirementChoices,
} from './override-fulfillment-choices';

export { default as retrieveAnalytics } from './analytics';
10 changes: 7 additions & 3 deletions src/requirements/admin/track-users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ function seasonToMonth(season: string) {
}
}

// true if a semester is an "old semester," i.e. if a semester on CoursePlan has already passed in real life
// the idea is that old semesters and new semesters represent whether users are planning in the future or just uploading courses
function isOld(semester: FirestoreSemester) {
const currentTime = new Date();
const month = currentTime.getMonth() + 1;
Expand Down Expand Up @@ -247,15 +249,17 @@ async function trackUsers() {
};
});

// Create a document in collection with current timestamp
const date = new Date(Date.now());
const docId = date.toISOString();

const outputData: FirestoreTrackUsersData = {
nameData,
semesterData,
onboardingData,
timestamp: date,
};

// Create a document in collection with current timestamp
const date = new Date(Date.now());
const docId = date.toISOString();
trackUsersCollection.doc(docId).set(outputData);
}

Expand Down
9 changes: 9 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Login from '@/containers/Login.vue';
import Dashboard from '@/containers/Dashboard.vue';
import Page404 from '@/containers/404.vue';
import Policy from '@/containers/Policy.vue';
import Analytics from '@/containers/Analytics.vue';
import store from '../store';

const router: Router = createRouter({
Expand All @@ -27,6 +28,14 @@ const router: Router = createRouter({
name: 'Policy',
component: Policy,
},
{
path: '/analytics',
name: 'Analytics',
component: Analytics,
meta: {
requiresAuth: true,
},
},
{
path: '/:pathMatch(.*)*',
name: '404',
Expand Down
1 change: 1 addition & 0 deletions src/user-data.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type FirestoreTrackUsersData = {
nameData: FirestoreTrackUsersNameData;
semesterData: FirestoreTrackUsersSemesterData;
onboardingData: FirestoreTrackUsersOnboardingData;
timestamp: Date;
};

type FirestoreTrackUsersNameData = {
Expand Down

0 comments on commit 0a9384a

Please sign in to comment.