diff --git a/src/components/common/messaging/MessageBox.tsx b/src/components/common/messaging/MessageBox.tsx index 53cb1e77..0c7acc9d 100644 --- a/src/components/common/messaging/MessageBox.tsx +++ b/src/components/common/messaging/MessageBox.tsx @@ -24,7 +24,7 @@ import { import { useApplicationState } from "../../../mobx/State"; import { Reply } from "../../../mobx/stores/MessageQueue"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; +import { modalController } from "../../../context/modals"; import { FileUploader, grabFiles, @@ -148,7 +148,6 @@ export default observer(({ channel }: Props) => { }); const [typing, setTyping] = useState(false); const [replies, setReplies] = useState([]); - const { openScreen } = useIntermediate(); const client = useContext(AppContext); const translate = useTranslation(); @@ -473,7 +472,10 @@ export default observer(({ channel }: Props) => { files: [...uploadState.files, ...files], }), () => - openScreen({ id: "error", error: "FileTooLarge" }), + modalController.push({ + type: "error", + error: "FileTooLarge", + }), true, ) } diff --git a/src/context/intermediate/Modals.tsx b/src/context/intermediate/Modals.tsx index 55ecb6f8..8ff715c3 100644 --- a/src/context/intermediate/Modals.tsx +++ b/src/context/intermediate/Modals.tsx @@ -1,14 +1,10 @@ -import { internalEmit } from "../../lib/eventEmitter"; - //import { isModalClosing } from "../../components/ui/Modal"; import { Screen } from "./Intermediate"; import { ClipboardModal } from "./modals/Clipboard"; -import { ErrorModal } from "./modals/Error"; import { ExternalLinkModal } from "./modals/ExternalLinkPrompt"; import { InputModal } from "./modals/Input"; import { OnboardingModal } from "./modals/Onboarding"; import { PromptModal } from "./modals/Prompt"; -import { TokenRevealModal } from "./modals/TokenReveal"; export interface Props { screen: Screen; @@ -26,12 +22,8 @@ export default function Modals({ screen, openScreen }: Props) { return ; case "_input": return ; - case "error": - return ; case "clipboard": return ; - case "token_reveal": - return ; case "onboarding": return ; case "external_link_prompt": diff --git a/src/context/intermediate/modals/Error.tsx b/src/context/modals/components/Error.tsx similarity index 70% rename from src/context/intermediate/modals/Error.tsx rename to src/context/modals/components/Error.tsx index d9e2cd01..92e3f7c8 100644 --- a/src/context/intermediate/modals/Error.tsx +++ b/src/context/modals/components/Error.tsx @@ -2,23 +2,23 @@ import { Text } from "preact-i18n"; import { Modal } from "@revoltchat/ui"; -interface Props { - onClose: () => void; - error: string; -} +import { noopTrue } from "../../../lib/js"; -export function ErrorModal({ onClose, error }: Props) { +import { ModalProps } from "../types"; + +export function Error({ error, ...props }: ModalProps<"error">) { return ( } actions={[ { - onClick: onClose, + onClick: noopTrue, confirmation: true, children: , }, { + palette: "plain-secondary", onClick: () => location.reload(), children: , }, diff --git a/src/context/intermediate/modals/TokenReveal.tsx b/src/context/modals/components/ShowToken.tsx similarity index 65% rename from src/context/intermediate/modals/TokenReveal.tsx rename to src/context/modals/components/ShowToken.tsx index a671d322..92c7fac3 100644 --- a/src/context/intermediate/modals/TokenReveal.tsx +++ b/src/context/modals/components/ShowToken.tsx @@ -2,25 +2,23 @@ import { Text } from "preact-i18n"; import { Modal } from "@revoltchat/ui"; -interface Props { - onClose: () => void; - token: string; - username: string; -} +import { noopTrue } from "../../../lib/js"; -export function TokenRevealModal({ onClose, token, username }: Props) { +import { ModalProps } from "../types"; + +export function ShowToken({ name, token, ...props }: ModalProps<"show_token">) { return ( } actions={[ { - onClick: onClose, + onClick: noopTrue, confirmation: true, children: , }, diff --git a/src/context/modals/components/Test.tsx b/src/context/modals/components/Test.tsx deleted file mode 100644 index ed59a414..00000000 --- a/src/context/modals/components/Test.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { Modal } from "@revoltchat/ui"; - -import { ModalProps } from "../types"; - -export default function Test({ onClose }: ModalProps<"test">) { - return ; -} diff --git a/src/context/modals/index.tsx b/src/context/modals/index.tsx index df66918e..cd969190 100644 --- a/src/context/modals/index.tsx +++ b/src/context/modals/index.tsx @@ -9,13 +9,14 @@ import type { Client, API } from "revolt.js"; import { ulid } from "ulid"; import Changelog from "./components/Changelog"; +import { Error } from "./components/Error"; import MFAEnableTOTP from "./components/MFAEnableTOTP"; import MFAFlow from "./components/MFAFlow"; import MFARecovery from "./components/MFARecovery"; import OutOfDate from "./components/OutOfDate"; +import { ShowToken } from "./components/ShowToken"; import { SignOutSessions } from "./components/SignOutSessions"; import { SignedOut } from "./components/SignedOut"; -import Test from "./components/Test"; import { Modal } from "./types"; type Components = Record>; @@ -92,6 +93,9 @@ class ModalController { ); } + /** + * Whether a modal is currently visible + */ get isVisible() { return this.stack.length > 0; } @@ -140,11 +144,12 @@ class ModalControllerExtended extends ModalController { export const modalController = new ModalControllerExtended({ changelog: Changelog, + error: Error, mfa_flow: MFAFlow, mfa_recovery: MFARecovery, mfa_enable_totp: MFAEnableTOTP, out_of_date: OutOfDate, + show_token: ShowToken, signed_out: SignedOut, sign_out_sessions: SignOutSessions, - test: Test, }); diff --git a/src/context/modals/types.ts b/src/context/modals/types.ts index 24efb49c..6349c132 100644 --- a/src/context/modals/types.ts +++ b/src/context/modals/types.ts @@ -33,13 +33,22 @@ export type Modal = { initial?: number; } | { + type: "sign_out_sessions"; client: Client; onDelete: () => void; onDeleting: () => void; - type: "sign_out_sessions"; } | { - type: "test" | "signed_out"; + type: "show_token"; + name: string; + token: string; + } + | { + type: "error"; + error: string; + } + | { + type: "signed_out"; } ); diff --git a/src/context/revoltjs/FileUploads.tsx b/src/context/revoltjs/FileUploads.tsx index 4d8a9a0c..16ec2792 100644 --- a/src/context/revoltjs/FileUploads.tsx +++ b/src/context/revoltjs/FileUploads.tsx @@ -12,6 +12,7 @@ import { IconButton, Preloader } from "@revoltchat/ui"; import { determineFileSize } from "../../lib/fileSize"; import { useIntermediate } from "../intermediate/Intermediate"; +import { modalController } from "../modals"; import { AppContext } from "./RevoltClient"; import { takeError } from "./util"; @@ -139,12 +140,19 @@ export function FileUploader(props: Props) { ); } } catch (err) { - return openScreen({ id: "error", error: takeError(err) }); + return modalController.push({ + type: "error", + error: takeError(err), + }); } finally { setUploading(false); } }, - () => openScreen({ id: "error", error: "FileTooLarge" }), + () => + modalController.push({ + type: "error", + error: "FileTooLarge", + }), props.behaviour === "multi", ); } @@ -180,8 +188,8 @@ export function FileUploader(props: Props) { const blob = item.getAsFile(); if (blob) { if (blob.size > props.maxFileSize) { - openScreen({ - id: "error", + modalController.push({ + type: "error", error: "FileTooLarge", }); continue; @@ -212,7 +220,10 @@ export function FileUploader(props: Props) { const files = []; for (const item of dropped) { if (item.size > props.maxFileSize) { - openScreen({ id: "error", error: "FileTooLarge" }); + modalController.push({ + type: "error", + error: "FileTooLarge", + }); continue; } diff --git a/src/context/revoltjs/RevoltClient.tsx b/src/context/revoltjs/RevoltClient.tsx index c24915fc..733b1c9e 100644 --- a/src/context/revoltjs/RevoltClient.tsx +++ b/src/context/revoltjs/RevoltClient.tsx @@ -9,7 +9,6 @@ import { Preloader } from "@revoltchat/ui"; import { useApplicationState } from "../../mobx/State"; -import { useIntermediate } from "../intermediate/Intermediate"; import { modalController } from "../modals"; import { registerEvents } from "./events"; import { takeError } from "./util"; @@ -30,7 +29,7 @@ export interface ClientOperations { export const AppContext = createContext(null!); export const StatusContext = createContext(null!); -export const LogOutContext = createContext((avoidReq?: boolean) => {}); +export const LogOutContext = createContext<(avoidReq?: boolean) => void>(null!); type Props = { children: Children; @@ -38,7 +37,6 @@ type Props = { export default observer(({ children }: Props) => { const state = useApplicationState(); - const { openScreen } = useIntermediate(); const [client, setClient] = useState(null!); const [status, setStatus] = useState(ClientStatus.LOADING); const [loaded, setLoaded] = useState(false); @@ -72,7 +70,10 @@ export default observer(({ children }: Props) => { modalController.push({ type: "signed_out" }); } else { setStatus(ClientStatus.DISCONNECTED); - openScreen({ id: "error", error }); + modalController.push({ + type: "error", + error, + }); } }) .finally(() => setLoaded(true)); diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx index a88c0bc2..7ca44ae7 100644 --- a/src/lib/ContextMenus.tsx +++ b/src/lib/ContextMenus.tsx @@ -2,8 +2,15 @@ import { ChevronRight, Trash } from "@styled-icons/boxicons-regular"; import { Cog, UserVoice } from "@styled-icons/boxicons-solid"; import { isFirefox } from "react-device-detect"; import { useHistory } from "react-router-dom"; -import { Channel, Message, Server, User, API } from "revolt.js"; -import { Permission, UserPermission } from "revolt.js"; +import { + Channel, + Message, + Server, + User, + API, + Permission, + UserPermission, +} from "revolt.js"; import { ContextMenuWithData, @@ -20,6 +27,7 @@ import { QueuedMessage } from "../mobx/stores/MessageQueue"; import { NotificationState } from "../mobx/stores/NotificationOptions"; import { Screen, useIntermediate } from "../context/intermediate/Intermediate"; +import { modalController } from "../context/modals"; import { AppContext, ClientStatus, @@ -431,7 +439,10 @@ export default function ContextMenus() { break; } })().catch((err) => { - openScreen({ id: "error", error: takeError(err) }); + modalController.push({ + type: "error", + error: takeError(err), + }); }); } diff --git a/src/pages/Open.tsx b/src/pages/Open.tsx index 20f9b3fa..20e5265f 100644 --- a/src/pages/Open.tsx +++ b/src/pages/Open.tsx @@ -6,7 +6,7 @@ import { useContext, useEffect } from "preact/hooks"; import { Header } from "@revoltchat/ui"; -import { useIntermediate } from "../context/intermediate/Intermediate"; +import { modalController } from "../context/modals"; import { AppContext, ClientStatus, @@ -18,7 +18,6 @@ export default function Open() { const client = useContext(AppContext); const status = useContext(StatusContext); const { id } = useParams<{ id: string }>(); - const { openScreen } = useIntermediate(); if (status !== ClientStatus.ONLINE) { return ( @@ -40,7 +39,12 @@ export default function Open() { client .user!.openDM() .then((channel) => history.push(`/channel/${channel?._id}`)) - .catch((error) => openScreen({ id: "error", error })); + .catch((error) => + modalController.push({ + type: "error", + error, + }), + ); return; } @@ -62,7 +66,12 @@ export default function Open() { .get(id) ?.openDM() .then((channel) => history.push(`/channel/${channel?._id}`)) - .catch((error) => openScreen({ id: "error", error })); + .catch((error) => + modalController.push({ + type: "error", + error, + }), + ); } return; diff --git a/src/pages/settings/panes/MyBots.tsx b/src/pages/settings/panes/MyBots.tsx index c3a49d70..a71f5a04 100644 --- a/src/pages/settings/panes/MyBots.tsx +++ b/src/pages/settings/panes/MyBots.tsx @@ -25,6 +25,7 @@ import { useTranslation } from "../../../lib/i18n"; import { stopPropagation } from "../../../lib/stopPropagation"; import { useIntermediate } from "../../../context/intermediate/Intermediate"; +import { modalController } from "../../../context/modals"; import { FileUploader } from "../../../context/revoltjs/FileUploads"; import { useClient } from "../../../context/revoltjs/RevoltClient"; @@ -366,10 +367,10 @@ function BotCard({ bot, onDelete, onUpdate }: Props) { onClick={(ev) => stopPropagation( ev, - openScreen({ - id: "token_reveal", + modalController.push({ + type: "show_token", token: bot.token, - username: user!.username, + name: user!.username, }), ) }> diff --git a/src/pages/settings/panes/Notifications.tsx b/src/pages/settings/panes/Notifications.tsx index b8edac46..d934a63d 100644 --- a/src/pages/settings/panes/Notifications.tsx +++ b/src/pages/settings/panes/Notifications.tsx @@ -10,12 +10,11 @@ import { urlBase64ToUint8Array } from "../../../lib/conversion"; import { useApplicationState } from "../../../mobx/State"; -import { useIntermediate } from "../../../context/intermediate/Intermediate"; +import { modalController } from "../../../context/modals"; import { AppContext } from "../../../context/revoltjs/RevoltClient"; export const Notifications = observer(() => { const client = useContext(AppContext); - const { openScreen } = useIntermediate(); const settings = useApplicationState().settings; const [pushEnabled, setPushEnabled] = useState( undefined, @@ -52,8 +51,8 @@ export const Notifications = observer(() => { await Notification.requestPermission(); if (permission !== "granted") { - return openScreen({ - id: "error", + return modalController.push({ + type: "error", error: "DeniedNotification", }); }