@sprucelabs/spruce-calendar-components 21.0.2 → 21.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/build/.spruce/errors/errors.types.d.ts +122 -0
  2. package/build/.spruce/errors/errors.types.js +4 -0
  3. package/build/.spruce/errors/options.types.d.ts +28 -0
  4. package/build/.spruce/errors/options.types.js +2 -0
  5. package/build/constants.d.ts +5 -0
  6. package/build/constants.js +9 -0
  7. package/build/errors/SpruceError.d.ts +5 -0
  8. package/build/errors/SpruceError.js +45 -0
  9. package/build/esm/.spruce/errors/errors.types.d.ts +122 -0
  10. package/build/esm/.spruce/errors/errors.types.js +3 -0
  11. package/build/esm/.spruce/errors/options.types.d.ts +28 -0
  12. package/build/esm/.spruce/errors/options.types.js +1 -0
  13. package/build/esm/constants.d.ts +5 -0
  14. package/build/esm/constants.js +6 -0
  15. package/build/esm/errors/SpruceError.d.ts +5 -0
  16. package/build/esm/errors/SpruceError.js +39 -0
  17. package/build/esm/index-module.d.ts +30 -0
  18. package/build/esm/index-module.js +7 -0
  19. package/build/esm/skillViewControllers/Root.svc.d.ts +73 -0
  20. package/build/esm/skillViewControllers/Root.svc.js +404 -0
  21. package/build/esm/toolBelt/CalendarToolTestFactory.d.ts +5 -0
  22. package/build/esm/toolBelt/CalendarToolTestFactory.js +28 -0
  23. package/build/esm/toolBelt/states/PrerequisitesToolBeltState.d.ts +37 -0
  24. package/build/esm/toolBelt/states/PrerequisitesToolBeltState.js +190 -0
  25. package/build/esm/toolBelt/states/RootToolBeltState.d.ts +37 -0
  26. package/build/esm/toolBelt/states/RootToolBeltState.js +122 -0
  27. package/build/esm/toolBelt/states/makeEventTyped.d.ts +2 -0
  28. package/build/esm/toolBelt/states/makeEventTyped.js +8 -0
  29. package/build/esm/types/calendar.types.d.ts +3 -0
  30. package/build/esm/utilities/CalendarEventManager.d.ts +72 -0
  31. package/build/esm/utilities/CalendarEventManager.js +321 -0
  32. package/build/esm/utilities/CalendarPeopleManager.d.ts +56 -0
  33. package/build/esm/utilities/CalendarPeopleManager.js +182 -0
  34. package/build/esm/utilities/calendarShiftGenerator.d.ts +8 -0
  35. package/build/esm/utilities/calendarShiftGenerator.js +24 -0
  36. package/build/esm/viewControllers/CalendarSelectTool.vc.d.ts +28 -0
  37. package/build/esm/viewControllers/CalendarSelectTool.vc.js +103 -0
  38. package/build/esm/viewControllers/DateSelectCard.vc.d.ts +29 -0
  39. package/build/esm/viewControllers/DateSelectCard.vc.js +77 -0
  40. package/build/esm/viewControllers/PersonSelectTool.vc.d.ts +36 -0
  41. package/build/esm/viewControllers/PersonSelectTool.vc.js +156 -0
  42. package/build/esm/viewControllers/SelectUpdateRepeatingStrategyCard.vc.d.ts +18 -0
  43. package/build/esm/viewControllers/SelectUpdateRepeatingStrategyCard.vc.js +85 -0
  44. package/build/index-module.d.ts +30 -0
  45. package/build/index-module.js +32 -0
  46. package/build/skillViewControllers/Root.svc.d.ts +73 -0
  47. package/build/skillViewControllers/Root.svc.js +359 -0
  48. package/build/toolBelt/CalendarToolTestFactory.d.ts +5 -0
  49. package/build/toolBelt/CalendarToolTestFactory.js +34 -0
  50. package/build/toolBelt/states/PrerequisitesToolBeltState.d.ts +37 -0
  51. package/build/toolBelt/states/PrerequisitesToolBeltState.js +172 -0
  52. package/build/toolBelt/states/RootToolBeltState.d.ts +37 -0
  53. package/build/toolBelt/states/RootToolBeltState.js +113 -0
  54. package/build/toolBelt/states/makeEventTyped.d.ts +2 -0
  55. package/build/toolBelt/states/makeEventTyped.js +14 -0
  56. package/build/types/calendar.types.d.ts +3 -0
  57. package/build/utilities/CalendarEventManager.d.ts +72 -0
  58. package/build/utilities/CalendarEventManager.js +279 -0
  59. package/build/utilities/CalendarPeopleManager.d.ts +56 -0
  60. package/build/utilities/CalendarPeopleManager.js +163 -0
  61. package/build/utilities/calendarShiftGenerator.d.ts +8 -0
  62. package/build/utilities/calendarShiftGenerator.js +26 -0
  63. package/build/viewControllers/CalendarSelectTool.vc.d.ts +28 -0
  64. package/build/viewControllers/CalendarSelectTool.vc.js +93 -0
  65. package/build/viewControllers/DateSelectCard.vc.d.ts +29 -0
  66. package/build/viewControllers/DateSelectCard.vc.js +69 -0
  67. package/build/viewControllers/PersonSelectTool.vc.d.ts +36 -0
  68. package/build/viewControllers/PersonSelectTool.vc.js +140 -0
  69. package/build/viewControllers/SelectUpdateRepeatingStrategyCard.vc.d.ts +18 -0
  70. package/build/viewControllers/SelectUpdateRepeatingStrategyCard.vc.js +88 -0
  71. package/package.json +99 -30
@@ -0,0 +1,404 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { AbstractSkillViewController, ToolBeltStateMachine, } from '@sprucelabs/heartwood-view-controllers';
11
+ import { RemoteViewControllerFactory } from '@sprucelabs/spruce-heartwood-utils';
12
+ import RemoteEventStore from '../stores/RemoteEventStore.js';
13
+ import RemotePreferencesStore from '../stores/RemotePreferencesStore.js';
14
+ import { PrerequisitesToolBeltState } from '../toolBelt/states/PrerequisitesToolBeltState.js';
15
+ import { RootToolBeltState } from '../toolBelt/states/RootToolBeltState.js';
16
+ import { CalendarEventManager } from '../utilities/CalendarEventManager.js';
17
+ import CalendarPeopleManager from '../utilities/CalendarPeopleManager.js';
18
+ export default class RootSkillViewController extends AbstractSkillViewController {
19
+ constructor(options) {
20
+ super(options);
21
+ this.getScope = () => ['employed', 'location'];
22
+ this.toolBeltVc = this.ToolBeltVc();
23
+ this.calendarVc = this.CalendarVc();
24
+ this.sm = this.ToolBeltStateMachine();
25
+ this.remoteVc = RemoteViewControllerFactory.Factory({
26
+ connectToApi: this.connectToApi.bind(this),
27
+ vcFactory: this.getVcFactory(),
28
+ });
29
+ this.remoteEventStore = new RemoteEventStore({
30
+ connectToApi: this.connectToApi.bind(this),
31
+ });
32
+ this.preferences = new RemotePreferencesStore({
33
+ connectToApi: this.connectToApi.bind(this),
34
+ });
35
+ this.people = new CalendarPeopleManager({
36
+ connectToApi: this.connectToApi.bind(this),
37
+ preferences: this.preferences,
38
+ calendarVc: this.calendarVc,
39
+ getVisibleEvents: this.getVisibleEvents.bind(this),
40
+ });
41
+ this.events = new CalendarEventManager({
42
+ calendarVc: this.calendarVc,
43
+ events: this.remoteEventStore,
44
+ remoteVc: this.remoteVc,
45
+ dates: this.dates,
46
+ sm: this.sm,
47
+ preferences: this.preferences,
48
+ askForUpdateStrategy: this.askForUpdateStrategy.bind(this),
49
+ });
50
+ this.createToolBeltStates();
51
+ }
52
+ createToolBeltStates() {
53
+ this.toolBeltStates = {
54
+ root: new RootToolBeltState({
55
+ people: this.people,
56
+ events: this.events,
57
+ }),
58
+ prerequisites: new PrerequisitesToolBeltState({
59
+ onSelectCalendar: this.handleSelectCalendar.bind(this),
60
+ onSelectEventType: this.handleSelectEventType.bind(this),
61
+ }),
62
+ };
63
+ }
64
+ ToolBeltStateMachine() {
65
+ const sm = new ToolBeltStateMachine({
66
+ toolBeltVc: this.toolBeltVc,
67
+ vcFactory: this.getVcFactory(),
68
+ connectToApi: this.connectToApi.bind(this),
69
+ context: {
70
+ calendarVc: this.calendarVc,
71
+ cancelEvent: (eventId) => this.handleCancelEvent(eventId),
72
+ },
73
+ });
74
+ return sm;
75
+ }
76
+ handleCancelEvent(eventId) {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ const confirm = yield this.confirm({
79
+ title: 'Cancel?',
80
+ message: `You wanna cancel this?`,
81
+ });
82
+ if (confirm) {
83
+ yield this.events.removeEvent(eventId);
84
+ }
85
+ });
86
+ }
87
+ askForUpdateStrategy(cleaned) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ let strategy;
90
+ const dlg = this.renderInDialog(Object.assign({ shouldShowCloseButton: false }, this.Controller('calendar.select-update-repeating-strategy-card', {
91
+ event: cleaned,
92
+ onSelectStrategy: (s) => __awaiter(this, void 0, void 0, function* () {
93
+ strategy = s;
94
+ yield dlg.hide();
95
+ }),
96
+ }).render()));
97
+ yield dlg.wait();
98
+ return strategy;
99
+ });
100
+ }
101
+ handleSelectEventType(type) {
102
+ var _a, _b;
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ this.selectingTypePromise = new Promise((resolve) => {
105
+ this.selectingTypeResolve = resolve;
106
+ });
107
+ if (type.viewControllerId) {
108
+ try {
109
+ yield this.events.setupVcForEventType(type.viewControllerId, type.slug);
110
+ yield this.transitionToStateFromDraftEvent();
111
+ }
112
+ catch (err) {
113
+ (_a = this.selectingTypeResolve) === null || _a === void 0 ? void 0 : _a.call(this);
114
+ console.error(err);
115
+ yield this.alert({
116
+ message: `I could not load what I need to add your ${type.name}! I've let the humans know and they are on the case!`,
117
+ });
118
+ yield this.restoreDraftAfterStateLoadError();
119
+ return;
120
+ }
121
+ }
122
+ (_b = this.selectingTypeResolve) === null || _b === void 0 ? void 0 : _b.call(this);
123
+ });
124
+ }
125
+ restoreDraftAfterStateLoadError() {
126
+ return __awaiter(this, void 0, void 0, function* () {
127
+ yield this.waitUntilDoneSaving();
128
+ yield this.sm.waitForContextUpdate();
129
+ void this.transitionTo(this.toolBeltStates.prerequisites);
130
+ yield this.events.restoreEventToDraftOnStateLoadError();
131
+ });
132
+ }
133
+ transitionToStateFromDraftEvent() {
134
+ return __awaiter(this, void 0, void 0, function* () {
135
+ const { event } = this.sm.getContext();
136
+ yield this.transitionToolBeltForEvent(event.id);
137
+ });
138
+ }
139
+ transitionToolBeltForEvent(eventId) {
140
+ var _a;
141
+ return __awaiter(this, void 0, void 0, function* () {
142
+ const vc = this.calendarVc.getEventVc(eventId);
143
+ const state = (_a = vc.getToolBeltState) === null || _a === void 0 ? void 0 : _a.call(vc);
144
+ if (state) {
145
+ yield this.transitionTo(state);
146
+ }
147
+ });
148
+ }
149
+ transitionTo(state) {
150
+ return __awaiter(this, void 0, void 0, function* () {
151
+ yield this.sm.transitionTo(state);
152
+ });
153
+ }
154
+ waitUntilDoneSaving() {
155
+ var _a;
156
+ return __awaiter(this, void 0, void 0, function* () {
157
+ yield Promise.all([
158
+ (_a = this.remoteEventStore) === null || _a === void 0 ? void 0 : _a.waitForPendingSaves(),
159
+ this.selectingTypePromise,
160
+ this.transitionPromise,
161
+ this.loadEventsPromise,
162
+ this.sm.waitForContextUpdate(),
163
+ ]);
164
+ });
165
+ }
166
+ handleSelectCalendar(calendar) {
167
+ var _a;
168
+ (_a = this.remoteEventStore) === null || _a === void 0 ? void 0 : _a.setCalendarId(calendar.id);
169
+ }
170
+ getToolBeltStateMachine() {
171
+ return this.sm;
172
+ }
173
+ getToolBeltStateId() {
174
+ return this.sm.getStateId();
175
+ }
176
+ CalendarVc() {
177
+ return this.Controller('calendar.calendar', {
178
+ onClickEvent: this.handleClickEvent.bind(this),
179
+ onAddDraftEvent: this.handleDraftEventAdded.bind(this),
180
+ onRemoveDraftEvent: this.handleDraftEventRemoved.bind(this),
181
+ onEventSwapped: this.handleEventSwapped.bind(this),
182
+ onDropEvent: this.handleDropEvent.bind(this),
183
+ onChangeStartDate: this.handleChangeDate.bind(this),
184
+ onDeselectEvent: this.handleDeselectEvent.bind(this),
185
+ });
186
+ }
187
+ handleChangeDate() {
188
+ return __awaiter(this, void 0, void 0, function* () {
189
+ this.makeDateSelectMatchSelectedDateFromCalendar();
190
+ yield this.loadEvents();
191
+ });
192
+ }
193
+ makeDateSelectMatchSelectedDateFromCalendar() {
194
+ const date = this.getStartDate();
195
+ this.setSelectedDateInDateSelectVc(date);
196
+ }
197
+ setSelectedDateInDateSelectVc(date) {
198
+ const { year, month, day } = this.dates.splitDate(date);
199
+ this.toolBeltStates.root.setSelectedDate(year, month, day);
200
+ }
201
+ getStartDate() {
202
+ var _a;
203
+ return (_a = this.calendarVc.getStartDate()) !== null && _a !== void 0 ? _a : this.dates.date();
204
+ }
205
+ handleDeselectEvent() {
206
+ return __awaiter(this, void 0, void 0, function* () {
207
+ if (this.calendarVc.getIsSwappingEvent()) {
208
+ return;
209
+ }
210
+ yield this.resetToRootState();
211
+ });
212
+ }
213
+ resetToRootState() {
214
+ return __awaiter(this, void 0, void 0, function* () {
215
+ yield this.events.reset();
216
+ this.makeDateSelectMatchSelectedDateFromCalendar();
217
+ this.transitionPromise = this.sm.transitionTo(this.toolBeltStates.root);
218
+ this.toolBeltVc.close();
219
+ yield this.transitionPromise;
220
+ });
221
+ }
222
+ ToolBeltVc() {
223
+ return this.Controller('toolBelt', {
224
+ shouldRenderAllToolsAtOnce: true,
225
+ });
226
+ }
227
+ handleClickEvent(options) {
228
+ var _a, _b;
229
+ return __awaiter(this, void 0, void 0, function* () {
230
+ const { event } = options;
231
+ yield this.events.selectEvent(event.id);
232
+ this.toolBeltVc.open({ shouldStayOpen: true });
233
+ try {
234
+ if (!event.eventTypeSlug) {
235
+ yield this.transitionTo(this.toolBeltStates.prerequisites);
236
+ }
237
+ else {
238
+ yield this.transitionToolBeltForEvent(event.id);
239
+ }
240
+ }
241
+ catch (err) {
242
+ console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
243
+ this.calendarVc.deselectEvent();
244
+ yield this.alert({
245
+ message: (_b = err.message) !== null && _b !== void 0 ? _b : 'Shoot! I could not load that for you! Refresh and try again!!',
246
+ });
247
+ }
248
+ });
249
+ }
250
+ handleDraftEventAdded(event) {
251
+ return __awaiter(this, void 0, void 0, function* () {
252
+ if (!event.eventTypeSlug) {
253
+ yield this.events.addDraftEvent(event);
254
+ this.toolBeltVc.open({ shouldStayOpen: true });
255
+ yield this.sm.transitionTo(this.toolBeltStates.prerequisites);
256
+ }
257
+ });
258
+ }
259
+ handleEventSwapped(event) {
260
+ return __awaiter(this, void 0, void 0, function* () {
261
+ yield this.events.silentlySwapEvent(this.sm.getContext().event.id, event);
262
+ });
263
+ }
264
+ handleDropEvent(id, updates) {
265
+ return __awaiter(this, void 0, void 0, function* () {
266
+ return this.events.handleDropEvent(id, updates);
267
+ });
268
+ }
269
+ handleDraftEventRemoved() {
270
+ return __awaiter(this, void 0, void 0, function* () { });
271
+ }
272
+ getPersonSelectVc() {
273
+ return this.toolBeltStates.root.getPersonSelectCardVc();
274
+ }
275
+ renderToolBelt() {
276
+ return this.toolBeltVc.render();
277
+ }
278
+ getCalendarSelectVc() {
279
+ return this.toolBeltStates.root.getCalendarSelectCardVc();
280
+ }
281
+ getCalendarVc() {
282
+ return this.calendarVc;
283
+ }
284
+ load(options) {
285
+ var _a;
286
+ return __awaiter(this, void 0, void 0, function* () {
287
+ yield this.sm.updateContext(Object.assign(Object.assign({}, options), { people: this.people, events: this.events }));
288
+ this.client = yield this.connectToApi();
289
+ const { scope, locale, args, router } = options;
290
+ yield locale.on('did-change-timezones', () => {
291
+ return this.syncOffsetWithLocale(locale);
292
+ });
293
+ const [location] = yield Promise.all([
294
+ scope.getCurrentLocation(),
295
+ this.loadLoggedInPerson(),
296
+ ]);
297
+ this.organizationId = location === null || location === void 0 ? void 0 : location.organizationId;
298
+ this.locationId = location === null || location === void 0 ? void 0 : location.id;
299
+ try {
300
+ yield this.preferences.load(this.organizationId);
301
+ yield this.people.on('did-update', this.syncPeopleOnCalendar.bind(this));
302
+ yield this.people.load({
303
+ loggedInPerson: this.person,
304
+ locationId: this.locationId,
305
+ organizationId: this.organizationId,
306
+ });
307
+ yield this.remoteEventStore.load({
308
+ locationId: this.locationId,
309
+ organizationId: this.organizationId,
310
+ });
311
+ yield this.events.load();
312
+ }
313
+ catch (err) {
314
+ yield this.alert({
315
+ message: (_a = err.message) !== null && _a !== void 0 ? _a : 'Something catastrophic happened! We gotta get out of there!',
316
+ });
317
+ yield router.redirect('heartwood.root');
318
+ }
319
+ const { startDate = this.dates.date() } = args;
320
+ yield this.calendarVc.renderOnce(() => {
321
+ this.syncOffsetWithLocale(locale);
322
+ this.calendarVc.setStartDate(startDate);
323
+ });
324
+ yield this.transitionToRoot();
325
+ this.setSelectedDateInDateSelectVc(startDate);
326
+ yield this.waitUntilDoneSaving();
327
+ });
328
+ }
329
+ syncPeopleOnCalendar() {
330
+ const visiblePeople = this.people.getVisiblePeople();
331
+ this.calendarVc.setPeople(visiblePeople);
332
+ }
333
+ syncOffsetWithLocale(locale) {
334
+ const offset = locale.getTimezoneOffsetMinutes();
335
+ this.calendarVc.setTimezoneOffsetMs(offset * 60 * 1000);
336
+ }
337
+ loadEvents() {
338
+ return __awaiter(this, void 0, void 0, function* () {
339
+ this.loadEventsPromise = this._loadEvents();
340
+ yield this.loadEventsPromise;
341
+ });
342
+ }
343
+ _loadEvents() {
344
+ var _a;
345
+ return __awaiter(this, void 0, void 0, function* () {
346
+ try {
347
+ if (this.events.getCalendars().length > 0) {
348
+ const date = this.getStartDate();
349
+ const startDate = this.dates.getStartOfDay(date);
350
+ const endDate = this.dates.getEndOfDay(date);
351
+ yield this.events.loadEvents(startDate, endDate, this.people.getTeam().map((t) => t.id));
352
+ yield this.people.emit('did-update');
353
+ }
354
+ }
355
+ catch (err) {
356
+ console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
357
+ void this.alert({
358
+ message: err.message,
359
+ });
360
+ }
361
+ });
362
+ }
363
+ transitionToRoot() {
364
+ return __awaiter(this, void 0, void 0, function* () {
365
+ yield this.sm.transitionTo(this.toolBeltStates.root);
366
+ });
367
+ }
368
+ loadLoggedInPerson() {
369
+ return __awaiter(this, void 0, void 0, function* () {
370
+ const [{ auth }] = yield this.client.emitAndFlattenResponses('whoami::v2020_12_25');
371
+ this.person = auth.person;
372
+ });
373
+ }
374
+ getVisibleEvents() {
375
+ const end = this.dates.getEndOfDay(this.calendarVc.getStartDate());
376
+ const start = this.dates.getStartOfDay(this.calendarVc.getStartDate());
377
+ const events = this.events
378
+ .getAllEvents()
379
+ .filter((e) => e.startDateTimeMs <= end && e.startDateTimeMs >= start);
380
+ return events;
381
+ }
382
+ render() {
383
+ return {
384
+ isFullScreen: true,
385
+ layouts: [
386
+ {
387
+ cards: [
388
+ {
389
+ body: {
390
+ sections: [
391
+ {
392
+ shouldBePadded: false,
393
+ calendar: this.calendarVc.render(),
394
+ },
395
+ ],
396
+ },
397
+ },
398
+ ],
399
+ },
400
+ ],
401
+ };
402
+ }
403
+ }
404
+ RootSkillViewController.id = 'root';
@@ -0,0 +1,5 @@
1
+ import { ViewControllerId } from '@sprucelabs/heartwood-view-controllers';
2
+ import { CalendarTool, CalendarToolBeltStateMachine, CalendarToolOptions } from '../types/calendar.types';
3
+ export default class CalendarToolTestFactory {
4
+ static Tool(stateMachine: CalendarToolBeltStateMachine, vcId: ViewControllerId, options?: Partial<CalendarToolOptions>): CalendarTool;
5
+ }
@@ -0,0 +1,28 @@
1
+ import { assertOptions, SchemaError } from '@sprucelabs/schema';
2
+ import { assert } from '@sprucelabs/test';
3
+ import cloneDeep from 'lodash/cloneDeep.js';
4
+ export default class CalendarToolTestFactory {
5
+ static Tool(stateMachine, vcId, options) {
6
+ assertOptions({ stateMachine, vcId }, ['stateMachine', 'vcId']);
7
+ const vc = stateMachine.Controller(vcId, Object.assign({ getContext: () => stateMachine.getContext(), updateContext: (context) => {
8
+ return stateMachine.updateContext(context);
9
+ }, getPersonFromEvent: () => {
10
+ throw new SchemaError({
11
+ code: 'MISSING_PARAMETERS',
12
+ parameters: ['getPersonFromEvent'],
13
+ friendlyMessage: `You need to pass 'getPersonFromEvent: () => login.getPerson()' or similar to CalendarToolTestFactory.Tool(....)`,
14
+ });
15
+ }, getHasPendingContextChanges: () => {
16
+ throw new SchemaError({
17
+ code: 'MISSING_PARAMETERS',
18
+ parameters: ['getHasPendingContextChanges'],
19
+ friendlyMessage: `You need to pass 'getHasPendingContextChanges: () => boolean' or similar to CalendarToolTestFactory.Tool(....)`,
20
+ });
21
+ } }, cloneDeep(options !== null && options !== void 0 ? options : {})));
22
+ void stateMachine.on('did-update-context', () => {
23
+ return vc.handleUpdateContext(stateMachine.getContext());
24
+ });
25
+ assert.isFunction(vc.handleUpdateContext, `You need to make sure your card view controller implements the CalendarTool interface!`);
26
+ return vc;
27
+ }
28
+ }
@@ -0,0 +1,37 @@
1
+ import { CardViewController, SpruceSchemas, ToolBeltState } from '@sprucelabs/heartwood-view-controllers';
2
+ import { CalendarToolBeltStateMachine } from '../../types/calendar.types';
3
+ declare type Calendar = SpruceSchemas.Calendar.v2021_05_19.Calendar;
4
+ declare type EventType = SpruceSchemas.Calendar.v2021_05_19.CalendarEventType;
5
+ declare type SelectCalendarHandler = (calendar: Calendar) => Promise<void> | void;
6
+ declare type SelectTypeHandler = (type: EventType) => Promise<void> | void;
7
+ export interface PrerequisitesToolBeltStateOptions {
8
+ onSelectCalendar?: SelectCalendarHandler;
9
+ onSelectEventType?: SelectTypeHandler;
10
+ }
11
+ export declare class PrerequisitesToolBeltState implements ToolBeltState {
12
+ readonly id = "prerequisites";
13
+ private calendarSelectCardVc?;
14
+ private typeSelectCardVc?;
15
+ private toolBeltVc;
16
+ private sm;
17
+ private calendars?;
18
+ private selectCalendarHandler?;
19
+ private selectEventTypeHandler?;
20
+ private calendar?;
21
+ constructor(options?: PrerequisitesToolBeltStateOptions);
22
+ load(stateMachine: CalendarToolBeltStateMachine): Promise<void>;
23
+ destroy(): void;
24
+ private setupCalendarSelectCard;
25
+ private handleSelectCalendar;
26
+ private setupTypeSelectCard;
27
+ private renderTypeButtonsSection;
28
+ private handleSelectType;
29
+ private updateEventInContext;
30
+ private TypeSelectCardVc;
31
+ getCalendarSelectCardVc(): CardViewController | undefined;
32
+ getTypeSelectCardVc(): CardViewController | undefined;
33
+ private SelectCalendarCardVc;
34
+ private listCalendars;
35
+ private connectToApi;
36
+ }
37
+ export {};
@@ -0,0 +1,190 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import makeEventTyped from './makeEventTyped.js';
11
+ export class PrerequisitesToolBeltState {
12
+ constructor(options) {
13
+ this.id = 'prerequisites';
14
+ this.selectCalendarHandler = options === null || options === void 0 ? void 0 : options.onSelectCalendar;
15
+ this.selectEventTypeHandler = options === null || options === void 0 ? void 0 : options.onSelectEventType;
16
+ }
17
+ load(stateMachine) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ const toolBeltVc = stateMachine.getToolBeltVc();
20
+ this.toolBeltVc = toolBeltVc;
21
+ this.sm = stateMachine;
22
+ void this.toolBeltVc.renderOnce(() => {
23
+ this.toolBeltVc.clearTools();
24
+ this.toolBeltVc.clearStickyTools();
25
+ });
26
+ if (!this.calendars) {
27
+ this.calendars = yield this.listCalendars();
28
+ }
29
+ if (this.calendars.length === 1) {
30
+ yield this.handleSelectCalendar(this.calendars[0]);
31
+ return;
32
+ }
33
+ this.setupCalendarSelectCard(this.calendars);
34
+ yield this.sm.updateContext({
35
+ event: Object.assign(Object.assign({}, this.sm.getContext().event), { isBusy: false }),
36
+ });
37
+ });
38
+ }
39
+ destroy() { }
40
+ setupCalendarSelectCard(calendars) {
41
+ this.calendarSelectCardVc = this.SelectCalendarCardVc();
42
+ this.toolBeltVc.addTool({
43
+ id: 'calendars',
44
+ lineIcon: 'calendar-add',
45
+ card: this.calendarSelectCardVc.render(),
46
+ });
47
+ if (calendars.length > 0) {
48
+ this.calendarSelectCardVc.addSection({
49
+ buttons: calendars.map((c) => ({
50
+ id: c.id,
51
+ label: c.title,
52
+ onClick: () => this.handleSelectCalendar(c),
53
+ })),
54
+ });
55
+ }
56
+ else {
57
+ this.calendarSelectCardVc.addSection({
58
+ text: {
59
+ content: `You don't have any calendars. The only way to get one is to book an appointment or work at a place that uses Sprucebot! 🌲🤖`,
60
+ },
61
+ });
62
+ }
63
+ this.calendarSelectCardVc.setIsBusy(false);
64
+ }
65
+ handleSelectCalendar(calendar) {
66
+ var _a, _b, _c, _d;
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ (_a = this.calendarSelectCardVc) === null || _a === void 0 ? void 0 : _a.setIsBusy(true);
69
+ this.calendar = calendar;
70
+ yield ((_b = this.selectCalendarHandler) === null || _b === void 0 ? void 0 : _b.call(this, calendar));
71
+ const client = yield this.connectToApi();
72
+ let [{ calendarEventTypes }] = yield client.emitAndFlattenResponses('calendar.list-calendar-event-types::v2021_05_19');
73
+ const types = (_c = calendar.eventTypes) !== null && _c !== void 0 ? _c : [];
74
+ if (types.length > 0) {
75
+ calendarEventTypes = calendarEventTypes.filter((t) => types.indexOf(t.slug) > -1);
76
+ }
77
+ if (calendarEventTypes.length === 1) {
78
+ yield this.handleSelectType(calendarEventTypes[0]);
79
+ }
80
+ else {
81
+ yield this.updateEventInContext();
82
+ yield this.setupTypeSelectCard(calendarEventTypes);
83
+ }
84
+ (_d = this.calendarSelectCardVc) === null || _d === void 0 ? void 0 : _d.setIsBusy(false);
85
+ });
86
+ }
87
+ setupTypeSelectCard(types) {
88
+ var _a, _b, _c, _d, _e, _f;
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ if (!this.toolBeltVc.getTool('types')) {
91
+ this.typeSelectCardVc = this.TypeSelectCardVc();
92
+ this.toolBeltVc.addTool({
93
+ id: 'types',
94
+ lineIcon: 'calendar-add',
95
+ card: this.typeSelectCardVc.render(),
96
+ });
97
+ }
98
+ (_a = this.typeSelectCardVc) === null || _a === void 0 ? void 0 : _a.setIsBusy(true);
99
+ (_b = this.toolBeltVc) === null || _b === void 0 ? void 0 : _b.focusTool('types');
100
+ const section = yield this.renderTypeButtonsSection(types);
101
+ if (((_c = this.typeSelectCardVc) === null || _c === void 0 ? void 0 : _c.getTotalSections()) === 0) {
102
+ (_d = this.typeSelectCardVc) === null || _d === void 0 ? void 0 : _d.addSection(section);
103
+ }
104
+ else {
105
+ (_e = this.typeSelectCardVc) === null || _e === void 0 ? void 0 : _e.setSection(0, section);
106
+ }
107
+ (_f = this.typeSelectCardVc) === null || _f === void 0 ? void 0 : _f.setIsBusy(false);
108
+ });
109
+ }
110
+ renderTypeButtonsSection(calendarEventTypes) {
111
+ return __awaiter(this, void 0, void 0, function* () {
112
+ const section = {
113
+ buttons: calendarEventTypes.map((t) => ({
114
+ id: t.id,
115
+ label: t.name,
116
+ onClick: () => this.handleSelectType(t),
117
+ })),
118
+ };
119
+ return section;
120
+ });
121
+ }
122
+ handleSelectType(type) {
123
+ var _a, _b, _c;
124
+ return __awaiter(this, void 0, void 0, function* () {
125
+ (_a = this.typeSelectCardVc) === null || _a === void 0 ? void 0 : _a.setIsBusy(true);
126
+ const { event } = this.sm.getContext();
127
+ const updated = makeEventTyped(event, type);
128
+ yield this.updateEventInContext({
129
+ eventTypeSlug: type.slug,
130
+ timeBlocks: updated.timeBlocks,
131
+ });
132
+ yield ((_b = this.selectEventTypeHandler) === null || _b === void 0 ? void 0 : _b.call(this, type));
133
+ (_c = this.typeSelectCardVc) === null || _c === void 0 ? void 0 : _c.setIsBusy(false);
134
+ });
135
+ }
136
+ updateEventInContext(updates) {
137
+ var _a;
138
+ return __awaiter(this, void 0, void 0, function* () {
139
+ const { event } = this.sm.getContext();
140
+ if (event) {
141
+ yield this.sm.updateContext({
142
+ event: Object.assign(Object.assign(Object.assign({}, event), { calendarId: (_a = this.calendar) === null || _a === void 0 ? void 0 : _a.id }), updates),
143
+ });
144
+ }
145
+ });
146
+ }
147
+ TypeSelectCardVc() {
148
+ return this.sm.Controller('card', {
149
+ header: {
150
+ title: 'What do you want to add?',
151
+ },
152
+ body: {
153
+ isBusy: true,
154
+ },
155
+ });
156
+ }
157
+ getCalendarSelectCardVc() {
158
+ return this.calendarSelectCardVc;
159
+ }
160
+ getTypeSelectCardVc() {
161
+ return this.typeSelectCardVc;
162
+ }
163
+ SelectCalendarCardVc() {
164
+ return this.sm.Controller('card', {
165
+ header: {
166
+ title: 'Which calendar?',
167
+ },
168
+ body: {
169
+ isBusy: true,
170
+ },
171
+ });
172
+ }
173
+ listCalendars() {
174
+ return __awaiter(this, void 0, void 0, function* () {
175
+ const org = yield this.sm.getContext().scope.getCurrentOrganization();
176
+ const client = yield this.connectToApi();
177
+ const [{ calendars }] = yield client.emitAndFlattenResponses('calendar.list-calendars::v2021_05_19', {
178
+ target: {
179
+ organizationId: org === null || org === void 0 ? void 0 : org.id,
180
+ },
181
+ });
182
+ return calendars;
183
+ });
184
+ }
185
+ connectToApi() {
186
+ return __awaiter(this, void 0, void 0, function* () {
187
+ return yield this.sm.connectToApi();
188
+ });
189
+ }
190
+ }