kitchen-simulator 5.0.0-test.13 → 5.0.0-test.14

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.
@@ -0,0 +1,710 @@
1
+ import Dialog from '@material-ui/core/Dialog';
2
+ import axios from 'axios';
3
+ import convert from 'convert-units';
4
+ import { Plugins as PlannerPlugins } from './index';
5
+ import PropTypes from 'prop-types';
6
+ import React, { Component } from 'react';
7
+ import ReactGA from 'react-ga4';
8
+ import { hotjar } from 'react-hotjar';
9
+ import { connect } from 'react-redux';
10
+ import { bindActionCreators } from 'redux';
11
+ import styled from 'styled-components';
12
+ import SnackBar from './components/atoms/Snackbar';
13
+ import * as constants from './constants';
14
+ import {
15
+ BG_COLOR_HOVER,
16
+ CLIENTS_NAME,
17
+ DEFAULT_FONT_FAMILY,
18
+ PRIMARY_GREEN_COLOR,
19
+ SECONDARY_PURPLE_COLOR,
20
+ TEXT_COLOR_NEUTRAL_1
21
+ } from './constants';
22
+ import { base64Decode, getPath } from './utils/helper';
23
+ import actions from './actions/export';
24
+ import Catalog from './catalog/catalog';
25
+ import { Content } from './components/_export';
26
+ import jwtService from './components/login/jwtService';
27
+ import './styles/export';
28
+ import Translator from './translator/translator';
29
+ import { objectsMap } from './utils/objects-utils';
30
+ import { VERSION } from './version';
31
+
32
+ const AWS = require('aws-sdk');
33
+
34
+ const StyledDialog = styled(Dialog)`
35
+ .MuiDialog-paperWidthSm {
36
+ border-radius: 10px;
37
+ }
38
+ `;
39
+
40
+ export const StyledDialogContent = styled.span`
41
+ font-family: ${DEFAULT_FONT_FAMILY};
42
+ color: ${TEXT_COLOR_NEUTRAL_1};
43
+ padding: 10px 30px;
44
+ padding-top: 30px;
45
+ `;
46
+
47
+ export const StyledDialogAction = styled.div`
48
+ display: flex;
49
+ justify-content: flex-end;
50
+ padding: 15px 30px 25px;
51
+ `;
52
+
53
+ export const StyledButton = styled.div`
54
+ padding: 10px 20px;
55
+ cursor: pointer;
56
+ margin-right: 10px;
57
+ color: ${SECONDARY_PURPLE_COLOR};
58
+ font-weight: bold;
59
+ font-family: ${DEFAULT_FONT_FAMILY};
60
+ font-size: 16px;
61
+ border-radius: 20px;
62
+ :hover {
63
+ background-color: ${BG_COLOR_HOVER};
64
+ }
65
+ `;
66
+
67
+ const s3 = new AWS.S3({
68
+ accessKeyId: process.env.REACT_APP_AWS_ID,
69
+ secretAccessKey: process.env.REACT_APP_AWS_SECRET
70
+ });
71
+
72
+ const toolbarW = 0;
73
+ const sidebarW = 250;
74
+ const footerBarH = 20;
75
+
76
+ const wrapperStyle = {
77
+ display: 'flex',
78
+ flexFlow: 'row nowrap'
79
+ };
80
+
81
+ class KitchenConfigurator extends Component {
82
+ constructor(props) {
83
+ super(props);
84
+
85
+ // utm tracking
86
+ const utmDetailParams = new URLSearchParams(
87
+ this.props.location && this.props.location.search
88
+ );
89
+
90
+ const utmStrEncoded = utmDetailParams.get('details');
91
+ let utmRequestData = null;
92
+ if (utmStrEncoded) {
93
+ try {
94
+ utmRequestData = JSON.parse(base64Decode(utmStrEncoded));
95
+ utmRequestData = JSON.parse(utmRequestData?.utm);
96
+ } catch (e) {
97
+ console.error('Cannot parse utm parameter: ', error);
98
+ utmRequestData = null;
99
+ }
100
+ }
101
+
102
+ this.state = {
103
+ savePopupVisible: false,
104
+ quotePopupVisible: false,
105
+ assistPopupVisible: false,
106
+ newProjectPopupVisible: false,
107
+ isModalVisible: false,
108
+ submitPromptVisible: false,
109
+ stateSubmitType: constants.SUBMIT_REQUEST_ASSIST,
110
+ savePromptVisible: false,
111
+ isShowProperty: true,
112
+ submitTosave: false,
113
+ signOpen: false,
114
+ myProjectsOpen: false,
115
+ myProjectsToLogin: false,
116
+ downloadPopupVisible: false,
117
+
118
+ // For Toolbar Item
119
+ toolbar: '',
120
+ reviewQuotePopupOpened: false,
121
+ floorOpened: false,
122
+ cabinetOpened: false,
123
+ applianceOpened: false,
124
+ finishingOpened: false,
125
+ doorStyleOpen: false,
126
+ wizardStepOpend: false,
127
+ tutorialMouseEventsAdd: false,
128
+ replaceCabinetFlag: false,
129
+ isSnackBarOpen: false,
130
+ isSnackBar1Open: false,
131
+ redirectURL: '',
132
+ snackBarMessage: '',
133
+ isSaved: false,
134
+ isLeaving: false
135
+ };
136
+
137
+ // For UTM tracking
138
+ this.utm = {
139
+ utm_source: utmRequestData?.source || 'source',
140
+ utm_medium: utmRequestData?.medium || 'medium',
141
+ utm_campaign: utmRequestData?.campaign || 'campaign',
142
+ utm_term: utmRequestData?.term || 'term',
143
+ utm_content: utmRequestData?.content || 'content',
144
+ gclid: utmRequestData?.gclid || 'gclid',
145
+ msclkid: utmRequestData?.msclkid || 'msclkid',
146
+ fbclid: utmRequestData?.fbclid || 'fbclid',
147
+ ttclid: utmRequestData?.ttclid || 'ttclid'
148
+ };
149
+
150
+ this.jwtCheck();
151
+
152
+ this.openFloor = this.openFloor.bind(this);
153
+ this.openCabinet = this.openCabinet.bind(this);
154
+ this.openFinishing = this.openFinishing.bind(this);
155
+ this.openAppliance = this.openAppliance.bind(this);
156
+ this.toggleDoorStyle = this.toggleDoorStyle.bind(this);
157
+ this.onReviewQuoteClicked = this.onReviewQuoteClicked.bind(this);
158
+ this.closeFloorTB = this.closeFloorTB.bind(this);
159
+ this.closeCabinetTB = this.closeCabinetTB.bind(this);
160
+ this.closeFinishingTB = this.closeFinishingTB.bind(this);
161
+ this.closeApplianceTB = this.closeApplianceTB.bind(this);
162
+ this.setToolbar = this.setToolbar.bind(this);
163
+ this.replaceCabinet = this.replaceCabinet.bind(this);
164
+ this.setSubmitToSave = this.setSubmitToSave.bind(this);
165
+ this.setSignOpen = this.setSignOpen.bind(this);
166
+ this.setMyProjectsOpen = this.setMyProjectsOpen.bind(this);
167
+ this.setMyProjectsToLogin = this.setMyProjectsToLogin.bind(this);
168
+ this.setDownloadPopupVisible = this.setDownloadPopupVisible.bind(this);
169
+ this.neverShowInput = React.createRef(null);
170
+ this.setShowProperty = this.setShowProperty.bind(this);
171
+ }
172
+
173
+ // Toolbar control functions
174
+
175
+ setToolbar(toolBarKey) {
176
+ this.setState({ toolbar: toolBarKey });
177
+ }
178
+
179
+ setShowProperty(value) {
180
+ this.setState({ isShowProperty: value });
181
+ }
182
+
183
+ setMyProjectsOpen(value) {
184
+ this.setState({ myProjectsOpen: value });
185
+ this.setState({ signOpen: false });
186
+ this.setState({ wizardStepOpend: false });
187
+ }
188
+
189
+ setMyProjectsToLogin(value) {
190
+ this.setState({ myProjectsToLogin: value });
191
+ }
192
+
193
+ setDownloadPopupVisible(value) {
194
+ this.setState({ reviewQuotePopupOpened: false });
195
+ this.setState({ savePopupVisible: false });
196
+ this.setState({ quotePopupVisible: false });
197
+ this.setState({ submitTosave: false });
198
+ this.setState({ assistPopupVisible: false });
199
+ this.setState({ newProjectPopupVisible: false });
200
+ this.setState({ downloadPopupVisible: value });
201
+ }
202
+
203
+ setSubmitToSave(value) {
204
+ this.setState({ submitTosave: value });
205
+ }
206
+
207
+ setSignOpen(value) {
208
+ this.setState({ wizardStepOpend: false });
209
+ this.setState({ myProjectsOpen: false });
210
+ this.setState({ signOpen: value });
211
+ }
212
+
213
+ openFloor() {
214
+ this.setState({ floorOpened: true });
215
+ document.getElementById(
216
+ 'make_floorplan_inactive'
217
+ ).parentElement.parentElement.style.zIndex = 999;
218
+ }
219
+
220
+ openCabinet() {
221
+ this.setState({ cabinetOpened: true });
222
+ document.getElementById(
223
+ 'add_cabinets_inactive'
224
+ ).parentElement.parentElement.style.zIndex = 999;
225
+ }
226
+
227
+ toggleDoorStyle(visible) {
228
+ this.setState({ doorStyleOpen: visible });
229
+ document.getElementById(
230
+ 'select_doorstyle_inactive'
231
+ ).parentElement.parentElement.style.zIndex = visible ? 999 : 6;
232
+ }
233
+
234
+ replaceCabinet(value) {
235
+ this.setState({ replaceCabinetFlag: value });
236
+ }
237
+
238
+ openAppliance() {
239
+ this.setState({ applianceOpened: true });
240
+ document.getElementById(
241
+ 'add_appliances_inactive'
242
+ ).parentElement.parentElement.style.zIndex = 999;
243
+ }
244
+
245
+ openFinishing() {
246
+ this.setState({ finishingOpened: true });
247
+ document.getElementById(
248
+ 'finishing_touches_inactive'
249
+ ).parentElement.parentElement.style.zIndex = 999;
250
+ }
251
+
252
+ onReviewQuoteClicked(visible) {
253
+ this.setState({ reviewQuotePopupOpened: visible });
254
+ document.getElementById(
255
+ 'review_quote_inactive'
256
+ ).parentElement.parentElement.style.zIndex = visible ? 999 : 6;
257
+ }
258
+
259
+ closeFloorTB() {
260
+ this.setState({ floorOpened: false });
261
+ document.getElementById('make_floorplan_inactive') &&
262
+ (document.getElementById(
263
+ 'make_floorplan_inactive'
264
+ ).parentElement.parentElement.style.zIndex = 6);
265
+ }
266
+
267
+ closeCabinetTB() {
268
+ this.setState({ cabinetOpened: false });
269
+ document.getElementById(
270
+ 'add_cabinets_inactive'
271
+ ).parentElement.parentElement.style.zIndex = 6;
272
+ }
273
+
274
+ closeFinishingTB() {
275
+ this.setState({ finishingOpened: false });
276
+ document.getElementById(
277
+ 'finishing_touches_inactive'
278
+ ).parentElement.parentElement.style.zIndex = 6;
279
+ }
280
+
281
+ closeApplianceTB() {
282
+ this.setState({ applianceOpened: false });
283
+ document.getElementById(
284
+ 'add_appliances_inactive'
285
+ ).parentElement.parentElement.style.zIndex = 6;
286
+ }
287
+
288
+ closeDoorstyle() {
289
+ this.setState({});
290
+ document.getElementById(
291
+ 'select_doorstyle_inactive'
292
+ ).parentElement.parentElement.style.zIndex = 6;
293
+ }
294
+ closeReviewQuote() {
295
+ this.setState({});
296
+ document.getElementById(
297
+ 'review_quote_inactive'
298
+ ).parentElement.parentElement.style.zIndex = 6;
299
+ }
300
+
301
+ jwtCheck() {
302
+ jwtService.on('onAutoLogin', () => {
303
+ // this.props.showMessage({message: 'Logging in with JWT'});
304
+
305
+ /**
306
+ * Sign in and retrieve user data from Api
307
+ */
308
+ jwtService
309
+ .signInWithToken()
310
+ .then(user => {
311
+ //this.props.userActions.setUserData(user);
312
+ this.props.userActions.login(
313
+ user.id,
314
+ user.role,
315
+ jwtService.getAccessToken(),
316
+ this.utm
317
+ );
318
+ //this.props.showMessage(option)
319
+ //this.props.showMessage({message: 'Logged in with token data', variant: 'success'});
320
+ //alert('Logged in with token data');
321
+ })
322
+ .catch(error => {
323
+ //this.props.showMessage({message: error});
324
+ this.setState({
325
+ isSnackBarOpen: true,
326
+ snackBarMessage: error
327
+ });
328
+ });
329
+ });
330
+
331
+ jwtService.on('onAutoLogout', message => {
332
+ if (message) {
333
+ //this.props.showMessage({message, variant: 'error'});
334
+ }
335
+ this.props.userActions.logout();
336
+ });
337
+
338
+ jwtService.init();
339
+ }
340
+
341
+ getChildContext() {
342
+ return {
343
+ ...objectsMap(actions, actionNamespace => this.props[actionNamespace]),
344
+ translator: this.props.translator,
345
+ catalog: this.props.catalog
346
+ };
347
+ }
348
+
349
+ saveProjectToStorage() {
350
+ let { state, stateExtractor } = this.props;
351
+ const extractedState = stateExtractor(state);
352
+ const projectData = JSON.stringify(extractedState.get('scene').toJS());
353
+ sessionStorage.setItem(window.location.href, projectData);
354
+ }
355
+
356
+ handleBeforeUnload = e => {
357
+ const areas = this.props
358
+ .stateExtractor(this.props.state)
359
+ .getIn([
360
+ 'scene',
361
+ 'layers',
362
+ this.props.stateExtractor(this.props.state).scene.selectedLayer,
363
+ 'areas'
364
+ ]);
365
+
366
+ if (!this.state.isSaved && areas.size > 0) {
367
+ setTimeout(() => {
368
+ this.setState({ savePromptVisible: true, isLeaving: true });
369
+ }, 500);
370
+
371
+ this.saveProjectToStorage();
372
+
373
+ // This line is required to trigger the browser confirmation dialog
374
+ e.preventDefault();
375
+ e.returnValue = '';
376
+ return '';
377
+ }
378
+ };
379
+
380
+ componentDidMount() {
381
+ ReactGA.send({ hitType: 'pageview', page: getPath() });
382
+ hotjar.event && hotjar.event(`pageview:${getPath()}`);
383
+
384
+ window.addEventListener('beforeunload', this.handleBeforeUnload);
385
+
386
+ console.log('context =>', this.context);
387
+
388
+ window.forRedo = [];
389
+ let { store } = this.context;
390
+ let { projectActions, catalog, stateExtractor, state, plugins } =
391
+ this.props;
392
+
393
+ projectActions.initCatalog(catalog);
394
+
395
+ let { match } = this.props;
396
+
397
+ if (sessionStorage.getItem(window.location.href)) {
398
+ const jsonData = sessionStorage.getItem(window.location.href);
399
+ projectActions.loadProject(JSON.parse(jsonData), this.props.categoryData);
400
+ sessionStorage.removeItem(window.location.href);
401
+ return;
402
+ }
403
+
404
+ if (match && match.params.pid === undefined) {
405
+ let newplugins = [
406
+ ...plugins,
407
+ PlannerPlugins.Autosave('KitchenConfigurator_v0', false)
408
+ ];
409
+ newplugins.forEach(newplugin => newplugin(store, stateExtractor));
410
+ projectActions.newProject();
411
+ sessionStorage.setItem('projectTitle', 'Untitled');
412
+ projectActions.rename('Untitled');
413
+ sessionStorage.removeItem('projectId');
414
+ sessionStorage.removeItem('email');
415
+ sessionStorage.removeItem('firstName');
416
+ sessionStorage.removeItem('lastName');
417
+ sessionStorage.removeItem('usedObjects');
418
+ return;
419
+ }
420
+
421
+ if (match && match.params.pid !== undefined) {
422
+ if (match.params.pid === 'new') {
423
+ projectActions.newProject();
424
+ sessionStorage.setItem('projectTitle', 'Untitled');
425
+ projectActions.rename('Untitled');
426
+ sessionStorage.removeItem('projectId');
427
+ sessionStorage.removeItem('email');
428
+ sessionStorage.removeItem('firstName');
429
+ sessionStorage.removeItem('lastName');
430
+ sessionStorage.removeItem('usedObjects');
431
+ } else {
432
+ axios
433
+ .post(`${constants.API_SERVER_URL}/api/project/loadPidProject`, {
434
+ pid: match.params.pid,
435
+ visualizerName: sessionStorage.getItem('visualizerName')
436
+ })
437
+ .then(async response => {
438
+ const { projectElement } = response.data;
439
+ if (projectElement.length === 0) return;
440
+ sessionStorage.setItem('projectTitle', projectElement[0].title);
441
+ projectActions.rename(projectElement[0].title);
442
+ sessionStorage.setItem('projectId', projectElement[0].id);
443
+ sessionStorage.setItem('email', projectElement[0].email);
444
+ sessionStorage.setItem('firstName', projectElement[0].firstName);
445
+ sessionStorage.setItem('lastName', projectElement[0].lastName);
446
+ sessionStorage.setItem('phone', projectElement[0].phone);
447
+ let jsonData;
448
+ if (projectElement[0].project_data) {
449
+ jsonData = JSON.parse(projectElement[0].project_data);
450
+ } else {
451
+ try {
452
+ jsonData = await axios.post(
453
+ `${constants.API_SERVER_URL}/api/project/loadPidData`,
454
+ { pid: match.params.pid }
455
+ ).data.data;
456
+ } catch (err) {
457
+ this.setState({
458
+ isSnackBarOpen: true,
459
+ snackBarMessage: err
460
+ });
461
+ }
462
+ }
463
+ jsonData.isLoadingCabinet = false;
464
+ projectActions.loadProject(jsonData, this.props.categoryData);
465
+ });
466
+ }
467
+
468
+ sessionStorage.removeItem('user_type');
469
+ sessionStorage.removeItem('project_type');
470
+ sessionStorage.removeItem('project_timeline');
471
+ }
472
+ }
473
+
474
+ componentWillUnmount() {
475
+ window.addEventListener('beforeunload', this.handleBeforeUnload);
476
+ window.onbeforeunload = null;
477
+ }
478
+
479
+ componentWillMount() {}
480
+
481
+ componentWillReceiveProps(nextProps) {
482
+ let { stateExtractor, state, projectActions, catalog } = nextProps;
483
+ let plannerState = stateExtractor(state);
484
+ let catalogReady = plannerState.getIn(['catalog', 'ready']);
485
+ if (!catalogReady) {
486
+ projectActions.initCatalog(catalog);
487
+ }
488
+ }
489
+
490
+ isProjectEmpty(scene) {
491
+ let { layers, selectedLayer } = scene;
492
+ let layer = layers.get(selectedLayer);
493
+ return (
494
+ layer.areas.size +
495
+ layer.lines.size +
496
+ layer.holes.size +
497
+ layer.items.size ===
498
+ 0
499
+ );
500
+ }
501
+
502
+ render() {
503
+ let { width, height, state, stateExtractor, ...props } = this.props;
504
+ let {
505
+ savePopupVisible,
506
+ quotePopupVisible,
507
+ assistPopupVisible,
508
+ signOpen,
509
+ myProjectsOpen
510
+ } = this.state;
511
+ let contentW = width - toolbarW;
512
+ let categoryData = this.props.categoryData;
513
+ // console.log(categoryData);
514
+ // let contentW = width - toolbarW - sidebarW;
515
+ // let toolbarH = height - footerBarH;
516
+ // let contentH = height - footerBarH;
517
+ // let sidebarH = height - footerBarH;
518
+ let toolbarH = height;
519
+ let contentH = height;
520
+ let sidebarH = height;
521
+ let headerW = width;
522
+ let headerH = 60;
523
+
524
+ let extractedState = stateExtractor(state);
525
+ let doorStyle = extractedState.get('doorStyle');
526
+ if (
527
+ extractedState.getIn([
528
+ 'scene',
529
+ 'layers',
530
+ extractedState.scene.selectedLayer,
531
+ 'doorStyle'
532
+ ]) !== undefined &&
533
+ extractedState.getIn([
534
+ 'scene',
535
+ 'layers',
536
+ extractedState.scene.selectedLayer,
537
+ 'doorStyle'
538
+ ]) !== null
539
+ ) {
540
+ const extractedStateData = extractedState.getIn([
541
+ 'scene',
542
+ 'layers',
543
+ extractedState.scene.selectedLayer,
544
+ 'doorStyle'
545
+ ]);
546
+ let doorIdAvailable = false;
547
+ if (
548
+ this.props.categoryData.doorStyles &&
549
+ this.props.categoryData.doorStyles.items
550
+ ) {
551
+ this.props.categoryData.doorStyles.items.find(category => {
552
+ doorIdAvailable = category.items.find(style => {
553
+ let item = style.items.find(it => it.id === extractedStateData.id);
554
+ if (item) {
555
+ colorItem = item;
556
+ return true;
557
+ } else {
558
+ return false;
559
+ }
560
+ });
561
+ });
562
+ }
563
+
564
+ if (doorIdAvailable) doorStyle = extractedStateData;
565
+ }
566
+
567
+ let firstVisit =
568
+ this.state.wizardStepOpend && this.isProjectEmpty(extractedState.scene);
569
+ let allVisible = firstVisit || signOpen || myProjectsOpen;
570
+
571
+ let _scene = extractedState.getIn(['scene']);
572
+ let len = convert(_scene.width).from(_scene.unit).to('cm');
573
+ let _viewer2D = extractedState.getIn(['viewer2D']);
574
+ if (_viewer2D.size > 0) {
575
+ let scaleX = (width / len) * 3;
576
+ let scaleY = (height / len) * 3;
577
+ let scale = scaleX > scaleY ? scaleY : scaleX;
578
+ let _e = width - len * scale,
579
+ _f = height - len * scale;
580
+ let viewer = _viewer2D.toJS();
581
+ if (viewer.e === 0 && viewer.f === 0) {
582
+ _viewer2D = _viewer2D.merge({
583
+ e: viewer.viewerWidth / 2 - viewer.SVGWidth / 2,
584
+ f: viewer.viewerHeight / 2 - viewer.SVGHeight / 2,
585
+ a: 0.99,
586
+ d: 0.99
587
+ });
588
+ }
589
+ }
590
+ extractedState = extractedState.merge({
591
+ viewer2D: _viewer2D
592
+ });
593
+
594
+ return (
595
+ <section>
596
+ <SnackBar
597
+ isOpen={this.state.isSnackBarOpen}
598
+ message={this.state.snackBarMessage}
599
+ handleClose={() =>
600
+ this.setState({ isSnackBarOpen: false, snackBarMessage: '' })
601
+ }
602
+ autoHideDuration={10000}
603
+ />
604
+ <SnackBar
605
+ style={{ marginTop: this.state.isSnackBarOpen ? 75 : 'unset' }}
606
+ isOpen={this.state.isSnackBar1Open}
607
+ message={`The items in your design have been added to your shopping cart at ${CLIENTS_NAME[sessionStorage.getItem('visualizerName')]}. <br />Please log in with the same email address.`}
608
+ autoHideDuration={20000}
609
+ action={
610
+ <div>
611
+ <a
612
+ href={this.state.redirectURL}
613
+ target="_blank"
614
+ style={{
615
+ fontFamily: DEFAULT_FONT_FAMILY,
616
+ color: PRIMARY_GREEN_COLOR,
617
+ fontWeight: 700,
618
+ marginRight: 10
619
+ }}
620
+ >
621
+ View Cart
622
+ </a>
623
+ <img
624
+ onClick={() => this.setState({ isSnackBar1Open: false })}
625
+ style={{ float: 'right', height: 24, cursor: 'pointer' }}
626
+ src="/assets/img/svg/close.svg"
627
+ />
628
+ </div>
629
+ }
630
+ />
631
+ <div style={{ ...wrapperStyle, height }}>
632
+ <Content
633
+ width={contentW}
634
+ height={contentH}
635
+ catalog={this.props.catalog}
636
+ state={extractedState}
637
+ toolBar={this.state.toolbar}
638
+ setToolbar={this.setToolbar}
639
+ replaceCabinet={this.replaceCabinet}
640
+ keyDownEnable={
641
+ !savePopupVisible && !quotePopupVisible && !assistPopupVisible
642
+ }
643
+ {...props}
644
+ onWheel={event => event.preventDefault()}
645
+ />
646
+ </div>
647
+ </section>
648
+ );
649
+ }
650
+ }
651
+
652
+ KitchenConfigurator.propTypes = {
653
+ translator: PropTypes.instanceOf(Translator),
654
+
655
+ catalog: PropTypes.instanceOf(Catalog),
656
+ allowProjectFileSupport: PropTypes.bool,
657
+ plugins: PropTypes.arrayOf(PropTypes.func),
658
+ autosaveKey: PropTypes.string,
659
+ autosaveDelay: PropTypes.number,
660
+ width: PropTypes.number.isRequired,
661
+ height: PropTypes.number.isRequired,
662
+ stateExtractor: PropTypes.func.isRequired,
663
+ toolbarButtons: PropTypes.array,
664
+ sidebarComponents: PropTypes.array,
665
+ footerbarComponents: PropTypes.array,
666
+ customContents: PropTypes.object,
667
+ softwareSignature: PropTypes.string,
668
+ configData: PropTypes.object
669
+ };
670
+
671
+ KitchenConfigurator.contextTypes = {
672
+ store: PropTypes.object.isRequired
673
+ };
674
+
675
+ KitchenConfigurator.childContextTypes = {
676
+ ...objectsMap(actions, () => PropTypes.object),
677
+ translator: PropTypes.object,
678
+ catalog: PropTypes.object
679
+ };
680
+
681
+ KitchenConfigurator.defaultProps = {
682
+ translator: new Translator(),
683
+ catalog: new Catalog(),
684
+ plugins: [],
685
+ allowProjectFileSupport: true,
686
+ softwareSignature: `KitchenConfigurator ${VERSION}`,
687
+ toolbarButtons: [],
688
+ sidebarComponents: [],
689
+ footerbarComponents: [],
690
+ customContents: {},
691
+ configData: {}
692
+ };
693
+
694
+ //redux connect
695
+ function mapStateToProps(reduxState) {
696
+ return {
697
+ state: reduxState
698
+ };
699
+ }
700
+
701
+ function mapDispatchToProps(dispatch) {
702
+ return objectsMap(actions, actionNamespace =>
703
+ bindActionCreators(actions[actionNamespace], dispatch)
704
+ );
705
+ }
706
+
707
+ export default connect(
708
+ mapStateToProps,
709
+ mapDispatchToProps
710
+ )(KitchenConfigurator);