161 lines
4.1 KiB
TypeScript

"use client";
import { useState, useEffect, useCallback } from "react";
import Link from "next/link";
import Items from "~/components/sellable_items";
import Search from "~/components/search";
import CartButton from "~/components/cart";
import type { Session } from "next-auth";
import AccountButton from "./account";
import SellableItemsButton from "./new_items";
import TransferButton from "./transfer";
type UserResponse = {
id: string;
name: string | null;
carts: {
cartItems: {
itemId: string;
quantity: number;
}[];
}[];
balance: number;
adresses: string[];
};
type SellableResponse = {
id: string;
item_name: string;
amount: number;
price: number;
enabled: boolean;
shop: {
label: string;
};
item: {
stock: number;
};
};
type Props = {
session: Session | null;
};
export default function HomeClient({ session }: Props) {
const [query, setQuery] = useState("");
const [userData, setUserData] = useState<UserResponse | null>(null);
const [sellableData, setSellableData] = useState<SellableResponse[]>([]);
const [loading, setLoading] = useState(true);
// Fetch /api/user once and store globally here
const loadUser = useCallback(async () => {
try {
setLoading(true);
const res = await fetch("/api/user");
if (!res.ok) throw new Error("Failed to fetch user");
const data = (await res.json()) as UserResponse;
setUserData(data);
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
}, []);
const loadSellable = useCallback(async () => {
try {
setLoading(true);
const res = await fetch("/api/sellable");
if (!res.ok) throw new Error("Failed to fetch sellable");
const data = (await res.json()) as SellableResponse[];
setSellableData(data);
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
if (!session) return;
// Load immediately
void loadUser();
void loadSellable();
// Set intervals to reload every 30s (30000ms)
const userInterval = setInterval(() => {
void loadUser();
}, 30000);
const sellableInterval = setInterval(() => {
void loadSellable();
}, 30000);
// Clear intervals on unmount
return () => {
clearInterval(userInterval);
clearInterval(sellableInterval);
};
}, [session, loadUser, loadSellable]);
return (
<main className="flex min-h-screen flex-col items-center justify-center bg-linear-to-b from-[#2e026d] to-[#7f3b3b] text-white">
<div className="absolute top-4 right-4 flex items-center gap-4">
{userData && (
<TransferButton
balance={userData.balance ?? 0}
reloadUser={loadUser}
/>
)}
{session?.user && (
<>
<CartButton
userData={userData}
reloadUser={loadUser}
loading={loading}
/>
<AccountButton loading={loading} />
<SellableItemsButton
loading={loading}
reloadSellable={loadSellable}
reloadUser={loadUser}
/>
</>
)}
<Search query={query} setQuery={setQuery} />
{session?.user ? (
<Link
href="/api/auth/signout"
className="rounded-full bg-white/10 px-4 py-2 font-semibold transition hover:bg-white/20"
>
Sign out
</Link>
) : (
<Link
href="/api/auth/signin"
className="rounded-full bg-white/10 px-4 py-2 font-semibold transition hover:bg-white/20"
>
Sign in
</Link>
)}
</div>
<div className="container flex flex-col items-center gap-12 px-4 py-16">
<h1 className="text-5xl font-extrabold tracking-tight">
Suchodupin <span className="text-[hsl(280,100%,70%)]">MC</span> Shop
</h1>
{sellableData && (
<Items
query={query}
sellableData={sellableData}
reloadUser={loadUser}
/>
)}
</div>
</main>
);
}