Last active
January 17, 2019 02:20
-
-
Save alexmanzo/7fe68db12ea9f17c7318987ada66e533 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import AlertModal from "../AlertModal.vue"; | |
import DoughnutChart from "../DoughnutChart.js"; | |
import Navigation from "../Navigation.vue"; | |
import { mapState } from "vuex"; | |
import moment from "moment"; | |
const BrandConfig = require("../../utils/BrandConfig.js"); | |
const ParseUtils = require("../../utils/ParseUtils.js"); | |
const Tools = require("../../utils/Tools.js"); | |
// This code comes from the <script> section of a Vue component. | |
//It imports other components to render the user's licenses dashboard . | |
export default { | |
// Bring in components to use in template | |
components: { AlertModal, DoughnutChart, Navigation }, | |
data() { | |
// Initial state for data used in template | |
return { | |
confirmRecall: false, | |
selectedLicense: undefined, | |
performingRequest: false, | |
boolVal: false, | |
overviewExamFilterName: "All Exams", | |
detailsExamFilterName: "All Exams", | |
detailsStatusFilterName: "All", | |
emailSearch: "", | |
statusFilters: ["Available", "Consumed", "Pending"], | |
paginate: ["licenses"], | |
showDetailsExamFilters: false, | |
showDetailsStatusFilters: false, | |
showOverviewExamFilters: false, | |
assigningLicenseAtIndex: null, | |
emailToAssign: null, | |
showAssignSuccess: false | |
}; | |
}, | |
computed: { | |
// Return array exams which have licenses purchased. | |
examFilters() { | |
let exams = []; | |
// Pulls licences from state (Vuex) | |
let licenses = this.$store.state.purchasedExams; | |
licenses.forEach(item => { | |
if (!exams.includes(item.examName)) { | |
exams.push(item.examName); | |
} | |
}); | |
return exams.sort(); | |
}, | |
// Will update DoughnutChart component with breakdown of license statuses | |
chartData() { | |
// Pull # of available licenses from state (Vuex) | |
let available = this.$store.state.purchasedExams.filter(item => { | |
if (this.overviewExamFilterName == "All Exams") { | |
// Returns all exams with status of available | |
return item.status == "available"; | |
} else { | |
// Returns available exams based on filterName - ie. If filter name == 'ACSM CPT', would only return available exams with that name. | |
return ( | |
item.status == "available" && | |
item.examName == this.overviewExamFilterName | |
); | |
} | |
}).length; | |
// Pull # of consumed licenses from state (Vuex) | |
let consumed = this.$store.state.purchasedExams.filter(item => { | |
if (this.overviewExamFilterName == "All Exams") { | |
// Returns all exams with status of consumed | |
return item.status == "consumed"; | |
} else { | |
// Returns consumed exams based on filterName - ie. If filter name == 'ACSM CPT', would only return consumed exams with that name. | |
return ( | |
item.status == "consumed" && | |
item.examName == this.overviewExamFilterName | |
); | |
} | |
}).length; | |
// Pull # of pending licenses from state (Vuex) | |
let pending = this.$store.state.purchasedExams.filter(item => { | |
if (this.overviewExamFilterName == "All Exams") { | |
// Returns all exams with status of pending | |
return item.status == "pending"; | |
} else { | |
// Returns pending exams based on filterName - ie. If filter name == 'ACSM CPT', would only return pending exams with that name. | |
return ( | |
item.status == "pending" && | |
item.examName == this.overviewExamFilterName | |
); | |
} | |
}).length; | |
// Notes: available, consumed, pending variables all contain repeating code. Would be better served to created a method of filtering through exams and passing status as a parameter. | |
// For example: | |
// let pending = this.filterExams(available) | |
// filterExams(status) { | |
// this.$store.state.purchasedExams.filter(item => { | |
// if (this.overviewExamFilterName == status) { | |
// return item.status == status; | |
// } else { | |
// return ( | |
// item.status == status && | |
// item.examName == this.overviewExamFilterName | |
// ); | |
// } | |
// }).length; | |
//} ^^ Or something to this effect. | |
return { | |
total: available + consumed + pending, | |
available: available, | |
consumed: consumed, | |
pending: pending | |
}; | |
// // Could also simplify this object to be { | |
// total: available + consumed + pending, | |
// available, | |
// consumed, | |
// pending | |
// } | |
}, | |
licenses() { | |
// Will update list of exams under 'license detail's' based on filters | |
let licenseArray = this.$store.state.purchasedExams; | |
// detailsExamFilterName -- filtering by Exam (leftmost column) | |
// detailsStatusFilterName -- filtering by status (status column) | |
// Both filters set to all | |
if ( | |
this.detailsExamFilterName == "All Exams" && | |
this.detailsStatusFilterName == "All" | |
) { | |
// If no e-mail search entered, return entire array | |
if (this.emailSearch == "") { | |
return licenseArray; | |
} | |
// Return array based on if license includes searched e-mail string. | |
return licenseArray.filter(item => { | |
if (item.userEmail) { | |
return item.userEmail.includes(this.emailSearch); | |
} | |
}); | |
// Status given, Exam name set to all | |
} else if ( | |
this.detailsStatusFilterName !== "All" && | |
this.detailsExamFilterName == "All Exams" | |
) { | |
if (this.emailSearch == "") { | |
// return items with specificed status | |
return licenseArray.filter(item => { | |
return item.status == this.detailsStatusFilterName.toLowerCase(); | |
}); | |
} | |
return licenseArray.filter(item => { | |
if (item.userEmail) { | |
return ( | |
// return items with specificed status & email | |
item.status == this.detailsStatusFilterName.toLowerCase() && | |
item.userEmail.includes(this.emailSearch) | |
); | |
} | |
}); | |
// Exam name given, status filter set to all | |
} else if ( | |
this.detailsStatusFilterName == "All" && | |
this.detailsExamFilterName !== "All Exams" | |
) { | |
if (this.emailSearch == "") { | |
// return items with specificed exam name | |
return licenseArray.filter(item => { | |
return item.examName == this.detailsExamFilterName; | |
}); | |
} | |
// return items with specificed status and email | |
return licenseArray.filter(item => { | |
if (item.userEmail) { | |
return ( | |
item.examName == this.detailsExamFilterName && | |
item.userEmail.includes(this.emailSearch) | |
); | |
} | |
}); | |
// Specific exam name and specific filter given | |
} else { | |
if (this.emailSearch == "") { | |
return licenseArray.filter(item => { | |
return ( | |
// return items with specificed status & specificed exam name | |
item.examName == this.detailsExamFilterName && | |
item.status == this.detailsStatusFilterName.toLowerCase() | |
); | |
}); | |
} | |
return licenseArray.filter(item => { | |
if (item.userEmail) { | |
return ( | |
// return items with specificed status, specificed exam name, and specifided e-mail | |
item.examName == this.detailsExamFilterName && | |
item.status == this.detailsStatusFilterName.toLowerCase() && | |
item.userEmail.includes(this.emailSearch) | |
); | |
} | |
}); | |
} | |
// Notes: This again contains a lot of repeating code. Additionally, such a long if Else statement leads to more potential for bugs, limitations in scalability, and makes code harder to read. | |
// Ideally, this could be condensed into one filter function, which would take an array of filters as an argument. Similar to: | |
// let examFilter; | |
// let statusFilter; | |
// let emailFilter; | |
// let activeFilters = []; | |
// if (this.detailsExamFilterName !== "All Exams") { | |
// examFilter = this.detailsExamFilterName | |
// activeFilters.push(examFilter) | |
// } | |
// if (this.detailsStatusFilterName !== "All") { | |
// statusFilter = this.detailsStatusFilterName | |
// activeFilters.push(statusFilter) | |
// } | |
// if (this.emailSearch !== '') { | |
// emailFilter = this.emailSearch | |
// activeFilters.push(emailFilter) | |
// } | |
// function filter(arr, criteria) { | |
// return arr.filter(item => { | |
// return Object.keys(criteria).every(key => { | |
// return item[key] == criteria[key]; | |
// }); | |
// }); | |
// } | |
// filter(licenseArray, activeFilters) | |
// ^^ This is an untested solution, but gets to basic idea of cutting down on long, nested if/else statements and repetitive code. | |
}, | |
methods: { | |
examFilterSelected(cellName, exam) { | |
if (cellName == "overview") { | |
this.overviewExamFilterName = exam; | |
this.showOverviewExamFilters = false; | |
} else if (cellName == "details") { | |
this.detailsExamFilterName = exam; | |
this.showDetailsExamFilters = false; | |
} | |
}, | |
statusFilterSelected(status) { | |
this.detailsStatusFilterName = status; | |
this.showDetailsStatusFilters = false; | |
}, | |
isExpiredLicense(expirationDate) { | |
if (!expirationDate) { | |
return; | |
} | |
let today = new Date(); | |
let licenseDate = new Date(expirationDate.iso); | |
if (today.getTime() > licenseDate.getTime()) { | |
return true; | |
} | |
}, | |
showAssignLicenseAtIndex(index) { | |
this.assigningLicenseAtIndex = index; | |
}, | |
assignLicense(item) { | |
if (!Tools.isEmailAddressValid(this.emailToAssign)) { | |
return; | |
} | |
var appId = item.appId; | |
var emailAddresses = [this.emailToAssign.toLowerCase()]; | |
var bulkPurchaserId = item.bulkPurchaser.objectId; | |
ParseUtils.assignLicensesTo(appId, bulkPurchaserId, emailAddresses).then( | |
assignedLicense => { | |
// intercom event | |
window.Intercom("trackEvent", "Assigned License Dashboard"); | |
gtag("event", "dashboard_assign", { | |
event_category: "assign_license", | |
event_label: appId | |
}); | |
item.userEmail = emailAddresses[0]; | |
item.status = "pending"; | |
this.clearAssignLicenseFields(); | |
} | |
); | |
}, | |
resendLicense(item) { | |
if (item.userEmail == null) { | |
return; | |
} | |
var attributes = { | |
appId: item.appId, | |
company: this.$store.state.user.get("company"), | |
email: item.userEmail.toLowerCase(), | |
examName: item.examName, | |
licenseKey: item.licenseKey | |
}; | |
ParseUtils.resendLicense(attributes).then(success => { | |
// intercom event | |
window.Intercom("trackEvent", "Resent Invite"); | |
if (success == true) { | |
this.showAssignSuccess = true; | |
setTimeout(() => { | |
this.showAssignSuccess = false; | |
}, 4000); | |
} | |
}); | |
}, | |
cancelAssign() { | |
this.clearAssignLicenseFields(); | |
}, | |
clearAssignLicenseFields() { | |
this.assigningLicenseAtIndex = null; | |
this.emailToAssign = null; | |
}, | |
cancelInvite(item) { | |
ParseUtils.cancelInvite(item.licenseKey).then(license => { | |
// intercom event | |
window.Intercom("trackEvent", "Cancelled Invite"); | |
item.userEmail = null; | |
item.status = "available"; | |
}); | |
}, | |
formatPrice(val) { | |
val = val.toString(); | |
val = val.slice(0, -2) + "." + val.slice(-2); | |
// val = '$' + val.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,") | |
return val; | |
}, | |
exportLicenseDetails() { | |
var csv = "Exam,User,License Key,Status,ExpirationDate\n"; | |
var dateString = ""; | |
this.licenses.forEach(license => { | |
if (license.expirationDate && license.expirationDate.iso) { | |
var date = new Date(license.expirationDate.iso); | |
var year = date.getFullYear(); | |
var month = date.getMonth() + 1; | |
var dt = date.getDate(); | |
var hour = date.getHours(); | |
var minute = date.getMinutes(); | |
var second = date.getSeconds(); | |
if (dt < 10) { | |
dt = "0" + dt; | |
} | |
if (month < 10) { | |
month = "0" + month; | |
} | |
if (hour < 10) { | |
hour = "0" + hour; | |
} | |
if (minute < 10) { | |
minute = "0" + minute; | |
} | |
if (second < 10) { | |
second = "0" + second; | |
} | |
dateString = | |
year + | |
"-" + | |
month + | |
"-" + | |
dt + | |
" " + | |
hour + | |
":" + | |
minute + | |
":" + | |
second; | |
} else { | |
dateString = ""; | |
} | |
var data = [ | |
license.examName, | |
license.userEmail, | |
license.licenseKey, | |
license.status, | |
dateString | |
]; | |
csv += data.join(","); | |
csv += "\n"; | |
}); | |
// Prior method did not work in Safari, this does | |
// https://github.com/mholt/PapaParse/issues/175 | |
const blob = new Blob([csv]); | |
if (window.navigator.msSaveOrOpenBlob) { | |
window.navigator.msSaveBlob(blob, "license-details.csv"); | |
} else { | |
var a = window.document.createElement("a"); | |
a.href = window.URL.createObjectURL(blob, { | |
type: "text/csv;charset=utf-8" | |
}); | |
a.download = "license-details.csv"; | |
document.body.appendChild(a); | |
a.click(); | |
document.body.removeChild(a); | |
} | |
}, | |
recallSelectedLicense() { | |
return ParseUtils.recallLicense( | |
this.selectedLicense.licenseKey, | |
true | |
).then(_ => { | |
// intercom event | |
window.Intercom("trackEvent", "Recalled License"); | |
this.dismissRecallConfirmation(); | |
// go fetch the updated license info | |
this.$store.dispatch("getPurchasedExams"); | |
}); | |
}, | |
showRecallConfirmation(item) { | |
(this.selectedLicense = item), (this.confirmRecall = true); | |
}, | |
dismissRecallConfirmation() { | |
// clear out our local state | |
this.confirmRecall = false; | |
this.selectedLicense = undefined; | |
} | |
}, | |
filters: { | |
formateDate(val) { | |
if (!val) { | |
return "-"; | |
} | |
return moment(val.iso).calendar(); | |
} | |
}, | |
mounted() { | |
// intercom updates | |
let user = this.$store.state.user; | |
let metaData = this.$store.state.userMetaData; | |
if (user && metaData) { | |
let appNames = ""; | |
let exams = []; | |
metaData.exams.forEach(exam => { | |
appNames = appNames + exam.name + ", "; | |
exams.push(exam.name); | |
}); | |
let totalSpent = this.formatPrice(metaData.subtotal); | |
let numOfExams = Array.from(new Set(exams)); | |
console.log(metaData); | |
const attributes = { | |
Company: user.get("company"), | |
"Has made a purchase": metaData.subtotal > 0 ? "Yes" : "No", | |
"Number of Purchases Made": metaData.numberOfPurchasesMade, | |
"Total Spent": totalSpent, | |
"Number of licenses purchased / received": metaData.totalNumOfLicenses, | |
"Number of licenses available": this.chartData.available, | |
"Number of licenses pending": this.chartData.pending, | |
"Number of licenses redeemed": this.chartData.consumed, | |
"App Names": appNames, | |
"Number of exams": numOfExams.length, | |
"Has Received Gifted Licenses": metaData.attachedLicenseCount | |
? "Yes" | |
: "No" | |
}; | |
window.intercomSettings = { | |
email: user.get("email"), | |
name: user.get("firstName") + " " + user.get("lastName"), | |
user_id: user.id | |
}; | |
window.Intercom("update", attributes); | |
window.Intercom("trackEvent", "Viewed Dashboard"); | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment