react query ftw

This commit is contained in:
2025-08-14 22:46:42 +03:00
parent 78f792578d
commit 502a25fe52
24 changed files with 365 additions and 462 deletions

View File

@@ -0,0 +1,22 @@
"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { useState } from "react";
export function ReactQueryProvider({
children
}: {
children: React.ReactNode;
}) {
const [queryClient] = useState(() => new QueryClient());
return (
<QueryClientProvider client={queryClient}>
{children}
{process.env.NODE_ENV === "development" && (
<ReactQueryDevtools initialIsOpen={false} />
)}
</QueryClientProvider>
);
}

View File

@@ -1,7 +1,6 @@
import { useCurrentAccount } from "@/hooks/roblox/useCurrentAccount";
import { useFriendsHome } from "@/hooks/roblox/useFriends";
import { useFriendsPresence } from "@/hooks/roblox/usePresence";
import React, { useEffect, useState } from "react";
import React, { useMemo } from "react";
import LazyLoadedImage from "../util/LazyLoadedImage";
import { StupidHoverThing } from "../util/MiscStuff";
import { VerifiedIcon } from "./RobloxIcons";
@@ -29,78 +28,32 @@ export function FriendCarousel({
}) {
const acct = useCurrentAccount();
const presence = useFriendsPresence(
(!!friendsUnsorted ? friendsUnsorted : []).map((f) => f.id)
(friendsUnsorted || []).map((f) => f.id)
);
const [friendsLabel, setFriendsLabel] = useState<string>("");
const friends = useMemo(() => {
if (!friendsUnsorted) return [];
const [friends, setFriends] = useState<
{
hasVerifiedBadge: boolean;
id: number;
name: string;
displayName: string;
}[]
>([]);
return [...friendsUnsorted].sort((a, b) => {
if (dontSortByActivity) return -10;
useEffect(() => {
let numStudio = 0;
let numGame = 0;
let numOnline = 0;
for (const friend of friendsUnsorted || []) {
const st = presence.find((c) => c.userId === friend.id);
switch (st?.userPresenceType || 0) {
case 1:
numOnline += 1;
break;
case 2:
numGame += 1;
break;
case 3:
numStudio += 1;
break;
}
}
setFriendsLabel(
[
// `${friends.length}`,
(numOnline+numGame+numStudio === 0 || numOnline === 0) ? null : `${numOnline+numGame+numStudio} online`,
numGame === 0 ? null : `${numGame} in-game`,
const userStatusA = presence.find((c) => c.userId === a.id);
const userStatusB = presence.find((c) => c.userId === b.id);
]
.filter((a) => !!a)
.join(" | ")
);
if (!friendsUnsorted) {
setFriends([]);
return;
}
setFriends(
friendsUnsorted.sort((a, b) => {
if (!!dontSortByActivity) return -10;
const userStatusA = presence.find((c) => c.userId === a.id);
const userStatusB = presence.find((c) => c.userId === b.id);
return (
(userStatusB?.userPresenceType || 0) -
(userStatusA?.userPresenceType || 0)
);
})
);
return (
(userStatusB?.userPresenceType || 0) -
(userStatusA?.userPresenceType || 0)
);
});
}, [friendsUnsorted, presence, dontSortByActivity]);
if (!friends || friends.length === 0) {
return <></>;
if (friends.length === 0) {
return null;
}
return (
<div {...props}>
{/* <button onClick={()=>console.log(acct,presence,friends)}>debug</button> */}
<h1 className="text-2xl pt-4 pl-4 -mb-4">
{title}{" "}
<span className="text-overlay1 text-sm pl-2">{friendsLabel}</span>
</h1>
<h1 className="text-2xl pt-4 pl-4 -mb-4">{title}</h1>
<div className="rounded-xl flex flex-col gap-2 px-4 no-scrollbar">
<div
className="flex p-8 items-center gap-4 overflow-x-auto overflow-y-visible no-scrollbar pb-2 -mx-4 w-screen scrollbar-thin scrollbar-thumb-surface2 scrollbar-track-surface0"
@@ -110,7 +63,6 @@ export function FriendCarousel({
scrollbarWidth: "none"
}}
>
{/* <div className="w-8" /> */}
{friends.map((a) => {
const userStatus = presence.find(
(b) => b.userId === a.id
@@ -161,15 +113,16 @@ export function FriendCarousel({
className={`w-4 h-4 shrink-0`}
/>
) : null}
{ userPresence >= 2 ? <p>{userStatus?.lastLocation}</p> : <></>}
{userPresence >= 2 ? (
<p>
{userStatus?.lastLocation}
</p>
) : null}
</span>
</div>
}
>
<div
key={a.id}
className="flex flex-col min-w-[6.5rem]"
>
<div className="flex flex-col min-w-[6.5rem]">
<LazyLoadedImage
imgId={`AvatarHeadShot_${a.id}`}
alt={a.name}
@@ -191,7 +144,6 @@ export function FriendCarousel({
</StupidHoverThing>
);
})}
{/* <div className="w-8" /> */}
</div>
</div>
</div>

View File

@@ -22,5 +22,12 @@ export function BestFriendsHomeSect(
) {
const friends = useBestFriends();
return <FriendCarousel {...props} title="Best Friends" dontSortByActivity friends={friends} />;
return (
<FriendCarousel
{...props}
title="Best Friends"
dontSortByActivity
friends={friends}
/>
);
}

View File

@@ -1,9 +1,5 @@
import { PremiumIconSmall, VerifiedIcon } from "./RobloxIcons";
import {
Tooltip,
TooltipContent,
TooltipTrigger
} from "../ui/tooltip";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
export function RobloxPremiumSmall(props: React.SVGProps<SVGSVGElement>) {
return (

View File

@@ -17,9 +17,7 @@ import { toast } from "sonner";
// chatgpt + human
function randomGreeting(name: string): string {
const greetings = [
`Howdy, ${name}`
];
const greetings = [`Howdy, ${name}`];
const index = Math.floor(Math.random() * greetings.length);
return greetings[index];
@@ -52,12 +50,12 @@ export function HomeLoggedInHeader() {
userPresence === 1
? "border-blue/25 bg-blue/25"
: userPresence === 2
? "border-green/25 bg-green/25"
: userPresence === 3
? "border-yellow/25 bg-yellow/25"
: userPresence === 0
? "border-surface2/25 bg-surface2/25"
: "border-red/25 bg-red/25";
? "border-green/25 bg-green/25"
: userPresence === 3
? "border-yellow/25 bg-yellow/25"
: userPresence === 0
? "border-surface2/25 bg-surface2/25"
: "border-red/25 bg-red/25";
const isLoaded = !!profile && !!accountSettings;
@@ -92,7 +90,13 @@ export function HomeLoggedInHeader() {
)}
<div className="flex flex-col justify-center">
<span className="text-3xl font-bold text-text flex items-center gap-2">
{isLoaded ? randomGreeting(window.localStorage.UserPreferredName || profile.displayName || "Robloxian!") : (
{isLoaded ? (
randomGreeting(
window.localStorage.UserPreferredName ||
profile.displayName ||
"Robloxian!"
)
) : (
<>
<Skeleton className="w-96 h-8 rounded-lg" />
</>

View File

@@ -10,10 +10,16 @@ import { useCurrentAccount } from "@/hooks/roblox/useCurrentAccount";
type OutfitSelectorProps = {
setVisible: (visible: boolean) => void;
updateOutfit: (outfit: { id: number }, acc: {id: number}) => Promise<void>;
updateOutfit: (
outfit: { id: number },
acc: { id: number }
) => Promise<void>;
};
export function OutfitSelector({ setVisible, updateOutfit }: OutfitSelectorProps) {
export function OutfitSelector({
setVisible,
updateOutfit
}: OutfitSelectorProps) {
const outfits = useAvatarOutfits();
const acc = useCurrentAccount();
@@ -33,7 +39,7 @@ export function OutfitSelector({ setVisible, updateOutfit }: OutfitSelectorProps
key={outfit.id}
className="hover:bg-base/50 rounded-lg"
onClick={async () => {
updateOutfit(outfit,acc);
updateOutfit(outfit, acc);
setVisible(false);
}}
>

View File

@@ -79,7 +79,6 @@ async function updateOutfit(outfit: { id: number }, acc: { id: number }) {
}
);
loadThumbnails([
{
type: "AvatarHeadShot",
@@ -98,7 +97,7 @@ export const QuickTopUI = React.memo(function () {
const bf = useBestFriends();
useCurrentAccount();
useFriendsPresence([...(f ? f : []), ...(bf ? bf : [])].map(a=>a.id))
useFriendsPresence([...(f ? f : []), ...(bf ? bf : [])].map((a) => a.id));
const robux = useRobuxBalance();
const [isOutfitSelectorVisible, setIsOutfitSelectorVisible] =
@@ -154,9 +153,12 @@ export const QuickTopUILogoPart = React.memo(function () {
<Link href="/" className="-m-1 w-8 h-8">
<img src="/icon-512.webp" className="w-8 h-8" alt="" />
</Link>
<Link href="/test" className="mt-2 gap-2 flex items-center">
<Link href="/" className="mt-2 gap-2 flex items-center">
<p>{"ocbwoy3-chan's roblox"}</p>
<p className="text-surface2 line-clamp-1">{process.env.NODE_ENV} {process.env.NEXT_PUBLIC_CWD} {process.env.NEXT_PUBLIC_ARGV0}</p>
{/* <p className="text-surface2 line-clamp-1">
{process.env.NODE_ENV} {process.env.NEXT_PUBLIC_CWD}{" "}
{process.env.NEXT_PUBLIC_ARGV0}
</p> */}
</Link>
</div>
);

View File

@@ -2,15 +2,18 @@ import { TooltipProps } from "@radix-ui/react-tooltip";
import { VerifiedIcon } from "../roblox/RobloxIcons";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
export function StupidHoverThing({ children, text, ...props }: React.PropsWithChildren & TooltipProps & { text: string | React.ReactNode }) {
export function StupidHoverThing({
children,
text,
...props
}: React.PropsWithChildren &
TooltipProps & { text: string | React.ReactNode }) {
return (
<Tooltip {...props}>
<TooltipTrigger asChild>
{children}
</TooltipTrigger>
<TooltipTrigger asChild>{children}</TooltipTrigger>
<TooltipContent className="bg-surface0 text-text m-2">
<span className="text-sm flex items-center">{text}</span>
</TooltipContent>
</Tooltip>
)
);
}