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

cameronwhite4121-Issue#317-EventsCalendarDisplay #347

Merged
merged 13 commits into from
Nov 25, 2024
Merged
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
5 changes: 1 addition & 4 deletions PC2/Controllers/AboutController.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
using Humanizer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.DotNet.Scaffolding.Shared.Project;
using Microsoft.EntityFrameworkCore;
using PC2.Data;
using PC2.Models;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace PC2.Controllers
{
Expand Down
28 changes: 27 additions & 1 deletion PC2/Controllers/EventsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,37 @@ public async Task<IActionResult> Index(string? eventType)
bool getPc2Events = eventType == null;
EventsModel eventsModel = new()
{
IsPC2EventCalendar = getPc2Events,
IsPC2EventCalendar = getPc2Events,
CalendarEvents = await CalendarEventDB.GetAllEvents(_context, getPc2Events)
};

return View(eventsModel);
}

// Returns events in JSON format for FullCalendar
public async Task<IActionResult> GetEvents(string? eventType)
{
bool getPc2Events = string.IsNullOrEmpty(eventType) || eventType == "PC2";

// Get events from the database
List<CalendarEvent> events = await CalendarEventDB.GetAllEvents(_context, getPc2Events);

// Create a list to hold FullCalendar-compatible events
List<object> fullCalendarEvents = new List<object>();

// Loop through the events and add them to the list
foreach (var e in events)
{
var calendarEvent = new
{
title = e.EventDescription,
start = e.StartingDateTime.ToString("yyyy-MM-ddTHH:mm:ss"), // FullCalendar format
end = e.EndingDateTime.ToString("yyyy-MM-ddTHH:mm:ss"), // FullCalendar format
};
fullCalendarEvents.Add(calendarEvent);
}

return Json(fullCalendarEvents);
}
}
}
17 changes: 17 additions & 0 deletions PC2/Models/CalendarEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,26 @@
/// </summary>
public bool CountyEvent { get; set; }

// Convert DateOnly and TimeOnly to DateTime
public DateTime StartingDateTime
{
get
{
return DateOfEvent.ToDateTime(StartingTime);
}
}

public DateTime EndingDateTime
{
get
{
return DateOfEvent.ToDateTime(EndingTime);
}
}

public int CompareTo(CalendarEvent? other)
{
return this.DateOfEvent.CompareTo(other.DateOfEvent);

Check warning on line 62 in PC2/Models/CalendarEvent.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.
}
}
}
188 changes: 91 additions & 97 deletions PC2/Views/Events/Index.cshtml
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
@model PC2.Models.EventsModel

@{
// Allows calendar to switch between PC2 and County events by grabbing the eventType
var eventType = Context.Request.Query["eventType"].ToString();
if (string.IsNullOrEmpty(eventType) || eventType == "PC2")
{
Model.IsPC2EventCalendar = true;
}
else
{
Model.IsPC2EventCalendar = false;
}

if (Model.IsPC2EventCalendar)
{
ViewData["Title"] = "PC2 Events and Activities";
Expand All @@ -8,12 +20,6 @@
{
ViewData["Title"] = "County-wide Events and Activities";
}

List<List<CalendarEvent>> eventDateGroups =
Model.CalendarEvents
.GroupBy(calEvent => calEvent.DateOfEvent)
.Select(group => group.ToList())
.ToList();
}

<div class="d-flex justify-content-center">
Expand All @@ -22,46 +28,22 @@
<img src=~/images/events/events3.jpg />
<img src=~/images/events/events4.jpg />
</div>

<br />
<h1>@ViewData["Title"]</h1>

<div class="divider"></div>

<br />


@section Head{
@section Head {
<style>
.img-flyer {
max-width: 625px;
max-height: 875px;
}

.agenda .agenda-date {
width: 170px;
}

.agenda .agenda-date .dayofmonth {
width: 40px !important;
font-size: 36px !important;
line-height: 36px !important;
float: left;
text-align: right;
margin-right: 10px;
}

.agenda .agenda-date .shortdate {
font-size: 0.75em;
}


/* Times */
.agenda .agenda-time {
width: 140px;
}
</style>
}

<!-- Links to toggle between PC2 and County events -->
@if (Model.IsPC2EventCalendar)
{
<p>
Expand All @@ -71,79 +53,91 @@
else
{
<p>
<a asp-action="Index">View PC2 Events</a>
<a asp-action="Index" asp-route-eventType="PC2">View PC2 Events</a>
</p>
}

<br />

@if (Model.CalendarEvents.Count > 0)
{
<div class="agenda">
<div class="table-responsive">
<table class="table table-condensed table-bordered">
<thead>
<tr>
<th>Date</th>
<th>Time</th>
<th>Event</th>
</tr>
</thead>
<tbody>
@for (int currentDate = 0; currentDate < eventDateGroups.Count; currentDate++)
{
<tr>
<td class="agenda-date" class="active" rowspan="@eventDateGroups[currentDate].Count">
<div class="dayofmonth">@eventDateGroups[currentDate][0].DateOfEvent.Day</div>
<div class="dayofweek">@eventDateGroups[currentDate][0].DateOfEvent.DayOfWeek</div>
<div class="shortdate text-muted">@eventDateGroups[currentDate][0].DateOfEvent.ToString("MMMM"),&nbsp;@eventDateGroups[currentDate][0].DateOfEvent.Year</div>
</td>
@*loop through all events on this date*@
@for (int currentEvent = 0; currentEvent < eventDateGroups[currentDate].Count; currentEvent++)
{
string eventDescription = eventDateGroups[currentDate][currentEvent].EventDescription;
@if (currentEvent > 0) // if this is not the first event on this date, then start a new row
{
<tr>
<td class="agenda-time">
@eventDateGroups[currentDate][currentEvent].StartingTime &nbsp;-&nbsp; @eventDateGroups[currentDate][currentEvent].EndingTime
</td>
<td class="agenda-events">
<div class="agenda-event">
@*// use partial view, pass in eventdescription as ViewData*@
@(await Html.PartialAsync("~/Views/Calendar/_IndexPartial.cshtml", new ViewDataDictionary(ViewData) { { "eventDescription", eventDescription } }))
</div>
</td>
</tr>
}
else
{
<td class="agenda-time">
@eventDateGroups[currentDate][currentEvent].StartingTime &nbsp;-&nbsp; @eventDateGroups[currentDate][currentEvent].EndingTime
</td>
<td class="agenda-events">
<div class="agenda-event">
@*// use partial view, pass in eventdescription as ViewData*@
@(await Html.PartialAsync("~/Views/Calendar/_IndexPartial.cshtml", new ViewDataDictionary(ViewData) { { "eventDescription", eventDescription } }))
</div>
</td>
}
}
</tr>
}
</tbody>
</table>
<!-- Modal popup -->
<div class="modal fade" id="eventModal" tabindex="-1" aria-labelledby="eventModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="eventModalLabel">Event Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h5 id="modalEventTitle" style="font-weight: normal;"></h5>
<p><strong>Start Time:</strong> <span id="modalEventDate"></span></p>
<p><strong>End Time:</strong> <span id="modalEventEndTime"></span></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
}
else
{
<h2>There are no upcoming @ViewData["Title"] on the Calendar</h2>
<br />
}
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.js"
integrity="sha384-B1OFx8Gy9GjPu8UbUyXbGQpzll9ubAUQ9agInFJ8NnD7nYG1u/CLR+Sqr5yifl4q"
crossorigin="anonymous"></script>

<script>
document.addEventListener('DOMContentLoaded', function() {

var calendarContainer = document.getElementById('calendar');

var calendar = new FullCalendar.Calendar(calendarContainer, {
initialView: 'dayGridMonth',
eventColor: '#ff9f89',
events: function(info, successCallback, failureCallback) {
// Get the eventType from the query string
var urlParams = new URLSearchParams(window.location.search);
var eventType = urlParams.get('eventType') || 'PC2';

// Fetch events from the controller based on eventType
fetch('@Url.Action("GetEvents", "Events")?eventType=' + eventType)
.then(function(response) {
return response.json();
})
.then(function(events) {
successCallback(events);
})
.catch(function(error) {
console.error('Error fetching events:', error);
failureCallback(error);
});
},

eventClick: function(info) {
var startTime = info.event.start.toLocaleString();
var endTime;

if (info.event.end) {
endTime = info.event.end.toLocaleString();
} else {
endTime = 'N/A';
}

document.getElementById('modalEventTitle').innerText = info.event.title;
document.getElementById('modalEventDate').innerText = startTime;
document.getElementById('modalEventEndTime').innerText = endTime;

var myModal = new bootstrap.Modal(document.getElementById('eventModal'));
myModal.show();
}
});

calendar.render();
});
</script>

<div id="calendar"></div>

@if (Model.IsPC2EventCalendar)
{
<img class="d-block mx-auto img-fluid img-flyer" src="~/images/events/ActivitiesFlyer2024.jpg" alt="PC2 Activities and Social Gatherings - Events Flyer">
<br />
<p class="text-center"><a target="_blank" href="~/PDF/Events/ActivitiesFlyer2024.pdf">Downloadable 2024 Activities Flyer</a></p>
}
}
38 changes: 38 additions & 0 deletions PC2/wwwroot/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -591,3 +591,41 @@ div.results:hover, div.results:hover #agencyName2 {
max-height : 550px;
overflow-y: auto;
}

/* Event Calendar CSS*/

/* Calendar styles for small screen sizes */
@media (max-width: 768px) {
#calendar {
font-size: 13px;
}

.fc-header-toolbar {
flex-direction: column;
align-items: center;
}

.fc-button {
padding: 5px 10px;
font-size: 12px;
}
}

/* Modal styles for small screen sizes */
@media (max-width: 767px) {
.modal-dialog {
max-width: 75%;
}
}

/* Make current day more obvious */
.fc-day-today {
font-weight: bold;
}

.fc-event {
background-color: cornflowerblue !important;
}



Loading