Add client context.

This commit is contained in:
Paul
2021-06-18 20:07:26 +01:00
parent e7d1ada13d
commit aa81ebb298
12 changed files with 260 additions and 33 deletions

View File

@@ -1,19 +1,22 @@
import { Text } from "preact-i18n";
import { CheckAuth } from "./context/revoltjs/CheckAuth";
import { Route, Switch } from "react-router-dom";
import Context from "./context";
import dayjs from "dayjs";
import localeData from "dayjs/plugin/localeData";
dayjs.extend(localeData);
export function App() {
return (
<Context>
<h1>
<Text id="general.about" />
</h1>
<h3>{dayjs.locale()}</h3>
<h2>{dayjs.months()}</h2>
<Switch>
<Route path="/login">
<CheckAuth>
<h1>login</h1>
</CheckAuth>
</Route>
<Route path="/">
<CheckAuth auth>
<h1>revolt app</h1>
</CheckAuth>
</Route>
</Switch>
</Context>
);
}

View File

@@ -1,15 +1,21 @@
import State from "../redux/State";
import { Children } from "../types/Preact";
import { BrowserRouter } from "react-router-dom";
import ClientContext from './revoltjs/RevoltClient';
import Locale from "./Locale";
import Theme from "./Theme";
export default function Context({ children }: { children: Children }) {
return (
<State>
<Locale>
<Theme>{children}</Theme>
</Locale>
</State>
<BrowserRouter>
<State>
<ClientContext>
<Locale>
<Theme>{children}</Theme>
</Locale>
</ClientContext>
</State>
</BrowserRouter>
);
}

View File

@@ -0,0 +1,22 @@
import { ReactNode } from "react";
import { useContext } from "preact/hooks";
import { Redirect } from "react-router-dom";
import { AppContext } from "./RevoltClient";
interface Props {
auth?: boolean;
children: ReactNode | ReactNode[];
}
export const CheckAuth = (props: Props) => {
const { operations } = useContext(AppContext);
if (props.auth && !operations.ready()) {
return <Redirect to="/login" />;
} else if (!props.auth && operations.ready()) {
return <Redirect to="/" />;
}
return <>{props.children}</>;
};

View File

@@ -1,4 +1,12 @@
import { Client } from "revolt.js";
import { createContext } from "preact";
import { useState } from "preact/hooks";
import { Children } from "../../types/Preact";
import { Route } from "revolt.js/dist/api/routes";
import { connectState } from "../../redux/connector";
import { WithDispatcher } from "../../redux/reducers";
import { AuthState } from "../../redux/reducers/auth";
import { SyncOptions } from "../../redux/reducers/sync";
export enum ClientStatus {
LOADING,
@@ -10,10 +18,60 @@ export enum ClientStatus {
ONLINE,
}
export const RevoltJSClient = new Client({
export interface ClientOperations {
login: (data: Route<"POST", "/auth/login">["data"]) => Promise<void>;
logout: (shouldRequest?: boolean) => Promise<void>;
loggedIn: () => boolean;
ready: () => boolean;
}
export interface AppState {
status: ClientStatus;
operations: ClientOperations;
}
export const AppContext = createContext<AppState>(undefined as any);
export const RevoltClient = new Client({
autoReconnect: false,
apiURL: process.env.API_SERVER,
apiURL: import.meta.env.VITE_API_URL,
debug: process.env.NODE_ENV === "development",
// Match sw.js#13
// db: new Db("state", 3, ["channels", "servers", "users", "members"])
});
type Props = WithDispatcher & {
auth: AuthState;
sync: SyncOptions;
children: Children;
};
function Context({ auth, sync, children, dispatcher }: Props) {
const [status, setStatus] = useState(ClientStatus.LOADING);
const value: AppState = {
status,
operations: {
login: async data => {},
logout: async shouldRequest => {},
loggedIn: () => false,
ready: () => false
}
};
return (
<AppContext.Provider value={value}>
{ children }
</AppContext.Provider>
);
}
export default connectState<{ children: Children }>(
Context,
state => {
return {
auth: state.auth,
sync: state.sync
};
},
true
);

5
src/env.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
interface ImportMetaEnv {
VITE_API_URL: string;
VITE_THEMES_URL: string;
}

View File

@@ -4,13 +4,6 @@ import { Provider } from "react-redux";
import { Children } from "../types/Preact";
import { useEffect, useState } from "preact/hooks";
async function loadState() {
const state = await localForage.getItem("state");
if (state) {
store.dispatch({ type: "__INIT", state });
}
}
interface Props {
children: Children;
}
@@ -19,10 +12,16 @@ export default function State(props: Props) {
const [loaded, setLoaded] = useState(false);
useEffect(() => {
loadState().then(() => setLoaded(true));
localForage.getItem("state")
.then(state => {
if (state !== null) {
store.dispatch({ type: "__INIT", state });
}
setLoaded(true);
});
}, []);
if (!loaded) return null;
return <Provider store={store}>{props.children}</Provider>;
}

View File

@@ -2,6 +2,7 @@ import { createStore } from "redux";
import rootReducer from "./reducers";
import localForage from "localforage";
import { Core } from "revolt.js/dist/api/objects";
import { Typing } from "./reducers/typing";
import { Drafts } from "./reducers/drafts";
import { AuthState } from "./reducers/auth";
@@ -13,6 +14,7 @@ import { QueuedMessage } from "./reducers/queue";
import { ExperimentOptions } from "./reducers/experiments";
export type State = {
config: Core.RevoltNodeConfiguration,
locale: Language;
auth: AuthState;
settings: Settings;
@@ -40,6 +42,7 @@ export const store = createStore((state: any, action: any) => {
// Save state using localForage.
store.subscribe(() => {
const {
config,
locale,
auth,
settings,
@@ -51,6 +54,7 @@ store.subscribe(() => {
} = store.getState() as State;
localForage.setItem("state", {
config,
locale,
auth,
settings,

View File

@@ -1,6 +1,7 @@
import { State } from "..";
import { combineReducers } from "redux";
import { config, ConfigAction } from "./server_config";
import { settings, SettingsAction } from "./settings";
import { locale, LocaleAction } from "./locale";
import { auth, AuthAction } from "./auth";
@@ -12,6 +13,7 @@ import { sync, SyncAction } from "./sync";
import { experiments, ExperimentsAction } from "./experiments";
export default combineReducers({
config,
locale,
auth,
settings,
@@ -24,6 +26,7 @@ export default combineReducers({
});
export type Action =
| ConfigAction
| LocaleAction
| AuthAction
| SettingsAction

View File

@@ -0,0 +1,20 @@
import { Core } from "revolt.js/dist/api/objects";
export type ConfigAction =
| { type: undefined }
| {
type: "SET_CONFIG";
config: Core.RevoltNodeConfiguration;
};
export function config(
state = { } as Core.RevoltNodeConfiguration,
action: ConfigAction
): Core.RevoltNodeConfiguration {
switch (action.type) {
case "SET_CONFIG":
return action.config;
default:
return state;
}
}