src/client/components/Buttons/RadioSlider.tsx
import React, { useState, useEffect, useCallback, FC } from 'react';import styled from 'styled-components';import STRINGS from '../../assets/strings.json'; export interface Props { disable?: boolean; large?: boolean; onChange?: (input: string) => void; option1: string; option2: string; option3: string; value: string; confirmMessageFunc?: (input: string) => string;} interface SelectorProps { color: string; left: string; width: string;} interface WrapperProps { disable: boolean; large: boolean;} const Wrapper = styled('div')` cursor: pointer; margin: auto; height: ${({ large }: WrapperProps): string => (large ? '3.0rem' : '1.5rem')}; line-height: ${({ large }: WrapperProps): string => (large ? '3.0rem' : '1.5rem')}; border-radius: 0.25rem; background: ${({ disable }: WrapperProps): string => (!disable ? '#ccc' : '#B0B0B0')}; position: relative; display: block; float: left;`; const Switch = styled('div')` cursor: pointer; position: relative; display: block; float: left; transition: 300ms ease-out; padding: 0 0.75rem;`; const Selector = styled('div')` left: ${({ left }: SelectorProps): string => left}; text-align: center; position: absolute; width: ${({ width }: SelectorProps): string => width}; box-sizing: border-box; transition: 300ms ease-out; border-radius: 0.225rem; color: white; box-shadow: 0px 0.125rem 0.625rem 0px #9b9b9b; background-color: ${({ color }: SelectorProps): string => color};`; const disabledColor = '#696969'; Function `RadioSlider` has a Cognitive Complexity of 31 (exceeds 5 allowed). Consider refactoring.
Function `RadioSlider` has 102 lines of code (exceeds 25 allowed). Consider refactoring.export const RadioSlider: FC<Props> = (props: Props) => { const { option1, option2, option3, disable = false, confirmMessageFunc } = props; const [selected, setSelected] = useState(option2); const [width, setWidth] = useState(0); const [left, setLeft] = useState(0); const [color, setColor] = useState(!disable ? STRINGS.ACCENT_COLOR_DARK : disabledColor); const [isLoaded, setIsLoaded] = useState(false); const [option1Width, setOption1Width] = useState(0); const [option2Width, setOption2Width] = useState(0); const [option3Width, setOption3Width] = useState(0); // Defines the width after the node as been loaded in the NodeSimilar blocks of code found in 3 locations. Consider refactoring. const option1Ref = useCallback((node): void => { if (node !== null) { setOption1Width(node.getBoundingClientRect().width); } }, []);Similar blocks of code found in 3 locations. Consider refactoring. const option2Ref = useCallback((node): void => { if (node !== null) { setOption2Width(node.getBoundingClientRect().width); } }, []);Similar blocks of code found in 3 locations. Consider refactoring. const option3Ref = useCallback((node): void => { if (node !== null) { setOption3Width(node.getBoundingClientRect().width); } }, []); // Moves the selector to the correct place, with the correct colors // Takes into account the disable state const toggle = useCallback( (input: string): void => { switch (input) { case option1: setWidth(option1Width); setLeft(0); setColor(!disable ? '#00C48C' : disabledColor); break; case option2: setWidth(option2Width); setLeft(option1Width); setColor(!disable ? STRINGS.ACCENT_COLOR_DARK : disabledColor); break; case option3: setWidth(option3Width); setLeft(option1Width + option2Width); setColor(!disable ? '#FF647C' : disabledColor); break; default: } setSelected(input); }, [option1, disable, option2, option3, option1Width, option2Width, option3Width] ); const { value } = props; // Forces a retoggle when the props.value changes (ie for outside changes) useEffect((): void => { if (isLoaded) { toggle(value); } }, [isLoaded, value, toggle]); // Will set isLoaded = true once the widths are successfully taken (ie non-zero) from the switch elements useEffect((): void => { if (isLoaded === false && option1Width && option2Width && option3Width) { toggle(value); setIsLoaded(true); } }, [isLoaded, option1Width, option2Width, option3Width, value, toggle]); const { onChange = null } = props; const onClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>): void => { const target = event.target as HTMLDivElement; if (!disable) { if (confirmMessageFunc) { // eslint-disable-next-line no-alert const confirmed = window.confirm(confirmMessageFunc(target.id)); if (!confirmed) { return; } } toggle(target.id); if (typeof onChange === 'function') { onChange(target.id); } } }; const { large = false } = props; // Selector's onClick works to allow you to click the middle button if it is already selected by default for the large button return ( <Wrapper large={large} disable={disable}> <Switch id={option1} onClick={onClick} ref={option1Ref}> {option1} </Switch> <Switch id={option2} onClick={onClick} ref={option2Ref}> {option2} </Switch> <Switch id={option3} onClick={onClick} ref={option3Ref}> {option3} </Switch> {isLoaded && ( <Selector left={`${left}px`} width={`${width}px`} color={color} id={selected} onClick={(event: React.MouseEvent<HTMLDivElement, MouseEvent>): void => { if (large) onClick(event); }}> {selected} </Selector> )} </Wrapper> );}; export default RadioSlider;