bigblocks
Version:
Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React
178 lines (177 loc) • 6.5 kB
JavaScript
// useFollowUser Hook - Follow/unfollow users by BAP ID
import { useMutation } from "@tanstack/react-query";
import { useBitcoinAuth } from "../../../hooks/useBitcoinAuth.js";
import { broadcastSocialTransaction } from "../../../lib/broadcast";
import { SocialActions } from "../../../lib/protocol.js";
export function useFollowUser(options = {}) {
const { app: _app = "bigblocks", onSuccess, onError } = options;
const { user } = useBitcoinAuth();
const followMutation = useMutation({
mutationFn: async ({ idKey }) => {
if (!user) {
throw {
code: "UNAUTHORIZED",
message: "User must be authenticated to follow others",
};
}
if (!idKey) {
throw {
code: "INVALID_BAP_ID",
message: "BAP ID is required to follow a user",
};
}
// Validate BAP ID format (basic validation)
if (typeof idKey !== "string" || idKey.trim().length === 0) {
throw {
code: "INVALID_BAP_ID",
message: "Invalid BAP ID format",
};
}
// Prevent self-following
if (user.idKey === idKey) {
throw {
code: "INVALID_CONTENT",
message: "Cannot follow yourself",
};
}
try {
const signingKey = user.signingKey;
if (!signingKey) {
throw {
code: "UNAUTHORIZED",
message: "No signing key available",
};
}
// Build follow transaction
const signedTransaction = await SocialActions.follow(idKey);
// Broadcast to Bitcoin network
const result = await broadcastSocialTransaction(signedTransaction);
if (!result.success) {
throw {
code: "BROADCAST_FAILED",
message: result.error || "Failed to broadcast follow",
};
}
return { ...result, action: "follow" };
}
catch (error) {
if (error.code) {
throw error;
}
throw {
code: "TRANSACTION_FAILED",
message: "Failed to create follow transaction",
details: error,
};
}
},
onSuccess: (data) => {
onSuccess?.({ ...data, action: "follow" });
},
onError: (error) => {
console.error("Follow user failed:", error);
onError?.(error);
},
});
return {
mutate: followMutation.mutate,
mutateAsync: followMutation.mutateAsync,
isLoading: followMutation.isPending,
isError: followMutation.isError,
isSuccess: followMutation.isSuccess,
error: followMutation.error,
data: followMutation.data,
reset: followMutation.reset,
};
}
// Unfollow hook
export function useUnfollowUser(options = {}) {
const { app: _app = "bigblocks", onSuccess, onError } = options;
const { user } = useBitcoinAuth();
const unfollowMutation = useMutation({
mutationFn: async ({ idKey }) => {
if (!user) {
throw {
code: "UNAUTHORIZED",
message: "User must be authenticated to unfollow others",
};
}
if (!idKey) {
throw {
code: "INVALID_BAP_ID",
message: "BAP ID is required to unfollow a user",
};
}
if (typeof idKey !== "string" || idKey.trim().length === 0) {
throw {
code: "INVALID_BAP_ID",
message: "Invalid BAP ID format",
};
}
try {
const signingKey = user.signingKey;
if (!signingKey) {
throw {
code: "UNAUTHORIZED",
message: "No signing key available",
};
}
// Build unfollow transaction
const signedTransaction = await SocialActions.unfollow(idKey);
// Broadcast to Bitcoin network
const result = await broadcastSocialTransaction(signedTransaction);
if (!result.success) {
throw {
code: "BROADCAST_FAILED",
message: result.error || "Failed to broadcast unfollow",
};
}
return { ...result, action: "unfollow" };
}
catch (error) {
if (error.code) {
throw error;
}
throw {
code: "TRANSACTION_FAILED",
message: "Failed to create unfollow transaction",
details: error,
};
}
},
onSuccess: (data) => {
onSuccess?.({ ...data, action: "unfollow" });
},
onError: (error) => {
console.error("Unfollow user failed:", error);
onError?.(error);
},
});
return {
mutate: unfollowMutation.mutate,
mutateAsync: unfollowMutation.mutateAsync,
isLoading: unfollowMutation.isPending,
isError: unfollowMutation.isError,
isSuccess: unfollowMutation.isSuccess,
error: unfollowMutation.error,
data: unfollowMutation.data,
reset: unfollowMutation.reset,
};
}
// Combined hook for toggling follow status
export function useToggleFollow(options = {}) {
const followUser = useFollowUser(options);
const unfollowUser = useUnfollowUser(options);
return {
follow: followUser,
unfollow: unfollowUser,
toggle: (idKey, currentlyFollowing) => {
if (currentlyFollowing) {
return unfollowUser.mutate({ idKey });
}
return followUser.mutate({ idKey });
},
isLoading: followUser.isLoading || unfollowUser.isLoading,
error: followUser.error || unfollowUser.error,
};
}