@softpak/components 21.2.0-capwesome.10 → 21.2.0-capwesome.12

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.
@@ -1,27 +1,26 @@
1
1
  import * as i3 from '@ionic/angular/standalone';
2
2
  import { IonContent, IonHeader, IonToolbar, IonTitle } from '@ionic/angular/standalone';
3
- import { spxTextCheckingForUpdates, spxTextOneMomentPlease, spxTextUpdateAppVersion, spxTextUpdateBinaryVersionGroup, spxTextUpdateBuildVersion, spxTextUpdateLiveBundle, spxTextUpdateLiveChannel, spxTextUpdateStatus, spxTextUpdateVersionInfo, spxTextUpdateStatusPreparing, spxTextUpdateStatusFailed, spxTextUpdateStatusSyncing, spxTextUpdateStatusCompleted, spxTextUpdate, spxTextReadyToBeInstalled, spxTextPatchAvailable, spxTextUpdateAvailable, spxTextOpenAppStore, spxTextLiveUpdateCheckFailed } from '@softpak/components/spx-translate';
3
+ import { spxTextCheckingForUpdates, spxTextOneMomentPlease, spxTextUpdateErrorReason, spxTextUpdateAppVersion, spxTextUpdateBinaryVersionGroup, spxTextUpdateBuildVersion, spxTextUpdateLastCheck, spxTextUpdateLiveBundle, spxTextUpdateLiveChannel, spxTextUpdateStatus, spxTextUpdateVersionInfo, spxTextUpdateStatusCompleted, spxTextUpdateStatusWebNotAvailable, spxTextUpdateStatusFailed, spxTextUpdateStatusUpdateReady, spxTextUpdateStatusUpToDate, spxTextUpdateStatusReloading, spxTextUpdateStatusSyncing, spxTextUpdateStatusPreparing, spxTextUpdate, spxTextReadyToBeInstalled, spxTextPatchAvailable, spxTextUpdateAvailable, spxTextOpenAppStore, spxTextLiveUpdateCheckFailedWithReason, spxTextLiveUpdateCheckFailed } from '@softpak/components/spx-translate';
4
4
  import { App } from '@capacitor/app';
5
5
  import * as i0 from '@angular/core';
6
6
  import { signal, computed, effect, Component, HostBinding, ChangeDetectionStrategy, inject, Injectable } from '@angular/core';
7
+ import { SpxAppChannelTypeEnum } from '@softpak/components/spx-app-configuration';
7
8
  import { SpxCapitalizePipe } from '@softpak/components/spx-capitalize';
9
+ import { getBinaryVersionGroup, unsubscribeSubscriptions, SpxSeverityEnum } from '@softpak/components/spx-helpers';
8
10
  import { SpxStorage, SpxStorageKeyEnum } from '@softpak/components/spx-storage';
9
11
  import { TranslatePipe, TranslateService } from '@ngx-translate/core';
10
12
  import * as i1 from '@ngrx/store';
11
- import { createActionGroup, props, emptyProps, createFeature, createReducer, on } from '@ngrx/store';
13
+ import { createActionGroup, emptyProps, props, createFeature, createReducer, on, Store } from '@ngrx/store';
12
14
  import { DateTime } from 'luxon';
13
15
  import * as i2 from '@angular/router';
14
- import { unsubscribeSubscriptions, SpxSeverityEnum, getBinaryVersionGroup } from '@softpak/components/spx-helpers';
15
16
  import { SpxButtonComponent } from '@softpak/components/spx-button';
16
17
  import * as i2$1 from '@angular/platform-browser';
17
- import * as i1$1 from '@ngrx/effects';
18
18
  import { Actions, createEffect, ofType } from '@ngrx/effects';
19
19
  import { LiveUpdate } from '@capawesome/capacitor-live-update';
20
20
  import { spxToasterActions, SpxToasterAutoCloseSpeedEnum } from '@softpak/components/spx-toaster';
21
- import { of, from } from 'rxjs';
21
+ import { of, concat, from, timer } from 'rxjs';
22
22
  import { delay, mergeMap, exhaustMap, map, catchError, tap } from 'rxjs/operators';
23
23
  import { Capacitor } from '@capacitor/core';
24
- import { SpxAppChannelTypeEnum } from '@softpak/components/spx-app-configuration';
25
24
  import { captureMessage } from '@sentry/angular';
26
25
 
27
26
  const spxUpdateCheckActions = createActionGroup({
@@ -33,14 +32,35 @@ const spxUpdateCheckActions = createActionGroup({
33
32
  initialize: emptyProps(),
34
33
  noUpdateWasFound: props(),
35
34
  notAvailableOnWeb: emptyProps(),
35
+ reloadStarted: emptyProps(),
36
36
  runCheck: props(),
37
+ syncStarted: emptyProps(),
37
38
  },
38
39
  });
39
40
 
41
+ var SpxUpdateCheckStatusEnum;
42
+ (function (SpxUpdateCheckStatusEnum) {
43
+ SpxUpdateCheckStatusEnum["failed"] = "failed";
44
+ SpxUpdateCheckStatusEnum["idle"] = "idle";
45
+ SpxUpdateCheckStatusEnum["notAvailableOnWeb"] = "notAvailableOnWeb";
46
+ SpxUpdateCheckStatusEnum["preparing"] = "preparing";
47
+ SpxUpdateCheckStatusEnum["reloading"] = "reloading";
48
+ SpxUpdateCheckStatusEnum["syncing"] = "syncing";
49
+ SpxUpdateCheckStatusEnum["upToDate"] = "upToDate";
50
+ SpxUpdateCheckStatusEnum["updateReady"] = "updateReady";
51
+ })(SpxUpdateCheckStatusEnum || (SpxUpdateCheckStatusEnum = {}));
52
+
53
+ var spxUpdateCheck_state = /*#__PURE__*/Object.freeze({
54
+ __proto__: null,
55
+ get SpxUpdateCheckStatusEnum () { return SpxUpdateCheckStatusEnum; }
56
+ });
57
+
40
58
  const initialState$1 = {
41
59
  forceWaitForUpdate: false,
60
+ lastErrorReason: null,
42
61
  lastCheck: null,
43
62
  showError: false,
63
+ status: SpxUpdateCheckStatusEnum.idle,
44
64
  };
45
65
 
46
66
  var spxUpdateCheck_initial = /*#__PURE__*/Object.freeze({
@@ -54,35 +74,56 @@ var updCheck = createFeature({
54
74
  return {
55
75
  ...state,
56
76
  lastCheck: DateTime.now().toISO(),
77
+ lastErrorReason: null,
57
78
  showError: false,
79
+ status: SpxUpdateCheckStatusEnum.updateReady,
58
80
  };
59
81
  }), on(spxUpdateCheckActions.clearError, (state) => {
60
82
  return {
61
83
  ...state,
84
+ lastErrorReason: null,
62
85
  showError: false,
63
86
  };
64
- }), on(spxUpdateCheckActions.checkFailed, (state) => {
87
+ }), on(spxUpdateCheckActions.checkFailed, (state, { errorReason }) => {
65
88
  return {
66
89
  ...state,
67
90
  forceWaitForUpdate: false,
91
+ lastErrorReason: errorReason || null,
68
92
  showError: true,
93
+ status: SpxUpdateCheckStatusEnum.failed,
69
94
  };
70
95
  }), on(spxUpdateCheckActions.noUpdateWasFound, (state) => {
71
96
  return {
72
97
  ...state,
73
98
  forceWaitForUpdate: false,
74
99
  lastCheck: DateTime.now().toISO(),
100
+ lastErrorReason: null,
75
101
  showError: false,
102
+ status: SpxUpdateCheckStatusEnum.upToDate,
76
103
  };
77
104
  }), on(spxUpdateCheckActions.runCheck, (state, { forceWaitForUpdate }) => {
78
105
  return {
79
106
  ...state,
80
- forceWaitForUpdate: forceWaitForUpdate ? true : state.forceWaitForUpdate
107
+ forceWaitForUpdate: forceWaitForUpdate ? true : state.forceWaitForUpdate,
108
+ lastErrorReason: null,
109
+ showError: false,
110
+ status: SpxUpdateCheckStatusEnum.preparing,
111
+ };
112
+ }), on(spxUpdateCheckActions.syncStarted, (state) => {
113
+ return {
114
+ ...state,
115
+ status: SpxUpdateCheckStatusEnum.syncing,
116
+ };
117
+ }), on(spxUpdateCheckActions.reloadStarted, (state) => {
118
+ return {
119
+ ...state,
120
+ status: SpxUpdateCheckStatusEnum.reloading,
81
121
  };
82
122
  }), on(spxUpdateCheckActions.notAvailableOnWeb, (state) => {
83
123
  return {
84
124
  ...state,
85
- forceWaitForUpdate: false
125
+ forceWaitForUpdate: false,
126
+ status: SpxUpdateCheckStatusEnum.notAvailableOnWeb,
86
127
  };
87
128
  })),
88
129
  });
@@ -93,11 +134,15 @@ var spxUpdateCheck_reducer = /*#__PURE__*/Object.freeze({
93
134
  });
94
135
 
95
136
  class SpxUpdatePageComponent {
137
+ static { this.SUCCESS_CLOSE_DELAY_MS = 5000; }
96
138
  ngOnInit() {
97
139
  this.hasStarted.set(true);
98
140
  void this.loadVersionInfo();
99
141
  this.appStore.dispatch(spxUpdateCheckActions.runCheck({ forceWaitForUpdate: true }));
100
142
  }
143
+ ngOnDestroy() {
144
+ this.clearScheduledClose();
145
+ }
101
146
  constructor(appStore, activatedRoute, navController) {
102
147
  this.appStore = appStore;
103
148
  this.activatedRoute = activatedRoute;
@@ -105,52 +150,139 @@ class SpxUpdatePageComponent {
105
150
  this.appVersion = signal('-', ...(ngDevMode ? [{ debugName: "appVersion" }] : []));
106
151
  this.binaryVersionGroup = signal('-', ...(ngDevMode ? [{ debugName: "binaryVersionGroup" }] : []));
107
152
  this.buildVersion = signal('-', ...(ngDevMode ? [{ debugName: "buildVersion" }] : []));
108
- this.forceWaitForUpdate = this.appStore.selectSignal(updCheck.selectForceWaitForUpdate);
153
+ this.lastCheck = this.appStore.selectSignal(updCheck.selectLastCheck);
154
+ this.lastErrorReason = this.appStore.selectSignal(updCheck.selectLastErrorReason);
109
155
  this.hasStarted = signal(false, ...(ngDevMode ? [{ debugName: "hasStarted" }] : []));
156
+ this.hasNavigatedAway = signal(false, ...(ngDevMode ? [{ debugName: "hasNavigatedAway" }] : []));
110
157
  this.liveBundle = signal('-', ...(ngDevMode ? [{ debugName: "liveBundle" }] : []));
111
158
  this.liveUpdateChannel = signal('-', ...(ngDevMode ? [{ debugName: "liveUpdateChannel" }] : []));
159
+ this.status = this.appStore.selectSignal(updCheck.selectStatus);
160
+ this.closeTimerId = null;
112
161
  this.spxTextCheckingForUpdates = spxTextCheckingForUpdates;
113
162
  this.spxTextOneMomentPlease = spxTextOneMomentPlease;
163
+ this.spxTextUpdateErrorReason = spxTextUpdateErrorReason;
114
164
  this.spxTextUpdateAppVersion = spxTextUpdateAppVersion;
115
165
  this.spxTextUpdateBinaryVersionGroup = spxTextUpdateBinaryVersionGroup;
116
166
  this.spxTextUpdateBuildVersion = spxTextUpdateBuildVersion;
167
+ this.spxTextUpdateLastCheck = spxTextUpdateLastCheck;
117
168
  this.spxTextUpdateLiveBundle = spxTextUpdateLiveBundle;
118
169
  this.spxTextUpdateLiveChannel = spxTextUpdateLiveChannel;
119
170
  this.spxTextUpdateStatus = spxTextUpdateStatus;
120
171
  this.spxTextUpdateVersionInfo = spxTextUpdateVersionInfo;
121
172
  this.statusText = computed(() => {
122
- if (!this.hasStarted()) {
123
- return spxTextUpdateStatusPreparing;
124
- }
125
- if (this.showError()) {
126
- return spxTextUpdateStatusFailed;
173
+ switch (this.status()) {
174
+ case SpxUpdateCheckStatusEnum.idle:
175
+ return spxTextUpdateStatusPreparing;
176
+ case SpxUpdateCheckStatusEnum.preparing:
177
+ return spxTextUpdateStatusPreparing;
178
+ case SpxUpdateCheckStatusEnum.syncing:
179
+ return spxTextUpdateStatusSyncing;
180
+ case SpxUpdateCheckStatusEnum.reloading:
181
+ return spxTextUpdateStatusReloading;
182
+ case SpxUpdateCheckStatusEnum.upToDate:
183
+ return spxTextUpdateStatusUpToDate;
184
+ case SpxUpdateCheckStatusEnum.updateReady:
185
+ return spxTextUpdateStatusUpdateReady;
186
+ case SpxUpdateCheckStatusEnum.failed:
187
+ return spxTextUpdateStatusFailed;
188
+ case SpxUpdateCheckStatusEnum.notAvailableOnWeb:
189
+ return spxTextUpdateStatusWebNotAvailable;
190
+ default:
191
+ return spxTextUpdateStatusCompleted;
127
192
  }
128
- if (this.forceWaitForUpdate()) {
129
- return spxTextUpdateStatusSyncing;
130
- }
131
- return spxTextUpdateStatusCompleted;
132
193
  }, ...(ngDevMode ? [{ debugName: "statusText" }] : []));
133
- this.showError = this.appStore.selectSignal(updCheck.selectShowError);
134
194
  effect(() => {
135
- if (!this.hasStarted() || this.forceWaitForUpdate()) {
195
+ this.status();
196
+ this.refreshStorageVersionInfo();
197
+ });
198
+ effect(() => {
199
+ const status = this.status();
200
+ if (!this.hasStarted() || this.hasNavigatedAway()) {
136
201
  return;
137
202
  }
138
- if (this.activatedRoute.snapshot.data['url'] === undefined) {
203
+ if (!this.shouldCloseUpdatePage(status)) {
204
+ this.clearScheduledClose();
205
+ return;
206
+ }
207
+ const targetUrl = this.activatedRoute.snapshot.data['url'];
208
+ if (targetUrl === undefined) {
139
209
  console.error('configure data property \'url\' in route for update page');
210
+ return;
211
+ }
212
+ const closeDelayMs = this.getCloseDelayMs(status);
213
+ if (closeDelayMs === 0) {
214
+ this.clearScheduledClose();
215
+ this.navigateAway(targetUrl);
216
+ return;
217
+ }
218
+ if (this.closeTimerId !== null) {
219
+ return;
140
220
  }
141
- this.navController.navigateRoot(this.activatedRoute.snapshot.data['url']);
221
+ this.closeTimerId = setTimeout(() => {
222
+ this.closeTimerId = null;
223
+ this.navigateAway(targetUrl);
224
+ }, closeDelayMs);
142
225
  });
143
226
  }
227
+ shouldCloseUpdatePage(status) {
228
+ return status === SpxUpdateCheckStatusEnum.upToDate ||
229
+ status === SpxUpdateCheckStatusEnum.failed ||
230
+ status === SpxUpdateCheckStatusEnum.notAvailableOnWeb ||
231
+ status === SpxUpdateCheckStatusEnum.updateReady;
232
+ }
233
+ getCloseDelayMs(status) {
234
+ if (status === SpxUpdateCheckStatusEnum.upToDate || status === SpxUpdateCheckStatusEnum.updateReady) {
235
+ return SpxUpdatePageComponent.SUCCESS_CLOSE_DELAY_MS;
236
+ }
237
+ return 0;
238
+ }
239
+ clearScheduledClose() {
240
+ if (this.closeTimerId === null) {
241
+ return;
242
+ }
243
+ clearTimeout(this.closeTimerId);
244
+ this.closeTimerId = null;
245
+ }
246
+ navigateAway(targetUrl) {
247
+ if (this.hasNavigatedAway()) {
248
+ return;
249
+ }
250
+ this.hasNavigatedAway.set(true);
251
+ this.navController.navigateRoot(targetUrl);
252
+ }
144
253
  async loadVersionInfo() {
145
254
  const appInfo = await App.getInfo();
146
- this.appVersion.set(appInfo.version || '-');
255
+ const appVersion = appInfo.version || '-';
256
+ this.appVersion.set(appVersion);
147
257
  this.buildVersion.set(appInfo.build || '-');
148
- this.binaryVersionGroup.set(SpxStorage.getSetting(SpxStorageKeyEnum.binaryVersionGroup) || '-');
149
- this.liveUpdateChannel.set(SpxStorage.getSetting(SpxStorageKeyEnum.liveUpdateChannel) || '-');
150
- this.liveBundle.set(SpxStorage.getSetting(SpxStorageKeyEnum.liveUpdate) || '-');
258
+ try {
259
+ const computedBinaryVersionGroup = `${getBinaryVersionGroup(appVersion)}.x`;
260
+ const storedBinaryVersionGroup = SpxStorage.getSetting(SpxStorageKeyEnum.binaryVersionGroup);
261
+ this.binaryVersionGroup.set(storedBinaryVersionGroup || computedBinaryVersionGroup);
262
+ const storedLiveUpdateChannel = SpxStorage.getSetting(SpxStorageKeyEnum.liveUpdateChannel);
263
+ const channelType = SpxStorage.getSetting(SpxStorageKeyEnum.channelType) || SpxAppChannelTypeEnum.production;
264
+ this.liveUpdateChannel.set(storedLiveUpdateChannel || `${channelType}-${computedBinaryVersionGroup}`);
265
+ }
266
+ catch {
267
+ this.binaryVersionGroup.set(SpxStorage.getSetting(SpxStorageKeyEnum.binaryVersionGroup) || '-');
268
+ this.liveUpdateChannel.set(SpxStorage.getSetting(SpxStorageKeyEnum.liveUpdateChannel) || '-');
269
+ }
270
+ this.refreshStorageVersionInfo();
271
+ }
272
+ refreshStorageVersionInfo() {
273
+ const storedBinaryVersionGroup = SpxStorage.getSetting(SpxStorageKeyEnum.binaryVersionGroup);
274
+ const storedLiveUpdateChannel = SpxStorage.getSetting(SpxStorageKeyEnum.liveUpdateChannel);
275
+ const storedLiveBundle = SpxStorage.getSetting(SpxStorageKeyEnum.liveUpdate);
276
+ if (storedBinaryVersionGroup) {
277
+ this.binaryVersionGroup.set(storedBinaryVersionGroup);
278
+ }
279
+ if (storedLiveUpdateChannel) {
280
+ this.liveUpdateChannel.set(storedLiveUpdateChannel);
281
+ }
282
+ this.liveBundle.set(storedLiveBundle || '-');
151
283
  }
152
284
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SpxUpdatePageComponent, deps: [{ token: i1.Store }, { token: i2.ActivatedRoute }, { token: i3.NavController }], target: i0.ɵɵFactoryTarget.Component }); }
153
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.0", type: SpxUpdatePageComponent, isStandalone: true, selector: "spx-update-page", ngImport: i0, template: "<ion-header>\n <ion-toolbar>\n <ion-title>\n {{ spxTextCheckingForUpdates | translate | capitalize }}\n </ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <p>{{ spxTextOneMomentPlease | translate | capitalize }}...</p>\n <p class=\"mt-2\">\n <strong>{{ spxTextUpdateStatus | translate | capitalize }}:</strong>\n {{ statusText() | translate | capitalize }}\n </p>\n\n <div class=\"mt-6 text-sm text-zinc-600\">\n <p><strong>{{ spxTextUpdateVersionInfo | translate | capitalize }}</strong></p>\n <p>{{ spxTextUpdateAppVersion | translate | capitalize }}: {{ appVersion() }}</p>\n <p>{{ spxTextUpdateBuildVersion | translate | capitalize }}: {{ buildVersion() }}</p>\n <p>{{ spxTextUpdateBinaryVersionGroup | translate | capitalize }}: {{ binaryVersionGroup() }}</p>\n <p>{{ spxTextUpdateLiveChannel | translate | capitalize }}: {{ liveUpdateChannel() }}</p>\n <p>{{ spxTextUpdateLiveBundle | translate | capitalize }}: {{ liveBundle() }}</p>\n </div>\n</ion-content>\n", dependencies: [{ kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "pipe", type: SpxCapitalizePipe, name: "capitalize" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
285
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: SpxUpdatePageComponent, isStandalone: true, selector: "spx-update-page", ngImport: i0, template: "<ion-header>\n <ion-toolbar>\n <ion-title>\n {{ spxTextCheckingForUpdates | translate | capitalize }}\n </ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <p>{{ spxTextOneMomentPlease | translate | capitalize }}...</p>\n <p class=\"mt-2\">\n <strong>{{ spxTextUpdateStatus | translate | capitalize }}:</strong>\n {{ statusText() | translate | capitalize }}\n </p>\n @if (lastErrorReason()) {\n <p class=\"mt-2 text-red-700\">\n <strong>{{ spxTextUpdateErrorReason | translate | capitalize }}:</strong>\n {{ lastErrorReason() }}\n </p>\n }\n @if (lastCheck()) {\n <p class=\"mt-1 text-sm text-zinc-600\">\n <strong>{{ spxTextUpdateLastCheck | translate | capitalize }}:</strong>\n {{ lastCheck() }}\n </p>\n }\n\n <div class=\"mt-6 text-sm text-zinc-600\">\n <p><strong>{{ spxTextUpdateVersionInfo | translate | capitalize }}</strong></p>\n <p>{{ spxTextUpdateAppVersion | translate | capitalize }}: {{ appVersion() }}</p>\n <p>{{ spxTextUpdateBuildVersion | translate | capitalize }}: {{ buildVersion() }}</p>\n <p>{{ spxTextUpdateBinaryVersionGroup | translate | capitalize }}: {{ binaryVersionGroup() }}</p>\n <p>{{ spxTextUpdateLiveChannel | translate | capitalize }}: {{ liveUpdateChannel() }}</p>\n <p>{{ spxTextUpdateLiveBundle | translate | capitalize }}: {{ liveBundle() }}</p>\n </div>\n</ion-content>\n", dependencies: [{ kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "pipe", type: SpxCapitalizePipe, name: "capitalize" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
154
286
  }
155
287
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: SpxUpdatePageComponent, decorators: [{
156
288
  type: Component,
@@ -161,7 +293,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
161
293
  IonTitle,
162
294
  SpxCapitalizePipe,
163
295
  TranslatePipe,
164
- ], standalone: true, template: "<ion-header>\n <ion-toolbar>\n <ion-title>\n {{ spxTextCheckingForUpdates | translate | capitalize }}\n </ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <p>{{ spxTextOneMomentPlease | translate | capitalize }}...</p>\n <p class=\"mt-2\">\n <strong>{{ spxTextUpdateStatus | translate | capitalize }}:</strong>\n {{ statusText() | translate | capitalize }}\n </p>\n\n <div class=\"mt-6 text-sm text-zinc-600\">\n <p><strong>{{ spxTextUpdateVersionInfo | translate | capitalize }}</strong></p>\n <p>{{ spxTextUpdateAppVersion | translate | capitalize }}: {{ appVersion() }}</p>\n <p>{{ spxTextUpdateBuildVersion | translate | capitalize }}: {{ buildVersion() }}</p>\n <p>{{ spxTextUpdateBinaryVersionGroup | translate | capitalize }}: {{ binaryVersionGroup() }}</p>\n <p>{{ spxTextUpdateLiveChannel | translate | capitalize }}: {{ liveUpdateChannel() }}</p>\n <p>{{ spxTextUpdateLiveBundle | translate | capitalize }}: {{ liveBundle() }}</p>\n </div>\n</ion-content>\n" }]
296
+ ], standalone: true, template: "<ion-header>\n <ion-toolbar>\n <ion-title>\n {{ spxTextCheckingForUpdates | translate | capitalize }}\n </ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <p>{{ spxTextOneMomentPlease | translate | capitalize }}...</p>\n <p class=\"mt-2\">\n <strong>{{ spxTextUpdateStatus | translate | capitalize }}:</strong>\n {{ statusText() | translate | capitalize }}\n </p>\n @if (lastErrorReason()) {\n <p class=\"mt-2 text-red-700\">\n <strong>{{ spxTextUpdateErrorReason | translate | capitalize }}:</strong>\n {{ lastErrorReason() }}\n </p>\n }\n @if (lastCheck()) {\n <p class=\"mt-1 text-sm text-zinc-600\">\n <strong>{{ spxTextUpdateLastCheck | translate | capitalize }}:</strong>\n {{ lastCheck() }}\n </p>\n }\n\n <div class=\"mt-6 text-sm text-zinc-600\">\n <p><strong>{{ spxTextUpdateVersionInfo | translate | capitalize }}</strong></p>\n <p>{{ spxTextUpdateAppVersion | translate | capitalize }}: {{ appVersion() }}</p>\n <p>{{ spxTextUpdateBuildVersion | translate | capitalize }}: {{ buildVersion() }}</p>\n <p>{{ spxTextUpdateBinaryVersionGroup | translate | capitalize }}: {{ binaryVersionGroup() }}</p>\n <p>{{ spxTextUpdateLiveChannel | translate | capitalize }}: {{ liveUpdateChannel() }}</p>\n <p>{{ spxTextUpdateLiveBundle | translate | capitalize }}: {{ liveBundle() }}</p>\n </div>\n</ion-content>\n" }]
165
297
  }], ctorParameters: () => [{ type: i1.Store }, { type: i2.ActivatedRoute }, { type: i3.NavController }] });
166
298
 
167
299
  const SpxUpdatePendingActions = createActionGroup({
@@ -277,10 +409,10 @@ let Effects$1 = class Effects {
277
409
  if (Capacitor.getPlatform() === 'web') {
278
410
  return of(spxUpdateCheckActions.notAvailableOnWeb());
279
411
  }
280
- return from(App.getInfo()).pipe(mergeMap((binaryInfo) => {
412
+ return concat(of(spxUpdateCheckActions.syncStarted()), from(App.getInfo()).pipe(mergeMap((binaryInfo) => {
281
413
  // Migrate from e.g. 1.2.x to 1.3.x
282
414
  const binaryVersionGroup = getBinaryVersionGroup(binaryInfo.version);
283
- let channelType = SpxStorage.getSetting(SpxStorageKeyEnum.channelType);
415
+ const channelType = SpxStorage.getSetting(SpxStorageKeyEnum.channelType);
284
416
  if (SpxStorage.getSetting(SpxStorageKeyEnum.binaryVersionGroup)) {
285
417
  SpxStorage.setSetting(SpxStorageKeyEnum.lastBinaryVersionGroup, SpxStorage.getSetting(SpxStorageKeyEnum.binaryVersionGroup));
286
418
  }
@@ -288,21 +420,35 @@ let Effects$1 = class Effects {
288
420
  SpxStorage.setSetting(SpxStorageKeyEnum.liveUpdateChannel, `${channelType ? channelType : SpxAppChannelTypeEnum.production}-${binaryVersionGroup}.x`);
289
421
  // End migrate from e.g. 1.2.x to 1.3.x
290
422
  return from(LiveUpdate.sync({ channel: SpxStorage.getSetting(SpxStorageKeyEnum.liveUpdateChannel) }));
291
- }), map((syncResult) => {
423
+ }), mergeMap((syncResult) => {
292
424
  if (syncResult.nextBundleId) {
425
+ SpxStorage.setSetting(SpxStorageKeyEnum.liveUpdate, syncResult.nextBundleId);
293
426
  if (action.forceWaitForUpdate) {
294
- SpxStorage.setSetting(SpxStorageKeyEnum.liveUpdate, syncResult.nextBundleId);
295
- LiveUpdate.reload();
427
+ return concat(of(spxUpdateCheckActions.reloadStarted()), from(LiveUpdate.reload()).pipe(map(() => spxUpdateCheckActions.anUpdateIsReady()), catchError((err) => {
428
+ const errorReason = this.getReadableErrorReason(err);
429
+ captureMessage(`[UPD] Reload failed: ${errorReason}`);
430
+ return of(spxUpdateCheckActions.checkFailed({
431
+ errorReason,
432
+ startUpdateAgainAfterTimeout: false,
433
+ }));
434
+ })));
296
435
  }
297
- return spxUpdateCheckActions.anUpdateIsReady();
436
+ return of(spxUpdateCheckActions.anUpdateIsReady());
298
437
  }
299
438
  else {
300
- return spxUpdateCheckActions.noUpdateWasFound({ startUpdateAgainAfterTimeout: !action.forceWaitForUpdate });
439
+ return of(spxUpdateCheckActions.noUpdateWasFound({ startUpdateAgainAfterTimeout: !action.forceWaitForUpdate }));
301
440
  }
302
441
  }), catchError((err) => {
303
- captureMessage("[UPD] Handled: " + err.message);
304
- return of(spxUpdateCheckActions.checkFailed({ startUpdateAgainAfterTimeout: !action.forceWaitForUpdate }));
305
- }));
442
+ const errorReason = this.getReadableErrorReason(err);
443
+ if (this.isSyncAlreadyInProgress(errorReason)) {
444
+ return timer(1500).pipe(map(() => spxUpdateCheckActions.runCheck({ forceWaitForUpdate: action.forceWaitForUpdate })));
445
+ }
446
+ captureMessage(`[UPD] Handled: ${errorReason}`);
447
+ return of(spxUpdateCheckActions.checkFailed({
448
+ errorReason,
449
+ startUpdateAgainAfterTimeout: false,
450
+ }));
451
+ })));
306
452
  })));
307
453
  this.whenAndUpdateIsReady$ = createEffect(() => this.actions$.pipe(ofType(spxUpdateCheckActions.anUpdateIsReady), mergeMap(() => [
308
454
  SpxUpdatePendingActions.hasBeenDownloaded(),
@@ -310,14 +456,44 @@ let Effects$1 = class Effects {
310
456
  this.whenCheckHasFailed$ = createEffect(() => this.actions$.pipe(ofType(spxUpdateCheckActions.checkFailed), delay(30000), mergeMap((action) => !action.startUpdateAgainAfterTimeout ? [] : [
311
457
  spxUpdateCheckActions.runCheck({}),
312
458
  ])));
313
- this.whenCheckHasFailedShowError$ = createEffect(() => this.actions$.pipe(ofType(spxUpdateCheckActions.checkFailed), map(() => spxToasterActions.createError({
459
+ this.whenCheckHasFailedShowError$ = createEffect(() => this.actions$.pipe(ofType(spxUpdateCheckActions.checkFailed), map((action) => spxToasterActions.createError({
314
460
  autoClose: SpxToasterAutoCloseSpeedEnum.DEFAULT,
315
- messageText: this.translateService.instant(spxTextLiveUpdateCheckFailed),
461
+ messageText: action.errorReason
462
+ ? this.translateService.instant(spxTextLiveUpdateCheckFailedWithReason, { reason: action.errorReason })
463
+ : this.translateService.instant(spxTextLiveUpdateCheckFailed),
316
464
  }))));
317
465
  this.whenNoUpdateWasFound$ = createEffect(() => this.actions$.pipe(ofType(spxUpdateCheckActions.noUpdateWasFound), delay(120000), mergeMap((action) => !action.startUpdateAgainAfterTimeout ? [] : [
318
466
  spxUpdateCheckActions.runCheck({}),
319
467
  ])));
320
468
  }
469
+ getReadableErrorReason(err) {
470
+ if (err instanceof Error && err.message?.trim()) {
471
+ return err.message.trim();
472
+ }
473
+ if (typeof err === 'string' && err.trim()) {
474
+ return err.trim();
475
+ }
476
+ if (err && typeof err === 'object') {
477
+ const withMessage = err;
478
+ if (typeof withMessage.message === 'string' && withMessage.message.trim()) {
479
+ return withMessage.message.trim();
480
+ }
481
+ try {
482
+ const serialized = JSON.stringify(err);
483
+ if (serialized && serialized !== '{}') {
484
+ return serialized.length > 180 ? `${serialized.slice(0, 177)}...` : serialized;
485
+ }
486
+ }
487
+ catch {
488
+ // ignore serialization errors
489
+ }
490
+ }
491
+ return '';
492
+ }
493
+ isSyncAlreadyInProgress(errorReason) {
494
+ const normalized = errorReason.toLowerCase();
495
+ return normalized.includes('sync is already in progress');
496
+ }
321
497
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: Effects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
322
498
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: Effects }); }
323
499
  };
@@ -330,23 +506,54 @@ var spxUpdateCheck_effects = /*#__PURE__*/Object.freeze({
330
506
  Effects: Effects$1
331
507
  });
332
508
 
333
- var spxUpdateCheck_state = /*#__PURE__*/Object.freeze({
334
- __proto__: null
335
- });
336
-
337
509
  class Effects {
338
- constructor(actions$) {
339
- this.actions$ = actions$;
510
+ constructor() {
511
+ this.actions$ = inject(Actions);
512
+ this.appStore = inject(Store);
513
+ this.translateService = inject(TranslateService);
340
514
  this.whenAccepted$ = createEffect(() => this.actions$.pipe(ofType(SpxUpdatePendingActions.acceptUpdate), tap(() => {
341
- void LiveUpdate.reload();
515
+ void LiveUpdate.reload().catch((err) => {
516
+ const errorReason = this.getReadableErrorReason(err);
517
+ captureMessage(`[UPD] Accept reload failed: ${errorReason}`);
518
+ this.appStore.dispatch(spxToasterActions.createError({
519
+ autoClose: SpxToasterAutoCloseSpeedEnum.DEFAULT,
520
+ messageText: errorReason
521
+ ? this.translateService.instant(spxTextLiveUpdateCheckFailedWithReason, { reason: errorReason })
522
+ : this.translateService.instant(spxTextLiveUpdateCheckFailed),
523
+ }));
524
+ });
342
525
  })), { dispatch: false });
343
526
  }
344
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: Effects, deps: [{ token: i1$1.Actions }], target: i0.ɵɵFactoryTarget.Injectable }); }
527
+ getReadableErrorReason(err) {
528
+ if (err instanceof Error && err.message?.trim()) {
529
+ return err.message.trim();
530
+ }
531
+ if (typeof err === 'string' && err.trim()) {
532
+ return err.trim();
533
+ }
534
+ if (err && typeof err === 'object') {
535
+ const withMessage = err;
536
+ if (typeof withMessage.message === 'string' && withMessage.message.trim()) {
537
+ return withMessage.message.trim();
538
+ }
539
+ try {
540
+ const serialized = JSON.stringify(err);
541
+ if (serialized && serialized !== '{}') {
542
+ return serialized.length > 180 ? `${serialized.slice(0, 177)}...` : serialized;
543
+ }
544
+ }
545
+ catch {
546
+ // ignore serialization errors
547
+ }
548
+ }
549
+ return '';
550
+ }
551
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: Effects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
345
552
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: Effects }); }
346
553
  }
347
554
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: Effects, decorators: [{
348
555
  type: Injectable
349
- }], ctorParameters: () => [{ type: i1$1.Actions }] });
556
+ }] });
350
557
 
351
558
  var spxUpdatePending_effects = /*#__PURE__*/Object.freeze({
352
559
  __proto__: null,