Skip to content

Commit 9a8251c

Browse files
Merge pull request #958 from cornell-dti/main
Saved Courses Release!
2 parents 1a99cf3 + 275203e commit 9a8251c

31 files changed

+1593
-148
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* eslint-disable no-console */
2+
3+
import { usernameCollection, semestersCollection } from '../firebase-config';
4+
5+
/**
6+
* Perform migration of a default The 'All' Collection for All Courses saved
7+
*/
8+
async function runOnUser(userEmail: string) {
9+
const courses = [] as object;
10+
await semestersCollection.doc(userEmail).update({
11+
savedCourses: [{ name: 'All', courses }],
12+
});
13+
}
14+
15+
async function main() {
16+
const userEmail = process.argv[2];
17+
if (userEmail != null) {
18+
await runOnUser(userEmail);
19+
return;
20+
}
21+
const collection = await usernameCollection.get();
22+
for (const { id } of collection.docs) {
23+
console.group(`Running on ${id}...`);
24+
// Intentionally await in a loop to have no interleaved console logs.
25+
// eslint-disable-next-line no-await-in-loop
26+
await runOnUser(id);
27+
console.groupEnd();
28+
}
29+
}
30+
31+
main();

src/assets/images/dropdown.svg

+3
Loading
Loading
Loading

src/assets/images/plus.svg

+3
Loading

src/assets/images/saveIconBig.svg

+3
Loading

src/assets/images/saveIconSmall.svg

+3
Loading

src/assets/images/trash-gray.svg

+5
Loading

src/assets/scss/_variables.scss

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ $offWhite: #f8f8f8;
1717
$searchBoxWhite: #f1f1f1;
1818
$veryLightGray: #e5e5e5;
1919
$lightGray: #acacac;
20+
$lightestGray: #e0e0e0;
2021
$viewLabelGray: #7e7e7e80;
2122
$medGray: #737373;
2223
$darkGray: #3c3c3c;

src/components/Course/Course.vue

+82-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
}"
88
class="course"
99
>
10+
<save-course-modal
11+
:courseCode="courseCode"
12+
@close-save-course-modal="closeSaveCourseModal"
13+
@save-course="saveCourse"
14+
@add-collection="addCollection"
15+
v-if="isSaveCourseOpen"
16+
/>
1017
<edit-color
1118
:editedColor="editedColor"
1219
@color-course="colorCourse"
@@ -42,9 +49,22 @@
4249
:isCompactView="true"
4350
/>
4451
</div>
45-
<button v-if="!isReqCourse" class="course-dotRow" @click="openMenu">
52+
<button
53+
v-if="!isReqCourse && isSemesterCourseCard"
54+
class="course-dotRow"
55+
@click="openMenu"
56+
>
4657
<img src="@/assets/images/dots/threeDots.svg" alt="open menu for course card" />
4758
</button>
59+
<button
60+
v-else-if="!isReqCourse && !isSemesterCourseCard"
61+
class="course-trash"
62+
@click.stop="deleteCourseFromCollection"
63+
@mouseover="hoverTrashIcon"
64+
@mouseleave="unhoverTrashIcon"
65+
>
66+
<img :src="trashIcon" alt="delete course from collection" />
67+
</button>
4868
</div>
4969
<div v-if="!compact" class="course-name">{{ courseObj.name }}</div>
5070
<div v-if="!compact" class="course-info">
@@ -60,12 +80,15 @@
6080
</div>
6181
<course-menu
6282
v-if="menuOpen"
83+
:courseObj="courseObj"
6384
:semesterIndex="semesterIndex"
6485
:isCompact="compact"
6586
:courseColor="courseObj.color"
87+
:courseCode="courseObj.code"
6688
@open-edit-color-modal="openEditColorModal"
6789
@delete-course="deleteCourse"
6890
@edit-course-credit="editCourseCredit"
91+
@open-save-course-modal="openSaveCourseModal"
6992
:getCreditRange="getCreditRange || []"
7093
v-click-outside="closeMenuIfOpen"
7194
/>
@@ -76,17 +99,20 @@
7699
import { CSSProperties, PropType, defineComponent } from 'vue';
77100
import CourseMenu from '@/components/Modals/CourseMenu.vue';
78101
import CourseCaution from '@/components/Course/CourseCaution.vue';
102+
import SaveCourseModal from '@/components/Modals/SaveCourseModal.vue';
79103
import {
80104
addCourseToBottomBar,
81105
reportCourseColorChange,
82106
reportSubjectColorChange,
83107
} from '@/components/BottomBar/BottomBarState';
108+
import { isCourseConflict } from '@/store';
84109
import { clickOutside } from '@/utilities';
85110
import EditColor from '../Modals/EditColor.vue';
86-
import { isCourseConflict } from '@/store';
111+
import trashGrayIcon from '@/assets/images/trash-gray.svg';
112+
import trashRedIcon from '@/assets/images/trash.svg';
87113
88114
export default defineComponent({
89-
components: { CourseCaution, CourseMenu, EditColor },
115+
components: { CourseCaution, CourseMenu, EditColor, SaveCourseModal },
90116
props: {
91117
courseObj: { type: Object as PropType<FirestoreSemesterCourse>, required: true },
92118
compact: { type: Boolean, required: true },
@@ -95,6 +121,7 @@ export default defineComponent({
95121
semesterIndex: { type: Number, required: false, default: 0 },
96122
season: { type: String, required: false, default: '' },
97123
year: { type: Number, required: false, default: 0 },
124+
isSemesterCourseCard: { type: Boolean, required: true },
98125
isSchedGenCourse: { type: Boolean, required: false, default: false },
99126
},
100127
emits: {
@@ -107,14 +134,28 @@ export default defineComponent({
107134
'course-on-click': (course: FirestoreSemesterCourse) => typeof course === 'object',
108135
'edit-course-credit': (credit: number, uniqueID: number) =>
109136
typeof credit === 'number' && typeof uniqueID === 'number',
137+
'save-course': (
138+
course: FirestoreSemesterCourse,
139+
addedToCollections: string[],
140+
deletedFromCollection: string[]
141+
) =>
142+
typeof course === 'object' &&
143+
typeof addedToCollections === 'object' &&
144+
typeof deletedFromCollection === 'object',
145+
'add-collection': (name: string) => typeof name === 'string',
146+
'delete-course-from-collection': (courseCode: string) => typeof courseCode === 'string',
110147
},
111148
data() {
112149
return {
113150
menuOpen: false,
114151
stopCloseFlag: false,
115152
getCreditRange: this.courseObj.creditRange,
116153
isEditColorOpen: false,
154+
isSaveCourseOpen: false,
117155
editedColor: '',
156+
deletingCourse: false,
157+
trashIcon: trashGrayIcon, // Default icon
158+
courseCode: '',
118159
};
119160
},
120161
computed: {
@@ -155,17 +196,35 @@ export default defineComponent({
155196
this.menuOpen = false;
156197
}
157198
},
199+
openSaveCourseModal(courseCode: string) {
200+
this.courseCode = courseCode;
201+
this.isSaveCourseOpen = true;
202+
this.closeMenuIfOpen();
203+
},
204+
closeSaveCourseModal() {
205+
this.isSaveCourseOpen = false;
206+
},
158207
deleteCourse() {
159208
this.$emit('delete-course', this.courseObj.code, this.courseObj.uniqueID);
160209
this.closeMenuIfOpen();
161210
},
211+
deleteCourseFromCollection() {
212+
this.$emit('delete-course-from-collection', this.courseObj.code);
213+
},
162214
openEditColorModal(color: string) {
163215
this.editedColor = color;
164216
this.isEditColorOpen = true;
165217
},
166218
closeEditColorModal() {
167219
this.isEditColorOpen = false;
168220
},
221+
addCollection(name: string) {
222+
this.$emit('add-collection', name);
223+
},
224+
saveCourse(addedToCollections: string[], deletedFromCollections: string[]) {
225+
const course = { ...this.courseObj };
226+
this.$emit('save-course', course, addedToCollections, deletedFromCollections);
227+
},
169228
colorCourse(color: string) {
170229
this.$emit('color-course', color, this.courseObj.uniqueID, this.courseObj.code);
171230
reportCourseColorChange(this.courseObj.uniqueID, color);
@@ -177,7 +236,7 @@ export default defineComponent({
177236
this.closeMenuIfOpen();
178237
},
179238
courseOnClick() {
180-
if (!this.menuOpen) {
239+
if (!this.menuOpen && !this.deletingCourse) {
181240
this.$emit('course-on-click', this.courseObj);
182241
addCourseToBottomBar(this.courseObj, this.season, this.year);
183242
}
@@ -187,6 +246,12 @@ export default defineComponent({
187246
this.closeMenuIfOpen();
188247
},
189248
isCourseConflict,
249+
hoverTrashIcon() {
250+
this.trashIcon = trashRedIcon;
251+
},
252+
unhoverTrashIcon() {
253+
this.trashIcon = trashGrayIcon;
254+
},
190255
},
191256
directives: {
192257
'click-outside': clickOutside,
@@ -251,6 +316,18 @@ export default defineComponent({
251316
}
252317
}
253318
319+
&-trash {
320+
padding: 8px 0;
321+
display: flex;
322+
position: relative;
323+
324+
&:hover,
325+
&:active,
326+
&:focus {
327+
cursor: pointer;
328+
}
329+
}
330+
254331
&-content {
255332
width: calc(100% - #{$colored-grabber-width});
256333
padding: 0 1rem;
@@ -297,8 +374,7 @@ export default defineComponent({
297374
display: flex;
298375
align-items: center;
299376
}
300-
301-
&-credits {
377+
port &-credits {
302378
white-space: nowrap;
303379
}
304380

src/components/DropDownArrow.vue

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export default defineComponent({
3131
</script>
3232

3333
<style scoped lang="scss">
34+
@import '@/assets/scss/_variables.scss';
3435
.arrow {
3536
height: 14px;
3637
width: 14px;

0 commit comments

Comments
 (0)