@colijnit/product 258.1.4 → 258.1.6

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,10 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Directive, Injectable, EventEmitter, Component, ViewEncapsulation, Input, Output, Renderer2, ChangeDetectorRef, ViewChild, ElementRef, Pipe, NgModule, ChangeDetectionStrategy, HostListener, HostBinding, SecurityContext, CUSTOM_ELEMENTS_SCHEMA, Inject, PLATFORM_ID, NO_ERRORS_SCHEMA } from '@angular/core';
3
3
  import { __awaiter } from 'tslib';
4
- import { Subject, BehaviorSubject } from 'rxjs';
5
- import * as i1 from '@angular/common/http';
6
- import { HttpClient } from '@angular/common/http';
7
- import { StringUtils } from '@colijnit/ioneconnector/build/utils/string-utils';
4
+ import { Subject, BehaviorSubject, combineLatest } from 'rxjs';
8
5
  import { Options } from '@colijnit/ioneconnector/build/model/options';
9
6
  import { ArticleFullObject } from '@colijnit/articleapi/build/model/article-full-object';
10
7
  import { SuperArticle } from '@colijnit/articleapi/build/model/super-article';
@@ -16,6 +13,9 @@ import { Transaction } from '@colijnit/transactionapi/build/transaction';
16
13
  import { MainApi } from '@colijnit/mainapi';
17
14
  import { TransactionInfoResponse } from '@colijnit/transactionapi/build/model/transaction-info-response.bo';
18
15
  import { ArticleListObjectExtended } from '@colijnit/articleapi/build/model/article-list-object-extended.bo';
16
+ import * as i1 from '@angular/common/http';
17
+ import { HttpClient } from '@angular/common/http';
18
+ import { StringUtils } from '@colijnit/ioneconnector/build/utils/string-utils';
19
19
  import { CommonModule, isPlatformBrowser } from '@angular/common';
20
20
  import { trigger, state, style, transition, animate } from '@angular/animations';
21
21
  import * as i1$1 from '@angular/platform-browser';
@@ -30,8 +30,48 @@ class Version {
30
30
  constructor() {
31
31
  this.name = "@colijnit/product";
32
32
  this.description = "Product detail page project for iOne";
33
- this.symVer = "258.1.4";
34
- this.publishDate = "23-6-2025 16:38:29";
33
+ this.symVer = "258.1.6";
34
+ this.publishDate = "22-8-2025 14:23:38";
35
+ }
36
+ }
37
+
38
+ class SettingsOptions {
39
+ constructor() {
40
+ this.showStockStatus = false;
41
+ this.showZoomButton = false;
42
+ this.showTagFilter = false;
43
+ this.showAsConfigured = false;
44
+ this.inlineAnswers = false;
45
+ this.showArButton = false;
46
+ this.arEnabled = false;
47
+ this.vrEnabled = false;
48
+ }
49
+ }
50
+
51
+ var RenderModes;
52
+ (function (RenderModes) {
53
+ RenderModes["RenderRoom"] = "render_room";
54
+ RenderModes["RenderShop"] = "render_shop";
55
+ RenderModes["RenderIone"] = "render_ione";
56
+ })(RenderModes || (RenderModes = {}));
57
+
58
+ class RenderParameters$1 {
59
+ constructor() {
60
+ this.host = "";
61
+ this.port = 0;
62
+ this.secure = false;
63
+ this.renderMode = RenderModes.RenderShop;
64
+ }
65
+ }
66
+
67
+ class ProductSettings extends Options {
68
+ constructor() {
69
+ super(...arguments);
70
+ this.session = undefined;
71
+ this.createWebOrder = true;
72
+ this.currencySymbol = '€';
73
+ this.options = new SettingsOptions();
74
+ this.renderParameters = new RenderParameters$1();
35
75
  }
36
76
  }
37
77
 
@@ -60,6 +100,180 @@ ProductEventService.decorators = [
60
100
  { type: Injectable }
61
101
  ];
62
102
 
103
+ // Sole responsibility is simply to wrap around a colijn.Connector to create a stable inner interface to the library in a 1:1 method way.
104
+ // Only to be used by the IOneControllerService.
105
+ class ProductConnectorAdapterService {
106
+ constructor(_eventService) {
107
+ this._eventService = _eventService;
108
+ this.showLoader = new Subject();
109
+ this._boFactory = new BusinessObjectFactory();
110
+ this._subs = [];
111
+ }
112
+ ngOnDestroy() {
113
+ this._subs.forEach(s => s.unsubscribe());
114
+ }
115
+ initConnector(options) {
116
+ return __awaiter(this, void 0, void 0, function* () {
117
+ this.articleConnector = new Articles(options);
118
+ yield this.articleConnector.connect();
119
+ this.transactionConnector = new Transaction(options);
120
+ this._subs.push(
121
+ // @ts-ignore
122
+ this.articleConnector.showLoader.subscribe(value => this.showLoader.next(value)));
123
+ });
124
+ }
125
+ setInstance(instanceId) {
126
+ // this.articleConnector.setInstanceToConfigure(instanceId, false);
127
+ }
128
+ getProductBundleSettings(url, upId) {
129
+ return __awaiter(this, void 0, void 0, function* () {
130
+ const tempSettings = new ProductSettings();
131
+ tempSettings.url = url;
132
+ tempSettings.schema = upId.toString();
133
+ const tempMainConnector = new MainApi(tempSettings);
134
+ const response = yield tempMainConnector.getPublicParams(upId);
135
+ if (response) {
136
+ return response.productSettings;
137
+ }
138
+ return "";
139
+ });
140
+ }
141
+ convertArticleFullObjectToArticleExtended(article) {
142
+ if (article) {
143
+ return this._boFactory.makeWithRawBackendData(ArticleListObjectExtended, article);
144
+ }
145
+ }
146
+ getDeliveryPrognosis(goodId, branchNr) {
147
+ return __awaiter(this, void 0, void 0, function* () {
148
+ const deliveryPrognosis = yield this.getSelectorDeliveryDate();
149
+ if (!deliveryPrognosis || !deliveryPrognosis.returnValue) {
150
+ return this.getDeliveryDate2(goodId);
151
+ }
152
+ return deliveryPrognosis;
153
+ });
154
+ }
155
+ getSelectorDeliveryDate() {
156
+ return __awaiter(this, void 0, void 0, function* () {
157
+ const response = yield this.articleConnector.getSelectorDeliveryDate();
158
+ if (response && response.validationResult && response.validationResult.success) {
159
+ return this._boFactory.makeWithRawBackendData(DeliveryPrognosis, response.resultObject);
160
+ }
161
+ else {
162
+ return null;
163
+ }
164
+ });
165
+ }
166
+ getArtStockStatus(goodId) {
167
+ return __awaiter(this, void 0, void 0, function* () {
168
+ const response = yield this.articleConnector.getArtStockStatus(goodId);
169
+ if (response && response.validationResult && response.validationResult.success) {
170
+ return response.resultObject;
171
+ }
172
+ else {
173
+ return null;
174
+ }
175
+ });
176
+ }
177
+ getDeliveryDate2(goodId) {
178
+ return __awaiter(this, void 0, void 0, function* () {
179
+ const response = yield this.articleConnector.getDeliveryDate2(goodId);
180
+ if (response && response.validationResult && response.validationResult.success) {
181
+ return this._boFactory.makeWithRawBackendData(DeliveryPrognosis, response.resultObject);
182
+ }
183
+ else {
184
+ return null;
185
+ }
186
+ });
187
+ }
188
+ getJsonConfiguredArticles(configuratorStatistics) {
189
+ return __awaiter(this, void 0, void 0, function* () {
190
+ const response = yield this.articleConnector.getJsonConfiguredArticles(configuratorStatistics);
191
+ if (response && response.validationResult && response.validationResult.success) {
192
+ return response.resultObject;
193
+ }
194
+ else {
195
+ return '';
196
+ }
197
+ });
198
+ }
199
+ getJsonArticleFlatTree(goodId, goodType, quantity, externalSource = false, showLoader = true, instanceId, configuratorStatistics) {
200
+ return __awaiter(this, void 0, void 0, function* () {
201
+ return this.articleConnector.getJsonArticleFlatTree(goodId, goodType, quantity, externalSource, showLoader, instanceId, configuratorStatistics).catch((messages) => {
202
+ this._eventService.errorMessage.next(messages);
203
+ return null;
204
+ });
205
+ });
206
+ }
207
+ getGeneratedArtDirectly(goodId, showLoader) {
208
+ return __awaiter(this, void 0, void 0, function* () {
209
+ return this.articleConnector.getGeneratedArtDirectly(goodId, showLoader).catch((messages) => {
210
+ this._eventService.errorMessage.next(messages);
211
+ return null;
212
+ });
213
+ });
214
+ }
215
+ getGoodIdFromArticleNr(sku) {
216
+ return __awaiter(this, void 0, void 0, function* () {
217
+ const response = yield this.articleConnector.getGoodIdFromArticleNr(sku);
218
+ if (response && response.validationResult && response.validationResult.success) {
219
+ return response.resultObject;
220
+ }
221
+ else {
222
+ return null;
223
+ }
224
+ });
225
+ }
226
+ getArticleFullObject(goodId, showLoader = true) {
227
+ return __awaiter(this, void 0, void 0, function* () {
228
+ const response = yield this.articleConnector.getArticleFullObject(goodId, showLoader);
229
+ if (response && response.validationResult && response.validationResult.success) {
230
+ return this._boFactory.makeWithRawBackendData(ArticleFullObject, response.resultObject);
231
+ }
232
+ else {
233
+ return null;
234
+ }
235
+ });
236
+ }
237
+ getSuperArticle(id, branch) {
238
+ return __awaiter(this, void 0, void 0, function* () {
239
+ const response = yield this.articleConnector.getSuperArticleQuickSel(id, branch);
240
+ if (response && response.validationResult && response.validationResult.success) {
241
+ return this._boFactory.makeWithRawBackendData(SuperArticle, response.resultObject);
242
+ }
243
+ else {
244
+ return null;
245
+ }
246
+ });
247
+ }
248
+ getDocumentContent(docId, thumbnail = true) {
249
+ return __awaiter(this, void 0, void 0, function* () {
250
+ const response = yield this.articleConnector.getDocumentContent(docId, thumbnail);
251
+ if (response && response.validationResult && response.validationResult.success) {
252
+ return this._boFactory.makeWithRawBackendData(DocumentContent, response.resultObject);
253
+ }
254
+ else {
255
+ return null;
256
+ }
257
+ });
258
+ }
259
+ addWebSessionTransactionLine(transactionUuid, sku, quantity) {
260
+ return __awaiter(this, void 0, void 0, function* () {
261
+ const response = yield this.transactionConnector.addWebSessionTransactionLine(transactionUuid, sku, quantity);
262
+ if (response && response.validationResult && response.validationResult.success) {
263
+ const infoResponse = this._boFactory.makeWithRawBackendData(TransactionInfoResponse, response.resultObject);
264
+ return infoResponse.transactionInfo.uuid;
265
+ }
266
+ return "";
267
+ });
268
+ }
269
+ }
270
+ ProductConnectorAdapterService.decorators = [
271
+ { type: Injectable }
272
+ ];
273
+ ProductConnectorAdapterService.ctorParameters = () => [
274
+ { type: ProductEventService }
275
+ ];
276
+
63
277
  class JsonUtilsService {
64
278
  readJsonFile(filePath) {
65
279
  return __awaiter(this, void 0, void 0, function* () {
@@ -280,46 +494,6 @@ DictionaryService.ctorParameters = () => [
280
494
  { type: JsonUtilsService }
281
495
  ];
282
496
 
283
- class SettingsOptions {
284
- constructor() {
285
- this.showStockStatus = false;
286
- this.showZoomButton = false;
287
- this.showTagFilter = false;
288
- this.showAsConfigured = false;
289
- this.inlineAnswers = false;
290
- this.showArButton = false;
291
- this.arEnabled = false;
292
- this.vrEnabled = false;
293
- }
294
- }
295
-
296
- var RenderModes;
297
- (function (RenderModes) {
298
- RenderModes["RenderRoom"] = "render_room";
299
- RenderModes["RenderShop"] = "render_shop";
300
- RenderModes["RenderIone"] = "render_ione";
301
- })(RenderModes || (RenderModes = {}));
302
-
303
- class RenderParameters$1 {
304
- constructor() {
305
- this.host = "";
306
- this.port = 0;
307
- this.secure = false;
308
- this.renderMode = RenderModes.RenderShop;
309
- }
310
- }
311
-
312
- class ProductSettings extends Options {
313
- constructor() {
314
- super(...arguments);
315
- this.session = undefined;
316
- this.createWebOrder = true;
317
- this.currencySymbol = '€';
318
- this.options = new SettingsOptions();
319
- this.renderParameters = new RenderParameters$1();
320
- }
321
- }
322
-
323
497
  class ProductSettingsService {
324
498
  constructor(_jsonUtilsService, _dictionaryService) {
325
499
  this._jsonUtilsService = _jsonUtilsService;
@@ -399,186 +573,13 @@ ProductSettingsService.ctorParameters = () => [
399
573
  { type: DictionaryService }
400
574
  ];
401
575
 
402
- // Sole responsibility is simply to wrap around a colijn.Connector to create a stable inner interface to the library in a 1:1 method way.
403
- // Only to be used by the IOneControllerService.
404
- class ProductConnectorAdapterService {
405
- constructor(_eventService) {
406
- this._eventService = _eventService;
407
- this.showLoader = new Subject();
408
- this._boFactory = new BusinessObjectFactory();
409
- this._subs = [];
410
- }
411
- ngOnDestroy() {
412
- this._subs.forEach(s => s.unsubscribe());
413
- }
414
- initConnector(options) {
415
- return __awaiter(this, void 0, void 0, function* () {
416
- this.articleConnector = new Articles(options);
417
- yield this.articleConnector.connect();
418
- this.transactionConnector = new Transaction(options);
419
- this._subs.push(
420
- // @ts-ignore
421
- this.articleConnector.showLoader.subscribe(value => this.showLoader.next(value)));
422
- });
423
- }
424
- setInstance(instanceId) {
425
- // this.articleConnector.setInstanceToConfigure(instanceId, false);
426
- }
427
- getProductBundleSettings(url, upId) {
428
- return __awaiter(this, void 0, void 0, function* () {
429
- const tempSettings = new ProductSettings();
430
- tempSettings.url = url;
431
- tempSettings.schema = upId.toString();
432
- const tempMainConnector = new MainApi(tempSettings);
433
- const response = yield tempMainConnector.getPublicParams(upId);
434
- if (response) {
435
- return response.productSettings;
436
- }
437
- return "";
438
- });
439
- }
440
- convertArticleFullObjectToArticleExtended(article) {
441
- if (article) {
442
- return this._boFactory.makeWithRawBackendData(ArticleListObjectExtended, article);
443
- }
444
- }
445
- getDeliveryPrognosis(goodId, branchNr) {
446
- return __awaiter(this, void 0, void 0, function* () {
447
- const deliveryPrognosis = yield this.getSelectorDeliveryDate();
448
- if (!deliveryPrognosis || !deliveryPrognosis.returnValue) {
449
- return this.getDeliveryDate2(goodId);
450
- }
451
- return deliveryPrognosis;
452
- });
453
- }
454
- getSelectorDeliveryDate() {
455
- return __awaiter(this, void 0, void 0, function* () {
456
- const response = yield this.articleConnector.getSelectorDeliveryDate();
457
- if (response && response.validationResult && response.validationResult.success) {
458
- return this._boFactory.makeWithRawBackendData(DeliveryPrognosis, response.resultObject);
459
- }
460
- else {
461
- return null;
462
- }
463
- });
464
- }
465
- getArtStockStatus(goodId) {
466
- return __awaiter(this, void 0, void 0, function* () {
467
- const response = yield this.articleConnector.getArtStockStatus(goodId);
468
- if (response && response.validationResult && response.validationResult.success) {
469
- return response.resultObject;
470
- }
471
- else {
472
- return null;
473
- }
474
- });
475
- }
476
- getDeliveryDate2(goodId) {
477
- return __awaiter(this, void 0, void 0, function* () {
478
- const response = yield this.articleConnector.getDeliveryDate2(goodId);
479
- if (response && response.validationResult && response.validationResult.success) {
480
- return this._boFactory.makeWithRawBackendData(DeliveryPrognosis, response.resultObject);
481
- }
482
- else {
483
- return null;
484
- }
485
- });
486
- }
487
- getJsonConfiguredArticles(configuratorStatistics) {
488
- return __awaiter(this, void 0, void 0, function* () {
489
- const response = yield this.articleConnector.getJsonConfiguredArticles(configuratorStatistics);
490
- if (response && response.validationResult && response.validationResult.success) {
491
- return response.resultObject;
492
- }
493
- else {
494
- return '';
495
- }
496
- });
497
- }
498
- getJsonArticleFlatTree(goodId, goodType, quantity, externalSource = false, showLoader = true, instanceId, configuratorStatistics) {
499
- return __awaiter(this, void 0, void 0, function* () {
500
- return this.articleConnector.getJsonArticleFlatTree(goodId, goodType, quantity, externalSource, showLoader, instanceId, configuratorStatistics).catch((messages) => {
501
- this._eventService.errorMessage.next(messages);
502
- return null;
503
- });
504
- });
505
- }
506
- getGeneratedArtDirectly(goodId, showLoader) {
507
- return __awaiter(this, void 0, void 0, function* () {
508
- return this.articleConnector.getGeneratedArtDirectly(goodId, showLoader).catch((messages) => {
509
- this._eventService.errorMessage.next(messages);
510
- return null;
511
- });
512
- });
513
- }
514
- getGoodIdFromArticleNr(sku) {
515
- return __awaiter(this, void 0, void 0, function* () {
516
- const response = yield this.articleConnector.getGoodIdFromArticleNr(sku);
517
- if (response && response.validationResult && response.validationResult.success) {
518
- return response.resultObject;
519
- }
520
- else {
521
- return null;
522
- }
523
- });
524
- }
525
- getArticleFullObject(goodId, showLoader = true) {
526
- return __awaiter(this, void 0, void 0, function* () {
527
- const response = yield this.articleConnector.getArticleFullObject(goodId, showLoader);
528
- if (response && response.validationResult && response.validationResult.success) {
529
- return this._boFactory.makeWithRawBackendData(ArticleFullObject, response.resultObject);
530
- }
531
- else {
532
- return null;
533
- }
534
- });
535
- }
536
- getSuperArticle(id, branch) {
537
- return __awaiter(this, void 0, void 0, function* () {
538
- const response = yield this.articleConnector.getSuperArticleQuickSel(id, branch);
539
- if (response && response.validationResult && response.validationResult.success) {
540
- return this._boFactory.makeWithRawBackendData(SuperArticle, response.resultObject);
541
- }
542
- else {
543
- return null;
544
- }
545
- });
546
- }
547
- getDocumentContent(docId, thumbnail = true) {
548
- return __awaiter(this, void 0, void 0, function* () {
549
- const response = yield this.articleConnector.getDocumentContent(docId, thumbnail);
550
- if (response && response.validationResult && response.validationResult.success) {
551
- return this._boFactory.makeWithRawBackendData(DocumentContent, response.resultObject);
552
- }
553
- else {
554
- return null;
555
- }
556
- });
557
- }
558
- addWebSessionTransactionLine(transactionUuid, sku, quantity) {
559
- return __awaiter(this, void 0, void 0, function* () {
560
- const response = yield this.transactionConnector.addWebSessionTransactionLine(transactionUuid, sku, quantity);
561
- if (response && response.validationResult && response.validationResult.success) {
562
- const infoResponse = this._boFactory.makeWithRawBackendData(TransactionInfoResponse, response.resultObject);
563
- return infoResponse.transactionInfo.uuid;
564
- }
565
- return "";
566
- });
567
- }
568
- }
569
- ProductConnectorAdapterService.decorators = [
570
- { type: Injectable }
571
- ];
572
- ProductConnectorAdapterService.ctorParameters = () => [
573
- { type: ProductEventService }
574
- ];
575
-
576
576
  // Holds all iONE backend related state and methods for a running HomeDecorator. To be used anywhere internally.
577
577
  class ProductConnectorService {
578
578
  constructor(_adapterService, _settingsService) {
579
579
  this._adapterService = _adapterService;
580
580
  this._settingsService = _settingsService;
581
581
  this.controllerInitialized = new BehaviorSubject(false);
582
+ this.articleLoaded = new BehaviorSubject(false);
582
583
  this._initializing = false;
583
584
  this._initialized = false;
584
585
  this.connectorOptions = new Options();
@@ -676,8 +677,43 @@ ProductConnectorService.ctorParameters = () => [
676
677
  { type: ProductSettingsService }
677
678
  ];
678
679
 
680
+ class RootStorageObject {
681
+ }
682
+ class LocalStorageService {
683
+ constructor() {
684
+ this.storage = localStorage;
685
+ this._appRoot = "web-order";
686
+ this._storageObj = new RootStorageObject();
687
+ this._initLocalStorageObj();
688
+ }
689
+ save() {
690
+ this.storage.setItem(this._appRoot, JSON.stringify(this._storageObj));
691
+ }
692
+ clear() {
693
+ this.storage.clear();
694
+ }
695
+ set id(id) {
696
+ this._storageObj.id = id;
697
+ this.save();
698
+ }
699
+ get id() {
700
+ return this._storageObj ? this._storageObj.id : "";
701
+ }
702
+ _initLocalStorageObj() {
703
+ this._storageObj = JSON.parse(this.storage.getItem(this._appRoot)) || this._storageObj;
704
+ this.save();
705
+ }
706
+ }
707
+ LocalStorageService.ɵprov = i0.ɵɵdefineInjectable({ factory: function LocalStorageService_Factory() { return new LocalStorageService(); }, token: LocalStorageService, providedIn: "root" });
708
+ LocalStorageService.decorators = [
709
+ { type: Injectable, args: [{
710
+ providedIn: 'root'
711
+ },] }
712
+ ];
713
+ LocalStorageService.ctorParameters = () => [];
714
+
679
715
  class IoneProductComponent {
680
- constructor(_appEventService, _settingsService) {
716
+ constructor(_appEventService, _settingsService, _productConnectorService, _localStorageService) {
681
717
  // this.sku = 'CF-HILL';
682
718
  // this.sku = 'CF-ALMADA';
683
719
  // this.sku = 'CF-39904ANT';
@@ -695,8 +731,11 @@ class IoneProductComponent {
695
731
  // this.sku = "1000612725";
696
732
  this._appEventService = _appEventService;
697
733
  this._settingsService = _settingsService;
734
+ this._productConnectorService = _productConnectorService;
735
+ this._localStorageService = _localStorageService;
698
736
  this.enableRenderCarousel = false;
699
737
  this.handleAddArticleInternally = true;
738
+ this.handleAddToCartInternally = false;
700
739
  this.onAddToCart = new EventEmitter();
701
740
  this.forceRenderImage = new EventEmitter();
702
741
  this.getRenderForRenderCarousel = new EventEmitter();
@@ -748,7 +787,31 @@ class IoneProductComponent {
748
787
  }
749
788
  _handleAddToCart(data) {
750
789
  return __awaiter(this, void 0, void 0, function* () {
751
- this.onAddToCart.emit(data);
790
+ if (this.handleAddToCartInternally) {
791
+ if (data && data.article) {
792
+ if (typeof data.article === 'string') {
793
+ const article = JSON.parse(data.article);
794
+ if (article.selectorData && article.selectorData.compositions) { // configured (frozen) article
795
+ const transactionId = yield this._productConnectorService.addWebSessionTransactionLine(this._localStorageService.id, article.selectorData.compositions[0].compositionArticleNo, data.quantity);
796
+ if (transactionId) {
797
+ this._localStorageService.id = transactionId;
798
+ }
799
+ }
800
+ }
801
+ else { // flat (simple) article
802
+ if (data.article.hasOwnProperty('articleNr')) {
803
+ const transactionId = yield this._productConnectorService.addWebSessionTransactionLine(this._localStorageService.id, data.article['articleNr'], data.quantity);
804
+ if (transactionId) {
805
+ this._localStorageService.id = transactionId;
806
+ }
807
+ }
808
+ }
809
+ this.onAddToCart.next(data);
810
+ }
811
+ }
812
+ else {
813
+ this.onAddToCart.emit(data);
814
+ }
752
815
  });
753
816
  }
754
817
  openStock() {
@@ -782,7 +845,9 @@ IoneProductComponent.decorators = [
782
845
  ];
783
846
  IoneProductComponent.ctorParameters = () => [
784
847
  { type: ProductEventService },
785
- { type: ProductSettingsService }
848
+ { type: ProductSettingsService },
849
+ { type: ProductConnectorService },
850
+ { type: LocalStorageService }
786
851
  ];
787
852
  IoneProductComponent.propDecorators = {
788
853
  sku: [{ type: Input }],
@@ -791,6 +856,7 @@ IoneProductComponent.propDecorators = {
791
856
  enableRenderCarousel: [{ type: Input }],
792
857
  settings: [{ type: Input }],
793
858
  handleAddArticleInternally: [{ type: Input }],
859
+ handleAddToCartInternally: [{ type: Input }],
794
860
  onAddToCart: [{ type: Output }],
795
861
  forceRenderImage: [{ type: Output }],
796
862
  getRenderForRenderCarousel: [{ type: Output }],
@@ -927,9 +993,18 @@ class ProductPageComponent {
927
993
  if (this.selections.nativeElement) {
928
994
  this.selections.nativeElement.forceRenderImage();
929
995
  }
930
- }), this.settingsService.settingsLoaded.subscribe(loaded => this._handleSettingsLoaded(loaded)), this._ione.controllerInitialized.subscribe((initialized) => {
931
- this.settingsLoaded = initialized;
932
- }), this.appEventService.onAnswersAvailable.subscribe((answers) => {
996
+ }), this.settingsService.settingsLoaded.subscribe(loaded => this._handleSettingsLoaded(loaded)), this._pageLoadedSubscription = combineLatest([
997
+ this._ione.controllerInitialized,
998
+ this._ione.articleLoaded
999
+ ]).subscribe(([initialized, articleLoaded]) => {
1000
+ if (initialized && articleLoaded) {
1001
+ this.settingsLoaded = initialized;
1002
+ }
1003
+ }),
1004
+ // this._ione.controllerInitialized.subscribe((initialized: boolean) => {
1005
+ // this.settingsLoaded = initialized;
1006
+ // }),
1007
+ this.appEventService.onAnswersAvailable.subscribe((answers) => {
933
1008
  if (answers && this.configurable) {
934
1009
  this.showAddToCart = false;
935
1010
  }
@@ -1009,6 +1084,7 @@ class ProductPageComponent {
1009
1084
  if (this._initializedSub) {
1010
1085
  this._initializedSub.unsubscribe();
1011
1086
  }
1087
+ this._pageLoadedSubscription.unsubscribe();
1012
1088
  this.configurator = undefined;
1013
1089
  this.selections = undefined;
1014
1090
  this.fullscreenbutton = undefined;
@@ -1058,6 +1134,7 @@ class ProductPageComponent {
1058
1134
  });
1059
1135
  this._changeDetector.detectChanges();
1060
1136
  }
1137
+ this._ione.articleLoaded.next(true);
1061
1138
  });
1062
1139
  }
1063
1140
  }));
@@ -1074,7 +1151,7 @@ class ProductPageComponent {
1074
1151
  ProductPageComponent.decorators = [
1075
1152
  { type: Component, args: [{
1076
1153
  selector: 'app-product-page',
1077
- template: "<ng-container *ngIf=\"settingsLoaded\">\r\n <div class=\"page-wrapper\">\r\n <div class=\"page-wrapper-content\">\r\n <div class=\"page-wrapper-left\">\r\n <div class=\"product-image-container\">\r\n <div class=\"product-page-block-selector-type\">\r\n <app-product-selector-type class=\"default-padding\"\r\n [(currentType)]=\"currentView\"\r\n [show2D]=\"configurable\"\r\n [show3D]=\"threeD\"\r\n ></app-product-selector-type>\r\n </div>\r\n <div class=\"product-page-block-image default-padding\" [class.full]=\"fullScreen\">\r\n\r\n <app-image-carousel\r\n *ngIf=\"!enableRenderCarousel\"\r\n [@toggleVisibilityByState]=\"show2D ? 'show' : 'hide'\"\r\n [images]=\"article?.images\"\r\n [showRefresh]=\"configurable && threeD\">\r\n </app-image-carousel>\r\n\r\n <app-render-carousel\r\n *ngIf=\"enableRenderCarousel\"\r\n [@toggleVisibilityByState]=\"show2D ? 'show' : 'hide'\"\r\n [article]=\"article\">\r\n </app-render-carousel>\r\n\r\n <ng-container *ngIf=\"settingsLoaded && this.configurable\">\r\n <threed-configurator\r\n #configurator\r\n class=\"threed-configurator\"\r\n [class.configurator-full-screen]=\"fullScreen\"\r\n [@toggleVisibilityByState]=\"show3D ? 'show' : 'hide'\"\r\n [@toggleFullScreen]=\"fullScreen ? 'fullscreen' : 'halfscreen'\">\r\n </threed-configurator>\r\n </ng-container>\r\n\r\n <co-icon #fullscreenbutton class=\"fullscreen-button\" *ngIf=\"show3D\"\r\n [@toggleTopLeft]=\"fullScreen ? 'fullscreen' : 'halfscreen'\"\r\n [iconData]=\"iconCache.getIcon(fullScreenIcon)\"\r\n (click)=\"showFullScreen()\"></co-icon>\r\n <co-icon class=\"threed-watermark\" *ngIf=\"show3D && fullScreen\"\r\n [iconData]=\"iconCache.getIcon(icon.Logo)\"></co-icon>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"page-wrapper-right\">\r\n <div class=\"product-page-block-description\">\r\n <app-product-description class=\"default-padding\" [article]=\"article\"></app-product-description>\r\n </div>\r\n <div class=\"product-page-block-additional\">\r\n <div class=\"product-page-block-additional-description\">\r\n <app-product-additional-description class=\"default-padding\" [article]=\"article\"></app-product-additional-description>\r\n </div>\r\n <div class=\"product-page-block-price\" [class.full]=\"configuring\">\r\n <app-product-price class=\"s-padding\" *ngIf=\"!configuring\"\r\n [pricing]=\"article?.pricing\"\r\n [configurable]=\"configurable\"\r\n ></app-product-price>\r\n <ng-container *ngIf=\"settingsLoaded\">\r\n <threed-selections #selections class=\"threed-selections\"\r\n [class.show-selections]=\"configuring\"\r\n [@toggleFullScreenRight]=\"fullScreen ? 'fullscreen' : 'halfscreen'\"\r\n [class.default-padding]=\"!fullScreen\"\r\n [class.show-full-screen]=\"fullScreen\"\r\n [class.mini-scrollbar]=\"fullScreen\"\r\n [sku]=\"sku\"\r\n [settings]=\"settings\"\r\n (onUserActionFromThreeD)=\"configuring = true\"\r\n (instanceSet)=\"setInstance($event)\"\r\n (onImageReceived)=\"appEventService.onImageReceived.next($event)\"\r\n (onRenderStarted)=\"appEventService.onRenderStarted.next()\"\r\n (onDraftRenderImageReceived)=\"appEventService.onDraftRenderImageReceived.next($event)\"\r\n (onArticleReceived)=\"appEventService.onArticleReceived.next($event.detail)\"\r\n (onSelectionsReceived)=\"appEventService.onSelectionsReceived.next($event.detail)\"\r\n (onArticleInfoReceived)=\"appEventService.onArticleInfoReceived.next($event.detail)\"\r\n (onAnswersAvailable)=\"appEventService.onAnswersAvailable.next($event.detail)\"\r\n (onReadyToRender)=\"appEventService.onReadyToRender.next($event.detail)\"\r\n (onRenderImageReceived)=\"appEventService.onRenderImageReceived.next($event.detail)\"\r\n ></threed-selections>\r\n </ng-container>\r\n </div>\r\n <div class=\"product-page-block-addtocart no-padding product-action-buttons\" *ngIf=\"!configuring\" [@toggleTopRight]=\"fullScreen ? 'fullscreen' : 'halfscreen'\">\r\n <app-product-addtocart\r\n [configurable]=\"configurable\"\r\n [createFrozenArticle]=\"createFrozenArticle\"\r\n [configuring]=\"configuring\"\r\n [showAddToCart]=\"showAddToCart\"\r\n [article]=\"article\"\r\n [externalSource]=\"externalSource\"\r\n [isReturn]=\"isReturn\"\r\n (startConfiguration)=\"handleStartConfiguration()\"\r\n (showRelatedPopup)=\"handlePopUpChange($event)\"\r\n ></app-product-addtocart>\r\n </div>\r\n <div class=\"addtocart-reserved product-action-buttons\" *ngIf=\"configuring\" [class.full-screen]=\"fullScreen\">\r\n <app-product-addtocart class=\"default-padding\"\r\n [configurable]=\"false\"\r\n [fullscreen]=\"fullScreen\"\r\n [showAddToCart]=\"showAddToCart\"\r\n [configuring]=\"configuring\"\r\n [article]=\"article\"\r\n [externalSource]=\"externalSource\"\r\n [isReturn]=\"isReturn\"\r\n (startConfiguration)=\"handleStartConfiguration()\"\r\n ></app-product-addtocart>\r\n </div>\r\n <div class=\"product-page-block-variants\">\r\n <app-product-related class=\"no-padding\" *ngIf=\"article?.relatedArticles && article?.relatedArticles.length > 0\"\r\n [externalSource]=\"externalSource\"\r\n [articles]=\"article?.relatedArticles\" [refType]=\"64\" [label]=\"'VARIANTS' | localize\"></app-product-related>\r\n </div>\r\n <div class=\"product-page-block-stock\">\r\n <app-product-stock class=\"no-padding\" [goodId]=\"article?.goodId\" (openStockEvent)=\"openStock()\"></app-product-stock>\r\n </div>\r\n <div class=\"product-page-block-delivery\">\r\n <app-product-delivery class=\"no-padding\" [stockAndDelivery]=\"stockAndDelivery\"></app-product-delivery>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"page-wrapper-content\">\r\n <div class=\"page-wrapper-left\">\r\n <app-product-info-tabs class=\"no-padding\" [article]=\"article\"></app-product-info-tabs>\r\n </div>\r\n <div class=\"page-wrapper-right\">\r\n <div class=\"product-page-block-related s-padding\">\r\n <app-product-related\r\n *ngIf=\"article?.relatedArticles && article?.relatedArticles.length > 0\"\r\n [externalSource]=\"externalSource\"\r\n [articles]=\"article?.relatedArticles\"\r\n [refType]=\"1\"\r\n [label]=\"'RELATED_PRODUCTS' | localize\">\r\n </app-product-related>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"page-wrapper-content no-top-margin\">\r\n <div class=\"page-wrapper-full\">\r\n <div class=\"product-page-block-alternatives s-padding\">\r\n <app-product-related\r\n *ngIf=\"article?.relatedArticles && article?.relatedArticles.length > 0\"\r\n [externalSource]=\"externalSource\"\r\n [articles]=\"article?.relatedArticles\"\r\n [refType]=\"4\"\r\n [isSmallModus]=\"false\"\r\n [label]=\"'ALTERNATIVE_PRODUCTS' | localize\">\r\n </app-product-related>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n\r\n <div *ngIf=\"showRelatedProductsPopup\">\r\n <co-product-dialog\r\n [mainArticle]=\"article\"\r\n [articles]=\"article?.relatedArticles\"\r\n [refType]=\"1\"\r\n (closeRelatedPopup)=\"handlePopUpChange($event)\"\r\n >\r\n </co-product-dialog>\r\n\r\n <!-- <app-product-related class=\"no-padding\" *ngIf=\"article?.relatedArticles && article?.relatedArticles.length > 0\"-->\r\n <!-- [articles]=\"article?.relatedArticles\" [refType]=\"64\" [label]=\"'VARIANTS' | localize\"></app-product-related>-->\r\n </div>\r\n\r\n\r\n </div>\r\n</ng-container>\r\n",
1154
+ template: "<ng-container *ngIf=\"settingsLoaded\">\r\n <div class=\"page-wrapper\">\r\n <div class=\"page-wrapper-content\">\r\n <div class=\"page-wrapper-left\">\r\n <div class=\"product-image-container\">\r\n <div class=\"product-page-block-selector-type\">\r\n <app-product-selector-type class=\"default-padding\"\r\n [(currentType)]=\"currentView\"\r\n [show2D]=\"configurable\"\r\n [show3D]=\"threeD\"\r\n ></app-product-selector-type>\r\n </div>\r\n <div class=\"product-page-block-image default-padding\" [class.full]=\"fullScreen\">\r\n\r\n <app-image-carousel\r\n *ngIf=\"!enableRenderCarousel\"\r\n [@toggleVisibilityByState]=\"show2D ? 'show' : 'hide'\"\r\n [images]=\"article?.images\"\r\n [showRefresh]=\"configurable && threeD\">\r\n </app-image-carousel>\r\n\r\n <app-render-carousel\r\n *ngIf=\"enableRenderCarousel\"\r\n [@toggleVisibilityByState]=\"show2D ? 'show' : 'hide'\"\r\n [article]=\"article\">\r\n </app-render-carousel>\r\n\r\n <ng-container *ngIf=\"settingsLoaded && this.configurable\">\r\n <threed-configurator\r\n #configurator\r\n class=\"threed-configurator\"\r\n [class.configurator-full-screen]=\"fullScreen\"\r\n [@toggleVisibilityByState]=\"show3D ? 'show' : 'hide'\"\r\n [@toggleFullScreen]=\"fullScreen ? 'fullscreen' : 'halfscreen'\">\r\n </threed-configurator>\r\n </ng-container>\r\n\r\n <co-icon #fullscreenbutton class=\"fullscreen-button\" *ngIf=\"show3D\"\r\n [@toggleTopLeft]=\"fullScreen ? 'fullscreen' : 'halfscreen'\"\r\n [iconData]=\"iconCache.getIcon(fullScreenIcon)\"\r\n (click)=\"showFullScreen()\"></co-icon>\r\n <co-icon class=\"threed-watermark\" *ngIf=\"show3D && fullScreen\"\r\n [iconData]=\"iconCache.getIcon(icon.Logo)\"></co-icon>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"page-wrapper-right\">\r\n <div class=\"product-page-block-description\">\r\n <app-product-description class=\"default-padding\" [article]=\"article\"></app-product-description>\r\n </div>\r\n <div class=\"product-page-block-additional\">\r\n <div class=\"product-page-block-additional-description\">\r\n <app-product-additional-description class=\"default-padding\" [article]=\"article\"></app-product-additional-description>\r\n </div>\r\n <div class=\"product-page-block-price\" [class.full]=\"configuring\">\r\n <app-product-price class=\"s-padding\" *ngIf=\"!configuring\"\r\n [pricing]=\"article?.pricing\"\r\n [configurable]=\"configurable\"\r\n ></app-product-price>\r\n <ng-container *ngIf=\"settingsLoaded\">\r\n <threed-selections #selections class=\"threed-selections\"\r\n [class.show-selections]=\"configuring\"\r\n [@toggleFullScreenRight]=\"fullScreen ? 'fullscreen' : 'halfscreen'\"\r\n [class.default-padding]=\"!fullScreen\"\r\n [class.show-full-screen]=\"fullScreen\"\r\n [class.mini-scrollbar]=\"fullScreen\"\r\n [sku]=\"sku\"\r\n [settings]=\"settings\"\r\n (onUserActionFromThreeD)=\"configuring = true\"\r\n (instanceSet)=\"setInstance($event)\"\r\n (onImageReceived)=\"appEventService.onImageReceived.next($event)\"\r\n (onRenderStarted)=\"appEventService.onRenderStarted.next()\"\r\n (onDraftRenderImageReceived)=\"appEventService.onDraftRenderImageReceived.next($event)\"\r\n (onArticleReceived)=\"appEventService.onArticleReceived.next($event.detail)\"\r\n (onSelectionsReceived)=\"appEventService.onSelectionsReceived.next($event.detail)\"\r\n (onArticleInfoReceived)=\"appEventService.onArticleInfoReceived.next($event.detail)\"\r\n (onAnswersAvailable)=\"appEventService.onAnswersAvailable.next($event.detail)\"\r\n (onReadyToRender)=\"appEventService.onReadyToRender.next($event.detail)\"\r\n (onRenderImageReceived)=\"appEventService.onRenderImageReceived.next($event.detail)\"\r\n ></threed-selections>\r\n </ng-container>\r\n </div>\r\n <div class=\"product-page-block-addtocart no-padding product-action-buttons\" *ngIf=\"!configuring\" [@toggleTopRight]=\"fullScreen ? 'fullscreen' : 'halfscreen'\">\r\n <app-product-addtocart\r\n [configurable]=\"configurable\"\r\n [createFrozenArticle]=\"createFrozenArticle\"\r\n [configuring]=\"configuring\"\r\n [showAddToCart]=\"showAddToCart\"\r\n [article]=\"article\"\r\n [externalSource]=\"externalSource\"\r\n [isReturn]=\"isReturn\"\r\n (startConfiguration)=\"handleStartConfiguration()\"\r\n (showRelatedPopup)=\"handlePopUpChange($event)\"\r\n ></app-product-addtocart>\r\n </div>\r\n <div class=\"addtocart-reserved product-action-buttons\" *ngIf=\"configuring\" [class.full-screen]=\"fullScreen\">\r\n <app-product-addtocart class=\"default-padding\"\r\n [configurable]=\"false\"\r\n [fullscreen]=\"fullScreen\"\r\n [showAddToCart]=\"showAddToCart\"\r\n [configuring]=\"configuring\"\r\n [article]=\"article\"\r\n [externalSource]=\"externalSource\"\r\n [isReturn]=\"isReturn\"\r\n (startConfiguration)=\"handleStartConfiguration()\"\r\n ></app-product-addtocart>\r\n </div>\r\n <div class=\"product-page-block-variants\">\r\n <app-product-related class=\"no-padding\" *ngIf=\"article?.relatedArticles && article?.relatedArticles.length > 0\"\r\n [externalSource]=\"externalSource\"\r\n [articles]=\"article?.relatedArticles\" [refType]=\"64\" [label]=\"'VARIANTS' | localize\"></app-product-related>\r\n </div>\r\n <div class=\"product-page-block-stock\">\r\n <app-product-stock class=\"no-padding\" [goodId]=\"article?.goodId\" (openStockEvent)=\"openStock()\"></app-product-stock>\r\n </div>\r\n <div class=\"product-page-block-delivery\">\r\n <app-product-delivery class=\"no-padding\" [stockAndDelivery]=\"stockAndDelivery\"></app-product-delivery>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"page-wrapper-content\">\r\n <div class=\"page-wrapper-left\" *ngIf=\"article\">\r\n <app-product-info-tabs class=\"no-padding\" [article]=\"article\"></app-product-info-tabs>\r\n </div>\r\n <div class=\"page-wrapper-right\">\r\n <div class=\"product-page-block-related s-padding\">\r\n <app-product-related\r\n *ngIf=\"article?.relatedArticles && article?.relatedArticles.length > 0\"\r\n [externalSource]=\"externalSource\"\r\n [articles]=\"article?.relatedArticles\"\r\n [refType]=\"1\"\r\n [label]=\"'RELATED_PRODUCTS' | localize\">\r\n </app-product-related>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"page-wrapper-content no-top-margin\">\r\n <div class=\"page-wrapper-full\">\r\n <div class=\"product-page-block-alternatives s-padding\">\r\n <app-product-related\r\n *ngIf=\"article?.relatedArticles && article?.relatedArticles.length > 0\"\r\n [externalSource]=\"externalSource\"\r\n [articles]=\"article?.relatedArticles\"\r\n [refType]=\"4\"\r\n [isSmallModus]=\"false\"\r\n [label]=\"'ALTERNATIVE_PRODUCTS' | localize\">\r\n </app-product-related>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n\r\n <div *ngIf=\"showRelatedProductsPopup\">\r\n <co-product-dialog\r\n [mainArticle]=\"article\"\r\n [articles]=\"article?.relatedArticles\"\r\n [refType]=\"1\"\r\n (closeRelatedPopup)=\"handlePopUpChange($event)\"\r\n >\r\n </co-product-dialog>\r\n\r\n <!-- <app-product-related class=\"no-padding\" *ngIf=\"article?.relatedArticles && article?.relatedArticles.length > 0\"-->\r\n <!-- [articles]=\"article?.relatedArticles\" [refType]=\"64\" [label]=\"'VARIANTS' | localize\"></app-product-related>-->\r\n </div>\r\n\r\n\r\n </div>\r\n</ng-container>\r\n",
1078
1155
  animations: [
1079
1156
  trigger('toggleFullScreen', [
1080
1157
  state('fullscreen', style({ 'position': 'fixed', 'top': '0', 'left': '0', 'width': '100%', 'height': '100%' })),
@@ -1261,6 +1338,7 @@ class ImageCarouselComponent {
1261
1338
  this._appEventService = _appEventService;
1262
1339
  this._changeDetector = _changeDetector;
1263
1340
  this._domSanitizer = _domSanitizer;
1341
+ this.isPopupOpen = false;
1264
1342
  this.showRefresh = false;
1265
1343
  this.resizing = false;
1266
1344
  this.imageViewModels = [];
@@ -1290,6 +1368,12 @@ class ImageCarouselComponent {
1290
1368
  this._changeDetector.detectChanges();
1291
1369
  }));
1292
1370
  }
1371
+ // Close on ESC
1372
+ onEsc() {
1373
+ if (this.isPopupOpen) {
1374
+ this.closePopup();
1375
+ }
1376
+ }
1293
1377
  set images(value) {
1294
1378
  if (value && value.length > 0) {
1295
1379
  this._images = this._filterValidImages(value);
@@ -1336,15 +1420,16 @@ class ImageCarouselComponent {
1336
1420
  }
1337
1421
  handleShowImage(imageViewModel) {
1338
1422
  if (imageViewModel && imageViewModel.originalSource) {
1339
- let popupWindow = window.open('', 'Image zoom', 'width=600,height=400');
1340
- // Set the content of the popup window
1341
- popupWindow.document.write('<html><head><title>Image zoom</title></head><body>');
1342
- popupWindow.document.write(`<img src=${imageViewModel.originalSource} alt="Image" style="width:100%; height:auto;">`);
1343
- popupWindow.document.write('</body></html>');
1344
- // Close the document to render the popup window
1345
- popupWindow.document.close();
1423
+ this.selectedImage = imageViewModel;
1424
+ this.isPopupOpen = true;
1425
+ this._changeDetector.markForCheck();
1346
1426
  }
1347
1427
  }
1428
+ closePopup() {
1429
+ this.isPopupOpen = false;
1430
+ this.selectedImage = undefined;
1431
+ this._changeDetector.markForCheck();
1432
+ }
1348
1433
  _filterValidImages(value) {
1349
1434
  if (!value) {
1350
1435
  return [];
@@ -1387,38 +1472,54 @@ class ImageCarouselComponent {
1387
1472
  }
1388
1473
  _resizeAndSanitizeSource(source, imageViewModel) {
1389
1474
  const resizeCanvas = document.createElement('canvas');
1390
- const resizeCanvasContext = resizeCanvas.getContext('2d');
1391
- const resizeImage = document.createElement('img');
1392
- resizeImage.crossOrigin = 'anonymous';
1393
- resizeImage.onload = () => __awaiter(this, void 0, void 0, function* () {
1394
- resizeCanvasContext.imageSmoothingEnabled = true;
1395
- resizeCanvasContext.imageSmoothingQuality = 'high';
1396
- // Get the original image dimensions
1397
- const originalWidth = resizeImage.width;
1398
- const originalHeight = resizeImage.height;
1399
- // Calculate the aspect ratio
1400
- const aspectRatio = originalWidth / originalHeight;
1401
- // Calculate the new width and height while maintaining the aspect ratio
1402
- let newWidth = this._resizeCanvasHeight;
1403
- let newHeight = this._resizeCanvasHeight;
1404
- if (originalWidth > originalHeight) {
1405
- newHeight = this._resizeCanvasHeight / aspectRatio;
1475
+ const ctx = resizeCanvas.getContext('2d');
1476
+ const img = document.createElement('img');
1477
+ img.crossOrigin = 'anonymous';
1478
+ img.onload = () => {
1479
+ ctx.imageSmoothingEnabled = true;
1480
+ ctx.imageSmoothingQuality = 'high';
1481
+ const ow = img.width;
1482
+ const oh = img.height;
1483
+ const aspect = ow / oh;
1484
+ let newW = this._resizeCanvasHeight;
1485
+ let newH = this._resizeCanvasHeight;
1486
+ if (ow > oh) {
1487
+ newH = this._resizeCanvasHeight / aspect;
1406
1488
  }
1407
1489
  else {
1408
- newWidth = this._resizeCanvasHeight * aspectRatio;
1409
- }
1410
- // Set the canvas size to the new width and height
1411
- resizeCanvas.width = newWidth;
1412
- resizeCanvas.height = newHeight;
1413
- const imageWidth = this._resizeCanvasHeight * (resizeImage.height / resizeImage.width);
1414
- resizeCanvasContext.drawImage(resizeImage, 0, 0, newWidth, newHeight);
1415
- const resizedSource = resizeCanvas.toDataURL('image/jpeg');
1490
+ newW = this._resizeCanvasHeight * aspect;
1491
+ }
1492
+ resizeCanvas.width = Math.round(newW);
1493
+ resizeCanvas.height = Math.round(newH);
1494
+ // Ensure transparent background before drawing
1495
+ ctx.clearRect(0, 0, resizeCanvas.width, resizeCanvas.height);
1496
+ ctx.drawImage(img, 0, 0, resizeCanvas.width, resizeCanvas.height);
1497
+ const mime = this._detectPreferredMime(source);
1498
+ const resizedSource = mime === 'image/jpeg'
1499
+ ? resizeCanvas.toDataURL('image/jpeg', 0.92) // only if original was JPEG
1500
+ : resizeCanvas.toDataURL(mime); // PNG/WebP keep alpha
1416
1501
  imageViewModel.source = this._domSanitizer.bypassSecurityTrustUrl(resizedSource);
1417
1502
  imageViewModel.originalSource = source;
1418
1503
  this._changeDetector.detectChanges();
1419
- });
1420
- // @ts-ignore
1421
- resizeImage.src = source;
1504
+ };
1505
+ img.src = source;
1506
+ }
1507
+ _detectPreferredMime(source) {
1508
+ // Data URI check
1509
+ const m = source.match(/^data:(image\/[a-zA-Z+.-]+);base64,/);
1510
+ if (m) {
1511
+ const t = m[1].toLowerCase();
1512
+ if (t === 'image/png' || t === 'image/webp' || t === 'image/jpeg')
1513
+ return t;
1514
+ }
1515
+ const lower = source.toLowerCase();
1516
+ if (lower.endsWith('.png'))
1517
+ return 'image/png';
1518
+ if (lower.endsWith('.webp'))
1519
+ return 'image/webp';
1520
+ if (lower.endsWith('.jpg') || lower.endsWith('.jpeg'))
1521
+ return 'image/jpeg';
1522
+ return 'image/png';
1422
1523
  }
1423
1524
  _scrollCarouselToIndex() {
1424
1525
  if (this.currentIndex > -1 && this.currentIndex <= this.images.length) {
@@ -1468,9 +1569,31 @@ ImageCarouselComponent.decorators = [
1468
1569
  </co-scroll-container>
1469
1570
  </div>
1470
1571
  </div>
1572
+ <!-- Modal (real popup) -->
1573
+ <div
1574
+ class="image-modal"
1575
+ *ngIf="isPopupOpen"
1576
+ (click)="closePopup()"
1577
+ role="dialog"
1578
+ aria-modal="true"
1579
+ aria-label="Image preview"
1580
+ >
1581
+ <div class="image-modal__content" (click)="$event.stopPropagation()">
1582
+ <button
1583
+ class="image-modal__close"
1584
+ type="button"
1585
+ aria-label="Close"
1586
+ (click)="closePopup()"
1587
+ >
1588
+ ×
1589
+ </button>
1590
+
1591
+ <img [src]="selectedImage?.originalSource" alt="Image preview" />
1592
+ </div>
1593
+ </div>
1471
1594
  `,
1472
1595
  changeDetection: ChangeDetectionStrategy.OnPush,
1473
- styles: [":host{max-height:540px;height:100%;position:relative}:host:not(.resizing) .inner-carousel{scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scroll-snap-type:x mandatory}#product_page_carousel{position:relative}#product_page_carousel .refresh-button{position:absolute;bottom:10px;right:10px;background:#fff}#product_page_carousel .refresh-button.loading{animation:spin 1s linear infinite}#product_page_carousel .refresh-button:hover{box-shadow:none;background:#74B77F;transition:all .2s ease-in-out}#product_page_carousel .refresh-button:hover ::ng-deep svg path{fill:#fff!important}#product_page_carousel #product_page_carousel_items{position:relative;margin-bottom:10px}#product_page_carousel #product_page_carousel_items ::ng-deep co-loader{position:absolute}#product_page_carousel .inner-carousel{display:flex;flex-direction:row;align-items:center;overflow:hidden;max-height:500px;border:1px solid #efefef}#product_page_carousel .carousel-item{max-height:500px;width:100%;display:flex;cursor:zoom-in;flex-shrink:0;flex-grow:0}#product_page_carousel .carousel-item img{width:100%;height:auto;-o-object-fit:contain;object-fit:contain}#product_page_carousel .carousel-scroller-layer{height:100%;width:100%;position:absolute;pointer-events:none;top:0;left:0}#product_page_carousel #product_page_carousel_thumbs{display:flex;justify-content:flex-start;height:80px;margin-left:auto;margin-right:auto}#product_page_carousel #product_page_carousel_thumbs ::ng-deep co-scroll-container{padding:0 22px}#product_page_carousel #product_page_carousel_thumbs ::ng-deep co-scroll-container .content-wrapper{padding:0}#product_page_carousel #product_page_carousel_thumbs .carousel-thumb{opacity:1;cursor:pointer;transition:all .2s ease;padding:4px;border:1px solid #f6f5f4}#product_page_carousel #product_page_carousel_thumbs .carousel-thumb.active,#product_page_carousel #product_page_carousel_thumbs .carousel-thumb:hover{border-color:#22313c}#product_page_carousel #product_page_carousel_thumbs .carousel-thumb:not(:last-child){margin-right:10px}#product_page_carousel #product_page_carousel_thumbs .carousel-thumb img{height:68px}@media screen and (max-width: 650px){#product_page_carousel_thumbs{height:57px!important}#product_page_carousel_thumbs .carousel-thumb img{height:50px!important}}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"]
1596
+ styles: [":host{max-height:540px;height:100%;position:relative}:host:not(.resizing) .inner-carousel{scroll-behavior:smooth;-webkit-overflow-scrolling:touch;scroll-snap-type:x mandatory}#product_page_carousel{position:relative}#product_page_carousel .refresh-button{position:absolute;bottom:10px;right:10px;background:#fff}#product_page_carousel .refresh-button.loading{animation:spin 1s linear infinite}#product_page_carousel .refresh-button:hover{box-shadow:none;background:#74B77F;transition:all .2s ease-in-out}#product_page_carousel .refresh-button:hover ::ng-deep svg path{fill:#fff!important}#product_page_carousel #product_page_carousel_items{position:relative;margin-bottom:10px}#product_page_carousel #product_page_carousel_items ::ng-deep co-loader{position:absolute}#product_page_carousel .inner-carousel{display:flex;flex-direction:row;align-items:center;overflow:hidden;max-height:500px;border:1px solid #efefef}#product_page_carousel .carousel-item{max-height:500px;width:100%;display:flex;cursor:zoom-in;flex-shrink:0;flex-grow:0}#product_page_carousel .carousel-item img{width:100%;height:auto;-o-object-fit:contain;object-fit:contain}#product_page_carousel .carousel-scroller-layer{height:100%;width:100%;position:absolute;pointer-events:none;top:0;left:0}#product_page_carousel #product_page_carousel_thumbs{display:flex;justify-content:flex-start;height:80px;margin-left:auto;margin-right:auto}#product_page_carousel #product_page_carousel_thumbs ::ng-deep co-scroll-container{padding:0 22px}#product_page_carousel #product_page_carousel_thumbs ::ng-deep co-scroll-container .content-wrapper{padding:0}#product_page_carousel #product_page_carousel_thumbs .carousel-thumb{opacity:1;cursor:pointer;transition:all .2s ease;padding:4px;border:1px solid #f6f5f4}#product_page_carousel #product_page_carousel_thumbs .carousel-thumb.active,#product_page_carousel #product_page_carousel_thumbs .carousel-thumb:hover{border-color:#22313c}#product_page_carousel #product_page_carousel_thumbs .carousel-thumb:not(:last-child){margin-right:10px}#product_page_carousel #product_page_carousel_thumbs .carousel-thumb img{height:68px}.image-modal{position:fixed;inset:0;background:rgba(0,0,0,.8);display:flex;align-items:center;justify-content:center;z-index:1000}.image-modal__content{position:relative;max-width:90vw;max-height:90vh}.image-modal__content img{max-width:90vw;max-height:90vh;-o-object-fit:contain;object-fit:contain;display:block}.image-modal__close{position:fixed;top:15px;right:30px;background:transparent;border:none;color:#fff;font-size:60px;line-height:1;cursor:pointer}@media screen and (max-width: 650px){#product_page_carousel_thumbs{height:57px!important}#product_page_carousel_thumbs .carousel-thumb img{height:50px!important}}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"]
1474
1597
  },] }
1475
1598
  ];
1476
1599
  ImageCarouselComponent.ctorParameters = () => [
@@ -1481,6 +1604,7 @@ ImageCarouselComponent.ctorParameters = () => [
1481
1604
  ];
1482
1605
  ImageCarouselComponent.propDecorators = {
1483
1606
  carousel: [{ type: ViewChild, args: ['carousel', { read: ElementRef },] }],
1607
+ onEsc: [{ type: HostListener, args: ['document:keydown.escape',] }],
1484
1608
  showRefresh: [{ type: Input }],
1485
1609
  images: [{ type: Input }],
1486
1610
  handleWindowResize: [{ type: HostListener, args: ['window:resize',] }],
@@ -1781,12 +1905,7 @@ class ProductAddtocartComponent {
1781
1905
  }
1782
1906
  }
1783
1907
  else {
1784
- const generatedGoodId = yield this._getGeneratedArtDirectly(this.article.goodId);
1785
- if (generatedGoodId) {
1786
- const articleFull = yield this._productConnectorAdapterService.getArticleFullObject(generatedGoodId, true);
1787
- const article = this._ioneControllerService.convertArticleFullObjectToArticleExtended(articleFull);
1788
- this._appEventService.onAddToCart.next({ article: article, quantity: quantity });
1789
- }
1908
+ yield this._handleGeneratedArticleDirectly(quantity);
1790
1909
  }
1791
1910
  }
1792
1911
  else {
@@ -1803,8 +1922,15 @@ class ProductAddtocartComponent {
1803
1922
  }
1804
1923
  }
1805
1924
  else {
1806
- const article = this._ioneControllerService.convertArticleFullObjectToArticleExtended(this.article);
1807
- this._appEventService.onAddToCart.next({ article: article, quantity: quantity });
1925
+ if (this.article.goodType === 'B') {
1926
+ if (!this.article.isConfigurable) {
1927
+ yield this._handleGeneratedArticleDirectly(quantity);
1928
+ }
1929
+ }
1930
+ else {
1931
+ const article = this._ioneControllerService.convertArticleFullObjectToArticleExtended(this.article);
1932
+ this._appEventService.onAddToCart.next({ article: article, quantity: quantity });
1933
+ }
1808
1934
  }
1809
1935
  });
1810
1936
  }
@@ -1813,6 +1939,21 @@ class ProductAddtocartComponent {
1813
1939
  this._appEventService.onAddToQuote.next(yield this._getJSONFromArticleObject({ article: this.article, quantity: quantity }));
1814
1940
  });
1815
1941
  }
1942
+ _handleGeneratedArticleDirectly(quantity) {
1943
+ return __awaiter(this, void 0, void 0, function* () {
1944
+ const generatedGoodId = yield this._getGeneratedArtDirectly(this.article.goodId);
1945
+ if (generatedGoodId) {
1946
+ const articleFull = yield this._productConnectorAdapterService.getArticleFullObject(generatedGoodId, true);
1947
+ const article = this._ioneControllerService.convertArticleFullObjectToArticleExtended(articleFull);
1948
+ this._appEventService.onAddToCart.next({ article: article, quantity: quantity });
1949
+ }
1950
+ });
1951
+ }
1952
+ _getGeneratedArtDirectly(goodId) {
1953
+ return __awaiter(this, void 0, void 0, function* () {
1954
+ return yield this._ioneControllerService.getGeneratedArtDirectly(goodId, true);
1955
+ });
1956
+ }
1816
1957
  _getJSONFromArticleObject(article) {
1817
1958
  return __awaiter(this, void 0, void 0, function* () {
1818
1959
  const configuratorStatistics = new ConfiguratorStatisticsEnvironment();
@@ -1825,11 +1966,6 @@ class ProductAddtocartComponent {
1825
1966
  return yield this._ioneControllerService.getJsonArticleFlatTree(article.article.goodId, article.article.goodType, article.quantity, !!this.externalSource, true, configuratorStatistics);
1826
1967
  });
1827
1968
  }
1828
- _getGeneratedArtDirectly(goodId) {
1829
- return __awaiter(this, void 0, void 0, function* () {
1830
- return yield this._ioneControllerService.getGeneratedArtDirectly(goodId, true);
1831
- });
1832
- }
1833
1969
  }
1834
1970
  ProductAddtocartComponent.decorators = [
1835
1971
  { type: Component, args: [{
@@ -2264,7 +2400,7 @@ class ProductInfoTabsComponent {
2264
2400
  this.updateHeight(tabIndex);
2265
2401
  }
2266
2402
  updateHeight(tabIndex) {
2267
- if (this.tabContent.nativeElement.children.length > 0) {
2403
+ if (this.tabContent && this.tabContent.nativeElement.children.length > 0) {
2268
2404
  if (this.tabContent.nativeElement.children[tabIndex] !== undefined) {
2269
2405
  this.activeTabHeight = this.tabContent.nativeElement.children[tabIndex].offsetHeight;
2270
2406
  }
@@ -3364,5 +3500,5 @@ IoneProductModule.decorators = [
3364
3500
  * Generated bundle index. Do not edit.
3365
3501
  */
3366
3502
 
3367
- export { IoneProductComponent, IoneProductModule, ProductConnectorAdapterService, ProductConnectorService, ProductEventService, ProductExternalSourceComponent, ProductExternalSourceModule, ProductSettingsService, Version, ProductPageModule as ɵa, ProductSelectorTypeModule as ɵb, ProductInfoTabsModule as ɵba, ProductAdditionalInfoModule as ɵbb, ProductAdditionalInfoComponent as ɵbc, ProductPropertiesModule as ɵbd, ProductPropertiesComponent as ɵbe, ProductDocumentModule as ɵbf, ProductDocumentsComponent as ɵbg, ProductSymbolsModule as ɵbh, ProductSymbolsComponent as ɵbi, ProductInfoTabsComponent as ɵbj, ProductDialogModule as ɵbk, ProductDialogComponent as ɵbl, RenderCarouselModule as ɵbm, RenderCarouselComponent as ɵbn, ProductPageComponent as ɵbo, ProductHdModule as ɵbp, ProductHdComponent as ɵbq, ProductScriptLoaderService as ɵbr, PipeModule as ɵc, LocalizePipe as ɵd, DictionaryService as ɵe, JsonUtilsService as ɵf, ProductSelectorTypeComponent as ɵg, IconCacheService as ɵh, ImageCarouselModule as ɵi, ImageCarouselComponent as ɵj, ProductDescriptionModule as ɵk, ProductDescriptionComponent as ɵl, ProductAdditionalDescriptionModule as ɵm, ProductAdditionalDescriptionComponent as ɵn, ProductPriceModule as ɵo, ProductPriceComponent as ɵp, ProductAddtocartModule as ɵq, ProductAddtocartComponent as ɵr, ProductRelatedModule as ɵs, HeaderModule as ɵt, HeaderComponent as ɵu, ProductRelatedComponent as ɵv, ProductStockModule as ɵw, ProductStockComponent as ɵx, ProductDeliveryModule as ɵy, ProductDeliveryComponent as ɵz };
3503
+ export { IoneProductComponent, IoneProductModule, ProductConnectorAdapterService, ProductConnectorService, ProductEventService, ProductExternalSourceComponent, ProductExternalSourceModule, ProductSettingsService, Version, ProductPageModule as ɵa, ProductSelectorTypeModule as ɵb, ProductInfoTabsModule as ɵba, ProductAdditionalInfoModule as ɵbb, ProductAdditionalInfoComponent as ɵbc, ProductPropertiesModule as ɵbd, ProductPropertiesComponent as ɵbe, ProductDocumentModule as ɵbf, ProductDocumentsComponent as ɵbg, ProductSymbolsModule as ɵbh, ProductSymbolsComponent as ɵbi, ProductInfoTabsComponent as ɵbj, ProductDialogModule as ɵbk, ProductDialogComponent as ɵbl, RenderCarouselModule as ɵbm, RenderCarouselComponent as ɵbn, ProductPageComponent as ɵbo, ProductHdModule as ɵbp, ProductHdComponent as ɵbq, ProductScriptLoaderService as ɵbr, LocalStorageService as ɵbs, PipeModule as ɵc, LocalizePipe as ɵd, DictionaryService as ɵe, JsonUtilsService as ɵf, ProductSelectorTypeComponent as ɵg, IconCacheService as ɵh, ImageCarouselModule as ɵi, ImageCarouselComponent as ɵj, ProductDescriptionModule as ɵk, ProductDescriptionComponent as ɵl, ProductAdditionalDescriptionModule as ɵm, ProductAdditionalDescriptionComponent as ɵn, ProductPriceModule as ɵo, ProductPriceComponent as ɵp, ProductAddtocartModule as ɵq, ProductAddtocartComponent as ɵr, ProductRelatedModule as ɵs, HeaderModule as ɵt, HeaderComponent as ɵu, ProductRelatedComponent as ɵv, ProductStockModule as ɵw, ProductStockComponent as ɵx, ProductDeliveryModule as ɵy, ProductDeliveryComponent as ɵz };
3368
3504
  //# sourceMappingURL=colijnit-product.js.map