@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 +5 -0
- package/components/data-table/DataTable.tsx +0 -1
- package/components/publish-wizard/PublishWizard.tsx +62 -8
- package/components/publish-wizard/publish/EmailWorkflow.tsx +232 -42
- package/components/select-field/SelectField.tsx +2 -3
- package/components/story-previewer/StoryPreviewer.tsx +19 -2
- package/constants/copy.ts +3 -0
- package/dist/components.js +4 -4
- package/dist/components.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/dist/styles.less +66 -0
- package/dist/styles.less.map +1 -1
- package/less/components/align-columns.less +66 -0
- package/less/styles.less +1 -0
- package/package.json +1 -1
- package/redux/actions/active-batch.ts +110 -0
- package/redux/reducers/active-batch.ts +108 -0
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({
|
|
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
|
|
67
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
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} {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
|
|
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/> {copy.publish.exporting}</span> : <span>{ICON_DOWNLOAD} {copy.publish.btnDownload}</span>;
|
|
234
403
|
|
|
235
|
-
const
|
|
236
|
-
<
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
};
|