From f8b8d96d3d34a7e13b0c8f62c09c01f54d247daa Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 11 Dec 2021 21:04:12 +0000 Subject: [PATCH] feat(mobx): migrate auth and config --- index.html | 10 +- package.json | 7 +- .../navigation/left/ServerListSidebar.tsx | 4 +- src/context/Locale.tsx | 1 - src/context/revoltjs/CheckAuth.tsx | 12 +- src/context/revoltjs/RevoltClient.tsx | 182 ++++-------------- src/context/revoltjs/SyncManager.tsx | 8 +- src/context/revoltjs/events.ts | 37 ++-- src/lib/ContextMenus.tsx | 58 +++--- src/mobx/State.ts | 23 ++- src/mobx/stores/Auth.ts | 61 ++++-- src/mobx/stores/ServerConfig.ts | 75 ++++++++ src/pages/login/Login.tsx | 14 +- src/pages/login/forms/CaptchaBlock.tsx | 19 +- src/pages/login/forms/Form.tsx | 28 ++- src/pages/login/forms/FormCreate.tsx | 7 +- src/pages/login/forms/FormLogin.tsx | 47 ++++- src/pages/login/forms/FormReset.tsx | 5 +- src/pages/login/forms/FormVerify.tsx | 5 +- src/pages/login/forms/MailProvider.tsx | 1 - src/pages/settings/Settings.tsx | 9 +- yarn.lock | 8 +- 22 files changed, 342 insertions(+), 279 deletions(-) create mode 100644 src/mobx/stores/ServerConfig.ts diff --git a/index.html b/index.html index 26041f77..ec592bdd 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,13 @@ - + + + Revolt + - diff --git a/package.json b/package.json index 76746ba4..6f14588c 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,10 @@ "FunctionExpression": false }, "ignore": { - "MethodDefinition": ["toJSON", "hydrate"] + "MethodDefinition": [ + "toJSON", + "hydrate" + ] } } ] @@ -140,7 +143,7 @@ "react-virtuoso": "^1.10.4", "redux": "^4.1.0", "revolt-api": "0.5.3-alpha.10", - "revolt.js": "^5.1.0-alpha.10", + "revolt.js": "5.1.0-alpha.15", "rimraf": "^3.0.2", "sass": "^1.35.1", "shade-blend-color": "^1.0.0", diff --git a/src/components/navigation/left/ServerListSidebar.tsx b/src/components/navigation/left/ServerListSidebar.tsx index 4385755d..ed9042f0 100644 --- a/src/components/navigation/left/ServerListSidebar.tsx +++ b/src/components/navigation/left/ServerListSidebar.tsx @@ -276,13 +276,13 @@ export const ServerListSidebar = observer(({ unreads }: Props) => { onClick={() => homeActive && history.push("/settings") }> - + { - const operations = useContext(OperationsContext); + const auth = useApplicationState().auth; + const client = useClient(); + const ready = auth.isLoggedIn() && typeof client?.user !== "undefined"; - if (props.auth && !operations.ready()) { + if (props.auth && !ready) { return ; - } else if (!props.auth && operations.ready()) { + } else if (!props.auth && ready) { return ; } diff --git a/src/context/revoltjs/RevoltClient.tsx b/src/context/revoltjs/RevoltClient.tsx index 4708d966..9124885b 100644 --- a/src/context/revoltjs/RevoltClient.tsx +++ b/src/context/revoltjs/RevoltClient.tsx @@ -1,26 +1,22 @@ /* eslint-disable react-hooks/rules-of-hooks */ -import { Session } from "revolt-api/types/Auth"; +import { observer } from "mobx-react-lite"; import { Client } from "revolt.js"; -import { Route } from "revolt.js/dist/api/routes"; import { createContext } from "preact"; import { useContext, useEffect, useMemo, useState } from "preact/hooks"; -import { dispatch } from "../../redux"; -import { connectState } from "../../redux/connector"; -import { AuthState } from "../../redux/reducers/auth"; +import { useApplicationState } from "../../mobx/State"; import Preloader from "../../components/ui/Preloader"; import { Children } from "../../types/Preact"; import { useIntermediate } from "../intermediate/Intermediate"; -import { registerEvents, setReconnectDisallowed } from "./events"; +import { registerEvents } from "./events"; import { takeError } from "./util"; export enum ClientStatus { - INIT, - LOADING, READY, + LOADING, OFFLINE, DISCONNECTED, CONNECTING, @@ -29,179 +25,75 @@ export enum ClientStatus { } export interface ClientOperations { - login: ( - data: Route<"POST", "/auth/session/login">["data"], - ) => Promise; logout: (shouldRequest?: boolean) => Promise; - loggedIn: () => boolean; - ready: () => boolean; } -// By the time they are used, they should all be initialized. -// Currently the app does not render until a client is built and the other two are always initialized on first render. -// - insert's words export const AppContext = createContext(null!); export const StatusContext = createContext(null!); export const OperationsContext = createContext(null!); +export const LogOutContext = createContext(() => {}); type Props = { - auth: AuthState; children: Children; }; -function Context({ auth, children }: Props) { +export default observer(({ children }: Props) => { + const state = useApplicationState(); const { openScreen } = useIntermediate(); - const [status, setStatus] = useState(ClientStatus.INIT); - const [client, setClient] = useState( - undefined as unknown as Client, - ); + const [client, setClient] = useState(null!); + const [status, setStatus] = useState(ClientStatus.LOADING); + const [loaded, setLoaded] = useState(false); + + function logout() { + setLoaded(false); + client.logout(false); + } useEffect(() => { - (async () => { - const client = new Client({ - autoReconnect: false, - apiURL: import.meta.env.VITE_API_URL, - debug: import.meta.env.DEV, - }); - - setClient(client); - setStatus(ClientStatus.LOADING); - })(); + if (navigator.onLine) { + new Client().req("GET", "/").then(state.config.set); + } }, []); - if (status === ClientStatus.INIT) return null; - - const operations: ClientOperations = useMemo(() => { - return { - login: async (data) => { - setReconnectDisallowed(true); - - try { - const onboarding = await client.login(data); - setReconnectDisallowed(false); - const login = () => - dispatch({ - type: "LOGIN", - session: client.session as Session, - }); - - if (onboarding) { - openScreen({ - id: "onboarding", - callback: async (username: string) => - onboarding(username, true).then(login), - }); - } else { - login(); - } - } catch (err) { - setReconnectDisallowed(false); - throw err; - } - }, - logout: async (shouldRequest) => { - dispatch({ type: "LOGOUT" }); - - client.reset(); - dispatch({ type: "RESET" }); - - openScreen({ id: "none" }); - setStatus(ClientStatus.READY); - - client.websocket.disconnect(); - - if (shouldRequest) { - try { - await client.logout(); - } catch (err) { - console.error(err); - } - } - }, - loggedIn: () => typeof auth.active !== "undefined", - ready: () => - operations.loggedIn() && typeof client.user !== "undefined", - }; - }, [client, auth.active, openScreen]); - - useEffect( - () => registerEvents({ operations }, setStatus, client), - [client, operations], - ); - useEffect(() => { - (async () => { - if (auth.active) { - dispatch({ type: "QUEUE_FAIL_ALL" }); + if (state.auth.isLoggedIn()) { + const client = state.config.createClient(); + setClient(client); - const active = auth.accounts[auth.active]; - client.user = client.users.get(active.session.user_id); - if (!navigator.onLine) { - return setStatus(ClientStatus.OFFLINE); - } - - if (operations.ready()) setStatus(ClientStatus.CONNECTING); - - if (navigator.onLine) { - await client - .fetchConfiguration() - .catch(() => - console.error("Failed to connect to API server."), - ); - } - - try { - await client.fetchConfiguration(); - const callback = await client.useExistingSession( - active.session, - ); - - if (callback) { - openScreen({ id: "onboarding", callback }); - } - } catch (err) { - setStatus(ClientStatus.DISCONNECTED); + client + .useExistingSession(state.auth.getSession()!) + .then(() => setLoaded(true)) + .catch((err) => { const error = takeError(err); if (error === "Forbidden" || error === "Unauthorized") { - operations.logout(true); + client.logout(true); openScreen({ id: "signed_out" }); } else { + setStatus(ClientStatus.DISCONNECTED); openScreen({ id: "error", error }); } - } - } else { - try { - await client.fetchConfiguration(); - } catch (err) { - console.error("Failed to connect to API server."); - } + }); + } else { + setStatus(ClientStatus.READY); + setLoaded(true); + } + }, [state.auth.getSession()]); - setStatus(ClientStatus.READY); - } - })(); - // eslint-disable-next-line - }, []); + useEffect(() => registerEvents(state.auth, setStatus, client), [client]); - if (status === ClientStatus.LOADING) { + if (!loaded || status === ClientStatus.LOADING) { return ; } return ( - + {children} - + ); -} - -export default connectState<{ children: Children }>(Context, (state) => { - return { - auth: state.auth, - sync: state.sync, - }; }); export const useClient = () => useContext(AppContext); diff --git a/src/context/revoltjs/SyncManager.tsx b/src/context/revoltjs/SyncManager.tsx index 1ab81d74..f4af77e0 100644 --- a/src/context/revoltjs/SyncManager.tsx +++ b/src/context/revoltjs/SyncManager.tsx @@ -21,7 +21,7 @@ import { import { Language } from "../Locale"; import { AppContext, ClientStatus, StatusContext } from "./RevoltClient"; -type Props = { +/*type Props = { settings: Settings; locale: Language; sync: SyncOptions; @@ -150,4 +150,8 @@ export default connectState(SyncManager, (state) => { sync: state.sync, notifications: state.notifications, }; -}); +});*/ + +function SyncManager() { + return <>; +} diff --git a/src/context/revoltjs/events.ts b/src/context/revoltjs/events.ts index 9823b491..2556e76f 100644 --- a/src/context/revoltjs/events.ts +++ b/src/context/revoltjs/events.ts @@ -4,9 +4,10 @@ import { ClientboundNotification } from "revolt.js/dist/websocket/notifications" import { StateUpdater } from "preact/hooks"; +import Auth from "../../mobx/stores/Auth"; import { dispatch } from "../../redux"; -import { ClientOperations, ClientStatus } from "./RevoltClient"; +import { ClientStatus } from "./RevoltClient"; export let preventReconnect = false; let preventUntil = 0; @@ -16,10 +17,12 @@ export function setReconnectDisallowed(allowed: boolean) { } export function registerEvents( - { operations }: { operations: ClientOperations }, + auth: Auth, setStatus: StateUpdater, client: Client, ) { + if (!client) return; + function attemptReconnect() { if (preventReconnect) return; function reconnect() { @@ -36,14 +39,11 @@ export function registerEvents( // eslint-disable-next-line @typescript-eslint/no-explicit-any let listeners: Record void> = { - connecting: () => - operations.ready() && setStatus(ClientStatus.CONNECTING), + connecting: () => setStatus(ClientStatus.CONNECTING), dropped: () => { - if (operations.ready()) { - setStatus(ClientStatus.DISCONNECTED); - attemptReconnect(); - } + setStatus(ClientStatus.DISCONNECTED); + attemptReconnect(); }, packet: (packet: ClientboundNotification) => { @@ -70,6 +70,11 @@ export function registerEvents( }, ready: () => setStatus(ClientStatus.ONLINE), + + logout: () => { + auth.logout(); + setStatus(ClientStatus.READY); + }, }; if (import.meta.env.DEV) { @@ -89,19 +94,15 @@ export function registerEvents( } const online = () => { - if (operations.ready()) { - setStatus(ClientStatus.RECONNECTING); - setReconnectDisallowed(false); - attemptReconnect(); - } + setStatus(ClientStatus.RECONNECTING); + setReconnectDisallowed(false); + attemptReconnect(); }; const offline = () => { - if (operations.ready()) { - setReconnectDisallowed(true); - client.websocket.disconnect(); - setStatus(ClientStatus.OFFLINE); - } + setReconnectDisallowed(true); + client.websocket.disconnect(); + setStatus(ClientStatus.OFFLINE); }; window.addEventListener("online", online); diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx index cb42b013..6a93bde1 100644 --- a/src/lib/ContextMenus.tsx +++ b/src/lib/ContextMenus.tsx @@ -105,14 +105,14 @@ type Action = | { action: "create_channel"; target: Server } | { action: "create_category"; target: Server } | { - action: "create_invite"; - target: Channel; - } + action: "create_invite"; + target: Channel; + } | { action: "leave_group"; target: Channel } | { - action: "delete_channel"; - target: Channel; - } + action: "delete_channel"; + target: Channel; + } | { action: "close_dm"; target: Channel } | { action: "leave_server"; target: Server } | { action: "delete_server"; target: Server } @@ -123,10 +123,10 @@ type Action = | { action: "open_server_settings"; id: string } | { action: "open_server_channel_settings"; server: string; id: string } | { - action: "set_notification_state"; - key: string; - state?: NotificationState; - }; + action: "set_notification_state"; + key: string; + state?: NotificationState; + }; type Props = { notifications: Notifications; @@ -488,8 +488,9 @@ function ContextMenus(props: Props) { elements.push( {tip &&
{tip}
}
, @@ -545,8 +546,8 @@ function ContextMenus(props: Props) { const user = uid ? client.users.get(uid) : undefined; const serverChannel = targetChannel && - (targetChannel.channel_type === "TextChannel" || - targetChannel.channel_type === "VoiceChannel") + (targetChannel.channel_type === "TextChannel" || + targetChannel.channel_type === "VoiceChannel") ? targetChannel : undefined; @@ -558,8 +559,8 @@ function ContextMenus(props: Props) { (server ? server.permission : serverChannel - ? serverChannel.server?.permission - : 0) || 0; + ? serverChannel.server?.permission + : 0) || 0; const userPermissions = (user ? user.permission : 0) || 0; if (unread) { @@ -705,7 +706,8 @@ function ContextMenus(props: Props) { if (message && !queued) { const sendPermission = message.channel && - message.channel.permission & ChannelPermission.SendMessage + message.channel.permission & + ChannelPermission.SendMessage; if (sendPermission) { generateAction({ @@ -741,7 +743,7 @@ function ContextMenus(props: Props) { if ( message.author_id === userId || channelPermissions & - ChannelPermission.ManageMessages + ChannelPermission.ManageMessages ) { generateAction({ action: "delete_message", @@ -765,8 +767,8 @@ function ContextMenus(props: Props) { type === "Image" ? "open_image" : type === "Video" - ? "open_video" - : "open_file", + ? "open_video" + : "open_file", ); generateAction( @@ -777,8 +779,8 @@ function ContextMenus(props: Props) { type === "Image" ? "save_image" : type === "Video" - ? "save_video" - : "save_file", + ? "save_video" + : "save_file", ); generateAction( @@ -930,9 +932,9 @@ function ContextMenus(props: Props) { if ( serverPermissions & - ServerPermission.ChangeNickname || + ServerPermission.ChangeNickname || serverPermissions & - ServerPermission.ChangeAvatar + ServerPermission.ChangeAvatar ) generateAction( { action: "edit_identity", target: server }, @@ -976,10 +978,10 @@ function ContextMenus(props: Props) { sid ? "copy_sid" : cid - ? "copy_cid" - : message - ? "copy_mid" - : "copy_uid", + ? "copy_cid" + : message + ? "copy_mid" + : "copy_uid", ); } diff --git a/src/mobx/State.ts b/src/mobx/State.ts index 006cae11..c4d808ed 100644 --- a/src/mobx/State.ts +++ b/src/mobx/State.ts @@ -10,6 +10,7 @@ import Draft from "./stores/Draft"; import Experiments from "./stores/Experiments"; import Layout from "./stores/Layout"; import LocaleOptions from "./stores/LocaleOptions"; +import ServerConfig from "./stores/ServerConfig"; /** * Handles global application state. @@ -20,6 +21,7 @@ export default class State { locale: LocaleOptions; experiments: Experiments; layout: Layout; + config: ServerConfig; private persistent: [string, Persistent][] = []; @@ -32,12 +34,16 @@ export default class State { this.locale = new LocaleOptions(); this.experiments = new Experiments(); this.layout = new Layout(); + this.config = new ServerConfig(); makeAutoObservable(this); this.registerListeners = this.registerListeners.bind(this); this.register(); } + /** + * Categorise and register stores referenced on this object. + */ private register() { for (const key of Object.keys(this)) { const obj = ( @@ -65,12 +71,22 @@ export default class State { } } + /** + * Register reaction listeners for persistent data stores. + * @returns Function to dispose of listeners + */ registerListeners() { const listeners = this.persistent.map(([id, store]) => { return reaction( () => store.toJSON(), - (value) => { - localforage.setItem(id, value); + async (value) => { + try { + await localforage.setItem(id, value); + } catch (err) { + console.error("Failed to serialise!"); + console.error(err); + console.error(value); + } }, ); }); @@ -78,6 +94,9 @@ export default class State { return () => listeners.forEach((x) => x()); } + /** + * Load data stores from local storage. + */ async hydrate() { for (const [id, store] of this.persistent) { const data = await localforage.getItem(id); diff --git a/src/mobx/stores/Auth.ts b/src/mobx/stores/Auth.ts index 9cea243e..042484bc 100644 --- a/src/mobx/stores/Auth.ts +++ b/src/mobx/stores/Auth.ts @@ -1,12 +1,18 @@ -import { makeAutoObservable, ObservableMap } from "mobx"; +import { action, computed, makeAutoObservable, ObservableMap } from "mobx"; import { Session } from "revolt-api/types/Auth"; import { Nullable } from "revolt.js/dist/util/null"; +import { mapToRecord } from "../../lib/conversion"; + import Persistent from "../interfaces/Persistent"; import Store from "../interfaces/Store"; +interface Account { + session: Session; +} + interface Data { - sessions: Record; + sessions: Record | [string, Account][]; current?: string; } @@ -15,7 +21,7 @@ interface Data { * accounts and their sessions. */ export default class Auth implements Store, Persistent { - private sessions: ObservableMap; + private sessions: ObservableMap; private current: Nullable; /** @@ -31,17 +37,27 @@ export default class Auth implements Store, Persistent { return "auth"; } - toJSON() { + @action toJSON() { return { - sessions: [...this.sessions], + sessions: JSON.parse(JSON.stringify(this.sessions)), current: this.current ?? undefined, }; } - hydrate(data: Data) { - Object.keys(data.sessions).forEach((id) => - this.sessions.set(id, data.sessions[id]), - ); + @action hydrate(data: Data) { + if (Array.isArray(data.sessions)) { + data.sessions.forEach(([key, value]) => + this.sessions.set(key, value), + ); + } else if ( + typeof data.sessions === "object" && + data.sessions !== null + ) { + let v = data.sessions; + Object.keys(data.sessions).forEach((id) => + this.sessions.set(id, v[id]), + ); + } if (data.current && this.sessions.has(data.current)) { this.current = data.current; @@ -52,8 +68,8 @@ export default class Auth implements Store, Persistent { * Add a new session to the auth manager. * @param session Session */ - setSession(session: Session) { - this.sessions.set(session.user_id, session); + @action setSession(session: Session) { + this.sessions.set(session.user_id, { session }); this.current = session.user_id; } @@ -61,11 +77,28 @@ export default class Auth implements Store, Persistent { * Remove existing session by user ID. * @param user_id User ID tied to session */ - removeSession(user_id: string) { - this.sessions.delete(user_id); - + @action removeSession(user_id: string) { if (user_id == this.current) { this.current = null; } + + this.sessions.delete(user_id); + } + + @action logout() { + this.current && this.removeSession(this.current); + } + + @computed getSession() { + if (!this.current) return; + return this.sessions.get(this.current)!.session; + } + + /** + * Check whether we are currently logged in. + * @returns Whether we are logged in + */ + @computed isLoggedIn() { + return this.current !== null; } } diff --git a/src/mobx/stores/ServerConfig.ts b/src/mobx/stores/ServerConfig.ts new file mode 100644 index 00000000..1b1d0498 --- /dev/null +++ b/src/mobx/stores/ServerConfig.ts @@ -0,0 +1,75 @@ +import { action, computed, makeAutoObservable } from "mobx"; +import { RevoltConfiguration } from "revolt-api/types/Core"; +import { Client } from "revolt.js"; +import { Nullable } from "revolt.js/dist/util/null"; + +import Persistent from "../interfaces/Persistent"; +import Store from "../interfaces/Store"; + +interface Data { + config?: RevoltConfiguration; +} + +/** + * Stores server configuration data. + */ +export default class ServerConfig + implements Store, Persistent +{ + private config: Nullable; + + /** + * Construct new ServerConfig store. + */ + constructor() { + this.config = null; + makeAutoObservable(this); + this.set = this.set.bind(this); + } + + get id() { + return "server_conf"; + } + + toJSON() { + return JSON.parse(JSON.stringify(this.config)); + } + + @action hydrate(data: RevoltConfiguration) { + this.config = data; + } + + /** + * Create a new Revolt client. + * @returns Revolt client + */ + createClient() { + const client = new Client({ + autoReconnect: false, + apiURL: import.meta.env.VITE_API_URL, + debug: import.meta.env.DEV, + }); + + if (this.config !== null) { + client.configuration = this.config; + } + + return client; + } + + /** + * Get server configuration. + * @returns Server configuration + */ + @computed get() { + return this.config; + } + + /** + * Set server configuration. + * @param config Server configuration + */ + @action set(config: RevoltConfiguration) { + this.config = config; + } +} diff --git a/src/pages/login/Login.tsx b/src/pages/login/Login.tsx index 9b38d13a..9633eb48 100644 --- a/src/pages/login/Login.tsx +++ b/src/pages/login/Login.tsx @@ -1,3 +1,4 @@ +import { observer } from "mobx-react-lite"; import { Helmet } from "react-helmet"; import { Route, Switch } from "react-router-dom"; import { LIBRARY_VERSION } from "revolt.js"; @@ -6,22 +7,24 @@ import styles from "./Login.module.scss"; import { Text } from "preact-i18n"; import { useContext } from "preact/hooks"; +import { useApplicationState } from "../../mobx/State"; + import { ThemeContext } from "../../context/Theme"; import { AppContext } from "../../context/revoltjs/RevoltClient"; import LocaleSelector from "../../components/common/LocaleSelector"; +import background from "./background.jpg"; import { Titlebar } from "../../components/native/Titlebar"; import { APP_VERSION } from "../../version"; -import background from "./background.jpg"; import { FormCreate } from "./forms/FormCreate"; import { FormLogin } from "./forms/FormLogin"; import { FormReset, FormSendReset } from "./forms/FormReset"; import { FormResend, FormVerify } from "./forms/FormVerify"; -export default function Login() { +export default observer(() => { const theme = useContext(ThemeContext); - const client = useContext(AppContext); + const configuration = useApplicationState().config.get(); return ( <> @@ -35,8 +38,7 @@ export default function Login() {
- API:{" "} - {client.configuration?.revolt ?? "???"}{" "} + API: {configuration?.revolt ?? "???"}{" "} · revolt.js: {LIBRARY_VERSION}{" "} · App: {APP_VERSION} @@ -80,4 +82,4 @@ export default function Login() {
); -} +}); diff --git a/src/pages/login/forms/CaptchaBlock.tsx b/src/pages/login/forms/CaptchaBlock.tsx index 51548c6b..09addd16 100644 --- a/src/pages/login/forms/CaptchaBlock.tsx +++ b/src/pages/login/forms/CaptchaBlock.tsx @@ -1,10 +1,11 @@ import HCaptcha from "@hcaptcha/react-hcaptcha"; +import { observer } from "mobx-react-lite"; import styles from "../Login.module.scss"; import { Text } from "preact-i18n"; -import { useContext, useEffect } from "preact/hooks"; +import { useEffect } from "preact/hooks"; -import { AppContext } from "../../../context/revoltjs/RevoltClient"; +import { useApplicationState } from "../../../mobx/State"; import Preloader from "../../../components/ui/Preloader"; @@ -13,22 +14,22 @@ export interface CaptchaProps { onCancel: () => void; } -export function CaptchaBlock(props: CaptchaProps) { - const client = useContext(AppContext); +export const CaptchaBlock = observer((props: CaptchaProps) => { + const configuration = useApplicationState().config.get(); useEffect(() => { - if (!client.configuration?.features.captcha.enabled) { + if (!configuration?.features.captcha.enabled) { props.onSuccess(); } - }, [client.configuration?.features.captcha.enabled, props]); + }, [configuration?.features.captcha.enabled, props]); - if (!client.configuration?.features.captcha.enabled) + if (!configuration?.features.captcha.enabled) return ; return (
props.onSuccess(token)} />
@@ -38,4 +39,4 @@ export function CaptchaBlock(props: CaptchaProps) {
); -} +}); diff --git a/src/pages/login/forms/Form.tsx b/src/pages/login/forms/Form.tsx index b11dbe91..35a6e14e 100644 --- a/src/pages/login/forms/Form.tsx +++ b/src/pages/login/forms/Form.tsx @@ -6,6 +6,8 @@ import styles from "../Login.module.scss"; import { Text } from "preact-i18n"; import { useContext, useState } from "preact/hooks"; +import { useApplicationState } from "../../../mobx/State"; + import { AppContext } from "../../../context/revoltjs/RevoltClient"; import { takeError } from "../../../context/revoltjs/util"; @@ -44,7 +46,7 @@ interface FormInputs { } export function Form({ page, callback }: Props) { - const client = useContext(AppContext); + const configuration = useApplicationState().config.get(); const [loading, setLoading] = useState(false); const [success, setSuccess] = useState(undefined); @@ -80,10 +82,7 @@ export function Form({ page, callback }: Props) { } try { - if ( - client.configuration?.features.captcha.enabled && - page !== "reset" - ) { + if (configuration?.features.captcha.enabled && page !== "reset") { setCaptcha({ onSuccess: async (captcha) => { setCaptcha(undefined); @@ -111,7 +110,7 @@ export function Form({ page, callback }: Props) { if (typeof success !== "undefined") { return (
- {client.configuration?.features.email ? ( + {configuration?.features.email ? ( <>

@@ -172,15 +171,14 @@ export function Form({ page, callback }: Props) { error={errors.password?.message} /> )} - {client.configuration?.features.invite_only && - page === "create" && ( - - )} + {configuration?.features.invite_only && page === "create" && ( + + )} {error && ( diff --git a/src/pages/login/forms/FormCreate.tsx b/src/pages/login/forms/FormCreate.tsx index 677aeba3..8d2e9ed7 100644 --- a/src/pages/login/forms/FormCreate.tsx +++ b/src/pages/login/forms/FormCreate.tsx @@ -1,10 +1,9 @@ -import { useContext } from "preact/hooks"; - -import { AppContext } from "../../../context/revoltjs/RevoltClient"; +import { useApplicationState } from "../../../mobx/State"; import { Form } from "./Form"; export function FormCreate() { - const client = useContext(AppContext); + const config = useApplicationState().config; + const client = config.createClient(); return
client.register(data)} />; } diff --git a/src/pages/login/forms/FormLogin.tsx b/src/pages/login/forms/FormLogin.tsx index 2eb3bbf5..d196ead7 100644 --- a/src/pages/login/forms/FormLogin.tsx +++ b/src/pages/login/forms/FormLogin.tsx @@ -1,15 +1,16 @@ import { detect } from "detect-browser"; -import { useHistory } from "react-router-dom"; +import { Session } from "revolt-api/types/Auth"; +import { Client } from "revolt.js"; -import { useContext } from "preact/hooks"; +import { useApplicationState } from "../../../mobx/State"; -import { OperationsContext } from "../../../context/revoltjs/RevoltClient"; +import { useIntermediate } from "../../../context/intermediate/Intermediate"; import { Form } from "./Form"; export function FormLogin() { - const { login } = useContext(OperationsContext); - const history = useHistory(); + const auth = useApplicationState().auth; + const { openScreen } = useIntermediate(); return ( + client + .completeOnboarding({ username }, false) + .then(login), + }); + } else { + login(); + } }} /> ); diff --git a/src/pages/login/forms/FormReset.tsx b/src/pages/login/forms/FormReset.tsx index 78b4a14a..fbce0e09 100644 --- a/src/pages/login/forms/FormReset.tsx +++ b/src/pages/login/forms/FormReset.tsx @@ -2,12 +2,15 @@ import { useHistory, useParams } from "react-router-dom"; import { useContext } from "preact/hooks"; +import { useApplicationState } from "../../../mobx/State"; + import { AppContext } from "../../../context/revoltjs/RevoltClient"; import { Form } from "./Form"; export function FormSendReset() { - const client = useContext(AppContext); + const config = useApplicationState().config; + const client = config.createClient(); return ( { const history = useHistory(); const client = useContext(AppContext); - const operations = useContext(OperationsContext); + const logout = useContext(LogOutContext); const experiments = useApplicationState().experiments; function switchPage(to?: string) { @@ -220,7 +217,7 @@ export default observer(() => { operations.logout()} + onClick={logout} className={styles.logOut} compact> diff --git a/yarn.lock b/yarn.lock index 52f2a349..a538d37b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3765,10 +3765,10 @@ revolt-api@^0.5.3-alpha.9: resolved "https://registry.yarnpkg.com/revolt-api/-/revolt-api-0.5.3-alpha.9.tgz#46e75b7d8f9c6702df39039b829dddbb7897f237" integrity sha512-L8K9uPV3ME8bLdtWm8L9iPQvFM0GghA+5LzmWFjd6Gbn56u22ZYub2lABi4iHrWgeA2X41dGSsuSBgHSlts9Og== -revolt.js@^5.1.0-alpha.10: - version "5.1.0-alpha.10" - resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-5.1.0-alpha.10.tgz#e393ac8524e629d3359135651b23b044c0cc9b7b" - integrity sha512-wEmBMJkZE/oWy6mzVZg1qw5QC9CE+Gb7sTFlJl+C4pbXfTJWAtY311Tjbd2tX8w3ohYDmN338bVfCW4cOQ8GXQ== +revolt.js@5.1.0-alpha.15: + version "5.1.0-alpha.15" + resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-5.1.0-alpha.15.tgz#a2be1f29de93f1ec18f0e502ecb65ade55c0070d" + integrity sha512-1gGcGDv1+J5NlmnX099XafKugCebACg9ke0NA754I4hLTNMMwkZyphyvYWWWkI394qn2mA3NG7WgEmrIoZUtgw== dependencies: axios "^0.21.4" eventemitter3 "^4.0.7"