import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import { Account, Input } from 'src/components';
import LinearGradientContainer, {
  Color,
} from 'src/components/LinearGradientContainer/LinearGradientContainer';
import { PATTERN_CYBER } from 'src/constants/app';
import {
  SliceState,
  selectAccountsPassports,
  selectCommunityPassports,
} from 'src/features/passport/passports.redux';
import { useAppSelector } from 'src/redux/hooks';
import { useQueryClient } from 'src/contexts/queryClient';
import { getPassportByNickname } from 'src/containers/portal/utils';
import { useSearchParams } from 'react-router-dom';
import useOnClickOutside from 'src/hooks/useOnClickOutside';
import ButtonsGroup from 'src/components/buttons/ButtonsGroup/ButtonsGroup';
import useDebounce from 'src/hooks/useDebounce';
import styles from './AccountInput.module.scss';
import contains from '../utils';
import AccountInputOptionList from './AccountInputItem';
import AccountInputListContainer from './AccountInputContainer';
import { TypeRecipient } from '../type';

type Props = {
  recipient: string | undefined;
  setRecipient: React.Dispatch<React.SetStateAction<string | undefined>>;
};

const PLACEHOLDER_TITLE = 'choose recipient';

function AccountInput({ recipient, setRecipient }: Props) {
  const queryClient = useQueryClient();
  const [searchParams] = useSearchParams();
  const inputElem = useRef(null);
  const selectContainerRef = useRef(null);
  const { debounce } = useDebounce();
  const firstEffectOccured = useRef(false);

  const [isOpen, setIsOpen] = useState(false);
  const [selectedTypeRecipient, setSelectedTypeRecipient] = useState(
    TypeRecipient.friends
  );
  const [valueRecipient, setValueRecipient] = useState<string>('');
  const [listRecipient, setListRecipient] = useState<SliceState>({});

  const selectCommunity = useAppSelector(selectCommunityPassports);
  const { accounts } = useAppSelector(selectAccountsPassports);

  const clickOutsideHandler = () => setIsOpen(false);

  useOnClickOutside(selectContainerRef, clickOutsideHandler);

  useEffect(() => {
    if (recipient && recipient.length && recipient.match(PATTERN_CYBER)) {
      clickOutsideHandler();
    }
  }, [recipient]);

  const selectedDataRecipient = useMemo(() => {
    if (selectedTypeRecipient === TypeRecipient.my) {
      return accounts;
    }

    if (selectedTypeRecipient === TypeRecipient.following) {
      return selectCommunity.following;
    }

    return selectCommunity.friends;
  }, [selectedTypeRecipient, accounts, selectCommunity]);

  const getRecipient = useCallback(
    async (value: string) => {
      if (!value) {
        setRecipient(undefined);
        setListRecipient({});
        return;
      }

      if (value.match(PATTERN_CYBER)) {
        setRecipient(value);
        setListRecipient({});
        return;
      }

      let listRecipientTemp: SliceState = {};
      if (Object.keys(selectedDataRecipient).length > 0) {
        const result = contains(value, selectedDataRecipient);
        if (Object.keys(result).length) {
          listRecipientTemp = { ...result };
        }
      }

      const resultHandle = await await getPassportByNickname(
        queryClient,
        value
      );

      if (resultHandle) {
        const resultHandleRecipient = {
          [resultHandle.owner]: { loading: false, data: resultHandle },
        };

        listRecipientTemp = { ...resultHandleRecipient, ...listRecipientTemp };
      }

      setListRecipient(listRecipientTemp);
    },
    [selectedDataRecipient, queryClient, setRecipient]
  );

  const handleSearch = useCallback(
    debounce((inputVal: string) => getRecipient(inputVal), 500),
    [getRecipient]
  );

  const onChangeRecipient = useCallback(
    (inputVal: string) => {
      if (!inputVal.length) {
        setListRecipient(selectedDataRecipient);
      }
      setValueRecipient(inputVal);
      handleSearch(inputElem.current?.value);
    },
    [handleSearch, selectedDataRecipient]
  );

  useEffect(() => {
    if (!firstEffectOccured.current) {
      firstEffectOccured.current = true;
      const param = Object.fromEntries(searchParams.entries());
      if (Object.keys(param).length > 0) {
        const { recipient: recipientParam } = param;
        if (recipientParam) {
          setValueRecipient(recipientParam);
          handleSearch(recipientParam);
        }
      }
    }
  }, [handleSearch, searchParams]);

  const useListRecipient = useMemo(() => {
    if (!valueRecipient.length || !Object.keys(listRecipient).length) {
      return selectedDataRecipient;
    }
    return listRecipient;
  }, [listRecipient, valueRecipient, selectedDataRecipient]);

  const onClickByNickname = (owner: string, nickname: string | undefined) => {
    setValueRecipient(nickname || owner);
    setRecipient(owner);
    clickOutsideHandler();
  };

  if (!isOpen && recipient) {
    return (
      <button
        type="button"
        onClick={() => setIsOpen(true)}
        className={styles.containerBtnValue}
      >
        <LinearGradientContainer color={Color.Green} title={PLACEHOLDER_TITLE}>
          <Account
            avatar
            disabled
            address={recipient}
            styleUser={{ height: '42px' }}
          />
        </LinearGradientContainer>
      </button>
    );
  }

  return (
    <div className={styles.containerListAndInput} ref={selectContainerRef}>
      <Input
        ref={inputElem}
        id="recipient"
        value={valueRecipient}
        onChange={(e) => onChangeRecipient(e.target.value)}
        title={PLACEHOLDER_TITLE}
        color={!recipient ? Color.Red : Color.Green}
        classNameTextbox={styles.contentValueInput}
        onFocusFnc={() => setIsOpen(true)}
        // onClick={}
      />

      {isOpen && (
        <AccountInputListContainer>
          <div className={styles.containerButtonText}>
            <ButtonsGroup
              type="radio"
              items={Object.values(TypeRecipient).map((recipType) => {
                return {
                  label: recipType,
                  name: recipType,
                  checked: selectedTypeRecipient === recipType,
                };
              })}
              onChange={(val: TypeRecipient) => setSelectedTypeRecipient(val)}
            />
          </div>

          {useListRecipient && Object.keys(useListRecipient).length > 0 && (
            <AccountInputOptionList
              data={useListRecipient}
              onClickByNickname={onClickByNickname}
            />
          )}
        </AccountInputListContainer>
      )}
    </div>
  );
}

AccountInput.displayName = 'AccountInput';

export default AccountInput;

Synonyms

cyb/src/pages/teleport/components/Inputs/AccountInput/AccountInput.tsx

Neighbours