Skip to content

Commit

Permalink
Merge pull request #947 from cornell-dti/main
Browse files Browse the repository at this point in the history
Giveaway Modal Release!
  • Loading branch information
nidhi-mylavarapu authored Oct 18, 2024
2 parents aa75411 + 9332b4f commit 12c1f1f
Show file tree
Hide file tree
Showing 16 changed files with 334 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
SERVICE_ACCOUNT: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_CORNELLDTI_COURSEPLAN_DEV }}
- name: Upload recordings if tests fail
if: ${{ failure() }}
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: recorded-videos
path: cypress/videos/
Expand Down
1 change: 1 addition & 0 deletions scripts/firebase-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ export const trackUsersCollection = db.collection('track-users');
export const coursesCollection = db.collection('courses');
export const availableRostersForCourseCollection = db.collection('available-rosters-for-course');
export const crseIdToCatalogNbrCollection = db.collection('crseid-to-catalognbr');
export const giveawayCollection = db.collection('giveaway-entries');
28 changes: 28 additions & 0 deletions scripts/migration/giveaway-migration.ts
Original file line number Diff line number Diff line change
@@ -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({ sawGiveaway: 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();
Binary file added src/assets/images/confetti.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/BottomBar/BottomBarState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const getReviews = (
classDifficulty: number;
classWorkload: number;
}> =>
fetch('https://www.cureviews.org/api/getCourseByInfo', {
fetch('https://www.cureviews.org/api/courses/get-by-info', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ subject: subject.toLowerCase(), number }),
Expand Down
235 changes: 235 additions & 0 deletions src/components/Modals/GiveawayModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
<template>
<div
class="teleport"
:class="{
'teleport-noBackground': hasNoBackground,
'teleport-transparentBackground': hasClickableTransparentBackground,
}"
@click="closeOnClickOutside"
data-cyId="giveaway-exit"
ref="modalBackground"
>
<div class="modal-content">
<div class="modal-top">
<button @click="close" class="modal-exitbutton" data-cyId="giveaway-exit">
<img class="modal-exit" src="@/assets/images/x.png" alt="x to close modal" />
</button>
</div>
<div class="modal-textWrapper">
<img class="modal-logo" src="@/assets/images/branding/logo.svg" />
<h1 class="modal-title">{{ title }}</h1>
<div>
Sign up for a chance to win a
<a
href="https://sonnyangelusa.com/products/smiski-hippers"
target="_blank"
style="color: black; text-decoration: underline"
onmouseover="this.style.color='#4D7D92'"
onmouseout="this.style.color='black'"
>Smiski Hipper</a
>
</div>
<div class="textInput">
<label class="textInput-label">Cornell NetID</label>
<div class="textInput-wrapper">
<input class="textInput-userinput" placeholder="Enter netid" v-model="netId" />
</div>
<label class="textInput-label">Instagram Username</label>
<div class="textInput-wrapper">
<input class="textInput-userinput" placeholder="Enter username" v-model="igUsername" />
</div>
</div>
</div>
<div class="modal-buttonWrapper">
<button
class="modal-button modal-button--add"
:class="{
'modal-button--highlighted': rightButtonIsHighlighted,
}"
@click="submitEntry"
>
<img
v-if="rightButtonImage"
class="modal-icon"
:src="rightButtonImage"
:alt="rightButtonAlt"
/>
{{ rightButtonText }}
</button>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import enterGiveaway from '@/global-firestore-data/giveaway-entries';
import { updateSawGiveaway } from '@/global-firestore-data';
export default defineComponent({
props: {
title: { type: String, default: '' },
rightButtonText: { type: String, default: '' },
rightButtonImage: { type: String, default: '' },
rightButtonAlt: { type: String, default: '' },
rightButtonIsHighlighted: { type: Boolean, default: false },
hasNoBackground: { type: Boolean, default: false }, // true for modals without the gray overlay behind them
hasClickableTransparentBackground: { type: Boolean, default: false }, // modals without a gray overlay behind them AND clicking on the background closes the modal
},
emits: ['left-button-clicked', 'right-button-clicked', 'modal-closed'],
data() {
return { netId: '', igUsername: '' };
},
methods: {
submitEntry() {
if (this.netId !== '' && this.igUsername !== '') {
enterGiveaway(this.netId, this.igUsername);
this.$emit('modal-closed', true);
}
updateSawGiveaway(true);
},
},
setup(props, { emit }) {
const modalBackground = ref((null as unknown) as HTMLDivElement);
const close = () => {
updateSawGiveaway(true);
emit('modal-closed', true);
};
const closeOnClickOutside = (e: MouseEvent) => {
if (e.target === modalBackground.value) close();
};
return { close, closeOnClickOutside, modalBackground };
},
});
</script>

<style scoped lang="scss">
@import '@/assets/scss/_variables.scss';
.teleport {
position: fixed;
left: 0;
top: 0;
width: 100vw;
min-height: 100vh;
background-color: rgba(0, 0, 0, 0.7);
z-index: 4;
padding: 1rem;
&-noBackground {
background-color: rgba(0, 0, 0, 0);
width: 100%;
min-height: 0;
pointer-events: none;
}
&-transparentBackground {
background-color: rgba(0, 0, 0, 0);
width: 100%;
min-height: 100vh;
}
}
.modal {
&-content {
width: 24rem;
background: $white;
border-radius: 9px;
margin-left: auto;
margin-right: auto;
padding: 1rem;
background-image: url('@/assets/images/confetti.gif');
}
&-logo {
margin-bottom: 1rem;
}
&-textWrapper {
text-align: center;
}
&-body {
padding: 0;
}
&-top {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
&-exitbutton {
margin-left: auto;
}
&-exit {
width: 10.5px;
height: 10.5px;
}
&-icon {
margin-right: 0.25rem;
}
&-buttonWrapper {
margin-top: 1rem;
display: flex;
justify-content: flex-end;
align-items: center;
}
&-button {
width: 4.75rem;
height: 1.8rem;
color: $sangBlue;
border-radius: 3px;
border: 1px solid $sangBlue;
background-color: $white;
display: flex;
justify-content: center;
align-items: center;
&--add {
color: $white;
background-color: $sangBlue;
margin-left: 0.5rem;
border: none;
}
&--highlighted {
border: 2px solid $error;
}
&--big {
width: 7rem;
}
}
}
.textInput {
width: 20rem;
margin: auto;
margin-top: 0.5rem;
&-label {
font-weight: bold;
top: 0.5rem;
position: relative;
float: left;
}
&-wrapper {
height: 4.2rem;
width: 20rem;
margin: auto;
}
&-userinput {
border: 1px solid $darkPlaceholderGray;
top: 0.5rem;
position: relative;
width: 100%;
height: 2rem;
padding-left: 0.5rem;
border-radius: 3px;
&::placeholder {
color: $darkPlaceholderGray;
}
}
}
</style>
18 changes: 12 additions & 6 deletions src/components/Modals/NewCourse/CourseSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,32 @@ const getMatchingCourses = (
/* code array for results that contain course code and title array for results that contain title */
const code: CornellCourseRosterCourse[] = [];
const title: CornellCourseRosterCourse[] = [];
const codeAndTitle: CornellCourseRosterCourse[] = [];
let filteredCourses: readonly CornellCourseRosterCourse[] = [];
if (coursesArray !== undefined) {
filteredCourses = coursesArray;
} else {
filteredCourses = filter != null ? fullCoursesArray.filter(filter) : fullCoursesArray;
}
const normalizedSearchText = searchText.toUpperCase().replace(/\s+/g, '').replace(/:/g, '');
for (const course of filteredCourses) {
const courseCode = `${course.subject} ${course.catalogNbr}`;
if (courseCode.toUpperCase().includes(searchText)) {
const courseCode = `${course.subject}${course.catalogNbr}`.toUpperCase().replace(/\s+/g, '');
const courseTitle = course.titleLong.toUpperCase().replace(/\s+/g, '');
if (courseCode.includes(normalizedSearchText)) {
code.push(course);
} else if (course.titleLong.toUpperCase().includes(searchText)) {
} else if (courseTitle.includes(normalizedSearchText)) {
title.push(course);
} else if ((courseCode + courseTitle).includes(normalizedSearchText)) {
codeAndTitle.push(course);
}
}
// Sort both results by title
// Sort all results by title, and prioritize code matches over other matches.
code.sort((first, second) => first.titleLong.localeCompare(second.titleLong));
title.sort((first, second) => first.titleLong.localeCompare(second.titleLong));
codeAndTitle.sort((first, second) => first.titleLong.localeCompare(second.titleLong));
/* prioritize code matches over title matches */
return code.concat(title);
return code.concat(title).concat(codeAndTitle);
// limit the number of results to 10
// return code.concat(title).slice(0, 10);
};
Expand Down
Loading

0 comments on commit 12c1f1f

Please sign in to comment.