forked from administration/panel
162 lines
6.8 KiB
TypeScript
162 lines
6.8 KiB
TypeScript
"use client"
|
|
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card";
|
|
import { ChannelInvite } from "@/lib/db";
|
|
import Link from "next/link";
|
|
import { Channel, User } from "revolt-api";
|
|
import { Button } from "../ui/button";
|
|
import { AlertDialogFooter, AlertDialogHeader, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger } from "../ui/alert-dialog";
|
|
import { toast } from "../ui/use-toast";
|
|
import { Input } from "../ui/input";
|
|
import { useMemo, useState } from "react";
|
|
import { deleteInvite, editInvite, editInviteChannel } from "@/lib/actions";
|
|
import { ChannelDropdown } from "../pages/inspector/InviteList";
|
|
|
|
export function InviteCard({
|
|
invite,
|
|
channel: channelInput,
|
|
channelList,
|
|
user,
|
|
}: {
|
|
invite: ChannelInvite;
|
|
channel?: Channel;
|
|
channelList?: Channel[];
|
|
user?: User;
|
|
}) {
|
|
const [editDraft, setEditDraft] = useState(invite._id);
|
|
const [deleted, setDeleted] = useState(false);
|
|
const [code, setCode] = useState(invite._id);
|
|
const [channelId, setChannelId] = useState(channelInput?._id ?? "");
|
|
const [channelDraft, setChannelDraft] = useState(channelInput?._id ?? "");
|
|
|
|
const channel = useMemo(
|
|
() => channelList?.find(channel => channel._id == channelId) || channelInput,
|
|
[channelId, channelList, channelInput]
|
|
);
|
|
|
|
if (deleted) return <></>;
|
|
|
|
return (
|
|
<Card className="my-2 flex">
|
|
<CardHeader className="flex-1">
|
|
<CardTitle className="flex items-center">
|
|
<span className="font-extralight mr-0.5 select-none">rvlt.gg/</span>{code}
|
|
<span className="select-none">{" "}</span> {/* looks better like this when for some reason the css doesnt load */}
|
|
{invite.vanity
|
|
? <span
|
|
className="select-none ml-2 p-1.5 bg-gray-400 text-white rounded-md font-normal text-base"
|
|
>
|
|
Vanity
|
|
</span>
|
|
: <></>}
|
|
</CardTitle>
|
|
<CardDescription>
|
|
{invite.type}
|
|
{" • "}
|
|
<Link href={`/panel/inspect/channel/${invite.channel}`}>
|
|
{(
|
|
channel &&
|
|
channel.channel_type != "DirectMessage" &&
|
|
channel.channel_type != "SavedMessages"
|
|
)
|
|
? `#${channel.name}`
|
|
: <i>Unknown Channel</i>}
|
|
</Link>
|
|
{" • "}
|
|
<Link href={`/panel/inspect/user/${invite.creator}`}>
|
|
{user ? `${user.username}#${user.discriminator}` : <i>Unknown Creator</i>}
|
|
</Link>
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="flex items-center py-0 gap-2">
|
|
{invite.vanity
|
|
? (
|
|
<AlertDialog>
|
|
<AlertDialogTrigger asChild>
|
|
<Button>Edit</Button>
|
|
</AlertDialogTrigger>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>
|
|
Edit vanity invite
|
|
</AlertDialogTitle>
|
|
</AlertDialogHeader>
|
|
<AlertDialogDescription>
|
|
<p className="mb-2">Invites are case sensitive.</p>
|
|
<div className="flex gap-2">
|
|
<Input
|
|
value={editDraft}
|
|
onChange={(e) => setEditDraft(e.currentTarget.value)}
|
|
placeholder={code}
|
|
/>
|
|
<ChannelDropdown
|
|
channels={channelList || []}
|
|
value={channelDraft}
|
|
setValue={setChannelDraft}
|
|
/>
|
|
</div>
|
|
</AlertDialogDescription>
|
|
<AlertDialogFooter>
|
|
<AlertDialogAction
|
|
disabled={!editDraft}
|
|
onClick={async () => {
|
|
try {
|
|
if (code != editDraft) await editInvite(code, editDraft);
|
|
if (channel?._id != channelDraft) await editInviteChannel(editDraft, channelDraft);
|
|
setCode(editDraft);
|
|
setEditDraft("");
|
|
setChannelId(channelDraft);
|
|
toast({ title: "Invite edited" });
|
|
} catch(e) {
|
|
toast({
|
|
title: "Failed to edit invite",
|
|
description: String(e),
|
|
variant: "destructive",
|
|
});
|
|
}
|
|
}}
|
|
>Edit</AlertDialogAction>
|
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
)
|
|
: <></>}
|
|
<AlertDialog>
|
|
<AlertDialogTrigger asChild>
|
|
<Button>Delete</Button>
|
|
</AlertDialogTrigger>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>
|
|
Delete invite
|
|
</AlertDialogTitle>
|
|
</AlertDialogHeader>
|
|
<AlertDialogDescription>
|
|
Are you sure you want to irreversibly delete this invite?
|
|
</AlertDialogDescription>
|
|
<AlertDialogFooter>
|
|
<AlertDialogAction
|
|
onClick={async () => {
|
|
try {
|
|
await deleteInvite(code);
|
|
setDeleted(true);
|
|
toast({ title: "Invite deleted" });
|
|
} catch(e) {
|
|
toast({
|
|
title: "Failed to delete invite",
|
|
description: String(e),
|
|
variant: "destructive",
|
|
});
|
|
}
|
|
}}
|
|
>Delete</AlertDialogAction>
|
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|