@headlessui/react#Menu TypeScript Examples

The following examples show how to use @headlessui/react#Menu. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: stake-actions.tsx    From arkadiko with GNU General Public License v3.0 6 votes vote down vote up
StakeActions: React.FC<StakeActionsProps> = ({ children }) => {
  return (
    <Menu as="div" className="relative flex items-center justify-end">
      {({ open }) => (
        <>
          <Menu.Button className="inline-flex items-center justify-center w-8 h-8 text-gray-400 bg-white rounded-full hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
            <span className="sr-only">Open options</span>
            <StyledIcon as="DotsVerticalIcon" size={5} />
          </Menu.Button>
          <Transition
            show={open}
            as={Fragment}
            enter="transition ease-out duration-100"
            enterFrom="transform opacity-0 scale-95"
            enterTo="transform opacity-100 scale-100"
            leave="transition ease-in duration-75"
            leaveFrom="transform opacity-100 scale-100"
            leaveTo="transform opacity-0 scale-95"
          >
            <Menu.Items
              static
              className="absolute top-0 z-10 w-48 mx-3 mt-1 origin-top-right bg-white divide-y divide-gray-200 rounded-md shadow-lg dark:bg-zinc-800 dark:divide-zinc-600 right-7 ring-1 ring-black ring-opacity-5 focus:outline-none"
            >
              <div className="px-1 py-1">{children}</div>
            </Menu.Items>
          </Transition>
        </>
      )}
    </Menu>
  );
}
Example #2
Source File: ProfileDropDown.tsx    From platform with MIT License 5 votes vote down vote up
export default function ProfileDropDown(props) {
  const { signOut, avatarUrl } = props;
  return (
    <Menu as="div" className="relative inline-block text-left">
      {({ open }) => (
        <>
          <div>
            <Menu.Button className="inline-flex justify-center w-full rounded-lg border-2 border-teal-500 shadow-sm bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-teal-500">
              {avatarUrl ? (
                <img
                  className="rounded-md h-8 w-8"
                  src={avatarUrl}
                  alt="Avatar"
                />
              ) : (
                <span className="inline-block relative h-8 w-8 rounded-lg">
                  <svg
                    className="h-full w-full text-gray-300 rounded-lg"
                    fill="currentColor"
                    viewBox="0 0 24 24"
                  >
                    <path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
                  </svg>
                </span>
              )}
            </Menu.Button>
          </div>

          <Transition
            show={open}
            as={Fragment}
            enter="transition ease-out duration-100"
            enterFrom="transform opacity-0 scale-95"
            enterTo="transform opacity-100 scale-100"
            leave="transition ease-in duration-75"
            leaveFrom="transform opacity-100 scale-100"
            leaveTo="transform opacity-0 scale-95"
          >
            <Menu.Items
              static
              className="origin-top-right absolute right-0 mt-2 w-32 sm:w-44 rounded-md shadow-lg bg-white border border-teal-500 ring-black ring-opacity-100 divide-y divide-gray-100 focus:outline-none"
            >
              <div className="py-1">
                <Menu.Item>
                  {({ active }) => (
                    <Link
                      to="/app/profile"
                      className={classNames(
                        active ? "bg-gray-100 text-gray-900" : "text-gray-700",
                        "block px-4 py-1 sm:py-2 text-xs sm:text-sm"
                      )}
                    >
                      Profile
                    </Link>
                  )}
                </Menu.Item>
              </div>
              <div className="py-1">
                <Menu.Item>
                  {({ active }) => (
                    <div
                      onClick={signOut}
                      className={classNames(
                        active ? "bg-gray-100 text-gray-900" : "text-gray-700",
                        "block px-4 py-1 sm:py-2 text-xs sm:text-sm cursor-pointer"
                      )}
                    >
                      Logout
                    </div>
                  )}
                </Menu.Item>
              </div>
            </Menu.Items>
          </Transition>
        </>
      )}
    </Menu>
  );
}
Example #3
Source File: stake-diko-section.tsx    From arkadiko with GNU General Public License v3.0 4 votes vote down vote up
StakeDikoSection = ({
  loadingData,
  loadingDikoToStDiko,
  stDikoToDiko,
  stakedAmount,
  dikoCooldown,
  dikoBalance,
  stDikoBalance,
  apy,
  cooldownRunning,
  startDikoCooldown,
  setShowStakeModal,
  setShowUnstakeModal,
  canUnstake
}) => {
  return (
    <>
      <section>
        <header className="pb-5 border-b border-gray-200 dark:border-zinc-600 sm:flex sm:justify-between sm:items-end">
          <div>
            <h3 className="text-lg leading-6 text-gray-900 font-headings dark:text-zinc-50">
              DIKO
            </h3>
            <p className="max-w-3xl mt-2 text-sm text-gray-500 dark:text-zinc-400">
              When staking DIKO in the security module{' '}
              <span className="font-semibold">you will receive stDIKO</span> which is a
              representation of your share of the pool. DIKO in the pool is{' '}
              <span className="font-semibold">auto-compounding</span>. Your amount of stDIKO{' '}
              <span className="font-semibold">does not change</span>, but the DIKO value it
              represents <span className="font-semibold">will increase</span>. Both DIKO and
              stDIKO can be used to propose and vote in governance.
            </p>
          </div>
          <div className="flex items-center mt-2 sm:mt-0">
            <div className="w-5.5 h-5.5 rounded-full bg-indigo-200 flex items-center justify-center">
              <StyledIcon as="QuestionMarkCircleIcon" size={5} className="text-indigo-600" />
            </div>
            <a
              className="inline-flex items-center px-2 text-sm font-medium text-indigo-500 dark:text-indigo-300 dark:hover:text-indigo-200 hover:text-indigo-700"
              href="https://docs.arkadiko.finance/protocol/diko/security-module"
              target="_blank"
              rel="noopener noreferrer"
            >
              More on the Security Module
              <StyledIcon as="ExternalLinkIcon" size={3} className="block ml-2" />
            </a>
          </div>
        </header>

        <div className="mt-4 bg-white divide-y divide-gray-200 rounded-md shadow dark:divide-gray-600 dark:bg-zinc-800">
          <div className="px-4 py-5 space-y-6 divide-y divide-gray-200 dark:divide-zinc-600 sm:p-6">
            <div className="md:grid md:grid-flow-col gap-4 sm:grid-cols-[min-content,auto]">
              <div className="self-center w-14">
                <img className="w-12 h-12 rounded-full" src={tokenList[1].logo} alt="" />
              </div>
              <div className="mt-3 md:mt-0">
                <p className="text-sm leading-6 text-gray-500 dark:text-zinc-400 md:mb-1">
                  stDIKO
                </p>
                {loadingDikoToStDiko ? (
                  <Placeholder className="py-2" width={Placeholder.width.HALF} />
                ) : (
                  <div>
                    <p className="text-lg font-semibold dark:text-white">
                      {microToReadable(stDikoBalance).toLocaleString(undefined, {
                        minimumFractionDigits: 2,
                        maximumFractionDigits: 6,
                      })}
                    </p>
                    <div className="flex items-center md:mt-1">
                      <p className="text-xs text-gray-500 dark:text-zinc-400">
                        1 stDIKO ≈{' '}
                        {stDikoToDiko.toLocaleString(undefined, {
                          minimumFractionDigits: 2,
                          maximumFractionDigits: 6,
                        })}{' '}
                        DIKO
                      </p>
                      <Tooltip
                        className="ml-2"
                        shouldWrapChildren={true}
                        label={`stDIKO's value is determined by dividing the total supply of DIKO in the pool by the total supply of stDIKO`}
                      >
                        <StyledIcon
                          as="InformationCircleIcon"
                          size={4}
                          className="block ml-2 text-gray-400"
                        />
                      </Tooltip>
                    </div>
                  </div>
                )}
              </div>
              <div className="mt-3 md:mt-0">
                <p className="text-sm leading-6 text-gray-500 dark:text-zinc-400 md:mb-1">
                  DIKO
                </p>
                {loadingData ? (
                  <Placeholder className="py-2" width={Placeholder.width.HALF} />
                ) : (
                  <p className="text-lg font-semibold dark:text-white">
                    {microToReadable(stakedAmount).toLocaleString(undefined, {
                      minimumFractionDigits: 2,
                      maximumFractionDigits: 6,
                    })}
                  </p>
                )}
              </div>
              <div className="mt-3 md:mt-0">
                <p className="text-sm leading-6 text-gray-500 dark:text-zinc-400 md:mb-1">
                  Current APR
                </p>
                {loadingData ? (
                  <Placeholder className="py-2" width={Placeholder.width.HALF} />
                ) : (
                  <p className="text-indigo-600 dark:text-indigo-400">{apy}%</p>
                )}
              </div>
              <div className="mt-3 md:mt-0">
                <p className="flex items-center text-sm leading-6 text-gray-500 dark:text-zinc-400 md:mb-1">
                  Cooldown status
                  <Tooltip
                    className="ml-2"
                    shouldWrapChildren={true}
                    label={`The 10-day cooldown period is the time required prior to unstaking your tokens. Once it expires, there is a 2-day window to unstake your tokens.`}
                  >
                    <StyledIcon
                      as="InformationCircleIcon"
                      size={5}
                      className="block ml-2 text-gray-400"
                    />
                  </Tooltip>
                </p>
                {loadingData ? (
                  <Placeholder className="py-2" width={Placeholder.width.HALF} />
                ) : (
                  <p className="text-base dark:text-white">{dikoCooldown}</p>
                )}
              </div>
              <div className="self-center">
                <Menu as="div" className="relative flex items-center justify-end">
                  {({ open }) => (
                    <>
                      <Menu.Button className="inline-flex items-center justify-center px-2 py-1 text-sm text-indigo-500 bg-white rounded-lg focus:outline-none focus-visible:ring focus-visible:ring-indigo-500 focus-visible:ring-opacity-75 dark:bg-zinc-800 dark:text-indigo-400">
                        <span>Actions</span>
                        <StyledIcon
                          as="ChevronUpIcon"
                          size={4}
                          className={`${
                            open
                              ? ''
                              : 'transform rotate-180 transition ease-in-out duration-300'
                          } ml-2`}
                        />
                      </Menu.Button>
                      <Transition
                        show={open}
                        as={Fragment}
                        enter="transition ease-out duration-100"
                        enterFrom="transform opacity-0 scale-95"
                        enterTo="transform opacity-100 scale-100"
                        leave="transition ease-in duration-75"
                        leaveFrom="transform opacity-100 scale-100"
                        leaveTo="transform opacity-0 scale-95"
                      >
                        <Menu.Items
                          static
                          className="absolute top-0 z-10 w-48 mx-3 mt-6 origin-top-right bg-white divide-y divide-gray-200 rounded-md shadow-lg dark:divide-gray-600 right-3 ring-1 ring-black ring-opacity-5 focus:outline-none"
                        >
                          <div className="px-1 py-1">
                            <Menu.Item>
                              {({ active }) => (
                                <button
                                  className={`${
                                    active
                                      ? 'bg-indigo-500 text-white disabled:bg-gray-400 disabled:cursor-not-allowed'
                                      : 'text-gray-900'
                                  } group flex rounded-md items-center w-full px-2 py-2 text-sm`}
                                  disabled={!(dikoBalance > 0)}
                                  onClick={() => setShowStakeModal(true)}
                                >
                                  {!(dikoBalance > 0) ? (
                                    <Tooltip
                                      placement="left"
                                      className="mr-2"
                                      label={`You don't have any available DIKO to stake in your wallet.`}
                                    >
                                      <div className="flex items-center w-full">
                                        <StyledIcon
                                          as="ArrowCircleDownIcon"
                                          size={5}
                                          className="block mr-3 text-gray-400 group-hover:text-white"
                                        />
                                        Stake
                                      </div>
                                    </Tooltip>
                                  ) : (
                                    <>
                                      <StyledIcon
                                        as="ArrowCircleDownIcon"
                                        size={5}
                                        className="block mr-3 text-gray-400 group-hover:text-white"
                                      />
                                      Stake
                                    </>
                                  )}
                                </button>
                              )}
                            </Menu.Item>

                            <Menu.Item>
                              {({ active }) => (
                                <button
                                  className={`${
                                    active
                                      ? 'bg-indigo-500 text-white disabled:bg-gray-400 disabled:cursor-not-allowed'
                                      : 'text-gray-900'
                                  } group flex rounded-md items-center w-full px-2 py-2 text-sm`}
                                  onClick={() => setShowUnstakeModal(true)}
                                  disabled={!(stakedAmount > 0 && canUnstake)}
                                >
                                  {!(stakedAmount > 0) ? (
                                    <Tooltip
                                      placement="left"
                                      className="mr-2"
                                      label={`You don't have any staked DIKO.`}
                                    >
                                      <div className="flex items-center w-full">
                                        <StyledIcon
                                          as="ArrowCircleUpIcon"
                                          size={5}
                                          className="mr-3 text-gray-400 group-hover:text-white"
                                        />
                                        Unstake
                                      </div>
                                    </Tooltip>
                                  ) : !canUnstake ? (
                                    <Tooltip
                                      placement="left"
                                      className="mr-2"
                                      label={`Either you haven't started the cooldown period, or the cooldown timer hasn't ended yet.`}
                                    >
                                      <div className="flex items-center w-full">
                                        <StyledIcon
                                          as="ArrowCircleUpIcon"
                                          size={5}
                                          className="mr-3 text-gray-400 group-hover:text-white"
                                        />
                                        Unstake
                                      </div>
                                    </Tooltip>
                                  ) : (
                                    <>
                                      <StyledIcon
                                        as="ArrowCircleUpIcon"
                                        size={5}
                                        className="mr-3 text-gray-400 group-hover:text-white"
                                      />
                                      Unstake
                                    </>
                                  )}
                                </button>
                              )}
                            </Menu.Item>

                            <Menu.Item>
                              {({ active }) => (
                                <button
                                  className={`${
                                    active
                                      ? 'bg-indigo-500 text-white disabled:bg-gray-400 disabled:cursor-not-allowed'
                                      : 'text-gray-900'
                                  } group flex rounded-md items-center w-full px-2 py-2 text-sm`}
                                  onClick={() => startDikoCooldown()}
                                  disabled={cooldownRunning}
                                >
                                  {cooldownRunning ? (
                                    <Tooltip
                                      placement="left"
                                      className="mr-2"
                                      label={`Cooldown is already in progress.`}
                                    >
                                      <div className="flex items-center w-full">
                                        <StyledIcon
                                          as="ClockIcon"
                                          size={5}
                                          className="mr-3 text-gray-400 group-hover:text-white"
                                        />
                                        Start cooldown
                                      </div>
                                    </Tooltip>
                                  ) : (
                                    <>
                                      <StyledIcon
                                        as="ClockIcon"
                                        size={5}
                                        className="mr-3 text-gray-400 group-hover:text-white"
                                      />
                                      Start cooldown
                                    </>
                                  )}
                                </button>
                              )}
                            </Menu.Item>
                          </div>
                        </Menu.Items>
                      </Transition>
                    </>
                  )}
                </Menu>
              </div>
            </div>
          </div>
        </div>
      </section>
    </>
  );
}
Example #4
Source File: events.tsx    From eventcatalog with MIT License 4 votes vote down vote up
export default function Page({ events, services, domains }: PageProps) {
  const filters = [
    {
      id: 'domains',
      name: `Filter by Domains (${domains.length})`,
      options: domains.map((domain) => ({
        value: domain,
        label: domain,
        checked: false,
      })),
    },
    {
      id: 'services',
      name: `Filter by Services (${services.length})`,
      options: services.map((service) => ({
        value: service,
        label: service,
        checked: false,
      })),
    },
  ];

  const [selectedFilters, setSelectedFilters] = useState({ services: [], domains: [] });
  const [showMermaidDiagrams, setShowMermaidDiagrams] = useState(false);
  const [eventsToRender, setEventsToRender] = useState(events);
  const [searchFilter, setSearchFilter] = useState('');

  const handleFilterSelection = (option, type, event) => {
    console.log(option, type, event);

    if (event.target.checked) {
      const newFilters = selectedFilters[type].concat([option.value]);
      setSelectedFilters({ ...selectedFilters, [type]: newFilters });
    } else {
      const newFilters = selectedFilters[type].filter((value) => value !== option.value);
      setSelectedFilters({ ...selectedFilters, [type]: newFilters });
    }
  };

  const getFilteredEvents = (): any => {
    if (!selectedFilters.services && !searchFilter && !selectedFilters.domains) return events;

    let filteredEvents = events;

    if (selectedFilters.services.length > 0) {
      // @ts-ignore
      filteredEvents = filteredEvents.filter((event) => {
        const { services: serviceFilters } = selectedFilters;

        const hasConsumersFromFilters = event.consumerNames.some((consumerId) => serviceFilters.indexOf(consumerId) > -1);
        const hasProducersFromFilters = event.producerNames.some((producerId) => serviceFilters.indexOf(producerId) > -1);

        return hasConsumersFromFilters || hasProducersFromFilters;
      });
    }

    if (selectedFilters.domains.length > 0) {
      // @ts-ignore
      filteredEvents = filteredEvents.filter((event) => {
        const { domains: domainFilters } = selectedFilters;
        return domainFilters.indexOf(event.domain) > -1;
      });
    }

    if (searchFilter) {
      filteredEvents = filteredEvents.filter((event) => event.name.toLowerCase().includes(searchFilter.toLowerCase()));
    }

    return filteredEvents;
  };

  useEffect(() => {
    setEventsToRender(getFilteredEvents());
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedFilters, searchFilter]);

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const debouncedFilter = useCallback(
    debounce((e) => {
      setSearchFilter(e.target.value);
    }, 500),
    [eventsToRender]
  );

  const filtersApplied = !!searchFilter || selectedFilters.services.length > 0;
  const { title } = useConfig();

  return (
    <>
      <Head>
        <title>{title} - All Events</title>
      </Head>
      <main className="max-w-7xl mx-auto min-h-screen px-4 xl:px-0">
        <div className="relative z-10 flex items-baseline justify-between pt-8 pb-6 border-b border-gray-200">
          <h1 className="text-2xl font-extrabold tracking-tight text-gray-900">Events ({events.length})</h1>

          <div className="flex items-center">
            <Menu as="div" className="hidden relative text-left">
              <div>
                <Menu.Button className="group inline-flex justify-center text-sm font-medium text-gray-700 hover:text-gray-900">
                  Sort
                  <ChevronDownIcon
                    className="flex-shrink-0 -mr-1 ml-1 h-5 w-5 text-gray-400 group-hover:text-gray-500"
                    aria-hidden="true"
                  />
                </Menu.Button>
              </div>

              <Transition
                as={Fragment}
                enter="transition ease-out duration-100"
                enterFrom="transform opacity-0 scale-95"
                enterTo="transform opacity-100 scale-100"
                leave="transition ease-in duration-75"
                leaveFrom="transform opacity-100 scale-100"
                leaveTo="transform opacity-0 scale-95"
              >
                <Menu.Items className="origin-top-right absolute right-0 mt-2 w-40 rounded-md shadow-2xl bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
                  <div className="py-1">
                    {sortOptions.map((option) => (
                      <Menu.Item key={option.name}>
                        {({ active }) => (
                          <a
                            href={option.href}
                            className={classNames(
                              option.current ? 'font-medium text-gray-900' : 'text-gray-500',
                              active ? 'bg-gray-100' : '',
                              'block px-4 py-2 text-sm'
                            )}
                          >
                            {option.name}
                          </a>
                        )}
                      </Menu.Item>
                    ))}
                  </div>
                </Menu.Items>
              </Transition>
            </Menu>
          </div>
        </div>

        <section className="pt-6 pb-24">
          <div className="grid grid-cols-4 gap-x-8 gap-y-10">
            {/* Filters */}
            <form className="hidden lg:block">
              <div className="border-b border-gray-200 pb-6">
                <label htmlFor="event" className="font-bold block text-sm font-medium text-gray-700">
                  Search Events
                </label>
                <div className="mt-1 relative rounded-md shadow-sm">
                  <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                    <SearchIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
                  </div>
                  <input
                    type="text"
                    name="event"
                    id="event"
                    onChange={debouncedFilter}
                    className="focus:ring-gray-500 focus:border-gray-500 block w-full pl-10 sm:text-sm border-gray-300 rounded-md"
                  />
                </div>
              </div>
              {filters.map((section: any) => {
                if (!section.options.length) return null;
                return (
                  <div key={section.id} className="border-b border-gray-200 py-6">
                    <h3 className="-my-3 flow-root">
                      <div className="py-3 bg-white w-full flex items-center justify-between text-sm text-gray-400 hover:text-gray-500">
                        <span className="font-bold font-medium text-gray-900">{section.name}</span>
                      </div>
                    </h3>
                    <div className="pt-6">
                      <div className="space-y-4">
                        {section.options.map((option, optionIdx) => (
                          <div key={option.value} className="flex items-center">
                            <input
                              id={`filter-${section.id}-${optionIdx}`}
                              name={`${section.id}[]`}
                              defaultValue={option.value}
                              type="checkbox"
                              onChange={(event) => handleFilterSelection(option, section.id, event)}
                              defaultChecked={option.checked}
                              className="h-4 w-4 border-gray-300 rounded text-gray-600 focus:ring-gray-500"
                            />
                            <label htmlFor={`filter-${section.id}-${optionIdx}`} className="ml-3 text-sm text-gray-600">
                              {option.label}
                            </label>
                          </div>
                        ))}
                      </div>
                    </div>
                  </div>
                );
              })}

              <div className="border-b border-gray-200 py-6">
                <h3 className="-my-3 flow-root">
                  <div className="py-3 bg-white w-full flex items-center justify-between text-sm text-gray-400 hover:text-gray-500">
                    <span className="font-bold font-medium text-gray-900">Features</span>
                  </div>
                </h3>
                <div className="pt-6">
                  <div className="space-y-4">
                    <div className="flex items-center">
                      <input
                        id="show-mermaid"
                        type="checkbox"
                        onChange={(e) => setShowMermaidDiagrams(e.target.checked)}
                        defaultChecked={showMermaidDiagrams}
                        className="h-4 w-4 border-gray-300 rounded text-gray-600 focus:ring-gray-500"
                      />
                      <label htmlFor="show-mermaid" className="ml-3 text-sm text-gray-600">
                        Show Mermaid Diagrams
                      </label>
                    </div>
                  </div>
                </div>
              </div>
            </form>

            <div className="col-span-4 lg:col-span-3">
              <div>
                <h2 className="text-gray-500 text-xs font-medium uppercase tracking-wide">
                  {filtersApplied
                    ? `Filtered Events (${eventsToRender.length}/${events.length})`
                    : `All Events (${events.length})`}
                </h2>
                <EventGrid events={eventsToRender} showMermaidDiagrams={showMermaidDiagrams} />
                {eventsToRender.length === 0 && (
                  <div className="text-gray-400 flex h-96  justify-center items-center">
                    <div>
                      <SearchIcon className="w-6 h-6 inline-block mr-1" />
                      No events found.
                    </div>
                  </div>
                )}
              </div>
            </div>
          </div>
        </section>
      </main>
    </>
  );
}
Example #5
Source File: services.tsx    From eventcatalog with MIT License 4 votes vote down vote up
export default function Page({ services }: PageProps) {
  const [servicesToRender, setServicesToRender] = useState(services);
  const [searchFilter, setSearchFilter] = useState('');

  const getFilteredServices = (): any => {
    let filteredServices = services;

    if (searchFilter) {
      filteredServices = filteredServices.filter((service) => service.name.toLowerCase().includes(searchFilter.toLowerCase()));
    }

    return filteredServices;
  };

  useEffect(() => {
    setServicesToRender(getFilteredServices());
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchFilter]);

  const debouncedFilter = useCallback(
    debounce((e) => {
      setSearchFilter(e.target.value);
    }, 500),
    [servicesToRender]
  );

  const filtersApplied = !!searchFilter;
  const [showMermaidDiagrams, setShowMermaidDiagrams] = useState(false);
  const { title } = useConfig();

  return (
    <>
      <Head>
        <title>{title} - All Services</title>
      </Head>
      <main className="max-w-7xl mx-auto md:min-h-screen px-4 xl:px-0">
        <div className="relative z-10 flex items-baseline justify-between pt-8 pb-6 border-b border-gray-200">
          <h1 className="text-2xl font-extrabold tracking-tight text-gray-900">Services ({services.length})</h1>

          <div className="flex items-center">
            <Menu as="div" className="relative hidden text-left">
              <div>
                <Menu.Button className="group inline-flex justify-center text-sm font-medium text-gray-700 hover:text-gray-900">
                  Sort
                  <ChevronDownIcon
                    className="flex-shrink-0 -mr-1 ml-1 h-5 w-5 text-gray-400 group-hover:text-gray-500"
                    aria-hidden="true"
                  />
                </Menu.Button>
              </div>

              <Transition
                as={Fragment}
                enter="transition ease-out duration-100"
                enterFrom="transform opacity-0 scale-95"
                enterTo="transform opacity-100 scale-100"
                leave="transition ease-in duration-75"
                leaveFrom="transform opacity-100 scale-100"
                leaveTo="transform opacity-0 scale-95"
              >
                <Menu.Items className="origin-top-right absolute right-0 mt-2 w-40 rounded-md shadow-2xl bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
                  <div className="py-1">
                    {sortOptions.map((option) => (
                      <Menu.Item key={option.name}>
                        {({ active }) => (
                          <a
                            href={option.href}
                            className={classNames(
                              option.current ? 'font-medium text-gray-900' : 'text-gray-500',
                              active ? 'bg-gray-100' : '',
                              'block px-4 py-2 text-sm'
                            )}
                          >
                            {option.name}
                          </a>
                        )}
                      </Menu.Item>
                    ))}
                  </div>
                </Menu.Items>
              </Transition>
            </Menu>
          </div>
        </div>

        <section className="pt-6 pb-24">
          <div className="grid grid-cols-4 gap-x-8 gap-y-10">
            {/* Filters */}
            <form className="hidden lg:block">
              <div className="border-b border-gray-200 pb-6">
                <label htmlFor="service" className="font-bold block text-sm font-medium text-gray-700">
                  Search Services
                </label>
                <div className="mt-1 relative rounded-md shadow-sm">
                  <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                    <SearchIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
                  </div>
                  <input
                    type="text"
                    name="service"
                    id="service"
                    onChange={debouncedFilter}
                    className="focus:ring-gray-500 focus:border-gray-500 block w-full pl-10 sm:text-sm border-gray-300 rounded-md"
                  />
                </div>
              </div>

              <div className="border-b border-gray-200 pb-6">
                <h3 className="-my-3 flow-root">
                  <div className="py-3 bg-white w-full flex items-center justify-between text-sm text-gray-400 hover:text-gray-500">
                    <span className="font-medium text-gray-900">Features</span>
                  </div>
                </h3>
                <div className="pt-6">
                  <div className="space-y-4">
                    <div className="flex items-center">
                      <input
                        id="show-mermaid"
                        type="checkbox"
                        onChange={(e) => setShowMermaidDiagrams(e.target.checked)}
                        defaultChecked={showMermaidDiagrams}
                        className="h-4 w-4 border-gray-300 rounded text-gray-600 focus:ring-gray-500"
                      />
                      <label htmlFor="show-mermaid" className="ml-3 text-sm text-gray-600">
                        Show Mermaid Diagrams
                      </label>
                    </div>
                  </div>
                </div>
              </div>
            </form>

            <div className="col-span-4 lg:col-span-3">
              <div>
                <h2 className="text-gray-500 text-xs font-medium uppercase tracking-wide">
                  {filtersApplied
                    ? `Filtered Services (${servicesToRender.length}/${services.length})`
                    : `All Services (${services.length})`}
                </h2>
                <ServiceGrid services={servicesToRender} showMermaidDiagrams={showMermaidDiagrams} />
                {servicesToRender.length === 0 && (
                  <div className="text-gray-400 flex h-96  justify-center items-center">
                    <div>
                      <SearchIcon className="w-6 h-6 inline-block mr-1" />
                      No services found.
                    </div>
                  </div>
                )}
              </div>
            </div>
          </div>
        </section>
      </main>
    </>
  );
}
Example #6
Source File: FilterMenu.tsx    From platform with MIT License 4 votes vote down vote up
export default function FilterMenu(props) {
  const { filters, setFilters, selected, setSelected, setAllDeselected } = props;
  const trueState = Object.keys(filters).reduce((pre, cur) => ({ ...pre, [cur]: true }), {});
  const falseState = Object.keys(filters).reduce((pre, cur) => ({ ...pre, [cur]: false }), {});
  const [someSelected, setSomeSelected] = useState(false);
  const handleClick = async (type) => {
    setFilters((state) => {
      return {
        ...state,
        [type]: !state[type],
      };
    });
  };
  const handleSelectAll = () => {
    selected ? setFilters(trueState) : setFilters(falseState);
    setSelected(!selected);
  };

  useEffect(() => {
    const allSelected = Object.values(filters).every(filter => filter);
    if (allSelected) {
      setSelected(false /* "Deselect All =" */);
    }
    setAllDeselected(Object.values(filters).every(filter => filter === false));

    // Note: "selected" is unchecked i.e false!
    setSomeSelected(Object.values(filters).some(filter => !filter));
  }, [filters, setSelected, setAllDeselected]);

  return (
    <div className="mt-0.5">
      <Menu as="div" className="relative inline-block text-left">
        <div>
          <Menu.Button
            className={classNames(someSelected ? 'text-teal-600 bg-gray-100' : 'text-gray-500 bg-white hover:bg-gray-50', `ml-2 relative inline-flex items-center px-2 py-2 shadow-md 
                      rounded-md border border-gray-300 text-sm ring-teal-500
                       focus:z-10 focus:outline-none 
                      focus:ring-1 focus:ring-teal-500 focus:border-teal-500`)}
          >
            <span className="sr-only">Filter</span>
            <i className="fas fa-filter"></i>
          </Menu.Button>
        </div>

        <Menu.Items className="origin-top-right absolute right-0 mt-2 w-34 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">

          {
            Object.keys(filters).map((filterName, key) => {
              return (
                <Menu.Item key={key} onClick={() => handleClick(filterName)}>
                  {({ active }) => (
                    <div
                      className={classNames(
                        active ? "bg-gray-100 text-gray-900" : "text-gray-700",
                        "group flex items-center px-4 py-2 text-sm cursor-pointer"
                      )}
                    >
                      <input
                        type="checkbox"
                        onChange={() => { }}
                        checked={filters[filterName]}
                        className="mr-3 focus:ring-teal-500 h-4 w-4 text-teal-600 rounded cursor-pointer"
                      />
                      {`${filterName[0].toUpperCase()}${filterName.slice(1)}`}
                    </div>
                  )}
                </Menu.Item>
              )
            })
          }
          <div className="py-1 border-t border-gray-100">
            <Menu.Item onClick={handleSelectAll}>
              {({ active }) => (
                <div
                  className={classNames(
                    active ? "bg-gray-100 text-gray-900" : "text-gray-700",
                    "group flex items-center px-4 py-2 text-xs cursor-pointer text-center"
                  )}
                >
                  {selected ? "Select All" : "Deselect All"}
                </div>
              )}
            </Menu.Item>
          </div>
        </Menu.Items>
      </Menu>
    </div>
  );
}
Example #7
Source File: ClassesDropdown.tsx    From cpinitiative with Mozilla Public License 2.0 4 votes vote down vote up
export default function ClassesDropdown({ dark = false }): JSX.Element {
  return (
    <Menu as="div" className="relative inline-block text-left">
      {({ open }) => (
        <div className="relative h-full">
          <Menu.Button
            className={classNames(
              "group inline-flex items-center h-full px-1 pt-1 border-b-2 border-transparent text-sm leading-6 font-medium transition ease-in-out duration-150",
              dark
                ? "hover:text-gray-200 hover:border-transparent focus:outline-none focus:text-gray-200"
                : "hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300",
              open
                ? dark
                  ? "text-gray-200"
                  : "text-gray-700"
                : dark
                ? "text-gray-400"
                : "text-gray-500"
            )}
          >
            Classes
            <ChevronDownIcon
              className={classNames(
                "h-5 w-5 ml-2 transition ease-in-out duration-150",
                dark
                  ? "group-hover:text-gray-200 group-focus:text-gray-200"
                  : "group-hover:text-gray-500 group-focus:text-gray-500",
                open
                  ? dark
                    ? "text-gray-200"
                    : "text-gray-500"
                  : "text-gray-400"
              )}
              aria-hidden="true"
            />
          </Menu.Button>
          <Transition
            as={Fragment}
            enter="transition ease-out duration-100"
            enterFrom="transform opacity-0 scale-95"
            enterTo="transform opacity-100 scale-100"
            leave="transition ease-in duration-75"
            leaveFrom="transform opacity-100 scale-100"
            leaveTo="transform opacity-0 scale-95"
          >
            <Menu.Items
              className={classNames(
                "origin-top-right absolute left-0 -mt-2 w-56 rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none",
                dark ? "bg-gray-800" : "bg-white"
              )}
            >
              <div className="py-1">
                <Menu.Item>
                  <Link href="/classes">
                    <a
                      className={classNames(
                        "block px-4 py-2 text-sm font-medium",
                        dark
                          ? "hover:bg-gray-600 text-gray-200"
                          : "hover:bg-gray-100 hover:text-gray-900 text-gray-700"
                      )}
                    >
                      Live Classes
                    </a>
                  </Link>
                </Menu.Item>
                <Menu.Item>
                  <Link href="/video-classes">
                    <a
                      className={classNames(
                        "block px-4 py-2 text-sm font-medium",
                        dark
                          ? "hover:bg-gray-600 text-gray-200"
                          : "hover:bg-gray-100 hover:text-gray-900 text-gray-700"
                      )}
                    >
                      Self-Study Classes
                    </a>
                  </Link>
                </Menu.Item>
              </div>
            </Menu.Items>
          </Transition>
        </div>
      )}
    </Menu>
  )
}
Example #8
Source File: FileMenu.tsx    From ide with Mozilla Public License 2.0 4 votes vote down vote up
FileMenu = (props: FileMenuProps): JSX.Element => {
  const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(
    null
  );
  const [popperElement, setPopperElement] = useState<HTMLElement | null>(null);
  const { styles, attributes } = usePopper(referenceElement, popperElement, {
    placement: 'bottom-start',
  });
  const [permission] = useAtom(actualUserPermissionAtom);
  const canWrite = permission === 'OWNER' || permission === 'READ_WRITE';

  const [mounted, setMounted] = useState(false);
  useEffect(() => {
    setMounted(true);
  }, []);

  return (
    <Menu as="div" className="relative inline-block text-left">
      {({ open }) => (
        <>
          <div>
            <Menu.Button
              className="relative inline-flex items-center px-4 py-2 shadow-sm text-sm font-medium text-gray-200 hover:bg-gray-800 focus:bg-gray-800 focus:outline-none"
              ref={setReferenceElement}
            >
              File
              <ChevronDownIcon
                className="-mr-1 ml-2 h-5 w-5"
                aria-hidden="true"
              />
            </Menu.Button>
          </div>

          <Transition show={open}>
            {mounted
              ? ReactDOM.createPortal(
                  <Menu.Items static as="div">
                    <div
                      ref={setPopperElement}
                      style={styles.popper}
                      {...attributes.popper}
                      className="relative"
                    >
                      <Transition.Child
                        as={Fragment}
                        enter="transition ease-out duration-100"
                        enterFrom="transform opacity-0 scale-95"
                        enterTo="transform opacity-100 scale-100"
                        leave="transition ease-in duration-75"
                        leaveFrom="transform opacity-100 scale-100"
                        leaveTo="transform opacity-0 scale-95"
                      >
                        <div className="origin-top-left absolute z-10 left-0 w-56 shadow-lg bg-gray-800 ring-1 ring-black ring-opacity-5 focus:outline-none">
                          <div className="py-1">
                            <Menu.Item>
                              {({ active }) => (
                                <a
                                  href="/"
                                  target="_blank"
                                  className={classNames(
                                    active
                                      ? 'bg-gray-700 text-gray-100'
                                      : 'text-gray-200',
                                    'group flex items-center px-4 py-2 text-sm'
                                  )}
                                >
                                  <PlusIcon
                                    className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
                                    aria-hidden="true"
                                  />
                                  New File
                                </a>
                              )}
                            </Menu.Item>
                            <Menu.Item>
                              {({ active }) => (
                                <button
                                  type="button"
                                  className={classNames(
                                    active
                                      ? 'bg-gray-700 text-gray-100'
                                      : 'text-gray-200',
                                    'group flex items-center px-4 py-2 text-sm w-full focus:outline-none'
                                  )}
                                  onClick={() => props.onDownloadFile()}
                                >
                                  <DownloadIcon
                                    className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
                                    aria-hidden="true"
                                  />
                                  Download File
                                </button>
                              )}
                            </Menu.Item>
                            <Menu.Item>
                              {({ active }) => (
                                <a
                                  href={props.forkButtonUrl}
                                  target="_blank"
                                  rel="noreferrer"
                                  className={classNames(
                                    active
                                      ? 'bg-gray-700 text-gray-100'
                                      : 'text-gray-200',
                                    'group flex items-center px-4 py-2 text-sm w-full focus:outline-none'
                                  )}
                                >
                                  <DuplicateIcon
                                    className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
                                    aria-hidden="true"
                                  />
                                  Clone File
                                </a>
                              )}
                            </Menu.Item>
                            {canWrite && (
                              <Menu.Item>
                                {({ active }) => (
                                  <button
                                    type="button"
                                    className={classNames(
                                      active
                                        ? 'bg-gray-700 text-gray-100'
                                        : 'text-gray-200',
                                      'group flex items-center px-4 py-2 text-sm w-full focus:outline-none'
                                    )}
                                    onClick={() => props.onInsertFileTemplate()}
                                  >
                                    <TemplateIcon
                                      className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
                                      aria-hidden="true"
                                    />
                                    Reset File to Template
                                  </button>
                                )}
                              </Menu.Item>
                            )}
                            <Menu.Item>
                              {({ active }) => (
                                <button
                                  type="button"
                                  className={classNames(
                                    active
                                      ? 'bg-gray-700 text-gray-100'
                                      : 'text-gray-200',
                                    'group flex items-center px-4 py-2 text-sm w-full focus:outline-none'
                                  )}
                                  onClick={() => props.onOpenSettings()}
                                >
                                  <CogIcon
                                    className="mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-300"
                                    aria-hidden="true"
                                  />
                                  Settings
                                </button>
                              )}
                            </Menu.Item>
                          </div>
                        </div>
                      </Transition.Child>
                    </div>
                  </Menu.Items>,
                  document.body
                )
              : null}
          </Transition>
        </>
      )}
    </Menu>
  );
}
Example #9
Source File: UserListItem.tsx    From ide with Mozilla Public License 2.0 4 votes vote down vote up
UserListItem = ({ user }: { user: User }): JSX.Element | null => {
  const userRef = useAtomValue(authenticatedUserRefAtom);
  const firebaseRef = useAtomValue(authenticatedFirebaseRefAtom);
  const [permission] = useAtom(actualUserPermissionAtom);
  const [defaultPermission] = useAtom(defaultPermissionAtom);

  const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(
    null
  );
  const [popperElement, setPopperElement] = useState<HTMLElement | null>(null);
  const { styles, attributes } = usePopper(referenceElement, popperElement, {
    placement: 'bottom-end',
  });

  if (!permission || !defaultPermission) return null;

  type PermissionUpdate = 'OWNER' | 'READ_WRITE' | 'READ' | 'DEFAULT';
  const handleUpdateUserPermission = (
    user: User,
    permission: PermissionUpdate
  ): void => {
    if (!firebaseRef) {
      alert("Firebase hasn't loaded yet, please wait");
      return;
    }
    if (permission === 'DEFAULT') {
      firebaseRef.child('users').child(user.id).child('permission').remove();
    } else {
      firebaseRef.child('users').child(user.id).update({
        permission,
      });
    }
  };

  return (
    <li key={user.id} className="py-2 flex">
      <span className="relative h-5 w-5">
        <span
          className="inline-block h-5 w-5 rounded"
          style={{ backgroundColor: user.color }}
        />
        <span className="absolute bottom-0 right-0 transform translate-y-1/3 translate-x-1/3 block rounded-full">
          <span
            className={`block h-3 w-3 rounded-full ${
              isUserOnline(user) ? 'bg-green-400' : 'bg-gray-400'
            }`}
          />
        </span>
      </span>
      <div className="ml-3 flex-1">
        <p
          className={`text-sm font-medium ${
            isUserOnline(user) ? 'text-gray-300' : 'text-gray-400'
          }`}
        >
          {user.name}
          {user.id === userRef?.key ? ' (Me)' : ''}
        </p>
        <p
          className={`text-sm ${
            isUserOnline(user) ? 'text-gray-400' : 'text-gray-500'
          }`}
        >
          {user.permission
            ? permissionLabels[user.permission]
            : `Default (${permissionLabels[defaultPermission]})`}
        </p>
      </div>

      {user.id !== userRef?.key && permission === 'OWNER' && (
        <Menu>
          {({ open }) => (
            <>
              <div>
                <Menu.Button
                  className="bg-[#1E1E1E] rounded-full flex items-center text-gray-500 hover:text-gray-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-[#1E1E1E] focus:ring-indigo-500"
                  ref={setReferenceElement}
                >
                  <span className="sr-only">Open options</span>
                  <DotsVerticalIcon className="h-5 w-5" aria-hidden="true" />
                </Menu.Button>
              </div>

              <Transition show={open}>
                {ReactDOM.createPortal(
                  <Menu.Items as="div" static>
                    <div
                      ref={setPopperElement}
                      style={styles.popper}
                      {...attributes.popper}
                      className="relative"
                    >
                      <Transition.Child
                        as={Fragment}
                        enter="transition ease-out duration-100"
                        enterFrom="transform opacity-0 scale-95"
                        enterTo="transform opacity-100 scale-100"
                        leave="transition ease-in duration-75"
                        leaveFrom="transform opacity-100 scale-100"
                        leaveTo="transform opacity-0 scale-95"
                      >
                        <div className="origin-top-right absolute right-0 bg-gray-800 rounded-md mt-2 w-48 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
                          <div className="py-1">
                            {([
                              ['OWNER', 'Owner'],
                              ['READ_WRITE', 'Read & Write'],
                              ['READ', 'View Only'],
                              [
                                'DEFAULT',
                                `Default (${permissionLabels[defaultPermission]})`,
                              ],
                              ['PRIVATE', 'Blocked'],
                            ] as [PermissionUpdate, string][]).map(option => (
                              <Menu.Item key={option[0]}>
                                {({ active }) => (
                                  <button
                                    className={classNames(
                                      active
                                        ? 'bg-gray-700 text-gray-100'
                                        : 'text-gray-200',
                                      'w-full text-left block px-4 py-2 text-sm focus:outline-none'
                                    )}
                                    onClick={() =>
                                      handleUpdateUserPermission(
                                        user,
                                        option[0]
                                      )
                                    }
                                  >
                                    {option[1]}
                                  </button>
                                )}
                              </Menu.Item>
                            ))}
                          </div>
                        </div>
                      </Transition.Child>
                    </div>
                  </Menu.Items>,
                  document.body
                )}
              </Transition>
            </>
          )}
        </Menu>
      )}
    </li>
  );
}
Example #10
Source File: Navbar.tsx    From ultimate-saas-ts with MIT License 4 votes vote down vote up
Component = () => {
  const { data: session, status } = useSession();
  const router = useRouter();

  return (
    <Disclosure as="nav" className="bg-white">
      {({ open }) => (
        <>
          <div className="px-2 mx-auto max-w-7xl sm:px-6 lg:px-8">
            <div className="relative flex justify-between h-16">
              <div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
                <Disclosure.Button className="inline-flex items-center justify-center p-2 text-gray-400 rounded-md hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
                  <span className="sr-only">Open main menu</span>
                  {open ? (
                    <XIcon className="block w-6 h-6" aria-hidden="true" />
                  ) : (
                    <MenuIcon className="block w-6 h-6" aria-hidden="true" />
                  )}
                </Disclosure.Button>
              </div>
              <div className="flex items-center justify-center flex-1 sm:items-stretch sm:justify-start">
                <div className="flex items-center flex-shrink-0">
                  <img
                    className="block w-auto h-8 lg:hidden"
                    src="https://tailwindui.com/img/logos/workflow-mark-indigo-600.svg"
                    alt="Workflow"
                  />
                  <img
                    className="hidden w-auto h-8 lg:block"
                    src="https://tailwindui.com/img/logos/workflow-logo-indigo-600-mark-gray-800-text.svg"
                    alt="Workflow"
                  />
                </div>
                <div className="hidden sm:ml-6 sm:flex sm:space-x-8">
                  <Link href="/">
                    <a
                      className={classNames(
                        'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium',
                        {
                          'border-indigo-500 text-gray-900':
                            router.pathname === '/',
                          '': router.pathname !== '/',
                        }
                      )}
                    >
                      Pricings
                    </a>
                  </Link>

                  <Link href="/account">
                    <a
                      className={classNames(
                        'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium',
                        {
                          'border-indigo-500 text-gray-900':
                            router.pathname === '/account',
                          '': router.pathname !== '/account',
                        }
                      )}
                    >
                      Account
                    </a>
                  </Link>
                </div>
              </div>
              <div className="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
                {/* Profile dropdown */}
                {status === 'authenticated' ? (
                  <Menu as="div" className="relative ml-3">
                    <div>
                      <Menu.Button className="flex text-sm bg-white rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
                        <span className="sr-only">Open user menu</span>
                        <img
                          className="w-8 h-8 rounded-full"
                          src={
                            session?.user?.image ||
                            'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80'
                          }
                          alt=""
                        />
                      </Menu.Button>
                    </div>
                    <Transition
                      as={Fragment}
                      enter="transition ease-out duration-200"
                      enterFrom="transform opacity-0 scale-95"
                      enterTo="transform opacity-100 scale-100"
                      leave="transition ease-in duration-75"
                      leaveFrom="transform opacity-100 scale-100"
                      leaveTo="transform opacity-0 scale-95"
                    >
                      <Menu.Items className="absolute right-0 w-48 py-1 mt-2 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
                        <Menu.Item>
                          {({ active }) => (
                            <Link href="/account">
                              <a
                                className={classNames(
                                  active ? 'bg-gray-100' : '',
                                  'block px-4 py-2 text-sm text-gray-700'
                                )}
                              >
                                Account
                              </a>
                            </Link>
                          )}
                        </Menu.Item>
                        <Menu.Item>
                          {({ active }) => (
                            <a
                              onClick={() => signOut()}
                              className={classNames(
                                active ? 'bg-gray-100' : '',
                                'block px-4 py-2 text-sm text-gray-700'
                              )}
                            >
                              Sign out
                            </a>
                          )}
                        </Menu.Item>
                      </Menu.Items>
                    </Transition>
                  </Menu>
                ) : (
                  <Link href="/api/auth/signin">
                    <a>Sign in</a>
                  </Link>
                )}
              </div>
            </div>
          </div>

          <Disclosure.Panel className="sm:hidden">
            <div className="pt-2 pb-4 space-y-1">
              {/* Current: "bg-indigo-50 border-indigo-500 text-indigo-700", Default: "border-transparent text-gray-500 hover:bg-gray-50 hover:border-gray-300 hover:text-gray-700" */}

              <Link href="/">
                <a className="block py-2 pl-3 pr-4 text-base font-medium text-indigo-700 border-l-4 border-indigo-500 bg-indigo-50">
                  Pricings
                </a>
              </Link>
              <Link href="/account">
                <a className="block py-2 pl-3 pr-4 text-base font-medium text-gray-500 border-l-4 border-transparent hover:bg-gray-50 hover:border-gray-300 hover:text-gray-700">
                  Account
                </a>
              </Link>
            </div>
          </Disclosure.Panel>
        </>
      )}
    </Disclosure>
  );
}
Example #11
Source File: AccountHeader.tsx    From pali-wallet with MIT License 4 votes vote down vote up
AccountMenu: React.FC = () => {
  const { navigate } = useUtils();
  const { wallet } = getController();
  const { encryptedMnemonic, accounts, activeAccount } = useStore();

  const verifyAccounts = Object.keys(accounts);

  const setActiveAccount = async (id: number) => {
    await wallet.setAccount(Number(id));
    wallet.account.sys.watchMemPool(accounts[Number(id)]);
  };

  const handleLogout = () => {
    wallet.lock();

    navigate('/');
  };

  return (
    <Menu
      id="account-settings-btn"
      as="div"
      className="absolute right-3 inline-block text-right md:max-w-2xl"
    >
      <Menu.Button className="inline-flex justify-center w-full hover:text-button-primaryhover text-white text-sm font-medium hover:bg-opacity-30 rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
        {encryptedMnemonic && <Icon name="dots" className="z-0" />}
      </Menu.Button>

      <Transition
        as="div"
        enter="transition ease-out duration-100"
        enterFrom="transform opacity-0 scale-95"
        enterTo="opacity-100 scale-100"
        leave="transition ease-in duration-75"
        leaveFrom="opacity-100 scale-100"
        leaveTo="transform opacity-0 scale-95"
      >
        <div className="fixed z-0 -inset-0 w-full bg-brand-black bg-opacity-50 transition-all duration-300 ease-in-out" />

        <Menu.Items
          as="div"
          className="scrollbar-styled absolute z-10 right-0 pb-6 w-72 text-center text-brand-white font-poppins bg-menu-primary rounded-2xl focus:outline-none shadow-2xl overflow-auto origin-top-right ring-1 ring-black ring-opacity-5"
        >
          <h2
            className="mb-3 pb-6 pt-8 w-full text-center text-brand-white bg-menu-primary border-b border-dashed border-dashed-light"
            id="account-settings-title"
          >
            ACCOUNT SETTINGS
          </h2>

          <Menu.Item>
            <li
              onClick={() => navigate('/settings/account/private-key')}
              className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
            >
              <Icon name="key" className="mb-2 ml-1 mr-2 text-brand-white" />

              <span className="px-3">Your keys</span>
            </li>
          </Menu.Item>

          <Menu.Item>
            <Disclosure>
              {({ open }) => (
                <>
                  <Disclosure.Button className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200">
                    <Icon
                      name="user"
                      className="mb-2 ml-1 mr-2 text-brand-white"
                      id="accounts-btn"
                    />

                    <span className="px-3 text-base">Accounts</span>

                    <Icon
                      name="select-down"
                      className={`${
                        open ? 'transform rotate-180' : ''
                      } mb-1 text-brand-white`}
                    />
                  </Disclosure.Button>

                  <div
                    className="relative"
                    style={{
                      paddingTop: `${open ? '45px' : '0px'}`,
                    }}
                  >
                    <Disclosure.Panel
                      className={`static overflow-y-scroll scrollbar-styled pb-2 
                    ${
                      verifyAccounts?.length === 1
                        ? 'h-16'
                        : verifyAccounts?.length === 2
                        ? 'h-28'
                        : verifyAccounts?.length >= 3
                        ? 'h-40'
                        : ''
                    }
                    text-sm bg-menu-secondary`}
                    >
                      <li
                        onClick={() => navigate('/settings/account/new')}
                        className="backface-visibility-hidden absolute top-0 flex items-center justify-center mb-4 mx-auto p-2.5 w-full text-brand-white text-sm font-medium hover:bg-bkg-2 bg-menu-secondary active:bg-opacity-40 border-b border-dashed border-gray-500 focus:outline-none cursor-pointer transform transition duration-300"
                        id="create-new-account-btn"
                      >
                        <Icon
                          name="appstoreadd"
                          className="mb-1 mr-3 text-brand-white"
                        />

                        <span>Create new account</span>
                      </li>

                      {Object.values(accounts).map((account, index) => (
                        <li
                          key={account.id}
                          className="backface-visibility-hidden flex flex-col items-center justify-around mt-2 mx-auto p-2.5 max-w-95 text-white text-sm font-medium bg-menu-secondary active:bg-opacity-40 focus:outline-none cursor-pointer transform hover:scale-105 transition duration-300"
                          onClick={() => setActiveAccount(account.id)}
                          id={`account-${index}`}
                        >
                          <span>
                            {account.label} ({ellipsis(account.address, 4, 8)})
                          </span>

                          {activeAccount.id === account.id && (
                            <Icon
                              name="check"
                              className="mb-1 w-4"
                              wrapperClassname="w-6 absolute right-1"
                            />
                          )}
                        </li>
                      ))}
                    </Disclosure.Panel>
                  </div>
                </>
              )}
            </Disclosure>
          </Menu.Item>

          <Menu.Item>
            <li
              onClick={() => navigate('/settings/account/hardware')}
              className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
            >
              <Icon
                name="partition"
                className="mb-2 ml-1 mr-2 text-brand-white"
                id="hardware-wallet-btn"
              />

              <span className="px-3">Hardware wallet</span>
            </li>
          </Menu.Item>

          <Menu.Item>
            <li
              onClick={handleLogout}
              className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
            >
              <Icon name="lock" className="mb-2 ml-1 mr-2 text-brand-white" />

              <span className="px-3">Lock</span>
            </li>
          </Menu.Item>
        </Menu.Items>
      </Transition>
    </Menu>
  );
}
Example #12
Source File: NormalHeader.tsx    From pali-wallet with MIT License 4 votes vote down vote up
NormalHeader: React.FC = () => {
  const { wallet } = getController();

  const { activeNetwork, encryptedMnemonic, networks } = useStore();
  const { handleRefresh, navigate } = useUtils();

  const [currentTabURL, setCurrentTabURL] = useState<string>('');

  const handleChangeNetwork = (chain: string, chainId: number) => {
    wallet.setActiveNetwork(chain, chainId);

    if (chain === 'syscoin') wallet.account.sys.setAddress();
  };

  const updateCurrentTabUrl = async () => {
    const windows = await browser.windows.getAll({ populate: true });

    for (const window of windows) {
      const views = browser.extension.getViews({ windowId: window.id });

      if (views) {
        const tabs = await browser.tabs.query({
          active: true,
          currentWindow: true,
        });
        return String(tabs[0].url);
      }
    }
  };

  useEffect(() => {
    let isMounted = true;

    updateCurrentTabUrl().then((response: any) => {
      if (isMounted) {
        setCurrentTabURL(response);
      }
    });

    return () => {
      isMounted = false;
    };
  }, [wallet.isUnlocked()]);

  const NetworkMenu = () => (
    <Menu as="div" className="absolute left-2 inline-block mr-8 text-left">
      {(menuprops) => (
        <>
          <Menu.Button className="inline-flex gap-x-2 items-center justify-start ml-2 w-full text-white text-sm font-medium hover:bg-opacity-30 rounded-full focus:outline-none cursor-pointer">
            <span>{activeNetwork.label}</span>

            <Icon
              name="select-down"
              className={`${
                menuprops.open ? 'transform rotate-180' : ''
              } text-brand-white`}
              id="network-settings-btn"
            />
          </Menu.Button>

          <Transition
            as="div"
            enter="transition ease-out duration-100"
            enterFrom="transform opacity-0 scale-95"
            enterTo="opacity-100 scale-100"
            leave="transition ease-in duration-75"
            leaveFrom="opacity-100 scale-100"
            leaveTo="transform opacity-0 scale-95"
          >
            <div className="fixed z-50 -inset-0 w-full bg-brand-black bg-opacity-50 transition-all duration-300 ease-in-out" />

            <Menu.Items
              as="div"
              className="absolute z-50 left-0 pb-6 w-72 h-menu text-center text-brand-white font-poppins bg-menu-primary rounded-2xl focus:outline-none shadow-2xl overflow-hidden origin-top-right ring-1 ring-black ring-opacity-5"
            >
              <h2
                className="mb-6 pb-6 pt-8 w-full text-center text-brand-white bg-menu-primary border-b border-dashed border-dashed-light"
                id="network-settings-title"
              >
                NETWORK SETTINGS
              </h2>
              <div className="scrollbar-styled h-80 overflow-auto">
                <Menu.Item>
                  <li
                    onClick={() =>
                      navigate('/settings/networks/connected-sites')
                    }
                    className="flex items-center justify-start mb-2 mx-3 px-2 py-1 text-base bg-warning-success hover:bg-opacity-70 border border-solid border-transparent hover:border-warning-success rounded-full cursor-pointer transition-all duration-200"
                  >
                    <Icon
                      name="globe"
                      className="mb-1 ml-1 mr-4 text-brand-white"
                    />

                    <span className="px-3">Connected sites</span>
                  </li>
                </Menu.Item>

                <Menu.Item>
                  <li
                    onClick={() => navigate('/settings/networks/trusted-sites')}
                    className="flex items-center justify-start mb-4 mx-3 px-2 py-1 text-base bg-brand-royalblue hover:bg-opacity-70 border border-solid border-brand-royalblue rounded-full cursor-pointer transition-all duration-200"
                  >
                    <Icon
                      name="warning"
                      className="mb-1 ml-1 mr-4 text-brand-white"
                    />

                    <span className="px-3">Trusted sites</span>
                  </li>
                </Menu.Item>

                <Menu.Item>
                  <Disclosure>
                    {({ open }) => (
                      <>
                        <Disclosure.Button className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200">
                          <Icon
                            name="dolar"
                            className="ml-1 mr-4 text-brand-white"
                          />

                          <span className="px-3 text-base">Syscoin core</span>

                          <Icon
                            name="select-down"
                            className={`${
                              open ? 'transform rotate-180' : ''
                            } text-brand-white mb-1`}
                          />
                        </Disclosure.Button>

                        <Disclosure.Panel className="scrollbar-styled pb-2 pt-0.5 h-28 text-sm bg-menu-secondary overflow-auto">
                          {Object.values(networks.syscoin).map(
                            (currentNetwork: any) => (
                              <li
                                key={currentNetwork.chainId}
                                className="backface-visibility-hidden flex flex-col justify-around mt-2 mx-auto p-2.5 max-w-95 text-white text-sm font-medium bg-menu-secondary active:bg-opacity-40 focus:outline-none cursor-pointer transform hover:scale-105 transition duration-300"
                                onClick={() =>
                                  handleChangeNetwork(
                                    'syscoin',
                                    currentNetwork.chainId
                                  )
                                }
                              >
                                <span className="ml-8 text-left">
                                  {currentNetwork.label}
                                </span>

                                {activeNetwork.chainId ===
                                  currentNetwork.chainId && (
                                  <Icon
                                    name="check"
                                    className="mb-1 w-4"
                                    wrapperClassname="w-6 absolute right-20"
                                  />
                                )}
                              </li>
                            )
                          )}
                        </Disclosure.Panel>
                      </>
                    )}
                  </Disclosure>
                </Menu.Item>

                <Menu.Item>
                  <Disclosure>
                    {({ open }) => (
                      <>
                        <Disclosure.Button className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200">
                          <Icon
                            name="dolar"
                            className="ml-1 mr-4 text-brand-white"
                          />

                          <span className="px-3 text-base">Web3 networks</span>

                          <Icon
                            name="select-down"
                            className={`${
                              open ? 'transform rotate-180' : ''
                            } mb-1 text-brand-white`}
                          />
                        </Disclosure.Button>

                        <Disclosure.Panel className="scrollbar-styled pb-2 pt-0.5 h-28 text-sm bg-menu-secondary overflow-auto">
                          {Object.values(networks.ethereum).map(
                            (currentNetwork: any) => (
                              <li
                                key={currentNetwork.id}
                                className="backface-visibility-hidden flex flex-col justify-around mt-2 mx-auto p-2.5 max-w-95 text-white text-sm font-medium bg-menu-secondary active:bg-opacity-40 focus:outline-none cursor-pointer transform hover:scale-105 transition duration-300"
                                onClick={() =>
                                  handleChangeNetwork(
                                    'ethereum',
                                    currentNetwork.chainId
                                  )
                                }
                              >
                                <span className="ml-8 text-left">
                                  {currentNetwork.label}
                                </span>

                                {activeNetwork.chainId ===
                                  currentNetwork.chainId && (
                                  <Icon
                                    name="check"
                                    className="mb-1 w-4"
                                    wrapperClassname="w-6 absolute right-16"
                                  />
                                )}
                              </li>
                            )
                          )}
                        </Disclosure.Panel>
                      </>
                    )}
                  </Disclosure>
                </Menu.Item>

                <Menu.Item>
                  <li
                    onClick={() => navigate('/settings/networks/custom-rpc')}
                    className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
                  >
                    <Icon
                      name="appstoreadd"
                      className="ml-1 mr-4 text-brand-white"
                    />

                    <span className="px-3">Custom RPC</span>
                  </li>
                </Menu.Item>

                <Menu.Item>
                  <li
                    onClick={() => navigate('/settings/networks/edit')}
                    className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
                  >
                    <Icon name="edit" className="ml-1 mr-4 text-brand-white" />

                    <span className="px-3">Manage networks</span>
                  </li>
                </Menu.Item>
              </div>
            </Menu.Items>
          </Transition>
        </>
      )}
    </Menu>
  );

  const GeneralMenu = () => (
    <Menu
      as="div"
      className="absolute right-2 top-2 flex items-center justify-evenly"
    >
      {() => (
        <>
          <Tooltip content={ellipsis(currentTabURL, 25, 0)}>
            <div
              onClick={() => navigate('/settings/networks/connected-sites')}
              className="relative mx-1.5 text-brand-white cursor-pointer"
            >
              <Icon
                name="globe"
                className="hover:text-brand-royalblue text-white"
              />

              <Badge className="absolute -right-1 top-1 w-3 h-3 text-warning-error bg-warning-error rounded-full" />
            </div>
          </Tooltip>

          <div
            onClick={() => handleRefresh(false)}
            className="mx-1.5 hover:text-brand-royalblue text-brand-white cursor-pointer"
          >
            <Icon name="reload" />
          </div>

          <Menu.Button as="button" className="mx-1.5">
            {Boolean(encryptedMnemonic) && (
              <div id="general-settings-button">
                <Icon
                  name="settings"
                  className="hover:text-brand-royalblue text-brand-white"
                />
              </div>
            )}
          </Menu.Button>

          <Transition
            as="div"
            enter="transition ease-out duration-100"
            enterFrom="transform opacity-0 scale-95"
            enterTo="opacity-100 scale-100"
            leave="transition ease-in duration-75"
            leaveFrom="opacity-100 scale-100"
            leaveTo="transform opacity-0 scale-95"
          >
            <div className="fixed z-50 -inset-0 w-full bg-brand-black bg-opacity-50 transition-all duration-300 ease-in-out" />

            <Menu.Items
              as="div"
              className="scrollbar-styled absolute z-50 right-0 pb-6 w-72 h-96 text-center text-brand-white font-poppins bg-menu-primary rounded-2xl focus:outline-none shadow-2xl overflow-auto origin-top-right ring-1 ring-black ring-opacity-5"
            >
              <h2
                className="mb-6 pb-6 pt-8 w-full text-center text-brand-white bg-menu-primary border-b border-dashed border-dashed-light"
                id="general-settings-title"
              >
                GENERAL SETTINGS
              </h2>

              <Menu.Item>
                <li
                  onClick={() => navigate('/settings/autolock')}
                  className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
                >
                  <Icon name="clock" className="ml-1 mr-4 text-brand-white" />

                  <span className="px-3">Auto lock timer</span>
                </li>
              </Menu.Item>

              <Menu.Item>
                <li
                  onClick={() => navigate('/settings/currency')}
                  className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
                >
                  <Icon name="dolar" className="ml-1 mr-4 text-brand-white" />

                  <span className="px-3">Currency</span>
                </li>
              </Menu.Item>

              <Menu.Item>
                <li
                  onClick={() => navigate('/settings/phrase')}
                  className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
                >
                  <Icon name="wallet" className="ml-1 mr-4 text-brand-white" />

                  <span id="wallet-seed-phrase-btn" className="px-3">
                    Wallet Seed Phrase
                  </span>
                </li>
              </Menu.Item>

              <Menu.Item>
                <li
                  onClick={() => navigate('/settings/about')}
                  className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
                >
                  <Icon
                    name="warning"
                    className="ml-1 mr-4 text-brand-white"
                    id="info-help-btn"
                  />

                  <span className="px-3">Info/Help</span>
                </li>
              </Menu.Item>

              <Menu.Item>
                <li
                  onClick={() => navigate('/settings/forget-wallet')}
                  className="flex items-center justify-start px-5 py-3 w-full text-base hover:bg-bkg-3 cursor-pointer transition-all duration-200"
                >
                  <Icon
                    name="forget"
                    className="ml-1 mr-4 w-5 h-5 text-brand-white"
                    id="forget-wallet-btn"
                  />

                  <span className="px-3">Forget wallet</span>
                </li>
              </Menu.Item>
            </Menu.Items>
          </Transition>
        </>
      )}
    </Menu>
  );

  return (
    <div className="relative flex items-center justify-between p-2 py-6 w-full text-gray-300 bg-bkg-1">
      <NetworkMenu />

      <GeneralMenu />
    </div>
  );
}
Example #13
Source File: SendEth.tsx    From pali-wallet with MIT License 4 votes vote down vote up
SendEth = () => {
  const controller = getController();

  const { alert, navigate } = useUtils();
  const { activeAccount } = useStore();
  const [selectedAsset, setSelectedAsset] = useState<any | null>(null);
  const [recommendedGasPrice, setRecommendedGasPrice] = useState(0);
  const [recommendedGasLimit, setRecommendedGasLimit] = useState(0);
  const [feeValue, setFeeValue] = useState(0);
  const [editGas, setEditGas] = useState(false);
  const [form] = Form.useForm();

  const { convertGasFee } = feeUtils();

  const getRecomendedFees = useCallback(async () => {
    const gasPrice =
      await controller.wallet.account.eth.tx.getRecommendedGasPrice(false);
    const gasLimit = await controller.wallet.account.eth.tx.getGasLimit();

    setRecommendedGasPrice(gasPrice);
    setRecommendedGasLimit(gasLimit);
    setFeeValue(gasPrice);

    form.setFieldsValue({ baseFee: recommendedGasPrice, gasLimit, gasPrice });
  }, [controller.wallet.account]);

  useEffect(() => {
    getRecomendedFees();
  }, [getRecomendedFees]);

  const hasAccountAssets = activeAccount && activeAccount.assets.length > 0;

  const handleSelectedAsset = (item: string) => {
    if (activeAccount?.assets) {
      const getAsset = activeAccount?.assets.find(
        (asset: any) => asset.contract_address === item
      );

      if (getAsset) {
        setSelectedAsset(getAsset);

        return;
      }

      setSelectedAsset(null);
    }
  };

  const nextStep = ({ receiver, amount, gasPrice, gasLimit }: any) => {
    try {
      navigate('/send/confirm', {
        state: {
          tx: {
            sender: activeAccount.address,
            senderXprv: activeAccount.xprv,
            receivingAddress: receiver,
            amount,
            gasPrice,
            gasLimit,
            fee: Number(convertGasFee(String(feeValue))),
            token: null,
            // token: {
            //   decimals: 18,
            //   contractAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
            // },
          },
        },
      });
    } catch (error) {
      alert.removeAll();
      alert.error('An internal error has occurred.');
    }
  };

  return (
    <>
      {editGas ? (
        <EditGasFee
          setGasFee={setRecommendedGasPrice}
          setEdit={setEditGas}
          form={form}
          setFee={setFeeValue}
        />
      ) : (
        <div className="mt-4">
          <p className="flex flex-col items-center justify-center text-center font-rubik">
            <span className="text-brand-royalblue font-poppins font-thin">
              Balance
            </span>

            {selectedAsset
              ? getAssetBalance(selectedAsset, activeAccount)
              : activeAccount.balances.ethereum}
          </p>

          <Form
            form={form}
            id="send-form"
            labelCol={{ span: 8 }}
            wrapperCol={{ span: 8 }}
            initialValues={{
              baseFee: recommendedGasPrice,
              gasLimit: recommendedGasLimit,
              gasPrice: recommendedGasPrice,
            }}
            onFinish={nextStep}
            autoComplete="off"
            className="standard flex flex-col gap-3 items-center justify-center mt-4 text-center md:w-full"
          >
            <Form.Item
              name="receiver"
              className="md:w-full md:max-w-md"
              hasFeedback
              rules={[
                {
                  required: true,
                  message: '',
                },
                () => ({
                  validator(_, value) {
                    if (!value || isValidEthereumAddress(value)) {
                      return Promise.resolve();
                    }

                    return Promise.reject();
                  },
                }),
              ]}
            >
              <Input type="text" placeholder="Receiver" className="large" />
            </Form.Item>

            <div className="flex items-center justify-center md:w-full md:max-w-md">
              {hasAccountAssets && (
                <Form.Item
                  name="asset"
                  className=""
                  rules={[
                    {
                      required: false,
                      message: '',
                    },
                  ]}
                >
                  <Menu>
                    <div className="relative inline-block text-left">
                      <Menu.Button
                        disabled={!hasAccountAssets}
                        className="inline-flex justify-center mt-3 py-3 w-20 text-white text-sm font-medium bg-fields-input-primary hover:bg-opacity-30 border border-fields-input-border focus:border-fields-input-borderfocus rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
                      >
                        {selectedAsset?.symbol
                          ? formatUrl(String(selectedAsset?.symbol), 2)
                          : 'ETH'}
                        <ChevronDoubleDownIcon
                          className="text-violet-200 hover:text-violet-100 -mr-1 ml-2 w-5 h-5"
                          aria-hidden="true"
                        />
                      </Menu.Button>

                      <Transition
                        as={Fragment}
                        enter="transition ease-out duration-100"
                        enterFrom="transform opacity-0 scale-95"
                        enterTo="transform opacity-100 scale-100"
                        leave="transition ease-in duration-75"
                        leaveFrom="transform opacity-100 scale-100"
                        leaveTo="transform opacity-0 scale-95"
                      >
                        {hasAccountAssets && (
                          <Menu.Items className="scrollbar-styled absolute z-10 left-0 mt-2 py-3 w-44 h-56 text-brand-white font-poppins bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-lg shadow-2xl overflow-auto origin-top-right">
                            {activeAccount &&
                              Object.values(activeAccount.assets).map(
                                (item: any) => (
                                  <Menu.Item>
                                    <button
                                      onClick={() =>
                                        handleSelectedAsset(
                                          item.contract_address
                                        )
                                      }
                                      className="group flex items-center justify-between px-2 py-2 w-full hover:text-brand-royalblue text-brand-white font-poppins text-sm border-0 border-transparent transition-all duration-300"
                                    >
                                      <p>{item.symbol}</p>
                                    </button>
                                  </Menu.Item>
                                )
                              )}
                          </Menu.Items>
                        )}
                      </Transition>
                    </div>
                  </Menu>
                </Form.Item>
              )}

              <div className="flex flex-col">
                <div className="flex w-full">
                  <label className="flex-1 mr-4 text-xs" htmlFor="gasPrice">
                    Gas Price
                  </label>
                  <label className="flex-1 mr-6 text-xs" htmlFor="gasLimit">
                    Gas Limit
                  </label>
                </div>

                <div
                  className={`${
                    hasAccountAssets ? 'w-48 ml-4' : 'w-72'
                  } flex gap-x-0.5 items-center justify-center md:w-full`}
                >
                  <Form.Item
                    name="gasPrice"
                    className="flex-1 w-32 text-center bg-fields-input-primary rounded-l-full md:w-full"
                    rules={[
                      {
                        required: false,
                        message: '',
                      },
                    ]}
                  >
                    <Input
                      type="text"
                      placeholder="Gas Price (GWEI)"
                      className="p-3 w-full text-sm bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-l-full outline-none md:w-full"
                    />
                  </Form.Item>

                  <Form.Item
                    name="gasLimit"
                    className="flex-1 w-32 text-center bg-fields-input-primary rounded-r-full"
                    rules={[
                      {
                        required: false,
                        message: '',
                      },
                    ]}
                  >
                    <Input
                      type="text"
                      placeholder="Gas Limit"
                      className="p-3 w-full text-sm bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-r-full outline-none md:w-full"
                    />
                  </Form.Item>
                </div>
              </div>
            </div>

            <Form.Item
              name="amount"
              className="md:w-full md:max-w-md"
              hasFeedback
              rules={[
                {
                  required: true,
                  message: '',
                },
                () => ({
                  validator(_, value) {
                    const balance = selectedAsset
                      ? selectedAsset.balance / 10 ** selectedAsset.decimals
                      : Number(activeAccount?.balances.ethereum);

                    if (value > balance) {
                      return Promise.reject();
                    }

                    return Promise.resolve();
                  },
                }),
              ]}
            >
              <Input className="large" type="number" placeholder="Amount" />
            </Form.Item>

            <div className="flex gap-x-0.5 items-center justify-center mx-2 md:w-full md:max-w-md">
              <Form.Item
                name="edit"
                className="w-12 text-center bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-l-full opacity-70 cursor-pointer"
                rules={[
                  {
                    required: false,
                    message: '',
                  },
                ]}
              >
                <Tooltip content="Click to edit fee">
                  <div onClick={() => setEditGas(true)}>
                    <Icon
                      wrapperClassname="w-6 ml-3 mt-1 h-10"
                      name="edit"
                      className="text-brand-royalbluemedium cursor-pointer"
                    />
                  </div>
                </Tooltip>
              </Form.Item>

              <Form.Item
                name="baseFee"
                className="md:w-full"
                hasFeedback
                rules={[
                  {
                    required: true,
                    message: '',
                  },
                ]}
              >
                <Tooltip content="Recommended network base fee">
                  <Input
                    disabled
                    className="block pl-4 pr-8 py-3 w-60 text-brand-white text-sm bg-fields-input-primary border border-fields-input-border rounded-r-full outline-none opacity-50 cursor-not-allowed md:w-full"
                    id="baseFee-input"
                    type="number"
                    placeholder="Base fee"
                    value={recommendedGasPrice}
                  />
                </Tooltip>
              </Form.Item>
            </div>

            <p className="flex flex-col items-center justify-center p-0 max-w-xs text-center text-brand-royalblue sm:w-full md:my-4">
              <span className="text-xs">Amount + fee</span>

              <span className="mt-0.5 text-brand-white font-rubik text-xs">
                {'≈ '}
              </span>
            </p>

            <SecondaryButton type="submit" id="next-btn">
              Next
            </SecondaryButton>
          </Form>
        </div>
      )}
    </>
  );
}
Example #14
Source File: SendSys.tsx    From pali-wallet with MIT License 4 votes vote down vote up
SendSys = () => {
  const { getFiatAmount } = usePrice();
  const controller = getController();

  const { alert, navigate } = useUtils();
  const { activeNetwork, fiat, activeAccount } = useStore();
  const [verifyAddress, setVerifyAddress] = useState<boolean>(true);
  const [ZDAG, setZDAG] = useState<boolean>(false);
  const [selectedAsset, setSelectedAsset] = useState<any | null>(null);
  const [recommend, setRecommend] = useState(0.00001);
  const [fiatValueToShow, setFiatValueToShow] = useState('');
  const [form] = Form.useForm();

  const handleGetFee = useCallback(async () => {
    const recommendFee =
      await controller.wallet.account.sys.tx.getRecommendedFee(
        activeNetwork.url
      );

    setRecommend(recommendFee);

    form.setFieldsValue({ fee: recommendFee });
  }, [controller.wallet.account, form]);

  useEffect(() => {
    handleGetFee();

    form.setFieldsValue({
      verify: true,
      ZDAG: false,
      fee: recommend,
    });
  }, [form, handleGetFee]);

  const assets = activeAccount.assets
    ? Object.values(activeAccount.assets)
    : [];

  const hasAccountAssets = assets && assets.length > 0;

  const handleSelectedAsset = (item: number) => {
    console.log('selected item', item);
    if (assets) {
      const getAsset = assets.find((asset: any) => asset.assetGuid === item);

      if (getAsset) {
        setSelectedAsset(getAsset);

        return;
      }

      setSelectedAsset(null);
    }
  };

  const verifyOnChange = (value: any) => {
    setVerifyAddress(value);

    form.setFieldsValue({ verify: value });
  };

  const ZDAGOnChange = (value: any) => {
    setZDAG(value);

    form.setFieldsValue({ ZDAG: value });
  };

  const nextStep = ({ receiver, amount, fee }: any) => {
    try {
      navigate('/send/confirm', {
        state: {
          tx: {
            sender: activeAccount.address,
            receivingAddress: receiver,
            amount: Number(amount),
            fee,
            token: selectedAsset ? selectedAsset.assetGuid : null,
            isToken: !!selectedAsset,
            rbf: !ZDAG,
          },
        },
      });
    } catch (error) {
      alert.removeAll();
      alert.error('An internal error has occurred.');
    }
  };

  const returnFiatAmount = async () => {
    if (!selectedAsset) {
      const value = await getFiatAmount(
        Number(recommend),
        6,
        String(fiat.asset)
      );

      setFiatValueToShow(value);
    }
    const value = await getFiatAmount(
      Number(recommend) + Number(recommend),
      6,
      String(fiat.asset)
    );
    setFiatValueToShow(value);
  };

  useEffect(() => {
    returnFiatAmount();
  }, [selectedAsset]);

  return (
    <div className="mt-4">
      <p className="flex flex-col items-center justify-center text-center font-rubik">
        <span className="text-brand-royalblue font-poppins font-thin">
          Balance
        </span>

        {selectedAsset
          ? getAssetBalance(selectedAsset, activeAccount)
          : activeAccount.balances.syscoin}
      </p>

      <Form
        form={form}
        id="send-form"
        labelCol={{ span: 8 }}
        wrapperCol={{ span: 8 }}
        initialValues={{
          verify: true,
          ZDAG: false,
          fee: recommend,
        }}
        onFinish={nextStep}
        autoComplete="off"
        className="standard flex flex-col gap-3 items-center justify-center mt-4 text-center md:w-full"
      >
        <Form.Item
          name="receiver"
          className="md:w-full md:max-w-md"
          hasFeedback
          rules={[
            {
              required: true,
              message: '',
            },
            () => ({
              validator(_, value) {
                if (
                  !value ||
                  isValidSYSAddress(value, activeNetwork, verifyAddress)
                ) {
                  return Promise.resolve();
                }

                return Promise.reject();
              },
            }),
          ]}
        >
          <Input type="text" placeholder="Receiver" className="large" />
        </Form.Item>

        <div className="flex items-center justify-center md:w-full md:max-w-md">
          {hasAccountAssets && (
            <Form.Item
              name="asset"
              className=""
              rules={[
                {
                  required: false,
                  message: '',
                },
              ]}
            >
              <Menu>
                <div className="relative inline-block text-left">
                  <Menu.Button
                    disabled={!hasAccountAssets}
                    className="inline-flex justify-center py-3 w-20 text-white text-sm font-medium bg-fields-input-primary hover:bg-opacity-30 border border-fields-input-border focus:border-fields-input-borderfocus rounded-full focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
                  >
                    {selectedAsset?.symbol
                      ? formatUrl(String(selectedAsset?.symbol), 2)
                      : 'SYS'}
                    <ChevronDoubleDownIcon
                      className="text-violet-200 hover:text-violet-100 -mr-1 ml-2 w-5 h-5"
                      aria-hidden="true"
                    />
                  </Menu.Button>

                  <Transition
                    as={Fragment}
                    enter="transition ease-out duration-100"
                    enterFrom="transform opacity-0 scale-95"
                    enterTo="transform opacity-100 scale-100"
                    leave="transition ease-in duration-75"
                    leaveFrom="transform opacity-100 scale-100"
                    leaveTo="transform opacity-0 scale-95"
                  >
                    {hasAccountAssets && (
                      <Menu.Items className="scrollbar-styled absolute z-10 left-0 mt-2 py-3 w-44 h-56 text-brand-white font-poppins bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-lg shadow-2xl overflow-auto origin-top-right">
                        {activeAccount && (
                          <>
                            {hasAccountAssets &&
                              Object.values(activeAccount.assets).map(
                                (item: any) => (
                                  <>
                                    <Menu.Item>
                                      <button
                                        onClick={() => handleSelectedAsset(-1)}
                                        className="group flex items-center justify-between px-2 py-2 w-full hover:text-brand-royalblue text-brand-white font-poppins text-sm border-0 border-transparent transition-all duration-300"
                                      >
                                        <p>SYS</p>
                                        <small>Native</small>
                                      </button>
                                    </Menu.Item>

                                    <Menu.Item>
                                      <button
                                        onClick={() =>
                                          handleSelectedAsset(item.assetGuid)
                                        }
                                        className="group flex items-center justify-between px-2 py-2 w-full hover:text-brand-royalblue text-brand-white font-poppins text-sm border-0 border-transparent transition-all duration-300"
                                      >
                                        <p>{item.symbol}</p>
                                        <small>
                                          {isNFT(item.assetGuid)
                                            ? 'NFT'
                                            : 'SPT'}
                                        </small>
                                      </button>
                                    </Menu.Item>
                                  </>
                                )
                              )}
                          </>
                        )}
                      </Menu.Items>
                    )}
                  </Transition>
                </div>
              </Menu>
            </Form.Item>
          )}

          <div
            className={`${
              hasAccountAssets ? 'w-48 ml-4' : 'w-72'
            } flex gap-x-0.5 items-center justify-center md:w-full`}
          >
            <Form.Item
              id="verify-address-switch"
              name="verify"
              className="flex-1 w-32 text-center bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-l-full md:w-full"
              rules={[
                {
                  required: false,
                  message: '',
                },
              ]}
            >
              <Tooltip
                childrenClassName="text-brand-white h-4"
                content="Pali verifies your address to check if it is a valid SYS address. It's useful disable this verification if you want to send to specific type of addresses, like legacy. Only disable this verification if you are fully aware of what you are doing."
              >
                <p
                  className={`${
                    !hasAccountAssets && ' absolute top-0 left-8'
                  } text-10px cursor-default`}
                >
                  Verify address
                </p>
              </Tooltip>

              <Switch
                checked={verifyAddress}
                onChange={verifyOnChange}
                className="relative inline-flex items-center w-9 h-4 border border-brand-royalblue rounded-full"
              >
                <span className="sr-only">Verify address</span>
                <span
                  className={`${
                    verifyAddress
                      ? 'translate-x-6 bg-warning-success'
                      : 'translate-x-1'
                  } inline-block w-2 h-2 transform bg-warning-error rounded-full`}
                />
              </Switch>
            </Form.Item>

            <Form.Item
              name="ZDAG"
              className="flex-1 w-32 text-center bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-r-full"
              rules={[
                {
                  required: false,
                  message: '',
                },
              ]}
            >
              <Tooltip
                childrenClassName="text-brand-white h-4"
                content="Disable this option for Replace-by-fee (RBF) and enable for Z-DAG, a exclusive Syscoin feature. Z-DAG enables faster transactions but should not be used for high amounts."
              >
                <p
                  className={`${
                    !hasAccountAssets && 'absolute top-0 right-14'
                  } text-10px cursor-default`}
                >
                  Z-DAG
                </p>
              </Tooltip>
              <Switch
                checked={ZDAG}
                onChange={ZDAGOnChange}
                className="relative inline-flex items-center w-9 h-4 bg-transparent border border-brand-royalblue rounded-full"
              >
                <span className="sr-only">Z-DAG</span>
                <span
                  className={`${
                    ZDAG
                      ? 'bg-warning-success translate-x-6'
                      : 'bg-warning-error translate-x-1'
                  } inline-block w-2 h-2 transform rounded-full`}
                  id="z-dag-switch"
                />
              </Switch>
            </Form.Item>
          </div>
        </div>

        <Form.Item
          name="amount"
          className="md:w-full md:max-w-md"
          hasFeedback
          rules={[
            {
              required: true,
              message: '',
            },
            () => ({
              validator(_, value) {
                const balance = selectedAsset
                  ? selectedAsset.balance / 10 ** selectedAsset.decimals
                  : Number(activeAccount?.balances.syscoin);

                if (value > balance) {
                  return Promise.reject();
                }

                return Promise.resolve();
              },
            }),
          ]}
        >
          <Input className="large" type="number" placeholder="Amount" />
        </Form.Item>

        <div className="flex gap-x-0.5 items-center justify-center mx-2 md:w-full md:max-w-md">
          <Form.Item
            name="recommend"
            className="py-1.5 w-12 text-center bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-l-full opacity-50"
            rules={[
              {
                required: false,
                message: '',
              },
            ]}
          >
            <Tooltip content="Use recommended fee. Disabled for SYS networks because the fee used in transactions is already the recommended with current network conditions.">
              <div>
                <Icon
                  wrapperClassname="w-6 ml-3 mb-1"
                  name="verified"
                  className="text-warning-success opacity-50 cursor-not-allowed"
                />
              </div>
            </Tooltip>
          </Form.Item>

          <Form.Item
            name="fee"
            className="md:w-full"
            hasFeedback
            rules={[
              {
                required: true,
                message: '',
              },
            ]}
          >
            <Tooltip content="Network fee">
              <Input
                disabled
                className="block pl-4 pr-8 py-3 w-60 text-brand-white text-sm bg-fields-input-primary border border-fields-input-border rounded-r-full outline-none opacity-50 cursor-not-allowed md:w-full"
                id="fee-input"
                type="number"
                placeholder="Fee network"
                value={recommend}
              />
            </Tooltip>
          </Form.Item>
        </div>

        <p className="flex flex-col items-center justify-center p-0 max-w-xs text-center text-brand-royalblue sm:w-full md:my-4">
          <span className="text-xs">
            {`With current network conditions we recommend a fee of ${recommend} SYS`}
          </span>

          <span className="mt-0.5 text-brand-white font-rubik text-xs">
            {'≈ '}
            {fiatValueToShow}
          </span>
        </p>

        <SecondaryButton type="submit" id="next-btn">
          Next
        </SecondaryButton>
      </Form>
    </div>
  );
}
Example #15
Source File: Currency.tsx    From pali-wallet with MIT License 4 votes vote down vote up
CurrencyView = () => {
  const controller = getController();
  const { navigate, handleRefresh } = useUtils();
  const { getFiatAmount } = usePrice();
  const { activeAccount } = useStore();

  if (!activeAccount) throw new Error('No account');

  const { accounts, activeAccountId, coins, fiat, activeNetwork, networks } =
    useStore();

  const { asset } = fiat;

  const [selectedCoin, setSelectedCoin] = useState(String(asset));
  const [checkValueCoin, setCheckValueCoin] = useState('usd');
  const [confirmed, setConfirmed] = useState(false);
  const [fiatAmountValue, setFiatAmountValue] = useState('');

  const convertCurrency = (value: number, toCoin: string) =>
    value * coins[toCoin];

  const convertToCrypto = (value: number, fromCoin: string) =>
    value / coins[fromCoin];

  const isUnlocked =
    controller.wallet.isUnlocked() && activeAccount.address !== '';

  const isSyscoinChain = Boolean(networks.syscoin[activeNetwork.chainId]);

  const balance = isSyscoinChain
    ? activeAccount.balances.syscoin
    : activeAccount.balances.ethereum;

  const [conversorValues, setConversorValues] = useState({
    crypto: balance,
    fiat: convertCurrency(balance, checkValueCoin),
  });

  const handleConvert = (value: number, toCoin: string) => {
    setConversorValues({
      crypto: value,
      fiat: convertCurrency(value, toCoin),
    });
  };

  const handleReverseConvert = (value: number, fromCoin: string) => {
    setConversorValues({
      crypto: convertToCrypto(value, fromCoin),
      fiat: value,
    });
  };

  const handleConfirmCurrencyChange = () => {
    setConfirmed(true);
  };

  const fiatCurrency = asset ? String(asset).toUpperCase() : 'USD';

  const getFiatAmountValue = async () => {
    const value = await getFiatAmount(balance || 0, 4, String(selectedCoin));

    setFiatAmountValue(value);
  };

  useEffect(() => {
    if (isUnlocked && accounts && accounts[activeAccountId]) {
      handleRefresh(true);
    }
  }, [isUnlocked, activeAccountId]);

  useEffect(() => {
    if (selectedCoin) {
      controller.utils.setFiat(
        selectedCoin,
        isSyscoinChain ? 'syscoin' : 'ethereum'
      );

      getFiatAmountValue();
    }
  }, [selectedCoin]);

  useEffect(() => {
    getFiatAmountValue();
  }, [selectedCoin, getFiatAmountValue]);

  return (
    <Layout title="FIAT CURRENCY" id="fiat-currency-title">
      <DefaultModal
        show={confirmed}
        onClose={() => navigate('/home')}
        title="Fiat currency set successfully"
        description={`Now you will see the values in your wallet in SYS and ${
          selectedCoin.toUpperCase() || 'USD'
        }`}
      />

      <p className="mx-4 my-3 max-w-xs text-left text-white text-sm md:max-w-full">
        You can choose and set your preferred currency to see in your wallet.
      </p>

      <div className="flex flex-col items-center justify-center">
        <Menu as="div" className="relative inline-block text-left">
          <Menu.Button
            disabled={!fiat || !coins}
            className="inline-flex justify-center py-2 w-80 text-white text-sm font-medium bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-full"
          >
            <p className="ml-2">
              {selectedCoin ? selectedCoin.toUpperCase() : fiatCurrency}
            </p>

            <Icon
              name="select-down"
              className="text-brand-royalblue"
              wrapperClassname="w-8 absolute right-28 bottom-3"
            />
          </Menu.Button>

          <Transition
            as={Fragment}
            enter="transition ease-out duration-100"
            enterFrom="transform opacity-0 scale-95"
            enterTo="transform opacity-100 scale-100"
            leave="transition ease-in duration-75"
            leaveFrom="transform opacity-100 scale-100"
            leaveTo="transform opacity-0 scale-95"
          >
            {fiat && coins && (
              <Menu.Items className="scrollbar-styled absolute z-10 mt-2 py-3 w-full h-44 text-brand-white font-poppins bg-bkg-4 border border-fields-input-border rounded-xl shadow-2xl overflow-auto origin-top-right">
                {Object.entries(coins).map(([key]) => (
                  <Menu.Item key={key}>
                    <button
                      key={key}
                      onClick={() => setSelectedCoin(key)}
                      className="group flex gap-x-1 items-center justify-start px-4 py-2 w-full hover:text-brand-royalbluemedium text-brand-white font-poppins text-sm border-0 border-b border-dashed border-brand-royalblue border-transparent border-opacity-30 transition-all duration-300"
                    >
                      {getSymbolFromCurrency(key.toUpperCase())}

                      <p>{key.toUpperCase()}</p>
                    </button>
                  </Menu.Item>
                ))}
              </Menu.Items>
            )}
          </Transition>
        </Menu>

        <div className="flex flex-col items-center justify-center text-center">
          {activeNetwork.chainId === 5700 ? (
            <div className="flex gap-x-0.5 items-center justify-center mt-8">
              <p className="font-rubik text-5xl font-medium">
                {formatNumber(Number(balance) || 0)}{' '}
              </p>

              <p className="font-poppins md:mt-4">TSYS</p>
            </div>
          ) : (
            <>
              <div className="flex gap-x-0.5 items-center justify-center mt-8">
                <p className="font-rubik text-5xl font-medium">
                  {formatNumber(balance || 0)}{' '}
                </p>

                <p className="font-poppins md:mt-4">
                  {activeNetwork.currency
                    ? activeNetwork.currency.toUpperCase()
                    : ''}
                </p>
              </div>

              <p>{fiatAmountValue ?? 0}</p>
            </>
          )}
        </div>

        <div className="mt-6 md:mt-8">
          <SecondaryButton type="button" onClick={handleConfirmCurrencyChange}>
            Save
          </SecondaryButton>
        </div>
      </div>

      <div className="fixed bottom-0 left-0 flex flex-col gap-y-3 items-center justify-center w-full max-w-2xl h-44 bg-bkg-4 md:bottom-8 md:left-auto">
        <p className="mb-2 text-left text-white text-sm">
          Check your balance in different currencies
        </p>

        <div className="standard relative text-brand-royalblue text-sm font-medium">
          <Input
            type="number"
            onChange={(event) =>
              handleConvert(Number(event.target.value), checkValueCoin)
            }
            maxLength={20}
            value={Number(conversorValues.crypto)}
            className="flex items-center justify-between px-4 py-2 w-80 bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-full outline-none"
          />

          <div className="absolute bottom-1.5 right-4 flex gap-x-3 items-center justify-center">
            <p
              className="cursor-pointer"
              onClick={() => handleConvert(Number(balance), checkValueCoin)}
            >
              MAX
            </p>

            <div className="flex gap-x-3 items-center justify-center border-l border-dashed border-gray-700">
              <Icon
                name="dolar"
                wrapperClassname="w-2 ml-4 mb-1.5"
                className="text-brand-royalblue"
              />

              <p>SYS</p>
            </div>
          </div>
        </div>

        <div className="standard relative text-brand-royalblue text-sm font-medium">
          <Input
            type="number"
            maxLength={20}
            onChange={(event) => {
              handleReverseConvert(Number(event.target.value), checkValueCoin);
            }}
            value={Number(conversorValues.fiat)}
            className="flex items-center justify-between px-4 py-2 w-80 bg-fields-input-primary border border-fields-input-border focus:border-fields-input-borderfocus rounded-full outline-none"
          />
          <div className="absolute bottom-2 right-2 flex gap-x-3 items-center justify-center">
            <Menu as="div" className="relative inline-block text-left">
              <Menu.Button
                disabled={!fiat || !coins}
                className="flex gap-x-1 justify-center mr-5 text-brand-royalblue text-sm font-medium bg-fields-input-primary rounded-full"
              >
                {getSymbolFromCurrency(checkValueCoin.toUpperCase())}
                {checkValueCoin.toUpperCase()}

                <Icon
                  name="select-down"
                  className="text-brand-royalblue"
                  wrapperClassname="w-8 absolute -right-1 bottom-1"
                />
              </Menu.Button>

              <Transition
                as={Fragment}
                enter="transition ease-out duration-100"
                enterFrom="transform opacity-0 scale-95"
                enterTo="transform opacity-100 scale-100"
                leave="transition ease-in duration-75"
                leaveFrom="transform opacity-100 scale-100"
                leaveTo="transform opacity-0 scale-95"
              >
                {fiat && coins && (
                  <Menu.Items className="scrollbar-styled absolute z-10 bottom-10 right-0 mt-2 py-3 w-44 h-56 text-brand-white font-poppins bg-bkg-4 border border-fields-input-border rounded-xl shadow-2xl overflow-auto origin-bottom-right">
                    {Object.entries(coins).map(([key]) => (
                      <Menu.Item key={key}>
                        <button
                          key={key}
                          onClick={() => {
                            setCheckValueCoin(key);
                            handleConvert(conversorValues.crypto, key);
                          }}
                          className="group flex gap-x-1 items-center justify-start px-4 py-2 w-full hover:text-brand-royalbluemedium text-brand-white font-poppins text-sm border-0 border-b border-dashed border-brand-royalblue border-transparent border-opacity-30 transition-all duration-300"
                        >
                          {getSymbolFromCurrency(key.toUpperCase())}

                          <p>{key.toUpperCase()}</p>
                        </button>
                      </Menu.Item>
                    ))}
                  </Menu.Items>
                )}
              </Transition>
            </Menu>
          </div>
        </div>
      </div>
    </Layout>
  );
}