smart smart method by google gemini
This commit is contained in:
@@ -9,7 +9,7 @@ import { loadThumbnails } from "@/lib/thumbnailLoader";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
let isFetching = false;
|
||||
let cachedData: any = null;
|
||||
let cachedData: UserProfileDetails | null | false = null;
|
||||
|
||||
export function useCurrentAccount() {
|
||||
const [profileDetails, setProfileDetails] = useState<
|
||||
@@ -18,7 +18,7 @@ export function useCurrentAccount() {
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
if (profileDetails !== null) return;
|
||||
if (profileDetails !== null && profileDetails !== undefined) return;
|
||||
if (isFetching) {
|
||||
const IN = setInterval(() => {
|
||||
if (cachedData !== null) {
|
||||
|
||||
127
hooks/roblox/usePresence.ts
Normal file
127
hooks/roblox/usePresence.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
"use client";
|
||||
|
||||
// smartass method by google gemini
|
||||
|
||||
import { useEffect, useState, useMemo } from "react";
|
||||
import { useCurrentAccount } from "./useCurrentAccount";
|
||||
import { proxyFetch } from "@/lib/utils";
|
||||
|
||||
type PresenceData = {
|
||||
userPresenceType: number;
|
||||
lastLocation: string;
|
||||
placeId: number;
|
||||
rootPlaceId: number;
|
||||
gameId: string;
|
||||
universeId: number;
|
||||
userId: number;
|
||||
};
|
||||
|
||||
// --- Internal Shared State ---
|
||||
|
||||
/**
|
||||
* A Map to track subscribers.
|
||||
* Key: The component's update callback function.
|
||||
* Value: The array of user IDs that component is interested in.
|
||||
* This allows multiple components to subscribe with their own lists of IDs.
|
||||
*/
|
||||
let subscribers = new Map<(data: PresenceData[]) => void, number[]>();
|
||||
|
||||
let interval: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
let latestData: PresenceData[] = [];
|
||||
|
||||
/**
|
||||
* Fetches presence for all unique user IDs requested by all subscribed components.
|
||||
* @param acctId - The ID of the currently logged-in user.
|
||||
*/
|
||||
async function fetchPresence(acctId: number) {
|
||||
const allIdArrays = [...subscribers.values()];
|
||||
const uniqueUserIds = [...new Set(allIdArrays.flat())];
|
||||
|
||||
if (!acctId || uniqueUserIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await proxyFetch(
|
||||
"https://presence.roblox.com/v1/presence/users",
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
userIds: [...new Set([acctId, ...uniqueUserIds])]
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`API request failed with status ${res.status}`);
|
||||
}
|
||||
|
||||
const json = await res.json();
|
||||
latestData = json.userPresences || [];
|
||||
|
||||
subscribers.forEach((_requestedIds, callback) => callback(latestData));
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch presence:", error);
|
||||
latestData = [];
|
||||
subscribers.forEach((_requestedIds, callback) => callback([]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A React hook to get the real-time presence of a list of Roblox users.
|
||||
* This hook can be used by multiple components simultaneously without conflict.
|
||||
*
|
||||
* @param userIds - An array of user IDs to track.
|
||||
* @returns An array of PresenceData objects for the requested user IDs.
|
||||
*/
|
||||
export function useFriendsPresence(userIds: number[]) {
|
||||
const acct = useCurrentAccount();
|
||||
const [data, setData] = useState<PresenceData[]>([]);
|
||||
|
||||
const userIdsKey = useMemo(
|
||||
() => JSON.stringify([...userIds].sort()),
|
||||
[userIds]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!acct || !userIds || userIds.length === 0) {
|
||||
setData([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const updateCallback = (globalData: PresenceData[]) => {
|
||||
const filteredData = globalData.filter((presence) =>
|
||||
userIds.includes(presence.userId)
|
||||
);
|
||||
setData(filteredData);
|
||||
};
|
||||
|
||||
updateCallback(latestData);
|
||||
|
||||
subscribers.set(updateCallback, userIds);
|
||||
|
||||
if (!interval) {
|
||||
fetchPresence(acct.id);
|
||||
interval = setInterval(() => fetchPresence(acct.id), 5000);
|
||||
} else {
|
||||
fetchPresence(acct.id);
|
||||
}
|
||||
|
||||
// The cleanup function runs when the component unmounts.
|
||||
return () => {
|
||||
subscribers.delete(updateCallback);
|
||||
|
||||
if (subscribers.size === 0 && interval) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
latestData = [];
|
||||
}
|
||||
};
|
||||
}, [acct, userIdsKey]);
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -4,46 +4,40 @@ import { useEffect, useState } from "react";
|
||||
import { useCurrentAccount } from "./useCurrentAccount";
|
||||
import { proxyFetch } from "@/lib/utils";
|
||||
|
||||
let isFetching = false;
|
||||
let cachedData: number | false | null = null;
|
||||
|
||||
export function useRobuxBalance() {
|
||||
const acct = useCurrentAccount();
|
||||
const [robux, setRobux] = useState<number | false | null>(cachedData);
|
||||
const [robux, setRobux] = useState<number | false | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
if (!acct) return;
|
||||
|
||||
async function fetchBalance() {
|
||||
if (isFetching) return;
|
||||
if (!acct) return;
|
||||
isFetching = true;
|
||||
let cancelled = false;
|
||||
|
||||
const fetchBalance = async () => {
|
||||
if (!acct || cancelled) return;
|
||||
try {
|
||||
const res = await proxyFetch(
|
||||
`https://economy.roblox.com/v1/users/${acct.id}/currency`
|
||||
);
|
||||
const data = await res.json();
|
||||
if (!cancelled) setRobux(data.robux);
|
||||
cachedData = data.robux;
|
||||
} catch {
|
||||
if (!cancelled) setRobux(false);
|
||||
cachedData = false;
|
||||
} finally {
|
||||
isFetching = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchBalance();
|
||||
const interval = setInterval(fetchBalance, 10000);
|
||||
|
||||
function handleTransaction() {
|
||||
const handleTransaction = () => {
|
||||
fetchBalance();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("transactionCompletedEvent", handleTransaction);
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
clearInterval(interval);
|
||||
window.removeEventListener(
|
||||
"transactionCompletedEvent",
|
||||
handleTransaction
|
||||
|
||||
Reference in New Issue
Block a user