diff --git a/caimira/apps/calculator/static/js/co2_form.js b/caimira/apps/calculator/static/js/co2_form.js
index 4618263c..c87739ef 100644
--- a/caimira/apps/calculator/static/js/co2_form.js
+++ b/caimira/apps/calculator/static/js/co2_form.js
@@ -1,245 +1,357 @@
const CO2_data_form = [
- 'CO2_data',
- 'exposed_coffee_break_option',
- 'exposed_coffee_duration',
- 'exposed_finish',
- 'exposed_lunch_finish',
- 'exposed_lunch_option',
- 'exposed_lunch_start',
- 'exposed_start',
- 'fitting_ventilation_states',
- 'fitting_ventilation_type',
- 'infected_coffee_break_option',
- 'infected_coffee_duration',
- 'infected_dont_have_breaks_with_exposed',
- 'infected_finish',
- 'infected_lunch_finish',
- 'infected_lunch_option',
- 'infected_lunch_start',
- 'infected_people',
- 'infected_start',
- 'room_volume',
- 'total_people',
- 'ventilation_type',
- ];
-
- // Method to upload a valid excel file
- function uploadFile(endpoint) {
- clearFittingResultComponent();
- const files = $("#file_upload")[0].files;
- if (files.length === 0) {
- $("#upload-error").show();
- return;
- } else {
- $("#upload-error").hide();
- };
- const file = files[0];
- const extension = file.name.substring(file.name.lastIndexOf(".")).toUpperCase();
- extension === ".XLS" || extension === ".XLSX"
- ? excelFileToJSON(endpoint, file)
- : $('#upload-file-extention-error').show();
+ "CO2_data",
+ "exposed_coffee_break_option",
+ "exposed_coffee_duration",
+ "exposed_finish",
+ "exposed_lunch_finish",
+ "exposed_lunch_option",
+ "exposed_lunch_start",
+ "exposed_start",
+ "fitting_ventilation_states",
+ "fitting_ventilation_type",
+ "infected_coffee_break_option",
+ "infected_coffee_duration",
+ "infected_dont_have_breaks_with_exposed",
+ "infected_finish",
+ "infected_lunch_finish",
+ "infected_lunch_option",
+ "infected_lunch_start",
+ "infected_people",
+ "infected_start",
+ "room_volume",
+ "total_people",
+ "ventilation_type",
+];
+
+// Method to upload a valid excel file
+function uploadFile(endpoint) {
+ clearFittingResultComponent();
+ const files = $("#file_upload")[0].files;
+ if (files.length === 0) {
+ $("#upload-error").show();
+ return;
}
-
- // Method to read excel file and convert it into JSON
- function excelFileToJSON(endpoint, file) {
- try {
- const reader = new FileReader();
- reader.readAsBinaryString(file);
- reader.onload = function (e) {
- const data = e.target.result;
- const workbook = XLSX.read(data, { type: "binary" });
- const firstSheetName = workbook.SheetNames[0];
- const jsonData = XLSX.utils.sheet_to_json(workbook.Sheets[firstSheetName]);
- displayJsonToHtmlTable(endpoint, jsonData);
- };
- } catch (e) {
- console.error(e);
- }
+ const file = files[0];
+ const extension = file.name
+ .substring(file.name.lastIndexOf("."))
+ .toUpperCase();
+ if (extension !== ".XLS" && extension !== ".XLSX") {
+ $("#upload-error")
+ .text("Please select a valid excel file (.XLS or .XLSX).")
+ .show();
+ return;
}
-
- // Method to display the data in HTML Table
- function displayJsonToHtmlTable(endpoint, jsonData) {
- // const table = $("#display_excel_data");
- const format = $("#CO2_data");
- const structure = { times: [], CO2: [] };
- if (jsonData.length > 0) {
- for (let i = 0; i < jsonData.length; i++) {
- const row = jsonData[i];
- structure.times.push(row["Times"]);
- structure.CO2.push(row["CO2"]);
- }
- format.val(JSON.stringify(structure));
- $('#generate_fitting_data').prop("disabled", false);
- $('#fitting_ventilation_states').prop('disabled', false);
- $('[name=fitting_ventilation_type]').prop('disabled', false);
- plotCO2Data(endpoint);
- };
+
+ // FileReader API to read the Excel file
+ const reader = new FileReader();
+ reader.onload = function (event) {
+ const fileContent = event.target.result;
+ const workbook = XLSX.read(fileContent, { type: "binary" });
+
+ // Assuming the first sheet is the one we want to validate
+ const firstSheetName = workbook.SheetNames[0];
+ const worksheet = workbook.Sheets[firstSheetName];
+
+ // Check if the headers match the expected format
+ const headerCoordinates = {
+ Times: "A1",
+ CO2: "B1",
+ };
+ for (const header in headerCoordinates) {
+ const cellValue = worksheet[headerCoordinates[header]]?.v;
+ if (
+ !cellValue ||
+ cellValue.trim().toLowerCase() !== header.toLowerCase()
+ ) {
+ $("#upload-error")
+ .text(`The file does not have the expected header "${header}".`)
+ .show();
+ return;
+ }
+ }
+
+ // Check if there is any data below the header row
+ if (data.length <= 1) {
+ $("#upload-error")
+ .text(
+ "The Excel file is empty. Please make sure it contains data below the header row."
+ )
+ .show();
+ return;
+ }
+
+ // Validate data in the columns
+ const data = XLSX.utils.sheet_to_json(worksheet, { header: 1, raw: false });
+ const timesColumnIndex = 0;
+ const CO2ColumnIndex = 1;
+ for (let i = 1; i < data.length; i++) {
+ try {
+ const timesCellValue = parseFloat(data[i][timesColumnIndex]);
+ const CO2CellValue = parseFloat(data[i][CO2ColumnIndex]);
+
+ if (isNaN(timesCellValue) || isNaN(CO2CellValue)) {
+ throw new Error("Invalid data in the Times or CO2 columns.");
+ }
+ } catch (error) {
+ $("#upload-error")
+ .text(
+ "Invalid data in the Times or CO2 columns. Please make sure they contain only float values."
+ )
+ .show();
+ return;
+ }
+ }
+
+ // Call function to convert Excel file to JSON and further processing
+ try {
+ generateJSONStructure(endpoint, data);
+ // If all validations pass, process the file here or display a success message
+ $("#upload-file-extention-error").hide();
+ } catch (error) {
+ console.log(error);
+ }
+ };
+ reader.readAsBinaryString(file); // Read the file as a binary string
+}
+
+// Method to generate the JSON structure
+function generateJSONStructure(endpoint, jsonData) {
+ const inputToPopulate = $("#CO2_data");
+
+ // Initialize the final structure
+ const finalStructure = { times: [], CO2: [] };
+
+ if (jsonData.length > 0) {
+ // Loop through the input dataArray and extract the values starting from the second array (index 1)
+ for (let i = 1; i < jsonData.length; i++) {
+ const arr = jsonData[i];
+ // Assuming arr contains two float values
+ finalStructure.times.push(parseFloat(arr[0]));
+ finalStructure.CO2.push(parseFloat(arr[1]));
+ }
+ inputToPopulate.val(JSON.stringify(finalStructure));
+ $("#generate_fitting_data").prop("disabled", false);
+ $("#fitting_ventilation_states").prop("disabled", false);
+ $("[name=fitting_ventilation_type]").prop("disabled", false);
+ plotCO2Data(endpoint);
}
-
- // Method to download Excel template available on CERNBox
- function downloadTemplate(uri = 'https://caimira-resources.web.cern.ch/CO2_template.xlsx', filename = 'CO2_template.xlsx') {
- const link = document.createElement("a");
- link.download = filename;
- link.href = uri;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- delete link;
+}
+
+// Method to download Excel template available on CERNBox
+function downloadTemplate(
+ uri = "https://caimira-resources.web.cern.ch/CO2_template.xlsx",
+ filename = "CO2_template.xlsx"
+) {
+ const link = document.createElement("a");
+ link.download = filename;
+ link.href = uri;
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ delete link;
+}
+
+function insertErrorFor(referenceNode, text) {
+ const element = $("")
+ .addClass("error_text text-danger")
+ .html(" " + text);
+ $(referenceNode).before(element);
+}
+
+function validateFormInputs(obj) {
+ $("span.error_text").remove();
+ let submit = true;
+ for (let i = 0; i < CO2_data_form.length; i++) {
+ const element = $(`[name=${CO2_data_form[i]}]`)[0];
+ if (element.name !== "fitting_ventilation_states" && element.value === "") {
+ insertErrorFor(
+ $("#DIVCO2_data_dialog"),
+ `'${element.name}' must be defined.
`
+ );
+ submit = false;
+ }
}
-
- function insertErrorFor(referenceNode, text) {
- const element = $('').addClass('error_text text-danger').html(' ' + text);
- $(referenceNode).before(element);
+ if (submit) {
+ $($(obj).data("target")).modal("show");
+ $("#upload-error").hide();
+ $("#upload-file-extention-error").hide();
}
-
- function validateFormInputs(obj) {
- $('span.error_text').remove();
- let submit = true;
- for (let i = 0; i < CO2_data_form.length; i++) {
- const element = $(`[name=${CO2_data_form[i]}]`)[0];
- if (element.name !== 'fitting_ventilation_states' && element.value === '') {
- insertErrorFor($('#DIVCO2_data_dialog'), `'${element.name}' must be defined.
`);
- submit = false;
- }
- }
- if (submit) {
- $($(obj).data('target')).modal('show');
- $("#upload-error").hide();
- $('#upload-file-extention-error').hide();
- }
- return submit;
- }
+ return submit;
+}
function validateCO2Form() {
- let submit = true;
- if (validateFormInputs($('#button_fit_data'))) submit = true;
-
- // Check if natural ventilation is selected
- if ($('input[name="fitting_ventilation_type"]:checked')[0].value == 'fitting_natural_ventilation') {
- // Validate ventilation scheme
- const element = $('[name=fitting_ventilation_states')[0]
- if (element.value !== '') {
- // validate input format
- try {
- const parsedValue = JSON.parse(element.value);
- if (!Array.isArray(parsedValue)) {
- insertErrorFor($('#DIVCO2_fitting_result'), `'${element.name}' must be a list.`);
- submit = false;
- };
- } catch {
- insertErrorFor($('#DIVCO2_fitting_result'), `'${element.name}' must be a list of numbers.`);
- submit = false;
- };
- } else {
- insertErrorFor($('#DIVCO2_fitting_result'), `'${element.name}' must be defined.`);
- submit = false;
- };
- };
+ let submit = true;
+ if (validateFormInputs($("#button_fit_data"))) submit = true;
- return submit;
+ // Check if natural ventilation is selected
+ if (
+ $('input[name="fitting_ventilation_type"]:checked')[0].value ==
+ "fitting_natural_ventilation"
+ ) {
+ // Validate ventilation scheme
+ const element = $("[name=fitting_ventilation_states")[0];
+ if (element.value !== "") {
+ // validate input format
+ try {
+ const parsedValue = JSON.parse(element.value);
+ if (!Array.isArray(parsedValue)) {
+ insertErrorFor(
+ $("#DIVCO2_fitting_result"),
+ `'${element.name}' must be a list.`
+ );
+ submit = false;
+ }
+ } catch {
+ insertErrorFor(
+ $("#DIVCO2_fitting_result"),
+ `'${element.name}' must be a list of numbers.`
+ );
+ submit = false;
+ }
+ } else {
+ insertErrorFor(
+ $("#DIVCO2_fitting_result"),
+ `'${element.name}' must be defined.`
+ );
+ submit = false;
+ }
+ }
+
+ return submit;
}
function displayTransitionTimesHourFormat(start, stop) {
- var minutes_start = (start % 1 * 60).toPrecision(2);
- var minutes_stop = (stop % 1 * 60).toPrecision(2);
- return Math.floor(start) + ':' + ((minutes_start != '0.0') ? minutes_start : '00') + ' - ' + Math.floor(stop) + ':' + ((minutes_stop != '0.0') ? minutes_stop : '00');
+ var minutes_start = ((start % 1) * 60).toPrecision(2);
+ var minutes_stop = ((stop % 1) * 60).toPrecision(2);
+ return (
+ Math.floor(start) +
+ ":" +
+ (minutes_start != "0.0" ? minutes_start : "00") +
+ " - " +
+ Math.floor(stop) +
+ ":" +
+ (minutes_stop != "0.0" ? minutes_stop : "00")
+ );
}
function displayFittingData(json_response) {
- $("#DIVCO2_fitting_result").show();
- $("#CO2_data_plot").attr("src", json_response['CO2_plot']);
- // Not needed for the form submission
- delete json_response['CO2_plot'];
- $("#CO2_fitting_result").val(JSON.stringify(json_response));
- $("#exhalation_rate_fit").html('Exhalation rate: ' + String(json_response['exhalation_rate'].toFixed(2)) + ' m³/h');
- let ventilation_table = "