Configure global storage

This commit is contained in:
Jorik Schellekens
2020-09-01 10:14:13 +02:00
parent 890669741c
commit 47fe7860c3
7 changed files with 313 additions and 54 deletions
+77 -35
View File
@@ -15,54 +15,96 @@ limitations under the License.
*/
import React from 'react';
import { object, string, boolean, TypeOf } from 'zod';
import { prefixFetch, Client, discoverServer } from 'matrix-cypher';
import { ClientId } from '../clients/types';
import { persistReducer } from '../utils/localStorage';
type State = {
clientURL: string;
client: Client;
}[];
const STATE_SCHEMA = object({
clientId: string().nullable(),
showOnlyDeviceClients: boolean(),
rememberSelection: boolean(),
showExperimentalClients: boolean(),
});
type State = TypeOf<typeof STATE_SCHEMA>;
// Actions are a discriminated union.
export enum ActionTypes {
AddClient = 'ADD_CLIENT',
RemoveClient = 'REMOVE_CLIENT',
export enum ActionType {
SetClient = 'SET_CLIENT',
ToggleRememberSelection = 'TOGGLE_REMEMBER_SELECTION',
ToggleShowOnlyDeviceClients = 'TOGGLE_SHOW_ONLY_DEVICE_CLIENTS',
ToggleShowExperimentalClients = 'TOGGLE_SHOW_EXPERIMENTAL_CLIENTS',
}
export interface AddClient {
action: ActionTypes.AddClient;
clientURL: string;
interface SetClient {
action: ActionType.SetClient;
clientId: ClientId;
}
export interface RemoveClient {
action: ActionTypes.RemoveClient;
clientURL: string;
interface ToggleRememberSelection {
action: ActionType.ToggleRememberSelection;
}
export type Action = AddClient | RemoveClient;
interface ToggleShowOnlyDeviceClients {
action: ActionType.ToggleShowOnlyDeviceClients;
}
export const INITIAL_STATE: State = [];
export const reducer = async (state: State, action: Action): Promise<State> => {
switch (action.action) {
case ActionTypes.AddClient:
return state.filter((x) => x.clientURL !== action.clientURL);
interface ToggleShowExperimentalClients {
action: ActionType.ToggleShowExperimentalClients;
}
case ActionTypes.RemoveClient:
if (!state.filter((x) => x.clientURL === action.clientURL)) {
const resolvedURL = await discoverServer(action.clientURL);
state.push({
clientURL: resolvedURL,
client: prefixFetch(resolvedURL),
});
}
}
return state;
export type Action =
| SetClient
| ToggleRememberSelection
| ToggleShowOnlyDeviceClients
| ToggleShowExperimentalClients;
const INITIAL_STATE: State = {
clientId: null,
rememberSelection: false,
showOnlyDeviceClients: true,
showExperimentalClients: false,
};
// The null is a hack to make the type checker happy
// create context does not need an argument
const { Provider, Consumer } = React.createContext<typeof reducer | null>(null);
export const [initialState, reducer] = persistReducer(
'default-client',
INITIAL_STATE,
STATE_SCHEMA,
(state: State, action: Action): State => {
switch (action.action) {
case ActionType.SetClient:
return {
...state,
clientId: action.clientId,
};
case ActionType.ToggleRememberSelection:
return {
...state,
rememberSelection: !state.rememberSelection,
};
case ActionType.ToggleShowOnlyDeviceClients:
return {
...state,
showOnlyDeviceClients: !state.showOnlyDeviceClients,
};
case ActionType.ToggleShowExperimentalClients:
return {
...state,
showExperimentalClients: !state.showExperimentalClients,
};
default:
return state;
}
}
);
// The defualt reducer needs to be overwritten with the one above
// after it's been put through react's useReducer
export const ClientContext = React.createContext<
[State, React.Dispatch<Action>]
>([initialState, (): void => {}]);
// Quick rename to make importing easier
export const ClientProvider = Provider;
export const ClientConsumer = Consumer;
export const ClientProvider = ClientContext.Provider;
export const ClientConsumer = ClientContext.Consumer;