import { useAuthSlice } from "@/app/providers";
import type { User } from "@/entities/user";
import { DisplayUser } from "@/features/display-user";
import { EventsList, myEventsFilter } from "@/features/events-list";
import { useLogin } from "@/features/login/hooks/useLogin";
import { useTokenBalance } from "@/shared/hooks";
import { getPrimaryRole, hasRole } from "@/shared/lib/RBAC";
import { formatUsdt, parseUsdt } from "@/shared/lib/money/usdt";
import { getCurrencySymbol, mintERC20 } from "@/shared/lib/web3";
// import { BridgeWidget } from "@/shared/ui/bridge/BridgeWidget";
import { Button } from "@/shared/ui/button";
import { Expandable } from "@/shared/ui/expandable/ui/Expandable";
import { ExpandableContent } from "@/shared/ui/expandable/ui/ExpandableContent";
import { ExpandableTrigger } from "@/shared/ui/expandable/ui/ExpandableTrigger";
import { useQueryClient } from "@tanstack/react-query";
import { LogOut } from "lucide-react";
import { useState } from "react";
import { Link, useNavigate } from "react-router";
import { twMerge } from "tailwind-merge";
import {
  useActiveAccount,
  useActiveWallet,
  useDisconnect,
} from "thirdweb/react";

const getRoleDisplayName = (user: User | null): string | null => {
  if (!user) return null;

  const primaryRole = getPrimaryRole(user.roles);

  switch (primaryRole) {
    case "master":
      return "Master";
    case "localprovider":
      return "LocalProvider";
    case "verifiedshaman":
      return "VerifiedShaman";
    case "creator":
      return "Shaman";
    default:
      return null;
  }
};

export const AccountPage: React.FC = () => {
  const navigate = useNavigate();
  const { clear, user, address: storedAddress } = useAuthSlice();
  const account = useActiveAccount();
  const activeWallet = useActiveWallet();
  const { disconnect } = useDisconnect();
  const { login, buttonProps } = useLogin();
  const { data: tokenBalance, isLoading: isLoadingBalance } = useTokenBalance();
  const queryClient = useQueryClient();
  const [isMinting, setIsMinting] = useState(false);

  const logout = async () => {
    if (!confirm("Logout?")) {
      return;
    }
    if (activeWallet) {
      disconnect(activeWallet);
    }
    clear();
  };

  // Use account address if available, otherwise fallback to user address from auth
  const address = account?.address ?? user?.address ?? storedAddress ?? "";
  const isConnected = !!account;

  return (
    <div>
      <header className="flex justify-start items-center gap-5 py-4 px-5">
        <h2 className="text-2xl font-semibold text-primary text-shadow-primary text-shadow-xs">
          Account
        </h2>
        <div className="ml-auto flex gap-2">
          {isConnected && (
            <Button variant="destructive" onClick={logout}>
              <LogOut />
            </Button>
          )}
        </div>
      </header>
      <div className="flex flex-col">
        <div className="flex gap-5 self-center py-5 px-10 sm:px-20">
          <div className="flex md:flex-row md:gap-3 flex-col items-center">
            {address ? (
              <img
                className="rounded-full h-14 md:h-20 aspect-square"
                src={`https://effigy.im/a/${address}.svg`}
                alt="User"
              />
            ) : (
              <div className="rounded-full h-14 md:h-20 aspect-square bg-primary/10" />
            )}
            <div className="flex flex-col items-center md:items-start gap-1">
              <p className="text-lg">
                {address ? (
                  <DisplayUser address={address} className="text-lg" />
                ) : (
                  <span className="text-muted-foreground">
                    Connect a wallet to continue
                  </span>
                )}
              </p>
              {getRoleDisplayName(user) && (
                <p className="text-sm font-semibold text-primary">
                  {getRoleDisplayName(user)}
                </p>
              )}
              <div className="flex items-center gap-2">
                <img
                  className="h-6 aspect-square"
                  src={getCurrencySymbol()}
                  alt="Token"
                />
                <p className="text-lg font-semibold text-gray-400">
                  {isLoadingBalance
                    ? "Loading..."
                    : tokenBalance
                      ? formatUsdt(tokenBalance)
                      : "0"}{" "}
                  USDT
                </p>
              </div>
            </div>
          </div>
        </div>

        {!isConnected ? (
          <div className="flex items-center justify-center min-h-[50vh] px-6">
            <Button
              className="w-full max-w-sm"
              disabled={buttonProps.isConnecting}
              onClick={() => login()}
            >
              {buttonProps.isConnecting ? "Connecting..." : "Connect"}
            </Button>
          </div>
        ) : (
          <>
            <div className="w-1/2 h-full self-center flex flex-col justify-between gap-20">
              <div className="flex flex-col gap-4">
                {(() => {
                  const lastSocial =
                    user?.socials && user.socials.length > 0
                      ? user.socials[user.socials.length - 1]
                      : null;
                  return (
                    lastSocial && (
                      <div className="flex items-center justify-between">
                        <h3 className="capitalize font-semibold text-lg">
                          {lastSocial.network}:
                        </h3>
                        <p className="italic">{lastSocial.value}</p>
                      </div>
                    )
                  );
                })()}
                <Button
                  filling="outline"
                  type="button"
                  onClick={() => navigate("/socials")}
                >
                  {user?.socials[0] ? "Update" : "Set"} socials
                </Button>
                <Button
                  className="mt-8"
                  disabled={isMinting}
                  onClick={async () => {
                    const maybeAmount = prompt("Amount of tokens to mint:");
                    if (maybeAmount == null) {
                      // User decided to cancel
                      return;
                    }

                    let amount: bigint;
                    try {
                      amount = parseUsdt(maybeAmount);
                    } catch (e) {
                      alert(
                        `Failed to process amount with: ${JSON.stringify(e)}`,
                      );
                      return;
                    }

                    if (amount <= 0) {
                      alert("Amount should be greater than zero");
                      return;
                    }

                    if (!account) {
                      alert("No active account found");
                      return;
                    }

                    setIsMinting(true);
                    try {
                      await mintERC20(account, amount);
                      alert(`Minted ${formatUsdt(amount)} USDT`);
                      // Invalidate and refetch the token balance
                      queryClient.invalidateQueries({
                        queryKey: ["tokenBalance", account?.address],
                      });
                    } catch (err) {
                      alert(`Failed to mint ERC20 with ${JSON.stringify(err)}`);
                    } finally {
                      setIsMinting(false);
                    }
                  }}
                >
                  {isMinting ? "Minting..." : "Mint ERC20"}
                </Button>
                {/* <BridgeWidget /> */}
              </div>
            </div>
            {user && manageView(user)}
            <div className="p-5">
              <Expandable defaultOpened>
                <ExpandableTrigger className="w-full my-3 p-3 text-xl flex justify-start gap-3 items-center">
                  {({ isCurrentExpanded }) => (
                    <>
                      <img
                        className={twMerge(
                          "h-8 transition-all duration-300",
                          isCurrentExpanded && "rotate-90",
                        )}
                        alt="chevrone"
                        src="/icons/chevrone_right.svg"
                      />
                      <span>Current events</span>
                    </>
                  )}
                </ExpandableTrigger>
                <ExpandableContent>
                  <EventsList
                    filterFn={(event, user) =>
                      myEventsFilter(event, user, "current")
                    }
                  />
                </ExpandableContent>
              </Expandable>
              <Expandable defaultOpened>
                <ExpandableTrigger className="w-full my-3 p-3 text-xl flex justify-start gap-3 items-center">
                  {({ isCurrentExpanded }) => (
                    <>
                      <img
                        className={twMerge(
                          "h-8 transition-all duration-300",
                          isCurrentExpanded && "rotate-90",
                        )}
                        alt="chevrone"
                        src="/icons/chevrone_right.svg"
                      />
                      <span>Upcoming events</span>
                    </>
                  )}
                </ExpandableTrigger>
                <ExpandableContent>
                  <EventsList
                    filterFn={(event, user) =>
                      myEventsFilter(event, user, "upcoming")
                    }
                  />
                </ExpandableContent>
              </Expandable>
              <Expandable defaultOpened>
                <ExpandableTrigger className="w-full my-3 p-3 text-xl flex justify-start gap-3 items-center">
                  {({ isCurrentExpanded }) => (
                    <>
                      <img
                        className={twMerge(
                          "h-8 transition-all duration-300",
                          isCurrentExpanded && "rotate-90",
                        )}
                        alt="chevrone"
                        src="/icons/chevrone_right.svg"
                      />
                      <span>Past events</span>
                    </>
                  )}
                </ExpandableTrigger>
                <ExpandableContent>
                  <EventsList
                    filterFn={(event, user) =>
                      myEventsFilter(event, user, "past")
                    }
                  />
                </ExpandableContent>
              </Expandable>
            </div>
          </>
        )}
      </div>
    </div>
  );
};

const manageView = (user: User): React.ReactNode => {
  // Show Master view if user has master role (highest priority)
  if (hasRole(user.roles, "master")) {
    return <MasterView />;
  }

  // Otherwise use primary role to determine view
  const primaryRole = getPrimaryRole(user.roles);

  switch (primaryRole) {
    case "localprovider":
      return <LocalProviderView />;
    case "verifiedshaman":
      return <VerifiedShamanView />;
    default:
      return null;
  }
};

const VerifiedShamanView = (): React.ReactNode => null;

const LocalProviderView = (): React.ReactNode => (
  <div className="p-5">
    <h3 className="text-xl font-semibold text-primary mb-4">Management</h3>
    <div className="flex flex-col gap-7">
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/manage/place"
      >
        Manage places
      </Link>
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/manage/staff"
      >
        Manage staff
      </Link>
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/manage/verifiedshamans"
      >
        Manage verified shamans
      </Link>
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/account/distribution-profiles/create"
      >
        Create distribution profile
      </Link>
    </div>
  </div>
);

const MasterView = (): React.ReactNode => (
  <div className="p-5">
    <h3 className="text-xl font-semibold text-primary mb-4">Management</h3>
    <div className="flex flex-col gap-7">
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/manage/localproviders"
      >
        Manage local providers
      </Link>
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/manage/place"
      >
        Manage places
      </Link>
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/manage/staff"
      >
        Manage staff
      </Link>
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/manage/verifiedshamans"
      >
        Manage verified shamans
      </Link>
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/manage/verification-stats"
      >
        Verification Statistics
      </Link>
      <Link
        className="card border-primary/30 text-center text-xl py-5"
        to="/account/distribution-profiles/create"
      >
        Create distribution profile
      </Link>
    </div>
  </div>
);

Homonyms

cyberia/research/events/client/src/pages/txhash/index.tsx
cyberia/research/events/client/src/pages/place/index.tsx
cyberia/research/events/client/src/pages/user/index.tsx
cyberia/research/events/client/src/pages/purchase/index.tsx
cyberia/research/events/client/src/pages/manage/index.tsx
cyberia/research/events/client/src/pages/notifications/index.tsx
cyberia/research/events/client/src/pages/shaman-verification/index.tsx
cyberia/research/events/client/src/pages/404/index.tsx
cyberia/research/events/client/src/pages/map/index.tsx
cyberia/research/events/client/src/pages/events/index.tsx
cyberia/research/events/client/src/pages/socials/index.tsx
cyberia/research/events/client/src/pages/home/index.tsx
cyberia/research/events/client/src/pages/events/attendees/index.tsx
cyberia/research/events/client/src/pages/events/create/index.tsx
cyberia/research/events/client/src/pages/events/details/index.tsx
cyberia/research/events/client/src/pages/manage/verifiedshamans/index.tsx
cyberia/research/events/client/src/pages/manage/staff/index.tsx
cyberia/research/events/client/src/pages/manage/verification-stats/index.tsx
cyberia/research/events/client/src/pages/manage/place/index.tsx
cyberia/research/events/client/src/pages/events/edit/index.tsx
cyberia/research/events/client/src/pages/manage/localprovider/index.tsx
cyberia/research/events/client/src/pages/manage/place/update/index.tsx
cyberia/research/events/client/src/pages/manage/place/create/index.tsx
cyberia/research/events/client/src/pages/account/distribution-profiles/create/index.tsx
cyberia/research/events/client/src/pages/manage/place/request/index.tsx

Graph