chore: refactor account UI

This commit is contained in:
Paul Makles
2022-06-12 15:07:30 +01:00
parent 8103cc03cf
commit 645e1af6db
7 changed files with 145 additions and 207 deletions

View File

@@ -4,12 +4,7 @@ import { ContextMenuTrigger } from "preact-context-menu";
import { Text } from "preact-i18n";
import { useEffect, useState } from "preact/hooks";
import {
LinkProvider,
Preloader,
TextProvider,
TrigProvider,
} from "@revoltchat/ui";
import { Preloader, UIProvider } from "@revoltchat/ui";
import { hydrateState } from "../mobx/State";
@@ -20,6 +15,13 @@ import ModalRenderer from "./modals/ModalRenderer";
import Client from "./revoltjs/RevoltClient";
import SyncManager from "./revoltjs/SyncManager";
const uiContext = {
Link,
Text: Text as any,
Trigger: ContextMenuTrigger,
emitAction: () => {},
};
/**
* This component provides all of the application's context layers.
* @param param0 Provided children
@@ -35,21 +37,17 @@ export default function Context({ children }: { children: Children }) {
return (
<Router basename={import.meta.env.BASE_URL}>
<LinkProvider value={Link}>
<TextProvider value={Text as any}>
<TrigProvider value={ContextMenuTrigger}>
<Locale>
<Intermediate>
<Client>
{children}
<SyncManager />
</Client>
</Intermediate>
<ModalRenderer />
</Locale>
</TrigProvider>
</TextProvider>
</LinkProvider>
<UIProvider value={uiContext}>
<Locale>
<Intermediate>
<Client>
{children}
<SyncManager />
</Client>
</Intermediate>
<ModalRenderer />
</Locale>
</UIProvider>
<Theme />
</Router>
);

View File

@@ -3,7 +3,12 @@ import { Key, Keyboard } from "@styled-icons/boxicons-solid";
import { API } from "revolt.js";
import { Text } from "preact-i18n";
import { useCallback, useEffect, useState } from "preact/hooks";
import {
useCallback,
useEffect,
useLayoutEffect,
useState,
} from "preact/hooks";
import {
Category,
@@ -15,8 +20,6 @@ import {
import { noopTrue } from "../../../lib/js";
import { useApplicationState } from "../../../mobx/State";
import { ModalProps } from "../types";
const ICONS: Record<API.MFAMethod, React.FC<any>> = {
@@ -34,12 +37,13 @@ function ResponseEntry({
value?: API.MFAResponse;
onChange: (v: API.MFAResponse) => void;
}) {
if (type === "Password") {
return (
<>
<Category compact>
<Text id={`login.${type.toLowerCase()}`} />
</Category>
return (
<>
<Category compact>
<Text id={`login.${type.toLowerCase()}`} />
</Category>
{type === "Password" && (
<InputBox
type="password"
value={(value as { password: string })?.password}
@@ -47,56 +51,51 @@ function ResponseEntry({
onChange({ password: e.currentTarget.value })
}
/>
</>
);
} else {
return null;
}
)}
</>
);
}
/**
* MFA ticket creation flow
*/
export default function MFAFlow({
callback,
onClose,
...props
}: ModalProps<"mfa_flow">) {
const state = useApplicationState();
export default function MFAFlow({ onClose, ...props }: ModalProps<"mfa_flow">) {
const [methods, setMethods] = useState<API.MFAMethod[] | undefined>(
props.state === "unknown" ? props.available_methods : undefined,
);
// Current state of the modal
const [selectedMethod, setSelected] = useState<API.MFAMethod>();
const [response, setResponse] = useState<API.MFAResponse>();
// Fetch available methods if they have not been provided.
useEffect(() => {
if (!methods && props.state === "known") {
props.client.api.get("/auth/mfa/methods").then(setMethods);
}
}, []);
// Always select first available method if only one available.
useLayoutEffect(() => {
if (methods && methods.length === 1) {
setSelected(methods[0]);
}
}, [methods]);
// Callback to generate a new ticket or send response back up the chain.
const generateTicket = useCallback(async () => {
if (response) {
let ticket;
if (props.state === "known") {
ticket = await props.client.api.put(
const ticket = await props.client.api.put(
"/auth/mfa/ticket",
response,
);
props.callback(ticket);
} else {
ticket = await state.config
.createClient()
.api.put("/auth/mfa/ticket", response, {
headers: {
"X-MFA-Ticket": props.ticket.token,
},
});
props.callback(response);
}
callback(ticket);
return true;
}
@@ -122,8 +121,12 @@ export default function MFAFlow({
},
{
palette: "plain",
children: "Back",
onClick: () => setSelected(undefined),
children:
methods!.length === 1 ? "Cancel" : "Back",
onClick: () =>
methods!.length === 1
? true
: void setSelected(undefined),
},
]
: [

View File

@@ -5,16 +5,16 @@ export type Modal = {
} & (
| ({
type: "mfa_flow";
callback: (ticket: API.MFATicket) => void;
} & (
| {
state: "known";
client: Client;
callback: (ticket: API.MFATicket) => void;
}
| {
state: "unknown";
available_methods: API.MFAMethod[];
ticket: API.MFATicket & { validated: false };
callback: (response: API.MFAResponse) => void;
}
))
| {