Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to an external cloud function to store requirements JSON #889

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 24 additions & 19 deletions src/components/Modals/Onboarding/Onboarding.vue
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,7 @@ import OnboardingBasic from '@/components/Modals/Onboarding/OnboardingBasic.vue'
import OnboardingTransfer from '@/components/Modals/Onboarding/OnboardingTransfer.vue';
import OnboardingReview from '@/components/Modals/Onboarding/OnboardingReview.vue';
import { setAppOnboardingData, populateSemesters } from '@/global-firestore-data';
import {
getMajorFullName,
getMinorFullName,
getGradFullName,
computeGradYears,
SeasonOrdinal,
} from '@/utilities';
import { computeGradYears, SeasonOrdinal } from '@/utilities';
import timeline1Text from '@/assets/images/timeline1text.svg';
import timeline2Text from '@/assets/images/timeline2text.svg';
import timeline3Text from '@/assets/images/timeline3text.svg';
Expand Down Expand Up @@ -176,17 +170,21 @@ export default defineComponent({
*
* @returns true if onboarding contains a major, minor, or program that is not in
* requirementsJSON on this branch, false otherwise.
*
* FIXME: the requirement graph is not generated for the chosen major / minor / grad
* etc. and so cannot tell if the user has chosen a valid major / minor / grad.
*/
isInvalidMajorMinorGradError(): boolean {
return (
this.onboarding.major
.map(getMajorFullName)
.some((majorFullName: string) => majorFullName === '') ||
this.onboarding.minor
.map(getMinorFullName)
.some((minorFullName: string) => minorFullName === '') ||
(this.onboarding.grad ? getGradFullName(this.onboarding.grad) === '' : false)
);
return false;
// return (
// this.onboarding.major
// .map(getMajorFullName)
// .some((majorFullName: string) => majorFullName === '') ||
// this.onboarding.minor
// .map(getMinorFullName)
// .some((minorFullName: string) => minorFullName === '') ||
// (this.onboarding.grad ? getGradFullName(this.onboarding.grad) === '' : false)
// );
},
/**
* Display error if the entrance and graduation year are not blank and the graduation semester comes before entrance semester, comparing the season if not blank
Expand Down Expand Up @@ -249,7 +247,7 @@ export default defineComponent({
submitOnboarding() {
const revised = this.setASCollegeReqs();
this.clearTransferCreditIfGraduate();
setAppOnboardingData(this.name, revised);
// setAppOnboardingData(this.name, revised); // now done when you navigate to the page
// indicates first time user onboarding
if (!this.isEditingProfile) populateSemesters(revised);
this.$emit('onboard');
Expand Down Expand Up @@ -279,9 +277,16 @@ export default defineComponent({
) {
// special case: if the user has a graduate program (and not an undergrad program), skip the transfer page
if (this.onboarding.grad !== '' && !this.onboarding.college && this.currentPage === 1) {
const revised = this.setASCollegeReqs();
this.clearTransferCreditIfGraduate();
setAppOnboardingData(this.name, revised);
this.currentPage += 2;
} else {
this.currentPage = this.currentPage === FINAL_PAGE ? FINAL_PAGE : this.currentPage + 1;
} else if (this.currentPage !== FINAL_PAGE) {
// Needs to be done ahead of time.
const revised = this.setASCollegeReqs();
this.clearTransferCreditIfGraduate();
setAppOnboardingData(this.name, revised);
this.currentPage += 1;
}
}
},
Expand Down
53 changes: 17 additions & 36 deletions src/components/Modals/Onboarding/OnboardingBasic.vue
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,8 @@

<script lang="ts">
import { PropType, defineComponent } from 'vue';
import reqsData from '@/requirements/typed-requirement-json';
import {
clickOutside,
getCurrentYear,
getCollegeFullName,
computeGradYears,
computeEntranceYears,
} from '@/utilities';
import store from '@/store';
import { clickOutside, getCurrentYear, computeGradYears, computeEntranceYears } from '@/utilities';
import OnboardingBasicMultiDropdown from './OnboardingBasicMultiDropdown.vue';
import OnboardingBasicSingleDropdown from './OnboardingBasicSingleDropdown.vue';

Expand All @@ -193,6 +187,11 @@ import spring from '@/assets/images/springEmoji.svg';
import winter from '@/assets/images/winterEmoji.svg';
import summer from '@/assets/images/summerEmoji.svg';

import majors from '@/requirements/majors.json';
import minors from '@/requirements/minors.json';
import colleges from '@/requirements/colleges.json';
import grad from '@/requirements/grad.json';

const placeholderText = 'Select one';

export default defineComponent({
Expand Down Expand Up @@ -274,40 +273,22 @@ export default defineComponent({
return computeGradYears(this.entranceYear);
},
colleges(): Readonly<Record<string, string>> {
const base = Object.entries(reqsData.college)
.filter(college => !college[0].startsWith('AS'))
.map(([key, { name }]) => [key, name]);
base.push(['AS', getCollegeFullName('AS')]);
base.sort((c1, c2) => c1[1].localeCompare(c2[1]));
return Object.fromEntries(base);
return Object.fromEntries(colleges);
},
majors(): Readonly<Record<string, string>> {
const majors: Record<string, string> = {};
const majorJSON = reqsData.major;
// only majors in the user's college
const acr = this.collegeAcronym !== 'AS' ? this.collegeAcronym : 'AS2';
Object.keys(majorJSON).forEach(key => {
// only show majors for schools the user is in
if (majorJSON[key].schools.includes(acr)) {
majors[key] = majorJSON[key].name;
}
});
return majors;
return Object.fromEntries(majors.filter(it => it[2].includes(acr)));
},
minors(): Readonly<Record<string, string>> {
const minors: Record<string, string> = {};
const minorJSON = reqsData.minor;
Object.keys(minorJSON).forEach(key => {
// show no minors if the user is not in a college
if (this.collegeAcronym) {
minors[key] = minorJSON[key].name;
}
});
return minors;
// show no minors if the user is not in a college
if (!this.collegeAcronym) {
return {};
}
return Object.fromEntries(minors);
},
gradPrograms(): Readonly<Record<string, string>> {
return Object.fromEntries(
Object.entries(reqsData.grad).map(([key, { name }]) => [key, name])
);
return Object.fromEntries(grad);
},
suggestedEntranceSem(): Readonly<number> {
return getCurrentYear();
Expand Down Expand Up @@ -359,7 +340,7 @@ export default defineComponent({
},
// Clear a major if a new college is selected and the major is not in it
clearMajorIfNotInCollege() {
const majorJSON = reqsData.major;
const majorJSON = store.state.storedRequirementsJSON.major;
for (let x = 0; x < this.majorAcronyms.length; x += 1) {
const majorAcronym = this.majorAcronyms[x];
let foundCollege = false;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Modals/Onboarding/OnboardingReview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ import {
getMajorFullName,
getMinorFullName,
getGradFullName,
} from '@/utilities';
} from '@/store-utilities';
import { GTagEvent } from '@/gtag';

const placeholderText = 'Select one';
Expand Down
4 changes: 2 additions & 2 deletions src/components/Requirements/RequirementHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,13 @@
import { PropType, defineComponent } from 'vue';
import DropDownArrow from '@/components/DropDownArrow.vue';
import ProgressBarCaution from '@/components/Requirements/ProgressBarCaution.vue';
import { getReqColor } from '@/utilities';
import {
getCollegeFullName,
getMajorFullName,
getMinorFullName,
getGradFullName,
getReqColor,
} from '@/utilities';
} from '@/store-utilities';
import featureFlagCheckers from '@/feature-flags';
import {
groupedRequirementDangerouslyFulfilled,
Expand Down
2 changes: 1 addition & 1 deletion src/components/Tools/AdvisorCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import store from '@/store';
import { getCollegeFullName, getMajorFullName } from '@/utilities';
import { getCollegeFullName, getMajorFullName } from '@/store-utilities';
import { AdvisorPackage } from '@/tools/advisors/types';
import getAdvisor from '@/tools/advisors/utilities';

Expand Down
29 changes: 13 additions & 16 deletions src/containers/Profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,7 @@ import OnboardingBasic from '@/components/Modals/Onboarding/OnboardingBasic.vue'
import OnboardingTransfer from '@/components/Modals/Onboarding/OnboardingTransfer.vue';
import { setAppOnboardingData } from '@/global-firestore-data';
import ProfileConfirmation from '@/components/Modals/ProfileConfirmation.vue';
import {
getMajorFullName,
getMinorFullName,
getGradFullName,
computeGradYears,
SeasonOrdinal,
} from '@/utilities';
import { computeGradYears, SeasonOrdinal } from '@/utilities';
import store from '@/store';

const placeholderText = 'Select one';
Expand Down Expand Up @@ -119,16 +113,19 @@ export default defineComponent({
}
return false;
},
// FIXME: the requirement graph is not generated for the chosen major / minor / grad
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wasn't super clear. Essentially what I mean here is that if you click to pick a new major (or college or minor or grad), we don't fetch from the cloud function to get the requirements for that major. Doing so would take say 0.5 seconds and so the warning would flash for 0.5 seconds, as the current requirement json has no information about whatever new choice you made and would hence think it is invalid.

// etc. and so cannot tell if the user has chosen a valid major / minor / grad.
isInvalidMajorMinorGradError(): boolean {
return (
this.onboarding.major
.map(getMajorFullName)
.some((majorFullName: string) => majorFullName === '') ||
this.onboarding.minor
.map(getMinorFullName)
.some((minorFullName: string) => minorFullName === '') ||
(this.onboarding.grad ? getGradFullName(this.onboarding.grad) === '' : false)
);
return false;
// return (
// this.onboarding.major
// .map(getMajorFullName)
// .some((majorFullName: string) => majorFullName === '') ||
// this.onboarding.minor
// .map(getMinorFullName)
// .some((minorFullName: string) => minorFullName === '') ||
// (this.onboarding.grad ? getGradFullName(this.onboarding.grad) === '' : false)
// );
},
isError(): boolean {
if (!this.changed || this.isInvalidGraduationSemester || this.isInvalidMajorMinorGradError) {
Expand Down
30 changes: 30 additions & 0 deletions src/requirements/colleges.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[
[
"AG",
"Agriculture and Life Sciences"
],
[
"AR",
"Architecture, Art and Planning"
],
[
"AS",
"Arts and Sciences"
],
[
"EN",
"Engineering"
],
[
"HE",
"Human Ecology"
],
[
"IL",
"Industrial Labor Relations"
],
[
"BU",
"SC Johnson College of Business"
]
]
40 changes: 40 additions & 0 deletions src/requirements/filter-from-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { DecoratedRequirementsJson } from './types';

// TODO: update to real firebase function URL
const BASE_URL = 'http://127.0.0.1:5001/advanced-todos-73680/us-central1/api/requirements';

export default async function getDecoratedRequirementsJson(
major?: readonly string[],
minor?: readonly string[],
college?: string,
grad?: string
): Promise<DecoratedRequirementsJson> {
try {
let formattedMajors = (major ?? []).join(',');
if (formattedMajors.length === 0) {
formattedMajors = 'skip-this';
}

let formattedMinors = (minor ?? []).join(',');
if (formattedMinors.length === 0) {
formattedMinors = 'skip-this';
}

let formattedGrad = grad;
if (!grad) {
formattedGrad = 'skip-this';
}

const route = `${BASE_URL}?major=${formattedMajors}&minor=${formattedMinors}&college=${college}&grad=${formattedGrad}`;
const response = await fetch(route);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = (await response.json()) as DecoratedRequirementsJson;
return data;
} catch (e) {
// FIXME: the alternative is to return a default json, but that
// defeats the whole purpose. Maybe throw an error here?
return {} as DecoratedRequirementsJson;
}
}
6 changes: 6 additions & 0 deletions src/requirements/grad.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
[
"MPA",
"Master of Public Administration (MPA) Program"
]
]
Loading
Loading