From b1d37b2c2029e4d63694d520a280c3768fcb32e0 Mon Sep 17 00:00:00 2001 From: Hannah Zhou <91917682+plumshum@users.noreply.github.com> Date: Mon, 19 Feb 2024 17:32:45 -0500 Subject: [PATCH 1/7] updated contributors page (#890) --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index fbc6aae71..431dafd48 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,17 @@ Then access http://localhost:8080/ ## Contributors +## SP24 +- **Hannah Zhou** - Developer +- **Nidhi Mylavarapu** - Developer +- **Simon Ilincev** - Developer +- **Zak Kent** - Dev Advisor +- **Joanna Chen** - Designer +- **Elizabeth Tang** - TPM +- **Andrew Xu** - TPM +- **Kaylin Chan** - PM +- **Ilyssa Yan** - APM + ### FA23 - **Nidhi Mylavarapu** - Developer - **Simon Ilincev** - Developer @@ -29,6 +40,7 @@ Then access http://localhost:8080/ - **Miranda Yu** - Developer - **Elizabeth Tang** - Developer - **Pablo Raigoza** - Developer +- **Andrew Xu** - Developer - **Michelle Dai** - Designer - **Joanna Chen** - Designer - **Jonathan Mak** - PMM From 75f8840c16144d4ab3d6466b4947f7c4de02a4a0 Mon Sep 17 00:00:00 2001 From: Simon Ilincev Date: Wed, 21 Feb 2024 15:00:10 -0500 Subject: [PATCH 2/7] chore: added engrc 3027 as valid engrc (#891) --- src/data/colleges/en.ts | 1 + src/requirements/decorated-requirements.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/data/colleges/en.ts b/src/data/colleges/en.ts index d56454a42..a267f1bb6 100644 --- a/src/data/colleges/en.ts +++ b/src/data/colleges/en.ts @@ -211,6 +211,7 @@ const engineeringRequirements: readonly CollegeOrMajorRequirement[] = [ 'COMM 3030', 'COMM 3020', 'ENGRC 3023', + 'ENGRC 3027', 'ENGRC 2640', 'ENGRC 3152', 'ENGRC 3160', diff --git a/src/requirements/decorated-requirements.json b/src/requirements/decorated-requirements.json index b854fa7f4..0e5764cb7 100644 --- a/src/requirements/decorated-requirements.json +++ b/src/requirements/decorated-requirements.json @@ -54754,7 +54754,8 @@ 367847, 367848, 367922, - 371145 + 371145, + 373380 ] ] } From 69871d79f63faa76c3af7928dc099556fe33895e Mon Sep 17 00:00:00 2001 From: Andrew Xu <53061040+andxu282@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:37:20 -0400 Subject: [PATCH 3/7] Add ENGRC 3025 as Engineering Communications (#900) * add engrc 3025 * run req-gen --- src/data/colleges/en.ts | 1 + src/requirements/decorated-requirements.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/data/colleges/en.ts b/src/data/colleges/en.ts index a267f1bb6..7355e3c2d 100644 --- a/src/data/colleges/en.ts +++ b/src/data/colleges/en.ts @@ -211,6 +211,7 @@ const engineeringRequirements: readonly CollegeOrMajorRequirement[] = [ 'COMM 3030', 'COMM 3020', 'ENGRC 3023', + 'ENGRC 3025', 'ENGRC 3027', 'ENGRC 2640', 'ENGRC 3152', diff --git a/src/requirements/decorated-requirements.json b/src/requirements/decorated-requirements.json index 0e5764cb7..cae71ca2d 100644 --- a/src/requirements/decorated-requirements.json +++ b/src/requirements/decorated-requirements.json @@ -54755,6 +54755,7 @@ 367848, 367922, 371145, + 371205, 373380 ] ] From e97cd36d9ad994516e59051548fb427ce529c059 Mon Sep 17 00:00:00 2001 From: elizabeth-tang <43019442+elizabeth-tang@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:50:57 -0400 Subject: [PATCH 4/7] multiple plans! (#877) * refactor whole codebase to plans instead of semesters * add functions that disappeared after merge * Implemented multiple plans feature flag and added add plan button * Multiple plans dropdown (#806) * Implement dropdown frontend - Add dropdown component - Add cypress tests for open/close states. * Add changing arrow direction * Change plan when clicked * Run checks * Enable feature flag before running test * Fix arrow resizing problem and address Zak changes * Change colors to set colors, try to fix test * Tests working + remove feature flag for time being * Finally passing the cypress tests <33 * Hover state cursor -> pointer * Refactor css into scss * Add scss file lol * migration script for multiple plans in firebase (#817) * migration script for multiple plans in firebase * Move Plan type to Migration Script * Multiple plans functions (#816) * Implement dropdown frontend - Add dropdown component - Add cypress tests for open/close states. * Add changing arrow direction * Change plan when clicked * Run checks * Enable feature flag before running test * Fix arrow resizing problem and address Zak changes * Change colors to set colors, try to fix test * Tests working + remove feature flag for time being * Finally passing the cypress tests <33 * Hover state cursor -> pointer * Refactor css into scss * Add scss file lol * Implement Vuex and Firestore functions * Update src/global-firestore-data/user-semesters.ts Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Update src/global-firestore-data/user-semesters.ts Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Update src/global-firestore-data/user-semesters.ts Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Update src/store.ts Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Run format * Add computed property for plans and currentplan --------- Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Implement frontend for all modals to add, delete and edit plans. * Run npm format * call firestore functions for add blank plan * Fix type issue in teleport modal * fix issue with adding 2nd new plan * add plan type * add getter for current plan's semesters * missed one use of getter * delete duplicate functions * multiple plans is multiple planning?? * confirmation modal when plans are added/deleted/edited * fix bug to display correct plan * cypress tests * address edge cases in multiple plans (#895) * Implemented multiple plans feature flag and added add plan button * Multiple plans dropdown (#806) * Implement dropdown frontend - Add dropdown component - Add cypress tests for open/close states. * Add changing arrow direction * Change plan when clicked * Run checks * Enable feature flag before running test * Fix arrow resizing problem and address Zak changes * Change colors to set colors, try to fix test * Tests working + remove feature flag for time being * Finally passing the cypress tests <33 * Hover state cursor -> pointer * Refactor css into scss * Add scss file lol * migration script for multiple plans in firebase (#817) * migration script for multiple plans in firebase * Move Plan type to Migration Script * Multiple plans functions (#816) * Implement dropdown frontend - Add dropdown component - Add cypress tests for open/close states. * Add changing arrow direction * Change plan when clicked * Run checks * Enable feature flag before running test * Fix arrow resizing problem and address Zak changes * Change colors to set colors, try to fix test * Tests working + remove feature flag for time being * Finally passing the cypress tests <33 * Hover state cursor -> pointer * Refactor css into scss * Add scss file lol * Implement Vuex and Firestore functions * Update src/global-firestore-data/user-semesters.ts Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Update src/global-firestore-data/user-semesters.ts Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Update src/global-firestore-data/user-semesters.ts Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Update src/store.ts Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Run format * Add computed property for plans and currentplan --------- Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> * Implement frontend for all modals to add, delete and edit plans. * Run npm format * call firestore functions for add blank plan * Fix type issue in teleport modal * fix issue with adding 2nd new plan * refactor whole codebase to plans instead of semesters * add functions that disappeared after merge * add plan type * add getter for current plan's semesters * missed one use of getter * delete duplicate functions * multiple plans is multiple planning?? * confirmation modal when plans are added/deleted/edited * fix bug to display correct plan * cypress tests * address edge cases in multiple plans * disable buttons * frontend fixes * frontend fix again * tour + refactoring * Revert "frontend fixes" This reverts commit 2e66263bdea759dfe6e2b72c1af0721af2218785. * Revert "tour + refactoring" This reverts commit 49ee18dc9900df93e080e29c48e79b7174ca6a73. * change button radius * refactoring again * silly format fix * frontend fixes * auto name for copy * sawNewFeature migration * tour! * firebase changes * slay? only appear once? * address edge cases in multiple plans * disable buttons * frontend fixes * frontend fix again * tour + refactoring * Revert "frontend fixes" This reverts commit 2e66263bdea759dfe6e2b72c1af0721af2218785. * Revert "tour + refactoring" This reverts commit 49ee18dc9900df93e080e29c48e79b7174ca6a73. * change button radius * refactoring again * silly format fix * frontend fixes * auto name for copy * sawNewFeature migration * tour! * firebase changes * slay? only appear once? * cypress --------- Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> Co-authored-by: andxu282 * get rid of console * copy name * fix * fix --------- Co-authored-by: zachary0kent <73757337+zachary0kent@users.noreply.github.com> Co-authored-by: andxu282 --- cypress/integration/test.spec.ts | 17 ++ package.json | 2 +- scripts/migration/new-feature-migration.ts | 28 +++ scripts/migration/plans-migration.ts | 32 ++++ scripts/track-users.ts | 6 +- src/assets/images/editplan.svg | 4 + src/components/Course/CourseCaution.vue | 3 +- src/components/Modals/EditSemester.vue | 2 +- .../Modals/MultiplePlans/AddPlanModal.vue | 71 ++++++++ .../Modals/MultiplePlans/CopyPlanModal.vue | 124 +++++++++++++ .../Modals/MultiplePlans/EditPlanModal.vue | 119 ++++++++++++ .../Modals/MultiplePlans/NamePlanModal.vue | 99 ++++++++++ .../MultiplePlans/PlanModalDropdown.scss | 74 ++++++++ .../Modals/MultiplePlans/TextInputModal.vue | 89 +++++++++ src/components/Modals/NewSemesterModal.vue | 2 +- .../Modals/Onboarding/Onboarding.vue | 3 +- src/components/Modals/TeleportModal.vue | 144 +++++++-------- .../Requirements/CompletedSubReqCourse.vue | 5 +- .../Requirements/IncompleteSelfCheck.vue | 6 +- .../Requirements/MultiplePlansDropdown.scss | 84 +++++++++ .../Requirements/MultiplePlansDropdown.vue | 102 +++++++++++ .../Requirements/RequirementSideBar.vue | 169 +++++++++++++++++- src/components/Semester/Semester.vue | 44 ++++- src/components/Semester/SemesterView.vue | 11 +- src/containers/Dashboard.vue | 7 +- src/feature-flags.ts | 6 +- src/global-firestore-data/index.ts | 10 +- .../user-onboarding-data.ts | 8 + src/global-firestore-data/user-semesters.ts | 99 +++++++--- src/gtag.ts | 16 ++ src/requirements/__test__/exam-credit.test.ts | 1 + src/store.ts | 67 +++++-- src/tools/export-plan/pdf-generator.ts | 2 +- src/user-data-converter.ts | 1 + src/user-data.d.ts | 12 +- src/utilities.ts | 7 +- 36 files changed, 1330 insertions(+), 146 deletions(-) create mode 100644 scripts/migration/new-feature-migration.ts create mode 100644 scripts/migration/plans-migration.ts create mode 100644 src/assets/images/editplan.svg create mode 100644 src/components/Modals/MultiplePlans/AddPlanModal.vue create mode 100644 src/components/Modals/MultiplePlans/CopyPlanModal.vue create mode 100644 src/components/Modals/MultiplePlans/EditPlanModal.vue create mode 100644 src/components/Modals/MultiplePlans/NamePlanModal.vue create mode 100644 src/components/Modals/MultiplePlans/PlanModalDropdown.scss create mode 100644 src/components/Modals/MultiplePlans/TextInputModal.vue create mode 100644 src/components/Requirements/MultiplePlansDropdown.scss create mode 100644 src/components/Requirements/MultiplePlansDropdown.vue diff --git a/cypress/integration/test.spec.ts b/cypress/integration/test.spec.ts index 83c4e3b46..a915c7257 100644 --- a/cypress/integration/test.spec.ts +++ b/cypress/integration/test.spec.ts @@ -17,6 +17,12 @@ before('Visit site logged in', () => { cy.wait(5000); // ensure the page has time to load }); +// Test to confirm that the new user walkthrough works as expected +// Click through the initial explanation, then the 4 following steps, and finally the finishing page +it('Click through new feature tour', () => { + cy.get('.introjs-nextbutton').click(); +}); + // Delete existing semesters to ensure existing data does not mess with tests it('Delete all existing semesters, if any exist', () => { const semesterMenus = '[data-cyId=semesterMenu]'; @@ -237,3 +243,14 @@ it('Minimize a semester', () => { cy.get('[data-cyId=semester-course]').should('be.visible'); cy.get('[data-cyId=semester-addCourse]').should('be.visible'); }); + +it('Multiple plans dropdown open/close', () => { + // dropdown initially closed + cy.get('[data-cyId=multiplePlans-dropdown-content]').should('not.exist'); + cy.get('[data-cyId=multiplePlans-dropdown-open]').click(); + // dropdown opens + cy.get('[data-cyId=multiplePlans-dropdown-content]').should('be.visible'); + cy.get('[data-cyId=multiplePlans-dropdown-close]').click(); + // dropdown closed again + cy.get('[data-cyId=multiplePlans-dropdown-content]').should('not.exist'); +}); diff --git a/package.json b/package.json index dd1bcdf91..616fa202d 100644 --- a/package.json +++ b/package.json @@ -100,4 +100,4 @@ "not dead" ], "license": "AGPL-3.0" -} \ No newline at end of file +} diff --git a/scripts/migration/new-feature-migration.ts b/scripts/migration/new-feature-migration.ts new file mode 100644 index 000000000..2c2642cbb --- /dev/null +++ b/scripts/migration/new-feature-migration.ts @@ -0,0 +1,28 @@ +/* eslint-disable no-console */ + +import { usernameCollection, onboardingDataCollection } from '../firebase-config'; + +/** + * Perform migration of semester to plans with a list of semesters + */ +async function runOnUser(userEmail: string) { + await onboardingDataCollection.doc(userEmail).update({ sawNewFeature: false }); +} + +async function main() { + const userEmail = process.argv[2]; + if (userEmail != null) { + await runOnUser(userEmail); + return; + } + const collection = await usernameCollection.get(); + for (const { id } of collection.docs) { + console.group(`Running on ${id}...`); + // Intentionally await in a loop to have no interleaved console logs. + // eslint-disable-next-line no-await-in-loop + await runOnUser(id); + console.groupEnd(); + } +} + +main(); diff --git a/scripts/migration/plans-migration.ts b/scripts/migration/plans-migration.ts new file mode 100644 index 000000000..8ed979f64 --- /dev/null +++ b/scripts/migration/plans-migration.ts @@ -0,0 +1,32 @@ +/* eslint-disable no-console */ + +import { usernameCollection, semestersCollection } from '../firebase-config'; + +/** + * Perform migration of semester to plans with a list of semesters + */ +async function runOnUser(userEmail: string) { + const semestersDoc = await semestersCollection.doc(userEmail).get(); + const semesters = semestersDoc.data()?.semesters ?? []; + await semestersCollection.doc(userEmail).update({ + plans: [{ name: 'Plan 1', semesters }], + }); +} + +async function main() { + const userEmail = process.argv[2]; + if (userEmail != null) { + await runOnUser(userEmail); + return; + } + const collection = await usernameCollection.get(); + for (const { id } of collection.docs) { + console.group(`Running on ${id}...`); + // Intentionally await in a loop to have no interleaved console logs. + // eslint-disable-next-line no-await-in-loop + await runOnUser(id); + console.groupEnd(); + } +} + +main(); diff --git a/scripts/track-users.ts b/scripts/track-users.ts index dc956c277..999568a62 100644 --- a/scripts/track-users.ts +++ b/scripts/track-users.ts @@ -135,11 +135,11 @@ async function trackUsers() { return; } - const semesters = getFirstPlan(doc.data()); + const plan = getFirstPlan(doc.data()); let oldSemesterCount = 0; let newSemesterCount = 0; - semesters.forEach((semester: { year: number; season: string }) => { + plan.semesters.forEach((semester: { year: number; season: string }) => { if (isOld(semester)) { oldSemesterCount += 1; } else { @@ -152,7 +152,7 @@ async function trackUsers() { activeUsersCount += 1; } - numSemestersPerUser.push(semesters.length); + numSemestersPerUser.push(plan.semesters.length); oldSemesters.push(oldSemesterCount); newSemesters.push(newSemesterCount); }); diff --git a/src/assets/images/editplan.svg b/src/assets/images/editplan.svg new file mode 100644 index 000000000..470eb4545 --- /dev/null +++ b/src/assets/images/editplan.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/Course/CourseCaution.vue b/src/components/Course/CourseCaution.vue index 0ef5f2efa..0a978eaf6 100644 --- a/src/components/Course/CourseCaution.vue +++ b/src/components/Course/CourseCaution.vue @@ -98,7 +98,8 @@ const getCourseCautions = ( isPlaceholderCourse(course) && ((!store.state.orderByNewest && semesterIndex !== course.startingSemester) || (store.state.orderByNewest && - store.state.semesters.length - semesterIndex + 1 !== course.startingSemester)); + store.getters.getCurrentPlanSemesters.length - semesterIndex + 1 !== + course.startingSemester)); return { noMatchedRequirement, typicallyOfferedWarning, diff --git a/src/components/Modals/EditSemester.vue b/src/components/Modals/EditSemester.vue index 8703e37e9..e1bc36508 100644 --- a/src/components/Modals/EditSemester.vue +++ b/src/components/Modals/EditSemester.vue @@ -46,7 +46,7 @@ export default defineComponent({ }, computed: { semesters(): readonly FirestoreSemester[] { - return store.state.semesters; + return store.getters.getCurrentPlanSemesters; }, }, methods: { diff --git a/src/components/Modals/MultiplePlans/AddPlanModal.vue b/src/components/Modals/MultiplePlans/AddPlanModal.vue new file mode 100644 index 000000000..8736b395d --- /dev/null +++ b/src/components/Modals/MultiplePlans/AddPlanModal.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/components/Modals/MultiplePlans/CopyPlanModal.vue b/src/components/Modals/MultiplePlans/CopyPlanModal.vue new file mode 100644 index 000000000..0169e1d2f --- /dev/null +++ b/src/components/Modals/MultiplePlans/CopyPlanModal.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/src/components/Modals/MultiplePlans/EditPlanModal.vue b/src/components/Modals/MultiplePlans/EditPlanModal.vue new file mode 100644 index 000000000..47925c6df --- /dev/null +++ b/src/components/Modals/MultiplePlans/EditPlanModal.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/src/components/Modals/MultiplePlans/NamePlanModal.vue b/src/components/Modals/MultiplePlans/NamePlanModal.vue new file mode 100644 index 000000000..c85d0e7ca --- /dev/null +++ b/src/components/Modals/MultiplePlans/NamePlanModal.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/components/Modals/MultiplePlans/PlanModalDropdown.scss b/src/components/Modals/MultiplePlans/PlanModalDropdown.scss new file mode 100644 index 000000000..73fff3b5a --- /dev/null +++ b/src/components/Modals/MultiplePlans/PlanModalDropdown.scss @@ -0,0 +1,74 @@ +@import '@/assets/scss/_variables.scss'; + +.multiplePlansModal-dropdown { + &-placeholder { + width: 100%; + height: 100%; + font-size: 14px; + font-weight: bold; + display: flex; + align-items: center; + + color: $darkPlaceholderGray; + + background: transparent; + + &.wrapper { + position: relative; + height: 2rem; + border-radius: 2px; + border: 1px solid $darkPlaceholderGray; + cursor: pointer; + } + + &.plan { + width: 100%; + padding-left: 10px; + } + + &.down-arrow { + position: relative; + right: 7%; + width: 6.24px; + height: 6.24px; + border-left: 6.24px solid transparent; + border-right: 6.24px solid transparent; + border-top: 6.24px solid $darkPlaceholderGray; + } + + &.up-arrow { + position: relative; + right: 7%; + width: 6.24px; + height: 6.24px; + border-left: 6.24px solid transparent; + border-right: 6.24px solid transparent; + border-top: 6.24px solid $darkPlaceholderGray; + transform: rotate(180deg); + } + } + + &-content { + width: 100%; + z-index: 100; + max-height: 8rem; + border-radius: 2px; + &.item { + border: 1px solid $darkPlaceholderGray; + z-index: 150; + background-color: white; + height: 2rem; + font-size: 14px; + line-height: 16px; + display: flex; + align-items: center; + color: $darkPlaceholderGray; + padding-left: 10px; + } + &.item:hover { + background-color: $searchBoxHoverGray; + opacity: 1; + cursor: pointer; + } + } +} diff --git a/src/components/Modals/MultiplePlans/TextInputModal.vue b/src/components/Modals/MultiplePlans/TextInputModal.vue new file mode 100644 index 000000000..90f46a237 --- /dev/null +++ b/src/components/Modals/MultiplePlans/TextInputModal.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/components/Modals/NewSemesterModal.vue b/src/components/Modals/NewSemesterModal.vue index cd956e6f8..f493e5aea 100644 --- a/src/components/Modals/NewSemesterModal.vue +++ b/src/components/Modals/NewSemesterModal.vue @@ -37,7 +37,7 @@ export default defineComponent({ }, computed: { semesters(): readonly FirestoreSemester[] { - return store.state.semesters; + return store.getters.getCurrentPlanSemesters; }, }, methods: { diff --git a/src/components/Modals/Onboarding/Onboarding.vue b/src/components/Modals/Onboarding/Onboarding.vue index aea70a69d..8ac3ed32d 100644 --- a/src/components/Modals/Onboarding/Onboarding.vue +++ b/src/components/Modals/Onboarding/Onboarding.vue @@ -124,6 +124,7 @@ import { import timeline1Text from '@/assets/images/timeline1text.svg'; import timeline2Text from '@/assets/images/timeline2text.svg'; import timeline3Text from '@/assets/images/timeline3text.svg'; +import store from '@/store'; const timelineTexts = [timeline1Text, timeline2Text, timeline3Text]; @@ -251,7 +252,7 @@ export default defineComponent({ this.clearTransferCreditIfGraduate(); setAppOnboardingData(this.name, revised); // indicates first time user onboarding - if (!this.isEditingProfile) populateSemesters(revised); + if (!this.isEditingProfile) populateSemesters(store.state.currentPlan, revised); this.$emit('onboard'); }, goBack() { diff --git a/src/components/Modals/TeleportModal.vue b/src/components/Modals/TeleportModal.vue index 0d64dff06..b5a0ff04a 100644 --- a/src/components/Modals/TeleportModal.vue +++ b/src/components/Modals/TeleportModal.vue @@ -23,7 +23,12 @@