export default function PopKPI()

in superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx [80:359]


export default function PopKPI(props: PopKPIProps) {
  const {
    height,
    width,
    bigNumber,
    prevNumber,
    valueDifference,
    percentDifferenceFormattedString,
    metricName,
    metricNameFontSize,
    headerFontSize,
    subheaderFontSize,
    comparisonColorEnabled,
    comparisonColorScheme,
    percentDifferenceNumber,
    currentTimeRangeFilter,
    startDateOffset,
    shift,
    subtitle,
    subtitleFontSize,
    dashboardTimeRange,
    showMetricName,
  } = props;
  const [comparisonRange, setComparisonRange] = useState<string>('');

  useEffect(() => {
    if (!currentTimeRangeFilter || (!shift && !startDateOffset)) {
      setComparisonRange('');
    } else if (!isEmpty(shift) || startDateOffset) {
      const promise: any = fetchTimeRange(
        dashboardTimeRange ?? (currentTimeRangeFilter as any).comparator,
        currentTimeRangeFilter.subject,
      );
      Promise.resolve(promise).then((res: any) => {
        const dates = res?.value?.match(DEFAULT_DATE_PATTERN);
        const [parsedStartDate, parsedEndDate] = dates ?? [];
        const newShift = getTimeOffset({
          timeRangeFilter: {
            ...currentTimeRangeFilter,
            comparator: `${parsedStartDate} : ${parsedEndDate}`,
          },
          shifts: ensureIsArray(shift),
          startDate: startDateOffset || '',
        });
        fetchTimeRange(
          dashboardTimeRange ?? (currentTimeRangeFilter as any).comparator,
          currentTimeRangeFilter.subject,
          ensureIsArray(newShift),
        ).then(res => {
          const response: string[] = ensureIsArray(res.value);
          const firstRange: string = response.flat()[0];
          const rangeText = firstRange.split('vs\n');
          setComparisonRange(
            rangeText.length > 1 ? rangeText[1].trim() : rangeText[0],
          );
        });
      });
    }
  }, [currentTimeRangeFilter, shift, startDateOffset, dashboardTimeRange]);

  const theme = useTheme();
  const flexGap = theme.gridUnit * 5;
  const wrapperDivStyles = css`
    font-family: ${theme.typography.families.sansSerif};
    display: flex;
    justify-content: center;
    align-items: center;
    height: ${height}px;
    width: ${width}px;
    overflow: auto;
  `;

  const bigValueContainerStyles = css`
    font-size: ${headerFontSize || 60}px;
    font-weight: ${theme.typography.weights.normal};
    text-align: center;
    margin-bottom: ${theme.gridUnit * 4}px;
  `;

  const SubtitleText = styled.div`
    ${({ theme }) => `
    font-family: ${theme.typography.families.sansSerif};
    font-weight: ${theme.typography.weights.medium};
    text-align: center;
    margin-top: -10px;
    margin-bottom: ${theme.gridUnit * 4}px;
  `}
  `;

  const getArrowIndicatorColor = () => {
    if (!comparisonColorEnabled || percentDifferenceNumber === 0) {
      return theme.colors.grayscale.base;
    }

    if (percentDifferenceNumber > 0) {
      // Positive difference
      return comparisonColorScheme === ColorSchemeEnum.Green
        ? theme.colors.success.base
        : theme.colors.error.base;
    }
    // Negative difference
    return comparisonColorScheme === ColorSchemeEnum.Red
      ? theme.colors.success.base
      : theme.colors.error.base;
  };

  const arrowIndicatorStyle = css`
    color: ${getArrowIndicatorColor()};
    margin-left: ${theme.gridUnit}px;
  `;

  const defaultBackgroundColor = theme.colors.grayscale.light4;
  const defaultTextColor = theme.colors.grayscale.base;
  const { backgroundColor, textColor } = useMemo(() => {
    let bgColor = defaultBackgroundColor;
    let txtColor = defaultTextColor;
    if (comparisonColorEnabled && percentDifferenceNumber !== 0) {
      const useSuccess =
        (percentDifferenceNumber > 0 &&
          comparisonColorScheme === ColorSchemeEnum.Green) ||
        (percentDifferenceNumber < 0 &&
          comparisonColorScheme === ColorSchemeEnum.Red);

      // Set background and text colors based on the conditions
      bgColor = useSuccess
        ? theme.colors.success.light2
        : theme.colors.error.light2;
      txtColor = useSuccess
        ? theme.colors.success.base
        : theme.colors.error.base;
    }

    return {
      backgroundColor: bgColor,
      textColor: txtColor,
    };
  }, [
    theme,
    comparisonColorScheme,
    comparisonColorEnabled,
    percentDifferenceNumber,
  ]);

  const SYMBOLS_WITH_VALUES = useMemo(
    () =>
      [
        {
          defaultSymbol: '#',
          value: prevNumber,
          tooltipText: t('Data for %s', comparisonRange || 'previous range'),
          columnKey: 'Previous value',
        },
        {
          defaultSymbol: '△',
          value: valueDifference,
          tooltipText: t('Value difference between the time periods'),
          columnKey: 'Delta',
        },
        {
          defaultSymbol: '%',
          value: percentDifferenceFormattedString,
          tooltipText: t('Percentage difference between the time periods'),
          columnKey: 'Percent change',
        },
      ].map(item => {
        const config = props.columnConfig?.[item.columnKey];
        return {
          ...item,
          symbol: config?.displayTypeIcon === false ? '' : item.defaultSymbol,
          label: config?.customColumnName || item.columnKey,
        };
      }),
    [
      comparisonRange,
      prevNumber,
      valueDifference,
      percentDifferenceFormattedString,
      props.columnConfig,
    ],
  );

  const visibleSymbols = SYMBOLS_WITH_VALUES.filter(
    symbol => props.columnConfig?.[symbol.columnKey]?.visible !== false,
  );

  const { isOverflowing, symbolContainerRef, wrapperRef } =
    useOverflowDetection(flexGap);

  return (
    <div css={wrapperDivStyles} ref={wrapperRef}>
      <NumbersContainer
        css={
          isOverflowing &&
          css`
            width: fit-content;
            margin: auto;
            align-items: flex-start;
            overflow: auto;
          `
        }
      >
        {showMetricName && metricName && (
          <MetricNameText metricNameFontSize={metricNameFontSize}>
            {metricName}
          </MetricNameText>
        )}

        <div css={bigValueContainerStyles}>
          {bigNumber}
          {percentDifferenceNumber !== 0 && (
            <span css={arrowIndicatorStyle}>
              {percentDifferenceNumber > 0 ? '↑' : '↓'}
            </span>
          )}
        </div>
        {subtitle && (
          <SubtitleText
            style={{
              fontSize: `${subtitleFontSize * height * 0.4}px`,
            }}
          >
            {subtitle}
          </SubtitleText>
        )}

        {visibleSymbols.length > 0 && (
          <div
            css={[
              css`
                display: flex;
                justify-content: space-around;
                gap: ${flexGap}px;
                min-width: 0;
                flex-shrink: 1;
              `,
              isOverflowing
                ? css`
                    flex-direction: column;
                    align-items: flex-start;
                    width: fit-content;
                  `
                : css`
                    align-items: center;
                    width: 100%;
                  `,
            ]}
            ref={symbolContainerRef}
          >
            {visibleSymbols.map((symbol_with_value, index) => (
              <ComparisonValue
                key={`comparison-symbol-${symbol_with_value.columnKey}`}
                subheaderFontSize={subheaderFontSize}
              >
                <Tooltip
                  id="tooltip"
                  placement="top"
                  title={symbol_with_value.tooltipText}
                >
                  {symbol_with_value.symbol && (
                    <SymbolWrapper
                      backgroundColor={
                        index > 0 ? backgroundColor : defaultBackgroundColor
                      }
                      textColor={index > 0 ? textColor : defaultTextColor}
                    >
                      {symbol_with_value.symbol}
                    </SymbolWrapper>
                  )}
                  {symbol_with_value.value}{' '}
                  {props.columnConfig?.[symbol_with_value.columnKey]
                    ?.customColumnName || ''}
                </Tooltip>
              </ComparisonValue>
            ))}
          </div>
        )}
      </NumbersContainer>
    </div>
  );
}