@elice/material-video-assessment 1.260609.0 → 1.260612.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.
@@ -56,6 +56,11 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
56
56
  }
57
57
  });
58
58
  var recorder = mediaKit.useMediaRecorder(['webcam', 'mic']);
59
+ var isSubmittingRef = React__default.default.useRef(false);
60
+ var _React$useState = React__default.default.useState(false),
61
+ _React$useState2 = _rollupPluginBabelHelpers.slicedToArray(_React$useState, 2),
62
+ isSubmitting = _React$useState2[0],
63
+ setIsSubmitting = _React$useState2[1];
59
64
  var timer = useVideoAssessmentTimer.useVideoAssessmentTimer({
60
65
  running: funnel.step === 'recording',
61
66
  mode: (_b = (_a = materialVideoAssessment === null || materialVideoAssessment === void 0 ? void 0 : materialVideoAssessment.timeLimit) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : 'recommended',
@@ -95,7 +100,9 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
95
100
  void funnel.history.push('recording', {});
96
101
  };
97
102
  /**
98
- *
103
+ * Submission can be triggered concurrently by the timer's `onLimitReached`
104
+ * and the manual submit button. The later call would `stop()` an already
105
+ * inactive recorder, which resolves an empty blob
99
106
  */
100
107
  var handleVideoSubmit = /*#__PURE__*/function () {
101
108
  var _ref2 = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee() {
@@ -109,37 +116,45 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
109
116
  }
110
117
  return _context.a(2);
111
118
  case 1:
112
- _context.p = 1;
119
+ if (!isSubmittingRef.current) {
120
+ _context.n = 2;
121
+ break;
122
+ }
123
+ return _context.a(2);
124
+ case 2:
125
+ isSubmittingRef.current = true;
126
+ setIsSubmitting(true);
127
+ _context.p = 3;
113
128
  timer.pause();
114
- _context.n = 2;
129
+ _context.n = 4;
115
130
  return recorder.stop();
116
- case 2:
131
+ case 4:
117
132
  blob = _context.v;
118
- if (blob) {
119
- _context.n = 3;
133
+ if (!(!blob || blob.size === 0)) {
134
+ _context.n = 5;
120
135
  break;
121
136
  }
122
137
  throw new Error(RECORDING_ERROR_REASON_MAP['no_recording']);
123
- case 3:
124
- _context.n = 4;
138
+ case 5:
139
+ _context.n = 6;
125
140
  return fileAdapter.upload(blob);
126
- case 4:
141
+ case 6:
127
142
  uploaded = _context.v;
128
143
  if (!(uploaded.status === 'incomplete')) {
129
- _context.n = 5;
144
+ _context.n = 7;
130
145
  break;
131
146
  }
132
147
  throw new Error(RECORDING_ERROR_REASON_MAP['file_upload_fail'], {
133
148
  cause: uploaded.reason
134
149
  });
135
- case 5:
136
- _context.n = 6;
150
+ case 7:
151
+ _context.n = 8;
137
152
  return apiClient.postOrgMaterialVideoAssessmentResponseAdd({
138
153
  materialVideoAssessmentId: materialVideoAssessmentId,
139
154
  resourceId: uploaded.resourceId,
140
155
  durationSeconds: Math.round(recorder.durationMs / 1000)
141
156
  });
142
- case 6:
157
+ case 8:
143
158
  void queryClient.invalidateQueries(useMaterialVideoAssessmentLastResponse.getOrgMaterialVideoAssessmentLastResponseQueryOptions({
144
159
  materialVideoAssessmentId: materialVideoAssessmentId,
145
160
  userId: userId
@@ -148,31 +163,36 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
148
163
  onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit({
149
164
  status: 'success'
150
165
  });
151
- _context.n = 9;
166
+ _context.n = 11;
152
167
  break;
153
- case 7:
154
- _context.p = 7;
168
+ case 9:
169
+ _context.p = 9;
155
170
  _t = _context.v;
156
171
  onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit({
157
172
  status: 'failure',
158
173
  error: _t
159
174
  });
160
175
  if (!(_t instanceof Error && _t.message === RECORDING_ERROR_REASON_MAP['no_recording'])) {
161
- _context.n = 8;
176
+ _context.n = 10;
162
177
  break;
163
178
  }
164
179
  void funnel.history.push('recording', {
165
180
  errorReason: RECORDING_ERROR_REASON_MAP['no_recording']
166
181
  });
167
182
  return _context.a(2);
168
- case 8:
183
+ case 10:
169
184
  void funnel.history.push('recording', {
170
185
  errorReason: RECORDING_ERROR_REASON_MAP['file_upload_fail']
171
186
  });
172
- case 9:
187
+ case 11:
188
+ _context.p = 11;
189
+ isSubmittingRef.current = false;
190
+ setIsSubmitting(false);
191
+ return _context.f(11);
192
+ case 12:
173
193
  return _context.a(2);
174
194
  }
175
- }, _callee, null, [[1, 7]]);
195
+ }, _callee, null, [[3, 9, 11, 12]]);
176
196
  }));
177
197
  return function handleVideoSubmit() {
178
198
  return _ref2.apply(this, arguments);
@@ -194,6 +214,7 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
194
214
  case 'recording':
195
215
  return jsxRuntime.jsx(StepRecording.default, {
196
216
  errorReason: funnel.context.errorReason,
217
+ isSubmitting: isSubmitting,
197
218
  recorder: recorder,
198
219
  timer: timer,
199
220
  onNext: handleVideoSubmit
@@ -6,6 +6,7 @@ interface StepRecordingProps {
6
6
  timer: UseVideoAssessmentTimerReturn;
7
7
  recorder: ReturnType<UseMediaRecorder>;
8
8
  errorReason?: RecordingErrorReason;
9
+ isSubmitting: boolean;
9
10
  onNext: () => void | Promise<void>;
10
11
  }
11
12
  declare const StepRecording: React.FC<StepRecordingProps>;
@@ -4,7 +4,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var _rollupPluginBabelHelpers = require('../../../../_virtual/_rollupPluginBabelHelpers.js');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
- var React = require('react');
8
7
  var intl = require('@elice/intl');
9
8
  var mediaKit = require('@elice/media-kit');
10
9
  var muiElements = require('@elice/mui-elements');
@@ -34,47 +33,19 @@ var StepRecording = function StepRecording(_ref) {
34
33
  var timer = _ref.timer,
35
34
  recorder = _ref.recorder,
36
35
  errorReason = _ref.errorReason,
36
+ isSubmitting = _ref.isSubmitting,
37
37
  onNext = _ref.onNext;
38
38
  var _a, _b, _c, _d;
39
39
  var intl$1 = intl.useRawEliceIntl();
40
40
  var volume = mediaKit.useMediaStreamAudioMeter('mic');
41
41
  var _useMaterialVideoAsse = MaterialVideoAssessmentContext.useMaterialVideoAssessmentState(),
42
42
  materialVideoAssessment = _useMaterialVideoAsse.materialVideoAssessment;
43
- var _useState = React.useState(false),
44
- _useState2 = _rollupPluginBabelHelpers.slicedToArray(_useState, 2),
45
- isSubmitting = _useState2[0],
46
- setSubmitting = _useState2[1];
47
43
  var showCountdown = timer.remainingSec !== null;
48
44
  var totalSec = (_b = (_a = materialVideoAssessment === null || materialVideoAssessment === void 0 ? void 0 : materialVideoAssessment.timeLimit) === null || _a === void 0 ? void 0 : _a.seconds) !== null && _b !== void 0 ? _b : 0;
49
45
  var elapsedSec = timer.elapsedSec;
50
46
  var remainingSec = (_c = timer.remainingSec) !== null && _c !== void 0 ? _c : 0;
51
47
  var progressValue = showCountdown && totalSec > 0 ? Math.min(100, elapsedSec / totalSec * 100) : 0;
52
48
  var accentColor = timer.isImminent ? 'warning.main' : 'text.primary';
53
- /**
54
- *
55
- */
56
- var handleVideoSubmit = /*#__PURE__*/function () {
57
- var _ref2 = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee() {
58
- return _rollupPluginBabelHelpers.regenerator().w(function (_context) {
59
- while (1) switch (_context.p = _context.n) {
60
- case 0:
61
- _context.p = 0;
62
- setSubmitting(true);
63
- _context.n = 1;
64
- return onNext();
65
- case 1:
66
- _context.p = 1;
67
- setSubmitting(false);
68
- return _context.f(1);
69
- case 2:
70
- return _context.a(2);
71
- }
72
- }, _callee, null, [[0,, 1, 2]]);
73
- }));
74
- return function handleVideoSubmit() {
75
- return _ref2.apply(this, arguments);
76
- };
77
- }();
78
49
  //
79
50
  //
80
51
  //
@@ -261,7 +232,9 @@ var StepRecording = function StepRecording(_ref) {
261
232
  children: jsxRuntime.jsx(lab.LoadingButton, {
262
233
  loading: isSubmitting,
263
234
  variant: "contained",
264
- onClick: handleVideoSubmit,
235
+ onClick: function onClick() {
236
+ void onNext();
237
+ },
265
238
  children: intl$1.formatMessage({
266
239
  id: 'video_assessment.recording.stop'
267
240
  })
@@ -1,4 +1,4 @@
1
- import { asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { slicedToArray as _slicedToArray, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import React from 'react';
4
4
  import { postOrgMaterialVideoAssessmentResponseAdd } from '@elice/api-client';
@@ -48,6 +48,11 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
48
48
  }
49
49
  });
50
50
  var recorder = useMediaRecorder(['webcam', 'mic']);
51
+ var isSubmittingRef = React.useRef(false);
52
+ var _React$useState = React.useState(false),
53
+ _React$useState2 = _slicedToArray(_React$useState, 2),
54
+ isSubmitting = _React$useState2[0],
55
+ setIsSubmitting = _React$useState2[1];
51
56
  var timer = useVideoAssessmentTimer({
52
57
  running: funnel.step === 'recording',
53
58
  mode: (_b = (_a = materialVideoAssessment === null || materialVideoAssessment === void 0 ? void 0 : materialVideoAssessment.timeLimit) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : 'recommended',
@@ -87,7 +92,9 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
87
92
  void funnel.history.push('recording', {});
88
93
  };
89
94
  /**
90
- *
95
+ * Submission can be triggered concurrently by the timer's `onLimitReached`
96
+ * and the manual submit button. The later call would `stop()` an already
97
+ * inactive recorder, which resolves an empty blob
91
98
  */
92
99
  var handleVideoSubmit = /*#__PURE__*/function () {
93
100
  var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
@@ -101,37 +108,45 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
101
108
  }
102
109
  return _context.a(2);
103
110
  case 1:
104
- _context.p = 1;
111
+ if (!isSubmittingRef.current) {
112
+ _context.n = 2;
113
+ break;
114
+ }
115
+ return _context.a(2);
116
+ case 2:
117
+ isSubmittingRef.current = true;
118
+ setIsSubmitting(true);
119
+ _context.p = 3;
105
120
  timer.pause();
106
- _context.n = 2;
121
+ _context.n = 4;
107
122
  return recorder.stop();
108
- case 2:
123
+ case 4:
109
124
  blob = _context.v;
110
- if (blob) {
111
- _context.n = 3;
125
+ if (!(!blob || blob.size === 0)) {
126
+ _context.n = 5;
112
127
  break;
113
128
  }
114
129
  throw new Error(RECORDING_ERROR_REASON_MAP['no_recording']);
115
- case 3:
116
- _context.n = 4;
130
+ case 5:
131
+ _context.n = 6;
117
132
  return fileAdapter.upload(blob);
118
- case 4:
133
+ case 6:
119
134
  uploaded = _context.v;
120
135
  if (!(uploaded.status === 'incomplete')) {
121
- _context.n = 5;
136
+ _context.n = 7;
122
137
  break;
123
138
  }
124
139
  throw new Error(RECORDING_ERROR_REASON_MAP['file_upload_fail'], {
125
140
  cause: uploaded.reason
126
141
  });
127
- case 5:
128
- _context.n = 6;
142
+ case 7:
143
+ _context.n = 8;
129
144
  return postOrgMaterialVideoAssessmentResponseAdd({
130
145
  materialVideoAssessmentId: materialVideoAssessmentId,
131
146
  resourceId: uploaded.resourceId,
132
147
  durationSeconds: Math.round(recorder.durationMs / 1000)
133
148
  });
134
- case 6:
149
+ case 8:
135
150
  void queryClient.invalidateQueries(getOrgMaterialVideoAssessmentLastResponseQueryOptions({
136
151
  materialVideoAssessmentId: materialVideoAssessmentId,
137
152
  userId: userId
@@ -140,31 +155,36 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
140
155
  onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit({
141
156
  status: 'success'
142
157
  });
143
- _context.n = 9;
158
+ _context.n = 11;
144
159
  break;
145
- case 7:
146
- _context.p = 7;
160
+ case 9:
161
+ _context.p = 9;
147
162
  _t = _context.v;
148
163
  onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit({
149
164
  status: 'failure',
150
165
  error: _t
151
166
  });
152
167
  if (!(_t instanceof Error && _t.message === RECORDING_ERROR_REASON_MAP['no_recording'])) {
153
- _context.n = 8;
168
+ _context.n = 10;
154
169
  break;
155
170
  }
156
171
  void funnel.history.push('recording', {
157
172
  errorReason: RECORDING_ERROR_REASON_MAP['no_recording']
158
173
  });
159
174
  return _context.a(2);
160
- case 8:
175
+ case 10:
161
176
  void funnel.history.push('recording', {
162
177
  errorReason: RECORDING_ERROR_REASON_MAP['file_upload_fail']
163
178
  });
164
- case 9:
179
+ case 11:
180
+ _context.p = 11;
181
+ isSubmittingRef.current = false;
182
+ setIsSubmitting(false);
183
+ return _context.f(11);
184
+ case 12:
165
185
  return _context.a(2);
166
186
  }
167
- }, _callee, null, [[1, 7]]);
187
+ }, _callee, null, [[3, 9, 11, 12]]);
168
188
  }));
169
189
  return function handleVideoSubmit() {
170
190
  return _ref2.apply(this, arguments);
@@ -186,6 +206,7 @@ var MaterialVideoAssessmentContent = function MaterialVideoAssessmentContent(_re
186
206
  case 'recording':
187
207
  return jsx(StepRecording, {
188
208
  errorReason: funnel.context.errorReason,
209
+ isSubmitting: isSubmitting,
189
210
  recorder: recorder,
190
211
  timer: timer,
191
212
  onNext: handleVideoSubmit
@@ -6,6 +6,7 @@ interface StepRecordingProps {
6
6
  timer: UseVideoAssessmentTimerReturn;
7
7
  recorder: ReturnType<UseMediaRecorder>;
8
8
  errorReason?: RecordingErrorReason;
9
+ isSubmitting: boolean;
9
10
  onNext: () => void | Promise<void>;
10
11
  }
11
12
  declare const StepRecording: React.FC<StepRecordingProps>;
@@ -1,6 +1,5 @@
1
- import { slicedToArray as _slicedToArray, defineProperty as _defineProperty, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { defineProperty as _defineProperty } from '../../../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useState } from 'react';
4
3
  import { useRawEliceIntl } from '@elice/intl';
5
4
  import { useMediaStreamAudioMeter, MediaStreamWebcam } from '@elice/media-kit';
6
5
  import { Tag, EliceIcon } from '@elice/mui-elements';
@@ -26,47 +25,19 @@ var StepRecording = function StepRecording(_ref) {
26
25
  var timer = _ref.timer,
27
26
  recorder = _ref.recorder,
28
27
  errorReason = _ref.errorReason,
28
+ isSubmitting = _ref.isSubmitting,
29
29
  onNext = _ref.onNext;
30
30
  var _a, _b, _c, _d;
31
31
  var intl = useRawEliceIntl();
32
32
  var volume = useMediaStreamAudioMeter('mic');
33
33
  var _useMaterialVideoAsse = useMaterialVideoAssessmentState(),
34
34
  materialVideoAssessment = _useMaterialVideoAsse.materialVideoAssessment;
35
- var _useState = useState(false),
36
- _useState2 = _slicedToArray(_useState, 2),
37
- isSubmitting = _useState2[0],
38
- setSubmitting = _useState2[1];
39
35
  var showCountdown = timer.remainingSec !== null;
40
36
  var totalSec = (_b = (_a = materialVideoAssessment === null || materialVideoAssessment === void 0 ? void 0 : materialVideoAssessment.timeLimit) === null || _a === void 0 ? void 0 : _a.seconds) !== null && _b !== void 0 ? _b : 0;
41
37
  var elapsedSec = timer.elapsedSec;
42
38
  var remainingSec = (_c = timer.remainingSec) !== null && _c !== void 0 ? _c : 0;
43
39
  var progressValue = showCountdown && totalSec > 0 ? Math.min(100, elapsedSec / totalSec * 100) : 0;
44
40
  var accentColor = timer.isImminent ? 'warning.main' : 'text.primary';
45
- /**
46
- *
47
- */
48
- var handleVideoSubmit = /*#__PURE__*/function () {
49
- var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
50
- return _regenerator().w(function (_context) {
51
- while (1) switch (_context.p = _context.n) {
52
- case 0:
53
- _context.p = 0;
54
- setSubmitting(true);
55
- _context.n = 1;
56
- return onNext();
57
- case 1:
58
- _context.p = 1;
59
- setSubmitting(false);
60
- return _context.f(1);
61
- case 2:
62
- return _context.a(2);
63
- }
64
- }, _callee, null, [[0,, 1, 2]]);
65
- }));
66
- return function handleVideoSubmit() {
67
- return _ref2.apply(this, arguments);
68
- };
69
- }();
70
41
  //
71
42
  //
72
43
  //
@@ -253,7 +224,9 @@ var StepRecording = function StepRecording(_ref) {
253
224
  children: jsx(LoadingButton, {
254
225
  loading: isSubmitting,
255
226
  variant: "contained",
256
- onClick: handleVideoSubmit,
227
+ onClick: function onClick() {
228
+ void onNext();
229
+ },
257
230
  children: intl.formatMessage({
258
231
  id: 'video_assessment.recording.stop'
259
232
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elice/material-video-assessment",
3
- "version": "1.260609.0",
3
+ "version": "1.260612.0",
4
4
  "description": "User view and editing components of Elice material video assessment",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,8 +36,8 @@
36
36
  "dayjs": "^1.11.0",
37
37
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
38
38
  "react-use": "^17.0.0",
39
- "@elice/material-shared-types": "1.260609.0",
40
- "@elice/material-shared-utils": "1.260609.0"
39
+ "@elice/material-shared-utils": "1.260612.0",
40
+ "@elice/material-shared-types": "1.260612.0"
41
41
  },
42
42
  "dependencies": {
43
43
  "@hookform/resolvers": "^3",
@@ -84,8 +84,8 @@
84
84
  "rollup": "^4.0.0",
85
85
  "typescript": "~5.9.3",
86
86
  "vite": "^4.4.9",
87
- "@elice/material-shared-types": "1.260609.0",
88
- "@elice/material-shared-utils": "1.260609.0"
87
+ "@elice/material-shared-types": "1.260612.0",
88
+ "@elice/material-shared-utils": "1.260612.0"
89
89
  },
90
90
  "scripts": {
91
91
  "start": "run-s watch",