codeRIT/brickhack.io

View on GitHub
bh7.js

Summary

Maintainability
F
4 days
Test Coverage
import './sass/event.scss'
import '@fortawesome/fontawesome-free/css/all.css'


// Hiring message
const hiringMessage = `Hey, you.
You’re finally awake.
You were trying to see the code, right?
Walked right into that hiring message, same as us.
If you’d like to work on this website and other cool projects with hackathons, send an email over to engineering@coderit.org!`

console.log(hiringMessage);

// Comment generated via js instead of directly in HTML so the hiring message text is only in one place
const comment = document.createComment("\n"+hiringMessage.toString()+"\n");
document.insertBefore(comment, document.firstChild);


// Nav highlighting on scroll
import ActiveMenuLink from "active-menu-link";

let options = {
    itemTag: "",
    scrollOffset: -90, // nav height
    scrollDuration: 1000,
    ease: "out-quart",
    showHash: false,
};

new ActiveMenuLink(".navbar-items", options);


// Random hero SVG on each page load
import desk1 from './assets/hero/desk1.svg'
import desk2 from './assets/hero/desk2.svg'
import desk3 from './assets/hero/desk3.svg'

$(document).ready(function() {
    var deskIndex = parseInt(localStorage.getItem('deskIndex'));
    if (!deskIndex) {
        deskIndex = 0;
        localStorage.setItem('deskIndex', 0);
    }
    var desks = [desk1, desk2, desk3]
    $('#desk').css('background-image', 'url(' + desks[deskIndex % desks.length] + ')');
    localStorage.setItem('deskIndex', deskIndex + 1);
});

// Parallax functionality
import Rellax from 'rellax';
var rellax = new Rellax('.rellax', {
    breakpoints:[0, 0, 900],
});

// Slick-carousel
import $ from 'jquery'
import 'slick-carousel'

$(document).ready(function() {
    $('.carousel').slick({
        infinite: true,
        swipeToSlide: true,
        variableWidth: true,
        slidesToShow: 3,
        slidesToScroll: 2,
        cssEase: 'ease-in-out',
        autoplay: true,
        autoplaySpeed: 2000,
        speed: 1000,
        responsive: [
            {
                breakpoint: 1500,
                settings: {
                    centerMode: true
                }
            }
        ]
    });
});

// Opens modal when img is clicked
$(document).on('click', '.slide-image', function() {
    $('#modal').show();
    $('#modal-content').attr('src', this.src);
});

// Closes modal when X is clicked
$(document).on('click', '#close', function() {
    $('#modal').hide();
});

// Closes modal when window is clicked
$(window).on('click', function(event) {
    if (event.target == modal) {
        $('#modal').hide();
    }
});

// Closes modal when esc key is pressed
$(document).on('keydown', function(event) {
    if (event.key == "Escape") {
        $('#modal').hide();
    }
});


// FAQ Cards hide/show
let card = document.getElementsByClassName("card");
for (let i = 0; i < card.length; i++) {
    let accordion = card[i].getElementsByClassName("accordion-header")[0];
    // Click should only work on accordion-header of each card
    accordion.addEventListener("click", function() {

        card[i].classList.toggle("active");

        let panel = card[i].getElementsByClassName("panel")[0];
        let fa = this.getElementsByTagName("i")[0];

        // Toggle panel and plus/minus on click of header
        if ($(card[i]).hasClass("active")) {
            $(panel).slideDown(200);
        } else {
            $(panel).slideUp(200);
        }

        $(fa).toggleClass("fa-plus");
        $(fa).toggleClass("fa-minus");
    });
}

// Schedule toggle code

$('.pre-event').click(function() {
    $('.pre-event').addClass('schedule-tab-active');
    $('.feb-20').removeClass('schedule-tab-active');
    $('.feb-21').removeClass('schedule-tab-active');
    $('#pre-event-content').css('display', 'flex');
    $('#feb-20-content').hide();
    $('#feb-21-content').hide();
});

$('.feb-20').click(function() {
    $('.pre-event').removeClass('schedule-tab-active');
    $('.feb-20').addClass('schedule-tab-active');
    $('.feb-21').removeClass('schedule-tab-active');
    $('#pre-event-content').hide();
    $('#feb-20-content').show();
    $('#feb-21-content').hide();
});

$('.feb-21').click(function() {
    $('.pre-event').removeClass('schedule-tab-active');
    $('.feb-20').removeClass('schedule-tab-active');
    $('.feb-21').addClass('schedule-tab-active');
    $('#pre-event-content').hide();
    $('#feb-20-content').hide();
    $('#feb-21-content').show();
});

$('.show-full-schedule').click(function() {
    $('#feb-20-content .events').css('height', 'auto'); // Easier w/o conditional
    $('#feb-21-content .events').css('height', 'auto');
    $('.hide-full-schedule').css('display', 'flex');
    $('.show-full-schedule').hide();
});

$('.hide-full-schedule').click(function() {
    $('#feb-20-content .events').css('height', '370px'); // Easier w/o conditional
    $('#feb-21-content .events').css('height', '370px');
    $('.hide-full-schedule').hide();
    $('.show-full-schedule').css('display', 'flex');
});

// Set schedule tab based on the date
let currentDate = new Date().getDate()
if (currentDate < 20) {
    $('#pre-event-tab').addClass('schedule-tab-active');
    $('#pre-event-content').show();
    $('#feb-20-content').hide();
    $('#feb-21-content').hide();
} else if (currentDate == 20) {
    $('#feb-20-tab').addClass('schedule-tab-active');
    $('#pre-event-content').hide();
    $('#feb-20-content').show();
    $('#feb-21-content').hide();
} else {
    $('#feb-21-tab').addClass('schedule-tab-active');
    $('#pre-event-content').hide();
    $('#feb-20-content').hide();
    $('#feb-21-content').show();
}

// Dynamic schedule code

function compareEvents(a, b) {
    // We can sort by start/end here because the ISO 8061
    // timestamps given by the server are lexicographically
    // sortable.

    if (a.start < b.start) {         // if a starts before b...
        return -1;                   //   ...then a goes before b
    } else if (a.start > b.start) {  // if a starts after b...
        return 1;                    //   ...then b goes before a
    } else {
        if (a.end < b.end) {         // if a ends before b...
            return -1;               //   ...then a goes before b
        } else if (a.end > b.end) {  // if a ends after b...
            return 1;                //   ...then b goes before a
        } else {
            return 0;
        }
    }
}

function convertDate(date) {
    let output = '';

    // hour
    if (date.getHours() > 12) {
        output = String(date.getHours() - 12);
    } else {
        output = String(date.getHours());
    }

    // minute
    if (date.getMinutes() !== 0) {
        output += ':' + String(date.getMinutes()).padStart(2, '0');
    }

    // AM/PM
    if (date.getHours() >= 12) {
        output += 'pm';
    } else {
        output += 'am';
    }

    return output;
}

function handleEventData(events) {
    let now = new Date()

    // needed to handle overlapping events
    let timeMarkerAdded = false;

    // need to sort events by start/end times instead of IDs
    events.sort(compareEvents);

    events.forEach(event => {
        let startDate = new Date(event.start);  // convert ISO 8601 -> Date object

        let finishDate = undefined;

        let dateString = convertDate(startDate);
        if (event.finish) {  // finish === null for instantaneous events
            finishDate = new Date(event.finish);

            let finishString = convertDate(finishDate);
            if (dateString.slice(-2) === finishString.slice(-2)) {  // hide "am/pm" of first time if both are identical
                dateString = dateString.slice(0, -2);
            }
            dateString += "-" + convertDate(finishDate);
        }

        // calculate event container classes
        let divClasses = 'event';
        if ((finishDate || startDate) < now) {
            divClasses += ' past';
        }

        // add event to DOM
        var eventContainer;

        switch (startDate.getDate()) {
            case 16: eventContainer = $('.pre-event-16-events'); break;
            case 17: eventContainer = $('.pre-event-17-events'); break;
            case 18: eventContainer = $('.pre-event-18-events'); break;
            case 19: eventContainer = $('.pre-event-19-events'); break;
            case 20: eventContainer = $('.feb-20-events'); break;
            case 21: eventContainer = $('.feb-21-events'); break;
        }

        if (!eventContainer) {
            console.log("Event " + event.title + " date " + startDate + " out of range.");
            return; // skip current iteration https://stackoverflow.com/a/31399448/1431900
        }

        const eventDiv = eventContainer.append(`<div class="${divClasses}"><p class="time">${dateString}</p><p class="title">${event.title}</p></div>`);

        // add time indicator for the current event
        if (!timeMarkerAdded && startDate < now && finishDate > now) {
            timeMarkerAdded = true;

            // calculate percent
            const eventLength = finishDate - startDate;
            const percent = ((now - startDate) / eventLength) * 100;

            eventDiv.children('div:last-child').css('background-image', `linear-gradient(0deg, white, white ${100-percent}%, #bfbfbf 0)`);
            eventDiv.children('div:last-child').append(`<div class="marker" style="top: ${percent}%;"></div>`);
        }
    });
}

fetch('https://apply.brickhack.io/events.json')
    .then(res => res.json())
    .then(events => handleEventData(events))
    .catch(err => console.log(err));