diff --git a/samples/react-rhythm-of-business-calendar/documentation/entities.md b/samples/react-rhythm-of-business-calendar/documentation/entities.md index c906b1a58..a35c05456 100644 --- a/samples/react-rhythm-of-business-calendar/documentation/entities.md +++ b/samples/react-rhythm-of-business-calendar/documentation/entities.md @@ -29,8 +29,8 @@ import { User } from 'common'; import { ListItemEntity } from 'common/sharepoint'; interface IState { - int order; - User[] owners; + order: number; + owners: User[]; // ... any other properties - these typically correspond with fields on the SharePoint list } diff --git a/samples/react-rhythm-of-business-calendar/src/common/services/timezones/OnlineTimeZoneService.ts b/samples/react-rhythm-of-business-calendar/src/common/services/timezones/OnlineTimeZoneService.ts index 890c637d3..eb0260f35 100644 --- a/samples/react-rhythm-of-business-calendar/src/common/services/timezones/OnlineTimeZoneService.ts +++ b/samples/react-rhythm-of-business-calendar/src/common/services/timezones/OnlineTimeZoneService.ts @@ -1,3 +1,4 @@ +import moment from 'moment-timezone'; import { ICachingOptions } from '@pnp/odata'; import { extractWebUrl, sp } from '@pnp/sp'; import "@pnp/sp/regional-settings"; @@ -51,6 +52,7 @@ export class OnlineTimeZoneService implements ITimeZoneService { private _timeZones: TimeZone[]; private _timeZonesBySharePointId: Map; + private _localTimeZone: ITimeZone; public get timeZones(): ITimeZone[] { return this._timeZones; @@ -60,6 +62,10 @@ export class OnlineTimeZoneService implements ITimeZoneService { return this._siteTimeZoneCache.get(sp.web.toUrl()); } + public get localTimeZone(): ITimeZone { + return this._localTimeZone; + } + public timeZoneFromId(id: number): ITimeZone { return this._timeZonesBySharePointId.get(id); } @@ -84,6 +90,7 @@ export class OnlineTimeZoneService implements ITimeZoneService { this._timeZones = timeZoneResults.map(TimeZone.fromTimeZoneResult).filter(tz => tz.hasMomentMapping); this._timeZonesBySharePointId = arrayToMap(this._timeZones, tz => tz.id); + this._localTimeZone = this._timeZones.find(tz => tz.momentId === moment.tz.guess()); this._siteTimeZoneCache.set(sp.web.toUrl(), siteTimeZone); diff --git a/samples/react-rhythm-of-business-calendar/src/common/services/timezones/TimeZoneServiceDescriptor.ts b/samples/react-rhythm-of-business-calendar/src/common/services/timezones/TimeZoneServiceDescriptor.ts index b14225193..33faf99f8 100644 --- a/samples/react-rhythm-of-business-calendar/src/common/services/timezones/TimeZoneServiceDescriptor.ts +++ b/samples/react-rhythm-of-business-calendar/src/common/services/timezones/TimeZoneServiceDescriptor.ts @@ -16,6 +16,7 @@ export interface ITimeZone { export interface ITimeZoneService extends IService { readonly timeZones: ITimeZone[]; readonly siteTimeZone: ITimeZone; + readonly localTimeZone: ITimeZone; timeZoneFromId(id: number): ITimeZone; timeZoneForWeb(web?: IWeb): Promise; } diff --git a/samples/react-rhythm-of-business-calendar/src/common/sharepoint/SPField.ts b/samples/react-rhythm-of-business-calendar/src/common/sharepoint/SPField.ts index 60a339779..5499fb934 100644 --- a/samples/react-rhythm-of-business-calendar/src/common/sharepoint/SPField.ts +++ b/samples/react-rhythm-of-business-calendar/src/common/sharepoint/SPField.ts @@ -98,8 +98,8 @@ export const fromDateTime = (row: T, fieldName: PropsOfType { - return dateTime ? dateTime.toISOString() : null; +export const toDateTime = (dateTime: Moment, { momentId }: ITimeZone): Update_DateTime => { + return dateTime ? dateTime.tz(momentId, true).toISOString() : null; }; export const toDateOnly = (dateTime: Moment): Update_DateTime => { diff --git a/samples/react-rhythm-of-business-calendar/src/services/events/EventLoader.ts b/samples/react-rhythm-of-business-calendar/src/services/events/EventLoader.ts index dad2f2536..91237335e 100644 --- a/samples/react-rhythm-of-business-calendar/src/services/events/EventLoader.ts +++ b/samples/react-rhythm-of-business-calendar/src/services/events/EventLoader.ts @@ -101,7 +101,7 @@ const getEventTypeValue = (event: Event) => { return 3; // 3 = cancelled this one occurrence of a series } -const toUpdateListItem = (event: Event): IEventUpdateListItem => { +const toUpdateListItem = (event: Event, siteTimeZone: ITimeZone): IEventUpdateListItem => { const { isNew, isAllDay, isRecurring, isSeriesMaster, isSeriesException } = event; return { Title: event.title, @@ -109,20 +109,20 @@ const toUpdateListItem = (event: Event): IEventUpdateListItem => { Location: event.location, ContactsId: SPField.fromUsers(event.contacts), RefinerValuesId: SPField.toLookupMulti(event.refinerValues.get()), - EventDate: isAllDay ? SPField.toDateOnly(event.start) : SPField.toDateTime(event.start), - EndDate: isAllDay ? SPField.toDateOnly(event.end) : SPField.toDateTime(event.end), + EventDate: isAllDay ? SPField.toDateOnly(event.start) : SPField.toDateTime(event.start, siteTimeZone), + EndDate: isAllDay ? SPField.toDateOnly(event.end) : SPField.toDateTime(event.end, siteTimeZone), fAllDayEvent: event.isAllDay, IsConfidential: event.isConfidential, RestrictedToAccountsId: SPField.fromUsers(event.restrictedToAccounts), ModerationStatus: event.moderationStatus?.name || EventModerationStatus.Pending.name, ModeratorId: SPField.fromUser(event.moderator), - ModerationTimestamp: SPField.toDateTime(event.moderationTimestamp), + ModerationTimestamp: SPField.toDateTime(event.moderationTimestamp, siteTimeZone), ModerationMessage: event.moderationMessage, fRecurrence: SPField.tofRecurrence(isRecurring), EventType: getEventTypeValue(event), RecurrenceData: isSeriesMaster ? RecurrenceData.serialize(event.recurrence) : undefined, MasterSeriesItemID: isSeriesException ? event.seriesMaster.get()?.id : undefined, - RecurrenceID: isSeriesException ? SPField.toDateTime(event.recurrenceExceptionInstanceDate) : undefined, + RecurrenceID: isSeriesException ? SPField.toDateTime(event.recurrenceExceptionInstanceDate, siteTimeZone) : undefined, UID: isRecurring && isNew ? event.recurrenceUID?.toString() : undefined, Duration: event.duration.asSeconds() }; @@ -137,6 +137,6 @@ export class EventLoader extends PagedViewLoader { protected readonly extractReferencedUsers = (event: Event) => [...event.contacts, ...event.restrictedToAccounts, event.moderator]; protected readonly toEntity = (row: IEventListItemResult, event: Event) => toEvent(row, event, this.timezones.siteTimeZone, this._refinerValueLoader, this._entitiesById); - protected readonly updateListItem = toUpdateListItem; + protected readonly updateListItem = (event: Event) => toUpdateListItem(event, this.timezones.siteTimeZone); protected readonly diagnosePersistError = (error: any) => ErrorHandler.is_412_PRECONDITION_FAILED(error) ? ErrorDiagnosis.Propogate : ErrorDiagnosis.Critical; } \ No newline at end of file