@brightcove/components-embed-code-modal 1.0.7 → 1.1.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 (185) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc +23 -0
  3. package/.github/workflows/ci.yml +23 -0
  4. package/.husky/pre-commit +4 -0
  5. package/.nvmrc +1 -0
  6. package/.prettierignore +7 -0
  7. package/.prettierrc +5 -0
  8. package/.release-it.json +40 -0
  9. package/.whitesource +3 -0
  10. package/CHANGELOG.md +398 -0
  11. package/CODEOWNERS +37 -0
  12. package/PULL_REQUEST_TEMPLATE.md +17 -0
  13. package/__tests__/EmbedCode.test.tsx +51 -0
  14. package/__tests__/InteractivityProject.test.tsx +50 -0
  15. package/__tests__/PlayerPreview.test.tsx +23 -0
  16. package/__tests__/PrismPlayerPreview.test.tsx +168 -0
  17. package/__tests__/TabsHeader.test.tsx +19 -0
  18. package/__tests__/TabsSection.test.tsx +46 -0
  19. package/__tests__/TitleWithTooltip.test.tsx +45 -0
  20. package/__tests__/VideoPlayer.test.tsx +38 -0
  21. package/__tests__/embedCodeGenerator.test.ts +111 -0
  22. package/__tests__/util.test.ts +89 -0
  23. package/babel.config.json +17 -0
  24. package/build/README.md +109 -0
  25. package/build/__tests__/PrismPlayerPreview.test.d.ts +2 -0
  26. package/build/__tests__/PrismPlayerPreview.test.d.ts.map +1 -0
  27. package/{index.js → build/index.js} +1 -1
  28. package/build/index.js.map +1 -0
  29. package/build/package.json +100 -0
  30. package/{src → build/src}/js/components/prism/PrismPlayerPreview.d.ts.map +1 -1
  31. package/{src → build/src}/js/i18n.d.ts +30 -6
  32. package/{src → build/src}/js/i18n.d.ts.map +1 -1
  33. package/etc/wildcard.brightcove.com.key +27 -0
  34. package/etc/wildcard.brightcove.com.pem +96 -0
  35. package/jest/jest.setup.js +90 -0
  36. package/jest/jest.stub.js +4 -0
  37. package/jest.config.js +24 -0
  38. package/package.json +15 -5
  39. package/scripts/create-dist-pkg-prod.js +18 -0
  40. package/src/index.ts +17 -0
  41. package/src/js/EmbedCodeModal.tsx +105 -0
  42. package/src/js/components/CustomSettingsDropdown.tsx +184 -0
  43. package/src/js/components/EmbedCopySection.tsx +130 -0
  44. package/src/js/components/ModalContainer.tsx +367 -0
  45. package/src/js/components/NoPlayerModal.tsx +42 -0
  46. package/src/js/components/PlayerPreview.tsx +116 -0
  47. package/src/js/components/TabsHeader.tsx +31 -0
  48. package/src/js/components/TabsSection.tsx +74 -0
  49. package/src/js/components/TitleWithTooltip.tsx +39 -0
  50. package/src/js/components/VideoLinks.tsx +83 -0
  51. package/src/js/components/VideoPlayer.tsx +324 -0
  52. package/src/js/components/index.ts +9 -0
  53. package/src/js/components/prism/PrismLiveModal.tsx +162 -0
  54. package/src/js/components/prism/PrismPlayerControls.tsx +343 -0
  55. package/src/js/components/prism/PrismPlayerPreview.tsx +188 -0
  56. package/src/js/components/prism/index.ts +3 -0
  57. package/src/js/constants/baseUrls.ts +4 -0
  58. package/src/js/constants/embed.ts +12 -0
  59. package/src/js/constants/player.ts +32 -0
  60. package/src/js/constants/pluginsRegistry.ts +30 -0
  61. package/src/js/hooks/useGetPlayers.ts +12 -0
  62. package/src/js/i18n.ts +43 -0
  63. package/src/js/services/players-api.ts +26 -0
  64. package/src/js/services/url-shortener.ts +10 -0
  65. package/src/js/types/EmbedCodeModalProps.ts +72 -0
  66. package/src/js/types/EmbedCodeProps.ts +13 -0
  67. package/src/js/types/brightcoveEmbedCode.d.ts +18 -0
  68. package/src/js/types/players.ts +64 -0
  69. package/src/js/types/react-i18next.d.ts +8 -0
  70. package/src/js/types/studioModule.ts +7 -0
  71. package/src/js/utils/addPluginsDataToPlayers.ts +59 -0
  72. package/src/js/utils/call.ts +31 -0
  73. package/src/js/utils/dimensions.ts +53 -0
  74. package/src/js/utils/embedCodeGenerator.ts +120 -0
  75. package/src/js/utils/featureSwitches.ts +16 -0
  76. package/src/js/utils/util.ts +153 -0
  77. package/src/module.tsx +280 -0
  78. package/src/styles/CustomSettingsDropdown.sass +42 -0
  79. package/src/styles/EmbedCode.sass +30 -0
  80. package/src/styles/EmbedCodeModal.sass +76 -0
  81. package/src/styles/base.sass +1 -0
  82. package/src/styles/prism/PrismLiveModal.sass +155 -0
  83. package/src/styles/theme.sass +11 -0
  84. package/src/styles/typings.td.ts +9 -0
  85. package/src/translations/en.json +65 -0
  86. package/src/translations/es.json +65 -0
  87. package/src/translations/fr.json +65 -0
  88. package/src/translations/ja.json +65 -0
  89. package/src/translations/ko.json +65 -0
  90. package/src/translations/zh.json +65 -0
  91. package/src/types/studio.ts +197 -0
  92. package/tsconfig.json +34 -0
  93. package/webpack.config.js +117 -0
  94. package/index.js.map +0 -1
  95. /package/{__tests__ → build/__tests__}/EmbedCode.test.d.ts +0 -0
  96. /package/{__tests__ → build/__tests__}/EmbedCode.test.d.ts.map +0 -0
  97. /package/{__tests__ → build/__tests__}/InteractivityProject.test.d.ts +0 -0
  98. /package/{__tests__ → build/__tests__}/InteractivityProject.test.d.ts.map +0 -0
  99. /package/{__tests__ → build/__tests__}/PlayerPreview.test.d.ts +0 -0
  100. /package/{__tests__ → build/__tests__}/PlayerPreview.test.d.ts.map +0 -0
  101. /package/{__tests__ → build/__tests__}/TabsHeader.test.d.ts +0 -0
  102. /package/{__tests__ → build/__tests__}/TabsHeader.test.d.ts.map +0 -0
  103. /package/{__tests__ → build/__tests__}/TabsSection.test.d.ts +0 -0
  104. /package/{__tests__ → build/__tests__}/TabsSection.test.d.ts.map +0 -0
  105. /package/{__tests__ → build/__tests__}/TitleWithTooltip.test.d.ts +0 -0
  106. /package/{__tests__ → build/__tests__}/TitleWithTooltip.test.d.ts.map +0 -0
  107. /package/{__tests__ → build/__tests__}/VideoPlayer.test.d.ts +0 -0
  108. /package/{__tests__ → build/__tests__}/VideoPlayer.test.d.ts.map +0 -0
  109. /package/{__tests__ → build/__tests__}/embedCodeGenerator.test.d.ts +0 -0
  110. /package/{__tests__ → build/__tests__}/embedCodeGenerator.test.d.ts.map +0 -0
  111. /package/{__tests__ → build/__tests__}/util.test.d.ts +0 -0
  112. /package/{__tests__ → build/__tests__}/util.test.d.ts.map +0 -0
  113. /package/{src → build/src}/index.d.ts +0 -0
  114. /package/{src → build/src}/index.d.ts.map +0 -0
  115. /package/{src → build/src}/js/EmbedCodeModal.d.ts +0 -0
  116. /package/{src → build/src}/js/EmbedCodeModal.d.ts.map +0 -0
  117. /package/{src → build/src}/js/components/CustomSettingsDropdown.d.ts +0 -0
  118. /package/{src → build/src}/js/components/CustomSettingsDropdown.d.ts.map +0 -0
  119. /package/{src → build/src}/js/components/EmbedCopySection.d.ts +0 -0
  120. /package/{src → build/src}/js/components/EmbedCopySection.d.ts.map +0 -0
  121. /package/{src → build/src}/js/components/ModalContainer.d.ts +0 -0
  122. /package/{src → build/src}/js/components/ModalContainer.d.ts.map +0 -0
  123. /package/{src → build/src}/js/components/NoPlayerModal.d.ts +0 -0
  124. /package/{src → build/src}/js/components/NoPlayerModal.d.ts.map +0 -0
  125. /package/{src → build/src}/js/components/PlayerPreview.d.ts +0 -0
  126. /package/{src → build/src}/js/components/PlayerPreview.d.ts.map +0 -0
  127. /package/{src → build/src}/js/components/TabsHeader.d.ts +0 -0
  128. /package/{src → build/src}/js/components/TabsHeader.d.ts.map +0 -0
  129. /package/{src → build/src}/js/components/TabsSection.d.ts +0 -0
  130. /package/{src → build/src}/js/components/TabsSection.d.ts.map +0 -0
  131. /package/{src → build/src}/js/components/TitleWithTooltip.d.ts +0 -0
  132. /package/{src → build/src}/js/components/TitleWithTooltip.d.ts.map +0 -0
  133. /package/{src → build/src}/js/components/VideoLinks.d.ts +0 -0
  134. /package/{src → build/src}/js/components/VideoLinks.d.ts.map +0 -0
  135. /package/{src → build/src}/js/components/VideoPlayer.d.ts +0 -0
  136. /package/{src → build/src}/js/components/VideoPlayer.d.ts.map +0 -0
  137. /package/{src → build/src}/js/components/index.d.ts +0 -0
  138. /package/{src → build/src}/js/components/index.d.ts.map +0 -0
  139. /package/{src → build/src}/js/components/prism/PrismLiveModal.d.ts +0 -0
  140. /package/{src → build/src}/js/components/prism/PrismLiveModal.d.ts.map +0 -0
  141. /package/{src → build/src}/js/components/prism/PrismPlayerControls.d.ts +0 -0
  142. /package/{src → build/src}/js/components/prism/PrismPlayerControls.d.ts.map +0 -0
  143. /package/{src → build/src}/js/components/prism/PrismPlayerPreview.d.ts +0 -0
  144. /package/{src → build/src}/js/components/prism/index.d.ts +0 -0
  145. /package/{src → build/src}/js/components/prism/index.d.ts.map +0 -0
  146. /package/{src → build/src}/js/constants/baseUrls.d.ts +0 -0
  147. /package/{src → build/src}/js/constants/baseUrls.d.ts.map +0 -0
  148. /package/{src → build/src}/js/constants/embed.d.ts +0 -0
  149. /package/{src → build/src}/js/constants/embed.d.ts.map +0 -0
  150. /package/{src → build/src}/js/constants/player.d.ts +0 -0
  151. /package/{src → build/src}/js/constants/player.d.ts.map +0 -0
  152. /package/{src → build/src}/js/constants/pluginsRegistry.d.ts +0 -0
  153. /package/{src → build/src}/js/constants/pluginsRegistry.d.ts.map +0 -0
  154. /package/{src → build/src}/js/hooks/useGetPlayers.d.ts +0 -0
  155. /package/{src → build/src}/js/hooks/useGetPlayers.d.ts.map +0 -0
  156. /package/{src → build/src}/js/services/players-api.d.ts +0 -0
  157. /package/{src → build/src}/js/services/players-api.d.ts.map +0 -0
  158. /package/{src → build/src}/js/services/url-shortener.d.ts +0 -0
  159. /package/{src → build/src}/js/services/url-shortener.d.ts.map +0 -0
  160. /package/{src → build/src}/js/types/EmbedCodeModalProps.d.ts +0 -0
  161. /package/{src → build/src}/js/types/EmbedCodeModalProps.d.ts.map +0 -0
  162. /package/{src → build/src}/js/types/EmbedCodeProps.d.ts +0 -0
  163. /package/{src → build/src}/js/types/EmbedCodeProps.d.ts.map +0 -0
  164. /package/{src → build/src}/js/types/players.d.ts +0 -0
  165. /package/{src → build/src}/js/types/players.d.ts.map +0 -0
  166. /package/{src → build/src}/js/types/studioModule.d.ts +0 -0
  167. /package/{src → build/src}/js/types/studioModule.d.ts.map +0 -0
  168. /package/{src → build/src}/js/utils/addPluginsDataToPlayers.d.ts +0 -0
  169. /package/{src → build/src}/js/utils/addPluginsDataToPlayers.d.ts.map +0 -0
  170. /package/{src → build/src}/js/utils/call.d.ts +0 -0
  171. /package/{src → build/src}/js/utils/call.d.ts.map +0 -0
  172. /package/{src → build/src}/js/utils/dimensions.d.ts +0 -0
  173. /package/{src → build/src}/js/utils/dimensions.d.ts.map +0 -0
  174. /package/{src → build/src}/js/utils/embedCodeGenerator.d.ts +0 -0
  175. /package/{src → build/src}/js/utils/embedCodeGenerator.d.ts.map +0 -0
  176. /package/{src → build/src}/js/utils/featureSwitches.d.ts +0 -0
  177. /package/{src → build/src}/js/utils/featureSwitches.d.ts.map +0 -0
  178. /package/{src → build/src}/js/utils/util.d.ts +0 -0
  179. /package/{src → build/src}/js/utils/util.d.ts.map +0 -0
  180. /package/{src → build/src}/module.d.ts +0 -0
  181. /package/{src → build/src}/module.d.ts.map +0 -0
  182. /package/{src → build/src}/styles/typings.td.d.ts +0 -0
  183. /package/{src → build/src}/styles/typings.td.d.ts.map +0 -0
  184. /package/{src → build/src}/types/studio.d.ts +0 -0
  185. /package/{src → build/src}/types/studio.d.ts.map +0 -0
@@ -0,0 +1,324 @@
1
+ import React, { useEffect, useState, useMemo, useCallback } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import ReactPlayerLoader from '@brightcove/react-player-loader';
4
+ import {
5
+ Checkbox,
6
+ Hideable,
7
+ Input,
8
+ PlayerSelect,
9
+ Select,
10
+ } from '@brightcove/studio-components';
11
+ import {
12
+ VideoPayload,
13
+ ProjectPayload,
14
+ EmbedCodeModalTypes,
15
+ EmbedCodeProperties,
16
+ LivePayload,
17
+ } from 'js/types/EmbedCodeModalProps';
18
+ import {
19
+ PlayerSelectItem,
20
+ PlayersObject,
21
+ PlayersObjectItem,
22
+ } from 'js/types/players';
23
+ import css from 'styles/EmbedCodeModal.sass';
24
+ import {
25
+ getUrlBase,
26
+ getVideoPreviewLink,
27
+ PREVIEW_URL_BASE,
28
+ VideoPreviewLinkOptions,
29
+ } from 'js/utils/util';
30
+ import {
31
+ VideoLinks,
32
+ TitleWithTooltip,
33
+ TabsSection,
34
+ CustomSettingsDropdown,
35
+ } from 'js/components';
36
+ import { DEFAULT_PLAYER_ID, PLAYERS } from 'js/constants/player';
37
+ import { EMBED_DEFAULT } from 'js/constants/embed';
38
+ import { getFavoritePlayer } from 'js/utils/featureSwitches';
39
+ import cx from 'classnames';
40
+
41
+ export const VideoPlayer = ({
42
+ video,
43
+ embedCodeModalType,
44
+ playerListForSelection,
45
+ players,
46
+ hasCreatedPlayer,
47
+ embedCodeProperties,
48
+ showDVR,
49
+ onDVRClick,
50
+ dvrTime,
51
+ showLowLatency,
52
+ onLowLatencyClick,
53
+ adConfigValue,
54
+ onAdConfigChange,
55
+ ssai = false,
56
+ adConfigOptions = [],
57
+ }: {
58
+ video: VideoPayload | ProjectPayload | LivePayload;
59
+ embedCodeModalType: EmbedCodeModalTypes;
60
+ playerListForSelection: PlayerSelectItem[];
61
+ players: PlayersObject;
62
+ hasCreatedPlayer?: boolean;
63
+ embedCodeProperties?: EmbedCodeProperties;
64
+ showDVR?: boolean;
65
+ onDVRClick?: (newValue: boolean) => void;
66
+ dvrTime?: number;
67
+ showLowLatency?: boolean;
68
+ onLowLatencyClick?: (newValue: boolean) => void;
69
+ adConfigValue?: string;
70
+ onAdConfigChange?: (value: string) => void;
71
+ ssai?: boolean;
72
+ adConfigOptions?: Array<{ label: string; value: string }>;
73
+ }) => {
74
+ const { t } = useTranslation();
75
+ const [player, setPlayer] = useState<PlayersObjectItem>(PLAYERS.default);
76
+ const [previewUrl, setPreviewUrl] = useState<string>('');
77
+ const [embedProperties, setEmbedProperties] = useState<EmbedCodeProperties>(
78
+ embedCodeProperties ? embedCodeProperties : EMBED_DEFAULT,
79
+ );
80
+ const [allowLowLatency, setAllowLowLatency] = useState(true);
81
+ const [allowDVR, setAllowDVR] = useState(!showLowLatency);
82
+ const [time, setTime] = useState<number>(dvrTime || 0);
83
+
84
+ useEffect(() => {
85
+ setTime(dvrTime || 0);
86
+ }, [dvrTime]);
87
+
88
+ useEffect(() => {
89
+ if (playerListForSelection.length === 0) return;
90
+ const favoritePlayer = getFavoritePlayer();
91
+ const player = players[favoritePlayer];
92
+
93
+ if (
94
+ playerListForSelection.find((selection) => selection.value === player?.id)
95
+ ) {
96
+ setPlayer(player);
97
+ } else {
98
+ setPlayer(players[playerListForSelection[0].value]);
99
+ }
100
+ // eslint-disable-next-line react-hooks/exhaustive-deps
101
+ }, [playerListForSelection]);
102
+
103
+ const onPlayerSelectChange = (id: string) => {
104
+ const player = players[id];
105
+ setPlayer(player);
106
+ };
107
+
108
+ const interactivityProjectId = useMemo(() => {
109
+ return embedCodeModalType === EmbedCodeModalTypes.PROJECT
110
+ ? (video as ProjectPayload).interactivityProjectId
111
+ : null;
112
+ }, [video, embedCodeModalType]);
113
+
114
+ const onEmbedCreated = useCallback(
115
+ (el: HTMLElement) => {
116
+ if (interactivityProjectId) {
117
+ el.setAttribute(
118
+ 'data-interactivity-project-id',
119
+ interactivityProjectId,
120
+ );
121
+ }
122
+ },
123
+ [interactivityProjectId],
124
+ );
125
+
126
+ const sharedProps: {
127
+ accountId: string;
128
+ playerId: string;
129
+ isCampaign: boolean;
130
+ isViewerIdSource: boolean;
131
+ isBcMapTracking: boolean;
132
+ videoId?: string;
133
+ interactivityProjectId?: string;
134
+ livePlaybackToken?: string;
135
+ adConfigId?: string;
136
+ } = {
137
+ accountId: video.accountId,
138
+ playerId:
139
+ player?.id ||
140
+ (playerListForSelection.length > 0
141
+ ? playerListForSelection[0].value
142
+ : DEFAULT_PLAYER_ID),
143
+ isCampaign: player?.hasCampaignPlugin || false,
144
+ isViewerIdSource: player?.hasViewerIDSource || false,
145
+ isBcMapTracking: player?.hasBcMapTracking || false,
146
+ videoId: video.videoId,
147
+ };
148
+
149
+ const name = interactivityProjectId
150
+ ? (video as ProjectPayload).interactivityProjectName
151
+ : (video as VideoPayload).videoName;
152
+ const id = interactivityProjectId || video.videoId;
153
+
154
+ if (interactivityProjectId) {
155
+ sharedProps.interactivityProjectId = interactivityProjectId;
156
+ }
157
+
158
+ const { livePlaybackToken, adConfigId } = video as LivePayload;
159
+
160
+ if (livePlaybackToken) {
161
+ sharedProps.livePlaybackToken = livePlaybackToken;
162
+ }
163
+
164
+ if (adConfigId) {
165
+ sharedProps.adConfigId = adConfigId;
166
+ }
167
+
168
+ const {
169
+ adConfigId: sharedAdConfigId,
170
+ livePlaybackToken: sharedLivePlaybackToken,
171
+ ...restSharedProps
172
+ } = sharedProps;
173
+
174
+ const playerProps = {
175
+ ...restSharedProps,
176
+ ...(sharedAdConfigId ? {} : { adConfigId: sharedAdConfigId }),
177
+ ...(sharedLivePlaybackToken
178
+ ? {}
179
+ : { livePlaybackToken: sharedLivePlaybackToken }),
180
+ };
181
+
182
+ useEffect(() => {
183
+ if (player?.id) {
184
+ const options: VideoPreviewLinkOptions = {
185
+ accountId: video.accountId,
186
+ playerId: player.id,
187
+ videoId: video.videoId,
188
+ };
189
+ if (interactivityProjectId) {
190
+ options.interactivityProjectId = interactivityProjectId;
191
+ }
192
+
193
+ if (adConfigId) {
194
+ options.adConfigId = adConfigId;
195
+ }
196
+
197
+ if (livePlaybackToken) {
198
+ options.livePlaybackToken = livePlaybackToken;
199
+ }
200
+
201
+ setPreviewUrl(getVideoPreviewLink(options));
202
+ }
203
+ }, [player, video, interactivityProjectId, adConfigId, livePlaybackToken]);
204
+
205
+ return (
206
+ <>
207
+ <div className={css.leftContent}>
208
+ <PlayerSelect
209
+ label={t('player')}
210
+ tooltip={
211
+ <>
212
+ <div>{t('tooltipTextNew')}</div>
213
+ <a href={t('learnmore')} target='_blank' rel='noreferrer'>
214
+ {t('tooltipLink')}
215
+ </a>
216
+ </>
217
+ }
218
+ selectedPlayer={player?.id || DEFAULT_PLAYER_ID}
219
+ players={playerListForSelection}
220
+ onChange={onPlayerSelectChange}
221
+ inputClassName={css.playerSelect}
222
+ testName='embed-player-select'
223
+ />
224
+ {embedCodeModalType === EmbedCodeModalTypes.LIVE &&
225
+ ssai &&
226
+ adConfigOptions.length > 0 &&
227
+ onAdConfigChange && (
228
+ <Select
229
+ label={t('adConfiguration')}
230
+ value={adConfigValue || adConfigOptions[0]?.value || ''}
231
+ options={adConfigOptions}
232
+ onChange={onAdConfigChange}
233
+ testName='ad-config-dropdown'
234
+ />
235
+ )}
236
+ {hasCreatedPlayer ? (
237
+ <iframe
238
+ src={`${PREVIEW_URL_BASE()}/${sharedProps.accountId}/players/${
239
+ sharedProps.playerId
240
+ }/preview/embeds/default/master/index.html?interactivityProjectId=${
241
+ sharedProps.interactivityProjectId
242
+ }&videoId=${sharedProps.videoId}`}
243
+ allowFullScreen
244
+ allow='autoplay;encrypted-media;fullscreen'
245
+ width='539'
246
+ height='303.2'
247
+ data-interactivity-project-id={interactivityProjectId}
248
+ ></iframe>
249
+ ) : (
250
+ <ReactPlayerLoader
251
+ {...playerProps}
252
+ baseUrl={getUrlBase()}
253
+ attrs={{ className: css.playerLoader }}
254
+ embedType='iframe'
255
+ refNode='player-container'
256
+ onEmbedCreated={onEmbedCreated}
257
+ />
258
+ )}
259
+ <Hideable show={player?.hasCustomPlugins}>
260
+ <span className={css.customPluginNotice}>
261
+ {t('customPluginNotice')}
262
+ </span>
263
+ </Hideable>
264
+ <VideoLinks previewUrl={previewUrl} playerUrl={previewUrl} />
265
+ </div>
266
+ <div
267
+ className={cx(css.rightContent, {
268
+ [css.expandRightContent]: showDVR,
269
+ })}
270
+ >
271
+ <TitleWithTooltip name={name} id={id} />
272
+ {(embedCodeModalType === EmbedCodeModalTypes.VIDEO ||
273
+ embedCodeModalType === EmbedCodeModalTypes.PROJECT ||
274
+ embedCodeModalType === EmbedCodeModalTypes.LIVE) && (
275
+ <CustomSettingsDropdown
276
+ setEmbedProperties={setEmbedProperties}
277
+ embedProperties={embedProperties}
278
+ />
279
+ )}
280
+ <TabsSection {...sharedProps} embedCodeProperties={embedProperties} />
281
+ {showLowLatency ? (
282
+ <Checkbox
283
+ disabled={showDVR && allowDVR}
284
+ checked={allowLowLatency}
285
+ onChange={() => {
286
+ onLowLatencyClick?.(!allowLowLatency);
287
+ setAllowLowLatency(!allowLowLatency);
288
+ }}
289
+ className={css.dvrCheckbox}
290
+ testName='low-latency-checkbox'
291
+ >
292
+ {t('lowLatency')}
293
+ </Checkbox>
294
+ ) : null}
295
+ {showDVR && (
296
+ <div>
297
+ <Checkbox
298
+ disabled={showLowLatency && allowLowLatency}
299
+ checked={allowDVR}
300
+ onChange={() => {
301
+ onDVRClick?.(!allowDVR);
302
+ setAllowDVR(!allowDVR);
303
+ }}
304
+ className={css.dvrCheckbox}
305
+ testName='dvr-checkbox'
306
+ >
307
+ {t('dvr.allowDVR')}
308
+ </Checkbox>
309
+ {allowDVR && (
310
+ <Input
311
+ className={css.timeInput}
312
+ label={t('dvr.inputLabel')}
313
+ value={time}
314
+ description={t('dvr.inputDescription')}
315
+ disabled
316
+ testName='dvr-time-input'
317
+ />
318
+ )}
319
+ </div>
320
+ )}
321
+ </div>
322
+ </>
323
+ );
324
+ };
@@ -0,0 +1,9 @@
1
+ export * from './EmbedCopySection';
2
+ export * from './ModalContainer';
3
+ export * from './TitleWithTooltip';
4
+ export * from './TabsHeader';
5
+ export * from './TabsSection';
6
+ export * from './VideoLinks';
7
+ export * from './VideoPlayer';
8
+ export * from './PlayerPreview';
9
+ export * from './CustomSettingsDropdown';
@@ -0,0 +1,162 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { PrismModal } from '@brightcove/prism-core';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { PlayerSelectItem, PlayersObject } from 'js/types/players';
5
+ import {
6
+ LivePayload,
7
+ EmbedCodeProperties,
8
+ EmbedCodeAspectRatio,
9
+ EmbedCodeUnits,
10
+ } from 'js/types/EmbedCodeModalProps';
11
+ import { getVideoPreviewLink, VideoPreviewLinkOptions } from 'js/utils/util';
12
+ import { getFavoritePlayer } from 'js/utils/featureSwitches';
13
+ import { PrismPlayerControls } from './PrismPlayerControls';
14
+ import { PrismPlayerPreview } from './PrismPlayerPreview';
15
+
16
+ import css from 'styles/prism/PrismLiveModal.sass';
17
+
18
+ interface PrismLiveModalProps {
19
+ isOpen: boolean;
20
+ onClose: () => void;
21
+ video: LivePayload;
22
+ players: PlayersObject;
23
+ playerListForSelection: PlayerSelectItem[];
24
+ showDVR?: boolean;
25
+ onDVRClick?: (newValue: boolean) => void;
26
+ dvrTime?: number;
27
+ showLowLatency?: boolean;
28
+ onLowLatencyClick?: (newValue: boolean) => void;
29
+ adConfigValue?: string;
30
+ onAdConfigChange?: (value: string) => void;
31
+ ssai?: boolean;
32
+ adConfigOptions?: Array<{ label: string; value: string }>;
33
+ }
34
+
35
+ const DEFAULT_PLAYER_ID = 'default';
36
+ const DEFAULT_EMBED_PROPERTIES: EmbedCodeProperties = {
37
+ width: 960,
38
+ height: 540,
39
+ units: EmbedCodeUnits.PX,
40
+ responsive: false,
41
+ aspectRatio: EmbedCodeAspectRatio.SIXTEEN_NINE,
42
+ };
43
+
44
+ export const PrismLiveModal = ({
45
+ isOpen,
46
+ onClose,
47
+ video,
48
+ players,
49
+ playerListForSelection,
50
+ showDVR,
51
+ onDVRClick,
52
+ dvrTime,
53
+ showLowLatency,
54
+ onLowLatencyClick,
55
+ adConfigValue,
56
+ onAdConfigChange,
57
+ ssai,
58
+ adConfigOptions,
59
+ }: PrismLiveModalProps) => {
60
+ const { t } = useTranslation();
61
+ const [selectedPlayer, setSelectedPlayer] =
62
+ useState<string>(DEFAULT_PLAYER_ID);
63
+ const [embedProperties, setEmbedProperties] = useState<EmbedCodeProperties>(
64
+ DEFAULT_EMBED_PROPERTIES,
65
+ );
66
+ const [previewUrl, setPreviewUrl] = useState<string>('');
67
+
68
+ // Initialize selected player
69
+ useEffect(() => {
70
+ if (playerListForSelection.length === 0) {
71
+ return;
72
+ }
73
+
74
+ const favoritePlayer = getFavoritePlayer();
75
+ const player = players[favoritePlayer];
76
+
77
+ if (
78
+ playerListForSelection.find((selection) => selection.value === player?.id)
79
+ ) {
80
+ setSelectedPlayer(player.id);
81
+ } else {
82
+ setSelectedPlayer(playerListForSelection[0].value);
83
+ }
84
+ }, [playerListForSelection, players]);
85
+
86
+ // Update preview URL when player or video changes
87
+ useEffect(() => {
88
+ if (!selectedPlayer) {
89
+ setPreviewUrl('');
90
+ return;
91
+ }
92
+
93
+ const options: VideoPreviewLinkOptions = {
94
+ accountId: video.accountId,
95
+ playerId: selectedPlayer,
96
+ videoId: video.videoId,
97
+ };
98
+
99
+ // Use the selected adConfigValue from dropdown, fallback to video.adConfigId
100
+ if (adConfigValue) {
101
+ options.adConfigId = adConfigValue;
102
+ } else if (video.adConfigId) {
103
+ options.adConfigId = video.adConfigId;
104
+ }
105
+
106
+ if (video.livePlaybackToken) {
107
+ options.livePlaybackToken = video.livePlaybackToken;
108
+ }
109
+
110
+ setPreviewUrl(getVideoPreviewLink(options));
111
+ }, [selectedPlayer, video, adConfigValue]);
112
+
113
+ const handlePlayerChange = (playerId: string) => {
114
+ setSelectedPlayer(playerId);
115
+ };
116
+
117
+ return (
118
+ <PrismModal
119
+ isOpen={isOpen}
120
+ onClose={onClose}
121
+ title={(t('modalHeader') as string) || 'Publish Video'}
122
+ onPrimaryAction={onClose}
123
+ primaryButtonText={t('done') as string}
124
+ cancelButtonText={t('cancel') as string}
125
+ className={css.prismLiveModal}
126
+ >
127
+ <div className={css.prismLiveModalContent}>
128
+ {/* Left Column: Player Controls */}
129
+ <PrismPlayerControls
130
+ video={video}
131
+ players={players}
132
+ playerListForSelection={playerListForSelection}
133
+ selectedPlayer={selectedPlayer}
134
+ onPlayerChange={handlePlayerChange}
135
+ embedProperties={embedProperties}
136
+ setEmbedProperties={setEmbedProperties}
137
+ showDVR={showDVR}
138
+ onDVRClick={onDVRClick}
139
+ dvrTime={dvrTime}
140
+ showLowLatency={showLowLatency}
141
+ onLowLatencyClick={onLowLatencyClick}
142
+ adConfigValue={adConfigValue}
143
+ onAdConfigChange={onAdConfigChange}
144
+ ssai={ssai}
145
+ adConfigOptions={adConfigOptions}
146
+ />
147
+
148
+ {/* Right Column: Player Preview */}
149
+ <div className={css.prismRightColumn}>
150
+ <PrismPlayerPreview
151
+ accountId={video.accountId}
152
+ playerId={selectedPlayer}
153
+ videoId={video.videoId}
154
+ previewUrl={previewUrl}
155
+ livePlaybackToken={video.livePlaybackToken}
156
+ adConfigId={adConfigValue || video.adConfigId}
157
+ />
158
+ </div>
159
+ </div>
160
+ </PrismModal>
161
+ );
162
+ };