From 3c2fe9af95e62eabc97189f57ab6e355cf6b7aac Mon Sep 17 00:00:00 2001 From: Pavel Gnedov Date: Fri, 2 Feb 2024 09:39:14 +0700 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D1=80=D0=B8=D0=B8=20=D0=B2=20=D0=BA=D0=BE=D0=B4=20=D0=B2=D0=B8?= =?UTF-8?q?=D0=B4=D0=B6=D0=B5=D1=82=D0=B0=20=D0=BA=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B4=D0=B0=D1=80=D1=8F=20=D0=BD=D0=B0=20frontend-=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../widgets/calendar-next-events.tsx | 180 ++++++++++-------- 1 file changed, 105 insertions(+), 75 deletions(-) diff --git a/frontend/src/dashboard/widgets/calendar-next-events.tsx b/frontend/src/dashboard/widgets/calendar-next-events.tsx index 0861722..8661fdb 100644 --- a/frontend/src/dashboard/widgets/calendar-next-events.tsx +++ b/frontend/src/dashboard/widgets/calendar-next-events.tsx @@ -6,6 +6,8 @@ import * as DashboardStoreNs from '../dashboard-store'; import { DateTime } from 'luxon'; import { IssueHref } from '../../misc-components/issue-href'; +// Описание основных и вспомогательных моделей данных для календаря: + export const CalendarEvent = types.model({ from: types.string, fromTimestamp: types.number, @@ -51,81 +53,6 @@ function getEventKey(e: IIssueAndEvent): string { return `${e.issue.id}-${fromKey}-${toKey}-${description}`; } -export const EventsStore = types - .model({ - events: types.array(IssueAndEvent), - }) - .views((self) => { - const getRelativeDate = (issueAndEvent: IIssueAndEvent): string | null => { - const from = Luxon.DateTime.fromMillis(issueAndEvent.event.fromTimestamp); - return from.toRelativeCalendar(); - }; - - const getStartOfDayTimestamp = (issueAndEvent: IIssueAndEvent): number => { - const from = Luxon.DateTime.fromMillis(issueAndEvent.event.fromTimestamp); - return from.startOf('day').toMillis(); - }; - - return { - eventsMap: (): Record => { - return self.events.reduce((acc, issueAndEvent) => { - const key = getEventKey(issueAndEvent); - acc[key] = issueAndEvent; - return acc; - }, {} as Record); - }, - - orderedByDates: (): InDay[] => { - const res: Record = self.events.reduce( - (acc, issueAndEvent) => { - const order = getStartOfDayTimestamp(issueAndEvent); - const formattedDate = DateTime.fromMillis( - issueAndEvent.event.fromTimestamp, - ).toFormat(DATE_FORMAT); - if (!acc[order]) { - acc[order] = { - order: order, - relativeDate: getRelativeDate(issueAndEvent), - formattedDate: formattedDate, - events: [], - }; - } - const key = getEventKey(issueAndEvent); - acc[order].events.push(key); - return acc; - }, - {} as Record, - ); - return Object.values(res).sort((a, b) => a.order - b.order); - }, - - formattedDateTimes: (): Record => { - const res: Record = self.events.reduce( - (acc, event) => { - const key = getEventKey(event); - acc[key] = getFormattedDateTime(event); - return acc; - }, - {} as Record, - ); - return res; - }, - }; - }) - .actions((self) => { - return { - setEvents: (events: any): void => { - self.events = events; - }, - }; - }); - -export type IEventsStore = Instance; - -export type Props = { - store: DashboardStoreNs.IWidget; -}; - function getFormattedDateTime( issueAndEvent: IIssueAndEvent, ): IFormattedDateTime { @@ -152,6 +79,99 @@ function getFormattedDateTime( }); } +function getRelativeDate(issueAndEvent: IIssueAndEvent): string | null { + const from = Luxon.DateTime.fromMillis(issueAndEvent.event.fromTimestamp); + return from.toRelativeCalendar(); +} + +function getStartOfDayTimestamp(issueAndEvent: IIssueAndEvent): number { + const from = Luxon.DateTime.fromMillis(issueAndEvent.event.fromTimestamp); + return from.startOf('day').toMillis(); +} + +/** Стор данных для виджета "Календарь следующих событий" */ +export const EventsStore = types + .model({ + events: types.array(IssueAndEvent), + }) + .views((self) => { + return { + /** Геттер мапы событий в формате eventKey -> issue+event */ + eventsMap: (): Record => { + return self.events.reduce((acc, issueAndEvent) => { + const key = getEventKey(issueAndEvent); + acc[key] = issueAndEvent; + return acc; + }, {} as Record); + }, + + /** + * Геттер сгруппированных по дням данных. + * + * Ключ группы определяется по timestamp-у указывающему на начало дня + * + * Дополнительные поля relativeDate и formattedDate для отображения в виджете подробной + * информации об этой группе событий + */ + orderedByDates: (): InDay[] => { + const res: Record = self.events.reduce( + (acc, issueAndEvent) => { + const order = getStartOfDayTimestamp(issueAndEvent); + const formattedDate = DateTime.fromMillis( + issueAndEvent.event.fromTimestamp, + ).toFormat(DATE_FORMAT); + if (!acc[order]) { + acc[order] = { + order: order, + relativeDate: getRelativeDate(issueAndEvent), + formattedDate: formattedDate, + events: [], + }; + } + const key = getEventKey(issueAndEvent); + acc[order].events.push(key); + return acc; + }, + {} as Record, + ); + return Object.values(res).sort((a, b) => a.order - b.order); + }, + + /** + * Мапа событий с отформатированными значениями даты и времени + * + * * Ключ - это ключ события + * * Значение - вспомогательная информация для человеко-читаемого вывода даты и времени + */ + formattedDateTimes: (): Record => { + const res: Record = self.events.reduce( + (acc, event) => { + const key = getEventKey(event); + acc[key] = getFormattedDateTime(event); + return acc; + }, + {} as Record, + ); + return res; + }, + }; + }) + .actions((self) => { + return { + /** Сеттер основных данных */ + setEvents: (events: any): void => { + self.events = events; + }, + }; + }); + +export type IEventsStore = Instance; + +/** + * Компонент для отображения данных из стора EventsStore + * + * @see {EventsStore} + */ export const CalendarList = observer( (props: { store: IEventsStore }): JSX.Element => { const list = props.store.orderedByDates().map((events) => { @@ -186,6 +206,16 @@ export const CalendarList = observer( }, ); +export type Props = { + store: DashboardStoreNs.IWidget; +}; + +/** + * Основной компонент календаря + * + * Он нужен для преобразования стора абстрактного виджета в стор специфичный для + * календаря + */ export const CalendarNextEvents = observer((props: Props): JSX.Element => { const calendarListStore = EventsStore.create(); onSnapshot(props.store, (storeState) => {