UNPKG

@knapsack/app

Version:

Build Design Systems on top of knapsack, by Basalt

177 lines (161 loc) 4.38 kB
import { ThunkAction, ThunkMiddleware } from 'redux-thunk'; import { Action } from './types'; import { setStatus } from './ui'; import { getUserInfo } from '../../cloud/user-utils'; import { apiUrlBase } from '../../lib/constants'; import { KnapsackDataStoreSaveBody } from '../../schemas/misc'; type AppState = import('./index').AppState; const SAVE_TO_SERVER_REQUEST = 'knapsack/meta/SAVE_TO_SERVER_REQUEST'; const SAVE_TO_SERVER_SUCCESS = 'knapsack/meta/SAVE_TO_SERVER_SUCCESS'; const SAVE_TO_SERVER_FAIL = 'knapsack/meta/SAVE_TO_SERVER_FAIL'; export interface MetaState { meta?: import('../../schemas/misc').KnapsackMeta; plugins: { id: string; /** * If `loadContent()` hook was implemented, then an API endpoint is set up and waiting for us */ hasContent: boolean; clientPluginPath?: string; }[]; } const initialState: MetaState = { plugins: [], }; interface SaveToServerRequestAction extends Action { type: typeof SAVE_TO_SERVER_REQUEST; } interface SaveToServerSuccessAction extends Action { type: typeof SAVE_TO_SERVER_SUCCESS; } interface SaveToServerFailAction extends Action { type: typeof SAVE_TO_SERVER_FAIL; } type Actions = | SaveToServerRequestAction | SaveToServerSuccessAction | SaveToServerFailAction; export function saveToServer({ storageLocation, title, message, }: Omit<KnapsackDataStoreSaveBody, 'state'>): ThunkAction< void, AppState, {}, Actions > { const showStatusMsgs = storageLocation === 'cloud'; return async (dispatch, getState) => { dispatch({ type: SAVE_TO_SERVER_REQUEST }); if (showStatusMsgs) { dispatch( setStatus({ message: 'Saving...', type: 'info', }), ); } const state = getState(); const body: KnapsackDataStoreSaveBody = { storageLocation, state, title, message, }; const { user, role, ksRepoAccess, token, username } = await getUserInfo(); const userHeaders = user ? { Authorization: token ? `token ${token}` : null, 'x-ks-cloud-role-id': role?.id, 'x-ks-cloud-repo-access': ksRepoAccess?.join(','), 'x-ks-cloud-username': username, } : {}; return window .fetch(`${apiUrlBase}/data-store/`, { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', ...userHeaders, }, body: JSON.stringify(body), }) .then(res => res.json()) .then(async results => { if (!results.ok) { console.error('failed saveToServer', results); dispatch({ type: SAVE_TO_SERVER_FAIL }); dispatch( setStatus({ message: `Failed: ${results.message}`, type: 'error', dismissAfter: 30, }), ); } else { dispatch({ type: SAVE_TO_SERVER_SUCCESS }); if (showStatusMsgs) { dispatch( setStatus({ message: `Success: ${results.message}`, type: 'success', dismissAfter: 45, }), ); } } return results; }); }; } export default function reducer( state = initialState, action: Actions, ): MetaState { switch (action.type) { default: return { ...initialState, ...state, }; } } let timeoutId: any; export const autoSaveMiddleware: ThunkMiddleware< AppState, Actions > = store => next => (action: Actions) => { const ignoredActionBases = ['knapsack/ui', 'knapsack/meta', 'knapsack/user']; if (ignoredActionBases.some(x => action.type.startsWith(x))) { return next(action); } const { isLocalDev, features: { autosave }, } = store.getState().userState; if (!isLocalDev || !autosave) { return next(action); } /** * Ms after last action to autosave, if enabled */ const autosaveDelay = action.meta?.autosaveDelay ?? 1500; if (autosaveDelay === -1) { // console.log('skipping'); return next(action); } if (timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => { store.dispatch( saveToServer({ storageLocation: 'local', }), ); timeoutId = ''; }, autosaveDelay); return next(action); };