redbadger/pride-london-app

View on GitHub
src/components/ButtonWithShapes.js

Summary

Maintainability
A
1 hr
Test Coverage
// @flow
import React from "react";
import { Image, Linking, StyleSheet, View } from "react-native";
import type { ViewStyleProp } from "react-native/Libraries/StyleSheet/StyleSheet";
import type { NavigationScreenProp, NavigationState } from "react-navigation";
import chevronRightCircleWhite from "../../assets/images/chevronRightCircleWhite.png";
import externalLinkBlue from "../../assets/images/externalLinkBlue.png";
import externalLinkWhite from "../../assets/images/externalLinkWhite.png";
import ContentPadding from "./ContentPadding";
import Text, { scaleWithFont } from "./Text";
import Touchable from "./Touchable";
import {
  lightNavyBlueColor,
  whiteColor,
  supportUsButtonShadow
} from "../constants/colors";
import type { ImageRef } from "../data/image-ref";

type Props = {|
  color: string,
  title: string,
  description: string,
  centerText?: boolean,
  bgBottomLeft?: ImageRef,
  bgTopRight?: ImageRef,
  bgBottomRight?: ImageRef,
  navigation: NavigationScreenProp<NavigationState>,
  url: string,
  contrast?: boolean,
  style?: ViewStyleProp,
  testID?: string
|};

const isExternalLink = (url: string) =>
  url.startsWith("http://") || url.startsWith("https://");

const pickLinkIcon = (url: string, contrast: boolean) => {
  if (isExternalLink(url)) {
    return contrast ? externalLinkBlue : externalLinkWhite;
  }

  return chevronRightCircleWhite;
};

class SupportUsButton extends React.PureComponent<Props> {
  static defaultProps = {
    centerText: false,
    bgBottomLeft: undefined,
    bgTopRight: undefined,
    bgBottomRight: undefined,
    contrast: false,
    style: {},
    testID: undefined
  };

  onPress = () => {
    if (isExternalLink(this.props.url)) {
      Linking.openURL(this.props.url);
    } else {
      this.props.navigation.navigate(this.props.url);
    }
  };

  render() {
    const {
      color,
      title,
      description,
      centerText,
      bgBottomLeft,
      bgTopRight,
      bgBottomRight,
      url,
      contrast,
      style,
      testID
    } = this.props;

    return (
      <Touchable
        accessibilityTraits={[isExternalLink ? "link" : "button"]}
        onPress={this.onPress}
        style={[styles.button, { backgroundColor: color }, style]}
        testID={testID}
      >
        {bgBottomLeft && (
          <Image source={bgBottomLeft} style={styles.bgBottomLeft} />
        )}
        {bgTopRight && <Image source={bgTopRight} style={styles.bgTopRight} />}
        {bgBottomRight && (
          <Image source={bgBottomRight} style={styles.bgBottomRight} />
        )}
        <ContentPadding
          padding={{
            small: { horizontal: 18, vertical: 0 },
            medium: { horizontal: 20, vertical: 0 },
            large: { horizontal: 29, vertical: 0 }
          }}
          style={centerText && styles.centerText}
        >
          <View style={styles.titleContainer}>
            <Text
              type="h1"
              style={contrast ? styles.textContrast : styles.text}
            >
              {title}
            </Text>
            <Image
              source={pickLinkIcon(url, !!contrast)}
              style={styles.titleIcon}
            />
          </View>
          <Text type="h3" style={contrast ? styles.textContrast : styles.text}>
            {description}
          </Text>
        </ContentPadding>
      </Touchable>
    );
  }
}

const styles = StyleSheet.create({
  button: {
    // Can't use `minHeight` because it has a weird behaviour. The
    // button will have the correct size but the sibling elements
    // will layout according to the buttons (smaller) `height`.
    height: Math.max(100, scaleWithFont("h3", 100)),
    justifyContent: "center",
    borderRadius: 5,
    overflow: "hidden",

    // The below properties are required for iOS shadow
    shadowColor: supportUsButtonShadow,
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 1,
    shadowRadius: 3,

    // The below properties are required for Android shadow
    borderWidth: 0,
    elevation: 3
  },
  bgBottomLeft: {
    position: "absolute",
    bottom: 0,
    left: 0
  },
  bgTopRight: {
    position: "absolute",
    top: 0,
    right: 0
  },
  bgBottomRight: {
    position: "absolute",
    bottom: 0,
    right: 0
  },
  centerText: {
    alignItems: "center"
  },
  titleContainer: {
    flexDirection: "row"
  },
  titleIcon: {
    marginLeft: 8,
    alignSelf: "center",
    transform: [{ translateY: scaleWithFont("h1", -4) }]
  },
  text: {
    color: whiteColor
  },
  textContrast: {
    color: lightNavyBlueColor
  }
});

export default SupportUsButton;