mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-04 13:07:55 +00:00 
			
		
		
		
	* feat: add heatmap component * feat: add heatmap component * feat: add dummy heatmap * refactor: compact tiles * feat: allow hour * feat: wire up heatmap query * feat: allow arbritrary number of weeks * feat: update position of the widget * chore: update heatmap title * refactor: move traffic heatmap to overview * chore: add comment for perf * feat: add reconcile logic for heatmap fetching Fetching the data for the last 6 days all the time is wasteful So we fetch only the data for today and reconcile it with the data we already have * refactor: re-org code for new utils * feat: add translations * feat: translate days of the week * chore: update chatwoot utils * feat: add markers to heatmap * refactor: update class names * refactor: move flatten as a separate method * test: Heatmap Helpers * chore: add comments * refactor: method naming * refactor: use heatmap-level mixin * refactor: cleanup css * chore: remove log * refactor: reports.js to use object instead of separate params * refactor: report store to use new API design * refactor: rename HeatmapHelper -> ReportsDataHelper * refactor: separate clampDataBetweenTimeline * feat: add tests * fix: group by hour * feat: add scroll for smaller screens * refactor: add base data to reconcile with * fix: tests * fix: overflow only on smaller screens * feat: translate tooltip * refactor: simplify reconcile * chore: add docs * chore: remoev heatmap from account report * feat: let Heatmap handle loading state * chore: Apply suggestions from code review Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> * feat: update css * refactor: color assignment to range * feat: add short circuit * Update app/javascript/dashboard/routes/dashboard/settings/reports/components/Heatmap.vue --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com> Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
		
			
				
	
	
		
			111 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import {
 | 
						|
  fromUnixTime,
 | 
						|
  startOfDay,
 | 
						|
  endOfDay,
 | 
						|
  getUnixTime,
 | 
						|
  subDays,
 | 
						|
} from 'date-fns';
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns a key-value pair of timestamp and value for heatmap data
 | 
						|
 *
 | 
						|
 * @param {Array} data - An array of objects containing timestamp and value
 | 
						|
 * @returns {Object} - An object with timestamp as keys and corresponding values as values
 | 
						|
 */
 | 
						|
export const flattenHeatmapData = data => {
 | 
						|
  return data.reduce((acc, curr) => {
 | 
						|
    acc[curr.timestamp] = curr.value;
 | 
						|
    return acc;
 | 
						|
  }, {});
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Filter the given array to remove data outside the timeline
 | 
						|
 *
 | 
						|
 * @param {Array} data - An array of objects containing timestamp and value
 | 
						|
 * @param {number} from - Unix timestamp
 | 
						|
 * @param {number} to - Unix timestamp
 | 
						|
 * @returns {Array} - An array of objects containing timestamp and value
 | 
						|
 */
 | 
						|
export const clampDataBetweenTimeline = (data, from, to) => {
 | 
						|
  if (from === undefined && to === undefined) {
 | 
						|
    return data;
 | 
						|
  }
 | 
						|
 | 
						|
  return data.filter(el => {
 | 
						|
    const { timestamp } = el;
 | 
						|
 | 
						|
    const isWithinFrom = from === undefined || timestamp - from >= 0;
 | 
						|
    const isWithinTo = to === undefined || to - timestamp > 0;
 | 
						|
 | 
						|
    return isWithinFrom && isWithinTo;
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Generates an array of objects with timestamp and value as 0 for the last 7 days
 | 
						|
 *
 | 
						|
 * @returns {Array} - An array of objects containing timestamp and value
 | 
						|
 */
 | 
						|
export const generateEmptyHeatmapData = () => {
 | 
						|
  const data = [];
 | 
						|
  const today = new Date();
 | 
						|
 | 
						|
  let timeMarker = getUnixTime(startOfDay(subDays(today, 6)));
 | 
						|
  let endOfToday = getUnixTime(endOfDay(today));
 | 
						|
 | 
						|
  const oneHour = 3600;
 | 
						|
 | 
						|
  while (timeMarker <= endOfToday) {
 | 
						|
    data.push({ value: 0, timestamp: timeMarker });
 | 
						|
    timeMarker += oneHour;
 | 
						|
  }
 | 
						|
 | 
						|
  return data;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Reconciles new data with existing heatmap data based on timestamps
 | 
						|
 *
 | 
						|
 * @param {Array} data - An array of objects containing timestamp and value
 | 
						|
 * @param {Array} heatmapData - An array of objects containing timestamp, value and other properties
 | 
						|
 * @returns {Array} - An array of objects with updated values
 | 
						|
 */
 | 
						|
export const reconcileHeatmapData = (data, dataFromStore) => {
 | 
						|
  const parsedData = flattenHeatmapData(data);
 | 
						|
  // make a copy of the data from store
 | 
						|
  const heatmapData = dataFromStore.length
 | 
						|
    ? dataFromStore
 | 
						|
    : generateEmptyHeatmapData();
 | 
						|
 | 
						|
  return heatmapData.map(dataItem => {
 | 
						|
    if (parsedData[dataItem.timestamp]) {
 | 
						|
      dataItem.value = parsedData[dataItem.timestamp];
 | 
						|
    }
 | 
						|
    return dataItem;
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Groups heatmap data by day
 | 
						|
 *
 | 
						|
 * @param {Array} heatmapData - An array of objects containing timestamp, value and other properties
 | 
						|
 * @returns {Map} - A Map object with dates as keys and corresponding data objects as values
 | 
						|
 */
 | 
						|
export const groupHeatmapByDay = heatmapData => {
 | 
						|
  return heatmapData.reduce((acc, data) => {
 | 
						|
    const date = fromUnixTime(data.timestamp);
 | 
						|
    const mapKey = startOfDay(date).toISOString();
 | 
						|
    const dataToAppend = {
 | 
						|
      ...data,
 | 
						|
      date: fromUnixTime(data.timestamp),
 | 
						|
      hour: date.getHours(),
 | 
						|
    };
 | 
						|
    if (!acc.has(mapKey)) {
 | 
						|
      acc.set(mapKey, []);
 | 
						|
    }
 | 
						|
    acc.get(mapKey).push(dataToAppend);
 | 
						|
    return acc;
 | 
						|
  }, new Map());
 | 
						|
};
 |