mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
BIG-126: async localization loaded data failed to be injected to application.
This commit is contained in:
@@ -9,7 +9,7 @@ import * as R from 'ramda';
|
|||||||
import { AppIntlProvider } from './AppIntlProvider';
|
import { AppIntlProvider } from './AppIntlProvider';
|
||||||
import { useSplashLoading } from '../hooks/state';
|
import { useSplashLoading } from '../hooks/state';
|
||||||
|
|
||||||
import { useWatch } from '../hooks';
|
import { useWatchImmediate } from '../hooks';
|
||||||
import withDashboardActions from '../containers/Dashboard/withDashboardActions';
|
import withDashboardActions from '../containers/Dashboard/withDashboardActions';
|
||||||
|
|
||||||
const SUPPORTED_LOCALES = [
|
const SUPPORTED_LOCALES = [
|
||||||
@@ -90,10 +90,10 @@ function useAppLoadLocales(currentLocale) {
|
|||||||
}, [currentLocale, stopLoading]);
|
}, [currentLocale, stopLoading]);
|
||||||
|
|
||||||
// Watches the value to start/stop splash screen.
|
// Watches the value to start/stop splash screen.
|
||||||
useWatch(isLoading, (value) => (value ? startLoading() : stopLoading()), {
|
useWatchImmediate(
|
||||||
immediate: true,
|
(value) => (value ? startLoading() : stopLoading()),
|
||||||
});
|
isLoading,
|
||||||
|
);
|
||||||
return { isLoading };
|
return { isLoading };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,10 +116,10 @@ function useAppYupLoadLocales(currentLocale) {
|
|||||||
}, [currentLocale, stopLoading]);
|
}, [currentLocale, stopLoading]);
|
||||||
|
|
||||||
// Watches the valiue to start/stop splash screen.
|
// Watches the valiue to start/stop splash screen.
|
||||||
useWatch(isLoading, (value) => (value ? startLoading() : stopLoading()), {
|
useWatchImmediate(
|
||||||
immediate: true,
|
(value) => (value ? startLoading() : stopLoading()),
|
||||||
});
|
isLoading,
|
||||||
|
);
|
||||||
return { isLoading };
|
return { isLoading };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ function AppIntlLoader({ children }) {
|
|||||||
const { isLoading: isAppLocalesLoading } = useAppLoadLocales(currentLocale);
|
const { isLoading: isAppLocalesLoading } = useAppLoadLocales(currentLocale);
|
||||||
|
|
||||||
// Detarmines whether the app locales loading.
|
// Detarmines whether the app locales loading.
|
||||||
const isLoading = isAppYupLocalesLoading && isAppLocalesLoading;
|
const isLoading = isAppYupLocalesLoading || isAppLocalesLoading;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppIntlProvider currentLocale={currentLocale} isRTL={isRTL}>
|
<AppIntlProvider currentLocale={currentLocale} isRTL={isRTL}>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as R from 'ramda';
|
|||||||
|
|
||||||
import { useUser, useCurrentOrganization } from '../../hooks/query';
|
import { useUser, useCurrentOrganization } from '../../hooks/query';
|
||||||
import { useSplashLoading } from '../../hooks/state';
|
import { useSplashLoading } from '../../hooks/state';
|
||||||
import { useWatch, useWhen } from '../../hooks';
|
import { useWatch, useWatchImmediate, useWhen } from '../../hooks';
|
||||||
|
|
||||||
import withAuthentication from '../../containers/Authentication/withAuthentication';
|
import withAuthentication from '../../containers/Authentication/withAuthentication';
|
||||||
|
|
||||||
@@ -21,10 +21,8 @@ function DashboardBootJSX({ authenticatedUserId }) {
|
|||||||
} = useCurrentOrganization();
|
} = useCurrentOrganization();
|
||||||
|
|
||||||
// Authenticated user.
|
// Authenticated user.
|
||||||
const {
|
const { isSuccess: isAuthUserSuccess, isLoading: isAuthUserLoading } =
|
||||||
isSuccess: isAuthUserSuccess,
|
useUser(authenticatedUserId);
|
||||||
isLoading: isAuthUserLoading,
|
|
||||||
} = useUser(authenticatedUserId);
|
|
||||||
|
|
||||||
// Initial locale cookie value.
|
// Initial locale cookie value.
|
||||||
const localeCookie = getCookie('locale');
|
const localeCookie = getCookie('locale');
|
||||||
@@ -59,25 +57,25 @@ function DashboardBootJSX({ authenticatedUserId }) {
|
|||||||
|
|
||||||
// Splash loading when organization request loading and
|
// Splash loading when organization request loading and
|
||||||
// applicaiton still not booted.
|
// applicaiton still not booted.
|
||||||
useWatch(isOrgLoading, (value) => {
|
useWatchImmediate((value) => {
|
||||||
value && !isBooted.current && startLoading();
|
value && !isBooted.current && startLoading();
|
||||||
});
|
}, isOrgLoading);
|
||||||
|
|
||||||
// Splash loading when request authenticated user loading and
|
// Splash loading when request authenticated user loading and
|
||||||
// application still not booted yet.
|
// application still not booted yet.
|
||||||
useWatch(isAuthUserLoading, (value) => {
|
useWatchImmediate((value) => {
|
||||||
value && !isBooted.current && startLoading();
|
value && !isBooted.current && startLoading();
|
||||||
});
|
}, isAuthUserLoading);
|
||||||
|
|
||||||
// Stop splash loading once organization request success.
|
// Stop splash loading once organization request success.
|
||||||
useWatch(isCurrentOrganizationSuccess, (value) => {
|
useWatch((value) => {
|
||||||
value && stopLoading();
|
value && stopLoading();
|
||||||
});
|
}, isCurrentOrganizationSuccess);
|
||||||
|
|
||||||
// Stop splash loading once authenticated user request success.
|
// Stop splash loading once authenticated user request success.
|
||||||
useWatch(isAuthUserSuccess, (value) => {
|
useWatch((value) => {
|
||||||
value && stopLoading();
|
value && stopLoading();
|
||||||
});
|
}, isAuthUserSuccess);
|
||||||
|
|
||||||
// Once the all requests complete change the app loading state.
|
// Once the all requests complete change the app loading state.
|
||||||
useWhen(
|
useWhen(
|
||||||
|
|||||||
@@ -1,27 +1,8 @@
|
|||||||
import { isEqual } from 'lodash';
|
import { useRef, useEffect, useMemo } from 'react';
|
||||||
import React, { useRef, useEffect, useMemo } from 'react';
|
|
||||||
import useAsync from './async';
|
|
||||||
import useAutofocus from './useAutofocus';
|
import useAutofocus from './useAutofocus';
|
||||||
|
import { useLocalStorage } from './utils/useLocalStorage';
|
||||||
|
|
||||||
// import use from 'async';
|
export * from './utils';
|
||||||
|
|
||||||
/**
|
|
||||||
* A custom useEffect hook that only triggers on updates, not on initial mount
|
|
||||||
* Idea stolen from: https://stackoverflow.com/a/55075818/1526448
|
|
||||||
* @param {Function} effect
|
|
||||||
* @param {Array<any>} dependencies
|
|
||||||
*/
|
|
||||||
export function useUpdateEffect(effect, dependencies = []) {
|
|
||||||
const isInitialMount = useRef(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isInitialMount.current) {
|
|
||||||
isInitialMount.current = false;
|
|
||||||
} else {
|
|
||||||
effect();
|
|
||||||
}
|
|
||||||
}, dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useIsValuePassed(value, compatatorValue) {
|
export function useIsValuePassed(value, compatatorValue) {
|
||||||
const cache = useRef([value]);
|
const cache = useRef([value]);
|
||||||
@@ -62,41 +43,7 @@ export function useCellAutoFocus(ref, autoFocus, columnId, rowIndex) {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
export * from './useRequestPdf';
|
export { useAutofocus };
|
||||||
export { useAsync, useAutofocus };
|
|
||||||
|
|
||||||
// Hook
|
|
||||||
export function useLocalStorage(key, initialValue) {
|
|
||||||
// State to store our value
|
|
||||||
// Pass initial state function to useState so logic is only executed once
|
|
||||||
const [storedValue, setStoredValue] = React.useState(() => {
|
|
||||||
try {
|
|
||||||
// Get from local storage by key
|
|
||||||
const item = window.localStorage.getItem(key);
|
|
||||||
// Parse stored json or if none return initialValue
|
|
||||||
return item ? JSON.parse(item) : initialValue;
|
|
||||||
} catch (error) {
|
|
||||||
return initialValue;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Return a wrapped version of useState's setter function that ...
|
|
||||||
// ... persists the new value to localStorage.
|
|
||||||
const setValue = (value) => {
|
|
||||||
try {
|
|
||||||
// Allow value to be a function so we have same API as useState
|
|
||||||
const valueToStore =
|
|
||||||
value instanceof Function ? value(storedValue) : value;
|
|
||||||
// Save state
|
|
||||||
setStoredValue(valueToStore);
|
|
||||||
// Save to local storage
|
|
||||||
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
||||||
} catch (error) {
|
|
||||||
// A more advanced implementation would handle the error case
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return [storedValue, setValue];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useMemorizedColumnsWidths(tableName) {
|
export function useMemorizedColumnsWidths(tableName) {
|
||||||
const [get, save] = useLocalStorage(`${tableName}.columns_widths`, {});
|
const [get, save] = useLocalStorage(`${tableName}.columns_widths`, {});
|
||||||
@@ -106,42 +53,3 @@ export function useMemorizedColumnsWidths(tableName) {
|
|||||||
};
|
};
|
||||||
return [get, save, handleColumnResizing];
|
return [get, save, handleColumnResizing];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hook
|
|
||||||
function usePrevious(value) {
|
|
||||||
// The ref object is a generic container whose current property is mutable ...
|
|
||||||
// ... and can hold any value, similar to an instance property on a class
|
|
||||||
const ref = useRef();
|
|
||||||
// Store current value in ref
|
|
||||||
useEffect(() => {
|
|
||||||
ref.current = value;
|
|
||||||
}, [value]); // Only re-run if value changes
|
|
||||||
// Return previous value (happens before update in useEffect above)
|
|
||||||
return ref.current;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useWhen(condition, callback) {
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (condition) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}, [condition, callback]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useWhenNot(condition, callback) {
|
|
||||||
return useWhen(!condition, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useWatch(state, callback, props) {
|
|
||||||
const config = { immediate: false, ...props };
|
|
||||||
|
|
||||||
const previosuState = usePrevious(state);
|
|
||||||
const flag = React.useRef(false);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (!isEqual(previosuState, state) || (config.immediate && !flag.current)) {
|
|
||||||
flag.current = true;
|
|
||||||
callback(state);
|
|
||||||
}
|
|
||||||
}, [previosuState, state, config.immediate, callback]);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useQueryClient, useMutation } from 'react-query';
|
import { useQueryClient, useMutation } from 'react-query';
|
||||||
import { useRequestQuery } from '../useQueryRequest';
|
import { useRequestQuery } from '../useQueryRequest';
|
||||||
import useApiRequest from '../useRequest';
|
import useApiRequest from '../useRequest';
|
||||||
import { useRequestPdf } from '../useRequestPdf';
|
import { useRequestPdf } from '../utils';
|
||||||
|
|
||||||
import { transformPagination } from 'utils';
|
import { transformPagination } from 'utils';
|
||||||
import t from './types';
|
import t from './types';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useQueryClient, useMutation } from 'react-query';
|
|||||||
import { useRequestQuery } from '../useQueryRequest';
|
import { useRequestQuery } from '../useQueryRequest';
|
||||||
import { transformPagination } from 'utils';
|
import { transformPagination } from 'utils';
|
||||||
import useApiRequest from '../useRequest';
|
import useApiRequest from '../useRequest';
|
||||||
import { useRequestPdf } from '../useRequestPdf';
|
import { useRequestPdf } from '../utils';
|
||||||
import t from './types';
|
import t from './types';
|
||||||
|
|
||||||
// Common invalidate queries.
|
// Common invalidate queries.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useQueryClient, useMutation } from 'react-query';
|
import { useQueryClient, useMutation } from 'react-query';
|
||||||
import { useRequestQuery } from '../useQueryRequest';
|
import { useRequestQuery } from '../useQueryRequest';
|
||||||
import { useRequestPdf } from '../useRequestPdf';
|
import { useRequestPdf } from '../utils';
|
||||||
import useApiRequest from '../useRequest';
|
import useApiRequest from '../useRequest';
|
||||||
import { transformPagination } from 'utils';
|
import { transformPagination } from 'utils';
|
||||||
import t from './types';
|
import t from './types';
|
||||||
|
|||||||
9
src/hooks/utils/index.js
Normal file
9
src/hooks/utils/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
export * from './useLocalStorage';
|
||||||
|
export * from './usePrevious';
|
||||||
|
export * from './useUpdateEffect';
|
||||||
|
export * from './useWatch';
|
||||||
|
export * from './useWhen';
|
||||||
|
export * from './useRequestPdf';
|
||||||
|
export * from './useAsync';
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import {useState, useCallback, useEffect} from 'react';
|
import { useState, useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
const useAsync = (asyncFunction, immediate = true) => {
|
export const useAsync = (asyncFunction, immediate = true) => {
|
||||||
const [pending, setPending] = useState(false);
|
const [pending, setPending] = useState(false);
|
||||||
const [value, setValue] = useState(null);
|
const [value, setValue] = useState(null);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
@@ -9,16 +9,19 @@ const useAsync = (asyncFunction, immediate = true) => {
|
|||||||
// handles setting state for pending, value, and error.
|
// handles setting state for pending, value, and error.
|
||||||
// useCallback ensures the below useEffect is not called
|
// useCallback ensures the below useEffect is not called
|
||||||
// on every render, but only if asyncFunction changes.
|
// on every render, but only if asyncFunction changes.
|
||||||
const execute = useCallback((...args) => {
|
const execute = useCallback(
|
||||||
setPending(true);
|
(...args) => {
|
||||||
setValue(null);
|
setPending(true);
|
||||||
setError(null);
|
setValue(null);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
return asyncFunction(...args)
|
return asyncFunction(...args)
|
||||||
.then(response => setValue(response))
|
.then((response) => setValue(response))
|
||||||
.catch(error => setError(error))
|
.catch((error) => setError(error))
|
||||||
.finally(() => setPending(false));
|
.finally(() => setPending(false));
|
||||||
}, [asyncFunction]);
|
},
|
||||||
|
[asyncFunction],
|
||||||
|
);
|
||||||
|
|
||||||
// Call execute if we want to fire it right away.
|
// Call execute if we want to fire it right away.
|
||||||
// Otherwise execute can be called later, such as
|
// Otherwise execute can be called later, such as
|
||||||
@@ -31,5 +34,3 @@ const useAsync = (asyncFunction, immediate = true) => {
|
|||||||
|
|
||||||
return { execute, pending, value, error };
|
return { execute, pending, value, error };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useAsync;
|
|
||||||
34
src/hooks/utils/useLocalStorage.js
Normal file
34
src/hooks/utils/useLocalStorage.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
// Hook
|
||||||
|
export function useLocalStorage(key, initialValue) {
|
||||||
|
// State to store our value
|
||||||
|
// Pass initial state function to useState so logic is only executed once
|
||||||
|
const [storedValue, setStoredValue] = React.useState(() => {
|
||||||
|
try {
|
||||||
|
// Get from local storage by key
|
||||||
|
const item = window.localStorage.getItem(key);
|
||||||
|
// Parse stored json or if none return initialValue
|
||||||
|
return item ? JSON.parse(item) : initialValue;
|
||||||
|
} catch (error) {
|
||||||
|
return initialValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Return a wrapped version of useState's setter function that ...
|
||||||
|
// ... persists the new value to localStorage.
|
||||||
|
const setValue = (value) => {
|
||||||
|
try {
|
||||||
|
// Allow value to be a function so we have same API as useState
|
||||||
|
const valueToStore =
|
||||||
|
value instanceof Function ? value(storedValue) : value;
|
||||||
|
// Save state
|
||||||
|
setStoredValue(valueToStore);
|
||||||
|
// Save to local storage
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
||||||
|
} catch (error) {
|
||||||
|
// A more advanced implementation would handle the error case
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return [storedValue, setValue];
|
||||||
|
}
|
||||||
15
src/hooks/utils/usePrevious.js
Normal file
15
src/hooks/utils/usePrevious.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
// Hook
|
||||||
|
export function usePrevious(value) {
|
||||||
|
// The ref object is a generic container whose current property is mutable ...
|
||||||
|
// ... and can hold any value, similar to an instance property on a class
|
||||||
|
const ref = useRef();
|
||||||
|
// Store current value in ref
|
||||||
|
useEffect(() => {
|
||||||
|
ref.current = value;
|
||||||
|
}, [value]); // Only re-run if value changes
|
||||||
|
// Return previous value (happens before update in useEffect above)
|
||||||
|
return ref.current;
|
||||||
|
}
|
||||||
38
src/hooks/utils/useRequestPdf.js
Normal file
38
src/hooks/utils/useRequestPdf.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import useApiRequest from '../useRequest';
|
||||||
|
|
||||||
|
export const useRequestPdf = (url) => {
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
const [isLoading, setIsLoading] = React.useState(false);
|
||||||
|
const [isLoaded, setIsLoaded] = React.useState(false);
|
||||||
|
const [pdfUrl, setPdfUrl] = React.useState('');
|
||||||
|
const [response, setResponse] = React.useState(null);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setIsLoading(true);
|
||||||
|
apiRequest
|
||||||
|
.get(url, {
|
||||||
|
headers: { accept: 'application/pdf' },
|
||||||
|
responseType: 'blob',
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
// Create a Blob from the PDF Stream.
|
||||||
|
const file = new Blob([response.data], { type: 'application/pdf' });
|
||||||
|
|
||||||
|
// Build a URL from the file
|
||||||
|
const fileURL = URL.createObjectURL(file);
|
||||||
|
|
||||||
|
setPdfUrl(fileURL);
|
||||||
|
setIsLoading(false);
|
||||||
|
setIsLoaded(true);
|
||||||
|
setResponse(response);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLoading,
|
||||||
|
isLoaded,
|
||||||
|
pdfUrl,
|
||||||
|
response,
|
||||||
|
};
|
||||||
|
};
|
||||||
19
src/hooks/utils/useUpdateEffect.js
Normal file
19
src/hooks/utils/useUpdateEffect.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom useEffect hook that only triggers on updates, not on initial mount
|
||||||
|
* Idea stolen from: https://stackoverflow.com/a/55075818/1526448
|
||||||
|
* @param {Function} effect
|
||||||
|
* @param {Array<any>} dependencies
|
||||||
|
*/
|
||||||
|
export function useUpdateEffect(effect, dependencies = []) {
|
||||||
|
const isInitialMount = useRef(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isInitialMount.current) {
|
||||||
|
isInitialMount.current = false;
|
||||||
|
} else {
|
||||||
|
effect();
|
||||||
|
}
|
||||||
|
}, dependencies);
|
||||||
|
}
|
||||||
21
src/hooks/utils/useWatch.js
Normal file
21
src/hooks/utils/useWatch.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
export function useWatch(callback, argument) {
|
||||||
|
const flag = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!flag.current) {
|
||||||
|
flag.current = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback(argument);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [argument]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useWatchImmediate(callback, argument) {
|
||||||
|
useEffect(() => {
|
||||||
|
callback(argument);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [argument]);
|
||||||
|
}
|
||||||
13
src/hooks/utils/useWhen.js
Normal file
13
src/hooks/utils/useWhen.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export function useWhen(condition, callback) {
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (condition) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}, [condition, callback]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useWhenNot(condition, callback) {
|
||||||
|
return useWhen(!condition, callback);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user