Work On Flickerbook Holiday Summary

I have written JavaScript functions that are responsible for generating holiday summary table and loading it with data. Below is a function that performs AJAX call and fetches the data from back end.

const loadHolidaySummary = () => {
	if (XMLHttpRequest){
               request = new XMLHttpRequest();
	} else if (ActiveXObject){
	       request = new ActiveXObject("Microsoft.XMLHTTP");
	} else {return false;}
	request.open("POST", "loadHolidaySummary.php", true);
	request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	request.onreadystatechange = function(){
		if(request.readyState == 4 && request.status == 200){
			let response = JSON.parse(this.responseText);
	
			//errors here are unlikely to happen
			let errorsArrayLength = Object.keys(response.errors).length;
			if (response.sessionIsSet === false){$('#notLoggedInModal').modal('show');notLoggedIn();}
			else {
				if (errorsArrayLength>0){
					for (let i=0; i<errorsArrayLength; i++)	{
						$("#holidaySummaryBody").addClass("errorStyle TAC");
						let errorText = '<br>';
						errorText += response.errors[i];
						errorText += '<br>';
						holidaySummaryBody.innerHTML = errorText;
					}
				} else {
					//generate holiday summary table
					populatedHolidaySummaryTable(response);
				}
			}
		} else if(request.readyState==4 && request.status==0 ) {
			notConnectedError();
		} else {}
	}
	request.send();
}

Apart from JavaScript, I have also amended HTML code. Right after the table that stores holiday summary I’ve added a button that copies all table once it is clicked. Additional HTML code for this button is below:

<div class="row PTB1">
	<div class="col-md-3 hidden-xs"></div>
	<div class="col-md-6 col-xs-12">
		<div class="col-sm-9 col-xs-8 rDiv" id="copyHolSumTableResponse"></div>
		<div class="col-sm-3 col-xs-4">
			<button type="button" class="btn btn-success btn-lg button bSh" id="copyHolSumTable">Copy Table</button>
		</div>
	</div>
</div>

Then I wrote a function to generate table, a function to copy table and 4 more functions that are used to avoid repetitive code. The functions that generate summary table and copy table are demonstrated below:

const copyTable = (table, responseDiv) => {
	// Select the table contents
	let range = document.createRange();
	range.selectNodeContents(table);
	window.getSelection().removeAllRanges();
	window.getSelection().addRange(range);
	// Copy the table contents
	document.execCommand("copy");
	// Deselect the table contents
	window.getSelection().removeAllRanges();
	responseDiv.textContent = 'Table Copied!';
	setTimeout(function(){responseDiv.textContent=" ";},1500);
}	

const populatedHolidaySummaryTable = response => {
	let holidaySummaryTable = document.getElementById('holidaySummaryTable');
	//first clear the table.
	holidaySummaryTable.innerHTML = "";
	//a table row to insert "Holidays Used" heading
	holidaysUsedBookedTR(holidaySummaryTable, "Holidays Used");
	//a table row to insert "Days" and "Date" heading
	tableRowForDateAndDays(holidaySummaryTable);
	//if holidays have been used add them to the table, else add a table row that informs the user that no holidays have been used.
	let usedHolidayCount = Object.keys(response.usedHolidaysArray).length;
	if (usedHolidayCount>0){
		for(let i=0; i<usedHolidayCount;i++) {
                        //call a function that created table row with 2 td elements that store date and day value.
			createTRForHolidaysTable(holidaySummaryTable, "holidayUsedColor", response.usedHolidaysArray[i]["holidayDate"], response.usedHolidaysArray[i]["holidayValue"]);
		}
	} else {
		//insert message that informs user that no holidays have been used.
		createTRForHolidaysTable(holidaySummaryTable, "holidayUsedColor", "No used holidays", 0);
	}
	//a row that shows the number of total holidays used
	tableRowForHolSummaryTotals(holidaySummaryTable, "Total Holidays Used", response.holidaysUsed);

	//BOOKED HOLIDAYS TABLE PART
	//a table row to insert "Holidays Used" heading
	holidaysUsedBookedTR(holidaySummaryTable, "Holidays Booked");
	//a table row to insert "Days" and "Date" heading
	tableRowForDateAndDays(holidaySummaryTable);
	let bookedHolidayCount = Object.keys(response.bookedHolidaysArray).length;
	if (bookedHolidayCount>0){
		for(let i=0; i<bookedHolidayCount;i++) {
                         //call a function that created table row with 2 td elements that store date and day value.
			createTRForHolidaysTable(holidaySummaryTable, "holidayBookedColor", response.bookedHolidaysArray[i]["holidayDate"], response.bookedHolidaysArray[i]["holidayValue"]);
		}
	} else {
		//insert message that informs user that no holidays have been booked.
		createTRForHolidaysTable(holidaySummaryTable, "holidayBookedColor", "No booked holidays", 0);	
	}
	//a row that shows the number of total holidays booked
	tableRowForHolSummaryTotals(holidaySummaryTable, "Total Holidays Booked", response.holidaysBooked);
	//a row that shows the number of total holidays available
	tableRowForHolSummaryTotals(holidaySummaryTable, "Total Holidays Available", response.availableHolidays);
	//Activate copy table button
	let responseDiv = document.getElementById("copyHolSumTableResponse");
	let copyTableButton = document.getElementById("copyHolSumTable");
	copyTableButton.onclick = function () { copyTable(holidaySummaryTable, responseDiv);}
	
}

As table rows in his summary table are repetitive: there are 2 heading rows, 2 sub heading rows, 3 rows that show holidays used, booked and available, and a variable number of rows that store dates when holidays where used. To avoid writing repetitive code, I created these functions below:

//a table row to insert the date for holiday and used holiday day value
const createTRForHolidaysTable = (holidaySummaryTable, color, date, dayValue) =>{
	let tableRow = document.createElement("tr");
	//table width 80% and 20% gets inherrited so no need to add these classess!
	let tableData = document.createElement("td");
	tableData.setAttribute("class", color);
	tableData.textContent = date;
	tableRow.appendChild(tableData);
	
	let tableData2 = document.createElement("td");
	tableData2.setAttribute("class", color);
	tableData2.textContent = dayValue;
	
	tableRow.appendChild(tableData2);
	holidaySummaryTable.appendChild(tableRow);

}
//a table row to insert "Holidays Used" heading
const holidaysUsedBookedTR = (holidaySummaryTable, titleText) => {
	let holidaysUsedHeading = document.createElement("tr");
	let tableDataUsedHolidaysHeading = document.createElement("td");
	tableDataUsedHolidaysHeading.setAttribute("colspan", "2");
	tableDataUsedHolidaysHeading.textContent = titleText;
	
	holidaysUsedHeading.appendChild(tableDataUsedHolidaysHeading);
	holidaySummaryTable.appendChild(holidaysUsedHeading);
	
}
//a table row to insert "Days" and "Date" heading
const tableRowForDateAndDays = holidaySummaryTable=> {
	let holidaysUsedSubHeading = document.createElement("tr");
	let tableDataSubHeading1 = document.createElement("td");
	tableDataSubHeading1.setAttribute("class", "width80");
	tableDataSubHeading1.textContent = "Date";
	holidaysUsedSubHeading.appendChild(tableDataSubHeading1);
	
	let tableDataSubHeading2 = document.createElement("td");
	tableDataSubHeading2.setAttribute("class", "width20");
	tableDataSubHeading2.textContent = "Days";
	holidaysUsedSubHeading.appendChild(tableDataSubHeading2);
	
	holidaySummaryTable.appendChild(holidaysUsedSubHeading);
	
}
//a table row to insert total holidays used, booked or available.
const tableRowForHolSummaryTotals = (holidaySummaryTable, totalsText, totalsDays) => {
	let totalHolidaysUsedRow = document.createElement("tr");
	let totalHolidaysUsedTD1 = document.createElement("td");
	totalHolidaysUsedTD1.setAttribute("class", "width80 TARI");
	totalHolidaysUsedTD1.textContent = totalsText;
	totalHolidaysUsedRow.appendChild(totalHolidaysUsedTD1);
	
	let totalHolidaysUsedTD2 = document.createElement("td");
	totalHolidaysUsedTD2.setAttribute("class", "width20");
	totalHolidaysUsedTD2.textContent = totalsDays;
	totalHolidaysUsedRow.appendChild(totalHolidaysUsedTD2);
	
	holidaySummaryTable.appendChild(totalHolidaysUsedRow);
}

And once finished I get the table I have desired. Below is an example of table that I have generated using this new feature, then copied it using the “Copy table” button and send it via email.

Holiday summary table from email.

However, while coding JavaScript, I have realised that it could be done even better. For example some holidays are consecutive, so instead of showing them in table like this:

Consecutive holidays.

It would be a lot more helpful if in “Date” field it would display the start and end date for consecutive days, and in the “Days” field a total number of holidays used for this period like this:

Concatenating consecutive dates.

This would look a lot more like how we write down the days on our holiday passports. I believe this can be achieved, but it will require some work on the PHP file 😉

Leave a Reply

Your email address will not be published. Required fields are marked *