Skip to content

Commit

Permalink
feat(FullCalendar): add conditional styling for participation status …
Browse files Browse the repository at this point in the history
…in grid

Signed-off-by: Grigory Vodyanov <scratchx@gmx.com>
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
  • Loading branch information
GVodyanov authored and st3iny committed Feb 17, 2025
1 parent 0921424 commit a68f90c
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 4 deletions.
7 changes: 7 additions & 0 deletions css/fullcalendar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@

.fc-event {
box-shadow: 0px 0px 0px 1px var(--color-primary-element-light) !important;
margin-top: 0px;
}

.fc-daygrid-day-top {
Expand Down Expand Up @@ -131,6 +132,7 @@
// ### FullCalendar Event adjustments
.fc-event {
padding-left: 3px;
border-width: 2px;

&.fc-event-nc-task-completed,
&.fc-event-nc-tentative,
Expand All @@ -149,6 +151,7 @@

.fc-event-title {
text-overflow: ellipsis;
font-weight: 700;
}

// Reminder icon on events with alarms set
Expand Down Expand Up @@ -200,6 +203,10 @@
max-width: 25vw;
}

svg {
margin-right: 2px;
}

@media only screen and (max-width: 767px) {
.fc-list-event-location,
.fc-list-event-description {
Expand Down
36 changes: 34 additions & 2 deletions src/fullcalendar/eventSources/eventSourceFunction.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from '../../utils/color.js'
import logger from '../../utils/logger.js'
import { getAllObjectsInTimeRange } from '../../utils/calendarObject.js'

import usePrincipalsStore from '../../store/principals.js'
/**
* convert an array of calendar-objects to events
*
Expand All @@ -23,6 +23,8 @@ import { getAllObjectsInTimeRange } from '../../utils/calendarObject.js'
* @return {object}[]
*/
export function eventSourceFunction(calendarObjects, calendar, start, end, timezone) {
const principalsStore = usePrincipalsStore()

const fcEvents = []
for (const calendarObject of calendarObjects) {
let allObjectsInTimeRange
Expand All @@ -32,16 +34,46 @@ export function eventSourceFunction(calendarObjects, calendar, start, end, timez
logger.error(error.message)
continue
}

for (const object of allObjectsInTimeRange) {
const classNames = []
let didEveryoneDecline = false

// You are an organizer
if (object.getFirstPropertyFirstValue('ORGANIZER') === `mailto:${principalsStore.getCurrentUserPrincipalEmail}`) {
// Check if all the attendees have declined the event
if (object.hasProperty('ATTENDEE')) {
didEveryoneDecline = true
for (const attendeeProperty of object.getPropertyIterator('ATTENDEE')) {
const hasDeclined = attendeeProperty.participationStatus === 'DECLINED'

Check warning on line 47 in src/fullcalendar/eventSources/eventSourceFunction.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/eventSources/eventSourceFunction.js#L45-L47

Added lines #L45 - L47 were not covered by tests
if (!hasDeclined) {
didEveryoneDecline = false

Check warning on line 49 in src/fullcalendar/eventSources/eventSourceFunction.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/eventSources/eventSourceFunction.js#L49

Added line #L49 was not covered by tests
}
}
if (didEveryoneDecline) {
classNames.push('fc-event-nc-all-declined')

Check warning on line 53 in src/fullcalendar/eventSources/eventSourceFunction.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/eventSources/eventSourceFunction.js#L53

Added line #L53 was not covered by tests
}
}
}

if (object.status === 'CANCELLED') {
classNames.push('fc-event-nc-cancelled')
} else if (object.status === 'TENTATIVE') {
classNames.push('fc-event-nc-tentative')
}

// You are invited
for (const attendeeProperty of object.getPropertyIterator('ATTENDEE')) {
if (attendeeProperty.email === `mailto:${principalsStore.getCurrentUserPrincipalEmail}`) {
if (attendeeProperty.participationStatus === 'DECLINED') {
classNames.push('fc-event-nc-declined')

Check warning on line 68 in src/fullcalendar/eventSources/eventSourceFunction.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/eventSources/eventSourceFunction.js#L68

Added line #L68 was not covered by tests
} else if (attendeeProperty.participationStatus === 'TENTATIVE') {
classNames.push('fc-event-nc-tentative')

Check warning on line 70 in src/fullcalendar/eventSources/eventSourceFunction.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/eventSources/eventSourceFunction.js#L70

Added line #L70 was not covered by tests
} else if (attendeeProperty.participationStatus === 'NEEDS-ACTION') {
classNames.push('fc-event-nc-needs-action')

Check warning on line 72 in src/fullcalendar/eventSources/eventSourceFunction.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/eventSources/eventSourceFunction.js#L72

Added line #L72 was not covered by tests
}
}
}

if (object.hasComponent('VALARM')) {
classNames.push('fc-event-nc-alarms')
}
Expand Down
80 changes: 78 additions & 2 deletions src/fullcalendar/rendering/eventDidMount.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function({ event, el }) {
const dotElement = el.querySelector('.fc-list-event-dot')
dotElement.classList.remove('fc-list-event-dot')
dotElement.classList.add('fc-list-event-checkbox')
dotElement.style.color = dotElement.style.borderColor
dotElement.style.color = 'var(--color-main-text)'

Check warning on line 32 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L32

Added line #L32 was not covered by tests

if (event.extendedProps.percent === 100) {
dotElement.classList.add('calendar-grid-checkbox-checked')
Expand All @@ -41,7 +41,7 @@ export default function({ event, el }) {
const dotElement = el.querySelector('.fc-daygrid-event-dot')
dotElement.classList.remove('fc-daygrid-event-dot')
dotElement.classList.add('fc-daygrid-event-checkbox')
dotElement.style.color = dotElement.style.borderColor
dotElement.style.color = 'var(--color-main-text)'

Check warning on line 44 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L44

Added line #L44 was not covered by tests

if (event.extendedProps.percent === 100) {
dotElement.classList.add('calendar-grid-checkbox-checked')
Expand Down Expand Up @@ -91,4 +91,80 @@ export default function({ event, el }) {
descriptionContainer.appendChild(description)
}
}

if (
el.classList.contains('fc-event-nc-all-declined')
|| el.classList.contains('fc-event-nc-needs-action')
|| el.classList.contains('fc-event-nc-declined')
) {
const titleElement = el.querySelector('.fc-event-title')
const dotElement = el.querySelector('.fc-daygrid-event-dot')

Check warning on line 101 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L100-L101

Added lines #L100 - L101 were not covered by tests

if (dotElement) {
dotElement.style.borderWidth = '2px'
dotElement.style.background = 'transparent'
dotElement.style.minWidth = '10px'
dotElement.style.minHeight = '10px'

Check warning on line 107 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L104-L107

Added lines #L104 - L107 were not covered by tests
}

titleElement.style.color = 'var(--color-main-text)'
el.style.background = 'transparent'
el.title = t('calendar', 'All participants declined')

Check warning on line 112 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L110-L112

Added lines #L110 - L112 were not covered by tests

if (el.classList.contains('fc-event-nc-needs-action')) {
el.title = t('calendar', 'Please confirm your participation')

Check warning on line 115 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L115

Added line #L115 was not covered by tests
}

if (el.classList.contains('fc-event-nc-declined')) {
el.title = t('calendar', 'You declined this event')
titleElement.style.textDecoration = 'line-through'

Check warning on line 120 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L119-L120

Added lines #L119 - L120 were not covered by tests
}
}

if (el.classList.contains('fc-event-nc-all-declined')) {
const titleElement = el.querySelector('.fc-event-title')

Check warning on line 125 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L125

Added line #L125 was not covered by tests

const svgString = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m40-120 440-760 440 760H40Zm440-120q17 0 28.5-11.5T520-280q0-17-11.5-28.5T480-320q-17 0-28.5 11.5T440-280q0 17 11.5 28.5T480-240Zm-40-120h80v-200h-80v200Z"/></svg>'
titleElement.innerHTML = svgString + titleElement.innerHTML

Check warning on line 128 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L127-L128

Added lines #L127 - L128 were not covered by tests

const svgElement = titleElement.querySelector('svg')
svgElement.style.fill = el.style.borderColor
svgElement.style.width = '1em'
svgElement.style.marginBottom = '0.2em'
svgElement.style.verticalAlign = 'middle'

Check warning on line 134 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L130-L134

Added lines #L130 - L134 were not covered by tests
}

if (el.classList.contains('fc-event-nc-tentative')) {
const dotElement = el.querySelector('.fc-daygrid-event-dot')

Check warning on line 138 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L138

Added line #L138 was not covered by tests

const bgColor = el.style.backgroundColor ? el.style.backgroundColor : dotElement.style.borderColor
const bgStripeColor = darkenColor(bgColor)

Check warning on line 141 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L141

Added line #L141 was not covered by tests

let backgroundStyling = `repeating-linear-gradient(45deg, ${bgStripeColor}, ${bgStripeColor} 1px, ${bgColor} 1px, ${bgColor} 10px)`

Check warning on line 143 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L143

Added line #L143 was not covered by tests

if (dotElement) {
dotElement.style.borderWidth = '2px'
backgroundStyling = `repeating-linear-gradient(45deg, ${bgColor}, ${bgColor} 1px, transparent 1px, transparent 3.5px)`

Check warning on line 147 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L146-L147

Added lines #L146 - L147 were not covered by tests

dotElement.style.background = backgroundStyling
dotElement.style.minWidth = '10px'
dotElement.style.minHeight = '10px'
} else {
el.style.background = backgroundStyling

Check warning on line 153 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L149-L153

Added lines #L149 - L153 were not covered by tests
}

el.title = t('calendar', 'Your participation is tentative')

Check warning on line 156 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L156

Added line #L156 was not covered by tests
}
}

/**
* Create a slightly darker color for background stripes
*
* @param {string} color The color to darken
*/
function darkenColor(color) {
const rgb = color.match(/\d+/g)

Check warning on line 166 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L165-L166

Added lines #L165 - L166 were not covered by tests
if (!rgb) return color
const [r, g, b] = rgb.map(c => Math.max(0, Math.min(255, c - (c * 0.3))))
return `rgb(${r}, ${g}, ${b})`

Check warning on line 169 in src/fullcalendar/rendering/eventDidMount.js

View check run for this annotation

Codecov / codecov/patch

src/fullcalendar/rendering/eventDidMount.js#L168-L169

Added lines #L168 - L169 were not covered by tests
}
Loading

0 comments on commit a68f90c

Please sign in to comment.