1 | "use strict";
|
2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
6 | return c > 3 && r && Object.defineProperty(target, key, r), r;
|
7 | };
|
8 | var __importStar = (this && this.__importStar) || function (mod) {
|
9 | if (mod && mod.__esModule) return mod;
|
10 | var result = {};
|
11 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
12 | result["default"] = mod;
|
13 | return result;
|
14 | };
|
15 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
16 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
17 | };
|
18 | Object.defineProperty(exports, "__esModule", { value: true });
|
19 | const React = __importStar(require("react"));
|
20 | const react_draggable_1 = __importDefault(require("react-draggable"));
|
21 | const with_html_1 = __importDefault(require("react-markdown/with-html"));
|
22 | const plyr_1 = __importDefault(require("plyr"));
|
23 | const kbc_intl_1 = require("@kano/kbc-intl");
|
24 | const kbc_icons_1 = require("@kano/kbc-icons");
|
25 | const kbc_telemetry_1 = require("@kano/kbc-telemetry");
|
26 | const kbc_utils_1 = require("@kano/kbc-utils");
|
27 | require("./styles/main.scss");
|
28 | const messages_1 = __importDefault(require("./messages"));
|
29 | const icons_1 = require("./icons");
|
30 | class VideoPlyrComp extends React.Component {
|
31 | componentDidMount() {
|
32 | this.initPlayer();
|
33 | }
|
34 | initPlayer() {
|
35 | const options = {
|
36 | controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'fullscreen'],
|
37 | autoplay: true,
|
38 | };
|
39 | this.player = new plyr_1.default('#plyr', options);
|
40 | const { action } = this.props;
|
41 | this.player.on('play', event => action('video-on-play'));
|
42 | this.player.on('pause', event => action('video-on-pause'));
|
43 | this.player.on('ended', event => action('video-on-ended'));
|
44 | const debounceSeek = kbc_utils_1.debounce(() => action('video-on-seeked'), 250);
|
45 | this.player.on('seeked', event => debounceSeek());
|
46 | this._checkProviderProps();
|
47 | }
|
48 | componentDidUpdate(prevProps) {
|
49 | const { url, provider } = this.props;
|
50 | if (prevProps.url !== url) {
|
51 | this._checkProviderProps();
|
52 | if (provider === 'youtube') {
|
53 | this;
|
54 | this.player.source = {
|
55 | type: 'video',
|
56 | sources: [
|
57 | {
|
58 | src: url,
|
59 | provider: 'youtube',
|
60 | },
|
61 | ],
|
62 | };
|
63 | }
|
64 | else {
|
65 | this.player.source = {
|
66 | type: 'video',
|
67 | sources: [
|
68 | {
|
69 | src: url,
|
70 | type: 'video/mp4',
|
71 | },
|
72 | ]
|
73 | };
|
74 | }
|
75 | }
|
76 | }
|
77 | componentWillUnmount() {
|
78 | if (this.player) {
|
79 | this.player.destroy();
|
80 | }
|
81 | }
|
82 | _checkProviderProps() {
|
83 | const { provider, url } = this.props;
|
84 | if (provider === 'youtube' && url.startsWith('http'))
|
85 | console.error('To use youtube as a video provider you must only pass the video id and not the full url i.e: hDOV6w3J3eU');
|
86 | }
|
87 | render() {
|
88 | const { url, action, showCountdown, counter, height, provider, intl } = this.props;
|
89 | return (React.createElement("div", { className: "plyr-wrapper", style: { height: `${height}px` } },
|
90 | React.createElement("button", { className: `plyr-countdown kbc-button--remove-browser-defaults${showCountdown ? ' animate--fade-in' : ''}`, onClick: () => action('next-step') }, intl.formatMessage(Object.assign({}, messages_1.default.nextStepIn), { counter })),
|
91 | provider === 'default' ? (React.createElement("video", { autoPlay: true, id: "plyr", src: url, style: { width: '100%' } }, intl.formatMessage(Object.assign({}, messages_1.default.browserNotSupported)))) : provider === 'youtube' ? (React.createElement("div", { id: "plyr", className: "plyr__video-embed", "data-plyr-provider": "youtube", "data-plyr-embed-id": url, style: { width: '100%' } })) : ''));
|
92 | }
|
93 | }
|
94 | exports.VideoPlyr = kbc_intl_1.withIntl(VideoPlyrComp);
|
95 | let KbcVideo = class KbcVideo extends React.Component {
|
96 | constructor(props) {
|
97 | super(props);
|
98 | this.setInactivity = () => {
|
99 | clearInterval(this.inactiveInterval);
|
100 | this.startInactiveInterval();
|
101 | this.setState({ inactive: false });
|
102 | };
|
103 | this.state = {
|
104 | videoSize: props.sizingConfig.defaultSize,
|
105 | ratio: props.sizingConfig.defaultRatio,
|
106 | endedAnimate: false,
|
107 | stage: 0,
|
108 | finalStage: props.steps ? props.steps.length - 1 : null,
|
109 | unlockedSteps: [],
|
110 | minimised: false,
|
111 | currentTranslation: null,
|
112 | showCountdown: false,
|
113 | counter: null,
|
114 | inactive: false,
|
115 | isPlaying: false,
|
116 | isSizeDefault: true,
|
117 | };
|
118 | this.videoRef = React.createRef();
|
119 | }
|
120 | componentDidMount() {
|
121 | const { steps } = this.props;
|
122 | if (steps) {
|
123 | this.setState({ unlockedSteps: [0] });
|
124 | }
|
125 | this.videoRef.current.addEventListener('click', this.setInactivity);
|
126 | this.startInactiveInterval();
|
127 | }
|
128 | componentDidUpdate(prevProps) {
|
129 | const { steps } = this.props;
|
130 | if (prevProps.steps !== steps) {
|
131 | if (steps) {
|
132 | this.setState({ stage: 0, unlockedSteps: [0], finalStage: steps.length - 1 });
|
133 | }
|
134 | }
|
135 | }
|
136 | componentWillUnmount() {
|
137 | if (this.videoRef && this.videoRef.current) {
|
138 | this.videoRef.current.removeEventListener('click', this.setInactivity);
|
139 | }
|
140 | if (this.inactiveInterval) {
|
141 | clearInterval(this.inactiveInterval);
|
142 | this.inactiveInterval = null;
|
143 | }
|
144 | if (this.counterInterval) {
|
145 | clearInterval(this.counterInterval);
|
146 | this.counterInterval = null;
|
147 | }
|
148 | if (this.isPlayingInterval) {
|
149 | clearInterval(this.isPlayingInterval);
|
150 | this.isPlayingInterval = null;
|
151 | }
|
152 | }
|
153 | startInactiveInterval() {
|
154 | this.inactiveInterval = setInterval(() => {
|
155 | if (!this.state.inactive) {
|
156 | this.setState({ inactive: true });
|
157 | clearInterval(this.inactiveInterval);
|
158 | }
|
159 | }, 45000);
|
160 | }
|
161 | startIsPlaying() {
|
162 | if (this.state.isPlaying)
|
163 | return;
|
164 | this.setState({ isPlaying: true });
|
165 | this.isPlayingInterval = setInterval(() => {
|
166 | if (this.state.isPlaying) {
|
167 | this.props.tracking.trackEvent({ event: 'video_playing' });
|
168 | }
|
169 | else {
|
170 | this.clearIsPlaying();
|
171 | }
|
172 | }, 30000);
|
173 | }
|
174 | clearIsPlaying() {
|
175 | if (this.isPlayingInterval === null && !this.state.isPlaying)
|
176 | return;
|
177 | clearInterval(this.isPlayingInterval);
|
178 | this.isPlayingInterval = null;
|
179 | this.setState({ isPlaying: false });
|
180 | }
|
181 | setVideoSize() {
|
182 | const { sizingConfig: { defaultSize, mediumSize, defaultRatio, mediumRatio } } = this.props;
|
183 | this.setState(prevState => ({
|
184 | videoSize: prevState.videoSize === defaultSize ? mediumSize : defaultSize,
|
185 | ratio: prevState.ratio === defaultRatio ? mediumRatio : defaultRatio,
|
186 | }), () => this.props.tracking.trackEvent({ event: 'alter_video_size', action: 'click', data: { size: this.state.videoSize } }));
|
187 | }
|
188 | videoAction(event, stage) {
|
189 | this.props.onVideoAction(event, stage);
|
190 | switch (event) {
|
191 | case 'video-on-play':
|
192 | this.startIsPlaying();
|
193 | break;
|
194 | case 'video-on-pause':
|
195 | this.clearIsPlaying();
|
196 | break;
|
197 | case 'video-on-seeked':
|
198 | if (this.state.showCountdown) {
|
199 | clearInterval(this.counterInterval);
|
200 | this.setState({ showCountdown: false });
|
201 | }
|
202 | break;
|
203 | case 'video-on-ended':
|
204 | this.clearIsPlaying();
|
205 | this.endAnimation();
|
206 | if (!this.props.vidSrc && this.state.stage !== this.state.finalStage) {
|
207 | this.videoEnded(stage);
|
208 | }
|
209 | break;
|
210 | case 'next-step':
|
211 | this.setState({ showCountdown: false });
|
212 | this.setStage(stage + 1);
|
213 | break;
|
214 | default:
|
215 | break;
|
216 | }
|
217 | }
|
218 | setStage(newStage, action) {
|
219 | this.setState({ stage: newStage });
|
220 | if (action === 'forward')
|
221 | this.setUnlockedSteps(newStage);
|
222 | }
|
223 | setMinimised() {
|
224 | const { sizingConfig: { defaultSize, mediumSize } } = this.props;
|
225 | const { videoSize } = this.state;
|
226 | if (!this.state.minimised) {
|
227 | const video = document.getElementById('kbc-video');
|
228 | this.setState({ currentTranslation: video.style.transform, isSizeDefault: videoSize === defaultSize });
|
229 | video.style.transform = 'translate(0,0)';
|
230 | }
|
231 | else {
|
232 | this.setState({ isSizeDefault: videoSize === defaultSize });
|
233 | const video = document.getElementById('kbc-video');
|
234 | video.style.transform = this.state.currentTranslation;
|
235 | }
|
236 | this.setState(prevState => ({
|
237 | minimised: !prevState.minimised,
|
238 | videoSize: this.state.isSizeDefault ? defaultSize : mediumSize,
|
239 | }));
|
240 | }
|
241 | handleOnClose() {
|
242 | this.videoAction('close-video');
|
243 | }
|
244 | setUnlockedSteps(newStage) {
|
245 | this.setState(prevState => {
|
246 | const unlocked = prevState.unlockedSteps;
|
247 | if (!unlocked.includes(newStage))
|
248 | unlocked.push(newStage);
|
249 | return { unlockedSteps: unlocked };
|
250 | });
|
251 | }
|
252 | videoEnded(stage) {
|
253 | this.setState({ showCountdown: true, counter: 10 });
|
254 | this.setUnlockedSteps(stage + 1);
|
255 | this.counterInterval = setInterval(() => {
|
256 | if (this.state.counter === 1) {
|
257 | clearInterval(this.counterInterval);
|
258 | this.setState({ showCountdown: false });
|
259 | this.setStage(stage + 1);
|
260 | return;
|
261 | }
|
262 | this.setState(prevState => ({ counter: prevState.counter - 1 }));
|
263 | }, 1000);
|
264 | }
|
265 | endAnimation() {
|
266 | this.setState({ endedAnimate: true });
|
267 | setTimeout(() => {
|
268 | this.setState({ endedAnimate: false });
|
269 | }, 1500);
|
270 | }
|
271 | canGoBack(stage) {
|
272 | return stage > 0;
|
273 | }
|
274 | canGoForward(stage, finalStage) {
|
275 | return stage < finalStage;
|
276 | }
|
277 | canMove(i) {
|
278 | return this.state.unlockedSteps.length >= i + 1;
|
279 | }
|
280 | render() {
|
281 | const { title, bounds, sizingConfig: { bottom, top, left, defaultSize }, vidSrc, steps, type, icons, actions, draggable, provider } = this.props;
|
282 | const { videoSize, ratio, stage, finalStage, endedAnimate, minimised, showCountdown, counter, inactive } = this.state;
|
283 | const mediaType = steps && steps[stage].image ? 'image' : 'video';
|
284 | const step = steps ? steps[stage] : null;
|
285 | let source;
|
286 | if (mediaType === 'video' && steps) {
|
287 | source = steps[stage].video;
|
288 | }
|
289 | else {
|
290 | source = vidSrc;
|
291 | }
|
292 | const bored = inactive || minimised;
|
293 | return (React.createElement(react_draggable_1.default, { bounds: bounds, disabled: minimised || !draggable, cancel: '.plyr__controls' },
|
294 | React.createElement("div", { className: "video", id: "kbc-video", style: { bottom, top, left: left ? left : `calc(${defaultSize / 2.5}px)`, width: videoSize }, ref: this.videoRef },
|
295 | React.createElement("div", { className: `video-header${minimised ? ' header-disable' : ''}` },
|
296 | React.createElement("div", { className: "video-header-title" },
|
297 | React.createElement("div", { className: "video-header-icon" }, icons.headerStatic !== false ? icons.headerStatic : (React.createElement(React.Fragment, null,
|
298 | icons.headerHappy === 'default' ? !endedAnimate && !bored && React.createElement(icons_1.VideoHappyIcon, null) : icons.headerHappy,
|
299 | icons.headerExcited === 'default' ? endedAnimate && !bored && React.createElement(icons_1.VideoExcitedIcon, null) : icons.headerExcited,
|
300 | icons.headerBored === 'default' ? bored && React.createElement(icons_1.VideoBoredIcon, null) : icons.headerBored))),
|
301 | title ?
|
302 | React.createElement("h5", null, title) :
|
303 | type === 'video' ?
|
304 | React.createElement("h5", null, "Guide") :
|
305 | type === 'stepper' ?
|
306 | React.createElement("h5", null,
|
307 | "Step ",
|
308 | stage + 1) :
|
309 | ''),
|
310 | React.createElement("div", { className: "video-header-actions" },
|
311 | actions.expand ? (!minimised && (React.createElement("button", { className: "kbc-button--remove-browser-defaults", onClick: () => this.setVideoSize() }, videoSize === defaultSize ? React.createElement(kbc_icons_1.KbcIcon, { name: "GuideEnlarge", size: "base" }) : React.createElement(kbc_icons_1.KbcIcon, { name: "GuideShrink", size: "base" })))) : '',
|
312 | actions.minimise ? (React.createElement("button", { className: "kbc-button--remove-browser-defaults", onClick: () => this.setMinimised() }, minimised ? React.createElement(kbc_icons_1.KbcIcon, { name: "Maximise", size: "base" }) : React.createElement(kbc_icons_1.KbcIcon, { name: "Minus", size: "base" }))) : '',
|
313 | actions.close ? (React.createElement("button", { className: "kbc-button--remove-browser-defaults", onClick: () => this.handleOnClose() },
|
314 | React.createElement(kbc_icons_1.KbcIcon, { name: "Delete", size: "base" }))) : '')),
|
315 | React.createElement("div", { className: `video-main${minimised ? ' video-hide' : ''}` },
|
316 | mediaType === 'video' ? React.createElement(exports.VideoPlyr, { url: source, provider: provider, action: (e) => this.videoAction(e, stage), showCountdown: showCountdown, counter: counter, height: Math.round(videoSize * ratio) }) : '',
|
317 | mediaType === 'image' ? React.createElement("img", { src: step.image }) : ''),
|
318 | type === 'stepper' && (React.createElement("div", { className: `stepper-wrapper${minimised ? ' video-hide' : ''}` },
|
319 | React.createElement("div", { className: "stepper-footer" },
|
320 | React.createElement("div", { className: "stepper-footer-text" },
|
321 | React.createElement(with_html_1.default, { source: step.instruction, escapeHtml: false })),
|
322 | React.createElement("div", { className: "stepper-footer-nav" },
|
323 | React.createElement("div", { className: "stepper-buttons" },
|
324 | React.createElement("div", { className: `stepper-button stepper-button-back${this.canGoBack(stage) ? '' : ' stepper-button-disabled'}`, onClick: () => this.canGoBack(stage) ? this.setStage(stage - 1, 'back') : null },
|
325 | React.createElement(kbc_icons_1.KbcIcon, { name: "ArrowCircleLeft", size: "large" })),
|
326 | React.createElement("div", { className: `stepper-button${this.canGoForward(stage, finalStage) ? '' : ' stepper-button-disabled'}`, onClick: () => this.canGoForward(stage, finalStage) ? this.setStage(stage + 1, 'forward') : null },
|
327 | React.createElement(kbc_icons_1.KbcIcon, { name: "ArrowCircleRight", size: "large" }))),
|
328 | React.createElement("div", { className: "stepper-path" }, steps.map((_step, i) => (React.createElement("div", { className: `stepper-step${this.canMove(i) ? '' : ' stepper-step-disabled'}`, onClick: () => this.canMove(i) ? this.setStage(i) : null, key: 'step-' + i },
|
329 | React.createElement("svg", { viewBox: "0 0 100 100", xmlns: "http://www.w3.org/2000/svg", className: 'stepper-step-icon' + (i === stage ? ' stepper-step-selected' : '') },
|
330 | React.createElement("circle", { cx: "50", cy: "50", r: "50" })))))))))))));
|
331 | }
|
332 | };
|
333 | KbcVideo.defaultProps = {
|
334 | type: 'video',
|
335 | title: false,
|
336 | vidSrc: 'videos/example_club_video.mp4',
|
337 | bounds: 'parent',
|
338 | sizingConfig: {
|
339 | bottom: 30,
|
340 | defaultSize: 400,
|
341 | mediumSize: 600,
|
342 | defaultRatio: 0.5325,
|
343 | mediumRatio: 0.541,
|
344 | },
|
345 | icons: {
|
346 | headerStatic: false,
|
347 | headerHappy: 'default',
|
348 | headerExcited: 'default',
|
349 | headerBored: 'default',
|
350 | },
|
351 | actions: {
|
352 | minimise: true,
|
353 | expand: true,
|
354 | close: false,
|
355 | },
|
356 | draggable: true,
|
357 | provider: 'default',
|
358 | };
|
359 | __decorate([
|
360 | kbc_telemetry_1.track((_p, _s, args) => ({ event: 'video_action', data: { type: args[0] } }))
|
361 | ], KbcVideo.prototype, "videoAction", null);
|
362 | __decorate([
|
363 | kbc_telemetry_1.track((_p, _s, args) => ({ event: 'video_step_changed', action: 'click', data: { type: args[1], stepIndex: args[0] } }))
|
364 | ], KbcVideo.prototype, "setStage", null);
|
365 | __decorate([
|
366 | kbc_telemetry_1.track((_p, s) => ({ event: 'video_minimise', action: 'click', data: { type: s.minimised ? 'maximise' : 'minimise' } }))
|
367 | ], KbcVideo.prototype, "setMinimised", null);
|
368 | __decorate([
|
369 | kbc_telemetry_1.track((_p, s) => ({ event: 'video_closed', action: 'click' }))
|
370 | ], KbcVideo.prototype, "handleOnClose", null);
|
371 | KbcVideo = __decorate([
|
372 | kbc_telemetry_1.track({ module: 'kbc-video' })
|
373 | ], KbcVideo);
|
374 | exports.default = KbcVideo;
|
375 |
|
\ | No newline at end of file |