{"version":3,"file":"helpers.643d6d92.js","sources":["../../../frontend/features/admin/utils/helpers.js"],"sourcesContent":["// Utilities\nimport { renderMarkdown } from 'common/utils/helpers';\n\nconst extractYoutubeId = (value) => {\n const exp =\n /^(https?:\\/\\/)?((www\\.)?(youtube(-nocookie)?|youtube.googleapis)\\.com.*(v\\/|v=|vi=|vi\\/|e\\/|embed\\/|user\\/.*\\/u\\/\\d+\\/)|youtu\\.be\\/)([_0-9a-z-]{11})/i;\n const match = value.match(exp);\n return match ? match[7] : null;\n};\n\nconst isValidYoutubeId = (value) => /^[_0-9a-z-]{11}$/i.test(value);\n\nconst embedYoutubeVideo = (id) =>\n ``;\n\nexport const displayYoutubePreview = (targetInput) => {\n const $target = $(targetInput);\n const youtubeId = extractYoutubeId($target.val());\n\n if (youtubeId) {\n $target.val(youtubeId);\n }\n\n const previewId = $target.val() || $target.attr('placeholder');\n\n if (isValidYoutubeId(previewId)) {\n $target.addClass('is-success');\n\n if (!$target.next('.youtube-preview').length) {\n $target.after('
');\n }\n\n $target.next('.youtube-preview').html(embedYoutubeVideo(previewId));\n } else {\n $target.removeClass('is-success');\n $target.next('.youtube-preview').html('');\n }\n};\n\nexport const renderEditor = (element) => {\n const disabled =\n $(element).closest('fieldset').hasClass('is-locked') || $(element).attr('disabled');\n\n const editor = new SimpleMDE({\n element,\n spellChecker: false,\n toolbar: [\n 'heading',\n 'bold',\n 'italic',\n 'link',\n 'ordered-list',\n 'unordered-list',\n 'table',\n ...(disabled ? [] : ['|', 'preview']),\n ],\n status: false,\n forceSync: true,\n previewRender: renderMarkdown,\n });\n\n editor.codemirror.on('change', () => {\n window.shouldShowExitPageConfirm = true;\n });\n\n $(element)\n .wrap('')\n .on('focus', (event) => {\n event.preventDefault();\n editor.codemirror.scrollIntoView();\n editor.codemirror.focus();\n });\n\n if (disabled) {\n editor.togglePreview();\n $(editor.gui.toolbar).addClass('disabled-for-preview');\n }\n\n return editor;\n};\n\n/**\n * Transform backend coordinate responses into simple array with updatedAt timestamp included\n * @param {Array} responses\n * @returns {Array}\n */\nexport const flattenCoordinateResponses = (responses) =>\n responses.reduce(\n (dataAccumulator, { answer, updatedAt }) => [\n ...dataAccumulator,\n ...Object.values(answer).reduce(\n (answerAccumulator, { value }) => [\n ...answerAccumulator,\n ...value.map((answerValue) => ({\n ...answerValue,\n updatedAt,\n })),\n ],\n []\n ),\n ],\n []\n );\n\nexport const renderNotification = (message, success = true) => {\n document.querySelectorAll('.admin-notification').forEach((el) => el.remove());\n const classList = [\n 'admin-notification',\n 'hero',\n 'is-medium',\n 'has-text-centered',\n 'has-text-white',\n ];\n const successOrAlert = success ? ['notice', 'is-primary'] : ['alert', 'is-warning'];\n classList.push(...successOrAlert);\n const element = document.createElement('div');\n element.classList.add(...classList);\n element.innerText = message;\n document.body.prepend(element);\n window.scrollTo({ top: 0, behavior: 'smooth' });\n};\n\n// Checks if number is between start and up to, but not including, end.\nexport const inRange = (number, start, end, includeEnd = false) => {\n if (includeEnd) return number >= start && number <= end;\n return number >= start && number < end;\n};\n\nexport const medianFn = (arr) => {\n const mid = Math.floor(arr.length / 2);\n const nums = [...arr].sort((a, b) => a - b);\n return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;\n};\n\n/* eslint-disable no-param-reassign */\nexport const modeFn = (numbers) => {\n const hash = numbers.reduce((hsh, current) => {\n if (hsh[current] === undefined) {\n hsh[current] = 1;\n } else {\n hsh[current] += 1;\n }\n return hsh;\n }, {});\n const maxValue = Math.max(...Object.values(hash));\n return Object.keys(hash).find((key) => hash[key] === maxValue);\n};\n/* eslint-enable no-param-reassign */\n\n// Javascript program to calculate the standered deviation of an array\nexport const devFn = (arr) => {\n // Creating the mean with Array.reduce\n const mean =\n arr.reduce((acc, curr) => {\n return acc + curr;\n }, 0) / arr.length;\n\n // Assigning (value - mean) ^ 2 to every array item\n const arr2 = arr.map((k) => {\n return (k - mean) ** 2;\n });\n\n // Calculating the sum of updated array\n const sum = arr2.reduce((acc, curr) => acc + curr, 0);\n\n // Calculating the variance\n // let variance = sum / arr.length\n\n // Returning the Standered deviation\n return Math.sqrt(sum / arr.length);\n};\n\nconst singleDigitBins = (data, start, end) => {\n const sanitizedData = [];\n const csvData = [];\n for (let i = Math.floor(start); i <= end; i += 1) {\n const label = i.toString();\n const filtered = data.filter((value) => Number(value) === i);\n const count = filtered.length;\n const percentage = (count / data.length) * 100;\n csvData.push([label, count, percentage]);\n sanitizedData.push({ label, count, percentage });\n }\n return { sanitizedData, csvData };\n};\n\nconst rangeBins = (data, start, end, decimalDigits) => {\n const rangeDifference = end - start;\n const numberOfBins = 10;\n const rangeIncrement = rangeDifference / numberOfBins;\n const strRangeIncrement = String(rangeIncrement);\n const decimalPlaces = strRangeIncrement.includes('.')\n ? strRangeIncrement.split('.')[1].length\n : 0;\n const sanitizedData = [];\n const csvData = [];\n const smallestDecimalPlace =\n Number(decimalDigits) > decimalPlaces ? Number(decimalDigits) : decimalPlaces;\n const unit = 1 / 10 ** smallestDecimalPlace;\n\n for (let i = 0; i < numberOfBins; i += 1) {\n const starting = Number(start) + rangeIncrement * i;\n let ending = Number(start) + rangeIncrement * (i + 1);\n const lastBin = i === numberOfBins - 1;\n if (!lastBin) ending -= unit;\n const label = `${starting.toFixed(smallestDecimalPlace)} - ${ending.toFixed(\n smallestDecimalPlace\n )}`;\n const filtered = data.filter((value) => inRange(value, starting, ending, true));\n const count = filtered.length;\n const percentage = parseFloat(((count / data.length) * 100).toFixed(2));\n csvData.push([label, count, percentage]);\n sanitizedData.push({ label, count, percentage });\n }\n return { sanitizedData, csvData };\n};\n\nexport const createNumericTableAndCsvData = (data, rangeStart, rangeEnd, decimalDigits) => {\n if (!data) return {};\n const rangeDifference = rangeEnd - rangeStart;\n const useSingleDigitBins = rangeDifference <= 10 && decimalDigits === '0';\n const { sanitizedData, csvData } = useSingleDigitBins\n ? singleDigitBins(data, rangeStart, rangeEnd)\n : rangeBins(data, rangeStart, rangeEnd, decimalDigits);\n return { sanitizedData, csvData };\n};\n\n/**\n * Switch language\n * @param {string} targetLanguage\n */\nexport const switchLanguage = (targetLanguage) => {\n const currentPath = window.location.pathname;\n const pathSplit = currentPath.split('/');\n if (pathSplit[1] === 'admin') {\n pathSplit.splice(1, 0, targetLanguage);\n } else {\n pathSplit[1] = targetLanguage;\n }\n const newPath = pathSplit.join('/');\n // eslint-disable-next-line no-alert\n const confirm = window.confirm(\n 'Please save your data before switching languages. All unsaved data will be lost. Do you want to proceed ?'\n );\n if (confirm) {\n window.location.pathname = newPath;\n }\n};\n\nexport function addNotice(message) {\n const noticeRoot = document.querySelector('#react-admin-notice');\n if (!noticeRoot) return;\n const noticeElement = document.createElement('div');\n noticeElement.classList.add(\n 'notice',\n 'hero',\n 'is-medium',\n 'is-info',\n 'has-text-centered',\n 'has-text-white'\n );\n noticeElement.innerHTML = message;\n noticeRoot.appendChild(noticeElement);\n}\n\nexport function navigateTo(path) {\n window.location.pathname = path;\n}\n"],"names":["extractYoutubeId","value","exp","match","isValidYoutubeId","embedYoutubeVideo","id","displayYoutubePreview","targetInput","$target","youtubeId","previewId","renderEditor","element","disabled","editor","renderMarkdown","event","renderNotification","message","success","el","classList","successOrAlert","inRange","number","start","end","includeEnd","singleDigitBins","data","sanitizedData","csvData","label","count","percentage","rangeBins","decimalDigits","rangeDifference","numberOfBins","rangeIncrement","strRangeIncrement","decimalPlaces","smallestDecimalPlace","unit","i","starting","ending","createNumericTableAndCsvData","rangeStart","rangeEnd","useSingleDigitBins","switchLanguage","targetLanguage","pathSplit","newPath","addNotice","noticeRoot","noticeElement","navigateTo","path"],"mappings":"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"}