codecombat/app/templates/admin/analytics.jade
Scott Erickson f0fa88206d Add Enrollment start/end dates, remove self-serve
* Refactor several related endpoints and views
* Redesign EnrollmentView, add TeacherContactModal
* Add "Enrollment Status" tab to TeacherClassView
* Delete PurchaseCoursesView and related files
* Style-flatten RemoveStudentModal
* Fix error handling in ActivateLicensesModal
* TeacherCoursesView loads faster by only loading course campaigns, and not load prepaids
2016-05-24 14:07:28 -07:00

372 lines
14 KiB
Text

extends /templates/base
block content
//- NOTE: do not localize / i18n
if me.isAdmin()
.container-fluid
.row
.col-md-5.big-stat.active-classes
div.description Monthly Active Classes
if view.activeClasses.length > 0
div.count= view.activeClasses[0].groups[view.activeClasses[0].groups.length - 1]
.col-md-5.big-stat.recurring-revenue
div.description Monthly Recurring Revenue
if view.revenue.length > 0
div.count $#{Math.round((view.revenue[0].groups[view.revenue[0].groups.length - 1]) / 100)}
.col-md-5.big-stat.classroom-active-users
div.description Classroom Monthly Active Users
if view.activeUsers.length > 0
- var classroomBigMAU = 0;
each count, event in view.activeUsers[0].events
if event.indexOf('MAU classroom') >= 0
- classroomBigMAU += count;
div.count= classroomBigMAU
.col-md-5.big-stat.campaign-active-users
div.description Campaign Monthly Active Users
if view.activeUsers.length > 0
- var campaignBigMAU = 0;
each count, event in view.activeUsers[0].events
if event.indexOf('MAU campaign') >= 0
- campaignBigMAU += count;
div.count= campaignBigMAU
ul.nav.nav-tabs
li.active
a(data-target="#tab_kpis", data-toggle="tab") KPIs
li
a(data-target="#tab_active_classes", data-toggle="tab") Active Classes
li
a(data-target="#tab_revenue", data-toggle="tab") Revenue
li
a(data-target="#tab_classroom", data-toggle="tab") Classroom
li
a(data-target="#tab_campaign", data-toggle="tab") Campaign
li
a(data-target="#tab_campaign_vs_classroom", data-toggle="tab") Campaign vs Classroom
.tab-content
.tab-pane.active#tab_kpis
h3 KPI 60 days
.kpi-recent-chart.line-chart-container
h3 KPI 365 days
.kpi-chart.line-chart-container
.tab-pane#tab_active_classes
h3 Active Classes 90 days
.small Active class: 12+ students in a classroom, with 6+ who played in last 30 days. Played == 'Started Level' analytics event.
.small Paid student: user.coursePrepaid set and prepaid.properties.trialRequestID NOT set
.small Trial student: user.coursePrepaid set and prepaid.properties.trialRequestID set
.small Paid class: at least one paid student in the classroom
.small Trial class: not paid, at least one trial student in classroom
.small Free class: not paid, not trial
.active-classes-chart-90.line-chart-container
h3 Active Classes 365 days
.active-classes-chart-365.line-chart-container
h1 Active Classes
table.table.table-striped.table-condensed
tr
th Day
for group in view.activeClassGroups
th= group.replace('Active classes', '')
each activeClass in view.activeClasses
tr
td= activeClass.day
each val in activeClass.groups
td= val
.tab-pane#tab_revenue
h3 Daily Recurring Revenue 90 days
.recurring-daily-revenue-chart-90.line-chart-container
h3 Monthly Recurring Revenue 90 days
.recurring-monthly-revenue-chart-90.line-chart-container
h3 Daily Recurring Revenue 365 days
.recurring-daily-revenue-chart-365.line-chart-container
h3 Monthly Recurring Revenue 365 days
.recurring-monthly-revenue-chart-365.line-chart-container
.school-sales
h3 School Sales
if view.schoolSales
table.table.table-striped.table-condensed
tr
th Amount
th(style='min-width:85px;') Created
th PaymentID
th PrepaidID
th Description
th Email
th School
each val, i in view.schoolSales
tr
td $#{val.amount / 100}
td= new Date(val.created).toISOString().substring(0, 10)
td= val._id
td= val.prepaidID
td= val.description
if val.user
td= val.user.emailLower
td= val.user.schoolName
else
td
td
else
div Loading ...
h1 Recurring Revenue
table.table.table-striped.table-condensed
tr
th(style='min-width:85px;') Day
for group in view.revenueGroups
th= group.replace('DRR ', 'Daily ').replace('MRR ', 'Monthly ')
each entry in view.revenue
tr
td= entry.day
each val in entry.groups
td $#{(val / 100).toFixed(2)}
.tab-pane#tab_classroom
h3 Classroom Daily Active Users 90 days
.small Paid student: user.coursePrepaid set and prepaid.properties.trialRequestID NOT set
.small Trial student: user.coursePrepaid set and prepaid.properties.trialRequestID set
.small Free student: not paid, not trial
.classroom-daily-active-users-chart-90.line-chart-container
h3 Classroom Monthly Active Users 90 days
.classroom-monthly-active-users-chart-90.line-chart-container
h3 Classroom Daily Active Users 365 days
.classroom-daily-active-users-chart-365.line-chart-container
h3 Classroom Monthly Active Users 365 days
.classroom-monthly-active-users-chart-365.line-chart-container
h3 Enrollments Issued and Redeemed 90 days
.paid-courses-chart.line-chart-container
#furthest-course
h3 Furthest Course in last #{view.furthestCourseDayRangeRecent} days
.small Restricted to courses instances from last #{view.furthestCourseDayRangeRecent} days
.small Teacher: owner of a course instance
.small Student: member of a course instance (assigned to course)
.small For course instances != Single Player, hourOfCode != true
.small Counts are not summed. I.e. a student or teacher only contributes to the count of one course
.small Paid student: user.coursePrepaid set and prepaid.properties.trialRequestID NOT set
.small Trial student: user.coursePrepaid set and prepaid.properties.trialRequestID set
.small Free student: not paid, not trial
.small Paid teacher: at least one paid student in course instance
.small Trial teacher: at least one trial student in course instance, and no paid students
.small Free teacher: no paid students, no trial students
.small Paid status takes precedent over furthest course, so teacher furthest course is furthest course of highest paid status student
if view.courseDistributionsRecent
table.table.table-striped.table-condensed
tr
th Course
th Paid Teachers
th Trial Teachers
th Free Teachers
th Total Teachers
th Paid Students
th Trial Students
th Free Students
th Total Students
each row in view.courseDistributionsRecent
tr
td= row.courseName
td= row.totals['Paid Teachers'] || 0
td= row.totals['Trial Teachers'] || 0
td= row.totals['Free Teachers'] || 0
td= row.totals['Total Teachers'] || 0
td= row.totals['Paid Students'] || 0
td= row.totals['Trial Students'] || 0
td= row.totals['Free Students'] || 0
td= row.totals['Total Students'] || 0
else
div Loading ...
h3 Furthest Course in last #{view.furthestCourseDayRange} days
if view.courseDistributions
table.table.table-striped.table-condensed
tr
th Course
th Paid Teachers
th Trial Teachers
th Free Teachers
th Total Teachers
th Paid Students
th Trial Students
th Free Students
th Total Students
each row in view.courseDistributions
tr
td= row.courseName
td= row.totals['Paid Teachers'] || 0
td= row.totals['Trial Teachers'] || 0
td= row.totals['Free Teachers'] || 0
td= row.totals['Total Teachers'] || 0
td= row.totals['Paid Students'] || 0
td= row.totals['Trial Students'] || 0
td= row.totals['Free Students'] || 0
td= row.totals['Total Students'] || 0
else
div Loading ...
.school-sales
h3 School Sales
if view.schoolSales
table.table.table-striped.table-condensed
tr
th Amount
th(style='min-width:85px;') Created
th PaymentID
th PrepaidID
th Description
th Email
th School
each val, i in view.schoolSales
tr
td $#{val.amount / 100}
td= new Date(val.created).toISOString().substring(0, 10)
td= val._id
td= val.prepaidID
td= val.description
if val.user
td= val.user.emailLower
td= val.user.schoolName
else
td
td
else
div Loading ...
#school-counts
h3 School Counts
.small Only including schools with #{view.minSchoolCount}+ counts
if view.schoolCounts
table.table.table-striped.table-condensed
tr
th
th School Name
th User Count
each val, i in view.schoolCounts
tr
td= i + 1
td= val.schoolName
td= val.count
else
div Loading ...
h1 Active Users
if view.activeUsers.length > 0
- var eventNames = [];
each count, event in view.activeUsers[0].events
if event.indexOf('classroom') >= 0
- eventNames.push(event)
- eventNames.sort(function (a, b) {return a.localeCompare(b);});
table.table.table-striped.table-condensed
tr
th(style='min-width:85px;') Day
each eventName in eventNames
th= eventName
each activeUser in view.activeUsers
tr
td= activeUser.day
each eventName in eventNames
td= activeUser.events[eventName] || 0
h1#enrollments-table Enrollments
table.table.table-striped.table-condensed
tr
th Day
th Paid Enrollments Issued
th Paid Enrollments Redeemed
th Trial Enrollments Issued
th Trial Enrollments Redeemed
each day in view.enrollmentDays
tr
td= day
if view.dayEnrollmentsMap[day]
td= view.dayEnrollmentsMap[day].paidIssued || 0
td= view.dayEnrollmentsMap[day].paidRedeemed || 0
td= view.dayEnrollmentsMap[day].trialIssued || 0
td= view.dayEnrollmentsMap[day].trialRedeemed || 0
else
td 0
td 0
td 0
td 0
.tab-pane#tab_campaign
h3 Campaign Daily Active Users 90 days
.small Paid user: had monthly or yearly sub on given day
.small Free user: not paid
.campaign-daily-active-users-chart-90.line-chart-container
h3 Campaign Monthly Active Users 90 days
.campaign-monthly-active-users-chart-90.line-chart-container
h3 Campaign Daily Active Users 365 days
.campaign-daily-active-users-chart-365.line-chart-container
h3 Campaign Monthly Active Users 365 days
.campaign-monthly-active-users-chart-365.line-chart-container
h1 Active Users
if view.activeUsers.length > 0
- var eventNames = [];
each count, event in view.activeUsers[0].events
if event.indexOf('campaign') >= 0
- eventNames.push(event)
- eventNames.sort(function (a, b) {return a.localeCompare(b);});
table.table.table-striped.table-condensed
tr
th(style='min-width:85px;') Day
each eventName in eventNames
th= eventName
each activeUser in view.activeUsers
tr
td= activeUser.day
each eventName in eventNames
td= activeUser.events[eventName] || 0
.tab-pane#tab_campaign_vs_classroom
h3 Campaign vs Classroom Paid Monthly Active Users 90 days
.campaign-vs-classroom-monthly-active-users-recent-chart.line-chart-container
h3 Campaign vs Classroom Paid Monthly Active Users 365 days
.campaign-vs-classroom-monthly-active-users-chart.line-chart-container
h1 Active Users
if view.activeUsers.length > 0
- var eventNames = [];
each count, event in view.activeUsers[0].events
- eventNames.push(event)
- eventNames.sort(function (a, b) {
- if (a.indexOf('campaign') == b.indexOf('campaign') || a.indexOf('classroom') == b.indexOf('classroom')) {
- return a.localeCompare(b);
- }
- else if (a.indexOf('campaign') > b.indexOf('campaign')) {
- return 1;
- }
- else {
- return -1;
- }
- });
table.table.table-striped.table-condensed
tr
th(style='min-width:85px;') Day
each eventName in eventNames
th= eventName
each activeUser in view.activeUsers
tr
td= activeUser.day
each eventName in eventNames
td= activeUser.events[eventName] || 0