@imposium-hub/components 1.42.5 → 1.43.1

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.
package/Entry.ts CHANGED
@@ -101,6 +101,8 @@ import assetTags from './redux/reducers/asset-tags';
101
101
  import assetUploads from './redux/reducers/asset-uploads';
102
102
  import selectedAssets from './redux/reducers/selected-assets';
103
103
  import assetActions from './redux/actions/asset-list';
104
+ import activeBatch from './redux/reducers/active-batch';
105
+ import batchActions from './redux/actions/active-batch';
104
106
  /*
105
107
  Statics / Services
106
108
  */
@@ -222,6 +224,9 @@ export {
222
224
  addAssetTagToList,
223
225
  assetTags,
224
226
  assetActions,
227
+
228
+ activeBatch,
229
+ batchActions,
225
230
 
226
231
  AuthService,
227
232
  IIdentity,
@@ -109,7 +109,6 @@ let doubleClickTimeout : number;
109
109
  const DataTable : React.FC<IDataTableProps> = (props : IDataTableProps) => {
110
110
  const wrapperRef = React.useRef(null);
111
111
  const activeRowRef = React.useRef(null);
112
-
113
112
  const [didMount, setDidMount] = React.useState(false);
114
113
  const [data, setData] = React.useState([]);
115
114
  const [columns, setColumns] = React.useState([]);
@@ -60,6 +60,9 @@ interface IPublishWizardState {
60
60
  accessKey : string;
61
61
  credentials : ICredential[];
62
62
  done : boolean;
63
+ error : boolean;
64
+ next : boolean;
65
+ nextStep : boolean;
63
66
  }
64
67
 
65
68
  interface IBigButtonProps {
@@ -78,6 +81,7 @@ interface IBigLinkProps {
78
81
  }
79
82
 
80
83
  class PublishWizard extends React.PureComponent<IPublishWizardProps, IPublishWizardState> {
84
+ public emailWorkflow : any;
81
85
  private readonly hiddenFileInputRef : any;
82
86
  constructor(props) {
83
87
  super(props);
@@ -92,7 +96,11 @@ class PublishWizard extends React.PureComponent<IPublishWizardProps, IPublishWiz
92
96
  accessKey: null,
93
97
  credentials: [],
94
98
  done: false,
99
+ error: false,
100
+ next: false,
101
+ nextStep: false,
95
102
  };
103
+ this.emailWorkflow = React.createRef();
96
104
  this.hiddenFileInputRef = React.createRef();
97
105
  }
98
106
 
@@ -216,8 +224,8 @@ class PublishWizard extends React.PureComponent<IPublishWizardProps, IPublishWiz
216
224
 
217
225
  private renderLowerButtons() {
218
226
 
219
- const {screenIndex, done} = this.state;
220
- const {publishing} = this.props;
227
+ const { screenIndex, done, error, next } = this.state;
228
+ const { publishing } = this.props;
221
229
 
222
230
  const lowerButtons = [];
223
231
 
@@ -246,26 +254,47 @@ class PublishWizard extends React.PureComponent<IPublishWizardProps, IPublishWiz
246
254
  </Button>);
247
255
  } else {
248
256
  // display button when emailworkflow downloading state is true to close the modal
249
- if (done) {
257
+ if (done || error) {
250
258
  lowerButtons.push(<Button
251
- tooltip = {copy.publish.btnFinished}
259
+ tooltip = { error ? copy.publish.btnCancel : copy.publish.btnFinished }
252
260
  size={'large'}
253
261
  key = 'btn-finish'
254
262
  onClick={() => this.props.onClose()}
255
263
  color = 'primary'>
256
- {copy.publish.btnFinished}
264
+ { error ? copy.publish.btnCancel : copy.publish.btnFinished }
257
265
  </Button>);
258
266
  }
267
+
259
268
  const backIndex = (screenIndex === 1) ? 0 : 1;
269
+
260
270
  // back button
261
271
  lowerButtons.push(<Button
262
272
  tooltip = {copy.publish.btnBack}
263
273
  size={'large'}
264
274
  key = 'btn-back'
265
- onClick={() => this.setState({screenIndex: backIndex})}
275
+ onClick={() => this.setState({
276
+ screenIndex: backIndex,
277
+ next: false,
278
+ nextStep: false,
279
+ error: false,
280
+ done: false,
281
+ })}
266
282
  color = 'primary'>
267
283
  {copy.publish.btnBack}
268
284
  </Button>);
285
+
286
+ // reimport after column align
287
+ if ( error ) {
288
+ lowerButtons.push(<Button
289
+ tooltip = {copy.publish.btnNext}
290
+ size={'large'}
291
+ key = 'btn-next'
292
+ color = 'primary'
293
+ disabled = {!next}
294
+ onClick={() => this.nextClickHandler()}>
295
+ {copy.publish.btnNext}
296
+ </Button>);
297
+ }
269
298
  }
270
299
 
271
300
  return lowerButtons;
@@ -362,13 +391,30 @@ class PublishWizard extends React.PureComponent<IPublishWizardProps, IPublishWiz
362
391
  );
363
392
  }
364
393
 
394
+ private nextClickHandler = () => {
395
+ this.setState({nextStep: true});
396
+
397
+ if (this.state.screenIndex === 7) {
398
+ this.emailWorkflow.current.getWrappedInstance().proceedWithExport();
399
+ }
400
+ }
401
+
365
402
  private onDoneHandler = () => {
366
- this.setState({done: true});
403
+ this.setState({ done: true, error: false });
404
+ }
405
+
406
+ private onErrorHandler = () => {
407
+ this.setState({error: !this.state.error});
408
+ }
409
+
410
+ private onNextHandler = (val : boolean) => {
411
+ this.setState({next: val});
367
412
  }
368
413
 
369
414
  public render() {
370
415
  const {
371
416
  story,
417
+ project,
372
418
  api,
373
419
  handleError,
374
420
  createFreshBatch,
@@ -380,11 +426,13 @@ class PublishWizard extends React.PureComponent<IPublishWizardProps, IPublishWiz
380
426
  batchJobs
381
427
  } = this.props;
382
428
 
383
- const {screenIndex, status, selectedComposition, compositions, accessKey} = this.state;
429
+ const {screenIndex, status, selectedComposition, compositions, accessKey, error, nextStep} = this.state;
384
430
  const compName = compositions.find((comp) => {
385
431
  return comp.id === selectedComposition;
386
432
  })?.name || '';
387
433
 
434
+ const variables = (story) ? story.acts[project.actId].inventory : {};
435
+
388
436
  return (
389
437
  <div className='publish-wizard'>
390
438
  <div className = 'publish-wizard-header'>
@@ -401,7 +449,11 @@ class PublishWizard extends React.PureComponent<IPublishWizardProps, IPublishWiz
401
449
  isExport = {screenIndex === 7}
402
450
  api={api}
403
451
  story={story}
452
+ variables= {variables}
404
453
  onDone={this.onDoneHandler}
454
+ onError={this.onErrorHandler}
455
+ onNext={this.onNextHandler}
456
+ error={error}
405
457
  status={status}
406
458
  renderBatch={renderBatch}
407
459
  batchJobs={batchJobs}
@@ -413,6 +465,8 @@ class PublishWizard extends React.PureComponent<IPublishWizardProps, IPublishWiz
413
465
  getBatches={getBatches}
414
466
  getBatchExport={getBatchExport}
415
467
  importBatchFromCsv={importBatchFromCsv}
468
+ next={nextStep}
469
+ ref={this.emailWorkflow}
416
470
  />}
417
471
  {
418
472
  screenIndex === 5 &&
@@ -7,9 +7,14 @@ import { ExportToCsv } from 'export-to-csv';
7
7
  import { ICON_DOWNLOAD, ICON_UPLOAD } from '../../../constants/icons';
8
8
  import * as moment from 'moment';
9
9
  import { IImposiumAPI } from '../../../services/API';
10
+ import { bindActionCreators } from 'redux';
11
+ import { connect } from 'react-redux';
12
+ import SelectField from '../../select-field/SelectField';
13
+ import { updateAssociation, getBatch, setPage } from '../../../redux/actions/active-batch';
10
14
 
11
15
  interface IEmailWorkflowProps {
12
16
  story : any;
17
+ variables : any;
13
18
  createFreshBatch : (e : string) => any;
14
19
  getBatches : () => any;
15
20
  getBatchExport : (batchId : string) => any;
@@ -20,10 +25,19 @@ interface IEmailWorkflowProps {
20
25
  compositionId : string;
21
26
  compositionName : string;
22
27
  onDone : () => void;
28
+ onError : () => void;
29
+ error : boolean;
23
30
  api : IImposiumAPI;
24
31
  handleError : (e) => any;
25
32
  batchJobs : any;
26
33
  isExport ? : boolean;
34
+ updateAssociation : (api : IImposiumAPI, colIndex : number, newType : string, newAssociation : string) => any;
35
+ getBatch : (api : IImposiumAPI) => any;
36
+ activeBatch : any;
37
+ batchesList : any;
38
+ setPage : (page : number) => any;
39
+ onNext : ( val : boolean ) => void;
40
+ next : boolean;
27
41
  }
28
42
 
29
43
  interface IEmailWorkflowState {
@@ -32,6 +46,8 @@ interface IEmailWorkflowState {
32
46
  uploading : boolean;
33
47
  downloading : boolean;
34
48
  renderedBatch : boolean;
49
+ inventory : any[];
50
+ inventoryKeys : string[];
35
51
  missingColumns : string;
36
52
  isMissing : boolean;
37
53
  }
@@ -47,8 +63,9 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
47
63
  showTitle: false,
48
64
  useTextFile: false,
49
65
  useBom: false,
50
- useKeysAsHeaders: true,
66
+ useKeysAsHeaders: true
51
67
  };
68
+
52
69
  constructor(props) {
53
70
  super(props);
54
71
  this.state = {
@@ -57,29 +74,20 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
57
74
  downloading : false,
58
75
  selectedBatchId: '',
59
76
  renderedBatch: false,
77
+ inventory: [],
78
+ inventoryKeys: [],
60
79
  missingColumns: '',
61
80
  isMissing: false,
62
81
  };
63
82
  this.hiddenFileInputRef = React.createRef();
64
83
  }
65
84
 
66
- public componentDidUpdate() : void {
67
- const { batchJobs : { missing }} = this.props;
68
- if (missing.length >= 0 ) {
69
- const missingColumn = Object.keys(missing).map((m) => missing[m]);
70
- const showMissing = missingColumn.join();
71
- this.setState({
72
- uploadComplete: false,
73
- missingColumns: showMissing,
74
- isMissing: true,
75
- });
76
- }
85
+ public componentDidMount() : void {
86
+ this.getInventory();
77
87
  }
78
88
 
79
- public downloadSampleCsv() {
80
-
81
- const {name} = this.props.story;
82
- const {acts} = this.props.story;
89
+ private getInventory() {
90
+ const { acts } = this.props.story;
83
91
  const actsKeys : string[] = Object.keys(acts);
84
92
  let inventory : any = {};
85
93
 
@@ -88,6 +96,16 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
88
96
  });
89
97
 
90
98
  const inventoryKeys : string[] = Object.keys(inventory).sort();
99
+
100
+ this.setState({inventory});
101
+ this.setState({inventoryKeys});
102
+ }
103
+
104
+ public downloadSampleCsv() {
105
+
106
+ const { name } = this.props.story;
107
+ const { inventory, inventoryKeys } = this.state;
108
+
91
109
  const maskConfig : any[] = inventoryKeys.map((currKey : string) => ({
92
110
  id: currKey,
93
111
  name: inventory[currKey].name,
@@ -141,24 +159,48 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
141
159
  });
142
160
  }
143
161
 
162
+ private getBatch = () => {
163
+ const { api } = this.props;
164
+ this.props.setPage(1);
165
+ this.props.getBatch(api);
166
+ }
167
+
168
+ public proceedWithExport() {
169
+ const { renderBatch, activeBatch: { data: { id, name }} } = this.props;
170
+ renderBatch(id, name).then(() => {
171
+ this.setState({renderedBatch: true});
172
+ }).catch((e) => {
173
+ this.props.handleError(copy.publish.renderBatchFailed);
174
+ this.setState({renderedBatch: false});
175
+ throw e;
176
+ });
177
+ }
178
+
144
179
  private importBatch({story_id, id, name, uploadEvt}) {
145
- this.setState({ missingColumns: '', isMissing: false });
146
- const {accessKey, compositionId, isExport, handleError} = this.props;
180
+ const {accessKey, compositionId, isExport, onError} = this.props;
147
181
  this.props.importBatchFromCsv(story_id, id, name, uploadEvt.target.files[0], accessKey, compositionId, !isExport, isExport)
148
182
  .then(() => {
183
+
184
+ if (this.props.batchJobs.missing.length > 0 ) {
185
+ onError();
186
+ }
187
+
149
188
  this.setState({uploadComplete: true, uploading: false});
150
- if (isExport) {
189
+ this.getBatch();
190
+
191
+ if (isExport && Object.keys(this.props.batchJobs.missing).length === 0) {
151
192
  this.renderBatch({id, name});
152
193
  }
153
194
  })
154
195
  .catch((e) => {
155
- const {status, data} = e.response;
156
-
157
- if (status === 400) {
158
- handleError(copy.publish.missingColumns);
159
- alert(copy.publish.csvMissingColumns + data.error);
160
- this.hiddenFileInputRef.current.value = '';
161
- }
196
+ // const {status, data} = e.response;
197
+ // if (status === 400) {
198
+ // handleError(copy.publish.missingColumns);
199
+ // this.setState({csvError: true});
200
+ // this.setState({csvErrorString: copy.publish.csvMissingColumns + data.error})
201
+ // // this.getBatch(id);
202
+ // this.hiddenFileInputRef.current.value = '';
203
+ // }
162
204
  this.setState({uploadComplete: false, uploading: false});
163
205
  throw e;
164
206
  });
@@ -186,6 +228,7 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
186
228
  }
187
229
  this.props.getBatchExport(selectedBatchId).then(() => {
188
230
  this.props.onDone();
231
+ // this.props.onError();
189
232
  this.setState({
190
233
  downloading: false
191
234
  });
@@ -194,9 +237,10 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
194
237
  }
195
238
 
196
239
  public renderLabel() {
197
- const {isExport, batchJobs} = this.props;
198
- const {renderedBatch, selectedBatchId, uploading, uploadComplete} = this.state;
199
- if (isExport && uploadComplete && !renderedBatch) {
240
+ const { isExport, batchJobs } = this.props;
241
+ const { renderedBatch, selectedBatchId, uploading, uploadComplete } = this.state;
242
+
243
+ if (isExport && uploadComplete && !renderedBatch && Object.keys(this.props.batchJobs.missing).length === 0 ) {
200
244
  return (
201
245
  <div className={'progress-bar'}>
202
246
  <progress
@@ -213,9 +257,134 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
213
257
  return <span>{ICON_UPLOAD}&nbsp;{copy.publish.uploadCsv}</span>;
214
258
  }
215
259
 
260
+ private onAssociationChange(colIndex : any, e : any, stillMissingCols : boolean) {
261
+
262
+ const {activeBatch: {data : { columns }}} = this.props;
263
+
264
+ // Change the previous association back to static
265
+ const previousColumn = columns.findIndex((col) => {
266
+ return col.detail === e;
267
+ });
268
+ if (previousColumn !== -1) {
269
+ this.props.updateAssociation(this.props.api, previousColumn, 'Static', null);
270
+ }
271
+
272
+ // Set the new association
273
+ this.props.updateAssociation(this.props.api, parseInt(colIndex, 10), 'UGC', e);
274
+
275
+ this.props.onNext(stillMissingCols);
276
+ }
277
+
278
+ private renderColumnMap() {
279
+
280
+ const { activeBatch: {data : { columns }}, batchJobs: { missing }, variables } = this.props;
281
+
282
+ if (missing.length >= 0 && columns) {
283
+
284
+ const varArray = Object.keys(variables).map((key) => {
285
+
286
+ // disable options which are already aligned
287
+ const opt = {...variables[key]};
288
+
289
+ return opt;
290
+ });
291
+
292
+ const colArray = Object.keys(columns).map((i) => {
293
+ return columns[i];
294
+ });
295
+
296
+ const colOpts = colArray.filter((c : any) => {
297
+ if (c.from_import === 0 ) {
298
+ return false;
299
+ }
300
+
301
+ return true;
302
+ }).map((c, i) => {
303
+
304
+ const opt : any = {
305
+ value: i,
306
+ label: c.name
307
+ };
308
+ const alignedColIdx = varArray.findIndex((v) => {
309
+ return c.detail === v.id;
310
+ });
311
+
312
+ if (alignedColIdx !== -1) {
313
+ opt.disabled = true;
314
+ }
315
+ return opt;
316
+ });
317
+
318
+ // check to see if any required variables are missing
319
+ let stillMissingCols = false;
320
+ for (const v of varArray) {
321
+ if (!v.optional) {
322
+ const selectedCol = colArray.findIndex((c : any) => {
323
+ return c.detail === v.id;
324
+ });
325
+ if (selectedCol === -1) {
326
+ stillMissingCols = true;
327
+ break;
328
+ }
329
+ }
330
+ }
331
+
332
+ // add an empty option to the columns
333
+ colOpts.unshift('');
334
+
335
+ const missingColumn = Object.keys(missing).map((m) => missing[m]);
336
+ const showMissing = missingColumn.join();
337
+
338
+ if (colOpts.length < varArray.length) {
339
+ return (
340
+ <><HRule/><p className='missingColumns'>{`${copy.publish.csvMissingColumns} ${showMissing}`}</p></>
341
+ );
342
+ } else {
343
+ return (
344
+ <div className = 'align-columns' >
345
+ <HRule/>
346
+ <p className='match-columns'>{`${copy.publish.csvMatchColumns}`}</p>
347
+
348
+ <table>
349
+ <thead>
350
+ <tr>
351
+ <th>Variable</th>
352
+ <th>CSV Column</th>
353
+ </tr>
354
+ </thead>
355
+ <tbody>
356
+ {
357
+ varArray.map((v, i) => {
358
+
359
+ const selectedCol = colArray.findIndex((c : any) => {
360
+ return c.detail === v.id;
361
+ });
362
+
363
+ const selectedVal = (selectedCol !== undefined && selectedCol !== null) ? selectedCol : '';
364
+ const rClass = (!v.optional) ? 'required' : '';
365
+
366
+ return <tr key = {`var-${v.id}`} className = {`${rClass}`}>
367
+ <td className='variable'>
368
+ <p>{v.name} { (!v.optional) ? <span style={{ color: 'red' }}> * </span> : null }</p>
369
+ </td>
370
+ <td>
371
+ <SelectField options={colOpts} value={selectedVal} onChange={(c) => this.onAssociationChange(c, v.id, stillMissingCols)} />
372
+ </td>
373
+ </tr>;
374
+ })
375
+ }
376
+ </tbody>
377
+ </table>
378
+ </div>
379
+ );
380
+ }
381
+
382
+ }
383
+ }
384
+
216
385
  public render() {
217
- const {uploadComplete, uploading, downloading, renderedBatch, selectedBatchId, missingColumns, isMissing} = this.state;
218
- const {isExport} = this.props;
386
+ const {uploadComplete, uploading, downloading, renderedBatch, selectedBatchId} = this.state;
387
+ const { isExport, batchJobs: { missing, renders } } = this.props;
219
388
 
220
389
  const emailOptions = [
221
390
  {
@@ -232,23 +401,33 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
232
401
  ];
233
402
  const downloadCsvLabel = (downloading) ? <span><Spinner/>&nbsp;{copy.publish.exporting}</span> : <span>{ICON_DOWNLOAD}&nbsp;{copy.publish.btnDownload}</span>;
234
403
 
235
- const downloadCSV = (
236
- <div>
404
+ const reRenderLabel = <div className={'progress-bar'}>
405
+ <progress
406
+ max = {EmailWorkflow.PROGRESS_MAX_VALUE}
407
+ value = {renders[selectedBatchId]}
408
+ />
409
+ </div>;
410
+
411
+ const downloadCSVDiv = <div>
237
412
  <h2>{uploadComplete ? copy.publish.downloadLink : copy.publish.generatingLink}</h2>
238
413
  <HRule/>
239
414
  <p>{uploadComplete ? copy.publish.downloadDesc : copy.publish.generatingLinkDesc}</p>
240
- <BigButton
241
- label={downloadCsvLabel}
242
- disabled = {downloading}
243
- onClick={() => this.downloadCsv()}/>
244
- </div>
415
+
416
+ { isExport && uploadComplete && !renderedBatch ?
417
+ <BigButton label={reRenderLabel} disabled={isExport}/> :
418
+ <BigButton label={downloadCsvLabel} disabled = {downloading} onClick={() => this.downloadCsv()}/>}
419
+ </div>;
420
+
421
+ const downloadCSV = (<>
422
+ {this.props.error ? ( this.props.next ? downloadCSVDiv : '' ) : downloadCSVDiv}
423
+ {this.renderColumnMap()}
424
+ </>
245
425
  );
246
426
 
247
427
  const uploadCSV = <div>
248
428
  <h2>{copy.publish.emailTitle}</h2>
249
429
  <HRule/>
250
430
  <p>{copy.publish.emailDesc}</p>
251
- {isMissing ? <><HRule/><p className='missingColumns'>{`${copy.publish.csvMissingColumns} ${missingColumns}`}</p></> : ''}
252
431
  <input
253
432
  type='file'
254
433
  style={{display: 'none'}}
@@ -257,7 +436,6 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
257
436
  onChange={this.doUploadCsv}/>
258
437
  <div className = 'link-wrapper'>
259
438
  {emailOptions?.map((option, index) => {
260
-
261
439
  return <BigButton
262
440
  label={<span>{option.label}</span>}
263
441
  onClick={option.onClick}
@@ -267,7 +445,7 @@ class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkf
267
445
  </div>
268
446
  </div>;
269
447
 
270
- return (isExport ? renderedBatch : uploadComplete) ? downloadCSV : uploadCSV;
448
+ return (( isExport && Object.keys(missing).length === 0 ) ? renderedBatch : uploadComplete) ? downloadCSV : uploadCSV;
271
449
  }
272
450
  }
273
451
 
@@ -275,4 +453,16 @@ const alphaNumeric = (str) => {
275
453
  return str.replace(/\W/g, '');
276
454
  };
277
455
 
278
- export default EmailWorkflow;
456
+ const mapDispatchToProps = (dispatch) : any => {
457
+ return bindActionCreators({
458
+ updateAssociation, getBatch, setPage
459
+ }, dispatch);
460
+ };
461
+
462
+ const mapStateToProps = (state) : any => {
463
+ return {
464
+ activeBatch: state.activeBatch,
465
+ batchesList: state.batchesList,
466
+ };
467
+ };
468
+ export default connect(mapStateToProps, mapDispatchToProps, null, { withRef: true })(EmailWorkflow);
@@ -62,7 +62,7 @@ class SelectField extends React.PureComponent<ISelectFieldProps, {}> {
62
62
 
63
63
  public render() {
64
64
 
65
- const {label, showCopy, placeholder, options, value, width, buttons, selectRef, disable, tooltip, info, labelPosition, disableFirst} = this.props;
65
+ const {label, showCopy, options, value, width, buttons, selectRef, disable, tooltip, info, labelPosition, disableFirst} = this.props;
66
66
  let opts = [];
67
67
 
68
68
  const selectValue = (value === null || value === undefined) ? '' : value;
@@ -91,8 +91,7 @@ class SelectField extends React.PureComponent<ISelectFieldProps, {}> {
91
91
 
92
92
  if (options) {
93
93
  opts = options.map((option , i) => {
94
-
95
- const disabled = (i === 0 && disableFirst) ? true : false;
94
+ const disabled = (i === 0 && disableFirst || (option.disabled !== undefined && option.disabled)) ? true : false;
96
95
  const optionValue = (option.value !== undefined) ? option.value : option;
97
96
  const optionLabel = (option.label !== undefined) ? option.label : option;
98
97
  return <option disabled = {disabled} key = {`option-${optionValue}`} value = {optionValue}>{optionLabel}</option>;
@@ -21,6 +21,7 @@ import {ICON_VIDEO, ICON_IMAGE, ICON_STICKY_NOTE} from '../../constants/icons';
21
21
  import { formattedTime } from '../../Util';
22
22
  import Timer from '../../services/Timer';
23
23
  import LogViewer from '../log-viewer/LogViewer';
24
+ import { connect } from 'react-redux';
24
25
 
25
26
  interface IStoryPreviewerProps {
26
27
  api : IImposiumAPI;
@@ -35,6 +36,7 @@ interface IStoryPreviewerProps {
35
36
  onJobCreated?(expId : string, jobId : string) : void;
36
37
  onExperenceLoaded?(exp : IExperience) : void;
37
38
  onError?(n : string) : void;
39
+ notifications : any;
38
40
  }
39
41
 
40
42
  interface IStoryPreviewerState {
@@ -210,6 +212,18 @@ class StoryPreviewer extends React.PureComponent<IStoryPreviewerProps, IStoryPre
210
212
  });
211
213
  }
212
214
 
215
+ if (this.props.notifications) {
216
+ if (this.props.notifications[0]) {
217
+ if (this.props.notifications[0]['type'] === 'error') {
218
+ this.setState({isTimeOut: true});
219
+ }
220
+
221
+ if (this.props.notifications[0]['type'] === 'info') {
222
+ this.setState({isTimeOut: false});
223
+ }
224
+ }
225
+ }
226
+
213
227
  if (prevState.timeElapsed !== this.state.timeElapsed) {
214
228
  if (formattedTime(this.state.timeElapsed) === this.TIMEOUT && !this.state.experience) {
215
229
 
@@ -530,7 +544,7 @@ class StoryPreviewer extends React.PureComponent<IStoryPreviewerProps, IStoryPre
530
544
  jobId: null,
531
545
  timeElapsed: !isTimeOut ? 0 : this.state.timeElapsed,
532
546
  activeOutput: null,
533
- isTimeOut
547
+ isTimeOut: false,
534
548
  }, () => {
535
549
  if (callback) {
536
550
  callback();
@@ -656,5 +670,8 @@ class StoryPreviewer extends React.PureComponent<IStoryPreviewerProps, IStoryPre
656
670
  </div>;
657
671
  }
658
672
  }
673
+ const mapStateToProps = (state) : any => {
674
+ return {notifications : state.notifications};
675
+ };
659
676
 
660
- export default StoryPreviewer;
677
+ export default connect(mapStateToProps, {})(StoryPreviewer);
package/constants/copy.ts CHANGED
@@ -138,6 +138,7 @@ export const publish = {
138
138
  importingData: 'Importing Data... (please wait)',
139
139
  downloadDesc: 'Your CSV data file is ready to download with an embed code you can import into your email platform to send out.',
140
140
  csvMissingColumns: 'Warning: Some of your column names did not match up with the variables in the story. Please ensure these variables line up and then re-upload the csv: ',
141
+ csvMatchColumns: 'Please match the column(s) provided to the story variables:',
141
142
  // export
142
143
  exportBatchOfVideo: 'Export batch of videos',
143
144
 
@@ -159,6 +160,8 @@ export const publish = {
159
160
  btnSkip: 'Skip',
160
161
  btnBack: 'Back',
161
162
  btnFinished: 'Done',
163
+ btnCancel: 'Cancel',
164
+ btnNext: 'Next',
162
165
  noCompErrorTitle: 'No Compositions Found',
163
166
  noCompErrorDesc: `You must have at least 1 composition on your story to render and distribute videos.`
164
167
  };