@newtonschool/react_proctoring_library 0.0.1 → 0.0.2
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/README.md +70 -66
- package/dist/assets/images/newton-school-logo.png +0 -0
- package/dist/assets/images/url-video-permission-highlight.png +0 -0
- package/dist/assets/images/vid-micro-permissions-given.png +0 -0
- package/dist/assets/images/vid-micro-permissions.png +0 -0
- package/dist/assets/videos/ask-permission.mp4 +0 -0
- package/dist/assets/videos/give-permissions.mp4 +0 -0
- package/dist/components/FullScreenPermission.js +84 -0
- package/dist/components/FullScreenTestInWebcam.js +22 -10
- package/dist/components/ProctorApp.js +92 -0
- package/dist/components/ResponseModal.js +24 -16
- package/dist/components/activity-tracker/index.js +144 -0
- package/dist/components/activity-tracker/index.scss +4 -0
- package/dist/components/full-screen-permission.scss +8 -0
- package/dist/components/index.js +31 -0
- package/dist/components/permissions/audio-video-permission.js +35 -0
- package/dist/components/permissions/audio-video-permission.scss +228 -0
- package/dist/components/permissions/blocked-permission.js +76 -0
- package/dist/components/permissions/full-screen-permission.js +43 -0
- package/dist/components/permissions/full-screen-permission.scss +8 -0
- package/dist/components/permissions/index.js +70 -0
- package/dist/components/permissions/index.scss +6 -0
- package/dist/components/permissions/initial-screen.js +52 -0
- package/dist/components/permissions/permission-body.js +53 -0
- package/dist/constants/defaults.js +38 -0
- package/dist/constants/text.js +56 -0
- package/dist/demo-code/README.md +70 -0
- package/dist/demo-code/package.json +38 -0
- package/dist/demo-code/public/favicon.ico +0 -0
- package/dist/demo-code/public/index.html +43 -0
- package/dist/demo-code/public/logo192.png +0 -0
- package/dist/demo-code/public/logo512.png +0 -0
- package/dist/demo-code/public/manifest.json +25 -0
- package/dist/demo-code/public/robots.txt +3 -0
- package/dist/demo-code/src/App.css +38 -0
- package/dist/demo-code/src/App.js +29 -0
- package/dist/demo-code/src/index.js +11 -0
- package/dist/hooks/index.js +39 -0
- package/dist/hooks/useAudioVideoPermission.js +96 -0
- package/dist/hooks/useAudioVideoPermissions.js +1 -0
- package/dist/hooks/useFullScreenData.js +55 -0
- package/dist/hooks/useFullScreenStatus.js +45 -0
- package/dist/hooks/usePageVisibility.js +31 -0
- package/dist/hooks/useTabSwitchCount.js +25 -0
- package/dist/hooks/useWebcamData.js +91 -0
- package/dist/index.js +5 -3
- package/dist/lib/index.js +19 -0
- package/dist/utils/ValidityChecks.js +1 -19
- package/dist/utils/arrayUtils.js +16 -0
- package/dist/utils/breachUtils.js +69 -0
- package/dist/utils/browserUtils.js +63 -0
- package/dist/utils/{GetBrowserDocumentProp.js → getBrowserDocumentProp.js} +0 -0
- package/dist/utils/getGlancePercentage.js +1 -43
- package/dist/utils/{GetIsDocumentHidden.js → getIsDocumentHidden.js} +2 -2
- package/dist/utils/index.js +49 -29
- package/dist/utils/localStorageUtils.js +33 -0
- package/dist/utils/webcamMicrophoneUtils.js +115 -0
- package/dist/utils/webcamUtils.js +79 -0
- package/package.json +55 -55
- package/dist/ProctorApp.js +0 -186
- package/dist/utils/TabVisibility.js +0 -32
- package/dist/utils/commonUtilConfigs.js +0 -21
- package/dist/utils/initialSetup.js +0 -15
- package/dist/utils/localStorageUtil.js +0 -27
- package/dist/utils/useFullScreenStatus.js +0 -45
package/README.md
CHANGED
|
@@ -1,66 +1,70 @@
|
|
|
1
|
-
# Welcome to react_proctoring_library · [](https://github.com/Newton-School/proctoring_react/blob/main/LICENSE) [](https://www.npmjs.com/package/react_proctoring_library) [](https://www.npmjs.com/package/react_proctoring_library) [](https://circleci.com/gh/facebook/react) [](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
|
|
2
|
-
|
|
3
|
-
Hi! **react_proctoring_library** is a user friendly, easy to use and your _one-stop_ [npm library](https://www.npmjs.com/package/react_proctoring_library) which will provide you the ability to proctor all your exams, tests, quizzes,
|
|
4
|
-
|
|
5
|
-
## Why?
|
|
6
|
-
|
|
7
|
-
- In these times when most of the exams are conducted online, a lot of us want some sort of mechanism which could make their life easy while taking online test and **react_proctoring_library** has done this for you.
|
|
8
|
-
|
|
9
|
-
Future Plans?
|
|
10
|
-
|
|
11
|
-
- Detection of multiple persons via Audio.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
1
|
+
# Welcome to react_proctoring_library · [](https://github.com/Newton-School/proctoring_react/blob/main/LICENSE) [](https://www.npmjs.com/package/react_proctoring_library) [](https://www.npmjs.com/package/react_proctoring_library) [](https://circleci.com/gh/facebook/react) [](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
|
|
2
|
+
|
|
3
|
+
Hi! **react_proctoring_library** is a user friendly, easy to use and your _one-stop_ [npm library](https://www.npmjs.com/package/react_proctoring_library) which will provide you the ability to proctor all your exams, tests, quizzes, playgrounds, almost everything you need to proctor with the minimum effort possible. We have used [body-pix](https://www.npmjs.com/package/@tensorflow-models/body-pix) model from [tensorflow](https://www.tensorflow.org/) library to detect if user is looking outside the screen, multiple people visible in camera. We have also implemented tab switching tracker and full screen exit tracker.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
- In these times when most of the exams are conducted online, a lot of us want some sort of mechanism which could make their life easy while taking online test and **react_proctoring_library** has done this for you.
|
|
8
|
+
|
|
9
|
+
Future Plans?
|
|
10
|
+
|
|
11
|
+
- Detection of multiple persons via Audio.
|
|
12
|
+
- Provision of videos of the proctored sessios.
|
|
13
|
+
- Screenshots when proctoring params are breached.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
You must have [React](https://reactjs.org/) v16.8 or above installed in your project to use this proctoring library.
|
|
18
|
+
|
|
19
|
+
If you want, you can also [create a new react app](https://reactjs.org/docs/create-a-new-react-app.html) using `npx create-react-app my-new-app` command.
|
|
20
|
+
|
|
21
|
+
Once you have a react app, just type
|
|
22
|
+
`npm install react_proctoring_library` in your terminal and if everything goes fine, you are good to go.
|
|
23
|
+
|
|
24
|
+
## Props
|
|
25
|
+
|
|
26
|
+
| Props | isRequired | ParamsType | Description |
|
|
27
|
+
| ---------------------- | ---------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
28
|
+
| `children` | Yes | JSX Component | The Component which you want to proctor |
|
|
29
|
+
| `proctoringIdentifier` | Yes | String | A unique string to identify every test |
|
|
30
|
+
| `proctoringParams` | Optional | Object {userCount tabSwitch, fullscreenExit, lookedAway} | Parameters on which the screen is proctored. By default, all parameters are true |
|
|
31
|
+
| `shouldSendDataOnBreach` | Optional | Boolean | True if data needs to be sent on breach, else False. Default is False |
|
|
32
|
+
| `sendData` | Optional | Function | if shouldSendDataOnBreach is True, this callback is called with the details of the breach on every breach |
|
|
33
|
+
|
|
34
|
+
## Documentation
|
|
35
|
+
|
|
36
|
+
Currently, **react_proctoring_library** comes with 2 things:
|
|
37
|
+
|
|
38
|
+
- `ProctorApp` - A Component which will help you in proctoring
|
|
39
|
+
- `Object getStatistics(string: proctoringIdentifier)` - A function which will return a data Object with all Statistics
|
|
40
|
+
about breaches.
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
import { ProctorApp, getStatistics } from 'react_proctoring_library';
|
|
44
|
+
function Test(props) {
|
|
45
|
+
return (
|
|
46
|
+
<div>
|
|
47
|
+
<h1>Proctoring Window</h1>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function App() {
|
|
53
|
+
const proctoringIdentifier = 'unique-proctoring-identifier';
|
|
54
|
+
|
|
55
|
+
const getStats = e => {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
console.log(getStatistics(proctoringIdentifier));
|
|
58
|
+
};
|
|
59
|
+
return (
|
|
60
|
+
<div className="App">
|
|
61
|
+
<ProctorApp proctoringIdentifier={proctoringIdentifier}>
|
|
62
|
+
<Test />
|
|
63
|
+
</ProctorApp>
|
|
64
|
+
</div>
|
|
65
|
+
<button onClick={getStats}>Get Statistics</button>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default App;
|
|
70
|
+
```
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = FullScreenPermission;
|
|
7
|
+
|
|
8
|
+
require("core-js/modules/web.dom-collections.iterator.js");
|
|
9
|
+
|
|
10
|
+
require("./full-screen-permission.scss");
|
|
11
|
+
|
|
12
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
13
|
+
|
|
14
|
+
var _reactBootstrap = require("react-bootstrap");
|
|
15
|
+
|
|
16
|
+
var text = _interopRequireWildcard(require("../constants/text"));
|
|
17
|
+
|
|
18
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
19
|
+
|
|
20
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
21
|
+
|
|
22
|
+
function FullScreenPermission(_ref) {
|
|
23
|
+
let {
|
|
24
|
+
firstTimeFullScreen,
|
|
25
|
+
setFirstTimeFullScreen,
|
|
26
|
+
isFullscreen,
|
|
27
|
+
setFullscreen,
|
|
28
|
+
setFullScreenExitCount,
|
|
29
|
+
fullScreenPermissionTexts
|
|
30
|
+
} = _ref;
|
|
31
|
+
const [show, setShow] = (0, _react.useState)(true);
|
|
32
|
+
|
|
33
|
+
const closePermissionModal = () => {
|
|
34
|
+
if (firstTimeFullScreen) {
|
|
35
|
+
setFirstTimeFullScreen(false);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setShow(false);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const handleNo = () => {
|
|
42
|
+
if (firstTimeFullScreen) {
|
|
43
|
+
setFullScreenExitCount(fullScreenExitCount => fullScreenExitCount + 1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
closePermissionModal();
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const switchToFullscreenMode = () => {
|
|
50
|
+
closePermissionModal();
|
|
51
|
+
setFullscreen();
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
(0, _react.useEffect)(() => {
|
|
55
|
+
if (!isFullscreen) {
|
|
56
|
+
setShow(true);
|
|
57
|
+
}
|
|
58
|
+
}, [isFullscreen]);
|
|
59
|
+
const {
|
|
60
|
+
title = "",
|
|
61
|
+
message = "",
|
|
62
|
+
deny = "",
|
|
63
|
+
allow = "",
|
|
64
|
+
errorMessage = ""
|
|
65
|
+
} = fullScreenPermissionTexts;
|
|
66
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("h1", {
|
|
67
|
+
className: "error-message"
|
|
68
|
+
}, errorMessage ? errorMessage : text.FULLSCREEN_ERROR_MESSAGE), /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal, {
|
|
69
|
+
show: show,
|
|
70
|
+
onHide: closePermissionModal,
|
|
71
|
+
size: "lg",
|
|
72
|
+
backdrop: "static",
|
|
73
|
+
"aria-labelledby": "contained-modal-title-vcenter",
|
|
74
|
+
centered: true
|
|
75
|
+
}, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Header, null, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Title, null, title ? title : text.FULLSCREEN_PERMISSION_TITLE)), /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Body, {
|
|
76
|
+
className: "dialog-message"
|
|
77
|
+
}, message ? message : text.MESSAGE), /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Footer, null, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Button, {
|
|
78
|
+
variant: "secondary",
|
|
79
|
+
onClick: handleNo
|
|
80
|
+
}, deny ? deny : text.DENY), /*#__PURE__*/_react.default.createElement(_reactBootstrap.Button, {
|
|
81
|
+
variant: "primary",
|
|
82
|
+
onClick: switchToFullscreenMode
|
|
83
|
+
}, allow ? allow : text.ALLOW))));
|
|
84
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
require("core-js/modules/web.dom-collections.iterator.js");
|
|
4
|
+
|
|
3
5
|
Object.defineProperty(exports, "__esModule", {
|
|
4
6
|
value: true
|
|
5
7
|
});
|
|
@@ -11,11 +13,21 @@ var _reactWebcam = _interopRequireDefault(require("react-webcam"));
|
|
|
11
13
|
|
|
12
14
|
var _reactBootstrap = require("react-bootstrap");
|
|
13
15
|
|
|
16
|
+
var text = _interopRequireWildcard(require("../constants/text"));
|
|
17
|
+
|
|
18
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
19
|
+
|
|
20
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
21
|
+
|
|
14
22
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
23
|
|
|
16
|
-
const FullScreenTestInWebcam =
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
const FullScreenTestInWebcam = _ref => {
|
|
25
|
+
let {
|
|
26
|
+
webcamReference,
|
|
27
|
+
canvasReference,
|
|
28
|
+
userCount,
|
|
29
|
+
isWatching
|
|
30
|
+
} = _ref;
|
|
19
31
|
return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Col, {
|
|
20
32
|
md: 6
|
|
21
33
|
}, /*#__PURE__*/_react.default.createElement(_reactWebcam.default, {
|
|
@@ -29,20 +41,20 @@ const FullScreenTestInWebcam = props => {
|
|
|
29
41
|
}, /*#__PURE__*/_react.default.createElement("canvas", {
|
|
30
42
|
id: "glanceTrackerCanvas",
|
|
31
43
|
style: {
|
|
32
|
-
display:
|
|
44
|
+
display: "none"
|
|
33
45
|
}
|
|
34
46
|
})), /*#__PURE__*/_react.default.createElement("div", {
|
|
35
47
|
style: {
|
|
36
|
-
position:
|
|
37
|
-
marginLeft:
|
|
38
|
-
marginRight:
|
|
48
|
+
position: "absolute",
|
|
49
|
+
marginLeft: "auto",
|
|
50
|
+
marginRight: "auto",
|
|
39
51
|
left: 0,
|
|
40
52
|
right: 0,
|
|
41
|
-
top:
|
|
42
|
-
textAlign:
|
|
53
|
+
top: "35rem",
|
|
54
|
+
textAlign: "center",
|
|
43
55
|
zindex: 9
|
|
44
56
|
}
|
|
45
|
-
}, "
|
|
57
|
+
}, text.USER_COUNT_LABEL, ": ", userCount, /*#__PURE__*/_react.default.createElement("br", null), isWatching ? text.WATCHING_SCREEN : text.NOT_WATCHING_SCREEN));
|
|
46
58
|
};
|
|
47
59
|
|
|
48
60
|
var _default = FullScreenTestInWebcam;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.ProctorApp = void 0;
|
|
7
|
+
|
|
8
|
+
require("core-js/modules/web.dom-collections.iterator.js");
|
|
9
|
+
|
|
10
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
+
|
|
12
|
+
var _ = require(".");
|
|
13
|
+
|
|
14
|
+
var _utils = require("../utils");
|
|
15
|
+
|
|
16
|
+
var _hooks = require("../hooks");
|
|
17
|
+
|
|
18
|
+
var _defaults = require("../constants/defaults");
|
|
19
|
+
|
|
20
|
+
var _permissions = require("./permissions");
|
|
21
|
+
|
|
22
|
+
var _useWebcamData = _interopRequireDefault(require("../hooks/useWebcamData"));
|
|
23
|
+
|
|
24
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
|
+
|
|
26
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
27
|
+
|
|
28
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
29
|
+
|
|
30
|
+
const ProctorApp = _ref => {
|
|
31
|
+
let {
|
|
32
|
+
proctoringIdentifier,
|
|
33
|
+
children,
|
|
34
|
+
proctoringParams = {
|
|
35
|
+
userCount: true,
|
|
36
|
+
tabSwitch: true,
|
|
37
|
+
fullscreenExit: true,
|
|
38
|
+
lookedAway: true
|
|
39
|
+
},
|
|
40
|
+
sendData = () => {},
|
|
41
|
+
shouldSendDataOnBreach = false
|
|
42
|
+
} = _ref;
|
|
43
|
+
const webcamReference = (0, _react.useRef)(null);
|
|
44
|
+
const canvasReference = (0, _react.useRef)(null);
|
|
45
|
+
const statistics = (0, _react.useRef)(_defaults.INITIAL_STATISTICS);
|
|
46
|
+
const [audioPermission, setAudioPermission] = (0, _react.useState)(false);
|
|
47
|
+
const [videoPermission, setVideoPermission] = (0, _react.useState)(false);
|
|
48
|
+
const {
|
|
49
|
+
isFullscreen,
|
|
50
|
+
setFullscreen,
|
|
51
|
+
fullScreenExitCount
|
|
52
|
+
} = (0, _hooks.useFullscreenData)();
|
|
53
|
+
const [userCount, lookedAwayCount] = (0, _useWebcamData.default)(webcamReference, canvasReference);
|
|
54
|
+
const tabSwitchCount = (0, _hooks.useTabSwitchCount)();
|
|
55
|
+
(0, _react.useEffect)(() => {
|
|
56
|
+
(0, _utils.removeStatsFromLocalStorage)(proctoringIdentifier);
|
|
57
|
+
}, [proctoringIdentifier]);
|
|
58
|
+
(0, _react.useEffect)(() => {
|
|
59
|
+
if (shouldSendDataOnBreach) {
|
|
60
|
+
(0, _utils.sendDataOnBreach)(statistics, {
|
|
61
|
+
userCount,
|
|
62
|
+
tabSwitchCount,
|
|
63
|
+
fullScreenExitCount,
|
|
64
|
+
lookedAwayCount
|
|
65
|
+
}, proctoringIdentifier, sendData);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
(0, _utils.updateStatistics)(statistics, tabSwitchCount, fullScreenExitCount, lookedAwayCount, userCount);
|
|
69
|
+
(0, _utils.addOrUpdateStatsToLocalStorage)(proctoringIdentifier, statistics.current);
|
|
70
|
+
}, [userCount, tabSwitchCount, fullScreenExitCount, lookedAwayCount, proctoringIdentifier, sendData, shouldSendDataOnBreach]);
|
|
71
|
+
|
|
72
|
+
if (proctoringIdentifier === undefined) {
|
|
73
|
+
// todo
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_permissions.Permission, {
|
|
78
|
+
isFullscreen: isFullscreen,
|
|
79
|
+
audioPermisison: audioPermission,
|
|
80
|
+
videoPermission: videoPermission,
|
|
81
|
+
setFullscreen: setFullscreen
|
|
82
|
+
}), /*#__PURE__*/_react.default.createElement(_.ActivityTracker, {
|
|
83
|
+
setAudioPermission: setAudioPermission,
|
|
84
|
+
setVideoPermission: setVideoPermission,
|
|
85
|
+
webcamReference: webcamReference,
|
|
86
|
+
canvasReference: canvasReference
|
|
87
|
+
}), isFullscreen && audioPermission && videoPermission && children);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
exports.ProctorApp = ProctorApp;
|
|
91
|
+
var _default = ProctorApp;
|
|
92
|
+
exports.default = _default;
|
|
@@ -11,26 +11,34 @@ var _react = _interopRequireWildcard(require("react"));
|
|
|
11
11
|
|
|
12
12
|
var _reactBootstrap = require("react-bootstrap");
|
|
13
13
|
|
|
14
|
+
var text = _interopRequireWildcard(require("../constants/text"));
|
|
15
|
+
|
|
14
16
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
15
17
|
|
|
16
18
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
17
19
|
|
|
18
|
-
function ResponseModal(
|
|
20
|
+
function ResponseModal(_ref) {
|
|
21
|
+
let {
|
|
22
|
+
firstTimeFullScreen,
|
|
23
|
+
setFirstTimeFullScreen,
|
|
24
|
+
isFullscreen,
|
|
25
|
+
setFullscreen,
|
|
26
|
+
setFullScreenExitCount,
|
|
27
|
+
fullScreenMessage
|
|
28
|
+
} = _ref;
|
|
19
29
|
const [show, setShow] = (0, _react.useState)(true);
|
|
20
30
|
|
|
21
|
-
const displayResponseModal = () => setShow(true);
|
|
22
|
-
|
|
23
31
|
const closeResponseModal = () => {
|
|
24
|
-
if (
|
|
25
|
-
|
|
32
|
+
if (firstTimeFullScreen) {
|
|
33
|
+
setFirstTimeFullScreen(false);
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
setShow(false);
|
|
29
37
|
};
|
|
30
38
|
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
33
|
-
|
|
39
|
+
const handleNo = () => {
|
|
40
|
+
if (firstTimeFullScreen) {
|
|
41
|
+
setFullScreenExitCount(fullScreenExitCount => fullScreenExitCount + 1);
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
closeResponseModal();
|
|
@@ -38,14 +46,14 @@ function ResponseModal(props) {
|
|
|
38
46
|
|
|
39
47
|
const openFullscreen = () => {
|
|
40
48
|
closeResponseModal();
|
|
41
|
-
|
|
49
|
+
setFullscreen();
|
|
42
50
|
};
|
|
43
51
|
|
|
44
52
|
(0, _react.useEffect)(() => {
|
|
45
|
-
if (!
|
|
46
|
-
|
|
53
|
+
if (!isFullscreen) {
|
|
54
|
+
setShow(true);
|
|
47
55
|
}
|
|
48
|
-
}, [
|
|
56
|
+
}, [isFullscreen]);
|
|
49
57
|
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal, {
|
|
50
58
|
show: show,
|
|
51
59
|
onHide: closeResponseModal,
|
|
@@ -53,11 +61,11 @@ function ResponseModal(props) {
|
|
|
53
61
|
backdrop: "static",
|
|
54
62
|
"aria-labelledby": "contained-modal-title-vcenter",
|
|
55
63
|
centered: true
|
|
56
|
-
}, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Header, null, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Title, null,
|
|
64
|
+
}, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Header, null, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Title, null, text.FULLSCREEN_PERMISSION_TITLE)), /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Body, null, fullScreenMessage), /*#__PURE__*/_react.default.createElement(_reactBootstrap.Modal.Footer, null, /*#__PURE__*/_react.default.createElement(_reactBootstrap.Button, {
|
|
57
65
|
variant: "secondary",
|
|
58
|
-
onClick:
|
|
59
|
-
},
|
|
66
|
+
onClick: handleNo
|
|
67
|
+
}, text.NO), /*#__PURE__*/_react.default.createElement(_reactBootstrap.Button, {
|
|
60
68
|
variant: "primary",
|
|
61
69
|
onClick: openFullscreen
|
|
62
|
-
},
|
|
70
|
+
}, text.YES))));
|
|
63
71
|
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
require("core-js/modules/web.dom-collections.iterator.js");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = void 0;
|
|
9
|
+
|
|
10
|
+
require("core-js/modules/es.regexp.exec.js");
|
|
11
|
+
|
|
12
|
+
require("core-js/modules/es.string.match.js");
|
|
13
|
+
|
|
14
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
15
|
+
|
|
16
|
+
var _reactWebcam = _interopRequireDefault(require("react-webcam"));
|
|
17
|
+
|
|
18
|
+
var _utils = require("../../utils");
|
|
19
|
+
|
|
20
|
+
var _webcamMicrophoneUtils = require("../../utils/webcamMicrophoneUtils");
|
|
21
|
+
|
|
22
|
+
require("./index.scss");
|
|
23
|
+
|
|
24
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
|
+
|
|
26
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
27
|
+
|
|
28
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
29
|
+
|
|
30
|
+
const isChrome = !!navigator.userAgent.match(/chrome|chromium/i);
|
|
31
|
+
|
|
32
|
+
const ActivityTracker = _ref => {
|
|
33
|
+
let {
|
|
34
|
+
webcamReference,
|
|
35
|
+
canvasReference,
|
|
36
|
+
setAudioPermission,
|
|
37
|
+
setVideoPermission
|
|
38
|
+
} = _ref;
|
|
39
|
+
(0, _react.useEffect)(() => {
|
|
40
|
+
if (isChrome) {
|
|
41
|
+
(0, _webcamMicrophoneUtils.updateVideoPermissions)(setVideoPermission);
|
|
42
|
+
(0, _webcamMicrophoneUtils.updateAudioPermissions)(setAudioPermission);
|
|
43
|
+
(0, _webcamMicrophoneUtils.getVideoPermissionQuery)().then(status => {
|
|
44
|
+
status.onchange = evt => {
|
|
45
|
+
(0, _webcamMicrophoneUtils.updateVideoPermissions)(setVideoPermission);
|
|
46
|
+
};
|
|
47
|
+
}).catch(err => {
|
|
48
|
+
console.log("Video Permission", err);
|
|
49
|
+
});
|
|
50
|
+
(0, _webcamMicrophoneUtils.getAudioPermissionQuery)().then(status => {
|
|
51
|
+
status.onchange = evt => {
|
|
52
|
+
(0, _webcamMicrophoneUtils.updateAudioPermissions)(setAudioPermission);
|
|
53
|
+
};
|
|
54
|
+
}).catch(err => {
|
|
55
|
+
(0, _webcamMicrophoneUtils.updateAudioPermissions)("Audio Permission", err);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}, [setVideoPermission, setAudioPermission]);
|
|
59
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactWebcam.default, {
|
|
60
|
+
audio: true,
|
|
61
|
+
muted: true,
|
|
62
|
+
ref: webcamReference,
|
|
63
|
+
onUserMedia: stream => {
|
|
64
|
+
if (!isChrome) {
|
|
65
|
+
const {
|
|
66
|
+
audio,
|
|
67
|
+
video
|
|
68
|
+
} = (0, _utils.getAudioVideoPermission)(stream);
|
|
69
|
+
setAudioPermission(audio);
|
|
70
|
+
setVideoPermission(video);
|
|
71
|
+
|
|
72
|
+
stream.onaddtrack = p => {
|
|
73
|
+
const {
|
|
74
|
+
audio,
|
|
75
|
+
video
|
|
76
|
+
} = (0, _utils.getAudioVideoPermission)(stream);
|
|
77
|
+
setAudioPermission(audio);
|
|
78
|
+
setVideoPermission(video);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
stream.onremovetrack = p => {
|
|
82
|
+
const {
|
|
83
|
+
audio,
|
|
84
|
+
video
|
|
85
|
+
} = (0, _utils.getAudioVideoPermission)(stream);
|
|
86
|
+
setAudioPermission(audio);
|
|
87
|
+
setVideoPermission(video);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
stream.onactive = p => {
|
|
91
|
+
const {
|
|
92
|
+
audio,
|
|
93
|
+
video
|
|
94
|
+
} = (0, _utils.getAudioVideoPermission)(stream);
|
|
95
|
+
setAudioPermission(audio);
|
|
96
|
+
setVideoPermission(video);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
stream.oninactive = e => {
|
|
100
|
+
setAudioPermission(false);
|
|
101
|
+
setVideoPermission(false);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const audioTracks = stream.getAudioTracks().filter(track => track.enabled && track.label);
|
|
105
|
+
audioTracks.forEach(track => {
|
|
106
|
+
track.onended = e => {
|
|
107
|
+
const audio = (0, _utils.getAudioPermission)(stream);
|
|
108
|
+
setAudioPermission(audio, e.currentTarget.id);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
track.onmute = e => {
|
|
112
|
+
const audio = (0, _utils.getAudioPermission)(stream);
|
|
113
|
+
setAudioPermission(audio, e.currentTarget.id);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
track.onunmute = e => {
|
|
117
|
+
const audio = (0, _utils.getAudioPermission)(stream);
|
|
118
|
+
setAudioPermission(audio);
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
const videoTracks = stream.getVideoTracks().filter(track => track.enabled && track.label);
|
|
122
|
+
videoTracks.forEach(track => {
|
|
123
|
+
track.onended = e => {
|
|
124
|
+
const video = (0, _utils.getVideoPermission)(stream, e.currentTarget.id);
|
|
125
|
+
setVideoPermission(video);
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
onUserMediaError: error => {
|
|
131
|
+
if (!isChrome) {
|
|
132
|
+
setVideoPermission(false);
|
|
133
|
+
setAudioPermission(false);
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
className: "captured-video-canvas"
|
|
137
|
+
}), /*#__PURE__*/_react.default.createElement("canvas", {
|
|
138
|
+
ref: canvasReference,
|
|
139
|
+
className: "captured-video-canvas"
|
|
140
|
+
}));
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
var _default = ActivityTracker;
|
|
144
|
+
exports.default = _default;
|