import { useHistory } from "react-router-dom"; import { Channels, Servers, Users } from "revolt.js/dist/api/objects"; import { ulid } from "ulid"; import styles from "./Prompt.module.scss"; import { Text } from "preact-i18n"; import { useContext, useEffect, useState } from "preact/hooks"; import { TextReact } from "../../../lib/i18n"; import Message from "../../../components/common/messaging/Message"; import UserIcon from "../../../components/common/user/UserIcon"; import InputBox from "../../../components/ui/InputBox"; import Modal, { Action } from "../../../components/ui/Modal"; import Overline from "../../../components/ui/Overline"; import Radio from "../../../components/ui/Radio"; import { Children } from "../../../types/Preact"; import { AppContext } from "../../revoltjs/RevoltClient"; import { mapMessage, takeError } from "../../revoltjs/util"; import { useIntermediate } from "../Intermediate"; interface Props { onClose: () => void; question: Children; content?: Children; disabled?: boolean; actions: Action[]; error?: string; } export function PromptModal({ onClose, question, content, actions, disabled, error, }: Props) { return ( {error && } {content} ); } type SpecialProps = { onClose: () => void } & ( | { type: "leave_group"; target: Channels.GroupChannel } | { type: "close_dm"; target: Channels.DirectMessageChannel } | { type: "leave_server"; target: Servers.Server } | { type: "delete_server"; target: Servers.Server } | { type: "delete_channel"; target: Channels.TextChannel } | { type: "delete_message"; target: Channels.Message } | { type: "create_invite"; target: Channels.TextChannel | Channels.GroupChannel; } | { type: "kick_member"; target: Servers.Server; user: string } | { type: "ban_member"; target: Servers.Server; user: string } | { type: "unfriend_user"; target: Users.User } | { type: "block_user"; target: Users.User } | { type: "create_channel"; target: Servers.Server } ); export function SpecialPromptModal(props: SpecialProps) { const client = useContext(AppContext); const [processing, setProcessing] = useState(false); const [error, setError] = useState(undefined); const { onClose } = props; switch (props.type) { case "leave_group": case "close_dm": case "leave_server": case "delete_server": case "delete_channel": case "unfriend_user": case "block_user": { const EVENTS = { close_dm: ["confirm_close_dm", "close"], delete_server: ["confirm_delete", "delete"], delete_channel: ["confirm_delete", "delete"], leave_group: ["confirm_leave", "leave"], leave_server: ["confirm_leave", "leave"], unfriend_user: ["unfriend_user", "remove"], block_user: ["block_user", "block"], }; let event = EVENTS[props.type]; let name; switch (props.type) { case "unfriend_user": case "block_user": name = props.target.username; break; case "close_dm": name = client.users.get( client.channels.getRecipient(props.target._id), )?.username; break; default: name = props.target.name; } return ( } actions={[ { confirmation: true, contrast: true, error: true, children: ( ), onClick: async () => { setProcessing(true); try { switch (props.type) { case "unfriend_user": await client.users.removeFriend( props.target._id, ); break; case "block_user": await client.users.blockUser( props.target._id, ); break; case "leave_group": case "close_dm": case "delete_channel": await client.channels.delete( props.target._id, ); break; case "leave_server": case "delete_server": await client.servers.delete( props.target._id, ); break; } onClose(); } catch (err) { setError(takeError(err)); setProcessing(false); } }, }, { children: ( ), onClick: onClose, }, ]} content={ {name} }} /> } disabled={processing} error={error} /> ); } case "delete_message": { return ( } actions={[ { confirmation: true, contrast: true, error: true, children: ( ), onClick: async () => { setProcessing(true); try { await client.channels.deleteMessage( props.target.channel, props.target._id, ); onClose(); } catch (err) { setError(takeError(err)); setProcessing(false); } }, }, { children: ( ), onClick: onClose, plain: true, }, ]} content={ <> } disabled={processing} error={error} /> ); } case "create_invite": { const [code, setCode] = useState("abcdef"); const { writeClipboard } = useIntermediate(); useEffect(() => { setProcessing(true); client.channels .createInvite(props.target._id) .then((code) => setCode(code)) .catch((err) => setError(takeError(err))) .finally(() => setProcessing(false)); }, []); return ( } actions={[ { children: , confirmation: true, onClick: onClose, }, { children: , onClick: () => writeClipboard( `${window.location.protocol}//${window.location.host}/invite/${code}`, ), }, ]} content={ processing ? ( ) : (
{code}
) } disabled={processing} error={error} /> ); } case "kick_member": { const user = client.users.get(props.user); return ( } actions={[ { children: , contrast: true, error: true, confirmation: true, onClick: async () => { setProcessing(true); try { await client.servers.members.kickMember( props.target._id, props.user, ); onClose(); } catch (err) { setError(takeError(err)); setProcessing(false); } }, }, { children: ( ), onClick: onClose, }, ]} content={
} disabled={processing} error={error} /> ); } case "ban_member": { const [reason, setReason] = useState(undefined); const user = client.users.get(props.user); return ( } actions={[ { children: , contrast: true, error: true, confirmation: true, onClick: async () => { setProcessing(true); try { await client.servers.banUser( props.target._id, props.user, { reason }, ); onClose(); } catch (err) { setError(takeError(err)); setProcessing(false); } }, }, { children: ( ), onClick: onClose, }, ]} content={
setReason(e.currentTarget.value) } />
} disabled={processing} error={error} /> ); } case "create_channel": { const [name, setName] = useState(""); const [type, setType] = useState<"Text" | "Voice">("Text"); const history = useHistory(); return ( } actions={[ { confirmation: true, contrast: true, children: ( ), onClick: async () => { setProcessing(true); try { const channel = await client.servers.createChannel( props.target._id, { type, name, nonce: ulid(), }, ); history.push( `/server/${props.target._id}/channel/${channel._id}`, ); onClose(); } catch (err) { setError(takeError(err)); setProcessing(false); } }, }, { children: ( ), onClick: onClose, }, ]} content={ <> setType("Text")}> setType("Voice")}> setName(e.currentTarget.value)} /> } disabled={processing} error={error} /> ); } default: return null; } }