@imposium-hub/components 1.39.1 → 1.41.0
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 +11 -2
- package/components/assets/AssetsUploadMenu.tsx +24 -5
- package/components/publish-wizard/PublishWizard.tsx +477 -0
- package/components/publish-wizard/publish/APIIntegration.tsx +28 -0
- package/components/publish-wizard/publish/EmailWorkflow.tsx +255 -0
- package/components/publish-wizard/publish/HubSpotFlow.tsx +80 -0
- package/components/publish-wizard/publish/PublishStatusIndicator.tsx +84 -0
- package/components/publish-wizard/publish/WebpageHosted.tsx +120 -0
- package/constants/copy.ts +100 -0
- package/constants/icons.tsx +21 -0
- package/dist/components.js +2 -2
- package/dist/components.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/dist/styles.less +145 -12
- package/dist/styles.less.map +1 -1
- package/less/components/assets.less +7 -0
- package/less/components/publish-status-indicator.less +22 -0
- package/less/components/publish-wizard.less +101 -0
- package/less/components/section.less +13 -12
- package/less/styles.less +2 -0
- package/package.json +4 -1
- package/redux/actions/asset-uploads.ts +19 -6
- package/redux/actions/publish.ts +84 -0
- package/redux/reducers/publish.ts +36 -0
- package/services/API.ts +29 -6
- package/utils/routing.ts +12 -0
- package/utils/template-generator.ts +32 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import HRule from '../../h-rule/HRule';
|
|
3
|
+
import Spinner from '../../spinner/Spinner';
|
|
4
|
+
import * as copy from '../../../constants/copy';
|
|
5
|
+
import {BigButton} from '../PublishWizard';
|
|
6
|
+
import { ExportToCsv } from 'export-to-csv';
|
|
7
|
+
import { ICON_DOWNLOAD, ICON_UPLOAD } from '../../../constants/icons';
|
|
8
|
+
import * as moment from 'moment';
|
|
9
|
+
import {IImposiumAPI} from '../../../services/API';
|
|
10
|
+
|
|
11
|
+
interface IEmailWorkflowProps {
|
|
12
|
+
story : any;
|
|
13
|
+
createFreshBatch : (e : string) => any;
|
|
14
|
+
getBatches : () => any;
|
|
15
|
+
getBatchExport : (batchId : string) => any;
|
|
16
|
+
importBatchFromCsv : (storyId : string, batchId : string, batchName : string, csvFile : File, accessKey : string, compId : string, embed : boolean) => any;
|
|
17
|
+
renderBatch : (batchId : string, batchName : string) => any;
|
|
18
|
+
status : string;
|
|
19
|
+
accessKey : string;
|
|
20
|
+
compositionId : string;
|
|
21
|
+
compositionName : string;
|
|
22
|
+
onDone : () => void;
|
|
23
|
+
api : IImposiumAPI;
|
|
24
|
+
handleError : (e) => any;
|
|
25
|
+
batchJobs : any;
|
|
26
|
+
isExport ? : boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface IEmailWorkflowState {
|
|
30
|
+
uploadComplete : boolean;
|
|
31
|
+
selectedBatchId : string;
|
|
32
|
+
uploading : boolean;
|
|
33
|
+
downloading : boolean;
|
|
34
|
+
renderedBatch : boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class EmailWorkflow extends React.PureComponent<IEmailWorkflowProps, IEmailWorkflowState> {
|
|
38
|
+
private readonly hiddenFileInputRef : any;
|
|
39
|
+
private static readonly PROGRESS_MAX_VALUE : number = 100;
|
|
40
|
+
private static readonly CSV_EXPORT_CONFIG : any = {
|
|
41
|
+
fieldSeparator: ',',
|
|
42
|
+
quoteStrings: '"',
|
|
43
|
+
decimalSeparator: '.',
|
|
44
|
+
showLabels: false,
|
|
45
|
+
showTitle: false,
|
|
46
|
+
useTextFile: false,
|
|
47
|
+
useBom: true,
|
|
48
|
+
useKeysAsHeaders: true
|
|
49
|
+
};
|
|
50
|
+
constructor(props) {
|
|
51
|
+
super(props);
|
|
52
|
+
this.state = {
|
|
53
|
+
uploadComplete: false,
|
|
54
|
+
uploading: false,
|
|
55
|
+
downloading : false,
|
|
56
|
+
selectedBatchId: '',
|
|
57
|
+
renderedBatch: false,
|
|
58
|
+
};
|
|
59
|
+
this.hiddenFileInputRef = React.createRef();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public downloadSampleCsv() {
|
|
63
|
+
|
|
64
|
+
const {name} = this.props.story;
|
|
65
|
+
const {acts} = this.props.story;
|
|
66
|
+
const actsKeys : string[] = Object.keys(acts);
|
|
67
|
+
let inventory : any = {};
|
|
68
|
+
|
|
69
|
+
actsKeys.forEach((actKey : string) => {
|
|
70
|
+
inventory = {...inventory, ...acts[actKey].inventory};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const inventoryKeys : string[] = Object.keys(inventory).sort();
|
|
74
|
+
const maskConfig : any[] = inventoryKeys.map((currKey : string) => ({
|
|
75
|
+
id: currKey,
|
|
76
|
+
name: inventory[currKey].name,
|
|
77
|
+
show: true
|
|
78
|
+
}));
|
|
79
|
+
|
|
80
|
+
const emptyRow : any = maskConfig.map((m : any) => (m.id))
|
|
81
|
+
.reduce((prevState : any, currId : string) => ({...prevState, [currId]: ''}), {});
|
|
82
|
+
|
|
83
|
+
const filename = `${alphaNumeric(name)}-batch-template.csv`;
|
|
84
|
+
const exporter = new ExportToCsv({
|
|
85
|
+
...EmailWorkflow.CSV_EXPORT_CONFIG,
|
|
86
|
+
filename
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
exporter.generateCsv([emptyRow]);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private selectCsv = () : void => {
|
|
93
|
+
if (this.hiddenFileInputRef.current) {
|
|
94
|
+
this.hiddenFileInputRef.current.click();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private getBatchName() {
|
|
99
|
+
|
|
100
|
+
const {story: {name}, compositionName} = this.props;
|
|
101
|
+
const date = Date.now();
|
|
102
|
+
const dateStr = moment(date).format('MMDDYY-HHmm');
|
|
103
|
+
const batchName = `${alphaNumeric(name)}-${alphaNumeric(compositionName)}-${dateStr}`;
|
|
104
|
+
return batchName;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private doUploadCsv = (uploadEvt) : void => {
|
|
108
|
+
uploadEvt.persist();
|
|
109
|
+
const {handleError} = this.props;
|
|
110
|
+
this.setState({
|
|
111
|
+
uploading: true,
|
|
112
|
+
renderedBatch: false,
|
|
113
|
+
});
|
|
114
|
+
this.props.createFreshBatch(this.getBatchName())
|
|
115
|
+
.then((res) => {
|
|
116
|
+
const {id, name, story_id} = res;
|
|
117
|
+
this.setState({selectedBatchId: id});
|
|
118
|
+
this.importBatch({story_id, id, name, uploadEvt});
|
|
119
|
+
})
|
|
120
|
+
.catch((e) => {
|
|
121
|
+
handleError(e);
|
|
122
|
+
this.setState({uploadComplete: false, uploading: false});
|
|
123
|
+
throw e;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private importBatch({story_id, id, name, uploadEvt}) {
|
|
128
|
+
const {accessKey, compositionId, isExport, handleError} = this.props;
|
|
129
|
+
this.props.importBatchFromCsv(story_id, id, name, uploadEvt.target.files[0], accessKey, compositionId, !isExport)
|
|
130
|
+
.then(() => {
|
|
131
|
+
this.setState({uploadComplete: true, uploading: false});
|
|
132
|
+
if (isExport) {
|
|
133
|
+
this.renderBatch({id, name});
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
.catch((e) => {
|
|
137
|
+
const {status, data} = e.response;
|
|
138
|
+
|
|
139
|
+
if (status === 400) {
|
|
140
|
+
handleError(copy.publish.missingColumns);
|
|
141
|
+
alert(copy.publish.csvMissingColumns + data.error);
|
|
142
|
+
}
|
|
143
|
+
this.setState({uploadComplete: false, uploading: false});
|
|
144
|
+
throw e;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private renderBatch({id, name}) {
|
|
149
|
+
this.props.renderBatch(id, name).then(() => {
|
|
150
|
+
this.setState({renderedBatch: true});
|
|
151
|
+
}).catch((e) => {
|
|
152
|
+
this.props.handleError(copy.publish.renderBatchFailed);
|
|
153
|
+
this.setState({renderedBatch: false});
|
|
154
|
+
throw e;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public downloadCsv() {
|
|
159
|
+
this.setState({
|
|
160
|
+
downloading: true
|
|
161
|
+
}, () => {
|
|
162
|
+
const {status, api, handleError} = this.props;
|
|
163
|
+
const {selectedBatchId} = this.state;
|
|
164
|
+
if (status === copy.header.publishing) {
|
|
165
|
+
handleError(copy.publish.downloadError);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this.props.getBatchExport(selectedBatchId).then(() => {
|
|
169
|
+
this.props.onDone();
|
|
170
|
+
this.setState({
|
|
171
|
+
downloading: false
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public renderLabel() {
|
|
178
|
+
const {isExport, batchJobs} = this.props;
|
|
179
|
+
const {renderedBatch, selectedBatchId, uploading, uploadComplete} = this.state;
|
|
180
|
+
if (isExport && uploadComplete && !renderedBatch) {
|
|
181
|
+
return (
|
|
182
|
+
<span className={'progress-bar'}>
|
|
183
|
+
<progress
|
|
184
|
+
max = {EmailWorkflow.PROGRESS_MAX_VALUE}
|
|
185
|
+
value = {batchJobs.renders[selectedBatchId]}
|
|
186
|
+
/>
|
|
187
|
+
</span>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (uploading) {
|
|
191
|
+
const uploadingCopy = (isExport) ? copy.publish.importingData : copy.publish.creatingLinks;
|
|
192
|
+
return <span><Spinner/> {uploadingCopy}</span>;
|
|
193
|
+
}
|
|
194
|
+
return <span>{ICON_UPLOAD} {copy.publish.uploadCsv}</span>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public render() {
|
|
198
|
+
const {uploadComplete, uploading, downloading, renderedBatch, selectedBatchId} = this.state;
|
|
199
|
+
const {isExport} = this.props;
|
|
200
|
+
|
|
201
|
+
const emailOptions = [
|
|
202
|
+
{
|
|
203
|
+
label: <span>{ICON_DOWNLOAD} {copy.publish.downloadSampleCsvLink}</span>,
|
|
204
|
+
onClick: () => this.downloadSampleCsv(),
|
|
205
|
+
key: 'download-sample'
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
label: this.renderLabel(),
|
|
209
|
+
onClick: () => this.selectCsv(),
|
|
210
|
+
key: 'upload',
|
|
211
|
+
disabled: isExport ? uploadComplete || uploading : uploading,
|
|
212
|
+
},
|
|
213
|
+
];
|
|
214
|
+
const downloadCsvLabel = (downloading) ? <span><Spinner/> {copy.publish.exporting}</span> : <span>{ICON_DOWNLOAD} {copy.publish.btnDownload}</span>;
|
|
215
|
+
|
|
216
|
+
const downloadCSV = (
|
|
217
|
+
<div>
|
|
218
|
+
<h2>{uploadComplete ? copy.publish.downloadLink : copy.publish.generatingLink}</h2>
|
|
219
|
+
<HRule/>
|
|
220
|
+
<p>{uploadComplete ? copy.publish.downloadDesc : copy.publish.generatingLinkDesc}</p>
|
|
221
|
+
<BigButton
|
|
222
|
+
label={downloadCsvLabel}
|
|
223
|
+
disabled = {downloading}
|
|
224
|
+
onClick={() => this.downloadCsv()}/>
|
|
225
|
+
</div>
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const uploadCSV = <div>
|
|
229
|
+
<h2>{copy.publish.emailTitle}</h2>
|
|
230
|
+
<HRule/>
|
|
231
|
+
<p>{copy.publish.emailDesc}</p>
|
|
232
|
+
<input
|
|
233
|
+
type='file'
|
|
234
|
+
style={{display: 'none'}}
|
|
235
|
+
accept='text/csv'
|
|
236
|
+
ref={this.hiddenFileInputRef}
|
|
237
|
+
onChange={this.doUploadCsv}/>
|
|
238
|
+
{emailOptions?.map((option, index) => {
|
|
239
|
+
return <BigButton
|
|
240
|
+
label={<span>{option.label}</span>}
|
|
241
|
+
onClick={option.onClick}
|
|
242
|
+
disabled={option?.disabled}
|
|
243
|
+
key={option.key}/>;
|
|
244
|
+
})}
|
|
245
|
+
</div>;
|
|
246
|
+
|
|
247
|
+
return (isExport ? renderedBatch : uploadComplete) ? downloadCSV : uploadCSV;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const alphaNumeric = (str) => {
|
|
252
|
+
return str.replace(/\W/g, '');
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
export default EmailWorkflow;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import Button from '../../button/Button';
|
|
3
|
+
import TextAreaField from '../../text-area-field/TextAreaField';
|
|
4
|
+
import HRule from '../../h-rule/HRule';
|
|
5
|
+
import * as copy from '../../../constants/copy';
|
|
6
|
+
import {ICON_CLIPBOARD} from '../../../constants/icons';
|
|
7
|
+
|
|
8
|
+
interface IHubSpotFlowProps {
|
|
9
|
+
story : any;
|
|
10
|
+
status : string;
|
|
11
|
+
compositionId : string;
|
|
12
|
+
accessKey : string;
|
|
13
|
+
handleError(e) : void;
|
|
14
|
+
handleNotification? : (n) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class HubSpotFlow extends React.PureComponent<IHubSpotFlowProps, undefined> {
|
|
18
|
+
constructor(props) {
|
|
19
|
+
super(props);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private createUrl() {
|
|
23
|
+
const { story, compositionId, accessKey} = this.props;
|
|
24
|
+
const storyId = story.id;
|
|
25
|
+
const act = this.getFirstAct(story);
|
|
26
|
+
const variables = act.inventory;
|
|
27
|
+
let queryString = '';
|
|
28
|
+
|
|
29
|
+
for (const key in variables) {
|
|
30
|
+
if (variables.hasOwnProperty(key)) {
|
|
31
|
+
const prefix = (queryString) ? '&' : '?';
|
|
32
|
+
queryString += `${prefix}${key}={{${key.toUpperCase()}}}`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const href = window.location.href;
|
|
37
|
+
const root = (href.indexOf('staging') !== -1 || href.indexOf('localhost') !== -1) ? 'staging.imposium.com' : 'imposium.com';
|
|
38
|
+
const playerUrl = `https://player.${root}/new/${accessKey}/${storyId}/${compositionId}${queryString}`;
|
|
39
|
+
const posterUrl = `https://api.${root}/story/${storyId}/${compositionId}/poster${queryString}`;
|
|
40
|
+
return `<a href="${playerUrl}" target="_blank"><img width="400" alt="Play Video" src="${posterUrl}"></a>`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private getFirstAct = (story) : any => {
|
|
44
|
+
|
|
45
|
+
for (const key in story.acts) {
|
|
46
|
+
if (story.acts.hasOwnProperty(key)) {
|
|
47
|
+
return story.acts[key];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public render() {
|
|
53
|
+
const {status, handleError, handleNotification} = this.props;
|
|
54
|
+
return (
|
|
55
|
+
<div>
|
|
56
|
+
<h2>{copy.publish.hubspotTitle}</h2>
|
|
57
|
+
<HRule/>
|
|
58
|
+
<p>{copy.publish.hubspotDesc}</p>
|
|
59
|
+
<HRule/>
|
|
60
|
+
<TextAreaField
|
|
61
|
+
label={copy.publish.embeddedCode}
|
|
62
|
+
value={this.createUrl()}
|
|
63
|
+
showCopy = {status !== copy.header.publishing}
|
|
64
|
+
onNotification = {(n) => handleNotification(n)}
|
|
65
|
+
onError = {(e) => handleError(e)}
|
|
66
|
+
readOnly = {true}/>
|
|
67
|
+
{status === copy.header.publishing &&
|
|
68
|
+
<Button size={'small'} customStyles={{margin: 0, height: '20px', border: 'none'}}
|
|
69
|
+
color='primary'
|
|
70
|
+
onClick={() => handleError(copy.publish.embeddedCodeCopyError)}
|
|
71
|
+
>
|
|
72
|
+
{ICON_CLIPBOARD}
|
|
73
|
+
</Button>
|
|
74
|
+
}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default HubSpotFlow;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cancelPublish } from '../../../redux/actions/publish';
|
|
3
|
+
import { IImposiumAPI } from '../../../services/API';
|
|
4
|
+
import Spinner from '../../spinner/Spinner';
|
|
5
|
+
import { connect } from 'react-redux';
|
|
6
|
+
import { ICON_TIMES } from '../../../constants/icons';
|
|
7
|
+
import { bindActionCreators } from 'redux';
|
|
8
|
+
|
|
9
|
+
interface IPublishStatusIndicatorProps {
|
|
10
|
+
publishData : any;
|
|
11
|
+
cancelPublish(api : IImposiumAPI, storyId : string) : void;
|
|
12
|
+
api : IImposiumAPI;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IPublishStatusIndicatorStates {
|
|
16
|
+
hover : boolean;
|
|
17
|
+
publishing : boolean;
|
|
18
|
+
}
|
|
19
|
+
class PublishStatusIndicator extends React.PureComponent<IPublishStatusIndicatorProps, IPublishStatusIndicatorStates> {
|
|
20
|
+
|
|
21
|
+
constructor(props) {
|
|
22
|
+
|
|
23
|
+
super(props);
|
|
24
|
+
|
|
25
|
+
this.state = {
|
|
26
|
+
hover: false,
|
|
27
|
+
publishing: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public onEnterHandler() {
|
|
32
|
+
this.setState({hover: true});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public onLeaveHandler() {
|
|
36
|
+
this.setState({hover: false});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public cancelPublisingHandler() {
|
|
40
|
+
const { publishData: {story_id}, api } = this.props;
|
|
41
|
+
this.props.cancelPublish(api, story_id);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public render() {
|
|
45
|
+
const { publishing, version} = this.props.publishData;
|
|
46
|
+
const { hover } = this.state;
|
|
47
|
+
|
|
48
|
+
// nothing published yet, using working copy
|
|
49
|
+
if (!publishing && !version) {
|
|
50
|
+
return null;
|
|
51
|
+
} else {
|
|
52
|
+
|
|
53
|
+
let cta : any = '';
|
|
54
|
+
if (publishing) {
|
|
55
|
+
const newVersion = version || 0 + 1;
|
|
56
|
+
const publishingString = `v${newVersion} Publishing`;
|
|
57
|
+
|
|
58
|
+
cta = <span onMouseEnter={() => this.onEnterHandler()} onMouseLeave={() => this.onLeaveHandler()}>
|
|
59
|
+
{hover ?
|
|
60
|
+
<><span onClick={() => this.cancelPublisingHandler()} style={{cursor: 'pointer'}}>{ICON_TIMES}</span>{' '}{publishingString}</> :
|
|
61
|
+
<><Spinner/>{publishingString}</>
|
|
62
|
+
}
|
|
63
|
+
</span>;
|
|
64
|
+
} else {
|
|
65
|
+
cta = <span>{`v${version} Live`}</span>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return <div className = 'publish-status-indicator'>
|
|
69
|
+
{cta}
|
|
70
|
+
</div>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const mapStateToProps = (state) => ({
|
|
77
|
+
publishData: state.publish
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const mapDispatchToProps = (dispatch) : any => {
|
|
81
|
+
return bindActionCreators({cancelPublish}, dispatch);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default connect(mapStateToProps, mapDispatchToProps)(PublishStatusIndicator);
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as copy from '../../../constants/copy';
|
|
3
|
+
import {BigLink, BigButton } from '../PublishWizard';
|
|
4
|
+
import {ICON_DOWNLOAD, ICON_GLOBE, ICON_JS, ICON_PROJECT_DIAGRAM} from '../../../constants/icons';
|
|
5
|
+
import {downloadSDKArchive, ISDKArchiveBody} from '../../../utils/template-generator';
|
|
6
|
+
import {getDemoURL} from '../../../utils/routing';
|
|
7
|
+
import HRule from '../../h-rule/HRule';
|
|
8
|
+
|
|
9
|
+
interface IWebpageHostedProps {
|
|
10
|
+
story : any;
|
|
11
|
+
accessKey : string;
|
|
12
|
+
compositionId : string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const documentationLinks = [
|
|
16
|
+
{
|
|
17
|
+
key: 'js-sdk-link',
|
|
18
|
+
label : <span>{ICON_JS} {copy.integration.js}</span>,
|
|
19
|
+
link : copy.integration.jsSdkLink
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
key: 'rest-link',
|
|
23
|
+
label : <span>{ICON_PROJECT_DIAGRAM} {copy.integration.rest}</span>,
|
|
24
|
+
link : copy.integration.restLink
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
class WebpageHosted extends React.PureComponent<IWebpageHostedProps> {
|
|
29
|
+
constructor(props) {
|
|
30
|
+
super(props);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private downloadSampleWebPage = () => {
|
|
34
|
+
const { story, compositionId, accessKey } = this.props;
|
|
35
|
+
const firstAct : any = this.getFirstAct(story);
|
|
36
|
+
let archiveName : string;
|
|
37
|
+
let sdkExampleBody : ISDKArchiveBody;
|
|
38
|
+
if (
|
|
39
|
+
story.id &&
|
|
40
|
+
story.name &&
|
|
41
|
+
typeof firstAct !== 'undefined' &&
|
|
42
|
+
firstAct.hasOwnProperty('inventory')
|
|
43
|
+
) {
|
|
44
|
+
archiveName = story.name + copy.integration.sdkArchiveSuffix;
|
|
45
|
+
sdkExampleBody = {
|
|
46
|
+
storyId: story.id,
|
|
47
|
+
compositionId,
|
|
48
|
+
storyName: story.name,
|
|
49
|
+
accessToken: accessKey,
|
|
50
|
+
inventory: firstAct.inventory
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
downloadSDKArchive(archiveName, sdkExampleBody);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private getFirstAct = (story) : any => {
|
|
58
|
+
|
|
59
|
+
for (const key in story.acts) {
|
|
60
|
+
if (story.acts.hasOwnProperty(key)) {
|
|
61
|
+
return story.acts[key];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private linkToDemoPage() {
|
|
67
|
+
const {accessKey, compositionId, story: {id}} = this.props;
|
|
68
|
+
if (accessKey) {
|
|
69
|
+
const demoUrl = `${getDemoURL()}/${accessKey}/${id}/${compositionId}`;
|
|
70
|
+
window.open(demoUrl, '_blank');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public render() {
|
|
75
|
+
const webPageOptions = [
|
|
76
|
+
{
|
|
77
|
+
label : <span>{ICON_GLOBE} {copy.publish.webPageHosted}</span>,
|
|
78
|
+
onClick: () => this.linkToDemoPage(),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
label : <span>{ICON_DOWNLOAD} {copy.publish.sampleWebpage}</span>,
|
|
82
|
+
onClick: () => this.downloadSampleWebPage(),
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div>
|
|
88
|
+
<h2>{copy.publish.webpageTitle}</h2>
|
|
89
|
+
<HRule/>
|
|
90
|
+
<p>{copy.publish.webpageDesc}</p>
|
|
91
|
+
<HRule/>
|
|
92
|
+
{webPageOptions?.map((option, index) => {
|
|
93
|
+
return (
|
|
94
|
+
<BigButton
|
|
95
|
+
key={index}
|
|
96
|
+
label={option.label}
|
|
97
|
+
onClick={() => option.onClick()}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
})}
|
|
101
|
+
<br/>
|
|
102
|
+
<br/>
|
|
103
|
+
<h2>{copy.integration.documentation}</h2>
|
|
104
|
+
<HRule/>
|
|
105
|
+
<p>{copy.integration.docParagraph}</p>
|
|
106
|
+
{documentationLinks?.map((link) => {
|
|
107
|
+
return (
|
|
108
|
+
<BigLink
|
|
109
|
+
key={link.key}
|
|
110
|
+
label = {link.label}
|
|
111
|
+
link = {link.link}
|
|
112
|
+
/>
|
|
113
|
+
);
|
|
114
|
+
})}
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export default WebpageHosted;
|
package/constants/copy.ts
CHANGED
|
@@ -95,3 +95,103 @@ export const compositions = {
|
|
|
95
95
|
textLayerContent: 'Content',
|
|
96
96
|
tooltipTextLayerContent: 'The copy rendered in this layer. Wrap variables like so: {{variable_id}}.'
|
|
97
97
|
};
|
|
98
|
+
|
|
99
|
+
export const publish = {
|
|
100
|
+
accessKey: 'Access Key',
|
|
101
|
+
tooltipAccessKey: 'API access key to use for this video distribution.',
|
|
102
|
+
publishTitle: 'Publish & Deliver',
|
|
103
|
+
|
|
104
|
+
// publish
|
|
105
|
+
publishStepTitle: 'STEP 1: Publish your Project',
|
|
106
|
+
publishStepDesc: 'Your project needs to be published before your changes can be seen. If you haven\'t made any changes since the last time you published, you can skip to the next step.',
|
|
107
|
+
|
|
108
|
+
// distribute
|
|
109
|
+
distributeStepTitle: 'STEP 2: How do you want your users to view their video?',
|
|
110
|
+
distributeStepDesc: 'Select which Composition you want to deliver, access credentials you want to use, and distribution channel.',
|
|
111
|
+
compositionError: 'Please Select Composition',
|
|
112
|
+
|
|
113
|
+
// webpage
|
|
114
|
+
btnWebsite: 'Webpage',
|
|
115
|
+
webpageTitle: 'STEP 3: Webpage',
|
|
116
|
+
webPageHosted: 'Webpage hosted on Imposium',
|
|
117
|
+
webpageDesc: 'You can share a demo page that is hosted on Imposium or you can download a sample webpage you can customize and use to generate videos. Please ensure you include a column for every variable on your story.',
|
|
118
|
+
sampleWebpage: 'Download sample webpage',
|
|
119
|
+
|
|
120
|
+
// email
|
|
121
|
+
btnEmail: 'Email',
|
|
122
|
+
exporting: 'Exporting CSV... (please wait)',
|
|
123
|
+
emailTitle: 'STEP 3: Upload a CSV file with your user information in it.',
|
|
124
|
+
emailDesc: 'You can download a sample CSV with fields to populate as a starting point. Or you can upload one that already has the data in it.',
|
|
125
|
+
downloadSampleCsvLink: 'Download Sample CSV',
|
|
126
|
+
uploadCsv: 'Upload Your CSV UserList',
|
|
127
|
+
generatingLink: 'STEP 4: Generating embed links',
|
|
128
|
+
downloadLink: 'STEP 5: Download Your Userlist CSV file',
|
|
129
|
+
btnDownload: 'Download CSV',
|
|
130
|
+
generatingLinkDesc: 'Please wait while we generate the link for your users. This may take few minutes.',
|
|
131
|
+
missingColumns: 'Error: missing required columns',
|
|
132
|
+
renderBatchFailed: 'Error: Failed to render batch',
|
|
133
|
+
createBatchFailed: 'Error: Failed to create batch',
|
|
134
|
+
downloadError: 'Error downloading sample CSV.',
|
|
135
|
+
embeddedCodeCopyError: 'Error copying embed code.',
|
|
136
|
+
creatingLinks: 'Creating User Links... (please wait)',
|
|
137
|
+
importingData: 'Importing Data... (please wait)',
|
|
138
|
+
downloadDesc: 'Your CSV data file is ready to download with an embed code you can import into your email platform to send out.',
|
|
139
|
+
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: ',
|
|
140
|
+
// export
|
|
141
|
+
exportBatchOfVideo: 'Export batch of videos',
|
|
142
|
+
|
|
143
|
+
// hubspot
|
|
144
|
+
btnHubspot: 'Hubspot',
|
|
145
|
+
hubspotTitle: 'STEP 3: Copy Hubspot code snippet',
|
|
146
|
+
hubspotDesc: 'Copy the provided embed code into HubSpot. Replace the placeholder variable values with HubSpot template strings, to splice in your user data.',
|
|
147
|
+
saveChanges: 'Save Changes',
|
|
148
|
+
embeddedCode: 'Embed Url: ',
|
|
149
|
+
|
|
150
|
+
// api
|
|
151
|
+
btnAPI: 'API integration',
|
|
152
|
+
|
|
153
|
+
// global
|
|
154
|
+
btnPublish: 'Publish',
|
|
155
|
+
btnSkip: 'Skip',
|
|
156
|
+
btnBack: 'Back',
|
|
157
|
+
btnFinished: 'Done',
|
|
158
|
+
noCompErrorTitle: 'No Compositions Found',
|
|
159
|
+
noCompErrorDesc: `You can't publish and deliver your project until you have created your first composition.`
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export const integration = {
|
|
163
|
+
errorPullingComps: ' Error getting composition IDs, contact your Imposium admin for support.',
|
|
164
|
+
errorCreatingCreds: ' Error creating credentials, contact your Imposium admin for support.',
|
|
165
|
+
errorGettingCreds: ' Error getting credentials, contact your Imposium admin for support.',
|
|
166
|
+
documentation: 'Documentation',
|
|
167
|
+
docParagraph: 'Use the links below for more information on integrating Imposium into your application.',
|
|
168
|
+
js: 'JavaScript SDK',
|
|
169
|
+
jsSdkLink: 'https://docs.imposium.com/js-sdk/#/',
|
|
170
|
+
restLink: 'https://docs.imposium.com',
|
|
171
|
+
rest: 'REST API',
|
|
172
|
+
sdkArchiveSuffix: ' - JS SDK Integration.zip',
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export const header = {
|
|
176
|
+
publishing: 'Publishing...',
|
|
177
|
+
working: 'Using Working Copy',
|
|
178
|
+
statusError: 'Error getting story status',
|
|
179
|
+
publishJobError: 'Error creating publish story job',
|
|
180
|
+
publishPollError: 'Error polling publish job status',
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const project = {
|
|
184
|
+
compName: 'Composition',
|
|
185
|
+
tooltipCompId : 'Unique ID of the selected composition. Used to render that specific composition via the API and Imposium JS-SDK.',
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const BATCHES_COPY = {
|
|
189
|
+
progress: {
|
|
190
|
+
notRendered: 'not rendered',
|
|
191
|
+
rendering: 'rendering',
|
|
192
|
+
rendered: 'rendered',
|
|
193
|
+
cancelled: 'cancelled',
|
|
194
|
+
queued: 'queued',
|
|
195
|
+
malformed: 'unknown'
|
|
196
|
+
}
|
|
197
|
+
};
|
package/constants/icons.tsx
CHANGED
|
@@ -51,6 +51,13 @@ import { faLayerGroup } from '@fortawesome/free-solid-svg-icons/faLayerGroup';
|
|
|
51
51
|
import { faCube } from '@fortawesome/free-solid-svg-icons/faCube';
|
|
52
52
|
import { faFileCode } from '@fortawesome/free-solid-svg-icons/faFileCode';
|
|
53
53
|
import { faQuestionCircle } from '@fortawesome/pro-light-svg-icons/faQuestionCircle';
|
|
54
|
+
import { faHubspot } from '@fortawesome/free-brands-svg-icons/faHubspot';
|
|
55
|
+
import { faEnvelope } from '@fortawesome/free-solid-svg-icons/faEnvelope';
|
|
56
|
+
import { faGlobe } from '@fortawesome/free-solid-svg-icons/faGlobe';
|
|
57
|
+
import { faProjectDiagram } from '@fortawesome/free-solid-svg-icons/faProjectDiagram';
|
|
58
|
+
import { faJs } from '@fortawesome/free-brands-svg-icons/faJs';
|
|
59
|
+
import { faDownload } from '@fortawesome/free-solid-svg-icons/faDownload';
|
|
60
|
+
import { faUpload } from '@fortawesome/free-solid-svg-icons/faUpload';
|
|
54
61
|
|
|
55
62
|
export const ICON_VIDEO = <FontAwesomeIcon icon = {faVideo}/>;
|
|
56
63
|
|
|
@@ -153,3 +160,17 @@ export const ICON_CUBE = <FontAwesomeIcon icon = {faCube}/>;
|
|
|
153
160
|
export const ICON_FILE_CODE = <FontAwesomeIcon icon = {faFileCode}/>;
|
|
154
161
|
|
|
155
162
|
export const ICON_HELP = <FontAwesomeIcon icon = {faQuestionCircle}/>;
|
|
163
|
+
|
|
164
|
+
export const ICON_HUBSPOT = <FontAwesomeIcon icon = {faHubspot}/>;
|
|
165
|
+
|
|
166
|
+
export const ICON_EMAIL = <FontAwesomeIcon icon = {faEnvelope}/>;
|
|
167
|
+
|
|
168
|
+
export const ICON_GLOBE = <FontAwesomeIcon icon = {faGlobe}/>;
|
|
169
|
+
|
|
170
|
+
export const ICON_PROJECT_DIAGRAM = <FontAwesomeIcon icon = {faProjectDiagram}/>;
|
|
171
|
+
|
|
172
|
+
export const ICON_JS = <FontAwesomeIcon icon = {faJs}/>;
|
|
173
|
+
|
|
174
|
+
export const ICON_DOWNLOAD = <FontAwesomeIcon icon = {faDownload}/>;
|
|
175
|
+
|
|
176
|
+
export const ICON_UPLOAD = <FontAwesomeIcon icon = {faUpload} />;
|