+
diff --git a/marlo-web/src/main/webapp/crp/css/home/dashboard.css b/marlo-web/src/main/webapp/crp/css/home/dashboard.css
index 43df02e1ce..931f4960ab 100644
--- a/marlo-web/src/main/webapp/crp/css/home/dashboard.css
+++ b/marlo-web/src/main/webapp/crp/css/home/dashboard.css
@@ -211,6 +211,8 @@ div#impactGraphic-fullscreen {
height: 100%;
}
+ /*************** Timeline ********************/
+
span.leftControl {
left: 5px;
}
@@ -411,6 +413,143 @@ span.timelineControl:hover {
height: 50px;
align-self: center;
}
+
+ #timelineContainer {
+ position: relative;
+ margin: 18px 30px 18px 30px;
+ scroll-behavior: smooth;
+ overflow-x: scroll;
+ overflow-y: hidden;
+ height: 28vh;
+ width: 80vw;
+ margin: 0 auto;
+ }
+
+ #timelineContainer::-webkit-scrollbar {
+ -webkit-appearance: none;
+ }
+
+ #timelineDescription{
+ display: flex;
+ justify-content: space-between;
+ padding: 18px 30px 18px 30px;
+ width: 100%;
+ align-items: baseline;
+ }
+
+ #timelineDescription_title{
+ font-size: 2.0em;
+ color: #333;
+ }
+
+ #timelineDescription_range{
+ font-size: 1.5rem;
+
+ }
+
+ #timeline_times {
+ display: flex;
+ width: max-content;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 5px 0;
+ position: absolute;
+ }
+
+ #timeline_activities {
+ position: relative;
+ }
+
+ #timeline_today {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 2px;
+ height: 100%;
+ background-color: red;
+ border-radius: 5px;
+ }
+
+ .timebox {
+ height: 144px;
+ position: relative;
+ text-align: center;
+ border-right: 1px dashed #CCCCCC;
+ border-left: 1px dashed #CCCCCC;
+ }
+
+ .timeNumber{
+ margin: 1.5px;
+ }
+
+ .activityCard {
+ position: relative;
+ }
+
+ .activityCard_container{
+ position: absolute;
+ display: flex;
+ padding: 0.5rem;
+ flex-direction: column;
+ gap: 0.5rem;
+ flex-shrink: 0;
+ border-radius: 0.75rem;
+ background: #E8F4FF;
+ margin-bottom: 1rem;
+ }
+
+ .activityCard_content{
+ display: inline-flex;
+ flex-direction: column;
+ gap: 0.25rem;
+ left: 0;
+ overflow: hidden;
+ padding: 4px 6px;
+ position: sticky;
+ max-width: max-content;
+ }
+
+ .activityCard_description {
+ overflow: hidden;
+ color: #000;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 1.5rem;
+ font-style: normal;
+ font-weight: 400;
+ margin: 0;
+ }
+
+ .activityCard_details{
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ max-width: max-content;
+ gap: 2rem;
+ }
+
+ .activityCard_details div{
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ }
+
+ .activityCard_details p{
+ font-size: 1rem;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 0.75rem;
+ margin: 0;
+ }
+
+ .activityCard:nth-child(even){
+ top: 108px;
+ }
+
+ .activityCard:nth-child(odd){
+ top: 48px;
+ }
+
/*************** sectionMap ********************/
diff --git a/marlo-web/src/main/webapp/crp/js/home/dashboard.js b/marlo-web/src/main/webapp/crp/js/home/dashboard.js
index bbe7b4146a..fd64c839e4 100644
--- a/marlo-web/src/main/webapp/crp/js/home/dashboard.js
+++ b/marlo-web/src/main/webapp/crp/js/home/dashboard.js
@@ -17,7 +17,10 @@ function initDashboard() {
$('.loadingBlock').hide().next().fadeIn(500);
getTimeline();
- createTimeline();
+ createTimeline2();
+ $(".timelineRefresh").hide();
+ $(".timeline").show();
+ setTimelinePosition();
$('.buttonRightTimeline').on("click", moveScrollRight);
@@ -148,105 +151,197 @@ function locateContentDialog(id){
}
function moveScrollRight() {
- const element = document.querySelector(".scroll-x-containerTimeline");
- element.scrollLeft += 200;
+ const element = document.getElementById("timelineContainer");
+ const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
+ const containerSize = vw * 0.8;
+
+ element.scrollLeft += containerSize;
}
function moveScrollLeft() {
- const element = document.querySelector(".scroll-x-containerTimeline");
- element.scrollLeft -= 200;
+ const element = document.getElementById("timelineContainer");
+ const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
+ const containerSize = vw * 0.8;
+
+ element.scrollLeft -= containerSize;
+}
+
+const convertDateToAfricanDate = (date) => {
+ const africanOptions = { timeZone: 'Africa/Nairobi', month: 'short', day: 'numeric', year: "numeric" };
+ return new Date(date.toLocaleString('en-US', africanOptions));
+}
+const convertDateToText = (date, withYear) => {
+ return new Date(date).toLocaleString('default', withYear? { timeZone: 'Africa/Nairobi', month: 'short', day: 'numeric', year: "numeric" } : { timeZone: 'Africa/Nairobi', month: 'short', day: 'numeric' });
}
-function createTimeline() {
- var counter = 0;
- var counterActvi = 0;
- var previusDate;
- var linePorcent;
- var lastPosition = timelineElements.length;
-
- // iterate timeline elements
- timelineElements.forEach(function(data,index){
- var listItemTimeline=document.getElementById("listItemTimeline");
- var newDiv= document.createElement("div")
- newDiv.className='infTimelineTimeline';
- listItemTimeline.appendChild(newDiv);
- var newDivTitle= document.createElement("span")
- newDivTitle.className='titleTimeline';
- newDiv.appendChild(newDivTitle)
- var newDivPoint= document.createElement("div")
- newDivPoint.className='timeline-pointTimeline';
- newDiv.appendChild(newDivPoint)
- var newPorcentTimeLine= document.createElement("div")
- newDiv.appendChild(newPorcentTimeLine)
- var newDivTimeLine= document.createElement("div")
- newDivTimeLine.className='timeline-line';
- newDiv.appendChild(newDivTimeLine)
- var newPTimeLine= document.createElement("p")
- newPTimeLine.className='dateTimeline';
- newDiv.appendChild(newPTimeLine)
- var options = {timeZone: 'Africa/Nairobi', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric'};
- var africaOpciones = { timeZone: 'Africa/Nairobi', day: 'numeric' };
- var africanDate = new Date(new Date().toLocaleString('en-US', options));
-
- var description = document.createTextNode(data.description);
- var dateMonthStart = new Date(data.startDate).toLocaleString("en-US", { month: "short" });
- var dateDayStart = new Date(data.startDate).getDate()+1;
- var dateMonthYear =new Date(data.endDate).getFullYear();
- var dateMonthEnd = new Date(new Date(data.endDate).toLocaleString('en-US', options)).toLocaleString("en-US", { month: "short" });
- var dateDayEnd = new Date(data.endDate).toLocaleString('en-US', africaOpciones);
- var date =document.createTextNode(dateMonthEnd+' '+ dateDayEnd+' - '+dateMonthYear)
- newDivTitle.appendChild(description);
- newPTimeLine.appendChild(date);
- var endDate = new Date(new Date(data.endDate).toLocaleString('en-US', options));
- endDate.setDate(endDate.getDate() + 1)
-
- if(description.length > 120)newDivTitle.style["width"] = '120px';
-
- //hide alert the days left to finalize activity
- if(((lastPosition - 1) == index) && endDate < africanDate )$('.timelineAlert').hide();
-
- var closingTime = new Date(africanDate.setHours(africanDate.getHours() + 1));
-
- if(endDate < closingTime){
-
- var newImgTimeLine= document.createElement("img");
- newImgTimeLine.className='imgTimeline';
- newImgTimeLine.setAttribute("src",baseURL +"/global/images/icon-check-tiny-white.png")
- newDivPoint.appendChild(newImgTimeLine);
- newDivTitle.classList.add('timelineColorSuccess');
- newDivPoint.classList.add('timelineBackSuccess');
- newDivTimeLine.classList.add('timelineBackSuccess');
- previusDate=data.endDate;
- counterActvi =counterActvi+1
+const getAbsoluteDays = (startDate, endDate) => {
+ const oneDay = 24 * 60 * 60 * 1000;
+ return Math.round(Math.abs((new Date(startDate) - new Date(endDate)) / oneDay));
+};
+
+const getFirstAndLastDates = (dates) => {
+ const sortDatesByStart = dates.map(date => Date.parse(date.startDate)).sort((a, b) => a - b);
+ const sortDatesByEnd = dates.map(date => Date.parse(date.endDate)).sort((a, b) => a - b);
+ return {
+ firstDate: sortDatesByStart[0],
+ lastDate: sortDatesByEnd[sortDatesByEnd.length - 1]
+ };
+}
+function getDateBasedOnASumOfDays(startDate, days) {
+ const newDate = new Date(startDate);
+ newDate.setDate(newDate.getDate() + days);
+ return newDate;
+}
+
+function createDivTimes(totalDays, divClass, divIdPrefix){
+ let arrayDays = [];
+ for(let i=0; i < totalDays+1; i++){
+ let newDiv = document.createElement('div');
+ newDiv.id = `time_${i}`
+ newDiv.className = divClass;
+ newDiv.style.width = setWidth();
+ newDiv.innerHTML = `
+
+ `;
+ arrayDays.push(newDiv);
+ }
+ return arrayDays;
+}
+
+function createDivActivities(activity, id){
+
+ const status = setStatus(activity.startDate,activity.endDate);
+ const card = document.createElement('div');
+ card.className = 'activityCard';
+ card.id = `activityCard_${id}`;
+ card.innerHTML = `
+
+
+
+
${activity.description}
+
+
+

+
Start date: ${activity.startDate}
+
+
Status: ${status}
+
+

+
End date: ${activity.endDate}
+
+
+
+
+ `;
+
+ return card;
+}
+
+const setStatus = (startDate, endDate) => {
+ const today = convertDateToAfricanDate(new Date());
+ const dateStatus = {
+ "Completed": today > new Date(endDate),
+ "In progress": today > new Date(startDate) && today < new Date(endDate),
+ "Not started": today < new Date(startDate)
+ };
+
+ const entries = Object.entries(dateStatus);
+ for (let i = 0; i < entries.length; i++) {
+ const [status, value] = entries[i];
+ if (value) {
+ return status;
}
- // Define the color and percentage of the bar
- if(counter == 0 && (endDate > africanDate)){
-
- let dateDiff = endDate.getTime() - new Date(previusDate).getTime();
- let daysFinalizeActivity = ((endDate.getTime() - africanDate.getTime())/(1000*60*60*24));
- newPorcentTimeLine.className='porcentTimeLine';
- newDivTitle.classList.add('timelineColorAlert');
- newDivPoint.classList.add('timelineBackAlert');
-
- linePorcent = -(daysFinalizeActivity*100)/(dateDiff/(1000*60*60*24))+100;
- newDivTimeLine.style["margin-top"] = "0";
- newPorcentTimeLine.style["width"] = Math.round(linePorcent)+'%';
- if(linePorcent < 0) newPorcentTimeLine.style["width"] = Math.round(0)+'%';
- newPorcentTimeLine.appendChild(newDivTimeLine);
- let textAlert ='';
- textAlert = Math.round(daysFinalizeActivity+1)+' day left to finalize the current activity';
- if(Math.round(daysFinalizeActivity+1)>1) textAlert = Math.round(daysFinalizeActivity+1)+' days left to finalize the current activity';
- counter = 1;
- $('.timelineAlertText').text(textAlert);
- }
- })
- $(".timelineRefresh").hide();
- $(".timeline").show();
- // Locate pending activity
- const element = document.querySelector(".scroll-x-containerTimeline");
- element.scrollLeft += 243*(counterActvi-2);
+ }
+}
+
+const setStatusColor = (status) => {
+ const colorStatus = {
+ "Completed": "#B5D08B",
+ "In progress": "#81B8C1",
+ "Not started": "#F9C786"
+ };
+
+ return colorStatus[status];
+}
+
+function setWidth(amount) {
+ return `calc(${amount !==undefined? (amount === 0? 3: amount+1)+"*(80vw / 7))": "calc(80vw / 7)"}`;
+}
+
+function setDistances(startDate,isToday, isJS) {
+ const today = convertDateToAfricanDate(new Date());
+ today.setDate(today.getDate());
+ let startofDay = new Date(today.getTime());
+ startofDay.setHours(0,0,0,0);
+ const porcentOfDay = ((today.getTime() - startofDay.getTime()) / (1000*60*60*24))
+ console.log(porcentOfDay);
+ const { firstDate } = getFirstAndLastDates(timelineElements);
+
+ const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
+ let containerSize = vw * 0.8;
+ if(isJS){
+
+ if(isToday){
+ return (getAbsoluteDays(firstDate,today) * ((containerSize/7) + ((containerSize/7)*porcentOfDay)) )
+ }
+
+ return (getAbsoluteDays(firstDate,startDate) * (containerSize/7))
+
+ } else {
+
+ if(isToday){
+ return `calc(${getAbsoluteDays(firstDate, today)} * (80vw / 7) + ((80vw / 7)* ${porcentOfDay}) )`;
+ }
+
+ return `calc(${getAbsoluteDays(firstDate, startDate)} * (80vw / 7))`;
+ }
+}
+
+function setTimelinePosition(){
+ let weekStart = new Date();
+ weekStart.setDate(weekStart.getDate() - weekStart.getDay())
+
+ const timelineContainer = document.getElementById("timelineContainer");
+ timelineContainer.scrollLeft += setDistances(weekStart, undefined,true);
+
+}
+
+
+
+function createTimeline2() {
+ const getFirstDate = getFirstAndLastDates(timelineElements).firstDate;
+ const getLastDate = getFirstAndLastDates(timelineElements).lastDate;
+ const getTotalDays = getAbsoluteDays(getFirstDate,getLastDate);
+
+ const listItemTimeline=document.getElementById("listItemTimeline2");
+ listItemTimeline.innerHTML = `
+
+
+
+
+ ${createDivTimes(getTotalDays,"timebox",getFirstDate).reduce((acc, curr) => acc + curr.outerHTML, '')}
+
+
+ ${timelineElements.map((elem,id) => `
+ ${createDivActivities(elem,id).outerHTML}
+ ` ).join('')}
+
+
+
+
+ `
}
function updateTable(){
diff --git a/marlo-web/src/main/webapp/global/images/end_date.png b/marlo-web/src/main/webapp/global/images/end_date.png
new file mode 100644
index 0000000000..2a3bbbe5a8
Binary files /dev/null and b/marlo-web/src/main/webapp/global/images/end_date.png differ
diff --git a/marlo-web/src/main/webapp/global/images/start_date.png b/marlo-web/src/main/webapp/global/images/start_date.png
new file mode 100644
index 0000000000..3bcc2a6e09
Binary files /dev/null and b/marlo-web/src/main/webapp/global/images/start_date.png differ