Skip to content

Commit

Permalink
feat(event sort): update event sort for multi day (jquense#2502)
Browse files Browse the repository at this point in the history
This changes the event sort used in the Month view to prioritize items in this order

- Multi Day events first
- Then all day events
- Then by start time
- Then by end time
  • Loading branch information
cutterbl committed Feb 9, 2024
1 parent 825c955 commit ff209d0
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 27 deletions.
13 changes: 8 additions & 5 deletions .scripts/build.mjs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
#!/usr/bin/env zx
import isCI from 'is-ci';
import isCI from 'is-ci'

const {
b = isCI, // pass `-b` to build if you want it to run browserslist update outside of CI environment
} = argv;
} = argv

if (b) {
// Update browserslist
await $`npx browserslist@latest --update-db`;
await $`npx update-browserslist-db@latest`
}

console.log(chalk.blue('[BEGIN BUILD]'))
console.log(chalk.blue('Building js'))
// build distributables
await $`NODE_ENV=production rollup -c`;
await $`NODE_ENV=production rollup -c`
console.log(chalk.blue(`Compiling 'lib' js files`))
// build files used for overrides
await $`NODE_ENV=production RBC_CJS_BUILD=true babel src --out-dir lib`
Expand All @@ -22,7 +22,10 @@ console.log(chalk.blue(`Copying SASS files to 'lib'`))
await fs.copy('./src/sass', './lib/sass')
console.log(chalk.blue(`...and the 'Add-on' SASS`))
// don't forget DnD
await fs.copy('./src/addons/dragAndDrop/styles.scss', './lib/addons/dragAndDrop/styles.scss')
await fs.copy(
'./src/addons/dragAndDrop/styles.scss',
'./lib/addons/dragAndDrop/styles.scss'
)
console.log(chalk.blue('Now we will build some CSS'))
// Compile SASS from './lib' to get sourcemaps
console.log(chalk.blue('Compile base styles'))
Expand Down
6 changes: 3 additions & 3 deletions src/Month.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import DateContentRow from './DateContentRow'
import Header from './Header'
import DateHeader from './DateHeader'

import { inRange, sortEvents } from './utils/eventLevels'
import { inRange, sortWeekEvents } from './utils/eventLevels'

let eventsForWeek = (evts, start, end, accessors, localizer) =>
evts.filter((e) => inRange(e, start, end, accessors, localizer))
Expand Down Expand Up @@ -124,7 +124,7 @@ class MonthView extends React.Component {
localizer
)

weeksEvents.sort((a, b) => sortEvents(a, b, accessors, localizer))
const sorted = sortWeekEvents(weeksEvents, accessors, localizer)

return (
<DateContentRow
Expand All @@ -135,7 +135,7 @@ class MonthView extends React.Component {
getNow={getNow}
date={date}
range={week}
events={weeksEvents}
events={sorted}
maxRows={showAllEvents ? Infinity : rowLimit}
selected={selected}
selectable={selectable}
Expand Down
14 changes: 10 additions & 4 deletions src/localizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
add,
range,
diff,
duration,
ceil,
min,
max,
Expand Down Expand Up @@ -87,20 +88,24 @@ function continuesAfter(start, end, last) {
: gt(end, last, 'minutes')
}

function daySpan(start, end) {
return duration(start, end, 'day')
}

// These two are used by eventLevels
function sortEvents({
evtA: { start: aStart, end: aEnd, allDay: aAllDay },
evtB: { start: bStart, end: bEnd, allDay: bAllDay },
}) {
let startSort = +startOf(aStart, 'day') - +startOf(bStart, 'day')

let durA = diff(aStart, ceil(aEnd, 'day'), 'day')
let durA = daySpan(aStart, aEnd)

let durB = diff(bStart, ceil(bEnd, 'day'), 'day')
let durB = daySpan(bStart, bEnd)

return (
startSort || // sort by start Day first
Math.max(durB, 1) - Math.max(durA, 1) || // events spanning multiple days go first
durB - durA || // events spanning multiple days go first
!!bAllDay - !!aAllDay || // then allDay single day events
+aStart - +bStart || // then sort by start time
+aEnd - +bEnd // then sort by end time
Expand Down Expand Up @@ -167,13 +172,14 @@ export class DateLocalizer {
this.min = spec.min || min
this.max = spec.max || max
this.minutes = spec.minutes || minutes
this.daySpan = spec.daySpan || daySpan
this.firstVisibleDay = spec.firstVisibleDay || firstVisibleDay
this.lastVisibleDay = spec.lastVisibleDay || lastVisibleDay
this.visibleDays = spec.visibleDays || visibleDays

this.getSlotDate = spec.getSlotDate || getSlotDate
this.getTimezoneOffset =
spec.getTimezoneOffset || (value => value.getTimezoneOffset())
spec.getTimezoneOffset || ((value) => value.getTimezoneOffset())
this.getDstOffset = spec.getDstOffset || getDstOffset
this.getTotalMin = spec.getTotalMin || getTotalMin
this.getMinutesFromMidnight =
Expand Down
12 changes: 9 additions & 3 deletions src/localizers/dayjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,20 +298,26 @@ export default function (dayjsLib) {
return djEnd.isSameOrAfter(djLast, 'minutes')
}

function daySpan(start, end) {
const startDay = dayjs(start)
const endDay = dayjs(end)
return endDay.diff(startDay, 'day')
}

// These two are used by eventLevels
function sortEvents({
evtA: { start: aStart, end: aEnd, allDay: aAllDay },
evtB: { start: bStart, end: bEnd, allDay: bAllDay },
}) {
const startSort = +startOf(aStart, 'day') - +startOf(bStart, 'day')

const durA = diff(aStart, ceil(aEnd, 'day'), 'day')
const durA = daySpan(aStart, aEnd)

const durB = diff(bStart, ceil(bEnd, 'day'), 'day')
const durB = daySpan(bStart, bEnd)

return (
startSort || // sort by start Day first
Math.max(durB, 1) - Math.max(durA, 1) || // events spanning multiple days go first
durB - durA || // events spanning multiple days go first
!!bAllDay - !!aAllDay || // then allDay single day events
+aStart - +bStart || // then sort by start time *don't need dayjs conversion here
+aEnd - +bEnd // then sort by end time *don't need dayjs conversion here either
Expand Down
13 changes: 10 additions & 3 deletions src/localizers/luxon.js
Original file line number Diff line number Diff line change
Expand Up @@ -308,20 +308,26 @@ export default function (DateTime, { firstDayOfWeek = 7 } = {}) {
return gte(end, last)
}

function daySpan(start, end) {
const dtStart = DateTime.fromJSDate(start)
const dtEnd = DateTime.fromJSDate(end)
return dtEnd.diff(dtStart).as('days')
}

// These two are used by eventLevels
function sortEvents({
evtA: { start: aStart, end: aEnd, allDay: aAllDay },
evtB: { start: bStart, end: bEnd, allDay: bAllDay },
}) {
const startSort = +startOf(aStart, 'day') - +startOf(bStart, 'day')

const durA = diff(aStart, ceil(aEnd, 'day'), 'day')
const durA = daySpan(aStart, aEnd)

const durB = diff(bStart, ceil(bEnd, 'day'), 'day')
const durB = daySpan(bStart, bEnd)

return (
startSort || // sort by start Day first
Math.max(durB, 1) - Math.max(durA, 1) || // events spanning multiple days go first
durB - durA || // events spanning multiple days go first
!!bAllDay - !!aAllDay || // then allDay single day events
+aStart - +bStart || // then sort by start time *don't need moment conversion here
+aEnd - +bEnd // then sort by end time *don't need moment conversion here either
Expand Down Expand Up @@ -413,6 +419,7 @@ export default function (DateTime, { firstDayOfWeek = 7 } = {}) {
sortEvents,
inEventRange,
isSameDate,
daySpan,
browserTZOffset,
})
}
14 changes: 11 additions & 3 deletions src/localizers/moment.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,20 +275,27 @@ export default function (moment) {
return mEnd.isSameOrAfter(mLast, 'minutes')
}

function daySpan(start, end) {
const mStart = moment(start)
const mEnd = moment(end)
const dur = moment.duration(mEnd.diff(mStart))
return dur.days()
}

// These two are used by eventLevels
function sortEvents({
evtA: { start: aStart, end: aEnd, allDay: aAllDay },
evtB: { start: bStart, end: bEnd, allDay: bAllDay },
}) {
const startSort = +startOf(aStart, 'day') - +startOf(bStart, 'day')

const durA = diff(aStart, ceil(aEnd, 'day'), 'day')
const durA = daySpan(aStart, aEnd)

const durB = diff(bStart, ceil(bEnd, 'day'), 'day')
const durB = daySpan(bStart, bEnd)

return (
startSort || // sort by start Day first
Math.max(durB, 1) - Math.max(durA, 1) || // events spanning multiple days go first
durB - durA || // events spanning multiple days go first
!!bAllDay - !!aAllDay || // then allDay single day events
+aStart - +bStart || // then sort by start time *don't need moment conversion here
+aEnd - +bEnd // then sort by end time *don't need moment conversion here either
Expand Down Expand Up @@ -381,6 +388,7 @@ export default function (moment) {
sortEvents,
inEventRange,
isSameDate,
daySpan,
browserTZOffset,
})
}
22 changes: 22 additions & 0 deletions src/utils/eventLevels.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,28 @@ export function segsOverlap(seg, otherSegs) {
)
}

export function sortWeekEvents(events, accessors, localizer) {
const base = [...events]
const multiDayEvents = []
const standardEvents = []
base.forEach((event) => {
const startCheck = accessors.start(event)
const endCheck = accessors.end(event)
if (localizer.daySpan(startCheck, endCheck) > 1) {
multiDayEvents.push(event)
} else {
standardEvents.push(event)
}
})
const multiSorted = multiDayEvents.sort((a, b) =>
sortEvents(a, b, accessors, localizer)
)
const standardSorted = standardEvents.sort((a, b) =>
sortEvents(a, b, accessors, localizer)
)
return [...multiSorted, ...standardSorted]
}

export function sortEvents(eventA, eventB, accessors, localizer) {
const evtA = {
start: accessors.start(eventA),
Expand Down
14 changes: 11 additions & 3 deletions stories/resources/events.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
const now = new Date()

export default [
{
/* {
id: 0,
title: 'All Day Event very long title',
allDay: true,
start: new Date(2015, 3, 0),
end: new Date(2015, 3, 1),
},
}, */
{
id: 1,
title: 'Long Event',
Expand All @@ -33,7 +33,15 @@ export default [
id: 4,
title: 'Some Event',
start: new Date(2015, 3, 9, 0, 0, 0),
end: new Date(2015, 3, 10, 0, 0, 0),
end: new Date(2015, 3, 9, 0, 0, 0),
allDay: true,
},

{
id: 92,
title: 'Some Other Event',
start: new Date(2015, 3, 9, 8, 0, 0),
end: new Date(2015, 3, 10, 11, 30, 0),
},
{
id: 5,
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5351,9 +5351,9 @@ camelcase@^6.2.0:
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==

caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001517:
version "1.0.30001519"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601"
integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==
version "1.0.30001585"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001585.tgz"
integrity sha512-yr2BWR1yLXQ8fMpdS/4ZZXpseBgE7o4g41x3a6AJOqZuOi+iE/WdJYAuZ6Y95i4Ohd2Y+9MzIWRR+uGABH4s3Q==

capture-exit@^2.0.0:
version "2.0.0"
Expand Down

0 comments on commit ff209d0

Please sign in to comment.