@imposium-hub/components 2.12.4 → 2.13.0-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.
Files changed (70) hide show
  1. package/README.md +2 -9
  2. package/dist/cjs/components/app-wrapper/AppWrapper.js +11 -14
  3. package/dist/cjs/components/app-wrapper/AppWrapper.js.map +1 -1
  4. package/dist/cjs/components/header/Header.js +2 -3
  5. package/dist/cjs/components/header/Header.js.map +1 -1
  6. package/dist/cjs/components/publish-wizard/PublishWizard.d.ts +8 -0
  7. package/dist/cjs/components/publish-wizard/PublishWizard.js +156 -94
  8. package/dist/cjs/components/publish-wizard/PublishWizard.js.map +1 -1
  9. package/dist/cjs/constants/copy.d.ts +3 -0
  10. package/dist/cjs/constants/copy.js +3 -0
  11. package/dist/cjs/constants/copy.js.map +1 -1
  12. package/dist/cjs/constants/icons.d.ts +1 -0
  13. package/dist/cjs/constants/icons.js +3 -1
  14. package/dist/cjs/constants/icons.js.map +1 -1
  15. package/dist/cjs/constants/publish.d.ts +27 -0
  16. package/dist/cjs/constants/publish.js +33 -1
  17. package/dist/cjs/constants/publish.js.map +1 -1
  18. package/dist/cjs/redux/actions/asset-list.js +1 -1
  19. package/dist/cjs/redux/actions/asset-list.js.map +1 -1
  20. package/dist/cjs/redux/actions/publish.d.ts +1 -1
  21. package/dist/cjs/redux/actions/publish.js +2 -2
  22. package/dist/cjs/redux/actions/publish.js.map +1 -1
  23. package/dist/cjs/services/API.d.ts +7 -5
  24. package/dist/cjs/services/API.js +16 -13
  25. package/dist/cjs/services/API.js.map +1 -1
  26. package/dist/esm/components/app-wrapper/AppWrapper.js +11 -14
  27. package/dist/esm/components/app-wrapper/AppWrapper.js.map +1 -1
  28. package/dist/esm/components/header/Header.js +2 -3
  29. package/dist/esm/components/header/Header.js.map +1 -1
  30. package/dist/esm/components/publish-wizard/PublishWizard.d.ts +8 -0
  31. package/dist/esm/components/publish-wizard/PublishWizard.js +152 -92
  32. package/dist/esm/components/publish-wizard/PublishWizard.js.map +1 -1
  33. package/dist/esm/constants/copy.d.ts +3 -0
  34. package/dist/esm/constants/copy.js +3 -0
  35. package/dist/esm/constants/copy.js.map +1 -1
  36. package/dist/esm/constants/icons.d.ts +1 -0
  37. package/dist/esm/constants/icons.js +2 -0
  38. package/dist/esm/constants/icons.js.map +1 -1
  39. package/dist/esm/constants/publish.d.ts +27 -0
  40. package/dist/esm/constants/publish.js +32 -0
  41. package/dist/esm/constants/publish.js.map +1 -1
  42. package/dist/esm/redux/actions/asset-list.js +1 -1
  43. package/dist/esm/redux/actions/asset-list.js.map +1 -1
  44. package/dist/esm/redux/actions/publish.d.ts +1 -1
  45. package/dist/esm/redux/actions/publish.js +2 -2
  46. package/dist/esm/redux/actions/publish.js.map +1 -1
  47. package/dist/esm/services/API.d.ts +7 -5
  48. package/dist/esm/services/API.js +16 -13
  49. package/dist/esm/services/API.js.map +1 -1
  50. package/dist/styles.css +27 -10
  51. package/dist/styles.less +33 -14
  52. package/less/components/data-table.less +1 -0
  53. package/less/components/header.less +6 -5
  54. package/less/components/publish-wizard.less +26 -9
  55. package/package.json +1 -1
  56. package/src/components/app-wrapper/AppWrapper.tsx +11 -14
  57. package/src/components/header/Header.tsx +2 -4
  58. package/src/components/publish-wizard/PublishWizard.tsx +219 -119
  59. package/src/components/publish-wizard/publish/CrMPublishCreativeSelectCell.tsx +29 -0
  60. package/src/components/publish-wizard/publish/CrMPublishCreativeSelectHeader.tsx +33 -0
  61. package/src/components/publish-wizard/publish/CrMPublishNameCell.tsx +27 -0
  62. package/src/components/publish-wizard/publish/CrMPublishPreviewCell.tsx +27 -0
  63. package/src/components/publish-wizard/publish/CrMPublishStatusCell.tsx +13 -0
  64. package/src/components/publish-wizard/publish/CrMPublishUI.tsx +211 -0
  65. package/src/constants/copy.ts +3 -0
  66. package/src/constants/icons.tsx +3 -0
  67. package/src/constants/publish.ts +36 -0
  68. package/src/redux/actions/asset-list.ts +1 -1
  69. package/src/redux/actions/publish.ts +2 -2
  70. package/src/services/API.ts +39 -23
@@ -0,0 +1,211 @@
1
+ import * as React from 'react';
2
+ import * as copy from '../../../constants/copy';
3
+ import { DataTable, HRule, Button, IImposiumAPI, TextField } from '../../..';
4
+ import { useEffect, useState, useCallback } from 'react';
5
+ import { ICON_SEARCH } from '../../../constants/icons';
6
+ import {
7
+ CREATIVE_STATUSES_TO_PUBLISH,
8
+ CRM_INTEGRATED_PROJECT_TYPES
9
+ } from '../../../constants/publish';
10
+ import { CrMPublishStatusCell } from './CrMPublishStatusCell';
11
+ import { CrMPublishPreviewCell } from './CrMPublishPreviewCell';
12
+ import { CrMPublishNameCell } from './CrMPublishNameCell';
13
+ import { CrMPublishCreativeSelectHeader } from './CrMPublishCreativeSelectHeader';
14
+ import { CrMPublishCreativeSelectCell } from './CrMPublishCreativeSelectCell';
15
+
16
+ interface ICrmPublishUIProps {
17
+ projectType: string;
18
+ publishing: boolean;
19
+ error: React.ReactNode;
20
+ api: IImposiumAPI;
21
+ creativeLibraryId: string;
22
+ projectId: string;
23
+ crmBaseUrl: string;
24
+ selectedCreatives: string[];
25
+ onUpdateSelectedCreatives: (selectedCreatives) => void;
26
+ onError: (error: string) => void;
27
+ }
28
+
29
+ export const CrMPublishUI: React.FC<ICrmPublishUIProps> = (props) => {
30
+ const {
31
+ projectType,
32
+ publishing,
33
+ error,
34
+ crmBaseUrl,
35
+ creativeLibraryId,
36
+ projectId,
37
+ api,
38
+ selectedCreatives,
39
+ onUpdateSelectedCreatives
40
+ } = props;
41
+ const [nameFilter, setNameFilter] = useState('');
42
+ const [creativeConfig, setCreativeConfig] = useState([]);
43
+
44
+ const nameSearch = (
45
+ <TextField
46
+ className='creative-name'
47
+ buttons={[
48
+ <Button
49
+ key='btn-search'
50
+ style='subtle'
51
+ size='small'>
52
+ {ICON_SEARCH}
53
+ </Button>
54
+ ]}
55
+ width='150px'
56
+ value={nameFilter}
57
+ onChange={(value) => setNameFilter(value)}
58
+ />
59
+ );
60
+
61
+ const onSelectChange = useCallback(
62
+ (creativeId: string, selected: boolean) => {
63
+ const previouslySelected = [...selectedCreatives];
64
+ if (selected) {
65
+ onUpdateSelectedCreatives([...previouslySelected, creativeId]);
66
+ } else {
67
+ onUpdateSelectedCreatives(previouslySelected.filter((id) => id !== creativeId));
68
+ }
69
+ },
70
+ [selectedCreatives, onUpdateSelectedCreatives]
71
+ );
72
+
73
+ const onSelectAllChange = useCallback(
74
+ (selected: boolean) => {
75
+ if (selected) {
76
+ const publishableCreativeIds = creativeConfig
77
+ .filter((creative) => canBePublishedTo(creative.approvalStatus))
78
+ .map((creative) => creative.creativeId);
79
+ onUpdateSelectedCreatives(publishableCreativeIds);
80
+ } else {
81
+ onUpdateSelectedCreatives([]);
82
+ }
83
+ },
84
+ [nameFilter, creativeConfig]
85
+ );
86
+
87
+ const COLUMN_CONFIG = [
88
+ {
89
+ accessor: 'selected',
90
+ width: 25,
91
+ disableResize: true,
92
+ disableSortBy: true,
93
+ Header: () => (
94
+ <CrMPublishCreativeSelectHeader
95
+ onSelectChange={onSelectAllChange}
96
+ selectedCreatives={selectedCreatives}
97
+ creativeConfig={creativeConfig}
98
+ />
99
+ ),
100
+ Cell: (cell: any) => (
101
+ <CrMPublishCreativeSelectCell
102
+ cell={cell}
103
+ onSelectChange={onSelectChange}
104
+ selectedCreatives={selectedCreatives}
105
+ />
106
+ )
107
+ },
108
+ {
109
+ accessor: 'creativeName',
110
+ Header: 'Creative Name',
111
+ width: 250,
112
+ minWidth: 250,
113
+ maxWidth: 250,
114
+ disableSortBy: true,
115
+ Cell: (cell: any) => <CrMPublishNameCell cell={cell} />,
116
+ Search: nameSearch
117
+ },
118
+ {
119
+ accessor: 'creativeId',
120
+ Header: 'ID',
121
+ width: 75,
122
+ minWidth: 75,
123
+ maxWidth: 75,
124
+ disableSortBy: true
125
+ },
126
+ {
127
+ accessor: 'numberOfVersions',
128
+ Header: 'Versions',
129
+ width: 75,
130
+ minWidth: 75,
131
+ maxWidth: 75,
132
+ disableSortBy: true
133
+ },
134
+ {
135
+ accessor: 'approvalStatus',
136
+ Header: 'Status',
137
+ width: 75,
138
+ minWidth: 75,
139
+ maxWidth: 75,
140
+ disableSortBy: true,
141
+ Cell: (cell: any) => <CrMPublishStatusCell cell={cell} />
142
+ },
143
+ {
144
+ accessor: 'preview',
145
+ Header: 'Preview',
146
+ width: 50,
147
+ minWidth: 50,
148
+ maxWidth: 50,
149
+ disableSortBy: true,
150
+ Cell: (cell: any) => (
151
+ <CrMPublishPreviewCell
152
+ cell={cell}
153
+ crmBaseUrl={crmBaseUrl}
154
+ creativeLibraryId={creativeLibraryId}
155
+ />
156
+ )
157
+ }
158
+ ];
159
+
160
+ useEffect(() => {
161
+ api.getCreativesLinkedToProject(projectId)
162
+ .then((res) => {
163
+ setCreativeConfig(res.creatives);
164
+ })
165
+ .catch((err) => {
166
+ const msg = err.response?.data?.error || err.message;
167
+ const errorCopy = copy.publish.errorGettingCreatives.replace('{{ERR}}', msg);
168
+ props.onError(errorCopy);
169
+ });
170
+ }, []);
171
+
172
+ if (projectType === CRM_INTEGRATED_PROJECT_TYPES.MULTI_CREATIVE) {
173
+ return (
174
+ <div>
175
+ <h2>{copy.publish.publishStepTitleFromCrM}</h2>
176
+ <HRule />
177
+ <p>{publishing ? copy.publish.publishInProgress : ''}</p>
178
+ <DataTable
179
+ showInterstitial={publishing}
180
+ columns={COLUMN_CONFIG}
181
+ data={
182
+ nameFilter
183
+ ? creativeConfig.filter((creative) => {
184
+ return creative.creativeName
185
+ .toLowerCase()
186
+ .includes(nameFilter.toLowerCase());
187
+ })
188
+ : creativeConfig
189
+ }
190
+ hidePaginator={true}
191
+ itemsPerPage={1000}
192
+ tightRows={true}
193
+ />
194
+ {error && <p className='publish-error'>{error}</p>}
195
+ </div>
196
+ );
197
+ } else {
198
+ return (
199
+ <div>
200
+ <h2>{copy.publish.publishStepTitle}</h2>
201
+ <HRule />
202
+ <p>{publishing ? copy.publish.publishInProgress : copy.publish.publishStepDesc}</p>
203
+ {error && <p className='publish-error'>{error}</p>}
204
+ </div>
205
+ );
206
+ }
207
+ };
208
+
209
+ export const canBePublishedTo = (approvalStatus: string) => {
210
+ return CREATIVE_STATUSES_TO_PUBLISH.includes(approvalStatus);
211
+ };
@@ -127,6 +127,8 @@ export const compositions = {
127
127
  };
128
128
 
129
129
  export const publish = {
130
+ errorGettingCreatives: 'Error getting creatives linked to project: {{ERR}}',
131
+ disabledCreativeTooltip: 'You cannot publish a project to a creative with Approved status.',
130
132
  uploadAsAssets: 'Upload as Assets',
131
133
  noVariablesError:
132
134
  'No variables found on the project. Cannot proceed with publishing to Creative Manager until at least one variable is added to the project.',
@@ -147,6 +149,7 @@ export const publish = {
147
149
 
148
150
  // publish
149
151
  publishStepTitle: 'STEP 1: Publish your Project',
152
+ publishStepTitleFromCrM: 'STEP 1: Publish your Project to selected Creatives',
150
153
  publishStepDesc:
151
154
  "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.",
152
155
 
@@ -60,6 +60,7 @@ import { faJs } from '@fortawesome/free-brands-svg-icons/faJs';
60
60
  import { faDownload } from '@fortawesome/free-solid-svg-icons/faDownload';
61
61
  import { faUpload } from '@fortawesome/free-solid-svg-icons/faUpload';
62
62
  import { faCode } from '@fortawesome/free-solid-svg-icons/faCode';
63
+ import { faEye } from '@fortawesome/free-solid-svg-icons/faEye';
63
64
  import {
64
65
  faArrowDown,
65
66
  faArrowLeft,
@@ -232,3 +233,5 @@ export const ICON_FILE_ERROR = <FontAwesomeIcon icon={faCircleExclamation} />;
232
233
  export const ICON_FILE_ADD = <FontAwesomeIcon icon={faFileCirclePlus} />;
233
234
 
234
235
  export const ICON_FILE_REPLACE = <FontAwesomeIcon icon={faFilePen} />;
236
+
237
+ export const ICON_EYE = <FontAwesomeIcon icon={faEye} />;
@@ -27,3 +27,39 @@ export const CRM_PLACEMENT_VARS = [
27
27
  export const ADSTUDIO_POST_RENDER_ACTION = 'crm-adstudio';
28
28
 
29
29
  export const ASSETS_POST_RENDER_ACTION = 'crm-asset';
30
+
31
+ export const CREATIVE_STATUSES = {
32
+ PENDING_APPROVAL: 'PENDING_APPROVAL',
33
+ UNSUBMITTED: 'UNSUBMITTED',
34
+ PRODUCTION_INCOMPLETE: 'PRODUCTION_INCOMPLETE',
35
+ APPROVED: 'APPROVED',
36
+ REJECTED: 'REJECTED',
37
+ FAILED: 'FAILED',
38
+ TRANSCODING: 'TRANSCODING',
39
+ TRANSCODING_ERROR: 'TRANSCODING_ERROR',
40
+ SUBMITTED: 'SUBMITTED'
41
+ };
42
+
43
+ export const CREATIVE_STATUS_LABELS = {
44
+ PENDING_APPROVAL: 'Pending Approval',
45
+ UNSUBMITTED: 'Production',
46
+ PRODUCTION_INCOMPLETE: 'Production',
47
+ APPROVED: 'Approved',
48
+ REJECTED: 'Rejected',
49
+ FAILED: 'Failed',
50
+ TRANSCODING: 'Transcoding',
51
+ TRANSCODING_ERROR: 'Transcoding Error',
52
+ SUBMITTED: 'Submitted'
53
+ };
54
+
55
+ export const CREATIVE_STATUSES_TO_PUBLISH = [
56
+ CREATIVE_STATUSES.UNSUBMITTED,
57
+ CREATIVE_STATUSES.PRODUCTION_INCOMPLETE,
58
+ CREATIVE_STATUSES.REJECTED,
59
+ CREATIVE_STATUSES.FAILED
60
+ ];
61
+
62
+ export const CRM_INTEGRATED_PROJECT_TYPES = {
63
+ SINGLE_CREATIVE: 'SINGLE_CREATIVE',
64
+ MULTI_CREATIVE: 'MULTI_CREATIVE'
65
+ };
@@ -87,7 +87,7 @@ export const deleteAssets = (api: IImposiumAPI, ids: string[], storyId: string):
87
87
  })
88
88
  .catch((errors: Error[]) => {
89
89
  dispatch(toggleLoading(false));
90
- reject(false);
90
+ reject(errors);
91
91
  });
92
92
  });
93
93
  };
@@ -74,10 +74,10 @@ export const cancelPublish = (api: IImposiumAPI, storyId: string) => {
74
74
  };
75
75
  };
76
76
 
77
- export const publishVersion = (api: IImposiumAPI, storyId: string) => {
77
+ export const publishVersion = (api: IImposiumAPI, storyId: string, creativeIds?: string[]) => {
78
78
  return (dispatch) => {
79
79
  return new Promise((resolve, reject) => {
80
- api.runPublish(storyId, '')
80
+ api.runPublish(storyId, '', creativeIds)
81
81
  .then((d) => {
82
82
  dispatch(getStoryPublishStatus(api, storyId))
83
83
  .then()
@@ -52,6 +52,7 @@ export interface IImposiumAPI {
52
52
  revertVersion(storyId: string, versionId: string);
53
53
  getStoryVersions(storyId: string);
54
54
  getStoryQRDesigns(creativeLibraryId: string): Promise<any | Error>;
55
+ getCreativesLinkedToProject(projectId: string): Promise<any | Error>;
55
56
  processStoryFile(storyId: string, file_key?: string, url?: string);
56
57
  getExperiences(storyId: string, params: any);
57
58
  createExperience(
@@ -113,7 +114,7 @@ export interface IImposiumAPI {
113
114
  runCut(storyId: string, actId: string, sceneId: string, cutId: string);
114
115
  runReRenderCuts(storyId: string, actId: string, sceneId: string);
115
116
  runProcessBaseVideo(storyId: string, fileKey: string);
116
- runPublish(storyId: string, message: string);
117
+ runPublish(storyId: string, message: string, creativeIds?: string[]);
117
118
  cancelPublish(storyId: string);
118
119
  cancelJobPolling();
119
120
  getAccssCredentials();
@@ -151,7 +152,7 @@ export interface IImposiumAPI {
151
152
  debugId(id: string);
152
153
  cacheActiveStory(serviceId: any, orgId: string, storyId?: string);
153
154
  getCachedStoryForOrg(serviceId: string, orgId: string);
154
- getAccessData(includeTotalRenders?: boolean, orgId?: string);
155
+ getAccessData(includeTotalRenders?: boolean, storyId?: string);
155
156
  deleteExperience(experienceId: string, eraseMedia?: boolean);
156
157
  exportExperiences(experienceId: string, params: any);
157
158
  addOrReplaceNote(experienceId: string, notes: string);
@@ -238,7 +239,8 @@ export default class API {
238
239
 
239
240
  private doRequest = async (
240
241
  config: AxiosRequestConfig,
241
- organizationId?: string
242
+ organizationId?: string,
243
+ storyId?: string
242
244
  ): Promise<any> => {
243
245
  if (this.authType === API_AUTH_TYPES.TOKEN) {
244
246
  const token = await this.getToken();
@@ -250,6 +252,10 @@ export default class API {
250
252
  headers['X-Imposium-Account-Id'] = organizationId;
251
253
  }
252
254
 
255
+ if (storyId) {
256
+ headers['X-Imposium-Project-Id'] = storyId;
257
+ }
258
+
253
259
  config.headers = headers;
254
260
  }
255
261
 
@@ -731,6 +737,13 @@ export default class API {
731
737
  });
732
738
  };
733
739
 
740
+ public getCreativesLinkedToProject = (projectId: string): Promise<any | Error> => {
741
+ return this.doRequest({
742
+ method: 'GET',
743
+ url: `/story/${projectId}/creative-library/creatives`
744
+ });
745
+ };
746
+
734
747
  public getExperiences = (storyId: string, params: any): Promise<any | Error> => {
735
748
  return this.doRequest({
736
749
  method: 'GET',
@@ -1032,14 +1045,22 @@ export default class API {
1032
1045
  });
1033
1046
  };
1034
1047
 
1035
- public runPublish = (storyId: string, message: string): Promise<any | Error> => {
1048
+ public runPublish = (
1049
+ storyId: string,
1050
+ message: string,
1051
+ creativeIds?: string[]
1052
+ ): Promise<any | Error> => {
1036
1053
  const route = `/job/publish`;
1037
1054
 
1038
- const jobConfig = {
1055
+ const jobConfig: any = {
1039
1056
  story_id: storyId,
1040
1057
  message
1041
1058
  };
1042
1059
 
1060
+ if (creativeIds) {
1061
+ jobConfig.creative_ids = creativeIds;
1062
+ }
1063
+
1043
1064
  return this.doRequest({
1044
1065
  method: 'POST',
1045
1066
  url: route,
@@ -1629,7 +1650,7 @@ export default class API {
1629
1650
  });
1630
1651
  };
1631
1652
 
1632
- public textToSpeech = (options: ITTSOptions): Promise<any> => {
1653
+ public textToSpeech = (options): Promise<any> => {
1633
1654
  const { text, voice, service } = options;
1634
1655
 
1635
1656
  let url = `/text-to-speech?text=${encodeURIComponent(
@@ -1644,18 +1665,6 @@ export default class API {
1644
1665
  url += `&speed=${options.speed}`;
1645
1666
  }
1646
1667
 
1647
- if (options.stability) {
1648
- url += `&stability=${options.stability}`;
1649
- }
1650
-
1651
- if (options.similarity) {
1652
- url += `&similarity=${options.similarity}`;
1653
- }
1654
-
1655
- if (options.style_exaggeration) {
1656
- url += `&style_exaggeration=${options.style_exaggeration}`;
1657
- }
1658
-
1659
1668
  if (options.pause_silences) {
1660
1669
  url += `&pause_silences=${options.pause_silences}`;
1661
1670
  }
@@ -1719,17 +1728,24 @@ export default class API {
1719
1728
  });
1720
1729
  };
1721
1730
 
1722
- public getAccessData = (getTotalRenders: boolean = false): Promise<any | Error> => {
1731
+ public getAccessData = (
1732
+ getTotalRenders: boolean = false,
1733
+ storyId?: string
1734
+ ): Promise<any | Error> => {
1723
1735
  let route = `/access`;
1724
1736
 
1725
1737
  if (getTotalRenders) {
1726
1738
  route += '?include_total_renders=true';
1727
1739
  }
1728
1740
 
1729
- return this.doRequest({
1730
- method: 'GET',
1731
- url: route
1732
- });
1741
+ return this.doRequest(
1742
+ {
1743
+ method: 'GET',
1744
+ url: route
1745
+ },
1746
+ null,
1747
+ storyId
1748
+ );
1733
1749
  };
1734
1750
 
1735
1751
  public removeQueueAssoc = (queueId: string, storyId: string): Promise<any> => {