teamdigitale/italia-app

View on GitHub
ts/features/messages/components/Home/DS/DoubleAvatar.tsx

Summary

Maintainability
A
35 mins
Test Coverage
import React, { useCallback } from "react";
import {
  Image,
  ImageRequireSource,
  ImageURISource,
  StyleSheet,
  View
} from "react-native";
import {
  IOColors,
  IOIconSizeScale,
  IOSpacingScale,
  IOVisualCostants,
  Icon,
  hexToRgba,
  useIOTheme
} from "@pagopa/io-app-design-system";
import { addCacheTimestampToUri } from "../../../../../utils/image";

type DoubleAvatarProps = {
  backgroundLogoUri?:
    | ImageRequireSource
    | ImageURISource
    | ReadonlyArray<ImageURISource>;
};

const avatarContainerSize: IOIconSizeScale = 30;
const avatarDoubleRadiusSizeSmall: number = 6;
const internalSpaceDefaultSize: number = 3;
const internalSpacePlaceholderDefaultSize: IOSpacingScale = 6;
const avatarBorderLightMode = hexToRgba(IOColors.black, 0.1);

const styles = StyleSheet.create({
  topContainer: {
    height: IOVisualCostants.avatarSizeSmall,
    width: IOVisualCostants.avatarSizeSmall
  },
  avatarWrapper: {
    overflow: "hidden",
    borderColor: avatarBorderLightMode,
    borderWidth: 1,
    borderCurve: "continuous",
    position: "absolute"
  },
  avatarInnerWrapper: {
    overflow: "hidden",
    backgroundColor: IOColors.white,
    borderCurve: "continuous"
  },
  avatarImage: {
    resizeMode: "contain",
    height: "100%",
    width: "100%"
  }
});

const getImageState = (
  backgroundLogoUri?:
    | ImageRequireSource
    | ImageURISource
    | ReadonlyArray<ImageURISource>
) => {
  switch (typeof backgroundLogoUri) {
    case "number":
      return backgroundLogoUri;
    case "object":
      if (Array.isArray(backgroundLogoUri)) {
        return addCacheTimestampToUri(backgroundLogoUri[0]);
      }
      return addCacheTimestampToUri(backgroundLogoUri as ImageURISource);
    default:
      return undefined;
  }
};

/**
 * DoubleAvatar component is used to display the background logo of an organization, with a fixed pagoPA icon on top. It accepts the following props:
 * - `backgroundLogoUri`: the uri of the image to display. If not provided, a placeholder icon will be displayed. It can be a single uri or an array of uris, in which case the first one that is available will be used.
 * @param DoubleAvatarProps
 * @returns
 */
export const DoubleAvatar = ({ backgroundLogoUri }: DoubleAvatarProps) => {
  const theme = useIOTheme();
  const indexValue = React.useRef<number>(0);

  const imageInitialState = useCallback(
    () => getImageState(backgroundLogoUri),
    [backgroundLogoUri]
  );
  const [imageSource, setImageSource] = React.useState(imageInitialState);

  const onError = () => {
    if (
      Array.isArray(backgroundLogoUri) &&
      indexValue.current + 1 < backgroundLogoUri.length
    ) {
      // eslint-disable-next-line functional/immutable-data
      indexValue.current = indexValue.current + 1;
      setImageSource(
        addCacheTimestampToUri(backgroundLogoUri[indexValue.current])
      );
      return;
    }
    setImageSource(undefined);
  };

  return (
    <View style={styles.topContainer}>
      <View
        accessibilityIgnoresInvertColors
        style={[
          styles.avatarWrapper,
          {
            height: avatarContainerSize,
            width: avatarContainerSize,
            borderRadius: avatarDoubleRadiusSizeSmall,
            backgroundColor:
              imageSource === undefined ? IOColors["grey-50"] : IOColors.white,
            padding:
              imageSource === undefined
                ? internalSpacePlaceholderDefaultSize
                : internalSpaceDefaultSize,
            bottom: 0,
            right: 0
          }
        ]}
      >
        {imageSource === undefined ? (
          <Icon
            name="institution"
            color={theme["icon-decorative"]}
            size={"100%"}
          />
        ) : (
          <View
            style={[
              styles.avatarInnerWrapper,
              {
                borderRadius:
                  avatarDoubleRadiusSizeSmall - internalSpaceDefaultSize
              }
            ]}
          >
            <Image
              accessibilityIgnoresInvertColors
              source={imageSource}
              style={styles.avatarImage}
              onError={onError}
            />
          </View>
        )}
      </View>
      <View
        accessibilityIgnoresInvertColors
        style={[
          styles.avatarWrapper,
          {
            height: avatarContainerSize,
            width: avatarContainerSize,
            borderRadius: avatarDoubleRadiusSizeSmall,
            backgroundColor:
              imageSource === undefined ? IOColors["grey-50"] : IOColors.white,
            padding: 0,
            justifyContent: "center",
            alignItems: "center"
          }
        ]}
      >
        <View
          style={[
            styles.avatarInnerWrapper,
            {
              borderRadius:
                avatarDoubleRadiusSizeSmall - internalSpaceDefaultSize
            }
          ]}
        >
          <Icon name="productPagoPA" color="blueItalia-500" size={20} />
        </View>
      </View>
    </View>
  );
};