UNPKG

ca-mfe-page-scoring-ui

Version:

This is a react shell for the SPGI Platform MFE implementation

460 lines (399 loc) 16.2 kB
import moment from 'moment'; import { platforms, noDataCaseColorMapping, dateFormat, modelFamily, stepIds, trackerStatus, financialsType, PRIMARY_SCORE_TYPE, letterGradeScores, scalesNeedingModification, proSpreadScaleId, proSpreadPeriodMapping, extractedDataFromPage } from '@root/constants'; import { constants } from '@spglobal/ca-mfe-package-utils'; export const formatDate = (date, dateFormat) => { if(date!== ''){ return (moment(date).format(dateFormat)); } return date; }; export const isFutureDate = date => date > new Date(); export const selectedFormData = (formdata, target) => { const result = formdata.find(data => target in data); return result ? result[target] : []; }; export const selectedFormField = (formdata, target) => { const result = formdata.find(item => item.name === target); return result ? result.value : ''; }; export const checkValidFormInput = updatedFormData => { const { modalFamily, companyType, industry, countryRegion } = updatedFormData; let isModalFamily = false; let isValidCompanyType = false; let isValidIndustry = false; let isValidCountryRegion = false; if (modalFamily.value !== '' && modalFamily.value !== undefined) { isModalFamily = true; } if (companyType.value !== '' && companyType.value !== undefined) { isValidCompanyType = true; } if (countryRegion.value !== '' && countryRegion.value !== undefined) { isValidCountryRegion = true; } if (industry.value !== '' && industry.value !== undefined) { isValidIndustry = true; } return { isModalFamily, isValidCompanyType, isValidIndustry, isValidCountryRegion }; }; export const stringformat = (s, replacedText) => s.toString().replace('{0}', replacedText); export const generateFormInputList = formData => { const inputList = []; for (const key in formData) { if (formData.hasOwnProperty(key)) { inputList.push({ name: key, value: formData[key] }); } } return inputList; }; export const sortFinancialStatement = list => list.sort((a, b) => b.fiscalYear - a.fiscalYear || b.fiscalQuarter - a.fiscalQuarter); export const sortSelectPeriod = list => list.sort((a, b) => b.fiscalYear - a.fiscalYear); export const checkPrivateCompanyType = companyTypeId => ['2', '4'].includes(companyTypeId); export const checkPrivateCorporateOnly = companyTypeId => companyTypeId === '2'; export const getCompanyID = () => { const href = window.location.search.toLowerCase(); const params = new URLSearchParams(href); const company: any = {}; if (href.indexOf('companyid') > -1) { company.companyID = params.get('companyid'); } else if (href.indexOf('alternateid') > -1) { company.companyID = params.get('alternateid').toUpperCase(); company.isUnlinkCompany = true; } return company; }; const isLocalhost = window.location.hostname === 'localhost'; export const apiBase = isLocalhost ? 'https://www.testciq.com' : ''; export const getFormattedDate = formatDate(new Date(),dateFormat); export const getCaHeader = (isProp = false) => constants.isCiqPlatform || isLocalhost ? (isProp ? platforms.CIQPROP :platforms.CIQ) : platforms.CIQPro; export const getDataSourceHeader = (datasource = platforms.CIQ) => ({ 'ca-datasource': (constants.isCiqPlatform || isLocalhost) ? datasource : platforms.CIQPro }); export const formatDateValue = val => { const newDate = new Date(val); const toPadStr = val => val.toString().padStart(2, '0'); const getMonth = toPadStr(newDate.getMonth()+1); const getDate = toPadStr(newDate.getDate()); const getYear = newDate.getFullYear(); return `${getYear}-${getMonth}-${getDate}`; }; const formatWithIntl = (num: number) => new Intl.NumberFormat('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 20 }).format(num); export const formatNumericValue = (val, decimals = 2, addComma = true) => { const [integerPart, decimalPart = ''] = String(val).split('.'); const totalLength = integerPart.replace(/,/g, '').length + decimalPart.length; const addDecimal = num => { if (totalLength >= 16) { return formatWithIntl(num); } const maxAllowedDecimals = Math.max(0, 16 - integerPart.length); const paddedDecimal = decimalPart.length > decimals ? decimalPart.slice(0, decimals) : String(decimalPart).padEnd(Math.min(decimals, maxAllowedDecimals), '0'); return decimals === 0 ? `${integerPart}` : `${integerPart}.${paddedDecimal}`; }; const separateWithComma = num => { if (totalLength >= 16) { return formatWithIntl(num); } const maxAllowedDecimals = Math.max(0, 16 - integerPart.length); const formattedNum = Math.floor(num).toLocaleString(); const paddedDecimal = decimalPart.length > decimals ? decimalPart.slice(0, decimals) : String(decimalPart).padEnd(Math.min(decimals, maxAllowedDecimals), '0'); return decimals === 0 ? `${formattedNum}` : `${formattedNum}.${paddedDecimal}`; }; if (val < 0) { const absValue = Math.abs(val); return `(${addComma ? separateWithComma(absValue) : addDecimal(absValue)})`; } return val !== null ? (addComma ? separateWithComma(Number(val)) : addDecimal(Number(val))) : val; }; const padValue = (value, max, pad = 0.99) => value === max ? max : value + pad; const getRanges = (clr, primaryScoreType, pdConfig: any = {}) => { if (primaryScoreType === PRIMARY_SCORE_TYPE.PD_PERCENT) { const { index, bandCount } = pdConfig; return { fromPd: clr.fromPd, toPd: clr.toPd, from: ((bandCount - 1 - index) * (100 / bandCount)), to: ((bandCount - 1 - index + 1) * (100 / bandCount)) }; } /*Note: For letterGrade, chart will be plotted based on oneToHundred score*/ // else if (primaryScoreType === PRIMARY_SCORE_TYPE.LETTER_GRADE) { // return { // from: clr.fromLetterGrade, // to: padValue(clr.toLetterGrade, 21) // }; // } return { from: clr.from === 0 ? clr.from - 0.99 : clr.from, to: padValue(Number(clr.to), 100) }; }; export const getGreyedoutBandColor = rgType => noDataCaseColorMapping.find(ob => ob.risktype === rgType)?.color; export const getRgScoreMapColorBands = ({ plotBandColors, thickness = 20, primaryScoreType, noDataCase = false }) => plotBandColors?.map((clr, index) => ({ rgType: clr.rgType, color: noDataCase ? getGreyedoutBandColor(clr.rgType) : clr.color, ...getRanges(clr, primaryScoreType, { index, bandCount: plotBandColors?.length }), thickness })); export const getTimestamp = data => { const date = new Date(data); return date.getTime(); }; export const getPercentageRounding = numbers => { const fixedTo10Nums = numbers.map(x => parseFloat(parseFloat(x).toFixed(10))); const total = Math.round(fixedTo10Nums.reduce((sum, e) => sum + e, 0)); const remainder = total - fixedTo10Nums.reduce((sum, x) => sum + Math.floor(x), 0); const values = fixedTo10Nums .map((value, index) => ({ index, value, remainder: Math.round((value % 1) * 100) })) .sort((a, b) => b.remainder - a.remainder) .map(({value, index}, idx)=>({ index, value: (idx<remainder) ? Math.ceil(value): Math.floor(value) })) .sort((a, b) => a.index - b.index) .map(({value})=>value); return values; }; export const calculateRevenueFromAssets = (assetVal, usdConvRate, decimals=2) => { if ((typeof assetVal === 'number') && usdConvRate) { const result = (2.5981 * (Math.pow(parseFloat((assetVal * usdConvRate).toString()), 0.7571))) / usdConvRate; return (truncateDecimal(result, decimals) ?? null); } return null; }; export const truncateDecimal = (val, decimalPts = 1) => { if (typeof val === 'number') { const decimalFactor = Math.pow(10, decimalPts); return Math.floor(val * decimalFactor) / decimalFactor; } return null; }; export const getDifference = (arr1 = [], arr2 = []) => [ ...arr1.filter(x => !arr2.includes(x)), ...arr2.filter(x => !arr1.includes(x)) ]; export const extractIndustry = (metaData, industryCode) => { const industriesData = metaData?.industries?.find( c => c.modelFamily === modelFamily.Risk_Gauge ); const industries = industriesData?.industryTypes?.find(c => c.options?.find(x => x.id.toString() === industryCode) ); return { ...industries?.options?.find(x => x.id.toString() === industryCode), ...(industries?.type && { type: industries.type }) }; }; export const extractCountry = (metaData, countryCode) => { const countriesData = metaData?.countries?.find( c => c.modelFamily === modelFamily.Risk_Gauge ); const validCountry = countriesData?.options?.find(c => c.code === countryCode); return validCountry || {}; }; export const validateCountryIndustry = (metaData, industryCode, countryCode) => { const validIndustry = extractIndustry(metaData, industryCode); const validCountry = extractCountry(metaData, countryCode); return Boolean(Object.keys(validCountry).length) && Boolean(Object.keys(validIndustry).length); }; export const getEnabledAdjStepsIds = steppers => { const adjSteps = steppers.find(steps => steps.stepId === stepIds.ADJUSTMENTS); return adjSteps?.nestedSteps.filter(({ status }) => (status === trackerStatus.SELECTED || status === trackerStatus.ACTIVE || status === trackerStatus.COMPLETED)) .map(({ stepId }) => stepId); }; export const checkAdjEnabled = (steppers = [], adjId = '') => { const adjustments = steppers?.find(adj => adj.stepId === stepIds.ADJUSTMENTS); return adjustments?.nestedSteps?.find(ns => ns.stepId === adjId)?.showStep; }; export const checkEpdCompany = (companyType, financialType) => companyType === '2' && financialType === financialsType.WithoutFinancials; export const checkIsNotValidInput = (analyticsName, val) => { if(isNaN(val)){ return true; } const numVal = Number(val); switch(analyticsName) { case 'GOVERNMENT_OWNERSHIP': case 'STANDALONE_PD_PARENT': { return Boolean(numVal < 0 || numVal > 100); } case 'TOTAL_EMPLOYEES': { return Boolean(numVal <= 0); } case 'ONLY_POSITIVE': { return Boolean(numVal > 0); } default:{ return false; } } }; export const rawPdFormatter = (rawPd, decimalPts = 4) => { if (typeof rawPd === 'number') { const tenPow = Math.pow(10, decimalPts); return Math.floor(rawPd * tenPow * 100) / tenPow; } return null; }; export const displayScore = (value, scoreScaleType) => { if (scoreScaleType === PRIMARY_SCORE_TYPE.PD_PERCENT) { return `${value?.toFixed(4)}%`; } else if (scoreScaleType === PRIMARY_SCORE_TYPE.LETTER_GRADE) { return letterGradeScores[value]; } return `${value}`; }; export const getPrimaryAndSecondaryScore = (scoreScaleType, scoreObj) => { const scores: any = {}; if (scoreScaleType === PRIMARY_SCORE_TYPE.LETTER_GRADE) { scores.primaryScore = scoreObj?.letterGradeNotch; /*Note: For letterGrade also chart will be plotted based on oneToHundred score*/ scores.oneToHundred = scoreObj?.oneToHundred; scores.secondaryScore = rawPdFormatter(scoreObj?.rawPd); scores.secondaryScoreType = PRIMARY_SCORE_TYPE.PD_PERCENT; } else if (scoreScaleType === PRIMARY_SCORE_TYPE.PD_PERCENT) { scores.primaryScore = rawPdFormatter(scoreObj?.rawPd); scores.secondaryScore = scoreObj?.letterGradeNotch; scores.secondaryScoreType = PRIMARY_SCORE_TYPE.LETTER_GRADE; scores.oneToHundred = scoreObj?.oneToHundred; } else if (scoreScaleType === PRIMARY_SCORE_TYPE.ONE_TO_HUNDRED) { scores.primaryScore = scoreObj?.oneToHundred; scores.secondaryScore = scoreObj?.letterGradeNotch; scores.secondaryScoreType = PRIMARY_SCORE_TYPE.LETTER_GRADE; scores.oneToHundred = scoreObj?.oneToHundred; } return scores; }; export const processProSpreadData = proSpreadData => { const { scaleId, instances = [], companyType = '', gicsCode, currencyName = '', compFinancial='', fromPage = '', isLinkedCompany = false, unlinkedSource = '' } = proSpreadData; proSpreadData.fromPage = fromPage; proSpreadData.companyType = companyType?.toUpperCase()?.indexOf('PUBLIC') > -1 ? 'PUBLIC' : (fromPage === extractedDataFromPage) ? companyType: 'PRIVATE'; proSpreadData.gicsCode = gicsCode ? `${gicsCode}` : gicsCode; proSpreadData.currencyName = currencyName.replace(/(^.*\[|\].*$)/g, ''); proSpreadData.compFinancial = compFinancial; proSpreadData.isLinkedCompany = isLinkedCompany; proSpreadData.unlinkedSource = unlinkedSource; instances.forEach(currInstance => { const periodType = proSpreadPeriodMapping[currInstance.Period]; currInstance.Period = periodType; currInstance.FQ = periodType === 'FY' ? 4 : currInstance.FQ; if (scalesNeedingModification.includes(scaleId)) { currInstance.Values.forEach(item => { switch (scaleId) { case proSpreadScaleId.thousands: item.Value /= 1000; break; case proSpreadScaleId.lac: item.Value /= 10; break; case proSpreadScaleId.billions: item.Value *= 1000; break; case proSpreadScaleId.absolute: item.Value /= 1000000; break; default: item.Value *= 1; } }); } }); return proSpreadData; }; export const flatGroupsAndMetrics = (finData = []) => ( finData?.reduce((acc, curr)=>{ const newMetrics = curr.metrics.map(metric=>({ ...metric, groupName: curr.groupName })); acc.push(...newMetrics); return acc; }, []) ); export const parseSizeAdjustmentNumber = (val, decimals) => { const formattedValue = formatNumericValue(truncateDecimal(val, decimals), decimals); return formattedValue; }; export const getValueFormat = (numValue, decimals = 2) => { const strNum = numValue?.toString().replaceAll(',', ''); const [restrictedLength, displayDecimals] = [18, decimals]; if (strNum?.length > restrictedLength) { const truncatedValue = addDecimalBasedOnValue(numValue, displayDecimals); return truncatedValue; } return numValue !== null ? formatNumericValue(numValue, displayDecimals) : numValue; }; export const addDecimalBasedOnValue = (num, decimals = 2) => { const [integerPart, decimalPart = ''] = String(num).split('.'); const totalLength = integerPart.length + decimalPart.length; if (num === '' || num === null) { return ''; } if (totalLength >= 16) { return num.toString(); } const maxAllowedDecimals = Math.max(0, 16 - integerPart.length); const paddedDecimal = decimalPart.length > decimals ? decimalPart.slice(0, decimals) : String(decimalPart).padEnd(Math.min(decimals, maxAllowedDecimals), '0'); return decimals === 0 ? `${integerPart}` : `${integerPart}.${paddedDecimal}`; }; export const trimValueToLength = (value, valDecLength = 18, valNumLength = 17) => { if (value) { const hasDecimal = value.includes('.'); const maxLength = hasDecimal ? valDecLength : valNumLength; if (value.length >= maxLength) { const trimmedValue = value.slice(0, maxLength); return Number(trimmedValue); } } return undefined; }; export const convertToNumber = value => { if (typeof value === 'number') { return value; } else if (typeof value === 'string' && !isNaN(value)) { return Number(value); } return null; }; export const setDecimalLength = (decimalPart, numValue, decimalValue = 2) => { if (numValue !== null && numValue !== undefined && numValue !== '' && !isNaN(numValue)) { return decimalPart === '' ? 0 : decimalPart.length; } return decimalPart === '' ? decimalValue : decimalPart.length; };