bookbrainz/bookbrainz-site

View on GitHub
src/client/entity-editor/common/validation-label.tsx

Summary

Maintainability
A
0 mins
Test Coverage
/*
 * Copyright (C) 2016  Ben Ockmore
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */


import * as React from 'react';
import {faCheck, faExclamationTriangle, faTimes} from '@fortawesome/free-solid-svg-icons';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import type {IconDefinition} from '@fortawesome/fontawesome-svg-core';


type OptionalBool = boolean | null | undefined;
function icon(empty: OptionalBool, error: OptionalBool, warn: OptionalBool): IconDefinition | null {
    if (empty) {
        return null;
    }

    if (error) {
        return faTimes;
    }

    if (warn) {
        return faExclamationTriangle;
    }

    return faCheck;
}

type ContextualColor = 'text-danger' | 'text-warning' | 'text-success';
function contextualColor(
    empty: OptionalBool,
    error: OptionalBool,
    warn: OptionalBool
): ContextualColor | null {
    if (empty) {
        return null;
    }

    if (error) {
        return 'text-danger';
    }

    if (warn) {
        return 'text-warning';
    }

    return 'text-success';
}

type Props = {
    children?: React.ReactNode,
    empty?: boolean,
    error?: boolean,
    errorMessage?: '',
    hideIcon?: boolean,
    warn?: boolean,
    warnMessage?: ''
};

/**
 * Presentational component. This component renders a textual label, intended
 * to be used with an input. Some formatting is applied and an icon is chosen
 * based on the validation state passed in via the component properties.
 *
 * @param {Object} props - The properties passed to the component.
 * @param {node} props.children - The element or value to display within the
 *        label.
 * @param {boolean} props.empty - A flag indicating whether the associated
 *        input is empty.
 * @param {boolean} props.error - A flag indicating whether there has been an
 *        error validating the contents of the associated input field.
 * @returns {Object} A React component containing the rendered input.
 */
function ValidationLabel({
    children,
    empty,
    error,
    hideIcon,
    errorMessage,
    warn,
    warnMessage
}: Props) {
    const warnElement = (warn && !empty && !error) &&
        <span className={contextualColor(empty, error, warn)}> {warnMessage} </span>;
    const errorElement = errorMessage && error &&
        <span className={contextualColor(empty, error, warn)}> {errorMessage} </span>;
    const iconElement = !hideIcon && icon(empty, error, warn) &&
        <FontAwesomeIcon className="margin-left-0-5" icon={icon(empty, error, warn)}/>;

    return (
        <span className={contextualColor(empty, error, warn)}>
            {children}
            {iconElement}
            {errorElement}
            {warnElement}
        </span>
    );
}
ValidationLabel.displayName = 'ValidationLabel';
ValidationLabel.defaultProps = {
    children: null,
    empty: false,
    error: false,
    errorMessage: '',
    hideIcon: false,
    warn: false,
    warnMessage: ''
};

export default ValidationLabel;