Untitled

mail@pastecode.io avatar
unknown
typescript
3 years ago
5.5 kB
3
Indexable
Never
import React, { useRef, useState } from "react";
import { useLocation } from "react-router-dom";
import { WriteTextControls } from "../../../reducers/interfaceData/types";
import { connect, ConnectedProps } from "react-redux";
import { useEffectOnce, useKeyPressEvent } from "react-use";
// @ts-ignore
import { composedWithMarkupTraps } from "../../../hocs/withMarkupTraps/withMarkupTraps";
// @ts-ignore
import { Button } from "../../Button";
import { WithMarkUpTrapsProps } from "../../../hocs/withMarkupTraps/types";
import useMobileDetect from "../../../customHooks/useMobileDetect";
import "./index.pcss";

type RootState = {
    interfaceData: {
        ui: {
            writeTextControls: WriteTextControls;
        };
    };
};

const mapState = ({
    interfaceData: {
        ui: { writeTextControls },
    },
}: RootState) => ({
    writeTextControls,
});

const connector = connect(mapState);

type PropsFromRedux = ConnectedProps<typeof connector>;
type HotKeys = string[];

type Props = PropsFromRedux & {
    hotKeys: HotKeys;
    renderMarkupTrapButton: ({ onClick, disabled }: WithMarkUpTrapsProps) => void;
    onConfirm: (text: string, markAsTrap?: boolean) => void;
    buttonText: string;
    placeholder: string;
};

const SUBMIT_KEY = "Enter";

const WriteTextControls = ({ writeTextControls, hotKeys, onConfirm, buttonText, placeholder, renderMarkupTrapButton }: Props) => {
    const textAreaRef = useRef<HTMLTextAreaElement>(null);
    const [text, setText] = useState("");
    const { isMobile } = useMobileDetect();
    const { state } = useLocation<{ id: string }>();
    const [withLowerCase, setWithLowerCase] = useState(false);
    useKeyPressEvent(SUBMIT_KEY, () => onEnter());
    useEffectOnce(() => checkForLoweCase());

    const onEnter = () => {
        if (!isUserWroteText()) {
            return;
        }

        onConfirm(getText());
        handleResetText();
        setFocusOnTextArea();
    };

    const checkForLoweCase = () => {
        if (!writeTextControls.options || !writeTextControls.options.withLowerCase || !writeTextControls.options.withLowerCase.length) {
            return;
        }

        const { id } = state;
        return setWithLowerCase(Boolean(writeTextControls.options.withLowerCase.find((gameId) => gameId === id)));
    };

    const renderHotKeys = (hotKeys: string[]) => {
        if (!hotKeys || !hotKeys.length) {
            return null;
        }

        const getTextWithHotKey = (cursorPosition: number, hotKey: string) => {
            return [text.slice(0, cursorPosition).concat(hotKey), text.slice(cursorPosition)].join("");
        };

        const onClick = (e: React.MouseEvent<HTMLButtonElement>, hotKey: string) => {
            e.preventDefault();

            const cursorPosition = textAreaRef?.current?.selectionStart;

            if (cursorPosition) {
                const text = getTextWithHotKey(cursorPosition, hotKey);
                setText(text);
            }
        };

        return hotKeys.map((hotKey) => (
            <Button
                key={hotKey}
                classNames="write-text-controls__hotKey"
                clickHandler={(e: React.MouseEvent<HTMLButtonElement>) => onClick(e, hotKey)}
                text={hotKey}
            />
        ));
    };

    const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
        setText(e.target.value);
    };

    const handleResetText = () => {
        setText("");
    };

    const setFocusOnTextArea = () => {
        textAreaRef?.current?.focus();
    };

    const getText = () => {
        if (withLowerCase) {
            return text.toLowerCase();
        }

        return text;
    };

    const isUserWroteText = () => {
        return text.trim().length;
    };

    const setInitialSettings = () => {
        handleResetText();
        setFocusOnTextArea();
    };

    const onClick = (e: React.MouseEvent<HTMLButtonElement>, markAsTrap?: boolean) => {
        e.preventDefault();
        onConfirm(getText(), markAsTrap);
        setInitialSettings();
    };

    const onAltClick = (e: React.MouseEvent<HTMLButtonElement>) => {
        e.preventDefault();
        onConfirm("");
        setInitialSettings();
    };

    return (
        <div className="write-text-controls">
            <form className="write-text-controls__form">
                {renderHotKeys(hotKeys || writeTextControls.quotes)}
                <textarea
                    ref={textAreaRef}
                    onChange={handleChange}
                    className="write-text-controls__textarea"
                    cols={10}
                    rows={2.5}
                    placeholder={placeholder || writeTextControls.placeholder}
                    value={text}
                    autoFocus={!isMobile}
                />
                <Button
                    classNames="write-text-controls__button write-text-controls__button--with-margin-bottom"
                    clickHandler={onClick}
                    disabled={!isUserWroteText()}
                    text={writeTextControls.ready}
                />
                <Button classNames="write-text-controls__button" clickHandler={onAltClick} text={buttonText || writeTextControls.noText} />
            </form>
            {renderMarkupTrapButton({
                onClick: (e: React.MouseEvent<HTMLButtonElement>) => onClick(e, true),
                disabled: false,
            })}
        </div>
    );
};

export default connector(composedWithMarkupTraps(WriteTextControls));