1
0
Fork 0

feat: user selector component

user-stream
Lea 2023-08-20 15:33:31 +02:00
parent 7d7017168b
commit 3f5ec1f2ef
Signed by: lea
GPG Key ID: 1BAFFE8347019C42
2 changed files with 101 additions and 18 deletions

View File

@ -1,6 +1,6 @@
"use client";
import { Server } from "revolt-api";
import { Server, User } from "revolt-api";
import { Button, buttonVariants } from "../../ui/button";
import {
Command,
@ -22,12 +22,13 @@ import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu";
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
import { Input } from "@/components/ui/input";
import { Checkbox } from "@/components/ui/checkbox";
import UserSelector from "@/components/ui/user-selector";
export function ServerActions({ server }: { server: Server }) {
const [selectBadges, setSelectBadges] = useState(false);
const [serverDraft, setDraft] = useState(server);
const [newOwner, setNewOwner] = useState("");
const [newMember, setNewMember] = useState("");
const [newOwner, setNewOwner] = useState<User | null>(null);
const [newMember, setNewMember] = useState<User | null>(null);
const [newMemberEvent, setNewMemberEvent] = useState(true);
const { toast } = useToast();
@ -167,21 +168,19 @@ export function ServerActions({ server }: { server: Server }) {
</AlertDialogTitle>
<AlertDialogDescription className="flex flex-col gap-2">
Enter the ID of the new server owner.
<Input
placeholder="01EXAF3KX65608AJ4NG27YG1HM"
value={newOwner}
onChange={(e) => setNewOwner(e.currentTarget.value)}
<UserSelector
onChange={(user) => setNewOwner(user)}
/>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
disabled={newOwner.length != 26}
disabled={!newOwner}
onClick={async () => {
try {
await updateServerOwner(server._id, newOwner);
setNewOwner("");
await updateServerOwner(server._id, newOwner!._id);
setNewOwner(null);
toast({ title: "Server owner changed" });
} catch(e) {
toast({
@ -211,22 +210,18 @@ export function ServerActions({ server }: { server: Server }) {
</AlertDialogTitle>
<AlertDialogDescription className="flex flex-col gap-2">
Enter the ID of the user you want to add.
<Input
placeholder="01EXAF3KX65608AJ4NG27YG1HM"
value={newMember}
onChange={(e) => setNewMember(e.currentTarget.value)}
/>
<UserSelector onChange={(user) => setNewMember(user)} />
<Checkbox checked={newMemberEvent} onChange={(state) => setNewMemberEvent(state === true)}>Publish join event</Checkbox>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
disabled={newMember.length != 26}
disabled={!newMember}
onClick={async () => {
try {
await addServerMember(server._id, newMember, newMemberEvent);
setNewMember("");
await addServerMember(server._id, newMember!._id, newMemberEvent);
setNewMember(null);
toast({ title: "User added to server" });
} catch(e) {
toast({

View File

@ -0,0 +1,88 @@
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>
)
}