|
|
|
import _ from 'lodash';
|
|
|
|
import { createAction } from 'redux-actions';
|
|
|
|
import { createThunk, handleThunks } from 'Store/thunks';
|
|
|
|
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
|
|
|
import getSectionState from 'Utilities/State/getSectionState';
|
|
|
|
import updateSectionState from 'Utilities/State/updateSectionState';
|
|
|
|
import { fetchTranslations as fetchAppTranslations } from 'Utilities/String/translate';
|
|
|
|
import createHandleActions from './Creators/createHandleActions';
|
|
|
|
|
|
|
|
function getDimensions(width, height) {
|
|
|
|
const dimensions = {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
isExtraSmallScreen: width <= 480,
|
|
|
|
isSmallScreen: width <= 768,
|
|
|
|
isMediumScreen: width <= 992,
|
|
|
|
isLargeScreen: width <= 1200
|
|
|
|
};
|
|
|
|
|
|
|
|
return dimensions;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Variables
|
|
|
|
|
|
|
|
export const section = 'app';
|
|
|
|
const messagesSection = 'app.messages';
|
|
|
|
let abortPingServer = null;
|
|
|
|
let pingTimeout = null;
|
|
|
|
|
|
|
|
//
|
|
|
|
// State
|
|
|
|
|
|
|
|
export const defaultState = {
|
|
|
|
dimensions: getDimensions(window.innerWidth, window.innerHeight),
|
|
|
|
messages: {
|
|
|
|
items: []
|
|
|
|
},
|
|
|
|
version: window.Lidarr.version,
|
|
|
|
isUpdated: false,
|
|
|
|
isConnected: true,
|
|
|
|
isReconnecting: false,
|
|
|
|
isDisconnected: false,
|
|
|
|
isRestarting: false,
|
|
|
|
isSidebarVisible: !getDimensions(window.innerWidth, window.innerHeight).isSmallScreen,
|
|
|
|
translations: {
|
|
|
|
isFetching: true,
|
|
|
|
isPopulated: false,
|
|
|
|
error: null
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// Action Types
|
|
|
|
|
|
|
|
export const SHOW_MESSAGE = 'app/showMessage';
|
|
|
|
export const HIDE_MESSAGE = 'app/hideMessage';
|
|
|
|
export const SAVE_DIMENSIONS = 'app/saveDimensions';
|
|
|
|
export const SET_VERSION = 'app/setVersion';
|
|
|
|
export const SET_APP_VALUE = 'app/setAppValue';
|
|
|
|
export const SET_IS_SIDEBAR_VISIBLE = 'app/setIsSidebarVisible';
|
|
|
|
export const FETCH_TRANSLATIONS = 'app/fetchTranslations';
|
|
|
|
|
|
|
|
export const PING_SERVER = 'app/pingServer';
|
|
|
|
|
|
|
|
//
|
|
|
|
// Action Creators
|
|
|
|
|
|
|
|
export const saveDimensions = createAction(SAVE_DIMENSIONS);
|
|
|
|
export const setVersion = createAction(SET_VERSION);
|
|
|
|
export const setIsSidebarVisible = createAction(SET_IS_SIDEBAR_VISIBLE);
|
|
|
|
export const setAppValue = createAction(SET_APP_VALUE);
|
|
|
|
export const showMessage = createAction(SHOW_MESSAGE);
|
|
|
|
export const hideMessage = createAction(HIDE_MESSAGE);
|
|
|
|
export const pingServer = createThunk(PING_SERVER);
|
|
|
|
export const fetchTranslations = createThunk(FETCH_TRANSLATIONS);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Helpers
|
|
|
|
|
|
|
|
function pingServerAfterTimeout(getState, dispatch) {
|
|
|
|
if (abortPingServer) {
|
|
|
|
abortPingServer();
|
|
|
|
abortPingServer = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pingTimeout) {
|
|
|
|
clearTimeout(pingTimeout);
|
|
|
|
pingTimeout = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
pingTimeout = setTimeout(() => {
|
|
|
|
if (!getState().isRestarting && getState().isConnected) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ajaxOptions = {
|
|
|
|
url: '/system/status',
|
|
|
|
method: 'GET',
|
|
|
|
contentType: 'application/json'
|
|
|
|
};
|
|
|
|
|
|
|
|
const { request, abortRequest } = createAjaxRequest(ajaxOptions);
|
|
|
|
|
|
|
|
abortPingServer = abortRequest;
|
|
|
|
|
|
|
|
request.done(() => {
|
|
|
|
abortPingServer = null;
|
|
|
|
pingTimeout = null;
|
|
|
|
|
|
|
|
dispatch(setAppValue({
|
|
|
|
isRestarting: false
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
|
|
|
|
request.fail((xhr) => {
|
|
|
|
abortPingServer = null;
|
|
|
|
pingTimeout = null;
|
|
|
|
|
|
|
|
// Unauthorized, but back online
|
|
|
|
if (xhr.status === 401) {
|
|
|
|
dispatch(setAppValue({
|
|
|
|
isRestarting: false
|
|
|
|
}));
|
|
|
|
} else {
|
|
|
|
pingServerAfterTimeout(getState, dispatch);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}, 5000);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Action Handlers
|
|
|
|
|
|
|
|
export const actionHandlers = handleThunks({
|
|
|
|
[PING_SERVER]: function(getState, payload, dispatch) {
|
|
|
|
pingServerAfterTimeout(getState, dispatch);
|
|
|
|
},
|
|
|
|
[FETCH_TRANSLATIONS]: async function(getState, payload, dispatch) {
|
|
|
|
const isFetchingComplete = await fetchAppTranslations();
|
|
|
|
|
|
|
|
dispatch(setAppValue({
|
|
|
|
translations: {
|
|
|
|
isFetching: false,
|
|
|
|
isPopulated: isFetchingComplete,
|
|
|
|
error: isFetchingComplete ? null : 'Failed to load translations from API'
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
//
|
|
|
|
// Reducers
|
|
|
|
|
|
|
|
export const reducers = createHandleActions({
|
|
|
|
|
|
|
|
[SAVE_DIMENSIONS]: function(state, { payload }) {
|
|
|
|
const {
|
|
|
|
width,
|
|
|
|
height
|
|
|
|
} = payload;
|
|
|
|
|
|
|
|
const dimensions = getDimensions(width, height);
|
|
|
|
|
|
|
|
return Object.assign({}, state, { dimensions });
|
|
|
|
},
|
|
|
|
|
|
|
|
[SHOW_MESSAGE]: function(state, { payload }) {
|
|
|
|
const newState = getSectionState(state, messagesSection);
|
|
|
|
const items = newState.items;
|
|
|
|
const index = _.findIndex(items, { id: payload.id });
|
|
|
|
|
|
|
|
newState.items = [...items];
|
|
|
|
|
|
|
|
if (index >= 0) {
|
|
|
|
const item = items[index];
|
|
|
|
|
|
|
|
newState.items.splice(index, 1, { ...item, ...payload });
|
|
|
|
} else {
|
|
|
|
newState.items.push({ ...payload });
|
|
|
|
}
|
|
|
|
|
|
|
|
return updateSectionState(state, messagesSection, newState);
|
|
|
|
},
|
|
|
|
|
|
|
|
[HIDE_MESSAGE]: function(state, { payload }) {
|
|
|
|
const newState = getSectionState(state, messagesSection);
|
|
|
|
|
|
|
|
newState.items = [...newState.items];
|
|
|
|
_.remove(newState.items, { id: payload.id });
|
|
|
|
|
|
|
|
return updateSectionState(state, messagesSection, newState);
|
|
|
|
},
|
|
|
|
|
|
|
|
[SET_APP_VALUE]: function(state, { payload }) {
|
|
|
|
const newState = Object.assign(getSectionState(state, section), payload);
|
|
|
|
|
|
|
|
return updateSectionState(state, section, newState);
|
|
|
|
},
|
|
|
|
|
|
|
|
[SET_VERSION]: function(state, { payload }) {
|
|
|
|
const version = payload.version;
|
|
|
|
|
|
|
|
const newState = {
|
|
|
|
version
|
|
|
|
};
|
|
|
|
|
|
|
|
if (state.version !== version) {
|
|
|
|
if (!state.prevVersion) {
|
|
|
|
newState.prevVersion = state.version;
|
|
|
|
}
|
|
|
|
newState.isUpdated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Object.assign({}, state, newState);
|
|
|
|
},
|
|
|
|
|
|
|
|
[SET_IS_SIDEBAR_VISIBLE]: function(state, { payload }) {
|
|
|
|
const newState = {
|
|
|
|
isSidebarVisible: payload.isSidebarVisible
|
|
|
|
};
|
|
|
|
|
|
|
|
return Object.assign({}, state, newState);
|
|
|
|
}
|
|
|
|
|
|
|
|
}, defaultState, section);
|