revite/src/context/intermediate/Intermediate.tsx

138 lines
4.5 KiB
TypeScript
Raw Normal View History

2021-06-19 13:46:05 -04:00
import { Attachment, Channels, EmbedImage, Servers } from "revolt.js/dist/api/objects";
import { useContext, useEffect, useMemo, useState } from "preact/hooks";
import { internalSubscribe } from "../../lib/eventEmitter";
2021-06-19 13:46:05 -04:00
import { Action } from "../../components/ui/Modal";
import { useHistory } from "react-router-dom";
import { Children } from "../../types/Preact";
import { createContext } from "preact";
import { Prompt } from "react-router";
2021-06-19 13:46:05 -04:00
import Modals from './Modals';
export type Screen =
| { id: "none" }
// Modals
| { id: "signed_out" }
| { id: "error"; error: string }
| { id: "clipboard"; text: string }
| { id: "modify_account"; field: "username" | "email" | "password" }
| { id: "_prompt"; question: Children; content?: Children; actions: Action[] }
| ({ id: "special_prompt" } & (
{ 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 }
)) |
({ id: "special_input" } & (
2021-06-19 15:00:30 -04:00
{ type: "create_group" | "create_server" | "set_custom_status" | "add_friend" } |
2021-06-19 13:46:05 -04:00
{ type: "create_channel", server: string }
))
| {
id: "_input";
question: Children;
field: Children;
defaultValue?: string;
callback: (value: string) => Promise<void>;
}
| {
id: "onboarding";
callback: (
username: string,
loginAfterSuccess?: true
) => Promise<void>;
}
// Pop-overs
| { id: "image_viewer"; attachment?: Attachment; embed?: EmbedImage; }
| { id: "profile"; user_id: string }
| { id: "channel_info"; channel_id: string }
| {
id: "user_picker";
omit?: string[];
callback: (users: string[]) => Promise<void>;
};
export const IntermediateContext = createContext({
screen: { id: "none" } as Screen,
focusTaken: false
});
export const IntermediateActionsContext = createContext({
openScreen: (screen: Screen) => {},
writeClipboard: (text: string) => {}
});
interface Props {
children: Children;
}
export default function Intermediate(props: Props) {
const [screen, openScreen] = useState<Screen>({ id: "none" });
const history = useHistory();
const value = {
screen,
focusTaken: screen.id !== 'none'
};
const actions = useMemo(() => {
return {
openScreen: (screen: Screen) => openScreen(screen),
writeClipboard: (text: string) => {
if (navigator.clipboard) {
navigator.clipboard.writeText(text);
} else {
actions.openScreen({ id: "clipboard", text });
}
}
}
}, []);
useEffect(() => {
const openProfile = (user_id: string) => openScreen({ id: "profile", user_id });
const navigate = (path: string) => history.push(path);
2021-06-19 13:46:05 -04:00
const subs = [
internalSubscribe("Intermediate", "open_profile", openProfile),
internalSubscribe("Intermediate", "navigate", navigate)
]
2021-06-19 13:46:05 -04:00
return () => subs.map(unsub => unsub());
2021-06-19 13:46:05 -04:00
}, []);
return (
<IntermediateContext.Provider value={value}>
<IntermediateActionsContext.Provider value={actions}>
{props.children}
<Modals
{...value}
{...actions}
key={
screen.id
} /** By specifying a key, we reset state whenever switching screen. */
/>
<Prompt
when={[ 'modify_account', 'special_prompt', 'special_input', 'image_viewer', 'profile', 'channel_info', 'user_picker' ].includes(screen.id)}
message={(_, action) => {
if (action === 'POP') {
openScreen({ id: 'none' });
setTimeout(() => history.push(history.location), 0);
2021-06-19 13:46:05 -04:00
return false;
}
return true;
2021-06-19 13:46:05 -04:00
}}
/>
2021-06-19 13:46:05 -04:00
</IntermediateActionsContext.Provider>
</IntermediateContext.Provider>
);
}
export const useIntermediate = () => useContext(IntermediateActionsContext);