From 9c033e1b3a79955a82267e4542812a9d8adda4eb Mon Sep 17 00:00:00 2001 From: Trey Stevens Date: Tue, 1 Dec 2020 16:54:55 -0500 Subject: [PATCH 1/3] added constants and utils for subject unlocking from server side --- src/consts.js | 166 +++++++++++++++++++++++++++++ src/utils/get-subject-type.js | 26 +++++ src/utils/get-unlocked-subjects.js | 31 ++++++ 3 files changed, 223 insertions(+) create mode 100644 src/utils/get-subject-type.js create mode 100644 src/utils/get-unlocked-subjects.js diff --git a/src/consts.js b/src/consts.js index df62956c..8290ca7e 100644 --- a/src/consts.js +++ b/src/consts.js @@ -380,3 +380,169 @@ export const STATES_WITH_ABBREVIATIONS = [ { label: "Wisconsin", value: "WI" }, { label: "Wyoming", value: "WY" } ]; + +export const SUBJECT_TYPES = { + MATH: "math", + SCIENCE: "science", + COLLEGE: "college", + SAT: "sat", + TRAINING: "training" +}; + +export const TRAINING = { + UPCHIEVE_101: "upchieve101", + TUTORING_SKILLS: "tutoringSkills", + COLLEGE_COUNSELING: "collegeCounseling", + SAT_STRATEGIES: "satStrategies", + COLLEGE_SKILLS: "collegeSkills" +}; + +export const MATH_CERTS = { + PREALGREBA: "prealgebra", + ALGEBRA: "algebra", + GEOMETRY: "geometry", + TRIGONOMETRY: "trigonometry", + PRECALCULUS: "precalculus", + CALCULUS_AB: "calculusAB", + CALCULUS_BC: "calculusBC", + STATISTICS: "statistics" +}; + +export const MATH_SUBJECTS = { + PREALGREBA: "prealgebra", + ALGEBRA_ONE: "algebraOne", + ALGEBRA_TWO: "algebraTwo", + GEOMETRY: "geometry", + TRIGONOMETRY: "trigonometry", + PRECALCULUS: "precalculus", + CALCULUS_AB: "calculusAB", + CALCULUS_BC: "calculusBC", + STATISTICS: "statistics", + INTEGRATED_MATH_ONE: "integratedMathOne", + INTEGRATED_MATH_TWO: "integratedMathTwo", + INTEGRATED_MATH_THREE: "integratedMathThree", + INTEGRATED_MATH_FOUR: "integratedMathFour" +}; + +export const SCIENCE_CERTS = { + BIOLOGY: "biology", + CHEMISTRY: "chemistry", + PHYSICS_ONE: "physicsOne", + PHYSICS_TWO: "physicsTwo", + ENVIRONMENTAL_SCIENCE: "environmentalScience" +}; +export const SCIENCE_SUBJECTS = { + BIOLOGY: "biology", + CHEMISTRY: "chemistry", + PHYSICS_ONE: "physicsOne", + PHYSICS_TWO: "physicsTwo", + ENVIRONMENTAL_SCIENCE: "environmentalScience" +}; + +export const COLLEGE_CERTS = { + ESSAYS: "essays", + FINANCIAL_AID: "financialAid", + SPORTS_RECRUITMENT_PLANNING: "sportsRecruitmentPlanning" +}; + +export const COLLEGE_SUBJECTS = { + ESSAYS: "essays", + FINANCIAL_AID: "financialAid", + SPORTS_RECRUITMENT_PLANNING: "sportsRecruitmentPlanning", + PLANNING: "planning", + APPLICATIONS: "applications" +}; + +export const SAT_CERTS = { + SAT_MATH: "satMath", + SAT_READING: "satReading" +}; + +export const SAT_SUBJECTS = { + SAT_MATH: "satMath", + SAT_READING: "satReading" +}; + +export const SUBJECTS = { + ...MATH_SUBJECTS, + ...SCIENCE_SUBJECTS, + ...COLLEGE_SUBJECTS, + ...SAT_SUBJECTS +}; + +export const CERT_UNLOCKING = { + [MATH_CERTS.CALCULUS_BC]: [ + MATH_SUBJECTS.CALCULUS_BC, + MATH_SUBJECTS.CALCULUS_AB, + MATH_SUBJECTS.PRECALCULUS, + MATH_SUBJECTS.TRIGONOMETRY, + MATH_SUBJECTS.ALGEBRA_ONE, + MATH_SUBJECTS.ALGEBRA_TWO, + MATH_SUBJECTS.PREALGREBA + ], + [MATH_CERTS.CALCULUS_AB]: [ + MATH_SUBJECTS.CALCULUS_AB, + MATH_SUBJECTS.PRECALCULUS, + MATH_SUBJECTS.TRIGONOMETRY, + MATH_SUBJECTS.ALGEBRA_ONE, + MATH_SUBJECTS.ALGEBRA_TWO, + MATH_SUBJECTS.PREALGREBA + ], + [MATH_CERTS.PRECALCULUS]: [ + MATH_SUBJECTS.PRECALCULUS, + MATH_SUBJECTS.TRIGONOMETRY, + MATH_SUBJECTS.ALGEBRA_ONE, + MATH_SUBJECTS.ALGEBRA_TWO, + MATH_SUBJECTS.PREALGREBA + ], + [MATH_CERTS.TRIGONOMETRY]: [MATH_SUBJECTS.TRIGONOMETRY], + [MATH_CERTS.ALGEBRA]: [ + MATH_SUBJECTS.ALGEBRA_ONE, + MATH_SUBJECTS.ALGEBRA_TWO, + MATH_SUBJECTS.PREALGREBA + ], + [MATH_CERTS.PREALGREBA]: [MATH_SUBJECTS.PREALGREBA], + [MATH_CERTS.STATISTICS]: [MATH_SUBJECTS.STATISTICS], + [MATH_CERTS.GEOMETRY]: [MATH_SUBJECTS.GEOMETRY], + [SCIENCE_CERTS.BIOLOGY]: [SCIENCE_SUBJECTS.BIOLOGY], + [SCIENCE_CERTS.CHEMISTRY]: [SCIENCE_SUBJECTS.CHEMISTRY], + [SCIENCE_CERTS.PHYSICS_ONE]: [SCIENCE_SUBJECTS.PHYSICS_ONE], + [SCIENCE_CERTS.PHYSICS_TWO]: [SCIENCE_SUBJECTS.PHYSICS_TWO], + [SCIENCE_CERTS.ENVIRONMENTAL_SCIENCE]: [ + SCIENCE_SUBJECTS.ENVIRONMENTAL_SCIENCE + ], + [COLLEGE_CERTS.ESSAYS]: [COLLEGE_SUBJECTS.ESSAYS], + [COLLEGE_SUBJECTS.APPLICATIONS]: [COLLEGE_SUBJECTS.APPLICATIONS], + [COLLEGE_SUBJECTS.PLANNING]: [COLLEGE_SUBJECTS.PLANNING], + [COLLEGE_CERTS.FINANCIAL_AID]: [COLLEGE_SUBJECTS.FINANCIAL_AID], + [COLLEGE_CERTS.SPORTS_RECRUITMENT_PLANNING]: [ + COLLEGE_SUBJECTS.SPORTS_RECRUITMENT_PLANNING + ], + [SAT_CERTS.SAT_MATH]: [SAT_CERTS.SAT_MATH], + [SAT_CERTS.SAT_READING]: [SAT_CERTS.SAT_READING], + [TRAINING.COLLEGE_COUNSELING]: [SUBJECTS.PLANNING, SUBJECTS.APPLICATIONS] +}; + +export const COMPUTED_CERTS = { + [SUBJECTS.INTEGRATED_MATH_ONE]: [ + SUBJECTS.ALGEBRA_ONE, + MATH_CERTS.GEOMETRY, + MATH_CERTS.STATISTICS + ], + [SUBJECTS.INTEGRATED_MATH_TWO]: [ + SUBJECTS.ALGEBRA_ONE, + MATH_CERTS.GEOMETRY, + MATH_CERTS.STATISTICS, + MATH_CERTS.TRIGONOMETRY + ], + [SUBJECTS.INTEGRATED_MATH_THREE]: [ + MATH_CERTS.PRECALCULUS, + MATH_CERTS.STATISTICS + ], + [SUBJECTS.INTEGRATED_MATH_FOUR]: [MATH_CERTS.PRECALCULUS], + [SUBJECTS.SAT_MATH]: [ + SUBJECTS.ALGEBRA_ONE, + MATH_CERTS.TRIGONOMETRY, + MATH_CERTS.GEOMETRY + ] +}; diff --git a/src/utils/get-subject-type.js b/src/utils/get-subject-type.js new file mode 100644 index 00000000..6c44c0ab --- /dev/null +++ b/src/utils/get-subject-type.js @@ -0,0 +1,26 @@ +import { + MATH_SUBJECTS, + MATH_CERTS, + SCIENCE_SUBJECTS, + COLLEGE_SUBJECTS, + SAT_SUBJECTS, + TRAINING, + SUBJECT_TYPES +} from "../consts"; + +const getSubjectType = subject => { + let type = ""; + + if (Object.values(MATH_SUBJECTS).includes(subject)) type = SUBJECT_TYPES.MATH; + if (Object.values(MATH_CERTS).includes(subject)) type = SUBJECT_TYPES.MATH; + if (Object.values(SCIENCE_SUBJECTS).includes(subject)) + type = SUBJECT_TYPES.SCIENCE; + if (Object.values(COLLEGE_SUBJECTS).includes(subject)) + type = SUBJECT_TYPES.COLLEGE; + if (Object.values(SAT_SUBJECTS).includes(subject)) type = SUBJECT_TYPES.SAT; + if (Object.values(TRAINING).includes(subject)) type = SUBJECT_TYPES.TRAINING; + + return type; +}; + +export default getSubjectType; diff --git a/src/utils/get-unlocked-subjects.js b/src/utils/get-unlocked-subjects.js new file mode 100644 index 00000000..923d81c4 --- /dev/null +++ b/src/utils/get-unlocked-subjects.js @@ -0,0 +1,31 @@ +import { CERT_UNLOCKING, COMPUTED_CERTS } from "../consts"; + +const getUnlockedSubjects = userCertifications => { + // Add all the certifications that this completed cert unlocks into a Set + const currentSubjects = new Set(); + + for (const cert in userCertifications) { + if (userCertifications[cert].passed && CERT_UNLOCKING[cert]) + CERT_UNLOCKING[cert].forEach(subject => currentSubjects.add(subject)); + } + + for (const cert in COMPUTED_CERTS) { + const prerequisiteCerts = COMPUTED_CERTS[cert]; + let meetsRequirements = true; + + for (let i = 0; i < prerequisiteCerts.length; i++) { + const prereqCert = prerequisiteCerts[i]; + + if (!currentSubjects.has(prereqCert)) { + meetsRequirements = false; + break; + } + } + + if (meetsRequirements) currentSubjects.add(cert); + } + + return Array.from(currentSubjects); +}; + +export default getUnlockedSubjects; From 5426d958da7deeadd18f6ea816fa7061352a6ab3 Mon Sep 17 00:00:00 2001 From: Trey Stevens Date: Tue, 1 Dec 2020 16:55:17 -0500 Subject: [PATCH 2/3] activate / deactivate subjects --- src/views/ProfileView.vue | 102 +++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 17 deletions(-) diff --git a/src/views/ProfileView.vue b/src/views/ProfileView.vue index 30022867..e1f3c47a 100644 --- a/src/views/ProfileView.vue +++ b/src/views/ProfileView.vue @@ -102,17 +102,36 @@
Unlocked Subjects
-
-
-
- {{ certKey[key] }} +
    +
  • +
    + {{ getSubjectType(subject).toUpperCase() }} + {{ displaySubjectName(subject) }}
    -
    {{ key }}
    -
-
+ + +
@@ -125,6 +144,9 @@ import { mapGetters, mapState } from "vuex"; import UserService from "@/services/UserService"; import { topics, allSubtopics } from "@/utils/topics"; import DeactivateAccountModal from "./DeactivateAccountModal"; +import getUnlockedSubjects from "@/utils/get-unlocked-subjects"; +import getSubjectType from "@/utils/get-subject-type"; +import { MATH_SUBJECTS } from "@/consts"; export default { name: "profile-view", @@ -141,7 +163,8 @@ export default { phoneNational: "", phoneInputInfo: {}, isAccountActive: true, - showDeactivateAccountModal: false + showDeactivateAccountModal: false, + modifiedSubjects: [] }; }, created() { @@ -158,6 +181,8 @@ export default { e164: pn.getNumber("e164") }; } + + this.modifiedSubjects = this.user.subjects; }, computed: { ...mapState({ @@ -197,10 +222,9 @@ export default { }, subjects() { const user = this.$store.state.user.user; + const subtopics = allSubtopics(); const subjects = user.subjects.reduce((displayObj, key) => { - const subtopics = allSubtopics(); - if (subtopics[key]) { displayObj[subtopics[key].displayName || subtopics[key]] = true; } @@ -209,6 +233,20 @@ export default { }, {}); return subjects; + }, + unlockedSubjects() { + const unlockedSubjects = getUnlockedSubjects(this.user.certifications); + + /** + * @note: Some users have subjects that were grandfathered in and won't unlock + * because they do not have the required certs to unlock them + * Push the grandfathered in subjects to unlockedSubjects + **/ + for (const subject of this.user.subjects) { + if (!unlockedSubjects.includes(subject)) unlockedSubjects.push(subject); + } + + return unlockedSubjects; } }, methods: { @@ -269,10 +307,11 @@ export default { // form fields valid, so set profile this.user.phone = this.phoneInputInfo.e164; this.user.isDeactivated = !this.isAccountActive; + this.user.subjects = this.modifiedSubjects; // send only the necessary data const payloadUser = {}; - const keys = ["phone", "isDeactivated"]; + const keys = ["phone", "isDeactivated", "subjects"]; keys.forEach(key => (payloadUser[key] = this.user[key])); @@ -288,6 +327,36 @@ export default { } ); } + }, + + getSubjectType(subject) { + return getSubjectType(subject); + }, + + displaySubjectName(subject) { + const subtopics = allSubtopics(); + if (subtopics[subject]) + return subtopics[subject].displayName || subtopics[subject]; + + return subject; + }, + + isSubjectAllowedToEdit(subject) { + const subjectsNotAllowedToEdit = [ + MATH_SUBJECTS.INTEGRATED_MATH_ONE, + MATH_SUBJECTS.INTEGRATED_MATH_TWO, + MATH_SUBJECTS.INTEGRATED_MATH_THREE, + MATH_SUBJECTS.INTEGRATED_MATH_FOUR + ]; + return !subjectsNotAllowedToEdit.includes(subject); + }, + + toggleActiveSubject({ value }, subject) { + if (value) this.modifiedSubjects.push(subject); + else + this.modifiedSubjects = this.modifiedSubjects.filter( + item => item !== subject + ); } } }; @@ -485,10 +554,9 @@ button:hover { } .certBox { - display: flex; + @include flex-container(row, space-between, center); height: 60px; - align-items: center; - padding-left: 20px; + padding: 0 20px; border-top: 1px solid #cccccf; font-weight: 600; } From 94c049072d425f75dfa7c3e6893cc0cbb0760d43 Mon Sep 17 00:00:00 2001 From: Trey Stevens Date: Tue, 1 Dec 2020 16:55:55 -0500 Subject: [PATCH 3/3] show deactivated subjects as unlocked if so in training --- src/components/SubjectCertsDropDown.vue | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/components/SubjectCertsDropDown.vue b/src/components/SubjectCertsDropDown.vue index 295e0738..69f4608b 100644 --- a/src/components/SubjectCertsDropDown.vue +++ b/src/components/SubjectCertsDropDown.vue @@ -79,6 +79,7 @@ import { mapState } from "vuex"; import CheckMark from "@/components/CheckMark"; import LargeButton from "@/components/LargeButton"; import ArrowIcon from "@/assets/arrow.svg"; +import getUnlockedSubjects from "@/utils/get-unlocked-subjects"; export default { name: "SubjectCertsDropDown", @@ -110,6 +111,20 @@ export default { const largeScreenBreakpoint = 992; return this.windowWidth <= largeScreenBreakpoint; + }, + unlockedSubjects() { + const unlockedSubjects = getUnlockedSubjects(this.user.certifications); + + /** + * @note: Some users have subjects that were grandfathered in and won't unlock + * because they do not have the required certs to unlock them + * Push the grandfathered in subjects to unlockedSubjects + **/ + for (const subject of this.user.subjects) { + if (!unlockedSubjects.includes(subject)) unlockedSubjects.push(subject); + } + + return unlockedSubjects; } }, @@ -118,9 +133,11 @@ export default { return this.user.certifications[cert].passed; }, hasUnlockedSubject(cert) { - if (cert === "algebra") return this.user.subjects.includes("algebraOne"); - return this.user.subjects.includes(cert); + if (cert === "algebra") + return this.unlockedSubjects.includes("algebraOne"); + return this.unlockedSubjects.includes(cert); }, + progressStatus(cert) { if (this.isComplete(cert)) return "Completed"; if (this.hasUnlockedSubject(cert)) return "Unlocked";