1
0
Fork 0
panel/components/ui/user-selector.tsx

89 lines
2.7 KiB
TypeScript

import { useEffect, useState } from "react";
import { Input } from "./input";
import { Card, CardDescription, CardHeader, CardTitle } from "./card";
import { Avatar, AvatarFallback, AvatarImage } from "./avatar";
import { User } from "revolt-api";
import { AUTUMN_URL } from "@/lib/constants";
import { fetchUserById } from "@/lib/db";
export default function UserSelector({ onChange }: {
onChange?: (user: User | null) => any,
}) {
const [input, setInput] = useState("");
const [user, setUser] = useState<User | null>(null);
const [searching, setSearching] = useState(false);
useEffect(() => {
if (input.length != 26) {
onChange?.(null);
if (user) setUser(null);
return;
}
if (!searching) return;
if (input != user?._id) {
setSearching(true);
fetchUserById(input)
.then((user) => {
setUser(user);
onChange?.(user);
})
.catch((e) => {
setUser(null);
onChange?.(null);
})
.finally(() => setSearching(false));
}
else setUser(null);
}, [input, user, searching, onChange]);
return (
<div>
<Input
className="rounded-b-none"
style={{ boxShadow: "none" }} // doing this with tailwind just... doesnt work
placeholder="Enter an ID..."
value={input}
onChange={(e) => {
setInput(e.currentTarget.value);
setSearching(true);
}}
/>
<Card className="border-t-0 rounded-t-none">
<CardHeader>
<CardTitle className={`flex items-center gap-1 ${user ? "" : "text-gray-400"}`}>
<Avatar>
{user && <AvatarImage src={`${AUTUMN_URL}/avatars/${user.avatar?._id}`} />}
<AvatarFallback className="overflow-hidden overflow-ellipsis whitespace-nowrap">
{user
? (user.display_name ?? user.username)
.split(" ")
.slice(0, 2)
.map((x) => String.fromCodePoint(x.codePointAt(0) ?? 32) ?? "")
.join("")
: "?"}
</AvatarFallback>
</Avatar>
{user
? <>{user.username}#{user.discriminator} {user.display_name}</>
: "User#0000"
}
</CardTitle>
<CardDescription>
{
!input
? "Enter an ID..."
: input.length != 26
? "Invalid ID"
: searching
? "Searching..."
: user
? "User exists!"
: "Unknown user"
}
</CardDescription>
</CardHeader>
</Card>
</div>
)
}