forked from administration/panel
feat: user selector component
parent
7d7017168b
commit
3f5ec1f2ef
|
@ -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({
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue