diff --git a/frontend/src/components/CopyAddressToClipboard.tsx b/frontend/src/components/CopyAddressToClipboard.tsx
new file mode 100644
index 0000000..1f314a5
--- /dev/null
+++ b/frontend/src/components/CopyAddressToClipboard.tsx
@@ -0,0 +1,64 @@
+import { useState } from "react";
+import { Copy, Check } from "lucide-react";
+import { cn } from "@/lib/utils";
+
+interface CopyAddressToClipboardProps {
+ address: string;
+ displayAddress?: string;
+ className?: string;
+ iconSize?: "sm" | "md";
+ showFeedback?: boolean;
+}
+
+export function CopyAddressToClipboard({
+ address,
+ displayAddress,
+ className,
+ iconSize = "sm",
+ showFeedback = true,
+}: CopyAddressToClipboardProps) {
+ const [copied, setCopied] = useState(false);
+
+ const handleCopy = async (e: React.MouseEvent) => {
+ e.preventDefault();
+ e.stopPropagation();
+
+ try {
+ await navigator.clipboard.writeText(address);
+ if (showFeedback) {
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ }
+ } catch (err) {
+ console.error("Failed to copy address:", err);
+ }
+ };
+
+ const iconClasses = cn(
+ "transition-colors hover:text-gray-700 cursor-pointer",
+ iconSize === "sm" ? "h-3.5 w-3.5" : "h-4 w-4",
+ copied ? "text-green-600" : "text-gray-500"
+ );
+
+ return (
+
+ {displayAddress && (
+ {displayAddress}
+ )}
+
+
+ );
+}
+
+export default CopyAddressToClipboard;
diff --git a/frontend/src/components/profiles/list/ProfileCard.tsx b/frontend/src/components/profiles/list/ProfileCard.tsx
index eae0318..f3c590a 100644
--- a/frontend/src/components/profiles/list/ProfileCard.tsx
+++ b/frontend/src/components/profiles/list/ProfileCard.tsx
@@ -12,6 +12,7 @@ import { useAccount } from "wagmi";
import DeleteProfileDialog from "../action-buttons/DeleteProfileDialog";
import { AddAttestationDialog } from "../action-buttons/AddAttestationDialog";
import AddressTokenBalance from "@/components/AddressTokenBalance";
+import CopyAddressToClipboard from "@/components/CopyAddressToClipboard";
interface ProfileCardProps {
address: string;
@@ -75,10 +76,15 @@ export function ProfileCard({
)}
-
-
+
+
{displayAddress}
+
diff --git a/frontend/src/components/profiles/profile-page/ProfileAttestations.tsx b/frontend/src/components/profiles/profile-page/ProfileAttestations.tsx
index e9fae57..2ed7742 100644
--- a/frontend/src/components/profiles/profile-page/ProfileAttestations.tsx
+++ b/frontend/src/components/profiles/profile-page/ProfileAttestations.tsx
@@ -8,6 +8,7 @@ import {
AccordionTrigger,
} from "@/components/ui/accordion";
import { useGetProfiles } from "@/hooks/profiles/use-get-profiles";
+import CopyAddressToClipboard from "@/components/CopyAddressToClipboard";
export function ProfileAttestations({ address }: { address: string }) {
const attestationsQuery = useGetAttestations();
@@ -87,17 +88,22 @@ export function ProfileAttestations({ address }: { address: string }) {
{it.justification}
-
- Issued by{" "}
+
diff --git a/frontend/src/components/profiles/profile-page/ProfileHeader.tsx b/frontend/src/components/profiles/profile-page/ProfileHeader.tsx
index cd0bc07..f75916a 100644
--- a/frontend/src/components/profiles/profile-page/ProfileHeader.tsx
+++ b/frontend/src/components/profiles/profile-page/ProfileHeader.tsx
@@ -3,6 +3,7 @@ import { useAccount } from "wagmi";
import { useMemo } from "react";
import { useGetProfiles } from "@/hooks/profiles/use-get-profiles";
import AddressTokenBalance from "@/components/AddressTokenBalance";
+import CopyAddressToClipboard from "@/components/CopyAddressToClipboard";
export function ProfileHeader({ address }: { address: string }) {
const profilesQuery = useGetProfiles();
@@ -43,7 +44,12 @@ export function ProfileHeader({ address }: { address: string }) {
)}
{displayAddress ? (
- {displayAddress}
+
) : null}