From 3058d902fca191ee07064d2ce7aad4e86a6f79de Mon Sep 17 00:00:00 2001 From: Alexander Platov Date: Tue, 25 Jul 2023 13:50:55 +0300 Subject: [PATCH] Fixed display of events for the whole day (#3519) Signed-off-by: Alexander Platov --- .../components/calendar/DayCalendar.svelte | 252 +++++++++++++----- packages/ui/src/index.ts | 1 + .../src/components/CalendarView.svelte | 51 ++-- .../src/components/CreateEvent.svelte | 37 ++- 4 files changed, 245 insertions(+), 96 deletions(-) diff --git a/packages/ui/src/components/calendar/DayCalendar.svelte b/packages/ui/src/components/calendar/DayCalendar.svelte index 1800f5153b..95fb2eb01f 100644 --- a/packages/ui/src/components/calendar/DayCalendar.svelte +++ b/packages/ui/src/components/calendar/DayCalendar.svelte @@ -25,6 +25,7 @@ areDatesEqual } from './internal/DateUtils' import { CalendarItem } from '../../types' + import { ActionIcon, IconUpOutline, IconDownOutline } from '../..' export let events: CalendarItem[] export let mondayStart = true @@ -39,19 +40,25 @@ const dispatch = createEventDispatcher() const todayDate = new Date() - const cellBorder = 1 + const ampm = new Intl.DateTimeFormat([], { hour: 'numeric' }).resolvedOptions().hour12 + const getTimeFormat = (hour: number): string => { + return ampm ? `${hour > 12 ? hour - 12 : hour}${hour < 12 ? 'am' : 'pm'}` : `${addZero(hour)}:00` + } + $: fontSize = $deviceInfo.fontSize + $: docHeight = $deviceInfo.docHeight $: cellHeight = 4 * fontSize $: weekMonday = startFromWeekStart ? getMonday(currentDate, mondayStart) : new Date(new Date(currentDate).setHours(0, 0, 0, 0)) - const ampm = new Intl.DateTimeFormat([], { hour: 'numeric' }).resolvedOptions().hour12 - // const timeZone = new Intl.DateTimeFormat([], { hour: 'numeric' }).resolvedOptions().timeZone - - const getTimeFormat = (hour: number): string => { - return ampm ? `${hour > 12 ? hour - 12 : hour}${hour < 12 ? 'am' : 'pm'}` : `${addZero(hour)}:00` - } + const rem = (n: number): number => n * fontSize + const cellBorder: number = 1 + const heightAD: number = 2 + let minHeightAD: number = 0 + let maxHeightAD: number = 0 + let shownHeightAD: number = 0 + let shownAD: boolean = false interface CalendarElement { id: string @@ -59,11 +66,20 @@ dueDate: Timestamp cols: number } - interface CalendarRow { + interface CalendarColumn { elements: CalendarElement[] } interface CalendarGrid { - columns: CalendarRow[] + columns: CalendarColumn[] + } + interface CalendarADGrid { + alldays: (string | null)[] + } + interface CalendarADRows { + id: string + row: number + startCol: number + endCol: number } let container: HTMLElement @@ -71,12 +87,20 @@ let calendarWidth: number = 0 let calendarRect: DOMRect let colWidth: number = 0 - let newEvents = events let grid: CalendarGrid[] = Array(displayedDaysCount) + let alldays: CalendarItem[] = [] + let alldaysGrid: CalendarADGrid[] = Array(displayedDaysCount) + let adMaxRow: number = 1 + let adRows: CalendarADRows[] + $: if (newEvents !== events) { grid = new Array(displayedDaysCount) + alldaysGrid = new Array(displayedDaysCount) newEvents = events + alldays = [] + prepareAllDays() + if (shownAD && adMaxRow < 4) shownAD = false } $: newEvents .filter((ev) => !ev.allDay) @@ -143,6 +167,39 @@ } } } + + const addNullRow = () => { + for (let i = 0; i < displayedDaysCount; i++) alldaysGrid[i].alldays.push(null) + adMaxRow++ + } + const prepareAllDays = () => { + alldays = events.filter((ev) => ev.day === -1) + adRows = [] + for (let i = 0; i < displayedDaysCount; i++) alldaysGrid[i] = { alldays: [null] } + adMaxRow = 1 + alldays.forEach((event) => { + const days = events + .filter((ev) => ev.allDay && ev.day !== -1 && event.eventId === ev.eventId) + .map((ev) => { + return ev.day + }) + let emptyRow = 0 + for (let checkRow = 0; checkRow < adMaxRow; checkRow++) { + const empty = days.every((day) => alldaysGrid[day].alldays[checkRow] === null) + if (empty) { + emptyRow = checkRow + break + } else if (checkRow === adMaxRow - 1) { + emptyRow = adMaxRow + addNullRow() + break + } + } + adRows.push({ id: event.eventId, row: emptyRow, startCol: days[0], endCol: days[days.length - 1] }) + days.forEach((day) => (alldaysGrid[day].alldays[emptyRow] = event.eventId)) + }) + } + const checkIntersect = (date1: CalendarItem | CalendarElement, date2: CalendarItem | CalendarElement): boolean => { return ( (date2.date <= date1.date && date2.dueDate > date1.date) || @@ -154,17 +211,10 @@ return { hours: temp.getHours() - startHour, mins: temp.getMinutes() } } - const checkSizes = (element: HTMLElement | Element) => { - calendarRect = element.getBoundingClientRect() - calendarWidth = calendarRect.width - colWidth = (calendarWidth - 3.5 * fontSize) / displayedDaysCount - } - const getGridOffset = (mins: number, end: boolean = false): number => { if (mins === 0) return end ? 2 + cellBorder : 2 return mins < 3 ? (end ? 1 : 2) : mins > 57 ? (end ? 2 + cellBorder : 1) : 1 } - const rem = (n: number): number => n * fontSize const getRect = ( event: CalendarItem @@ -177,7 +227,11 @@ const endTime = event.dueDate > endDay ? { hours: displayedHours - startHour, mins: 0 } : convertToTime(event.dueDate) result.top = - rem(5.75) + cellHeight * startTime.hours + (startTime.mins / 60) * cellHeight + getGridOffset(startTime.mins) + rem(3.5) + + styleAD + + cellHeight * startTime.hours + + (startTime.mins / 60) * cellHeight + + getGridOffset(startTime.mins) result.bottom = cellHeight * (displayedHours - startHour - endTime.hours - 1) + ((60 - endTime.mins) / 60) * cellHeight + @@ -203,21 +257,55 @@ return result } + const getADRect = (event: CalendarItem): { top: number; left: number; width: number } => { + const result = { top: 0, left: 0, width: 0 } + const index = adRows.findIndex((ev) => ev.id === event.eventId) + result.top = rem(0.125 + adRows[index].row * (heightAD + 0.125)) + result.left = rem(0.125) + adRows[index].startCol * (colWidth + 0.125) + const w = adRows[index].endCol - adRows[index].startCol + result.width = colWidth + colWidth * w - rem(0.25) + return result + } + + const getTimeZone = (): string => { + return new Intl.DateTimeFormat([], { timeZoneName: 'short' }).format(Date.now()).split(' ')[1] + } + onMount(() => { if (container) checkSizes(container) + minHeightAD = rem((heightAD + 0.125) * 2 + 0.25) }) + + const checkSizes = (element: HTMLElement | Element) => { + calendarRect = element.getBoundingClientRect() + calendarWidth = calendarRect.width + colWidth = (calendarWidth - 3.5 * fontSize) / displayedDaysCount + } + $: if (docHeight && calendarRect?.top) { + const proc = ((docHeight - calendarRect.top) * 30) / 100 + const temp = rem((heightAD + 0.125) * Math.trunc(proc / rem(heightAD + 0.125)) + 0.25) + maxHeightAD = temp < minHeightAD ? minHeightAD : temp + shownHeightAD = rem((heightAD + 0.125) * adMaxRow + 0.25) + } + $: styleAD = shownAD + ? shownHeightAD > maxHeightAD + ? maxHeightAD + : shownHeightAD + : rem((heightAD + 0.125) * adMaxRow + 0.25) > maxHeightAD && maxHeightAD === minHeightAD + ? rem((heightAD + 0.125) * (adMaxRow < 3 ? adMaxRow : 2) + 0.25) + : rem((heightAD + 0.125) * (adMaxRow < 4 ? adMaxRow : 3) + 0.25) - +
checkSizes(element)} > - + {#each [...Array(displayedDaysCount).keys()] as dayOfWeek} {@const day = getDay(weekMonday, dayOfWeek)} {/each} - - {#each [...Array(displayedDaysCount).keys()] as dayOfWeek} - {@const day = getDay(weekMonday, dayOfWeek)} - {@const alldays = events.filter((ev) => ev.allDay && ev.day === dayOfWeek)} - - - {/each} + +