Bell Schedule Tracker
One of our features was a bell schedule feature, where the user would input their bell schedule and then it would tell them how much time was left in each period. This is a feature on the popular app Saturn, which was the main inspiration for our project. Here is the frontend code I made:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>School Bell Schedule Tracker</title>
<style>
// style goes here
</style>
</head>
<body>
<div style="display: flex; flex-direction: column; width: 100%; justify-content: center; align-items: center;">
<h1 id="typewriter"></h1>
</div>
<div id="datetime">
<div id="date"></div>
<div id="time"></div>
</div>
<h2 style="color:white;">Enter Your School Schedule</h2>
<div id="inputSchedule">
<label for="classPeriod1" >Period 1:</label>
<input type="text" id="classPeriod1" style="color:blue;"><br>
<label for="classPeriod2">Period 2:</label>
<input type="text" id="classPeriod2" style="color:blue;"><br>
<label for="classPeriod3" >Period 3:</label>
<input type="text" id="classPeriod3" style="color:blue;"><br>
<label for="classPeriod4" >Period 4:</label>
<input type="text" id="classPeriod4" style="color:blue;"><br>
<label for="classPeriod5" > Period 5:</label>
<input type="text" id="classPeriod5" style="color:blue;"><br>
<button onclick="updateSchedule()">Update Schedule</button>
</div>
<div id="scheduleResults" style="color:blue;"></div>
<!-- <div id="time" style="text-align: center; font-size: 20px;"></div> -->
<script>
var i = 0;
var text = "Welcome to Project Pluto! 😱🤯🤩";
var speed = 150; // Adjust typing speed (lower value = faster)
function typeWriter() {
if (i < text.length) {
document.getElementById("typewriter").innerHTML += text.charAt(i);
i++;
setTimeout(typeWriter, speed);
}
}
typeWriter();
const commonSchedule = [
{ period: 'Period 1', startTime: '08:35', endTime: '09:44', duration: 69, class: '' },
{ period: 'Period 2', startTime: '09:49', endTime: '10:58', duration: 69, class: '' },
{ period: 'BREAK', startTime: '10:58', endTime: '11:08', duration: 10, class: 'Break' },
{ period: 'Period 3', startTime: '11:13', endTime: '12:22', duration: 69, class: '' },
{ period: 'LUNCH', startTime: '12:22', endTime: '12:52', duration: 30, class: 'Lunch' },
{ period: 'Period 4', startTime: '12:57', endTime: '14:06', duration: 69, class: '' },
{ period: 'OFFICE HOURS', startTime: '14:06', endTime: '14:31', duration: 25, class: 'Office Hours' },
{ period: 'Period 5', startTime: '14:36', endTime: '15:45', duration: 69, class: '' }
];
const wednesdaySchedule = [
{ period: 'Period 1', startTime: '09:55', endTime: '10:53', duration: 58, class: '' },
{ period: 'Period 2', startTime: '10:58', endTime: '11:56', duration: 58, class: '' },
{ period: 'BREAK', startTime: '11:56', endTime: '12:06', duration: 10, class: 'Break' },
{ period: 'Period 3', startTime: '12:11', endTime: '13:09', duration: 58, class: '' },
{ period: 'LUNCH', startTime: '13:09', endTime: '13:39', duration: 30, class: 'Lunch' },
{ period: 'Period 4', startTime: '13:44', endTime: '14:42', duration: 58, class: '' },
{ period: 'Period 5', startTime: '14:47', endTime: '15:45', duration: 58, class: '' }
];
const fridaySchedule = [
{ period: 'Period 1', startTime: '08:35', endTime: '09:49', duration: 74, class: '' },
{ period: 'Period 2', startTime: '09:54', endTime: '11:08', duration: 74, class: '' },
{ period: 'BREAK', startTime: '11:08', endTime: '11:18', duration: 10, class: 'Break' },
{ period: 'Period 3', startTime: '11:23', endTime: '12:37', duration: 74, class: '' },
{ period: 'LUNCH', startTime: '12:37', endTime: '13:07', duration: 30, class: 'Lunch' },
{ period: 'Period 4', startTime: '13:12', endTime: '14:26', duration: 74, class: '' },
{ period: 'Period 5', startTime: '14:31', endTime: '15:45', duration: 74, class: '' }
];
function calculateTimeLeft(currentTime, startTime, endTime) {
const current = new Date(currentTime);
const start = new Date(currentTime);
const end = new Date(currentTime);
start.setHours(startTime.split(':')[0]);
start.setMinutes(startTime.split(':')[1]);
end.setHours(endTime.split(':')[0]);
end.setMinutes(endTime.split(':')[1]);
const timeLeft = Math.max(0, (end - current) / 60000);
return timeLeft;
}
function postScheduleData(scheduleData) {
fetch('http:/https://no-papels.stu.nighthawkcodingsociety.com//api/schedule', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(scheduleData)
})
.then(response => response.text())
.then(data => {
console.log(data); // log the response message
// You can perform any additional actions here after successful posting
})
.catch(error => {
console.error('Error:', error);
});
}
function updateSchedule() {
const currentDay = new Date().getDay();
switch (currentDay) {
case 3: // WednesdayfridaySchedule
wednesdaySchedule[0].class = document.getElementById(`classPeriod${0 + 1}`).value;
wednesdaySchedule[1].class = document.getElementById(`classPeriod${1 + 1}`).value;
wednesdaySchedule[3].class = document.getElementById(`classPeriod${2 + 1}`).value;
wednesdaySchedule[5].class = document.getElementById(`classPeriod${3 + 1}`).value;
wednesdaySchedule[6].class = document.getElementById(`classPeriod${4 + 1}`).value;
case 5: // Friday
fridaySchedule[0].class = document.getElementById(`classPeriod${0 + 1}`).value;
fridaySchedule[1].class = document.getElementById(`classPeriod${1 + 1}`).value;
fridaySchedule[3].class = document.getElementById(`classPeriod${2 + 1}`).value;
fridaySchedule[5].class = document.getElementById(`classPeriod${3 + 1}`).value;
fridaySchedule[6].class = document.getElementById(`classPeriod${4 + 1}`).value;
break;
default:
commonSchedule[0].class = document.getElementById(`classPeriod${0 + 1}`).value;
commonSchedule[1].class = document.getElementById(`classPeriod${1 + 1}`).value;
commonSchedule[3].class = document.getElementById(`classPeriod${2 + 1}`).value;
commonSchedule[5].class = document.getElementById(`classPeriod${3 + 1}`).value;
commonSchedule[7].class = document.getElementById(`classPeriod${4 + 1}`).value;
break;
}
updateClock();
}
function getSchedule() {
fetch('http:/https://no-papels.stu.nighthawkcodingsociety.com//api/schedule')
.then(response => response.json())
.then(data => {
// Use the retrieved schedule data as needed
console.log('Retrieved schedule data:', data);
// You can perform any additional actions here after successful retrieval
})
.catch(error => {
console.error('Error:', error);
});
}
function updateClock() {
const now = new Date();
const hours = now.getHours();
const minutes = now.getMinutes();
const seconds = now.getSeconds();
const ampm = hours >= 12 ? 'PM' : 'AM';
const formattedHours = hours % 12 || 12;
const timeString = `${formattedHours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')} ${ampm}`;
const timeElement = document.getElementById('time');
timeElement.textContent = timeString;
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
const dateString = now.toLocaleDateString('en-US', options);
const dateElement = document.getElementById('date');
dateElement.textContent = dateString;
const scheduleResults = document.getElementById('scheduleResults');
scheduleResults.innerHTML = '';
const currentSchedule = getCurrentSchedule(now);
// Iterate through each item in the current schedule
for (const item of currentSchedule) {
// Calculate the time left for the current class
const timeLeft = calculateTimeLeft(now, item.startTime, item.endTime);
// Check if the class is still in progress (timeLeft is greater than 0)
if (timeLeft > 0) {
// If there are more than 60 minutes left, calculate and display hours left
if (timeLeft > 60) {
const hoursLeft = Math.floor(timeLeft / 60);
scheduleResults.innerHTML += `<p>${item.period} (${item.class}): ${hoursLeft} hours left</p>`;
} else {
// If there are 60 minutes or less left, display minutes left
scheduleResults.innerHTML += `<p>${item.period} (${item.class}): ${timeLeft.toFixed(0)} minutes left</p>`;
}
} else {
// If timeLeft is less than or equal to 0, the class has finished
scheduleResults.innerHTML += `<p>${item.period} (${item.class}): Period finished</p>`;
}
}
function getCurrentSchedule(currentTime) {
const currentDay = currentTime.getDay();
switch (currentDay) {
case 3: // Wednesday
return wednesdaySchedule;
case 5: // Friday
return fridaySchedule;
default:
return commonSchedule;
}
}
updateClock();
setInterval(updateClock, 1000);
</script>
</body>
</html>
This code allows users to input class names for each period of their school schedule, and upon clicking the “Update Schedule” button, the code updates the schedule data based on the current day of the week. I saved the different schedules for Wednesdays and Fridays as well so it will check if it is one of those days. The code automatically calculates and displays the time left for each class, considering its start and end times. Additionally, it sends a get request to the backend in order to send and retrieve schedule data, making it possible to store and retrieve past entered schedule information.
Weather API Frontend Code
This feature is used to get Weather from a Weather API and display clothing advice based off the weather forecast.
What's our weather like? 🌧️
<html>
<head>
<style>
/* styling goes here */
</style>
</head>
<body>
<div id="content">
<h3>What's our weather like? 🌧️</h3>
<button id="getWeatherButton">Get Current Weather</button>
<div id="weatherData" class = "text"></div>
<div id="clothingAdvice"></div>
<div id="clothingImage" style="text-align: center;">
<img id="hotImage" src="https://raw.githubusercontent.com/Soham360/sturdy-fiesta/main/images/279477144-37eedd64-48c1-45e7-ba55-75108b851efd.png" alt="Hot Weather" style="display: none; margin: 0 auto; width: 50%;">
<img id="warmImage" src="https://github.com/Soham360/sturdy-fiesta/blob/main/images/279540917-7159ad70-8fb9-40b6-9bae-e1fa1b6ff07d.png?raw=true" alt="Warm Weather" style="display: none; margin: 0 auto; width: 50%;">
<img id="mildImage" src="https://github.com/Soham360/sturdy-fiesta/blob/main/images/279541100-97edf9f8-0114-440f-b383-a5f327648cee.png?raw=true" alt="Mild Weather" style="display: none; margin: 0 auto; width: 50%;">
<img id="coolImage" src="https://github.com/Soham360/sturdy-fiesta/blob/main/images/279540782-6104c0fe-2ac7-435b-bf75-1e1612592b5b.png?raw=true" alt="Cool Weather" style="display: none; margin: 0 auto; width: 50%;">
<img id="coldImage" src="https://github.com/Soham360/sturdy-fiesta/blob/main/images/279541006-1afab2be-b2fe-42bf-85d1-c9c83cab7952.png?raw=true" alt="Cold Weather" style="display: none; margin: 0 auto; width: 50%;">
</div>
</div>
<script>
document.getElementById("getWeatherButton").addEventListener("click", function() {
const apiUrl = `https://no-papels.stu.nighthawkcodingsociety.com/api/weather/daily`;
fetch(apiUrl)
.then(response => response.json())
.then(data => {
// Get additional weather data
const forecast = data.properties.forecast;
fetch(forecast)
.then(response => response.json())
.then(forecastData => {
const currentWeather = forecastData.properties.periods[0];
const temperature = currentWeather.temperature;
const weatherConditions = currentWeather.shortForecast;
const precipitation = currentWeather.detailedForecast.includes('precipitation');
// Display temperature, weather conditions, and precipitation
const weatherDataElement = document.getElementById("weatherData");
weatherDataElement.innerHTML = `
<p>Temperature: ${temperature}°F</p>
<p>Weather Conditions: ${weatherConditions}</p>
<p>Chance of Precipitation: ${precipitation ? 'Yes' : 'No'}</p>
<p>${getClothingAdvice(temperature, weatherConditions, precipitation)}</p>
`;
// Show the corresponding image based on temperature range
const hotImage = document.getElementById("hotImage");
const warmImage = document.getElementById("warmImage");
const mildImage = document.getElementById("mildImage");
const coolImage = document.getElementById("coolImage");
const coldImage = document.getElementById("coldImage");
// Hide all images initially
hotImage.style.display = "none";
warmImage.style.display = "none";
mildImage.style.display = "none";
coolImage.style.display = "none";
coldImage.style.display = "none";
if (temperature >= 80) {
hotImage.style.display = "block";
} else if (temperature >= 70) {
warmImage.style.display = "block";
} else if (temperature >= 60) {
mildImage.style.display = "block";
} else if (temperature >= 40) {
coolImage.style.display = "block";
} else {
coldImage.style.display = "block";
}
})
.catch(error => {
console.error("An error occurred:", error);
});
})
.catch(error => {
console.error("An error occurred:", error);
});
});
function getClothingAdvice(temperature, weatherConditions, precipitation) {
if (temperature >= 80) {
return "It's hot! Wear light and breathable clothing like short sleeves and shorts. Don't forget sunscreen!";
} else if (temperature >= 70) {
return "It's warm. Consider wearing short sleeves and pants or a skirt.";
} else if (temperature >= 60) {
if (precipitation) {
return "It's mild and may rain. A light jacket or sweater with an umbrella might be a good idea.";
} else {
return "It's mild. A light jacket or sweater might be a good idea.";
}
} else if (temperature >= 40) {
return "It's cool. Wear long sleeves and pants. You may want to add a jacket.";
} else {
return "It's cold. Bundle up with a warm coat, gloves, and a scarf.";
}
}
</script>
</body>
</html>
Explanation:
I combined JavaScript and CSS to create a weather application. When I click the “Get Current Weather” button, I fetch weather data from an external API, extracting temperature, weather conditions, and precipitation information. I then use a function to provide clothing advice based on the temperature and weather conditions, displaying this advice on the page. The application also shows an image that corresponds to the temperature range (hot, warm, mild, cool, or cold). My CSS styles the page, including fonts, colors, and custom scrollbars. In essence, I’ve built a simple weather information tool that offers me visual cues and clothing recommendations based on the weather conditions and temperature.
Errors I faced:
During the development of this project, I faced a few key challenges and potential issues should be addressed. Security is a primary concern, as the login code lacks authentication and authorization mechanisms, making it vulnerable to unauthorized access and data breaches. Additionally, robust error handling is essential to ensure the application gracefully handles unexpected situations, such as network failures or invalid input data. Furthermore, Cross-Origin Resource Sharing (CORS) errors happened a lot because the web page and the API are hosted on different domains, requiring appropriate CORS configuration to enable seamless communication between them. Addressing these issues by implementing security measures, comprehensive error handling, and proper CORS setup is crucial for a secure, reliable, and user-friendly web application.
I ran into a lot of CORS errors, and to fix them, I took the following steps. First, I updated the server that hosts the API to include the appropriate CORS headers in the response. This involved adding specific HTTP response headers, such as “Access-Control-Allow-Origin,” to indicate which domains are allowed to access the API. I configured these headers to include the domain where my web page is hosted. This step allowed my web page to make requests to the API without encountering CORS errors. Additionally, I ensured that the API server’s CORS configuration was up to date and aligned with the latest security best practices. This approach successfully resolved the CORS issues and enabled seamless communication between my web page and the API, ensuring a smooth user experience.