@clickview/lite 0.57.3-rc.0 → 0.58.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 (23) hide show
  1. package/dist/bundles.json +1 -1
  2. package/dist/scripts/{2564-98ba0d782a-lite.chunk.js → 2564-04ffede8c7-lite.chunk.js} +3 -3
  3. package/dist/scripts/{2564-98ba0d782a-lite.chunk.js.map → 2564-04ffede8c7-lite.chunk.js.map} +1 -1
  4. package/dist/scripts/2615-27b126b1ab-lite.chunk.js +3 -0
  5. package/dist/scripts/2615-27b126b1ab-lite.chunk.js.map +1 -0
  6. package/dist/scripts/{2978-b7bcc3eac4-lite.chunk.js → 2978-e4a60f90a5-lite.chunk.js} +2 -2
  7. package/dist/scripts/2978-e4a60f90a5-lite.chunk.js.map +1 -0
  8. package/dist/scripts/{8095-afb976fac0-lite.chunk.js → 8095-7236697220-lite.chunk.js} +2 -2
  9. package/dist/scripts/8095-7236697220-lite.chunk.js.map +1 -0
  10. package/dist/scripts/8849-7d50f76777-lite.chunk.js +2 -0
  11. package/dist/scripts/8849-7d50f76777-lite.chunk.js.map +1 -0
  12. package/dist/scripts/{bundle-b25c09d3e8.min.js → bundle-176a4f3a0a.min.js} +3 -3
  13. package/dist/scripts/{bundle-b25c09d3e8.min.js.map → bundle-176a4f3a0a.min.js.map} +1 -1
  14. package/package.json +1 -1
  15. package/dist/scripts/2615-e9b2938c18-lite.chunk.js +0 -3
  16. package/dist/scripts/2615-e9b2938c18-lite.chunk.js.map +0 -1
  17. package/dist/scripts/2978-b7bcc3eac4-lite.chunk.js.map +0 -1
  18. package/dist/scripts/8095-afb976fac0-lite.chunk.js.map +0 -1
  19. package/dist/scripts/8849-020bfd8cdd-lite.chunk.js +0 -2
  20. package/dist/scripts/8849-020bfd8cdd-lite.chunk.js.map +0 -1
  21. /package/dist/scripts/{2564-98ba0d782a-lite.chunk.js.LICENSE.txt → 2564-04ffede8c7-lite.chunk.js.LICENSE.txt} +0 -0
  22. /package/dist/scripts/{2615-e9b2938c18-lite.chunk.js.LICENSE.txt → 2615-27b126b1ab-lite.chunk.js.LICENSE.txt} +0 -0
  23. /package/dist/scripts/{bundle-b25c09d3e8.min.js.LICENSE.txt → bundle-176a4f3a0a.min.js.LICENSE.txt} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clickview/lite",
3
- "version": "0.57.3-rc.0",
3
+ "version": "0.58.0",
4
4
  "description": "ClickView Lite",
5
5
  "main": "dist/scripts/bundle.js",
6
6
  "types": "dist/projects/lite/src/index.d.ts",
@@ -1,3 +0,0 @@
1
- /*! For license information please see 2615-e9b2938c18-lite.chunk.js.LICENSE.txt */
2
- "use strict";(self.webpackChunk_clickview_lite=self.webpackChunk_clickview_lite||[]).push([[2615],{39157:(t,e,r)=>{r.d(e,{HI:()=>h,R6:()=>s,Rt:()=>d,UU:()=>f,Zs:()=>l,nq:()=>p});var n=r(75896),o=r(94892),i=r(28972),a=r(8246),c=r(83140),u=r(80845);function s(t,e,r){var i={markingRequired:[],lowScore:[],highScore:[],completed:[],notCompleted:[]},a=(0,u.Q)(t).length;e.students.forEach((function(e){var c=Object.assign(Object.assign({},e),{summary:d(t,e)});c.summary.awaitingMarking?i.markingRequired.push(c):n.m.last(e.results).attempts.length===a?(i.completed.push(c),c.summary.percentCorrect>=(r.HIGH||o.i.HIGH)&&i.highScore.push(c),c.summary.percentCorrect<(r.MODERATE||o.i.MODERATE)&&i.lowScore.push(c)):i.notCompleted.push(c)}));var c=n.m.sortBy(i.lowScore,(function(t){return t.summary.percentCorrect})),s=n.m.sortBy(i.highScore,(function(t){return-t.summary.percentCorrect}));return Object.assign(Object.assign({},i),{lowScore:c,highScore:s})}function l(t,e){return(0,u.Wn)(t).find((function(t){return t.id.toString()===e.toString()}))}function f(t){return"".concat(t.questionId,":").concat(t.resultId)}function h(t,e,r){var n=(0,u.j_)(e),o=(0,u.f6)(t,n);return(null==o?void 0:o.answers.every((function(t){var e;return(null===(e=r[f(t)])||void 0===e?void 0:e.status)===a.N.Correct})))?a.N.Correct:(null==o?void 0:o.answers.every((function(t){var e;return(null===(e=r[f(t)])||void 0===e?void 0:e.status)===a.N.Incorrect})))?a.N.Incorrect:void 0}function p(t,e){var r=e.students.length,n=0,o=0,a=0,s=0,l=0;return e.students.forEach((function(e){var r=(0,u.j_)(e);if(r){l+=e.results.length;var f=c.A.isInteractionCorrect(t,r);f===i.w.Correct&&n++,f===i.w.UnAnswered&&a++,f===i.w.AwaitingMarking&&s++,f!==i.w.UnAnswered&&o++}})),{percentCorrect:r>0?n/r:0,correct:n,answered:o,unanswered:a,awaitingMarking:s,attempts:l}}function d(t,e){var r=(0,u.j_)(e),n=(0,u.Q)(t),o=n.length,a=0,s=0;n.forEach((function(t){var e=c.A.isInteractionCorrect(t,r);e===i.w.Correct&&a++,e===i.w.AwaitingMarking&&s++}));var l=o>0?a/o:0,f=new Set(n.map((function(t){return t.id}))),h=r.attempts.filter((function(t){var e;return!!f.has(null===(e=null==t?void 0:t.answers[0])||void 0===e?void 0:e.questionId)})).length;return{answered:r.attempts.length,attempts:e.results.length,unanswered:o-h,percentCorrect:l,correct:a,awaitingMarking:s}}},32615:(t,e,r)=>{r.r(e),r.d(e,{InteractiveEditSuggestedResponse:()=>E});var n=r(32735),o=r(23481),i=r(44704),a=r(20354),c=r(39157),u=r(86572),s=r(9111),l=r(13876),f=r(83345),h=r(20768),p=r(69883);function d(t){return d="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},d(t)}function v(){v=function(){return e};var t,e={},r=Object.prototype,n=r.hasOwnProperty,o=Object.defineProperty||function(t,e,r){t[e]=r.value},i="function"==typeof Symbol?Symbol:{},a=i.iterator||"@@iterator",c=i.asyncIterator||"@@asyncIterator",u=i.toStringTag||"@@toStringTag";function s(t,e,r){return Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{s({},"")}catch(t){s=function(t,e,r){return t[e]=r}}function l(t,e,r,n){var i=e&&e.prototype instanceof w?e:w,a=Object.create(i.prototype),c=new N(n||[]);return o(a,"_invoke",{value:j(t,r,c)}),a}function f(t,e,r){try{return{type:"normal",arg:t.call(e,r)}}catch(t){return{type:"throw",arg:t}}}e.wrap=l;var h="suspendedStart",p="suspendedYield",y="executing",m="completed",g={};function w(){}function b(){}function E(){}var I={};s(I,a,(function(){return this}));var S=Object.getPrototypeOf,A=S&&S(S(M([])));A&&A!==r&&n.call(A,a)&&(I=A);var C=E.prototype=w.prototype=Object.create(I);function x(t){["next","throw","return"].forEach((function(e){s(t,e,(function(t){return this._invoke(e,t)}))}))}function k(t,e){function r(o,i,a,c){var u=f(t[o],t,i);if("throw"!==u.type){var s=u.arg,l=s.value;return l&&"object"==d(l)&&n.call(l,"__await")?e.resolve(l.__await).then((function(t){r("next",t,a,c)}),(function(t){r("throw",t,a,c)})):e.resolve(l).then((function(t){s.value=t,a(s)}),(function(t){return r("throw",t,a,c)}))}c(u.arg)}var i;o(this,"_invoke",{value:function(t,n){function o(){return new e((function(e,o){r(t,n,e,o)}))}return i=i?i.then(o,o):o()}})}function j(e,r,n){var o=h;return function(i,a){if(o===y)throw Error("Generator is already running");if(o===m){if("throw"===i)throw a;return{value:t,done:!0}}for(n.method=i,n.arg=a;;){var c=n.delegate;if(c){var u=L(c,n);if(u){if(u===g)continue;return u}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(o===h)throw o=m,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o=y;var s=f(e,r,n);if("normal"===s.type){if(o=n.done?m:p,s.arg===g)continue;return{value:s.arg,done:n.done}}"throw"===s.type&&(o=m,n.method="throw",n.arg=s.arg)}}}function L(e,r){var n=r.method,o=e.iterator[n];if(o===t)return r.delegate=null,"throw"===n&&e.iterator.return&&(r.method="return",r.arg=t,L(e,r),"throw"===r.method)||"return"!==n&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+n+"' method")),g;var i=f(o,e.iterator,r.arg);if("throw"===i.type)return r.method="throw",r.arg=i.arg,r.delegate=null,g;var a=i.arg;return a?a.done?(r[e.resultName]=a.value,r.next=e.nextLoc,"return"!==r.method&&(r.method="next",r.arg=t),r.delegate=null,g):a:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,g)}function O(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function _(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function N(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(O,this),this.reset(!0)}function M(e){if(e||""===e){var r=e[a];if(r)return r.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var o=-1,i=function r(){for(;++o<e.length;)if(n.call(e,o))return r.value=e[o],r.done=!1,r;return r.value=t,r.done=!0,r};return i.next=i}}throw new TypeError(d(e)+" is not iterable")}return b.prototype=E,o(C,"constructor",{value:E,configurable:!0}),o(E,"constructor",{value:b,configurable:!0}),b.displayName=s(E,u,"GeneratorFunction"),e.isGeneratorFunction=function(t){var e="function"==typeof t&&t.constructor;return!!e&&(e===b||"GeneratorFunction"===(e.displayName||e.name))},e.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,E):(t.__proto__=E,s(t,u,"GeneratorFunction")),t.prototype=Object.create(C),t},e.awrap=function(t){return{__await:t}},x(k.prototype),s(k.prototype,c,(function(){return this})),e.AsyncIterator=k,e.async=function(t,r,n,o,i){void 0===i&&(i=Promise);var a=new k(l(t,r,n,o),i);return e.isGeneratorFunction(r)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},x(C),s(C,u,"Generator"),s(C,a,(function(){return this})),s(C,"toString",(function(){return"[object Generator]"})),e.keys=function(t){var e=Object(t),r=[];for(var n in e)r.push(n);return r.reverse(),function t(){for(;r.length;){var n=r.pop();if(n in e)return t.value=n,t.done=!1,t}return t.done=!0,t}},e.values=M,N.prototype={constructor:N,reset:function(e){if(this.prev=0,this.next=0,this.sent=this._sent=t,this.done=!1,this.delegate=null,this.method="next",this.arg=t,this.tryEntries.forEach(_),!e)for(var r in this)"t"===r.charAt(0)&&n.call(this,r)&&!isNaN(+r.slice(1))&&(this[r]=t)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(e){if(this.done)throw e;var r=this;function o(n,o){return c.type="throw",c.arg=e,r.next=n,o&&(r.method="next",r.arg=t),!!o}for(var i=this.tryEntries.length-1;i>=0;--i){var a=this.tryEntries[i],c=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var u=n.call(a,"catchLoc"),s=n.call(a,"finallyLoc");if(u&&s){if(this.prev<a.catchLoc)return o(a.catchLoc,!0);if(this.prev<a.finallyLoc)return o(a.finallyLoc)}else if(u){if(this.prev<a.catchLoc)return o(a.catchLoc,!0)}else{if(!s)throw Error("try statement without catch or finally");if(this.prev<a.finallyLoc)return o(a.finallyLoc)}}}},abrupt:function(t,e){for(var r=this.tryEntries.length-1;r>=0;--r){var o=this.tryEntries[r];if(o.tryLoc<=this.prev&&n.call(o,"finallyLoc")&&this.prev<o.finallyLoc){var i=o;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=e&&e<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=e,i?(this.method="next",this.next=i.finallyLoc,g):this.complete(a)},complete:function(t,e){if("throw"===t.type)throw t.arg;return"break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&e&&(this.next=e),g},finish:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var r=this.tryEntries[e];if(r.finallyLoc===t)return this.complete(r.completion,r.afterLoc),_(r),g}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var r=this.tryEntries[e];if(r.tryLoc===t){var n=r.completion;if("throw"===n.type){var o=n.arg;_(r)}return o}}throw Error("illegal catch attempt")},delegateYield:function(e,r,n){return this.delegate={iterator:M(e),resultName:r,nextLoc:n},"next"===this.method&&(this.arg=t),g}},e}function y(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var r=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=r){var n,o,i,a,c=[],u=!0,s=!1;try{if(i=(r=r.call(t)).next,0===e){if(Object(r)!==r)return;u=!1}else for(;!(u=(n=i.call(r)).done)&&(c.push(n.value),c.length!==e);u=!0);}catch(t){s=!0,o=t}finally{try{if(!u&&null!=r.return&&(a=r.return(),Object(a)!==a))return}finally{if(s)throw o}}return c}}(t,e)||function(t,e){if(t){if("string"==typeof t)return m(t,e);var r={}.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?m(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function m(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=Array(e);r<e;r++)n[r]=t[r];return n}var g=function(t,e,r,n){return new(r||(r=Promise))((function(o,i){function a(t){try{u(n.next(t))}catch(t){i(t)}}function c(t){try{u(n.throw(t))}catch(t){i(t)}}function u(t){var e;t.done?o(t.value):(e=t.value,e instanceof r?e:new r((function(t){t(e)}))).then(a,c)}u((n=n.apply(t,e||[])).next())}))},w="shared.interactiveEditSuggestedResponse",b=o.T.encloseNamespace(w);function E(t){var e,r,o=(0,p.Z)(),d=(0,i.useGetFetchAsync)(),m=y(n.useState(!1),2),E=m[0],I=m[1],S=a.a.useBasicFetch(h.b.interactiveMetadata(t.interactiveId)),A=a.a.useBasicFetch((null===(e=S.data)||void 0===e?void 0:e.interactiveId)&&h.b.interactive(S.data.interactiveId)),C=A.data&&(0,c.Zs)(A.data,t.interactionId),x=y(n.useState(null===(r=C.data)||void 0===r?void 0:r.suggestedResponse),2),k=x[0],j=x[1];return n.createElement(s.G,{title:b(k?"edit":"create"),closePopup:t.closePopup},n.createElement("div",{className:"mb-3"},n.createElement(u.y,{interaction:C})),n.createElement("label",{htmlFor:"suggestedResponse",className:"form-label"},n.createElement(f.x,{namespace:w,phrase:"label"}),":"),n.createElement("textarea",{id:"suggestedResponse",className:"form-control w-100 mb-3",placeholder:b("placeholder"),onChange:function(t){return j(t.target.value)},value:k,rows:4}),n.createElement(l.u,null,n.createElement(l.u.Cancel,{onClick:t.closePopup}),n.createElement(l.u.Submit,{variant:"dark",text:b("save"),onClick:function(){return g(this,void 0,void 0,v().mark((function e(){var r;return v().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=Object.assign(Object.assign({},C),{actionableItems:[{name:"Answer"}],data:{suggestedResponse:k}}),I(!0),e.prev=2,e.next=5,d(h.b.updateInteraction(r));case 5:o.success(b("suggestedResponseSuccess")),t.closePopup(),e.next=12;break;case 9:e.prev=9,e.t0=e.catch(2),o.error(b("suggestedResponseError"));case 12:return e.prev=12,I(!1),e.finish(12);case 15:case"end":return e.stop()}}),e,null,[[2,9,12,15]])})))},showSpinner:E})))}},94892:(t,e,r)=>{r.d(e,{T:()=>o,i:()=>n});var n={HIGH:.75,MODERATE:.5},o={HIGH:.7,MODERATE:.7}},28972:(t,e,r)=>{var n;r.d(e,{w:()=>n}),function(t){t[t.Correct=0]="Correct",t[t.Incorrect=1]="Incorrect",t[t.AwaitingMarking=2]="AwaitingMarking",t[t.Answered=3]="Answered",t[t.UnAnswered=4]="UnAnswered",t[t.NotApplicable=5]="NotApplicable"}(n||(n={}))},8246:(t,e,r)=>{var n;r.d(e,{N:()=>n}),function(t){t[t.Incorrect=0]="Incorrect",t[t.Correct=1]="Correct",t[t.PendingReview=2]="PendingReview"}(n||(n={}))},83140:(t,e,r)=>{r.d(e,{A:()=>v});var n=r(28972),o=r(8246),i=r(40424);function a(t){return a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},a(t)}function c(t,e,r){return(e=function(t){var e=function(t,e){if("object"!=a(t)||!t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var n=r.call(t,"string");if("object"!=a(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==a(e)?e:e+""}(e))in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function u(){return n.w.NotApplicable}function s(t,e){var r=t.actionableItems.filter((function(t){return t.isCorrect}));return r.every((function(t){return!e(t.id)}))?n.w.UnAnswered:r.every((function(t){var r;return t.name.trim().toLowerCase()===(null===(r=e(t.id))||void 0===r?void 0:r.trim().toLowerCase())}))?n.w.Correct:n.w.Incorrect}function l(t,e){return t.actionableItems.every((function(t){return!e(t.id)}))?n.w.UnAnswered:t.actionableItems.filter((function(t){return t.isCorrect})).every((function(t){var r,n=e(t.id);return(null==n?void 0:n.toString())===(null===(r=t.id)||void 0===r?void 0:r.toString())||n===t.name}))?n.w.Correct:n.w.Incorrect}function f(t,e){return function(r){var n=e.attempts.find((function(e){return e.id===t.id}));return null==n?void 0:n.answers.find((function(t){return t.id===r}))}}function h(t,e){var r=f(t,e);return l(t,(function(t){var e=r(t);return null==e?void 0:e.text}))}function p(t,e){return function(t,e){var r;return t.actionableItems.forEach((function(t){var i=e(t.id);r=i?i.status!==o.N.Correct?i.status!==o.N.Incorrect?n.w.AwaitingMarking:n.w.Incorrect:n.w.Correct:n.w.UnAnswered})),r}(t,f(t,e))}var d=c(c(c(c(c(c(c({},i.Z9.Annotation,u),i.Z9.Image,u),i.Z9.MissingWord,(function(t,e){var r=f(t,e);return s(t,(function(t){var e=r(t);return null==e?void 0:e.text}))})),i.Z9.MultipleChoice,h),i.Z9.ShortAnswer,p),i.Z9.TrueOrFalse,h),i.Z9.Illustration,p),v={notApplicable:u,awaitingMarking:function(){return n.w.AwaitingMarking},isMissingWordCorrect:s,isMultipleChoiceCorrect:l,isInteractionCorrect:function(t,e){return(0,d[t.typeId])(t,e)}}},80845:(t,e,r)=>{r.d(e,{Q:()=>s,Wn:()=>a,f6:()=>u,j_:()=>c});var n=r(75896),o=r(40424);function i(t){return t.typeId!==o.Z9.Annotation&&t.typeId!==o.Z9.Image}function a(t){return n.m.flatten(t.timepoints.map((function(t){return t.interactions})))}function c(t){return n.m.last(t.results)}function u(t,e){return n.m.findWhere(null==e?void 0:e.attempts,{id:t})}function s(t){return a(t).filter(i)}}}]);
3
- //# sourceMappingURL=2615-e9b2938c18-lite.chunk.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scripts/2615-e9b2938c18-lite.chunk.js","mappings":";uPAqBM,SAAUA,EACdC,EACAC,EACAC,GAEA,IAAMC,EAAwB,CAC5BC,gBAAiB,GACjBC,SAAU,GACVC,UAAW,GACXC,UAAW,GACXC,aAAc,IAKVC,GAFe,OAAgBT,GAEAU,OAErCT,EAAQU,SAASC,SAAQ,SAAAC,GACvB,IAAMC,EAAc,OAAH,wBACZD,GAAC,CACJE,QAASC,EAAyBhB,EAAaa,KAG7CC,EAAYC,QAAQE,gBACtBd,EAAOC,gBAAgBc,KAAKJ,GAI1B,SAAiBD,EAAEZ,SAASkB,SAAST,SAAWD,GAClDN,EAAOI,UAAUW,KAAKJ,GAMpBA,EAAYC,QAAQK,iBAAmBlB,EAAemB,MAAQ,WAChElB,EAAOG,UAAUY,KAAKJ,GAEpBA,EAAYC,QAAQK,gBAAkBlB,EAAeoB,UAAY,eACnEnB,EAAOE,SAASa,KAAKJ,IARrBX,EAAOK,aAAaU,KAAKJ,EAS7B,IAEA,IAAMS,EAAiB,WAAmBpB,EAAOE,UAAU,SAAAQ,GAAC,OAAIA,EAAEE,QAAQK,cAAc,IAClFI,EAAkB,WAAmBrB,EAAOG,WAAW,SAAAO,GAAC,OAAKA,EAAEE,QAAQK,cAAc,IAE3F,OAAO,OAAP,wBACKjB,GAAM,CACTE,SAAUkB,EACVjB,UAAWkB,GAEf,CAEM,SAAUC,EAAmBzB,EAA0B0B,GAE3D,OAD8B,QAAoB1B,GACrB2B,MAAK,SAAAC,GAAC,OAAIA,EAAEC,GAAGC,aAAeJ,EAAcI,UAAU,GACrF,CAOM,SAAUC,EAAkBC,GAChC,MAAO,GAAP,OAAUA,EAAOC,WAAU,YAAID,EAAOE,SACxC,CAEM,SAAUC,EACdT,EACAU,EACAC,GAEA,IAAMC,GAAS,QAAiBF,GAC1BG,GAAkB,QAAkBb,EAAeY,GAMzD,OAJwBC,aAAe,EAAfA,EAAiBC,QAAQC,OAAM,SAAAC,SACrD,OAA0C,QAAnC,EAAAL,EAAcN,EAAkBW,WAAG,eAAEC,UAAW,WACzD,KAGS,aAEiBJ,aAAe,EAAfA,EAAiBC,QAAQC,OAAM,SAAAC,SACvD,OAA0C,QAAnC,EAAAL,EAAcN,EAAkBW,WAAG,eAAEC,UAAW,aACzD,KAGS,mBADT,CAEF,CAEM,SAAUC,EACdC,EACA5C,GAEA,IAAM6C,EAAc7C,EAAQU,SAASD,OACjCqC,EAAa,EACbC,EAAW,EACXC,EAAa,EACbhC,EAAkB,EAClBE,EAAW,EA8Bf,OA5BAlB,EAAQU,SAASC,SAAQ,SAAAC,GACvB,IAAMyB,GAAS,QAAiBzB,GAEhC,GAAKyB,EAAL,CAGAnB,GAAsBN,EAAEZ,QAAQS,OAEhC,IAAMwC,EAAc,yBAAkDL,EAAaP,GAE/EY,IAAgB,aAClBH,IAEEG,IAAgB,gBAClBD,IAEEC,IAAgB,qBAClBjC,IAEEiC,IAAgB,gBAClBF,GAhBM,CAiBV,IAOO,CACL5B,eALqB0B,EAAc,EACjCC,EAAaD,EACb,EAIFK,QAASJ,EACTC,SAAAA,EACAC,WAAAA,EACAhC,gBAAAA,EACAE,SAAAA,EAEJ,CAEM,SAAUH,EAAyBhB,EAA0BoC,GACjE,IAAME,GAAS,QAAiBF,GAE1BgB,GAAe,OAAgBpD,GAE/BS,EAAkB2C,EAAa1C,OAEjCqC,EAAa,EACb9B,EAAkB,EAEtBmC,EAAaxC,SAAQ,SAAAgB,GACnB,IAAMsB,EAAc,yBAAkDtB,EAAGU,GAErEY,IAAgB,aAClBH,IAEEG,IAAgB,qBAClBjC,GACJ,IAEA,IAAMG,EAAiBX,EAAkB,EAAIsC,EAAatC,EAAkB,EAQtE4C,EAAiB,IAAIC,IAAIF,EAAaG,KAAI,SAAA3B,GAAC,OAAIA,EAAEC,EAAE,KACnD2B,EAAuBlB,EAAOnB,SAASsC,QAAO,SAAAf,GAAI,MAAC,QAAEW,EAAeK,IAAiB,QAAb,EAAAhB,aAAC,EAADA,EAAGF,QAAQ,UAAE,eAAEP,WAAW,IAAEvB,OAE1G,MAAO,CACLsC,SAAUV,EAAOnB,SAAST,OAC1BS,SAAUiB,EAAenC,QAAQS,OACjCuC,WAAYxC,EAAkB+C,EAC9BpC,eAAAA,EACA+B,QAASJ,EACT9B,gBAAAA,EAEJ,ojQCvLM0C,EAAY,0CACZC,EAAY,qBAAiCD,GAO7C,SAAUE,EAAiCC,WACzCC,GAAQ,SACRC,GAAa,IAAAC,oBAE0C,IAArB,YAAe,GAAM,GAArDC,EAAW,KAAEC,EAAc,KAE7BC,EAAsB,kBAC1B,wBAAwCN,EAAMO,gBAE1CrE,EAAc,mBAA0D,QAAxB,EAAAoE,EAAoBE,YAAI,eAAED,gBAC9E,gBAAgCD,EAAoBE,KAAKD,gBAErDxB,EAAc7C,EAAYsE,OAAQ,QAAmBtE,EAAYsE,KAAMR,EAAMpC,eAEoB,IAAnD,WAA+B,QAAhB,EAAAmB,EAAYyB,YAAI,eAAEC,mBAAkB,GAA/FA,EAAiB,KAAEC,EAAoB,KAwB/C,OACE,gBAAC,IAAK,CACJC,MAAOb,EAAWW,EAA+B,OAAX,UACtCG,WAAYZ,EAAMY,YAElB,uBAAKC,UAAU,QACb,gBAAC,IAAgB,CAAC9B,YAAaA,KAGjC,yBAAO+B,QAAQ,oBAAoBD,UAAU,cAC3C,gBAAC,IAAI,CAAChB,UAAWA,EAAWkB,OAAO,UAAU,KAG/C,4BACEhD,GAAG,oBACH8C,UAAU,0BACVG,YAAalB,EAAU,eACvBmB,SAAU,SAAAC,GAAC,OAAIR,EAAqBQ,EAAEC,OAAOC,MAAM,EACnDA,MAAOX,EACPY,KAAM,IAGR,gBAAC,IAAY,KACX,gBAAC,WAAmB,CAACC,QAAStB,EAAMY,aACpC,gBAAC,WAAmB,CAClBW,QAAQ,OACRC,KAAM1B,EAAU,QAChBwB,QAjDR,qIAUI,OATId,EAAI,+BACLzB,GAAW,CACd0C,gBAAiB,CAAC,CAAEC,KAAM,WAC1BlB,KAAM,CAAEC,kBAAAA,KAGVJ,GAAe,GAAM,kBAGbH,EAAW,sBAAsCM,IAAM,OAE7DP,EAAM0B,QAAQ7B,EAAU,6BAExBE,EAAMY,aAAa,gDAEnBX,EAAM2B,MAAM9B,EAAU,2BAA2B,QAE3B,OAF2B,UAEjDO,GAAe,GAAO,2EAEzB,EA8BOD,YAAaA,KAKvB,4CCzFO,IAAMyB,EAA0C,CACrDtE,KAAM,IACNC,SAAU,IAGCsE,EAA0C,CACrDvE,KAAM,GACNC,SAAU,qBCZZ,IAAYuE,mBAAZ,SAAYA,GACV,yBACA,6BACA,yCAEA,2BACA,+BACA,oCACD,CARD,CAAYA,IAAAA,EAAsB,qBCAlC,IAAYC,mBAAZ,SAAYA,GACV,6BACA,yBACA,oCACD,CAJD,CAAYA,IAAAA,EAAuB,gsBCMnC,SAASC,IACP,OAAO,iBACT,CAMA,SAASC,EACPnD,EACAoD,GAEA,IAAMC,EAAQrD,EAAY0C,gBAAgB9B,QAAO,SAAAf,GAAC,OAAIA,EACnDyD,SAAS,IAEZ,OAAID,EAAMzD,OAAM,SAAAC,GAAC,OAAKuD,EAAiBvD,EAAEb,GAAG,IACnC,eAEOqE,EAAMzD,OAAM,SAAAC,GAAI,MAAC,OAAAA,EAAE8C,KAAKY,OAAOC,iBAAwC,QAAtB,EAAAJ,EAAiBvD,EAAEb,WAAG,eAAEuE,OAAOC,cAAa,IAC5F,YAAiC,aACpD,CAEA,SAASC,EACPzD,EACAoD,GAEA,OAAIpD,EAAY0C,gBAAgB9C,OAAM,SAAAC,GAAC,OAAKuD,EAAiBvD,EAAEb,GAAG,IACzD,eAEYgB,EAAY0C,gBAAgB9B,QAAO,SAAAf,GAAC,OAAIA,EAAEyD,SAAS,IAE3C1D,OAAM,SAAAC,SAC3B6D,EAAgBN,EAAiBvD,EAAEb,IAOzC,OAAO0E,aAAa,EAAbA,EAAezE,eAAmB,QAAJ,EAAAY,EAAEb,UAAE,eAAEC,aAAcyE,IAAkB7D,EAAE8C,IAC/E,IACiB,YAAiC,aACpD,CAmCA,SAASgB,EAAoB3D,EAA0BP,GACrD,OAAO,SAACT,GACN,IAAM4E,EAAUnE,EAAOnB,SAASQ,MAAK,SAAAe,GAAC,OAAIA,EAAEb,KAAOgB,EAAYhB,EAAE,IACjE,OAAO4E,aAAO,EAAPA,EAASjE,QAAQb,MAAK,SAAAd,GAAC,OAAIA,EAAEgB,KAAOA,CAAE,GAC/C,CACF,CAWA,SAAS6E,EAA4B7D,EAA0BP,GAC7D,IAAM2D,EAAmBO,EAAoB3D,EAAaP,GAE1D,OAAOgE,EAAwBzD,GAAa,SAAChB,GAC3C,IAAMG,EAASiE,EAAiBpE,GAChC,OAAOG,aAAM,EAANA,EAAQsD,IACjB,GACF,CAEA,SAASqB,EACP9D,EACAP,GAGA,OA/DF,SACEO,EACAoD,GAEA,IAAI/C,EAwBJ,OArBAL,EAAY0C,gBAAgB3E,SAAQ,SAAAgG,GAClC,IAAML,EAAgBN,EAAiBW,EAAK/E,IAiB5CqB,EAfKqD,EAKDA,EAAc5D,SAAW,YAKzB4D,EAAc5D,SAAW,cAKf,oBAJE,cALA,YALA,cAelB,IAEOO,CACT,CAkCS2D,CAA8BhE,EADZ2D,EAAoB3D,EAAaP,GAE5D,CAEA,IAAMwE,EAAe,iBAClB,gBAA+Bf,GAC/B,WAA0BA,GAC1B,kBA7BH,SAAkClD,EAA0BP,GAC1D,IAAM2D,EAAmBO,EAAoB3D,EAAaP,GAE1D,OAAO0D,EAAqBnD,GAAa,SAAChB,GACxC,IAAMG,EAASiE,EAAiBpE,GAChC,OAAOG,aAAM,EAANA,EAAQsD,IACjB,GACF,IAuBG,oBAAmCoB,GACnC,iBAAgCC,GAChC,iBAAgCD,GAChC,kBAAiCC,GASvBI,EAA+B,CAC1ChB,cAAAA,EACA9E,gBA5HF,WACE,OAAO,mBACT,EA2HE+E,qBAAAA,EACAM,wBAAAA,EACAU,qBAXF,SAA8BnE,EAA0BP,GAGtD,OAAO2E,EAFaH,EAAgBjE,EAAYqE,SAE7BrE,EAAaP,EAClC,0FCvHA,SAAS6E,EAA0BtE,GACjC,OAAOA,EAAYqE,SAAW,iBAAgCrE,EAAYqE,SAAW,UACvF,CAEM,SAAUE,EAAoBpH,GAClC,OAAO,YAAoBA,EAAYqH,WAAW9D,KAAI,SAAA3B,GAAC,OAAIA,EAAEwB,YAAY,IAC3E,CAKM,SAAUkE,EAAiBlF,GAC/B,OAAO,SAAiBA,EAAenC,QACzC,CAEM,SAAUsH,EAAkB7F,EAAuBY,GACvD,OAAO,cAAsBA,aAAM,EAANA,EAAQnB,SAAU,CAAEU,GAAIH,GACvD,CAMM,SAAU8F,EAAgBxH,GAC9B,OAAOoH,EAAoBpH,GAAayD,OAAO0D,EACjD","sources":["file:///app/packages/libs/shared/src/apps/analytics/utils/InteractiveUtils.ts","file:///app/packages/libs/shared/src/apps/analytics/views/interactive-edit-suggested-response/InteractiveEditSuggestedResponse.tsx","file:///app/packages/libs/shared/src/constants/ScoreThresholds.ts","file:///app/packages/libs/shared/src/enums/InteractionCorrectness.ts","file:///app/packages/libs/shared/src/enums/InteractiveAnswerStatus.ts","file:///app/packages/libs/shared/src/utils/InteractiveCorrectnessHelper.ts","file:///app/packages/libs/shared/src/utils/InteractiveHelper.ts"],"sourcesContent":["import { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { MarkedAnswerHash } from 'libs/shared/apps/analytics/hooks/UseMarkAnswers';\nimport { ResultsSummary } from 'libs/shared/apps/analytics/interfaces/ResultsSummary';\nimport { StudentResultsWithSummary } from 'libs/shared/apps/analytics/interfaces/StudentResultsWithSummary';\nimport { ScoreThresholdDefaults, ScoreThresholds } from 'libs/shared/constants/ScoreThresholds';\nimport { InteractionCorrectness } from 'libs/shared/enums/InteractionCorrectness';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { Interaction, StudentAnswer, StudentResults } from 'libs/shared/interfaces';\nimport { Interactive, InteractiveResultSet } from 'libs/shared/interfaces';\nimport { InteractiveCorrectnessHelper } from 'libs/shared/utils/InteractiveCorrectnessHelper';\nimport { flattenInteractions, getInteractions, getStudentAttempt, getStudentResult } from 'libs/shared/utils/InteractiveHelper';\n\ninterface StudentGroups {\n markingRequired: StudentResultsWithSummary[];\n lowScore: StudentResultsWithSummary[];\n highScore: StudentResultsWithSummary[];\n completed: StudentResultsWithSummary[];\n notCompleted: StudentResultsWithSummary[];\n}\n\nexport function groupStudents(\n interactive: Interactive,\n results: InteractiveResultSet,\n scoreThreshold?: ScoreThresholds\n): StudentGroups {\n const groups: StudentGroups = {\n markingRequired: [],\n lowScore: [],\n highScore: [],\n completed: [],\n notCompleted: []\n };\n\n const interactions = getInteractions(interactive);\n\n const numInteractions = interactions.length;\n \n results.students.forEach(s => {\n const withSummary = {\n ...s,\n summary: getStudentResultsSummary(interactive, s)\n };\n \n if (withSummary.summary.awaitingMarking) {\n groups.markingRequired.push(withSummary);\n return;\n }\n\n if (ArrayHelper.last(s.results).attempts.length === numInteractions) {\n groups.completed.push(withSummary);\n } else {\n groups.notCompleted.push(withSummary);\n return;\n }\n \n if (withSummary.summary.percentCorrect >= (scoreThreshold.HIGH || ScoreThresholdDefaults.HIGH))\n groups.highScore.push(withSummary);\n \n if (withSummary.summary.percentCorrect < (scoreThreshold.MODERATE || ScoreThresholdDefaults.MODERATE))\n groups.lowScore.push(withSummary);\n });\n \n const sortedLowScore = ArrayHelper.sortBy(groups.lowScore, s => s.summary.percentCorrect);\n const sortedHighScore = ArrayHelper.sortBy(groups.highScore, s => -s.summary.percentCorrect);\n \n return {\n ...groups,\n lowScore: sortedLowScore,\n highScore: sortedHighScore\n };\n}\n\nexport function getInteractionById(interactive: Interactive, interactionId: string): Interaction {\n const flattenedInteractions = flattenInteractions(interactive);\n return flattenedInteractions.find(i => i.id.toString() === interactionId.toString());\n}\n\n/**\n * We need to use the question and result ids as a list of one student's responses\n * to multiple questions will all have the same result id and a list of multiple\n * students responses to one question will all have the same questionId.\n */\nexport function getMarkedAnswerId(answer: StudentAnswer): string {\n return `${answer.questionId}:${answer.resultId}`;\n}\n\nexport function getMarkedStatus(\n interactionId: string,\n studentResults: StudentResults,\n markedAnswers: MarkedAnswerHash\n): InteractiveAnswerStatus {\n const result = getStudentResult(studentResults);\n const studentResponse = getStudentAttempt(interactionId, result);\n\n const isMarkedCorrect = studentResponse?.answers.every(a => {\n return markedAnswers[getMarkedAnswerId(a)]?.status === InteractiveAnswerStatus.Correct;\n });\n\n if (isMarkedCorrect)\n return InteractiveAnswerStatus.Correct;\n\n const isMarkedIncorrect = studentResponse?.answers.every(a => {\n return markedAnswers[getMarkedAnswerId(a)]?.status === InteractiveAnswerStatus.Incorrect;\n });\n\n if (isMarkedIncorrect)\n return InteractiveAnswerStatus.Incorrect;\n}\n\nexport function getInteractionResultsSummary(\n interaction: Interaction,\n results: InteractiveResultSet\n): ResultsSummary {\n const numStudents = results.students.length;\n let numCorrect = 0;\n let answered = 0;\n let unanswered = 0;\n let awaitingMarking = 0;\n let attempts = 0;\n\n results.students.forEach(s => {\n const result = getStudentResult(s);\n\n if (!result)\n return;\n\n attempts = attempts + s.results.length;\n\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(interaction, result);\n\n if (correctness === InteractionCorrectness.Correct)\n numCorrect++;\n\n if (correctness === InteractionCorrectness.UnAnswered)\n unanswered++;\n\n if (correctness === InteractionCorrectness.AwaitingMarking)\n awaitingMarking++;\n\n if (correctness !== InteractionCorrectness.UnAnswered)\n answered++;\n });\n\n\n const percentCorrect = numStudents > 0\n ? numCorrect / numStudents\n : 0;\n\n return {\n percentCorrect,\n correct: numCorrect,\n answered,\n unanswered,\n awaitingMarking,\n attempts\n };\n}\n\nexport function getStudentResultsSummary(interactive: Interactive, studentResults: StudentResults): ResultsSummary {\n const result = getStudentResult(studentResults);\n\n const interactions = getInteractions(interactive);\n\n const numInteractions = interactions.length;\n\n let numCorrect = 0;\n let awaitingMarking = 0;\n\n interactions.forEach(i => {\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(i, result);\n\n if (correctness === InteractionCorrectness.Correct)\n numCorrect++;\n\n if (correctness === InteractionCorrectness.AwaitingMarking)\n awaitingMarking++;\n });\n\n const percentCorrect = numInteractions > 0 ? numCorrect / numInteractions : 0;\n\n /**\n * Our interactions list has images and annotations filtered out.\n * We built a map of valid questions, so that we can calculate the unswered accurately.\n * We're doing this because of a bug that caused annotations and images to record answers in the player.\n * - Sha\n */\n const interactionIds = new Set(interactions.map(i => i.id));\n const answeredInteractions = result.attempts.filter(a => !!interactionIds.has(a?.answers[0]?.questionId)).length;\n\n return {\n answered: result.attempts.length,\n attempts: studentResults.results.length,\n unanswered: numInteractions - answeredInteractions,\n percentCorrect,\n correct: numCorrect,\n awaitingMarking\n };\n}","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { useGetFetchAsync } from 'libs/common/react/flight';\nimport { Flight } from 'libs/common/react/index';\n\nimport { getInteractionById } from 'libs/shared/apps/analytics/utils/InteractiveUtils';\nimport { InteractionLabel } from 'libs/shared/components/interactive-questions/InteractionLabel';\nimport { Popup, PopupProps } from 'libs/shared/components/popup/Popup';\nimport { PopupButtons } from 'libs/shared/components/popup/PopupButtons';\nimport { Text } from 'libs/shared/components/text/Text';\nimport { InteractiveRequests } from 'libs/shared/flight-requests/InteractiveRequests';\nimport { useAlerts } from 'libs/shared/hooks/UseAlerts';\nimport { Interaction, Interactive, InteractiveMetadata } from 'libs/shared/interfaces';\n\nconst namespace = 'shared.interactiveEditSuggestedResponse';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\ninterface InteractiveEditSuggestedResponseProps extends PopupProps {\n interactiveId: string;\n interactionId: string;\n}\n\nexport function InteractiveEditSuggestedResponse(props: InteractiveEditSuggestedResponseProps) {\n const alert = useAlerts();\n const fetchAsync = useGetFetchAsync();\n\n const [ showSpinner, setShowSpinner ] = React.useState(false);\n\n const interactiveMetadata = Flight.useBasicFetch<InteractiveMetadata>(\n InteractiveRequests.interactiveMetadata(props.interactiveId)\n );\n const interactive = Flight.useBasicFetch<Interactive>(interactiveMetadata.data?.interactiveId &&\n InteractiveRequests.interactive(interactiveMetadata.data.interactiveId));\n\n const interaction = interactive.data && getInteractionById(interactive.data, props.interactionId);\n \n const [ suggestedResponse, setSuggestedResponse ] = React.useState(interaction.data?.suggestedResponse);\n\n async function submitSuggestedResponse() {\n const data: Interaction = {\n ...interaction,\n actionableItems: [{ name: 'Answer' }],\n data: { suggestedResponse }\n };\n\n setShowSpinner(true);\n\n try {\n await fetchAsync(InteractiveRequests.updateInteraction(data));\n\n alert.success(getPhrase('suggestedResponseSuccess'));\n\n props.closePopup();\n } catch {\n alert.error(getPhrase('suggestedResponseError'));\n } finally {\n setShowSpinner(false);\n }\n }\n\n return (\n <Popup\n title={getPhrase(!suggestedResponse ? 'create' : 'edit')}\n closePopup={props.closePopup}\n >\n <div className='mb-3'>\n <InteractionLabel interaction={interaction} />\n </div>\n\n <label htmlFor='suggestedResponse' className='form-label'>\n <Text namespace={namespace} phrase='label' />:\n </label>\n\n <textarea\n id='suggestedResponse'\n className='form-control w-100 mb-3'\n placeholder={getPhrase('placeholder')}\n onChange={e => setSuggestedResponse(e.target.value)}\n value={suggestedResponse}\n rows={4}\n />\n\n <PopupButtons>\n <PopupButtons.Cancel onClick={props.closePopup} />\n <PopupButtons.Submit\n variant='dark'\n text={getPhrase('save')}\n onClick={submitSuggestedResponse}\n showSpinner={showSpinner}\n />\n </PopupButtons>\n </Popup>\n );\n}","export interface ScoreThresholds {\n HIGH: number;\n MODERATE: number;\n}\n\nexport const ScoreThresholdDefaults: ScoreThresholds = {\n HIGH: 0.75,\n MODERATE: 0.5\n};\n\nexport const ScoreThresholdInsights: ScoreThresholds = {\n HIGH: 0.7,\n MODERATE: 0.7\n};","export enum InteractionCorrectness {\n Correct,\n Incorrect,\n AwaitingMarking,\n \n Answered,\n UnAnswered,\n NotApplicable\n}","export enum InteractiveAnswerStatus {\n Incorrect = 0,\n Correct = 1,\n PendingReview = 2\n}","import { InteractionCorrectness } from 'libs/shared/enums/InteractionCorrectness';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { Interaction, InteractionTypeId, InteractiveResult, StudentAnswer } from 'libs/shared/interfaces';\n\ntype GetStudentAnswerByActionableItemId = (id: string) => string;\n\nfunction notApplicable(): InteractionCorrectness {\n return InteractionCorrectness.NotApplicable;\n}\n\nfunction awaitingMarking(): InteractionCorrectness {\n return InteractionCorrectness.AwaitingMarking;\n}\n\nfunction isMissingWordCorrect(\n interaction: Interaction,\n getStudentAnswer: GetStudentAnswerByActionableItemId\n): InteractionCorrectness {\n const items = interaction.actionableItems.filter(a => a\n .isCorrect);\n\n if (items.every(a => !getStudentAnswer(a.id)))\n return InteractionCorrectness.UnAnswered;\n\n const correct = items.every(a => a.name.trim().toLowerCase() === getStudentAnswer(a.id)?.trim().toLowerCase());\n return correct ? InteractionCorrectness.Correct : InteractionCorrectness.Incorrect;\n}\n\nfunction isMultipleChoiceCorrect(\n interaction: Interaction,\n getStudentAnswer: GetStudentAnswerByActionableItemId\n): InteractionCorrectness {\n if (interaction.actionableItems.every(a => !getStudentAnswer(a.id)))\n return InteractionCorrectness.UnAnswered;\n \n const correctItems = interaction.actionableItems.filter(a => a.isCorrect);\n\n const correct = correctItems.every(a => {\n const studentAnswer = getStudentAnswer(a.id);\n\n /**\n * In the past we've only ever checked the answer name. But since we introduced the ability to have image interactions\n * with no question text, we've need to swap to saving the id. But past submissions still have the name\n * - Sha\n */\n return studentAnswer?.toString() === a.id?.toString() || studentAnswer === a.name;\n });\n return correct ? InteractionCorrectness.Correct : InteractionCorrectness.Incorrect;\n}\n\nfunction isMarkableAnswerMarkedCorrect(\n interaction: Interaction,\n getStudentAnswer: (id: string) => StudentAnswer\n): InteractionCorrectness {\n let correctness: InteractionCorrectness;\n\n // There should only be one actionableItem\n interaction.actionableItems.forEach(item => {\n const studentAnswer = getStudentAnswer(item.id);\n\n if (!studentAnswer) {\n correctness = InteractionCorrectness.UnAnswered;\n return;\n }\n\n if (studentAnswer.status === InteractiveAnswerStatus.Correct) {\n correctness = InteractionCorrectness.Correct;\n return;\n }\n\n if (studentAnswer.status === InteractiveAnswerStatus.Incorrect) {\n correctness = InteractionCorrectness.Incorrect;\n return;\n }\n\n correctness = InteractionCorrectness.AwaitingMarking;\n });\n\n return correctness;\n}\n\ntype IsCorrectFunction = (interaction: Interaction, result: InteractiveResult) => InteractionCorrectness;\n\nfunction getGetStudentAnswer(interaction: Interaction, result: InteractiveResult): (id: string) => StudentAnswer {\n return (id: string) => {\n const attempt = result.attempts.find(a => a.id === interaction.id);\n return attempt?.answers.find(s => s.id === id);\n };\n}\n\nfunction wrapIsMissingWordCorrect(interaction: Interaction, result: InteractiveResult): InteractionCorrectness {\n const getStudentAnswer = getGetStudentAnswer(interaction, result);\n\n return isMissingWordCorrect(interaction, (id: string) => {\n const answer = getStudentAnswer(id);\n return answer?.text;\n });\n}\n\nfunction wrapIsMultipleChoiceCorrect(interaction: Interaction, result: InteractiveResult): InteractionCorrectness {\n const getStudentAnswer = getGetStudentAnswer(interaction, result);\n\n return isMultipleChoiceCorrect(interaction, (id: string) => {\n const answer = getStudentAnswer(id);\n return answer?.text;\n });\n}\n\nfunction wrapIsMarkableAnswerMarkedCorrect(\n interaction: Interaction,\n result: InteractiveResult\n): InteractionCorrectness {\n const getStudentAnswer = getGetStudentAnswer(interaction, result);\n return isMarkableAnswerMarkedCorrect(interaction, getStudentAnswer);\n}\n\nconst IsCorrectLookup: {[typeId: number]: IsCorrectFunction} = {\n [InteractionTypeId.Annotation]: notApplicable,\n [InteractionTypeId.Image]: notApplicable,\n [InteractionTypeId.MissingWord]: wrapIsMissingWordCorrect,\n [InteractionTypeId.MultipleChoice]: wrapIsMultipleChoiceCorrect,\n [InteractionTypeId.ShortAnswer]: wrapIsMarkableAnswerMarkedCorrect,\n [InteractionTypeId.TrueOrFalse]: wrapIsMultipleChoiceCorrect,\n [InteractionTypeId.Illustration]: wrapIsMarkableAnswerMarkedCorrect\n};\n\nfunction isInteractionCorrect(interaction: Interaction, result: InteractiveResult): InteractionCorrectness {\n const isCorrectFn = IsCorrectLookup[interaction.typeId];\n\n return isCorrectFn(interaction, result);\n}\n\nexport const InteractiveCorrectnessHelper = {\n notApplicable,\n awaitingMarking,\n isMissingWordCorrect,\n isMultipleChoiceCorrect,\n isInteractionCorrect\n};\n","import { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport {\n Interaction,\n InteractionTypeId,\n Interactive,\n InteractiveResult,\n StudentAttempt,\n StudentResults\n} from 'libs/shared/interfaces';\n\nfunction interactionRequiresAnswer(interaction: Interaction): boolean {\n return interaction.typeId !== InteractionTypeId.Annotation && interaction.typeId !== InteractionTypeId.Image;\n}\n\nexport function flattenInteractions(interactive: Interactive): Interaction[] {\n return ArrayHelper.flatten(interactive.timepoints.map(i => i.interactions));\n}\n\n/**\n * Centralised logic for using the most recent student result.\n */\nexport function getStudentResult(studentResults: StudentResults): InteractiveResult {\n return ArrayHelper.last(studentResults.results);\n}\n\nexport function getStudentAttempt(interactionId: string, result: InteractiveResult): StudentAttempt {\n return ArrayHelper.findWhere(result?.attempts, { id: interactionId });\n}\n\n/**\n * Returns a flat list of interactions on an interactive and filters out\n * those that don't require an answer (annotations and images).\n */\nexport function getInteractions(interactive: Interactive): Interaction [] {\n return flattenInteractions(interactive).filter(interactionRequiresAnswer);\n}"],"names":["groupStudents","interactive","results","scoreThreshold","groups","markingRequired","lowScore","highScore","completed","notCompleted","numInteractions","length","students","forEach","s","withSummary","summary","getStudentResultsSummary","awaitingMarking","push","attempts","percentCorrect","HIGH","MODERATE","sortedLowScore","sortedHighScore","getInteractionById","interactionId","find","i","id","toString","getMarkedAnswerId","answer","questionId","resultId","getMarkedStatus","studentResults","markedAnswers","result","studentResponse","answers","every","a","status","getInteractionResultsSummary","interaction","numStudents","numCorrect","answered","unanswered","correctness","correct","interactions","interactionIds","Set","map","answeredInteractions","filter","has","namespace","getPhrase","InteractiveEditSuggestedResponse","props","alert","fetchAsync","useGetFetchAsync","showSpinner","setShowSpinner","interactiveMetadata","interactiveId","data","suggestedResponse","setSuggestedResponse","title","closePopup","className","htmlFor","phrase","placeholder","onChange","e","target","value","rows","onClick","variant","text","actionableItems","name","success","error","ScoreThresholdDefaults","ScoreThresholdInsights","InteractionCorrectness","InteractiveAnswerStatus","notApplicable","isMissingWordCorrect","getStudentAnswer","items","isCorrect","trim","toLowerCase","isMultipleChoiceCorrect","studentAnswer","getGetStudentAnswer","attempt","wrapIsMultipleChoiceCorrect","wrapIsMarkableAnswerMarkedCorrect","item","isMarkableAnswerMarkedCorrect","IsCorrectLookup","InteractiveCorrectnessHelper","isInteractionCorrect","isCorrectFn","typeId","interactionRequiresAnswer","flattenInteractions","timepoints","getStudentResult","getStudentAttempt","getInteractions"],"sourceRoot":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"scripts/2978-b7bcc3eac4-lite.chunk.js","mappings":"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","sources":["file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/IllustrationResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/MissingWordResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/MultipleChoiceResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/TrueOrFalseResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/components/ShortAnswerResponse.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/interaction-response-item.scss","file:///app/packages/libs/shared/src/apps/analytics/components/questions-list/interaction-response-item/InteractionResponseItem.tsx","file:///app/packages/libs/shared/src/apps/analytics/flight-requests/InteractiveResultsRequests.ts","file:///app/packages/libs/shared/src/apps/analytics/hooks/UseFetchInteractiveResults.ts","file:///app/packages/libs/shared/src/apps/analytics/hooks/UseMarkAnswers.ts","file:///app/packages/libs/shared/src/apps/analytics/utils/InteractiveUtils.ts"],"sourcesContent":["import React from 'react';\n\nimport { SvgContainer } from 'libs/shared/components/svg-container/SvgContainer';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { StudentAnswer } from 'libs/shared/interfaces';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\ninterface AnswerContainerProps extends React.PropsWithChildren {\n answer: StudentAnswer;\n textClassName?: string;\n customAnswer?: boolean;\n}\n\nexport function AnswerContainer(props: AnswerContainerProps) {\n const { answer } = props;\n\n function getBgColour(status: InteractiveAnswerStatus) {\n switch (status) {\n case InteractiveAnswerStatus.Correct: return 'bg-light-green';\n case InteractiveAnswerStatus.Incorrect: return 'bg-light-red';\n case InteractiveAnswerStatus.PendingReview: return 'bg-light-blue';\n }\n }\n\n return (\n <div key={answer.id} className={`${getBgColour(answer.status)} rounded p-2 mb-2`}>\n <div className='d-flex align-items-center gap-2'>\n {answer.status === InteractiveAnswerStatus.Correct && <SvgContainer svgName={cvSvgLibrary.Check} className='svg-container flex-shrink-0 text-success' />}\n {answer.status === InteractiveAnswerStatus.Incorrect && <SvgContainer svgName={cvSvgLibrary.Close} className='svg-container flex-shrink-0 text-danger' />}\n {!props.customAnswer && <span className={props.textClassName}>{answer.text}</span>}\n </div>\n {props.children}\n </div>\n );\n}","import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\nconst namespace = 'shared.interactionResponses';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nexport function IllustrationResponse(props: ResponseItemComponentProps): JSX.Element {\n const answer = ArrayHelper.first(props.answers);\n\n if (!answer)\n return <></>;\n\n return (\n <AnswerContainer answer={answer} customAnswer>\n <div className='ratio ratio-16x9'>\n <img\n className='img-fluid bg-white border rounded h-100 w-100'\n src={answer.text}\n alt={`${getPhrase('illustrationAlt')}: ${props.interaction.name}`}\n />\n </div>\n {props.children}\n </AnswerContainer>\n );\n}","import React from 'react';\n\nimport { Interaction, InteractionTypeId, StudentAnswer, User } from 'libs/shared/interfaces';\n\nimport { IllustrationResponse } from './components/IllustrationResponse';\nimport { MissingWordResponse } from './components/MissingWordResponse';\nimport { MultipleChoiceResponse } from './components/MultipleChoiceResponse';\nimport { ShortAnswerResponse } from './components/ShortAnswerResponse';\nimport { TrueOrFalseResponse } from './components/TrueOrFalseResponse';\n\nexport interface ResponseItemComponentProps extends React.PropsWithChildren {\n interaction: Interaction;\n answers: StudentAnswer[];\n imageCdnUrl: string;\n user: User;\n showFeedback?: boolean;\n showAvatar?: boolean;\n anonymisedUserName?: string;\n}\nconst NoResponseRequired = () => <></>;\n\nexport const ResponseItemComponentLookup: {\n [typeId: number]: (props: ResponseItemComponentProps) => JSX.Element\n} = {\n [InteractionTypeId.Annotation]: NoResponseRequired,\n [InteractionTypeId.Image]: NoResponseRequired,\n [InteractionTypeId.MissingWord]: MissingWordResponse,\n [InteractionTypeId.MultipleChoice]: MultipleChoiceResponse,\n [InteractionTypeId.TrueOrFalse]: TrueOrFalseResponse,\n [InteractionTypeId.ShortAnswer]: ShortAnswerResponse,\n [InteractionTypeId.Illustration]: IllustrationResponse\n};","import React from 'react';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\n\nexport function MissingWordResponse(props: ResponseItemComponentProps) {\n if (!props.answers.length) return <></>;\n\n return (\n <ul className='list-unstyled'>\n {props.answers.map(answer => (\n <AnswerContainer\n key={answer.id}\n answer={answer}\n textClassName='bg-white p-1 border border-gray-300 rounded'\n />\n ))}\n </ul>\n );\n}","import React from 'react';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\nexport function MultipleChoiceResponse(props: ResponseItemComponentProps) {\n if (!props.answers.length) return <></>;\n\n return (\n <ul className='list-unstyled'>\n {props.answers.map(answer => (\n <li key={answer.id}>\n <AnswerContainer answer={answer} />\n </li>\n ))}\n </ul>\n );\n}","import React from 'react';\n\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\nexport function TrueOrFalseResponse(props: ResponseItemComponentProps) {\n const answer = ArrayHelper.first(props.answers);\n\n if (!answer)\n return <></>;\n\n return (\n <AnswerContainer answer={answer} />\n );\n}","import React from 'react';\n\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { AnswerContainer } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/components/AnswerContainer';\nimport { ResponseItemComponentProps } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\n\nexport function ShortAnswerResponse(props: ResponseItemComponentProps): JSX.Element {\n const answer = ArrayHelper.first(props.answers);\n\n if (!answer)\n return <></>;\n\n return (\n <AnswerContainer answer={answer}>\n {props.children}\n </AnswerContainer>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"avatarContainer\":\"O7oaA\"};","import React from 'react';\n\nimport { ResponseItemComponentLookup } from 'libs/shared/apps/analytics/components/questions-list/interaction-response-item/ResponseItemComponentLookup';\nimport { Avatar } from 'libs/shared/components/avatar/Avatar';\nimport { InteractionResponseCorrectness } from 'libs/shared/components/interaction-response/InteractionResponseCorrectness';\nimport { InteractionStudentDetailsHeader } from 'libs/shared/components/interaction-response/InteractionStudentDetailsHeader';\nimport { MarkResponse } from 'libs/shared/components/interaction-response/MarkResponse';\nimport { NoResponse } from 'libs/shared/components/interaction-response/response-types/NoResponse';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { Interaction, StudentAnswer, StudentResults } from 'libs/shared/interfaces';\nimport { InteractiveCorrectnessHelper } from 'libs/shared/utils/InteractiveCorrectnessHelper';\nimport { getStudentAttempt, getStudentResult } from 'libs/shared/utils/InteractiveHelper';\nimport { UserHelper } from 'libs/shared/utils/UserHelper';\n\nimport styles from './interaction-response-item.scss';\n\ninterface InteractionResponseProps {\n interaction: Interaction;\n studentResults: StudentResults;\n imageCdnUrl: string;\n markInteraction: (answers: StudentAnswer[], status: InteractiveAnswerStatus) => void;\n markedStatus?: InteractiveAnswerStatus;\n showStudentDetails?: boolean;\n className?: string;\n showFeedback?: boolean;\n showAvatar?: boolean;\n anonymisedUserName?: string;\n responseComponentClass?: string;\n}\n\nexport function InteractionResponseItem(props: InteractionResponseProps): JSX.Element {\n const ResponseItemComponent = ResponseItemComponentLookup[props.interaction.typeId];\n\n if (!ResponseItemComponent)\n return <></>;\n\n const result = getStudentResult(props.studentResults);\n\n const studentAttempt = getStudentAttempt(props.interaction.id, result);\n\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(props.interaction, result);\n\n return (\n <div className={`rounded ${props.className ?? ''}`}>\n <div className='d-flex'>\n {!!props.showStudentDetails &&\n <div className='me-2'>\n <div className={styles.avatarContainer}>\n <Avatar\n imageCdnUrl={props.imageCdnUrl}\n initials={props.anonymisedUserName\n ? UserHelper.getInitialsFromFullName(props.anonymisedUserName)\n : UserHelper.getInitials(props.studentResults.user?.name, props.studentResults.user?.surname)\n }\n imageUrl={props.anonymisedUserName ? null : props.studentResults.user?.avatar?.url}\n />\n </div>\n </div>\n }\n <div className='flex-grow-1'>\n {!!props.showStudentDetails &&\n <InteractionStudentDetailsHeader\n studentResults={props.studentResults}\n correctness={correctness}\n anonymisedUserName={props.anonymisedUserName}\n />\n }\n <div className='d-flex justify-content-between'>\n <div className={`flex-grow-1 mb-2 ${props.responseComponentClass ? props.responseComponentClass : ''}`}>\n {studentAttempt\n ? <ResponseItemComponent\n interaction={props.interaction}\n answers={studentAttempt.answers}\n imageCdnUrl={props.imageCdnUrl}\n user={props.studentResults.user}\n showFeedback={props.showFeedback}\n showAvatar={props.showAvatar}\n >\n <MarkResponse\n studentAttempt={studentAttempt}\n correctness={correctness}\n markInteraction={props.markInteraction}\n markedStatus={props.markedStatus}\n />\n </ResponseItemComponent>\n : <NoResponse />\n }\n </div>\n {!props.showStudentDetails &&\n <InteractionResponseCorrectness correctness={correctness} />\n }\n </div>\n </div>\n </div>\n </div>\n );\n}","import { HttpVerbs } from 'libs/common/backbone/enums/HttpVerbs';\nimport { Flight } from 'libs/common/react/index';\n\nimport { MarkInteractiveAnswer } from 'libs/shared/apps/analytics/interfaces/MarkInteractiveAnswer';\nimport { InteractiveResultsReport } from 'libs/shared/apps/analytics/interfaces/requests/InteractiveResultsReport';\nimport { InteractivesPendingReviewsRequest } from 'libs/shared/apps/analytics/interfaces/requests/InteractivesPendingReviewsRequest';\nimport { AnalyticsRequestFilter, CurrentUser, InteractiveResultSet } from 'libs/shared/interfaces';\nimport { getAnalyticsRequestKey } from 'libs/shared/utils/AnalyticsRequestUtils';\n\ninterface InteractiveResultFilters {\n currentUserId: string;\n currentCustomerId: string;\n dateRange?: { start: string, end: string }\n userIds?: string | string[];\n classroomsAndGroups?: string | string[];\n}\n\nfunction getInteractiveResultFilters(\n currentUser: CurrentUser,\n filter: AnalyticsRequestFilter\n): InteractiveResultFilters {\n return {\n currentUserId: currentUser.id,\n currentCustomerId: currentUser.customerId,\n dateRange: { start: filter.start, end: filter.end },\n userIds: filter.userId,\n classroomsAndGroups: filter.groupId\n };\n}\n\nexport const InteractiveResultsRequests = {\n /** \n * This endpoint returns data with a lot of duplicated ids,\n * e.g. student answers to the same question will have the same id.\n * Because of that, we don't normalize.\n */\n interactiveResultSet(\n interactiveId: string,\n interactiveMetadataId: string,\n currentUser: CurrentUser,\n filter: AnalyticsRequestFilter,\n success?: (data: InteractiveResultSet) => void,\n error?: (data: any) => void,\n always?: () => void\n ): Flight.Request {\n return {\n url: `/api/domain/v2/analytics/interactives/${interactiveId}/metadata/${interactiveMetadataId}`,\n key: getAnalyticsRequestKey(`interactive:result:set:${interactiveId}:${interactiveMetadataId}`, filter),\n data: getInteractiveResultFilters(currentUser, filter),\n type: HttpVerbs.POST,\n normalize: false,\n success,\n error,\n always\n };\n },\n \n /**\n * As the response from `interactiveResultSet` isn't normalised, we need to invalidate the cache\n * to update the results data.\n */\n mark(\n interactiveId: string,\n interactiveMetadataId: string,\n answerId: string,\n data: MarkInteractiveAnswer,\n success?: () => void,\n error?: (data: any) => void,\n always?: () => void\n ): Flight.Request {\n return {\n url: `/api/domain/v1/analytics/answers/${answerId}`,\n key: `mark:answer:${answerId}:${data.resultId}`,\n type: HttpVerbs.PUT,\n data,\n normalize: false,\n invalidationKeys: `interactive:result:set:${interactiveId}:${interactiveMetadataId}`,\n success,\n error,\n always\n };\n },\n\n pendingReviews(data: InteractivesPendingReviewsRequest): Flight.Request {\n return {\n url: `/api/domain/v1/analytics/interactives/pending-reviews/summary`,\n key: `interactives:pending:reviews`,\n type: HttpVerbs.POST,\n data\n };\n },\n\n interactiveResultsReport(data: InteractiveResultsReport): Flight.Request {\n return {\n url: '{gateway}/v2/analytics/interactives/report',\n key: 'interactive:results:report',\n data,\n type: HttpVerbs.POST,\n normalize: false\n };\n }\n};","import { Flight } from 'libs/common/flight';\n\nimport { InteractiveResultsRequests } from 'libs/shared/apps/analytics/flight-requests/InteractiveResultsRequests';\nimport { InteractiveRequests } from 'libs/shared/flight-requests/InteractiveRequests';\nimport { UserRequests } from 'libs/shared/flight-requests/UserRequests';\nimport { AnalyticsRequestFilter, CurrentUser, Interactive, InteractiveMetadata, InteractiveResultSet } from 'libs/shared/interfaces';\n\nexport function useFetchInteractiveResults(\n interactiveMetadataId: string,\n requestFilter: AnalyticsRequestFilter\n): Flight.Response<InteractiveResultSet> {\n const currentUser = Flight.useBasicFetch<CurrentUser>(UserRequests.currentUser());\n\n const interactiveMetadata = Flight.useBasicFetch<InteractiveMetadata>(!!interactiveMetadataId &&\n InteractiveRequests.interactiveMetadata(interactiveMetadataId));\n\n const interactive = Flight.useBasicFetch<Interactive>(!!interactiveMetadata.data?.interactiveId &&\n InteractiveRequests.interactive(interactiveMetadata.data.interactiveId));\n\n const shouldFetchResults = !!currentUser.data && !!interactive.data && (!!requestFilter);\n\n return Flight.useBasicFetch<InteractiveResultSet>(shouldFetchResults &&\n InteractiveResultsRequests.interactiveResultSet(\n interactiveMetadata.data.interactiveId,\n interactiveMetadata.data.id,\n currentUser.data,\n requestFilter\n ));\n}","import { useState } from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { Flight } from 'libs/common/flight';\n\nimport { InteractiveResultsRequests } from 'libs/shared/apps/analytics/flight-requests/InteractiveResultsRequests';\nimport { getMarkedAnswerId } from 'libs/shared/apps/analytics/utils/InteractiveUtils';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { useAlerts } from 'libs/shared/hooks/UseAlerts';\nimport { StudentAnswer } from 'libs/shared/interfaces';\n\nconst getPhrase = LanguageService.encloseNamespace('reportsShared.dataHooks');\n\nexport type MarkedAnswerHash = { [id: string]: StudentAnswer };\n\n/**\n * This hook manages the storing of a marked answer hash in state and then the submitting\n * of those answers via an api call.\n */\nexport const useMarkAnswers = (interactiveId: string, interactiveMetadataId: string, onDone?: () => void) => {\n const [ markedAnswers, setMarkedAnswers ] = useState<MarkedAnswerHash>({});\n\n const dispatch = useDispatch();\n const alerts = useAlerts();\n\n function addMarkedAnswers(answers: StudentAnswer[], status: InteractiveAnswerStatus): void {\n answers.forEach(a => {\n setMarkedAnswers(m => ({ ...m, [getMarkedAnswerId(a)]: { ...a, status } }));\n });\n }\n\n function submitMarkedAnswers(): void {\n const answers = Object.keys(markedAnswers).map(key => markedAnswers[key]);\n\n if (!answers.length)\n return;\n\n let completeCount = 0;\n let successCount = 0;\n\n function onSuccess(): void {\n successCount++;\n }\n\n function onAlways(): void {\n completeCount++;\n\n if (completeCount === answers.length)\n onComplete();\n }\n\n function onComplete(): void {\n let alertMessage = '';\n let useErrorAlert = false;\n\n if (successCount === 0) {\n alertMessage = getPhrase('error', { smartCount: answers.length });\n useErrorAlert = true;\n }\n\n if (successCount < completeCount) {\n alertMessage = getPhrase('success', { smartCount: successCount })\n + ` ${getPhrase('partialError', { smartCount: completeCount - successCount })}`;\n }\n\n if (successCount === completeCount) {\n alertMessage = getPhrase('success', { smartCount: successCount });\n }\n\n useErrorAlert\n ? alerts.error(alertMessage)\n : alerts.success(alertMessage);\n\n setMarkedAnswers({});\n\n onDone && onDone();\n }\n\n answers.forEach(({ id, resultId, questionId, status }) => {\n Flight.fetch(dispatch, InteractiveResultsRequests.mark(\n interactiveId,\n interactiveMetadataId,\n id,\n { id, resultId, questionId, status },\n onSuccess,\n null,\n onAlways\n ));\n });\n }\n\n return {\n markedAnswers,\n addMarkedAnswers,\n submitMarkedAnswers\n };\n};","import { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { MarkedAnswerHash } from 'libs/shared/apps/analytics/hooks/UseMarkAnswers';\nimport { ResultsSummary } from 'libs/shared/apps/analytics/interfaces/ResultsSummary';\nimport { StudentResultsWithSummary } from 'libs/shared/apps/analytics/interfaces/StudentResultsWithSummary';\nimport { ScoreThresholdDefaults, ScoreThresholds } from 'libs/shared/constants/ScoreThresholds';\nimport { InteractionCorrectness } from 'libs/shared/enums/InteractionCorrectness';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { Interaction, StudentAnswer, StudentResults } from 'libs/shared/interfaces';\nimport { Interactive, InteractiveResultSet } from 'libs/shared/interfaces';\nimport { InteractiveCorrectnessHelper } from 'libs/shared/utils/InteractiveCorrectnessHelper';\nimport { flattenInteractions, getInteractions, getStudentAttempt, getStudentResult } from 'libs/shared/utils/InteractiveHelper';\n\ninterface StudentGroups {\n markingRequired: StudentResultsWithSummary[];\n lowScore: StudentResultsWithSummary[];\n highScore: StudentResultsWithSummary[];\n completed: StudentResultsWithSummary[];\n notCompleted: StudentResultsWithSummary[];\n}\n\nexport function groupStudents(\n interactive: Interactive,\n results: InteractiveResultSet,\n scoreThreshold?: ScoreThresholds\n): StudentGroups {\n const groups: StudentGroups = {\n markingRequired: [],\n lowScore: [],\n highScore: [],\n completed: [],\n notCompleted: []\n };\n\n const interactions = getInteractions(interactive);\n\n const numInteractions = interactions.length;\n \n results.students.forEach(s => {\n const withSummary = {\n ...s,\n summary: getStudentResultsSummary(interactive, s)\n };\n \n if (withSummary.summary.awaitingMarking) {\n groups.markingRequired.push(withSummary);\n return;\n }\n\n if (ArrayHelper.last(s.results).attempts.length === numInteractions) {\n groups.completed.push(withSummary);\n } else {\n groups.notCompleted.push(withSummary);\n return;\n }\n \n if (withSummary.summary.percentCorrect >= (scoreThreshold.HIGH || ScoreThresholdDefaults.HIGH))\n groups.highScore.push(withSummary);\n \n if (withSummary.summary.percentCorrect < (scoreThreshold.MODERATE || ScoreThresholdDefaults.MODERATE))\n groups.lowScore.push(withSummary);\n });\n \n const sortedLowScore = ArrayHelper.sortBy(groups.lowScore, s => s.summary.percentCorrect);\n const sortedHighScore = ArrayHelper.sortBy(groups.highScore, s => -s.summary.percentCorrect);\n \n return {\n ...groups,\n lowScore: sortedLowScore,\n highScore: sortedHighScore\n };\n}\n\nexport function getInteractionById(interactive: Interactive, interactionId: string): Interaction {\n const flattenedInteractions = flattenInteractions(interactive);\n return flattenedInteractions.find(i => i.id.toString() === interactionId.toString());\n}\n\n/**\n * We need to use the question and result ids as a list of one student's responses\n * to multiple questions will all have the same result id and a list of multiple\n * students responses to one question will all have the same questionId.\n */\nexport function getMarkedAnswerId(answer: StudentAnswer): string {\n return `${answer.questionId}:${answer.resultId}`;\n}\n\nexport function getMarkedStatus(\n interactionId: string,\n studentResults: StudentResults,\n markedAnswers: MarkedAnswerHash\n): InteractiveAnswerStatus {\n const result = getStudentResult(studentResults);\n const studentResponse = getStudentAttempt(interactionId, result);\n\n const isMarkedCorrect = studentResponse?.answers.every(a => {\n return markedAnswers[getMarkedAnswerId(a)]?.status === InteractiveAnswerStatus.Correct;\n });\n\n if (isMarkedCorrect)\n return InteractiveAnswerStatus.Correct;\n\n const isMarkedIncorrect = studentResponse?.answers.every(a => {\n return markedAnswers[getMarkedAnswerId(a)]?.status === InteractiveAnswerStatus.Incorrect;\n });\n\n if (isMarkedIncorrect)\n return InteractiveAnswerStatus.Incorrect;\n}\n\nexport function getInteractionResultsSummary(\n interaction: Interaction,\n results: InteractiveResultSet\n): ResultsSummary {\n const numStudents = results.students.length;\n let numCorrect = 0;\n let answered = 0;\n let unanswered = 0;\n let awaitingMarking = 0;\n let attempts = 0;\n\n results.students.forEach(s => {\n const result = getStudentResult(s);\n\n if (!result)\n return;\n\n attempts = attempts + s.results.length;\n\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(interaction, result);\n\n if (correctness === InteractionCorrectness.Correct)\n numCorrect++;\n\n if (correctness === InteractionCorrectness.UnAnswered)\n unanswered++;\n\n if (correctness === InteractionCorrectness.AwaitingMarking)\n awaitingMarking++;\n\n if (correctness !== InteractionCorrectness.UnAnswered)\n answered++;\n });\n\n\n const percentCorrect = numStudents > 0\n ? numCorrect / numStudents\n : 0;\n\n return {\n percentCorrect,\n correct: numCorrect,\n answered,\n unanswered,\n awaitingMarking,\n attempts\n };\n}\n\nexport function getStudentResultsSummary(interactive: Interactive, studentResults: StudentResults): ResultsSummary {\n const result = getStudentResult(studentResults);\n\n const interactions = getInteractions(interactive);\n\n const numInteractions = interactions.length;\n\n let numCorrect = 0;\n let awaitingMarking = 0;\n\n interactions.forEach(i => {\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(i, result);\n\n if (correctness === InteractionCorrectness.Correct)\n numCorrect++;\n\n if (correctness === InteractionCorrectness.AwaitingMarking)\n awaitingMarking++;\n });\n\n const percentCorrect = numInteractions > 0 ? numCorrect / numInteractions : 0;\n\n /**\n * Our interactions list has images and annotations filtered out.\n * We built a map of valid questions, so that we can calculate the unswered accurately.\n * We're doing this because of a bug that caused annotations and images to record answers in the player.\n * - Sha\n */\n const interactionIds = new Set(interactions.map(i => i.id));\n const answeredInteractions = result.attempts.filter(a => !!interactionIds.has(a?.answers[0]?.questionId)).length;\n\n return {\n answered: result.attempts.length,\n attempts: studentResults.results.length,\n unanswered: numInteractions - answeredInteractions,\n percentCorrect,\n correct: numCorrect,\n awaitingMarking\n };\n}"],"names":["AnswerContainer","props","answer","key","id","className","status","InteractiveAnswerStatus","getBgColour","SvgContainer","svgName","customAnswer","textClassName","text","children","getPhrase","LanguageService","NoResponseRequired","ResponseItemComponentLookup","answers","length","map","ArrayHelper","src","alt","interaction","name","InteractionResponseItem","ResponseItemComponent","typeId","result","studentResults","studentAttempt","correctness","InteractiveCorrectnessHelper","showStudentDetails","Avatar","imageCdnUrl","initials","anonymisedUserName","UserHelper","user","surname","imageUrl","avatar","url","InteractionStudentDetailsHeader","responseComponentClass","showFeedback","showAvatar","MarkResponse","markInteraction","markedStatus","NoResponse","InteractionResponseCorrectness","getInteractiveResultFilters","currentUser","filter","currentUserId","currentCustomerId","customerId","dateRange","start","end","userIds","userId","classroomsAndGroups","groupId","InteractiveResultsRequests","interactiveResultSet","interactiveId","interactiveMetadataId","success","error","always","data","type","normalize","mark","answerId","resultId","invalidationKeys","pendingReviews","interactiveResultsReport","useFetchInteractiveResults","requestFilter","interactiveMetadata","interactive","shouldFetchResults","I","useMarkAnswers","onDone","useState","markedAnswers","setMarkedAnswers","dispatch","alerts","addMarkedAnswers","forEach","a","m","submitMarkedAnswers","Object","keys","completeCount","successCount","questionId","onSuccess","onAlways","alertMessage","useErrorAlert","smartCount","groupStudents","results","scoreThreshold","groups","markingRequired","lowScore","highScore","completed","notCompleted","numInteractions","students","s","withSummary","summary","getStudentResultsSummary","awaitingMarking","push","attempts","percentCorrect","HIGH","MODERATE","sortedLowScore","sortedHighScore","getInteractionById","interactionId","find","i","toString","getMarkedAnswerId","getMarkedStatus","studentResponse","every","getInteractionResultsSummary","numStudents","numCorrect","answered","unanswered","correct","interactions","interactionIds","Set","answeredInteractions","has"],"sourceRoot":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"scripts/8095-afb976fac0-lite.chunk.js","mappings":"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","sources":["file:///app/packages/libs/shared/src/apps/analytics/components/pending-indicator/PendingIndicator.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/student-results/interactions-bar/interactions-bar.scss","file:///app/packages/libs/shared/src/apps/analytics/components/student-results/interactions-bar/InteractionsBar.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/student-results/interaction-results-summary/InteractionResultsSummary.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/student-results/interaction-results-summary/interaction-results-summary.scss","file:///app/packages/libs/shared/src/apps/analytics/components/student-results/student-results-table/InteractionHeaderCell.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/student-results/student-results-table/StudentResultCell.tsx","file:///app/packages/libs/shared/src/apps/analytics/components/student-results/student-results-table/StudentResultsTableUtils.tsx","file:///app/packages/libs/shared/src/apps/analytics/flight-requests/InteractiveResultsRequests.ts","file:///app/packages/libs/shared/src/apps/analytics/hooks/UseFetchInteractiveResults.ts","file:///app/packages/libs/shared/src/apps/analytics/utils/InteractiveUtils.ts","file:///app/packages/libs/shared/src/enums/InteractionCorrectness.ts","file:///app/packages/libs/shared/src/enums/InteractiveAnswerStatus.ts","file:///app/packages/libs/shared/src/utils/InteractiveCorrectnessHelper.ts","file:///app/packages/libs/shared/src/utils/InteractiveHelper.ts","file:///app/packages/libs/shared/src/apps/analytics/components/student-results/student-results-table/student-results-table.scss"],"sourcesContent":["import React from 'react';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { PercentageIndicator } from 'libs/shared/components/percentage-indicator/PercentageIndicator';\nimport { Tooltip } from 'libs/shared/components/tooltip/Tooltip';\n\nconst namespace = 'interactives.pendingIndicator';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nfunction getClassName(props: PendingIndicatorProps): string {\n let className = 'd-flex align-items-center h-100';\n\n className += props.showLabel ? ' justify-content-between' : ' justify-content-center';\n\n if (props.className)\n className += ` ${props.className}`;\n\n return className;\n}\n\ninterface PendingIndicatorProps {\n title?: string;\n className?: string;\n showLabel?: boolean;\n tooltipClassName?: string;\n}\n\nexport function PendingIndicator(props: PendingIndicatorProps): JSX.Element {\n const Indicator = () => (\n <div className={getClassName(props)}>\n {!!props.showLabel &&\n <em>{getPhrase('pending')}</em>\n }\n <PercentageIndicator />\n </div>\n );\n\n if (!props.title)\n return <Indicator />;\n\n return (\n <Tooltip title={props.title} spanHack spanHackClassName={props.tooltipClassName || 'h-100 w-100 d-flex align-items-center'}>\n <Indicator />\n </Tooltip>\n );\n}","// extracted by mini-css-extract-plugin\nexport default {\"container\":\"Wf1bl\",\"interaction\":\"Fpm49\"};","import React from 'react';\n\nimport { Interaction, Interactive, Timepoint } from 'libs/shared/interfaces';\nimport { DurationHelper } from 'libs/shared/utils/DurationHelper';\nimport { InteractionTypeHelper } from 'libs/shared/utils/interaction-type-helper/InteractionTypeHelper';\n\nimport styles from './interactions-bar.scss';\n\nfunction getInteraction(timepoint: Timepoint, selectedInteraction: Interaction): Interaction {\n return timepoint.interactions.find(i => i.id === selectedInteraction.id) || timepoint.interactions[0];\n}\n\ninterface InteractionBarProps {\n interactive: Interactive;\n duration: number;\n selectedInteraction: Interaction;\n}\n\nexport function InteractionsBar(props: InteractionBarProps): React.ReactElement {\n if (!props.duration)\n return <></>;\n\n return (\n <>\n {props.interactive.timepoints.map((t, i) => {\n if (!t.interactions.length)\n return <></>;\n\n const interaction = getInteraction(t, props.selectedInteraction);\n const isSelected = interaction.id === props.selectedInteraction.id;\n\n const bgClassName = isSelected ? (InteractionTypeHelper.getTypeInfo(interaction.typeId)).bgClassName : 'bg-gray-500';\n\n const left = ((t.visibleAt / 1000) / props.duration) * 100;\n\n return (\n <div\n key={i}\n className={`${styles.container} text-center`}\n style={{ left: `${left}%` }}\n >\n <div className={`${styles.interaction} ${bgClassName}`} />\n {!!isSelected &&\n <div>\n {DurationHelper.ToDisplayDuration(t.visibleAt)}\n </div>\n }\n </div>\n );\n })}\n </>\n );\n}","import React from 'react';\nimport { Popover } from 'react-bootstrap';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\n\nimport { InteractionsBar } from 'libs/shared/apps/analytics/components/student-results/interactions-bar/InteractionsBar';\nimport { getInteractionResultsSummary } from 'libs/shared/apps/analytics/utils/InteractiveUtils';\nimport { InteractionLabel } from 'libs/shared/components/interactive-questions/InteractionLabel';\nimport { PercentageIndicator, PercentageIndicatorLayout } from 'libs/shared/components/percentage-indicator/PercentageIndicator';\nimport { Interaction, Interactive, InteractiveMetadata, InteractiveResultSet } from 'libs/shared/interfaces';\n\nimport styles from './interaction-results-summary.scss';\n\nconst namespace = 'shared.interactionResultsSummary';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nfunction getDuration(interactiveMetadata: InteractiveMetadata): number {\n if (interactiveMetadata._parentClip)\n return interactiveMetadata._parentClip.endTime - interactiveMetadata._parentClip.startTime;\n\n if (!interactiveMetadata._parentVideo.duration)\n return 0;\n\n return interactiveMetadata._parentVideo.duration / 1000;\n}\n\ninterface InteractionResultsSummaryProps {\n interaction: Interaction;\n interactive: Interactive;\n interactiveMetadata: InteractiveMetadata;\n results: InteractiveResultSet;\n}\n\nfunction InteractionResultsSummary(props: InteractionResultsSummaryProps): JSX.Element {\n const summary = React.useMemo(\n () => getInteractionResultsSummary(props.interaction, props.results),\n [ props.interaction, props.results ]\n );\n\n return (\n <div className='px-1 pt-1'>\n <div className='d-flex'>\n <InteractionLabel\n interaction={props.interaction}\n iconClassName='flex-shrink-0'\n />\n </div>\n <div className={`my-4 ${styles.bar}`}>\n <InteractionsBar\n interactive={props.interactive}\n duration={getDuration(props.interactiveMetadata)}\n selectedInteraction={props.interaction}\n />\n </div>\n <div className='row pt-1 pb-2'>\n <div className='col-6 pe-1'>\n <div className='bg-light rounded p-2 h-100'>\n {!summary.awaitingMarking &&\n <div className='d-flex align-items-center justify-content-between'>\n <strong>{getPhrase('correctlyAnswered')}</strong>\n <PercentageIndicator\n percentage={summary.percentCorrect}\n layout={PercentageIndicatorLayout.LabelOnly}\n />\n </div>\n }\n {!!summary.awaitingMarking &&\n <div className='d-flex align-items-center justify-content-center'>\n <strong>\n <em>{getPhrase('pending')}</em>\n </strong>\n </div>\n }\n </div>\n </div>\n <div className='col-6 ps-1'>\n <div className='bg-light rounded h-100 p-2 d-flex align-items-center justify-content-between'>\n <strong>{getPhrase('unanswered')}</strong>\n <span>{summary.unanswered}</span>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nconst InteractionResultsSummaryPopover = React.forwardRef((\n { interaction, interactive, interactiveMetadata, results, ...popoverProps }: InteractionResultsSummaryProps,\n ref: React.MutableRefObject<HTMLElement>\n) => {\n return (\n <div className='popover-lg'>\n <Popover\n id={`interaction-results-summary-${interaction.id}`}\n ref={ref as any}\n {...popoverProps}\n >\n <Popover.Body>\n <InteractionResultsSummary\n interaction={interaction}\n interactive={interactive}\n interactiveMetadata={interactiveMetadata}\n results={results}\n />\n </Popover.Body>\n </Popover>\n </div>\n );\n});\n\nexport { InteractionResultsSummaryPopover as InteractionResultsSummary };","// extracted by mini-css-extract-plugin\nexport default {\"bar\":\"FCXQd\"};","import React from 'react';\nimport { OverlayTrigger } from 'react-bootstrap';\n\nimport { InteractionResultsSummary } from 'libs/shared/apps/analytics/components/student-results/interaction-results-summary/InteractionResultsSummary';\nimport { Interaction, Interactive, InteractiveMetadata, InteractiveResultSet } from 'libs/shared/interfaces';\n\nimport styles from './student-results-table.scss';\n\ninterface InteractionHeaderCellProps {\n interaction: Interaction;\n results: InteractiveResultSet;\n interactionNumber: number;\n interactive: Interactive;\n interactiveMetadata: InteractiveMetadata;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n}\n\nexport function InteractionHeaderCell(props: InteractionHeaderCellProps): JSX.Element {\n return (\n <OverlayTrigger\n trigger={props.results.students?.length ? 'click' : null}\n placement='bottom'\n overlay={\n <InteractionResultsSummary\n interaction={props.interaction}\n interactive={props.interactive}\n interactiveMetadata={props.interactiveMetadata}\n results={props.results}\n />\n }\n rootClose\n >\n <div\n className={\n `text-center h-100\n d-flex align-items-center justify-content-center\n ${styles.interactionHeaderCellInner}`\n }\n onMouseEnter={props.onMouseEnter}\n onMouseLeave={props.onMouseLeave}\n >\n <div className='p-1 position-relative'>\n {props.interactionNumber}\n </div>\n </div>\n </OverlayTrigger>\n );\n}","import React from 'react';\n\nimport { PendingIndicator } from 'libs/shared/apps/analytics/components/pending-indicator/PendingIndicator';\nimport { SvgContainer } from 'libs/shared/components/svg-container/SvgContainer';\nimport { InteractionCorrectness } from 'libs/shared/enums/InteractionCorrectness';\nimport { Interaction, StudentResults } from 'libs/shared/interfaces';\nimport { InteractiveCorrectnessHelper } from 'libs/shared/utils/InteractiveCorrectnessHelper';\nimport { getStudentResult } from 'libs/shared/utils/InteractiveHelper';\nimport { cvSvgLibrary } from 'libs/shared/utils/SvgHelper';\n\nimport styles from './student-results-table.scss';\n\nfunction getSvgName(correctness: InteractionCorrectness): string {\n if (correctness === InteractionCorrectness.Correct)\n return cvSvgLibrary.Check;\n\n if (correctness === InteractionCorrectness.Incorrect)\n return cvSvgLibrary.Close;\n\n if (correctness === InteractionCorrectness.UnAnswered)\n return cvSvgLibrary.Minus;\n\n return;\n}\n\nfunction getClassName(correctness: InteractionCorrectness): string {\n let className = `${styles.resultsCellInner} h-100 position-relative`;\n\n if (correctness === InteractionCorrectness.Correct)\n className += ` ${styles.correct}`;\n\n if (correctness === InteractionCorrectness.Incorrect)\n className += ` ${styles.incorrect} text-danger`;\n\n if (correctness === InteractionCorrectness.AwaitingMarking)\n className += ` ${styles.awaitingMarking}`;\n\n if (correctness === InteractionCorrectness.UnAnswered)\n className += ` ${styles.unanswered} text-warning`;\n\n return className;\n}\n\ninterface StudentResultCellProps {\n interaction: Interaction;\n studentResults: StudentResults;\n}\n\nexport function StudentResultCell(props: StudentResultCellProps): JSX.Element {\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(\n props.interaction,\n getStudentResult(props.studentResults)\n );\n\n const svgName = getSvgName(correctness);\n\n return (\n <div className={getClassName(correctness)}>\n {!!svgName && <SvgContainer svgName={svgName} />}\n {correctness === InteractionCorrectness.AwaitingMarking &&\n <PendingIndicator />\n }\n </div>\n );\n}","import React from 'react';\nimport { CellProps, Column, ColumnInstance, SortingRule } from 'react-table';\n\nimport { LanguageService } from 'libs/common/backbone/services/LanguageService';\nimport { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { PendingIndicator } from 'libs/shared/apps/analytics/components/pending-indicator/PendingIndicator';\nimport { StudentResultsWithSummary } from 'libs/shared/apps/analytics/interfaces/StudentResultsWithSummary';\nimport { anonymiseUserName } from 'libs/shared/apps/analytics/utils/AnonymiseUserUtils';\nimport { getStudentResultsSummary } from 'libs/shared/apps/analytics/utils/InteractiveUtils';\nimport { PercentageIndicator, PercentageIndicatorLayout } from 'libs/shared/components/percentage-indicator/PercentageIndicator';\nimport { Interactive, InteractiveMetadata, InteractiveResultSet } from 'libs/shared/interfaces';\nimport { getInteractions } from 'libs/shared/utils/InteractiveHelper';\n\nimport { InteractionHeaderCell } from './InteractionHeaderCell';\nimport { StudentResultCell } from './StudentResultCell';\n\nimport styles from './student-results-table.scss';\n\nconst namespace = 'shared.studentResultsTable';\nconst getPhrase = LanguageService.encloseNamespace(namespace);\n\nexport const RESULTS_COL_WIDTH = 60;\n\ninterface CellWrapperProps {\n className?: string;\n}\n\nfunction CellWrapper(props: React.PropsWithChildren<CellWrapperProps>): JSX.Element {\n return (\n <div className={`d-flex align-items-center p-2 h-100 ${props.className ?? ''}`}>\n {props.children}\n </div>\n );\n}\n\ninterface HeaderCellProps {\n column: ColumnInstance<StudentResultsWithSummary>;\n phraseKey: string;\n}\n\nfunction HeaderCell(props: HeaderCellProps): JSX.Element {\n return (\n <CellWrapper className={props.column.isSorted && 'fw-bold'}>\n {getPhrase(props.phraseKey)}\n </CellWrapper>\n );\n}\n\nexport function useGetFixedColumns(\n results: InteractiveResultSet,\n anonymiseUsers: boolean\n): Column<StudentResultsWithSummary>[] {\n const hasResults = !!results.students?.length;\n\n return React.useMemo(() => {\n const cols: Column<StudentResultsWithSummary>[] = [\n {\n Header: ({ column }) => <HeaderCell column={column} phraseKey='name' />,\n accessor: 'user',\n Cell: ({ value }) => (\n <CellWrapper>\n <span className='text-truncate'>{anonymiseUserName(value, anonymiseUsers)}</span>\n </CellWrapper>\n ),\n disableSortBy: !hasResults\n },\n {\n Header: ({ column }) => <HeaderCell column={column} phraseKey='unanswered' />,\n accessor: 'summary.unanswered' as keyof StudentResultsWithSummary,\n sortType: 'basic', // Default is 'alphanumeric' which would treat the numbers as strings\n sortDescFirst: true,\n disableSortBy: !hasResults,\n Cell: ({ value }: CellProps<StudentResultsWithSummary, any>) => <CellWrapper>{value}</CellWrapper>\n },\n {\n Header: ({ column }) => <HeaderCell column={column} phraseKey='score' />,\n accessor: 'summary',\n id: 'score',\n Cell: ({ value }) => {\n if (value.awaitingMarking) {\n return (\n <CellWrapper>\n <PendingIndicator\n title={getPhrase('markingRequired')}\n className='flex-grow-1'\n showLabel\n />\n </CellWrapper>\n );\n }\n\n return (\n <CellWrapper>\n {`${value.correct}/${value.answered + value.unanswered}`}\n </CellWrapper>\n );\n },\n width: 125,\n sortDescFirst: true,\n disableSortBy: !hasResults\n },\n {\n Header: ({ column }) => <HeaderCell column={column} phraseKey='percentage' />,\n accessor: 'summary',\n id: 'percentage',\n Cell: ({ value }) => {\n if (value.awaitingMarking) {\n return (\n <CellWrapper>\n <PendingIndicator\n title={getPhrase('markingRequired')}\n className='flex-grow-1'\n showLabel\n />\n </CellWrapper>\n );\n }\n\n return (\n <CellWrapper>\n <PercentageIndicator\n percentage={value.percentCorrect}\n layout={PercentageIndicatorLayout.LabelBefore}\n className='flex-grow-1'\n />\n </CellWrapper>\n );\n },\n width: 125,\n sortDescFirst: true,\n disableSortBy: !hasResults\n }\n ];\n\n return cols;\n }, [ anonymiseUsers, hasResults ]);\n}\n\n/**\n * Returns memoized table columns. To trigger a recalculation, toggle the value of `refreshData`.\n */\nexport function useGetResultColumns(\n interactive: Interactive,\n interactiveMetadata: InteractiveMetadata,\n results: InteractiveResultSet,\n onColumnHover: (index?: number) => void,\n refreshData: boolean\n): Column<StudentResultsWithSummary>[] {\n return React.useMemo(() => {\n const interactions = getInteractions(interactive);\n\n return interactions.map((interaction, index) => {\n const col: Column<StudentResultsWithSummary> = {\n Header: () => {\n return (\n <InteractionHeaderCell\n interaction={interaction}\n results={results}\n interactive={interactive}\n interactiveMetadata={interactiveMetadata}\n interactionNumber={index + 1}\n onMouseEnter={() => onColumnHover(index)}\n onMouseLeave={() => onColumnHover(null)}\n />\n );\n },\n accessor: 'results',\n /**\n * `onSelectStudentResponse` in `StudentResultsTable` expects the column id to the interaction id\n */\n id: interaction.id,\n disableSortBy: true,\n width: RESULTS_COL_WIDTH,\n Cell: ({ row: { original: studentResults } }) => (\n <StudentResultCell interaction={interaction} studentResults={studentResults} />\n )\n };\n return col;\n });\n }, [refreshData]);\n}\n\n/**\n * Returns memoized table data. To trigger a recalculation, toggle the value of `refreshData`.\n */\nexport function useGetResultsTableData(\n interactive: Interactive,\n results: InteractiveResultSet,\n refreshData: boolean,\n anonymiseUsers: boolean,\n sortBy?: SortingRule<StudentResultsWithSummary>\n): StudentResultsWithSummary[] {\n return React.useMemo(() => {\n const students: StudentResultsWithSummary[] = [];\n\n results.students.forEach(s => {\n students.push(({ ...s, summary: getStudentResultsSummary(interactive, s) }));\n });\n\n if (sortBy?.id === 'user') {\n const sorted = ArrayHelper.sortBy(students, student => anonymiseUserName(student.user, anonymiseUsers));\n\n return sortBy.desc ? sorted.reverse() : sorted;\n }\n\n if (sortBy?.id === 'summary.unanswered') {\n const sorted = ArrayHelper.sortBy(students, student => student.summary.unanswered);\n\n return sortBy.desc ? sorted.reverse() : sorted;\n }\n\n if (sortBy?.id === 'score' || sortBy?.id === 'percentage') {\n const sorted = ArrayHelper.sortBy(students, student => {\n if (student.summary.awaitingMarking)\n return -1;\n\n return student.summary.percentCorrect;\n });\n\n return sortBy.desc ? sorted.reverse() : sorted;\n }\n\n return students;\n }, [ refreshData, sortBy, anonymiseUsers ]);\n}\n\nexport function highlightColumns(tableEl: HTMLElement, highlightIndex?: number): void {\n if (!tableEl)\n return;\n\n const rows = tableEl.querySelectorAll(`.${styles.resultsRow}`);\n\n rows?.forEach(row => {\n row.childNodes.forEach((col: HTMLElement, colIdx: number) => {\n col.classList.remove(styles.highlightColumn);\n\n if (colIdx === highlightIndex)\n col.classList.add(styles.highlightColumn);\n });\n });\n}\n\nexport function highlightRows(tableEl: HTMLElement, highlightIndex?: number): void {\n if (!tableEl)\n return;\n\n const rows = tableEl.querySelectorAll(`.${styles.resultsRow}`);\n\n rows?.forEach((row, rowIdx) => {\n row.classList.remove(styles.highlightResultsRow);\n\n if (rowIdx === highlightIndex)\n row.classList.add(styles.highlightResultsRow);\n });\n}","import { HttpVerbs } from 'libs/common/backbone/enums/HttpVerbs';\nimport { Flight } from 'libs/common/react/index';\n\nimport { MarkInteractiveAnswer } from 'libs/shared/apps/analytics/interfaces/MarkInteractiveAnswer';\nimport { InteractiveResultsReport } from 'libs/shared/apps/analytics/interfaces/requests/InteractiveResultsReport';\nimport { InteractivesPendingReviewsRequest } from 'libs/shared/apps/analytics/interfaces/requests/InteractivesPendingReviewsRequest';\nimport { AnalyticsRequestFilter, CurrentUser, InteractiveResultSet } from 'libs/shared/interfaces';\nimport { getAnalyticsRequestKey } from 'libs/shared/utils/AnalyticsRequestUtils';\n\ninterface InteractiveResultFilters {\n currentUserId: string;\n currentCustomerId: string;\n dateRange?: { start: string, end: string }\n userIds?: string | string[];\n classroomsAndGroups?: string | string[];\n}\n\nfunction getInteractiveResultFilters(\n currentUser: CurrentUser,\n filter: AnalyticsRequestFilter\n): InteractiveResultFilters {\n return {\n currentUserId: currentUser.id,\n currentCustomerId: currentUser.customerId,\n dateRange: { start: filter.start, end: filter.end },\n userIds: filter.userId,\n classroomsAndGroups: filter.groupId\n };\n}\n\nexport const InteractiveResultsRequests = {\n /** \n * This endpoint returns data with a lot of duplicated ids,\n * e.g. student answers to the same question will have the same id.\n * Because of that, we don't normalize.\n */\n interactiveResultSet(\n interactiveId: string,\n interactiveMetadataId: string,\n currentUser: CurrentUser,\n filter: AnalyticsRequestFilter,\n success?: (data: InteractiveResultSet) => void,\n error?: (data: any) => void,\n always?: () => void\n ): Flight.Request {\n return {\n url: `/api/domain/v2/analytics/interactives/${interactiveId}/metadata/${interactiveMetadataId}`,\n key: getAnalyticsRequestKey(`interactive:result:set:${interactiveId}:${interactiveMetadataId}`, filter),\n data: getInteractiveResultFilters(currentUser, filter),\n type: HttpVerbs.POST,\n normalize: false,\n success,\n error,\n always\n };\n },\n \n /**\n * As the response from `interactiveResultSet` isn't normalised, we need to invalidate the cache\n * to update the results data.\n */\n mark(\n interactiveId: string,\n interactiveMetadataId: string,\n answerId: string,\n data: MarkInteractiveAnswer,\n success?: () => void,\n error?: (data: any) => void,\n always?: () => void\n ): Flight.Request {\n return {\n url: `/api/domain/v1/analytics/answers/${answerId}`,\n key: `mark:answer:${answerId}:${data.resultId}`,\n type: HttpVerbs.PUT,\n data,\n normalize: false,\n invalidationKeys: `interactive:result:set:${interactiveId}:${interactiveMetadataId}`,\n success,\n error,\n always\n };\n },\n\n pendingReviews(data: InteractivesPendingReviewsRequest): Flight.Request {\n return {\n url: `/api/domain/v1/analytics/interactives/pending-reviews/summary`,\n key: `interactives:pending:reviews`,\n type: HttpVerbs.POST,\n data\n };\n },\n\n interactiveResultsReport(data: InteractiveResultsReport): Flight.Request {\n return {\n url: '{gateway}/v2/analytics/interactives/report',\n key: 'interactive:results:report',\n data,\n type: HttpVerbs.POST,\n normalize: false\n };\n }\n};","import { Flight } from 'libs/common/flight';\n\nimport { InteractiveResultsRequests } from 'libs/shared/apps/analytics/flight-requests/InteractiveResultsRequests';\nimport { InteractiveRequests } from 'libs/shared/flight-requests/InteractiveRequests';\nimport { UserRequests } from 'libs/shared/flight-requests/UserRequests';\nimport { AnalyticsRequestFilter, CurrentUser, Interactive, InteractiveMetadata, InteractiveResultSet } from 'libs/shared/interfaces';\n\nexport function useFetchInteractiveResults(\n interactiveMetadataId: string,\n requestFilter: AnalyticsRequestFilter\n): Flight.Response<InteractiveResultSet> {\n const currentUser = Flight.useBasicFetch<CurrentUser>(UserRequests.currentUser());\n\n const interactiveMetadata = Flight.useBasicFetch<InteractiveMetadata>(!!interactiveMetadataId &&\n InteractiveRequests.interactiveMetadata(interactiveMetadataId));\n\n const interactive = Flight.useBasicFetch<Interactive>(!!interactiveMetadata.data?.interactiveId &&\n InteractiveRequests.interactive(interactiveMetadata.data.interactiveId));\n\n const shouldFetchResults = !!currentUser.data && !!interactive.data && (!!requestFilter);\n\n return Flight.useBasicFetch<InteractiveResultSet>(shouldFetchResults &&\n InteractiveResultsRequests.interactiveResultSet(\n interactiveMetadata.data.interactiveId,\n interactiveMetadata.data.id,\n currentUser.data,\n requestFilter\n ));\n}","import { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport { MarkedAnswerHash } from 'libs/shared/apps/analytics/hooks/UseMarkAnswers';\nimport { ResultsSummary } from 'libs/shared/apps/analytics/interfaces/ResultsSummary';\nimport { StudentResultsWithSummary } from 'libs/shared/apps/analytics/interfaces/StudentResultsWithSummary';\nimport { ScoreThresholdDefaults, ScoreThresholds } from 'libs/shared/constants/ScoreThresholds';\nimport { InteractionCorrectness } from 'libs/shared/enums/InteractionCorrectness';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { Interaction, StudentAnswer, StudentResults } from 'libs/shared/interfaces';\nimport { Interactive, InteractiveResultSet } from 'libs/shared/interfaces';\nimport { InteractiveCorrectnessHelper } from 'libs/shared/utils/InteractiveCorrectnessHelper';\nimport { flattenInteractions, getInteractions, getStudentAttempt, getStudentResult } from 'libs/shared/utils/InteractiveHelper';\n\ninterface StudentGroups {\n markingRequired: StudentResultsWithSummary[];\n lowScore: StudentResultsWithSummary[];\n highScore: StudentResultsWithSummary[];\n completed: StudentResultsWithSummary[];\n notCompleted: StudentResultsWithSummary[];\n}\n\nexport function groupStudents(\n interactive: Interactive,\n results: InteractiveResultSet,\n scoreThreshold?: ScoreThresholds\n): StudentGroups {\n const groups: StudentGroups = {\n markingRequired: [],\n lowScore: [],\n highScore: [],\n completed: [],\n notCompleted: []\n };\n\n const interactions = getInteractions(interactive);\n\n const numInteractions = interactions.length;\n \n results.students.forEach(s => {\n const withSummary = {\n ...s,\n summary: getStudentResultsSummary(interactive, s)\n };\n \n if (withSummary.summary.awaitingMarking) {\n groups.markingRequired.push(withSummary);\n return;\n }\n\n if (ArrayHelper.last(s.results).attempts.length === numInteractions) {\n groups.completed.push(withSummary);\n } else {\n groups.notCompleted.push(withSummary);\n return;\n }\n \n if (withSummary.summary.percentCorrect >= (scoreThreshold.HIGH || ScoreThresholdDefaults.HIGH))\n groups.highScore.push(withSummary);\n \n if (withSummary.summary.percentCorrect < (scoreThreshold.MODERATE || ScoreThresholdDefaults.MODERATE))\n groups.lowScore.push(withSummary);\n });\n \n const sortedLowScore = ArrayHelper.sortBy(groups.lowScore, s => s.summary.percentCorrect);\n const sortedHighScore = ArrayHelper.sortBy(groups.highScore, s => -s.summary.percentCorrect);\n \n return {\n ...groups,\n lowScore: sortedLowScore,\n highScore: sortedHighScore\n };\n}\n\nexport function getInteractionById(interactive: Interactive, interactionId: string): Interaction {\n const flattenedInteractions = flattenInteractions(interactive);\n return flattenedInteractions.find(i => i.id.toString() === interactionId.toString());\n}\n\n/**\n * We need to use the question and result ids as a list of one student's responses\n * to multiple questions will all have the same result id and a list of multiple\n * students responses to one question will all have the same questionId.\n */\nexport function getMarkedAnswerId(answer: StudentAnswer): string {\n return `${answer.questionId}:${answer.resultId}`;\n}\n\nexport function getMarkedStatus(\n interactionId: string,\n studentResults: StudentResults,\n markedAnswers: MarkedAnswerHash\n): InteractiveAnswerStatus {\n const result = getStudentResult(studentResults);\n const studentResponse = getStudentAttempt(interactionId, result);\n\n const isMarkedCorrect = studentResponse?.answers.every(a => {\n return markedAnswers[getMarkedAnswerId(a)]?.status === InteractiveAnswerStatus.Correct;\n });\n\n if (isMarkedCorrect)\n return InteractiveAnswerStatus.Correct;\n\n const isMarkedIncorrect = studentResponse?.answers.every(a => {\n return markedAnswers[getMarkedAnswerId(a)]?.status === InteractiveAnswerStatus.Incorrect;\n });\n\n if (isMarkedIncorrect)\n return InteractiveAnswerStatus.Incorrect;\n}\n\nexport function getInteractionResultsSummary(\n interaction: Interaction,\n results: InteractiveResultSet\n): ResultsSummary {\n const numStudents = results.students.length;\n let numCorrect = 0;\n let answered = 0;\n let unanswered = 0;\n let awaitingMarking = 0;\n let attempts = 0;\n\n results.students.forEach(s => {\n const result = getStudentResult(s);\n\n if (!result)\n return;\n\n attempts = attempts + s.results.length;\n\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(interaction, result);\n\n if (correctness === InteractionCorrectness.Correct)\n numCorrect++;\n\n if (correctness === InteractionCorrectness.UnAnswered)\n unanswered++;\n\n if (correctness === InteractionCorrectness.AwaitingMarking)\n awaitingMarking++;\n\n if (correctness !== InteractionCorrectness.UnAnswered)\n answered++;\n });\n\n\n const percentCorrect = numStudents > 0\n ? numCorrect / numStudents\n : 0;\n\n return {\n percentCorrect,\n correct: numCorrect,\n answered,\n unanswered,\n awaitingMarking,\n attempts\n };\n}\n\nexport function getStudentResultsSummary(interactive: Interactive, studentResults: StudentResults): ResultsSummary {\n const result = getStudentResult(studentResults);\n\n const interactions = getInteractions(interactive);\n\n const numInteractions = interactions.length;\n\n let numCorrect = 0;\n let awaitingMarking = 0;\n\n interactions.forEach(i => {\n const correctness = InteractiveCorrectnessHelper.isInteractionCorrect(i, result);\n\n if (correctness === InteractionCorrectness.Correct)\n numCorrect++;\n\n if (correctness === InteractionCorrectness.AwaitingMarking)\n awaitingMarking++;\n });\n\n const percentCorrect = numInteractions > 0 ? numCorrect / numInteractions : 0;\n\n /**\n * Our interactions list has images and annotations filtered out.\n * We built a map of valid questions, so that we can calculate the unswered accurately.\n * We're doing this because of a bug that caused annotations and images to record answers in the player.\n * - Sha\n */\n const interactionIds = new Set(interactions.map(i => i.id));\n const answeredInteractions = result.attempts.filter(a => !!interactionIds.has(a?.answers[0]?.questionId)).length;\n\n return {\n answered: result.attempts.length,\n attempts: studentResults.results.length,\n unanswered: numInteractions - answeredInteractions,\n percentCorrect,\n correct: numCorrect,\n awaitingMarking\n };\n}","export enum InteractionCorrectness {\n Correct,\n Incorrect,\n AwaitingMarking,\n \n Answered,\n UnAnswered,\n NotApplicable\n}","export enum InteractiveAnswerStatus {\n Incorrect = 0,\n Correct = 1,\n PendingReview = 2\n}","import { InteractionCorrectness } from 'libs/shared/enums/InteractionCorrectness';\nimport { InteractiveAnswerStatus } from 'libs/shared/enums/InteractiveAnswerStatus';\nimport { Interaction, InteractionTypeId, InteractiveResult, StudentAnswer } from 'libs/shared/interfaces';\n\ntype GetStudentAnswerByActionableItemId = (id: string) => string;\n\nfunction notApplicable(): InteractionCorrectness {\n return InteractionCorrectness.NotApplicable;\n}\n\nfunction awaitingMarking(): InteractionCorrectness {\n return InteractionCorrectness.AwaitingMarking;\n}\n\nfunction isMissingWordCorrect(\n interaction: Interaction,\n getStudentAnswer: GetStudentAnswerByActionableItemId\n): InteractionCorrectness {\n const items = interaction.actionableItems.filter(a => a\n .isCorrect);\n\n if (items.every(a => !getStudentAnswer(a.id)))\n return InteractionCorrectness.UnAnswered;\n\n const correct = items.every(a => a.name.trim().toLowerCase() === getStudentAnswer(a.id)?.trim().toLowerCase());\n return correct ? InteractionCorrectness.Correct : InteractionCorrectness.Incorrect;\n}\n\nfunction isMultipleChoiceCorrect(\n interaction: Interaction,\n getStudentAnswer: GetStudentAnswerByActionableItemId\n): InteractionCorrectness {\n if (interaction.actionableItems.every(a => !getStudentAnswer(a.id)))\n return InteractionCorrectness.UnAnswered;\n \n const correctItems = interaction.actionableItems.filter(a => a.isCorrect);\n\n const correct = correctItems.every(a => {\n const studentAnswer = getStudentAnswer(a.id);\n\n /**\n * In the past we've only ever checked the answer name. But since we introduced the ability to have image interactions\n * with no question text, we've need to swap to saving the id. But past submissions still have the name\n * - Sha\n */\n return studentAnswer?.toString() === a.id?.toString() || studentAnswer === a.name;\n });\n return correct ? InteractionCorrectness.Correct : InteractionCorrectness.Incorrect;\n}\n\nfunction isMarkableAnswerMarkedCorrect(\n interaction: Interaction,\n getStudentAnswer: (id: string) => StudentAnswer\n): InteractionCorrectness {\n let correctness: InteractionCorrectness;\n\n // There should only be one actionableItem\n interaction.actionableItems.forEach(item => {\n const studentAnswer = getStudentAnswer(item.id);\n\n if (!studentAnswer) {\n correctness = InteractionCorrectness.UnAnswered;\n return;\n }\n\n if (studentAnswer.status === InteractiveAnswerStatus.Correct) {\n correctness = InteractionCorrectness.Correct;\n return;\n }\n\n if (studentAnswer.status === InteractiveAnswerStatus.Incorrect) {\n correctness = InteractionCorrectness.Incorrect;\n return;\n }\n\n correctness = InteractionCorrectness.AwaitingMarking;\n });\n\n return correctness;\n}\n\ntype IsCorrectFunction = (interaction: Interaction, result: InteractiveResult) => InteractionCorrectness;\n\nfunction getGetStudentAnswer(interaction: Interaction, result: InteractiveResult): (id: string) => StudentAnswer {\n return (id: string) => {\n const attempt = result.attempts.find(a => a.id === interaction.id);\n return attempt?.answers.find(s => s.id === id);\n };\n}\n\nfunction wrapIsMissingWordCorrect(interaction: Interaction, result: InteractiveResult): InteractionCorrectness {\n const getStudentAnswer = getGetStudentAnswer(interaction, result);\n\n return isMissingWordCorrect(interaction, (id: string) => {\n const answer = getStudentAnswer(id);\n return answer?.text;\n });\n}\n\nfunction wrapIsMultipleChoiceCorrect(interaction: Interaction, result: InteractiveResult): InteractionCorrectness {\n const getStudentAnswer = getGetStudentAnswer(interaction, result);\n\n return isMultipleChoiceCorrect(interaction, (id: string) => {\n const answer = getStudentAnswer(id);\n return answer?.text;\n });\n}\n\nfunction wrapIsMarkableAnswerMarkedCorrect(\n interaction: Interaction,\n result: InteractiveResult\n): InteractionCorrectness {\n const getStudentAnswer = getGetStudentAnswer(interaction, result);\n return isMarkableAnswerMarkedCorrect(interaction, getStudentAnswer);\n}\n\nconst IsCorrectLookup: {[typeId: number]: IsCorrectFunction} = {\n [InteractionTypeId.Annotation]: notApplicable,\n [InteractionTypeId.Image]: notApplicable,\n [InteractionTypeId.MissingWord]: wrapIsMissingWordCorrect,\n [InteractionTypeId.MultipleChoice]: wrapIsMultipleChoiceCorrect,\n [InteractionTypeId.ShortAnswer]: wrapIsMarkableAnswerMarkedCorrect,\n [InteractionTypeId.TrueOrFalse]: wrapIsMultipleChoiceCorrect,\n [InteractionTypeId.Illustration]: wrapIsMarkableAnswerMarkedCorrect\n};\n\nfunction isInteractionCorrect(interaction: Interaction, result: InteractiveResult): InteractionCorrectness {\n const isCorrectFn = IsCorrectLookup[interaction.typeId];\n\n return isCorrectFn(interaction, result);\n}\n\nexport const InteractiveCorrectnessHelper = {\n notApplicable,\n awaitingMarking,\n isMissingWordCorrect,\n isMultipleChoiceCorrect,\n isInteractionCorrect\n};\n","import { ArrayHelper } from 'libs/common/react/utils/ArrayHelper';\n\nimport {\n Interaction,\n InteractionTypeId,\n Interactive,\n InteractiveResult,\n StudentAttempt,\n StudentResults\n} from 'libs/shared/interfaces';\n\nfunction interactionRequiresAnswer(interaction: Interaction): boolean {\n return interaction.typeId !== InteractionTypeId.Annotation && interaction.typeId !== InteractionTypeId.Image;\n}\n\nexport function flattenInteractions(interactive: Interactive): Interaction[] {\n return ArrayHelper.flatten(interactive.timepoints.map(i => i.interactions));\n}\n\n/**\n * Centralised logic for using the most recent student result.\n */\nexport function getStudentResult(studentResults: StudentResults): InteractiveResult {\n return ArrayHelper.last(studentResults.results);\n}\n\nexport function getStudentAttempt(interactionId: string, result: InteractiveResult): StudentAttempt {\n return ArrayHelper.findWhere(result?.attempts, { id: interactionId });\n}\n\n/**\n * Returns a flat list of interactions on an interactive and filters out\n * those that don't require an answer (annotations and images).\n */\nexport function getInteractions(interactive: Interactive): Interaction [] {\n return flattenInteractions(interactive).filter(interactionRequiresAnswer);\n}","// extracted by mini-css-extract-plugin\nexport default {\"header\":\"hnMke\",\"row\":\"ILLa_\",\"fixedTable\":\"_fdpt\",\"interactionHeaderCellOuter\":\"kjXYB\",\"hasResults\":\"M4qgr\",\"interactionHeaderCellInner\":\"cnFvB\",\"resultsCellOuter\":\"bdzRb\",\"correct\":\"xANR6\",\"incorrect\":\"_44sb\",\"awaitingMarking\":\"eQ9sh\",\"unanswered\":\"xRUK8\",\"highlightColumn\":\"f9Zqr\",\"resultsCellInner\":\"LAFwi\",\"highlightResultsRow\":\"TwwLO\",\"resultsRow\":\"xZ5iP\"};"],"names":["getPhrase","getClassName","props","className","showLabel","PendingIndicator","Indicator","title","spanHack","spanHackClassName","tooltipClassName","InteractionsBar","duration","interactive","timepoints","map","t","i","interactions","length","timepoint","selectedInteraction","interaction","find","id","isSelected","bgClassName","InteractionTypeHelper","typeId","left","visibleAt","key","style","DurationHelper","LanguageService","InteractionResultsSummary","interactiveMetadata","summary","results","InteractionLabel","iconClassName","_parentClip","endTime","startTime","_parentVideo","awaitingMarking","PercentageIndicator","percentage","percentCorrect","layout","unanswered","InteractionResultsSummaryPopover","ref","popoverProps","Popover","InteractionHeaderCell","OverlayTrigger","trigger","students","placement","overlay","rootClose","onMouseEnter","onMouseLeave","interactionNumber","correctness","InteractionCorrectness","StudentResultCell","InteractiveCorrectnessHelper","studentResults","svgName","getSvgName","SvgContainer","RESULTS_COL_WIDTH","CellWrapper","children","HeaderCell","column","isSorted","phraseKey","useGetFixedColumns","anonymiseUsers","hasResults","Header","accessor","Cell","value","disableSortBy","sortType","sortDescFirst","correct","answered","width","useGetResultColumns","onColumnHover","refreshData","index","row","original","useGetResultsTableData","sortBy","forEach","s","push","sorted","ArrayHelper","student","user","desc","reverse","highlightColumns","tableEl","highlightIndex","rows","querySelectorAll","childNodes","col","colIdx","classList","remove","add","highlightRows","rowIdx","getInteractiveResultFilters","currentUser","filter","currentUserId","currentCustomerId","customerId","dateRange","start","end","userIds","userId","classroomsAndGroups","groupId","InteractiveResultsRequests","interactiveResultSet","interactiveId","interactiveMetadataId","success","error","always","url","data","type","normalize","mark","answerId","resultId","invalidationKeys","pendingReviews","interactiveResultsReport","useFetchInteractiveResults","requestFilter","shouldFetchResults","I","groupStudents","scoreThreshold","groups","markingRequired","lowScore","highScore","completed","notCompleted","numInteractions","withSummary","getStudentResultsSummary","attempts","HIGH","MODERATE","sortedLowScore","sortedHighScore","getInteractionById","interactionId","toString","getMarkedAnswerId","answer","questionId","getMarkedStatus","markedAnswers","result","studentResponse","answers","every","a","status","getInteractionResultsSummary","numStudents","numCorrect","interactionIds","Set","answeredInteractions","has","InteractiveAnswerStatus","notApplicable","isMissingWordCorrect","getStudentAnswer","items","actionableItems","isCorrect","name","trim","toLowerCase","isMultipleChoiceCorrect","studentAnswer","getGetStudentAnswer","attempt","wrapIsMultipleChoiceCorrect","text","wrapIsMarkableAnswerMarkedCorrect","item","isMarkableAnswerMarkedCorrect","IsCorrectLookup","isInteractionCorrect","isCorrectFn","interactionRequiresAnswer","flattenInteractions","getStudentResult","getStudentAttempt","getInteractions"],"sourceRoot":""}
@@ -1,2 +0,0 @@
1
- "use strict";(self.webpackChunk_clickview_lite=self.webpackChunk_clickview_lite||[]).push([[8849],{53353:(e,t,n)=>{n.d(t,{c:()=>h,l:()=>f});var a=n(32735),r=n(232),s=n.n(r),i=n(8604),c=n(83345);const l={heatMap:"epapa",legend:"uhH4p"};function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=Array(t);n<t;n++)a[n]=e[n];return a}var u="shared.engagementHeatMap",m="#f1f1f1",d=s().scale(["#daf07d","#08bd1a"]),p=[0,.01,.25,.5,.75,1];function g(e,t){return e?d(e/t).hex():m}function v(e,t){for(var n=[],a=0;a<e.length;a++){var r=a>0&&e[a-1],s=e[a],i=a<e.length-1&&e[a+1];s===r&&s===i||n.push("".concat(g(s,t)," ").concat(100/e.length*a,"%"))}return"linear-gradient(to right, ".concat(n.join(","),")")}function f(){var e=Math.max.apply(Math,p),t=100/p.length;return a.createElement("div",{className:"d-flex justify-content-between w-100"},a.createElement(c.x,{namespace:u,phrase:"less"}),a.createElement("div",{className:"d-flex mx-1 flex-grow-1 ".concat(l.legend)},p.map((function(n,r){return a.createElement("div",{key:r,style:{width:"".concat(t,"%"),backgroundColor:g(n,e)}})}))),a.createElement(c.x,{namespace:u,phrase:"more"}))}function h(e){var t,n,r,s=(0,i.O)(e.engagement),c=null!==(t=e.max)&&void 0!==t?t:Math.max.apply(Math,function(e){if(Array.isArray(e))return o(e)}(r=s)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(r)||function(e,t){if(e){if("string"==typeof e)return o(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?o(e,t):void 0}}(r)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}());return a.createElement("div",{className:"border rounded ".concat(l.heatMap," ").concat(null!==(n=e.className)&&void 0!==n?n:""),style:{background:v(s,c)}})}},25216:(e,t,n)=>{n.d(t,{L:()=>i});var a=n(32735),r=n(83914);const s={icon:"sAmpy",count:"faDs4"};function i(e){return a.createElement("section",{className:"d-flex flex-column border border-light rounded p-3 h-100"},a.createElement("div",{className:"d-flex align-items-center mb-2"},a.createElement("div",{className:"".concat(s.icon," ").concat(e.svgClassName," rounded-circle d-flex align-items-center justify-content-center")},a.createElement(r.x,{svgName:e.svgName})),a.createElement("div",{className:"d-flex flex-column ms-2"},a.createElement("h2",{className:"h6 mb-0"},e.title),e.subtitle&&a.createElement("p",{className:"text-secondary font-size-sm mb-0"},e.subtitle)),"number"==typeof e.count&&a.createElement("div",{className:"".concat(s.count," d-flex justify-content-center align-items-center bg-light rounded-circle ms-auto")},e.count)),e.children)}},69332:(e,t,n)=>{n.d(t,{x:()=>o});var a=n(32735),r=n(72306),s=n.n(r),i=n(70312),c=n.n(i);var l=function(e){return{title:{text:null},credits:{enabled:!1},yAxis:{title:{text:null},labels:{enabled:!1},gridLineWidth:0,min:0,tickAmount:1},xAxis:{title:{text:e,style:{color:"#313543",fontSize:"12px"}},labels:{style:{color:"#313543",fontSize:"12px"}},className:"nSTtI",lineWidth:0},legend:{enabled:!1},chart:{type:"column",backgroundColor:"transparent",height:"160px",spacingTop:20},plotOptions:{column:{dataLabels:{enabled:!1},enableMouseTracking:!1,minPointLength:8}}}};function o(e){return a.createElement(c(),{highcharts:s(),options:(t=e.chartData,n=l(e.label),Object.assign(Object.assign({},n),{xAxis:Object.assign(Object.assign({},n.xAxis),{categories:t.categories}),series:t.series}))});var t,n}},461:(e,t,n)=>{n.d(t,{y:()=>o});var a=n(32735),r=n(77640),s=n(36848),i=n(40782);const c={avatar:"uMuZt",image:"WdKiU"};var l=3;function o(e){return a.createElement(a.Fragment,null,e.students.length?a.createElement("ul",{className:"list-unstyled mb-2"},e.students.slice(0,l).map((function(t,n){return a.createElement("li",{key:n,className:"d-flex align-items-center mb-2"},a.createElement(r.t,{user:t,imageCdnUrl:e.imageCdnUrl,avatarClassName:c.avatar,detailsClassName:"ms-2",showDisplayName:!0,showSubText:!1,anonymiseUsers:e.anonymiseUsers}),a.createElement("div",{className:"d-flex align-items-center ms-auto"},a.createElement("span",{className:"me-1"},void 0===t.percentage?"- ":Math.round(100*t.percentage),"%"),a.createElement(i.O,{percentage:t.percentage})))}))):a.createElement("div",{className:"text-center"},a.createElement("img",{className:"".concat(c.image," mb-2"),src:e.imageUrl}),a.createElement("p",{className:"text-secondary mb-0",dangerouslySetInnerHTML:{__html:e.description}})),!!e.students.length&&a.createElement(s.F,{appLink:e.appLink,className:"text-info mt-auto"},e.appLinkText))}},42642:(e,t,n)=>{n.d(t,{i:()=>g});var a=n(32735),r=n(23481),s=n(75896),i=n(25216),c=n(69332),l=n(83345),o=n(35223);const u={font:"xTiKg",purpleChart:"OPcvi",grayChart:"HlWj7"};var m="shared.insightDevices",d=r.T.encloseNamespace(m);function p(e){switch(e){case"Android":case"Windows Phone":case"iOS":case"BlackBerry":return"Mobile";case"Linux":case"Unix":case"Macintosh":case"Windows":return"Computer"}}function g(e){var t,n,r=function(){var t,n={Phone:0,Computer:0};return(null===(t=e.osCount)||void 0===t?void 0:t.length)?e.osCount.reduce((function(e,t){if(!t.name)return e;var n=p(t.name);return e[n]=e[n]+t.count,e}),n):n}(),g=function(){var t;return(null===(t=e.osCount)||void 0===t?void 0:t.length)?e.osCount.reduce((function(t,n){return n.name&&n.count>t.count?n:s.m.first(e.osCount)})):null}(),v={categories:Object.keys(r),series:[{type:"column",borderRadius:4,dataLabels:{enabled:!0,style:{fontSize:"12px",fontWeight:"normal"},inside:!1,overflow:"allow",crop:!1,className:u.font},data:Object.keys(r).map((function(e){return{className:"".concat(0===r[e]?u.grayChart:u.purpleChart," ").concat(r[e]!==(null==g?void 0:g.count)?"opacity-25":""),y:r[e]}}))}]};return a.createElement(i.L,{title:d("title"),svgClassName:"bg-light-ultramarine text-ultramarine",svgName:o.vn.Monitor},a.createElement("p",{className:"mb-0"},(null===(t=e.osCount)||void 0===t?void 0:t.filter((function(e){return e.name})).length)?a.createElement(l.x,{namespace:m,phrase:"description",options:{device:null===(n=p(null==g?void 0:g.name))||void 0===n?void 0:n.toLowerCase()}}):a.createElement(l.x,{namespace:m,phrase:"notViewed"})),a.createElement("div",{className:"position-relative mt-auto"},a.createElement(c.x,{label:d("title"),chartData:v})))}},94652:(e,t,n)=>{n.d(t,{b:()=>p});var a=n(32735),r=n(23481),s=n(53353),i=n(25216),c=n(36848),l=n(83345),o=n(35223);const u={heatMap:"Rfr9N",heatMapTimepointIndicator:"s6JbA",heatMapTimepointIndicatorVisible:"mgjWX"};var m="shared.insightHeatmap",d=r.T.encloseNamespace(m);function p(e){var t=e.engagement.engagementRate>0?Math.round(100*e.engagement.engagementRate):null;return a.createElement(i.L,{title:d("title"),svgName:o.vn.Timer,svgClassName:"bg-light-green text-green"},a.createElement("div",{className:"mb-2"},a.createElement("p",{className:"mb-0"},t?a.createElement(l.x,{namespace:m,phrase:"everyoneWatched",options:{engagementRate:t}}):a.createElement(l.x,{namespace:m,phrase:"notWatched"})),t&&a.createElement(c.F,{appLink:e.heatmapAppLink,className:"text-info"},a.createElement(l.x,{namespace:m,phrase:"viewHeatmap"}))),a.createElement("div",{className:"mb-2"},a.createElement(s.c,{engagement:e.engagement,className:u.heatMap})),a.createElement("p",{className:"h3 text-center mb-2"},t||"--","%"),a.createElement("p",{className:"text-center mb-0 font-size-sm"},a.createElement(l.x,{namespace:m,phrase:"amountWatched"})))}},71553:(e,t,n)=>{n.d(t,{I:()=>i});var a=n(99940),r=n(62875);function s(e,t){return{currentUserId:e.id,currentCustomerId:e.customerId,dateRange:{start:t.start,end:t.end},userIds:t.userId,classroomsAndGroups:t.groupId}}var i={interactiveResultSet:function(e,t,n,i,c,l,o){return{url:"/api/domain/v2/analytics/interactives/".concat(e,"/metadata/").concat(t),key:(0,r.H)("interactive:result:set:".concat(e,":").concat(t),i),data:s(n,i),type:a.k.POST,normalize:!1,success:c,error:l,always:o}},mark:function(e,t,n,r,s,i,c){return{url:"/api/domain/v1/analytics/answers/".concat(n),key:"mark:answer:".concat(n,":").concat(r.resultId),type:a.k.PUT,data:r,normalize:!1,invalidationKeys:"interactive:result:set:".concat(e,":").concat(t),success:s,error:i,always:c}},pendingReviews:function(e){return{url:"/api/domain/v1/analytics/interactives/pending-reviews/summary",key:"interactives:pending:reviews",type:a.k.POST,data:e}},interactiveResultsReport:function(e){return{url:"{gateway}/v2/analytics/interactives/report",key:"interactive:results:report",data:e,type:a.k.POST,normalize:!1}}}},41196:(e,t,n)=>{n.d(t,{W:()=>c});var a=n(20354),r=n(71553),s=n(20768),i=n(31949);function c(e,t){var n,c=a.a.useBasicFetch(i.N.currentUser()),l=a.a.useBasicFetch(!!e&&s.b.interactiveMetadata(e)),o=a.a.useBasicFetch(!!(null===(n=l.data)||void 0===n?void 0:n.interactiveId)&&s.b.interactive(l.data.interactiveId)),u=!!c.data&&!!o.data&&!!t;return a.a.useBasicFetch(u&&r.I.interactiveResultSet(l.data.interactiveId,l.data.id,c.data,t))}},8604:(e,t,n)=>{function a(e){return new Array(Math.ceil(e.videoDuration)).fill(null).map((function(t,n){return e.heatMap[n]||0}))}n.d(t,{O:()=>a})},39157:(e,t,n)=>{n.d(t,{HI:()=>d,R6:()=>o,Rt:()=>g,UU:()=>m,Zs:()=>u,nq:()=>p});var a=n(75896),r=n(94892),s=n(28972),i=n(8246),c=n(83140),l=n(80845);function o(e,t,n){var s={markingRequired:[],lowScore:[],highScore:[],completed:[],notCompleted:[]},i=(0,l.Q)(e).length;t.students.forEach((function(t){var c=Object.assign(Object.assign({},t),{summary:g(e,t)});c.summary.awaitingMarking?s.markingRequired.push(c):a.m.last(t.results).attempts.length===i?(s.completed.push(c),c.summary.percentCorrect>=(n.HIGH||r.i.HIGH)&&s.highScore.push(c),c.summary.percentCorrect<(n.MODERATE||r.i.MODERATE)&&s.lowScore.push(c)):s.notCompleted.push(c)}));var c=a.m.sortBy(s.lowScore,(function(e){return e.summary.percentCorrect})),o=a.m.sortBy(s.highScore,(function(e){return-e.summary.percentCorrect}));return Object.assign(Object.assign({},s),{lowScore:c,highScore:o})}function u(e,t){return(0,l.Wn)(e).find((function(e){return e.id.toString()===t.toString()}))}function m(e){return"".concat(e.questionId,":").concat(e.resultId)}function d(e,t,n){var a=(0,l.j_)(t),r=(0,l.f6)(e,a);return(null==r?void 0:r.answers.every((function(e){var t;return(null===(t=n[m(e)])||void 0===t?void 0:t.status)===i.N.Correct})))?i.N.Correct:(null==r?void 0:r.answers.every((function(e){var t;return(null===(t=n[m(e)])||void 0===t?void 0:t.status)===i.N.Incorrect})))?i.N.Incorrect:void 0}function p(e,t){var n=t.students.length,a=0,r=0,i=0,o=0,u=0;return t.students.forEach((function(t){var n=(0,l.j_)(t);if(n){u+=t.results.length;var m=c.A.isInteractionCorrect(e,n);m===s.w.Correct&&a++,m===s.w.UnAnswered&&i++,m===s.w.AwaitingMarking&&o++,m!==s.w.UnAnswered&&r++}})),{percentCorrect:n>0?a/n:0,correct:a,answered:r,unanswered:i,awaitingMarking:o,attempts:u}}function g(e,t){var n=(0,l.j_)(t),a=(0,l.Q)(e),r=a.length,i=0,o=0;a.forEach((function(e){var t=c.A.isInteractionCorrect(e,n);t===s.w.Correct&&i++,t===s.w.AwaitingMarking&&o++}));var u=r>0?i/r:0,m=new Set(a.map((function(e){return e.id}))),d=n.attempts.filter((function(e){var t;return!!m.has(null===(t=null==e?void 0:e.answers[0])||void 0===t?void 0:t.questionId)})).length;return{answered:n.attempts.length,attempts:t.results.length,unanswered:r-d,percentCorrect:u,correct:i,awaitingMarking:o}}},77640:(e,t,n)=>{n.d(t,{t:()=>d});var a=n(32735),r=n(23481),s=n(26136),i=n(20789),c=n(76881),l=n(86613),o=n(64818),u=n(94831),m=r.T.encloseNamespace("shared.userRecipientItemMetadata");function d(e){var t;return a.createElement(a.Fragment,null,a.createElement("div",{className:"".concat(u.Z.avatarContainer," ").concat(e.avatarClassName," d-inline-block")},a.createElement(i.q,{imageUrl:null===(t=e.user.avatar)||void 0===t?void 0:t.url,imageCdnUrl:e.imageCdnUrl,initials:o.l.getInitials(e.user.name,e.user.surname)})),a.createElement("div",{className:e.detailsClassName},a.createElement("h4",{className:"font-size-normal fw-normal m-0"},e.anonymiseUsers?(0,s.B)(e.user,!0):e.showDisplayName?o.l.getDisplayName(e.user):o.l.getFullName(e.user)),e.showSubText&&a.createElement("p",{className:"text-secondary m-0"},e.getSubText?e.getSubText(e.user):function(e){var t=o.l.getUserType(e),n=o.l.getUserRole(e);if(t===c.Y.Staff)return n===l.i.Admin?m("admin"):m("staff");var a=o.l.getYearGroup(e);return(null==a?void 0:a.name)?a.name:m("student")}(e.user))))}d.defaults={showSubText:!0}},28972:(e,t,n)=>{var a;n.d(t,{w:()=>a}),function(e){e[e.Correct=0]="Correct",e[e.Incorrect=1]="Incorrect",e[e.AwaitingMarking=2]="AwaitingMarking",e[e.Answered=3]="Answered",e[e.UnAnswered=4]="UnAnswered",e[e.NotApplicable=5]="NotApplicable"}(a||(a={}))},8246:(e,t,n)=>{var a;n.d(t,{N:()=>a}),function(e){e[e.Incorrect=0]="Incorrect",e[e.Correct=1]="Correct",e[e.PendingReview=2]="PendingReview"}(a||(a={}))},17913:(e,t,n)=>{n.d(t,{u:()=>i});var a=n(97395),r=n(110),s=n(62875),i={individualEngagement:function(e,t,n,r,i,c){var l=Object.assign({objectId:e},t);return n&&(l.sharerId=n),{url:a._.urlBuilder("{gateway}/v1/analytics/heat-map",l),key:(0,s.H)("engagement:".concat(e),t,n),formatData:function(e){var t;return Object.assign(Object.assign({},e),{data:null===(t=e.data)||void 0===t?void 0:t.map((function(e){var t;return Object.assign(Object.assign({},e),{heatMap:null!==(t=e.heatMap)&&void 0!==t?t:[]})}))})},normalize:!1,success:r,error:i,always:c}},aggregateEngagement:function(e,t,n,r,i,c){var l=Object.assign({objectId:e},t);return n&&(l.sharerId=n),{url:a._.urlBuilder("{gateway}/v1/analytics/heat-map/aggregations",l),key:(0,s.H)("aggregate:engagement:".concat(e),t,n),formatData:function(e){var t;return Object.assign(Object.assign({},e),{heatMap:null!==(t=e.heatMap)&&void 0!==t?t:[]})},normalize:!1,success:r,error:i,always:c}},views:function(e,t,n,i,c,l){var o="video:views";t&&(o+=":".concat(t));var u=Object.assign(Object.assign({objectId:t},e),{timeOffset:r.O.getTimezoneOffset()});return n&&(u.sharerId=n),{url:a._.urlBuilder("{gateway}/v1/analytics/video-views",u),key:(0,s.H)(o,e,n),normalize:!1,success:i,error:c,always:l}}}},83140:(e,t,n)=>{n.d(t,{A:()=>v});var a=n(28972),r=n(8246),s=n(40424);function i(e){return i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},i(e)}function c(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=i(e)||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var a=n.call(e,"string");if("object"!=i(a))return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==i(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(){return a.w.NotApplicable}function o(e,t){var n=e.actionableItems.filter((function(e){return e.isCorrect}));return n.every((function(e){return!t(e.id)}))?a.w.UnAnswered:n.every((function(e){var n;return e.name.trim().toLowerCase()===(null===(n=t(e.id))||void 0===n?void 0:n.trim().toLowerCase())}))?a.w.Correct:a.w.Incorrect}function u(e,t){return e.actionableItems.every((function(e){return!t(e.id)}))?a.w.UnAnswered:e.actionableItems.filter((function(e){return e.isCorrect})).every((function(e){var n,a=t(e.id);return(null==a?void 0:a.toString())===(null===(n=e.id)||void 0===n?void 0:n.toString())||a===e.name}))?a.w.Correct:a.w.Incorrect}function m(e,t){return function(n){var a=t.attempts.find((function(t){return t.id===e.id}));return null==a?void 0:a.answers.find((function(e){return e.id===n}))}}function d(e,t){var n=m(e,t);return u(e,(function(e){var t=n(e);return null==t?void 0:t.text}))}function p(e,t){return function(e,t){var n;return e.actionableItems.forEach((function(e){var s=t(e.id);n=s?s.status!==r.N.Correct?s.status!==r.N.Incorrect?a.w.AwaitingMarking:a.w.Incorrect:a.w.Correct:a.w.UnAnswered})),n}(e,m(e,t))}var g=c(c(c(c(c(c(c({},s.Z9.Annotation,l),s.Z9.Image,l),s.Z9.MissingWord,(function(e,t){var n=m(e,t);return o(e,(function(e){var t=n(e);return null==t?void 0:t.text}))})),s.Z9.MultipleChoice,d),s.Z9.ShortAnswer,p),s.Z9.TrueOrFalse,d),s.Z9.Illustration,p),v={notApplicable:l,awaitingMarking:function(){return a.w.AwaitingMarking},isMissingWordCorrect:o,isMultipleChoiceCorrect:u,isInteractionCorrect:function(e,t){return(0,g[e.typeId])(e,t)}}},80845:(e,t,n)=>{n.d(t,{Q:()=>o,Wn:()=>i,f6:()=>l,j_:()=>c});var a=n(75896),r=n(40424);function s(e){return e.typeId!==r.Z9.Annotation&&e.typeId!==r.Z9.Image}function i(e){return a.m.flatten(e.timepoints.map((function(e){return e.interactions})))}function c(e){return a.m.last(e.results)}function l(e,t){return a.m.findWhere(null==t?void 0:t.attempts,{id:e})}function o(e){return i(e).filter(s)}},80331:(e,t,n)=>{n.r(t),n.d(t,{InteractiveInsightsOverviewView:()=>me});var a=n(32735),r=n(2948),s=n(20354),i=n(75896),c=n(23481),l=n(25216),o=n(69332),u=n(83345),m=n(35223);const d={tealChart:"lZZf0",grayChart:"wJQc4",font:"o1Xbr"};function p(e){return p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},p(e)}var g="shared.insightAverageAttempts",v=c.T.encloseNamespace(g);function f(e){var t,n,r=e.students.reduce((function(e,t){return t.summary.attempts>e?t.summary.attempts:e}),0),s=(t=function(){var t=e.students.reduce((function(e,t){var n,a,r,s=t.summary.attempts.toString();return s in e||Object.assign(e,(n={},r=0,(a=function(e){var t=function(e,t){if("object"!=p(e)||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var a=n.call(e,"string");if("object"!=p(a))return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==p(t)?t:t+""}(a=s))in n?Object.defineProperty(n,a,{value:r,enumerable:!0,configurable:!0,writable:!0}):n[a]=r,n)),e[s]++,e}),{});return Object.keys(t).length?t:{0:0}}(),n=0===t[0],{categories:Object.keys(t),series:[{type:"column",color:t[0]?"#EAEAEA":"#40C2BB",borderRadius:4,dataLabels:{enabled:!n,style:{fontSize:"12px",fontWeight:"normal"},inside:!1,overflow:"allow",crop:!1,className:d.font},data:Object.keys(t).map((function(e){return{className:"".concat(n?d.grayChart:d.tealChart," ").concat(r.toString()!==e?"opacity-25":""),y:t[e]}}))}]});return a.createElement(l.L,{title:v("title"),svgName:m.vn.Refresh,svgClassName:"bg-light-purple text-purple"},a.createElement("p",null,r?a.createElement(u.x,{namespace:g,phrase:"averageAttempts",options:{smartCount:r}}):a.createElement(u.x,{namespace:g,phrase:"noAttempts"})),a.createElement("div",{className:"mt-auto"},a.createElement(o.x,{label:v("attempts"),chartData:s})))}const h={redChart:"G7zOw",yellowChart:"k34mm",greenChart:"vBneA",blueChart:"RPTWm",grayChart:"k4JFZ",borderDark:"LWor3"};var y="shared.insightAverageScore",b=c.T.encloseNamespace(y);function E(e){return a.createElement(l.L,{title:b("title"),svgName:m.vn.Analytics,svgClassName:"bg-light-orange text-orange"},a.createElement("p",null,e.students.length?a.createElement(u.x,{namespace:y,phrase:"averageScore",options:(s=e.students.map((function(e){return e.summary.percentCorrect})),c=s.reduce((function(e,t){return e+t}),0)/s.length,d=i.m.last(i.m.last(e.students).results).attempts.length,{averageScore:Math.round(d*c),totalQuestions:d,averagePercentage:(100*c).toFixed(1)})}):a.createElement(u.x,{namespace:y,phrase:"noAnswers"})),a.createElement(o.x,{label:"".concat(b("studentScores")," (%)"),chartData:(t=Array(11).fill(0),n=e.students.reduce((function(e,t){return e[Math.floor(10*t.summary.percentCorrect)]++,e}),t),r=["0","10","20","30","40","50","60","70","80","90","100"],{categories:r,series:[{type:"column",color:"#4E9ACE",borderRadius:4,data:n.map((function(e,t){var n=Number(r[t]);return{className:"".concat(function(e,t){return 0===t?h.grayChart:e<50?h.redChart:e<70?h.yellowChart:e<90?h.greenChart:h.blueChart}(n,e)," rounded"),y:e}}))}]})}));var t,n,r,s,c,d}var C=n(461),w=c.T.encloseNamespace("shared.insightCompletedStudents");function N(e){return a.createElement(l.L,{title:w("title"),svgName:m.vn.Flag,svgClassName:"bg-light-indigo text-indigo",count:e.students.length},a.createElement(C.y,{students:e.students.map((function(e){return Object.assign(Object.assign({},e.user),{percentage:e.summary.percentCorrect})})),imageCdnUrl:e.imageCdnUrl,imageUrl:e.imageUrl,description:w("completedStudents"),appLink:e.resultsAppLink,appLinkText:w("viewAll"),anonymiseUsers:e.anonymiseUsers}))}var A=n(42642),S=n(39157),k=n(36848),I=n(86572),x=n(40782),O=n(80845),U="shared.insightEasiestQuestion",j=c.T.encloseNamespace(U);function L(e){var t,n=a.useMemo((function(){return t=e.interactive,n=e.results,a=(0,O.Q)(t).map((function(e){return Object.assign(Object.assign({},e),{resultsSummary:(0,S.nq)(e,n)})})).filter((function(e){return!!e.resultsSummary.answered&&!e.resultsSummary.awaitingMarking})),r=i.m.sortBy(a,(function(e){return e.resultsSummary.percentCorrect})),i.m.last(r);var t,n,a,r}),[e.results.students.length]);return a.createElement(l.L,{title:j("title"),subtitle:j("subtitle"),svgName:m.vn.StarOutline,svgClassName:"bg-light-blue text-blue"},a.createElement("div",{className:"d-flex align-items-center"},a.createElement(x.O,{percentage:null===(t=null==n?void 0:n.resultsSummary)||void 0===t?void 0:t.percentCorrect,layout:x.I.LabelInside}),n?a.createElement("div",{className:"d-flex ms-2"},a.createElement(I.y,{interaction:n,iconClassName:"flex-shrink-0"})):a.createElement("span",{className:"ms-2"},j("noAnswers"))),n&&a.createElement(k.F,{appLink:Object.assign(Object.assign({},e.questionsAppLink),{params:Object.assign(Object.assign({},e.questionsAppLink.params),{sortBy:"score_desc"})}),className:"text-info"},a.createElement(u.x,{namespace:U,phrase:"viewQuestions"})))}var T="shared.insightHardestQuestion",M=c.T.encloseNamespace(T);function R(e){var t,n=a.useMemo((function(){return t=e.interactive,n=e.results,a=(0,O.Q)(t).map((function(e){return Object.assign(Object.assign({},e),{resultsSummary:(0,S.nq)(e,n)})})).filter((function(e){return!!e.resultsSummary.answered&&!e.resultsSummary.awaitingMarking})),r=i.m.sortBy(a,(function(e){return e.resultsSummary.percentCorrect})),i.m.first(r);var t,n,a,r}),[e.results.students.length]);return a.createElement(l.L,{title:M("title"),subtitle:M("subtitle"),svgName:m.vn.QuestionMark,svgClassName:"bg-light-orange text-orange"},a.createElement("div",{className:"d-flex align-items-center"},a.createElement(x.O,{percentage:null===(t=null==n?void 0:n.resultsSummary)||void 0===t?void 0:t.percentCorrect,layout:x.I.LabelInside}),n?a.createElement("div",{className:"d-flex ms-2"},a.createElement(I.y,{interaction:n,iconClassName:"flex-shrink-0"})):a.createElement("span",{className:"ms-2"},M("noAnswers"))),n&&a.createElement(k.F,{appLink:Object.assign(Object.assign({},e.questionsAppLink),{params:Object.assign(Object.assign({},e.questionsAppLink.params),{sortBy:"score_asc"})}),className:"text-info"},a.createElement(u.x,{namespace:T,phrase:"viewQuestions"})))}var B=n(94652),H=c.T.encloseNamespace("shared.insightHighScoringStudents");function W(e){return a.createElement(l.L,{title:H("title"),subtitle:H("subtitle"),svgName:m.vn.Trophy,svgClassName:"bg-light-teal text-teal",count:e.students.length},a.createElement(C.y,{students:e.students.map((function(e){return Object.assign(Object.assign({},e.user),{percentage:e.summary.percentCorrect})})),imageCdnUrl:e.imageCdnUrl,imageUrl:e.greenChartImageUrl,description:H(e.completed.length?"noStudents":"highScore"),appLink:Object.assign(Object.assign({},e.resultsAppLink),{params:Object.assign(Object.assign({},e.resultsAppLink.params),{sortBy:"score_desc"})}),appLinkText:H("viewByHighest"),anonymiseUsers:e.anonymiseUsers}))}var P=c.T.encloseNamespace("shared.insightLowScoringStudents");function _(e){return a.createElement(l.L,{title:P("title"),subtitle:P("subtitle"),svgName:m.vn.Hand,svgClassName:"bg-light-red text-red",count:e.students.length},a.createElement(C.y,{students:e.students.map((function(e){return Object.assign(Object.assign({},e.user),{percentage:e.summary.percentCorrect})})),imageCdnUrl:e.imageCdnUrl,imageUrl:e.completed.length?e.heartImageUrl:e.redChartImageUrl,description:P(e.completed.length?"doingWell":"lowScore"),appLink:Object.assign(Object.assign({},e.resultsAppLink),{params:Object.assign(Object.assign({},e.resultsAppLink.params),{sortBy:"score_asc"})}),appLinkText:P("viewByLowest"),anonymiseUsers:e.anonymiseUsers}))}var F=c.T.encloseNamespace("shared.insightMarkingRequired");function q(e){return a.createElement(l.L,{title:F("title"),svgName:m.vn.Hand,svgClassName:"bg-light-blue text-blue",count:e.students.length},a.createElement(C.y,{students:e.students,imageCdnUrl:e.imageCdnUrl,imageUrl:e.imageUrl,description:F("studentsRequireMarking"),appLink:e.resultsAppLink,appLinkText:F("viewAll"),anonymiseUsers:e.anonymiseUsers}))}function D(e){return function(e){if(Array.isArray(e))return z(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(e){if("string"==typeof e)return z(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?z(e,t):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function z(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=Array(t);n<t;n++)a[n]=e[n];return a}var Z=c.T.encloseNamespace("shared.insightNotCompletedStudents");function Q(e){var t,n,r,s=(t=e.markingRequiredStudents.map((function(e){return null==e?void 0:e.user.id})),n=e.completedStudents.map((function(e){return null==e?void 0:e.user.id})),r=e.classroomStudents.filter((function(e){return!t.includes(e.id)&&!n.includes(e.id)})),i.m.uniq([].concat(D(e.notCompletedStudents.map((function(e){return e.user}))),D(r)),"id"));return a.createElement(l.L,{title:Z("title"),svgName:m.vn.Puzzle,svgClassName:"bg-light-teal text-teal",count:s.length},a.createElement(C.y,{students:s,imageCdnUrl:e.imageCdnUrl,imageUrl:e.imageUrl,description:Z("completed"),appLink:e.resultsAppLink,appLinkText:Z("viewAll"),anonymiseUsers:e.anonymiseUsers}))}var G=n(41196),V=n(26025),K=n(74901),J=n(40003),Y=n(94892),$=n(38143),X=n(39151),ee=n(20768),te=n(31949),ne=n(17913),ae=n(99742),re=n(88630),se=n(5672),ie=n(83590),ce=n(14070),le=n(97291);function oe(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=Array(t);n<t;n++)a[n]=e[n];return a}var ue="insights.interactiveInsightsOverview";function me(e){var t,n,c,l,o,m,d=(o=(0,r.D)($.g.ANONYMISE_USERS),m=1,function(e){if(Array.isArray(e))return e}(o)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var a,r,s,i,c=[],l=!0,o=!1;try{if(s=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;l=!1}else for(;!(l=(a=s.call(n)).done)&&(c.push(a.value),c.length!==t);l=!0);}catch(e){o=!0,r=e}finally{try{if(!l&&null!=n.return&&(i=n.return(),Object(i)!==i))return}finally{if(o)throw r}}return c}}(o,m)||function(e,t){if(e){if("string"==typeof e)return oe(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?oe(e,t):void 0}}(o,m)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}())[0],p=s.a.useBasicFetch(te.N.currentUser()),g=s.a.useBasicFetch(X.L.config()),v=s.a.useBasicFetch(p.data&&e.classroomId&&re.F.getClassroom(e.classroomId,p.data.id)),h=s.a.useBasicFetch(ee.b.interactiveMetadata(e.interactiveId)),y=s.a.useBasicFetch((null===(t=h.data)||void 0===t?void 0:t.interactiveId)&&ee.b.interactive(h.data.interactiveId)),b=V.B.getAudienceAppLinkParams(),C=V.B.getDateRangeAppLinkParams(),w=Object.assign(Object.assign({},(0,J.wO)((0,J.Hb)(),C)),(0,K.K)(b)),k=(0,G.W)(e.interactiveId,w),I=1===(null===(n=b.classrooms)||void 0===n?void 0:n.length)&&!(null===(c=b.classroomGroups)||void 0===c?void 0:c.length),x=s.a.useBasicFetch(I&&re.F.getClassroomStudents(i.m.first(b.classrooms))),O=s.a.useBasicFetch(ne.u.aggregateEngagement(e.interactiveId,w,p.data.id)),U=s.a.useBasicFetch(p.data&&ne.u.views(w,e.interactiveId,p.data.id)),j=p.data&&g.data&&(!e.classroomId||v.data)&&h.data&&y.data&&k.data&&(!I||x.data)&&O.data&&U.data,T=j&&(0,S.R6)(y.data,k.data,Y.T);if(!j)return a.createElement(a.Fragment,null);var M,H=Object.assign(Object.assign({},b),C),P=function(e,t){return{resultsAppLink:{application:le.O.INSIGHTS,action:ce.e.Insights.INTERACTIVE_RESULTS,args:[e],params:t},questionsAppLink:{application:le.O.INSIGHTS,action:ce.e.Insights.INTERACTIVE_QUESTIONS,args:[e],params:t},heatmapAppLink:{application:le.O.INSIGHTS,action:ce.e.Insights.INTERACTIVE_HEATMAP,args:[e],params:t}}}(e.interactiveId);return a.createElement("div",{className:"px-3"},a.createElement(ie.m,{video:h.data,audienceAppLinkParams:b,dateRangeAppLinkParams:C,tabs:(0,se.kj)(h.data.id,"overview",H)}),a.createElement("section",{className:"mb-5"},a.createElement("h2",{className:"h4"},a.createElement(u.x,{namespace:ue,phrase:"studentResponses"}),a.createElement("span",null,": ",T.completed.length,x.data?"/".concat(x.data.data.length):"")),a.createElement("div",{className:"row g-3"},a.createElement("div",{className:"col-12 col-md"},a.createElement(q,{imageUrl:ae.W.Insights.SPEECH_BUBBLE_ASTERISK,resultsAppLink:P.resultsAppLink,imageCdnUrl:g.data.imageCdnUrl,students:(M=T.markingRequired,M.map((function(e){return e.user}))),anonymiseUsers:d})),I&&a.createElement("div",{className:"col-12 col-md"},a.createElement(Q,{markingRequiredStudents:T.markingRequired,completedStudents:T.completed,notCompletedStudents:T.notCompleted,classroomStudents:x.data.data,imageCdnUrl:g.data.imageCdnUrl,imageUrl:ae.W.Insights.JIGSAW,resultsAppLink:P.resultsAppLink,anonymiseUsers:d})),a.createElement("div",{className:"col-12 col-md"},a.createElement(N,{students:T.completed,imageCdnUrl:g.data.imageCdnUrl,imageUrl:ae.W.Insights.AVATAR,resultsAppLink:P.resultsAppLink,anonymiseUsers:d})))),a.createElement("section",{className:"mb-5"},a.createElement("h2",{className:"h4"},a.createElement(u.x,{namespace:ue,phrase:"studentsPerformance"})),a.createElement("div",{className:"row g-3"},a.createElement("div",{className:"col-12 col-md-6"},a.createElement(_,{redChartImageUrl:ae.W.Insights.RED_CHART,heartImageUrl:ae.W.Insights.SPEECH_BUBBLE_HEART,resultsAppLink:P.resultsAppLink,imageCdnUrl:g.data.imageCdnUrl,students:T.lowScore,completed:T.completed,anonymiseUsers:d})),a.createElement("div",{className:"col-12 col-md-6"},a.createElement(W,{greenChartImageUrl:ae.W.Insights.GREEN_CHART,resultsAppLink:P.resultsAppLink,imageCdnUrl:g.data.imageCdnUrl,students:T.highScore,completed:T.completed,anonymiseUsers:d})),a.createElement("div",{className:"col-12 col-md-6"},a.createElement(R,{interactive:y.data,interactiveMetadata:h.data,results:k.data,questionsAppLink:P.questionsAppLink})),a.createElement("div",{className:"col-12 col-md-6"},a.createElement(L,{interactive:y.data,interactiveMetadata:h.data,results:k.data,questionsAppLink:P.questionsAppLink})))),a.createElement("section",{className:"mb-5"},a.createElement("h2",{className:"h4"},a.createElement(u.x,{namespace:ue,phrase:"classPerformance"})),a.createElement("div",{className:"row g-3"},a.createElement("div",{className:"col-12 col-md-6"},a.createElement(E,{students:T.completed})),a.createElement("div",{className:"col-12 col-md-6"},a.createElement(f,{students:T.completed})),a.createElement("div",{className:"col-12 col-md-6"},a.createElement(A.i,{osCount:null===(l=U.data)||void 0===l?void 0:l.osCount})),a.createElement("div",{className:"col-12 col-md-6"},a.createElement(B.b,{engagement:O.data,heatmapAppLink:P.heatmapAppLink})))))}},94831:(e,t,n)=>{n.d(t,{Z:()=>a});const a={removeRecipient:"mCbMC",recipientItem:"kdcb0",showSpinner:"xH6Mu",avatarContainer:"Zcpg3",recipientDetails:"v5EmV",recipientDetailsWithRemoveButton:"_V928"}}}]);
2
- //# sourceMappingURL=8849-020bfd8cdd-lite.chunk.js.map