import { ulid } from "ulid"; import { Text } from "preact-i18n"; import styles from './Prompt.module.scss'; import { useHistory } from "react-router-dom"; import Radio from "../../../components/ui/Radio"; import { Children } from "../../../types/Preact"; import { useIntermediate } from "../Intermediate"; import InputBox from "../../../components/ui/InputBox"; import Overline from "../../../components/ui/Overline"; import { AppContext } from "../../revoltjs/RevoltClient"; import { mapMessage, takeError } from "../../revoltjs/util"; import Modal, { Action } from "../../../components/ui/Modal"; import { Channels, Servers, Users } from "revolt.js/dist/api/objects"; import { useContext, useEffect, useState } from "preact/hooks"; import UserIcon from "../../../components/common/user/UserIcon"; import Message from "../../../components/common/messaging/Message"; import { TextReact } from "../../../lib/i18n"; 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, text: , 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); } } }, { text: , onClick: onClose } ]} content={{ name } }} />} disabled={processing} error={error} /> ) } case 'delete_message': { return ( } actions={[ { confirmation: true, contrast: true, error: true, text: , onClick: async () => { setProcessing(true); try { await client.channels.deleteMessage(props.target.channel, props.target._id); onClose(); } catch (err) { setError(takeError(err)); setProcessing(false); } } }, { text: , onClick: onClose } ]} 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={[ { text: , confirmation: true, onClick: onClose }, { text: , 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={[ { text: , 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); } } }, { text: , onClick: onClose } ]} content={
} disabled={processing} error={error} /> ) } case "ban_member": { const [ reason, setReason ] = useState(undefined); const user = client.users.get(props.user); return ( } actions={[ { text: , 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); } } }, { text: , 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, text: , 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); } } }, { text: , onClick: onClose } ]} content={<> setType('Text')}> setType('Voice')}> setName(e.currentTarget.value)} /> } disabled={processing} error={error} /> ) } default: return null; } }