react query ftw
This commit is contained in:
22
components/providers/ReactQueryProvider.tsx
Normal file
22
components/providers/ReactQueryProvider.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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" />
|
||||
</>
|
||||
|
||||
@@ -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);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user