Fixing #3658 - RoB Calendar sample - event time changes after page refresh (#5)

Fix for differing local and site time zones

---------

Co-authored-by: d-turley <daniel.p.turley@avanade.com>
This commit is contained in:
d-turley 2023-05-10 13:04:52 -07:00 committed by GitHub
parent 089162f740
commit 3beb73587c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 18 additions and 10 deletions

View File

@ -29,8 +29,8 @@ import { User } from 'common';
import { ListItemEntity } from 'common/sharepoint'; import { ListItemEntity } from 'common/sharepoint';
interface IState { interface IState {
int order; order: number;
User[] owners; owners: User[];
// ... any other properties - these typically correspond with fields on the SharePoint list // ... any other properties - these typically correspond with fields on the SharePoint list
} }

View File

@ -1,3 +1,4 @@
import moment from 'moment-timezone';
import { ICachingOptions } from '@pnp/odata'; import { ICachingOptions } from '@pnp/odata';
import { extractWebUrl, sp } from '@pnp/sp'; import { extractWebUrl, sp } from '@pnp/sp';
import "@pnp/sp/regional-settings"; import "@pnp/sp/regional-settings";
@ -51,6 +52,7 @@ export class OnlineTimeZoneService implements ITimeZoneService {
private _timeZones: TimeZone[]; private _timeZones: TimeZone[];
private _timeZonesBySharePointId: Map<number, TimeZone>; private _timeZonesBySharePointId: Map<number, TimeZone>;
private _localTimeZone: ITimeZone;
public get timeZones(): ITimeZone[] { public get timeZones(): ITimeZone[] {
return this._timeZones; return this._timeZones;
@ -60,6 +62,10 @@ export class OnlineTimeZoneService implements ITimeZoneService {
return this._siteTimeZoneCache.get(sp.web.toUrl()); return this._siteTimeZoneCache.get(sp.web.toUrl());
} }
public get localTimeZone(): ITimeZone {
return this._localTimeZone;
}
public timeZoneFromId(id: number): ITimeZone { public timeZoneFromId(id: number): ITimeZone {
return this._timeZonesBySharePointId.get(id); 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._timeZones = timeZoneResults.map(TimeZone.fromTimeZoneResult).filter(tz => tz.hasMomentMapping);
this._timeZonesBySharePointId = arrayToMap(this._timeZones, tz => tz.id); 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); this._siteTimeZoneCache.set(sp.web.toUrl(), siteTimeZone);

View File

@ -16,6 +16,7 @@ export interface ITimeZone {
export interface ITimeZoneService extends IService { export interface ITimeZoneService extends IService {
readonly timeZones: ITimeZone[]; readonly timeZones: ITimeZone[];
readonly siteTimeZone: ITimeZone; readonly siteTimeZone: ITimeZone;
readonly localTimeZone: ITimeZone;
timeZoneFromId(id: number): ITimeZone; timeZoneFromId(id: number): ITimeZone;
timeZoneForWeb(web?: IWeb): Promise<ITimeZone>; timeZoneForWeb(web?: IWeb): Promise<ITimeZone>;
} }

View File

@ -98,8 +98,8 @@ export const fromDateTime = <T>(row: T, fieldName: PropsOfType<T, Query_DateTime
return value ? moment.tz(value, [moment.ISO_8601, sharepointDateTimeFormat], momentId) : null; return value ? moment.tz(value, [moment.ISO_8601, sharepointDateTimeFormat], momentId) : null;
}; };
export const toDateTime = (dateTime: Moment): Update_DateTime => { export const toDateTime = (dateTime: Moment, { momentId }: ITimeZone): Update_DateTime => {
return dateTime ? dateTime.toISOString() : null; return dateTime ? dateTime.tz(momentId, true).toISOString() : null;
}; };
export const toDateOnly = (dateTime: Moment): Update_DateTime => { export const toDateOnly = (dateTime: Moment): Update_DateTime => {

View File

@ -101,7 +101,7 @@ const getEventTypeValue = (event: Event) => {
return 3; // 3 = cancelled this one occurrence of a series 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; const { isNew, isAllDay, isRecurring, isSeriesMaster, isSeriesException } = event;
return { return {
Title: event.title, Title: event.title,
@ -109,20 +109,20 @@ const toUpdateListItem = (event: Event): IEventUpdateListItem => {
Location: event.location, Location: event.location,
ContactsId: SPField.fromUsers(event.contacts), ContactsId: SPField.fromUsers(event.contacts),
RefinerValuesId: SPField.toLookupMulti(event.refinerValues.get()), RefinerValuesId: SPField.toLookupMulti(event.refinerValues.get()),
EventDate: isAllDay ? SPField.toDateOnly(event.start) : SPField.toDateTime(event.start), EventDate: isAllDay ? SPField.toDateOnly(event.start) : SPField.toDateTime(event.start, siteTimeZone),
EndDate: isAllDay ? SPField.toDateOnly(event.end) : SPField.toDateTime(event.end), EndDate: isAllDay ? SPField.toDateOnly(event.end) : SPField.toDateTime(event.end, siteTimeZone),
fAllDayEvent: event.isAllDay, fAllDayEvent: event.isAllDay,
IsConfidential: event.isConfidential, IsConfidential: event.isConfidential,
RestrictedToAccountsId: SPField.fromUsers(event.restrictedToAccounts), RestrictedToAccountsId: SPField.fromUsers(event.restrictedToAccounts),
ModerationStatus: event.moderationStatus?.name || EventModerationStatus.Pending.name, ModerationStatus: event.moderationStatus?.name || EventModerationStatus.Pending.name,
ModeratorId: SPField.fromUser(event.moderator), ModeratorId: SPField.fromUser(event.moderator),
ModerationTimestamp: SPField.toDateTime(event.moderationTimestamp), ModerationTimestamp: SPField.toDateTime(event.moderationTimestamp, siteTimeZone),
ModerationMessage: event.moderationMessage, ModerationMessage: event.moderationMessage,
fRecurrence: SPField.tofRecurrence(isRecurring), fRecurrence: SPField.tofRecurrence(isRecurring),
EventType: getEventTypeValue(event), EventType: getEventTypeValue(event),
RecurrenceData: isSeriesMaster ? RecurrenceData.serialize(event.recurrence) : undefined, RecurrenceData: isSeriesMaster ? RecurrenceData.serialize(event.recurrence) : undefined,
MasterSeriesItemID: isSeriesException ? event.seriesMaster.get()?.id : 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, UID: isRecurring && isNew ? event.recurrenceUID?.toString() : undefined,
Duration: event.duration.asSeconds() Duration: event.duration.asSeconds()
}; };
@ -137,6 +137,6 @@ export class EventLoader extends PagedViewLoader<Event> {
protected readonly extractReferencedUsers = (event: Event) => [...event.contacts, ...event.restrictedToAccounts, event.moderator]; 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 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; protected readonly diagnosePersistError = (error: any) => ErrorHandler.is_412_PRECONDITION_FAILED(error) ? ErrorDiagnosis.Propogate : ErrorDiagnosis.Critical;
} }