import { useEffect, useState } from "react";
import { useNavigate } from "react-router";

import { useAuthSlice } from "@/app/providers";
import type { User } from "@/entities/user";
import { type Socials, upsertUserSocials } from "@/entities/user";
import { SocialsForm } from "@/features/socials-form";
import {
  fetchSiwePayload,
  fetchSiweStatus,
  fetchSiweVerify,
} from "@/shared/lib/siwe/api";
import { PageContainer } from "@/shared/ui/PageContainer";
import { Button } from "@/shared/ui/button";
import { useActiveAccount } from "thirdweb/react";

export const SocialsPage: React.FC = () => {
  const { user, setUser } = useAuthSlice();
  const [error, setError] = useState(false);
  const navigate = useNavigate();
  const account = useActiveAccount();
  const [isTrusted, setIsTrusted] = useState(false);
  const [isSigning, setIsSigning] = useState(false);
  const [isCheckingTrust, setIsCheckingTrust] = useState(true);

  useEffect(() => {
    if (!account?.address) {
      setIsTrusted(false);
      setIsCheckingTrust(false);
      return;
    }

    // Check server-side trust cookie
    fetchSiweStatus({ address: account.address, scope: "ticket:nonce" })
      .then((s) => {
        setIsTrusted(s.trusted);
      })
      .catch(() => {
        setIsTrusted(false);
      })
      .finally(() => {
        setIsCheckingTrust(false);
      });
  }, [account?.address]);

  async function handleSubmit(socials: Socials) {
    setError(false);
    const { response } = await upsertUserSocials(socials);
    if (!response.ok) {
      setError(true);
      console.error("Failed to set socials");
      return;
    }
    // Refetch user data to get updated socials
    if (account?.address) {
      const url = new URL(
        "/api/users/current/",
        import.meta.env.PUBLIC_API_HOST,
      );
      url.searchParams.set("address", account.address);
      const resp = await fetch(url.toString(), { credentials: "include" });
      if (resp.ok) {
        setUser((await resp.json()) as User);
      }
    }
    navigate(-1);
  }

  const signToContinue = async () => {
    if (!account) {
      alert("No active wallet");
      return;
    }
    setIsSigning(true);
    try {
      const addr = account.address;
      const { payload, message } = await fetchSiwePayload({
        address: addr,
        purpose: "ticket_qr",
      });
      const signature = await account.signMessage({ message });
      await fetchSiweVerify({ payload, signature });
      setIsTrusted(true);
    } catch (e) {
      console.error(e);
      alert("Failed to sign");
    } finally {
      setIsSigning(false);
    }
  };

  if (!user) return null;

  return (
    <PageContainer name="Socials">
      {isCheckingTrust ? (
        <div className="flex flex-col items-center justify-center gap-4 p-6 text-center">
          <p className="text-muted-foreground">Checking authentication...</p>
        </div>
      ) : !isTrusted ? (
        <div className="flex flex-col items-center justify-center gap-4 p-6 text-center">
          <p className="text-muted-foreground">
            To protect your social information, please sign a message to prove
            you own this wallet.
          </p>
          <Button
            className="w-full max-w-sm"
            onClick={signToContinue}
            disabled={isSigning}
          >
            {isSigning ? "Signing..." : "Sign to continue"}
          </Button>
        </div>
      ) : (
        <SocialsForm
          onSubmit={handleSubmit}
          existingSocials={user.socials[0]}
          userAddress={user.address}
        />
      )}
      {error && (
        <p className="text-center py-6 text-lg text-red-500">
          Some problem occured while setting socials. <br /> Try again.
        </p>
      )}
    </PageContainer>
  );
};

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/account/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/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