@pagamio/frontend-commons-lib
Version:
Pagamio library for Frontend reusable components like the form engine and table container
181 lines (180 loc) • 7.57 kB
JavaScript
import dayjs from 'dayjs';
import { formatPrice } from '../../helpers';
const createTooltipContainer = () => `
<div style="margin-top: 5px; border-top: 1px solid #eee; padding-top: 5px;">
`;
const isDateString = (value) => {
// Check if the string is a valid date format
return dayjs(value).isValid() && !Number.isNaN(Date.parse(value));
};
const formatDisplayName = (name) => {
if (isDateString(name)) {
return dayjs(name).format('MMM DD HH:mm');
}
return name;
};
const formatTooltipValue = (value, format, currency, displaySymbol) => {
if (format === 'number') {
return value.toLocaleString();
}
const numericValue = Number(value);
return currency ? formatPrice(numericValue, currency, 2, undefined, displaySymbol) : formatPrice(numericValue);
};
const createTooltipRow = (label, value, suffix = '', format = 'number', currency, displaySymbol) => {
return `
<div style="font-size: 12px; color: #666; margin-bottom: 3px;">
<span style="font-weight: 500;">${label}:</span> ${formatTooltipValue(value, format, currency, displaySymbol)}${suffix}
</div>
`;
};
export const processTooltipFields = (tooltipAdditionalFields) => {
return tooltipAdditionalFields.map((field) => {
if (typeof field === 'string') {
return {
toolTipkey: field,
valueKey: field,
nameKey: field,
label: field.replace(/([A-Z])/g, ' $1').trim(),
suffix: '',
format: 'number',
formatter: (value, currency) => {
if (typeof value === 'number') {
return value.toLocaleString();
}
return String(value);
},
};
}
return {
toolTipkey: field.toolTipkey,
valueKey: field.valueKey,
nameKey: field.nameKey,
label: field.label ?? field.toolTipkey.replace(/([A-Z])/g, ' $1').trim(),
suffix: field.suffix ?? '',
format: field.format ?? 'number',
formatter: field.formatter ??
((value, currency, displaySymbol) => {
if (field.format === 'currency') {
return formatPrice(Number(value), currency, 2, undefined, displaySymbol);
}
if (typeof value === 'number') {
return value.toLocaleString();
}
return String(value);
}),
};
});
};
const processAdditionalFields = (data, processedTooltipFields, currency, displaySymbol) => {
let content = createTooltipContainer();
processedTooltipFields.forEach((field) => {
if (data[field.toolTipkey] !== undefined) {
const rawValue = data[field.toolTipkey];
if (field.formatter) {
// If there's a custom formatter
const formattedValue = field.formatter(rawValue, currency, displaySymbol);
content += `
<div style="font-size: 12px; color: #666; margin-bottom: 3px;">
<span style="font-weight: 500;">${field.label}:</span> ${formattedValue}${field.suffix}
</div>
`;
}
else {
// No custom formatter, let createTooltipRow handle it
content += createTooltipRow(field.label, rawValue, field.suffix, field.format, currency, displaySymbol);
}
}
});
return content + '</div>';
};
const processLineGraphData = (date) => {
return createTooltipContainer() + createTooltipRow('Date', date) + '</div>';
};
const processMetricData = (processedTooltipFields, metricData, seriesValue, name, currency, displaySymbol) => {
let content = '';
processedTooltipFields.forEach((field) => {
const filteredValue = metricData.find((item) => item[field.valueKey] === seriesValue && item[field.nameKey] === name);
if (filteredValue) {
if (!content) {
content = createTooltipContainer();
}
const rawValue = filteredValue[field.toolTipkey];
if (field.formatter) {
// If there's a custom formatter,
const formattedValue = field.formatter(rawValue, currency, displaySymbol);
content += `
<div style="font-size: 12px; color: #666; margin-bottom: 3px;">
<span style="font-weight: 500;">${field.label}:</span> ${formattedValue}${field.suffix}
</div>
`;
}
else {
// No custom formatter, let createTooltipRow handle it
content += createTooltipRow(field.label, rawValue, field.suffix, field.format, currency, displaySymbol);
}
}
});
return content ? content + '</div>' : '';
};
export const createTooltipFormatter = (format, tooltipTitle, tooltipUnit, processedTooltipFields, metricData, currency, displaySymbol) => {
return (params) => {
let seriesColor = '#5470c6';
let seriesValue = 0;
let isLineGraph = false;
let date = '';
const { name, value, color, data, seriesName } = Array.isArray(params) ? params[0] : params;
if (typeof color === 'string') {
seriesColor = color;
}
else if (color?.colorStops?.[0]?.color) {
seriesColor = color.colorStops[0].color;
}
if (Array.isArray(value)) {
seriesValue = value[1];
date = value[0];
isLineGraph = true;
}
else {
seriesValue = value;
}
// Format the main value
let mainValueFormatted;
if (format === 'number') {
mainValueFormatted = `${seriesValue.toLocaleString()} ${tooltipUnit}`;
}
else if (displaySymbol) {
// Use display symbol with explicit currency fallback
const currencyToUse = currency || 'ZAR';
mainValueFormatted = formatPrice(seriesValue, currencyToUse, 2, undefined, displaySymbol);
}
else if (currency) {
mainValueFormatted = formatPrice(seriesValue, currency);
}
else {
mainValueFormatted = formatPrice(seriesValue);
}
let tooltipContent = `
<div>
<div style="font-size: 14px; font-weight: 500; margin-bottom: 8px;"><b>${tooltipTitle}</b></div>
<div style="display: flex; align-items: center; margin-bottom: 5px;">
<span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: ${seriesColor}; margin-right: 8px;"></span>
<span style="font-weight: 500;">${formatDisplayName(name === '' ? seriesName : name)}:</span>
<span style="margin-left: 5px;">${mainValueFormatted}</span>
</div>
`;
// Add additional fields if available
if (processedTooltipFields.length > 0) {
const hasAdditionalData = processedTooltipFields.some((field) => data[field.toolTipkey] !== undefined);
if (hasAdditionalData) {
tooltipContent += processAdditionalFields(data, processedTooltipFields, currency, displaySymbol);
}
else {
tooltipContent += isLineGraph
? processLineGraphData(date)
: processMetricData(processedTooltipFields, metricData, seriesValue, name, currency, displaySymbol);
}
}
tooltipContent += '</div>';
return tooltipContent;
};
};