mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
feat: application booting.
This commit is contained in:
@@ -14,6 +14,7 @@ const CLASSES = {
|
||||
DASHBOARD_CONTENT: 'dashboard-content',
|
||||
DASHBOARD_CONTENT_PREFERENCES: 'dashboard-content--preferences',
|
||||
DASHBOARD_CONTENT_PANE: 'Pane2',
|
||||
DASHBOARD_CENTERED_EMPTY_STATUS: 'dashboard__centered-empty-status',
|
||||
|
||||
PAGE_FORM: 'page-form',
|
||||
PAGE_FORM_HEADER: 'page-form__header',
|
||||
|
||||
@@ -13,29 +13,14 @@ import PrivateRoute from 'components/Guards/PrivateRoute';
|
||||
import GlobalErrors from 'containers/GlobalErrors/GlobalErrors';
|
||||
import DashboardPrivatePages from 'components/Dashboard/PrivatePages';
|
||||
import Authentication from 'components/Authentication';
|
||||
|
||||
// Query client config.
|
||||
const queryConfig = {
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
refetchOnWindowFocus: true,
|
||||
staleTime: 30000,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Global fetch query.
|
||||
function GlobalFetchQuery({
|
||||
children
|
||||
}) {
|
||||
window.localStorage.setItem('lang', 'ar-ly');
|
||||
return children
|
||||
}
|
||||
import { SplashScreen } from '../components';
|
||||
import { queryConfig } from '../hooks/query/base'
|
||||
|
||||
/**
|
||||
* Core application.
|
||||
*/
|
||||
function App({ locale }) {
|
||||
export default function App() {
|
||||
// Browser history.
|
||||
const history = createBrowserHistory();
|
||||
|
||||
// Query client.
|
||||
@@ -43,30 +28,24 @@ function App({ locale }) {
|
||||
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<GlobalFetchQuery>
|
||||
<AppIntlLoader>
|
||||
<div className="App">
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route path={'/auth'} component={Authentication} />
|
||||
<Route path={'/'}>
|
||||
<PrivateRoute component={DashboardPrivatePages} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
<SplashScreen />
|
||||
|
||||
<GlobalErrors />
|
||||
</div>
|
||||
</AppIntlLoader>
|
||||
</GlobalFetchQuery>
|
||||
<AppIntlLoader>
|
||||
<div className="App">
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route path={'/auth'} component={Authentication} />
|
||||
<Route path={'/'}>
|
||||
<PrivateRoute component={DashboardPrivatePages} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
|
||||
<GlobalErrors />
|
||||
</div>
|
||||
</AppIntlLoader>
|
||||
|
||||
<ReactQueryDevtools initialIsOpen />
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
||||
App.defaultProps = {
|
||||
locale: 'en',
|
||||
};
|
||||
|
||||
export default App;
|
||||
}
|
||||
@@ -4,12 +4,14 @@ import { setLocale } from 'yup';
|
||||
import intl from 'react-intl-universal';
|
||||
import { find } from 'lodash';
|
||||
import rtlDetect from 'rtl-detect';
|
||||
import * as R from 'ramda';
|
||||
import { AppIntlProvider } from './AppIntlProvider';
|
||||
import DashboardLoadingIndicator from 'components/Dashboard/DashboardLoadingIndicator';
|
||||
import withDashboardActions from '../containers/Dashboard/withDashboardActions';
|
||||
import withDashboard from '../containers/Dashboard/withDashboard';
|
||||
|
||||
const SUPPORTED_LOCALES = [
|
||||
{ name: 'English', value: 'en' },
|
||||
{ name: 'العربية', value: 'ar-ly' },
|
||||
{ name: 'العربية', value: 'ar' },
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -18,7 +20,7 @@ const SUPPORTED_LOCALES = [
|
||||
function getCurrentLocal() {
|
||||
let currentLocale = intl.determineLocale({
|
||||
urlLocaleKey: 'lang',
|
||||
cookieLocaleKey: 'lang',
|
||||
cookieLocaleKey: 'locale',
|
||||
localStorageLocaleKey: 'lang',
|
||||
});
|
||||
if (!find(SUPPORTED_LOCALES, { value: currentLocale })) {
|
||||
@@ -57,10 +59,14 @@ function useDocumentDirectionModifier(locale, isRTL) {
|
||||
/**
|
||||
* Application Intl loader.
|
||||
*/
|
||||
export default function AppIntlLoader({ children }) {
|
||||
const [isLoading, setIsLoading] = React.useState(true);
|
||||
function AppIntlLoader({ appIntlIsLoading, setAppIntlIsLoading, children }) {
|
||||
const [isLocalsLoading, setIsLocalsLoading] = React.useState(true);
|
||||
const [isYupLoading, setIsYupLoading] = React.useState(true);
|
||||
|
||||
// Retrieve the current locale.
|
||||
const currentLocale = getCurrentLocal();
|
||||
|
||||
// Detarmines the document direction based on the given locale.
|
||||
const isRTL = rtlDetect.isRtlLang(currentLocale);
|
||||
|
||||
// Modifies the html document direction
|
||||
@@ -79,23 +85,33 @@ export default function AppIntlLoader({ children }) {
|
||||
})
|
||||
.then(() => {
|
||||
moment.locale(currentLocale);
|
||||
setIsLoading(false);
|
||||
setIsLocalsLoading(false);
|
||||
});
|
||||
}, [currentLocale, setIsLoading]);
|
||||
}, [currentLocale, setIsLocalsLoading]);
|
||||
|
||||
React.useEffect(() => {
|
||||
loadYupLocales(currentLocale)
|
||||
.then(({ locale }) => {
|
||||
setLocale(locale);
|
||||
setIsYupLoading(false);
|
||||
})
|
||||
.then(() => {});
|
||||
}, [currentLocale]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!isLocalsLoading && !isYupLoading) {
|
||||
setAppIntlIsLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<AppIntlProvider currentLocale={currentLocale} isRTL={isRTL}>
|
||||
<DashboardLoadingIndicator isLoading={isLoading}>
|
||||
{children}
|
||||
</DashboardLoadingIndicator>
|
||||
{appIntlIsLoading ? null : children}
|
||||
</AppIntlProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default R.compose(
|
||||
withDashboardActions,
|
||||
withDashboard(({ appIntlIsLoading }) => ({ appIntlIsLoading })),
|
||||
)(AppIntlLoader);
|
||||
|
||||
@@ -6,7 +6,7 @@ import authenticationRoutes from 'routes/authentication';
|
||||
import { FormattedMessage as T } from 'components';
|
||||
import Icon from 'components/Icon';
|
||||
import { useIsAuthenticated } from 'hooks/state';
|
||||
|
||||
import {AuthenticationBoot} from '../containers/Authentication/AuthenticationBoot';
|
||||
import 'style/pages/Authentication/Auth.scss';
|
||||
|
||||
function PageFade(props) {
|
||||
@@ -26,6 +26,7 @@ export default function AuthenticationWrapper({ ...rest }) {
|
||||
) : (
|
||||
<BodyClassName className={'authentication'}>
|
||||
<div class="authentication-page">
|
||||
<AuthenticationBoot />
|
||||
<a
|
||||
href={'http://bigcapital.ly'}
|
||||
className={'authentication-page__goto-bigcapital'}
|
||||
|
||||
28
client/src/components/Dashboard/AuthenticatedUser.js
Normal file
28
client/src/components/Dashboard/AuthenticatedUser.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { useUser } from 'hooks/query';
|
||||
import withAuthentication from '../../containers/Authentication/withAuthentication';
|
||||
|
||||
const AuthenticatedUserContext = React.createContext();
|
||||
|
||||
function AuthenticatedUserComponent({ authenticatedUserId, children }) {
|
||||
const { data: user, ...restProps } = useUser(authenticatedUserId);
|
||||
|
||||
return (
|
||||
<AuthenticatedUserContext.Provider
|
||||
value={{
|
||||
user,
|
||||
...restProps,
|
||||
}}
|
||||
children={children}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const AuthenticatedUser = withAuthentication(
|
||||
({ authenticatedUserId }) => ({
|
||||
authenticatedUserId,
|
||||
}),
|
||||
)(AuthenticatedUserComponent);
|
||||
|
||||
export const useAuthenticatedUser = () =>
|
||||
React.useContext(AuthenticatedUserContext);
|
||||
76
client/src/components/Dashboard/DashboardBoot.js
Normal file
76
client/src/components/Dashboard/DashboardBoot.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
|
||||
import { useUser, useCurrentOrganization } from 'hooks/query';
|
||||
import withAuthentication from '../../containers/Authentication/withAuthentication';
|
||||
import withDashboardActions from '../../containers/Dashboard/withDashboardActions';
|
||||
|
||||
import { setCookie, getCookie } from '../../utils';
|
||||
|
||||
/**
|
||||
* Dashboard async booting.
|
||||
*/
|
||||
function DashboardBootJSX({ setAppIsLoading, authenticatedUserId }) {
|
||||
// Fetches the current user's organization.
|
||||
const { isSuccess: isCurrentOrganizationSuccess, data: organization } =
|
||||
useCurrentOrganization();
|
||||
|
||||
// Authenticated user.
|
||||
const { isSuccess: isAuthUserSuccess, data: authUser } =
|
||||
useUser(authenticatedUserId);
|
||||
|
||||
// Initial locale cookie value.
|
||||
const localeCookie = getCookie('locale');
|
||||
|
||||
// Is the dashboard booted.
|
||||
const isBooted = React.useRef(false);
|
||||
|
||||
// Syns the organization language with locale cookie.
|
||||
React.useEffect(() => {
|
||||
if (organization?.metadata?.language) {
|
||||
setCookie('locale', organization.metadata.language);
|
||||
}
|
||||
}, [organization]);
|
||||
|
||||
React.useEffect(() => {
|
||||
// Can't continue if the organization metadata is not loaded yet.
|
||||
if (!organization?.metadata?.language) {
|
||||
return;
|
||||
}
|
||||
// Can't continue if the organization is already booted.
|
||||
if (isBooted.current) {
|
||||
return;
|
||||
}
|
||||
// Reboot the application in case the initial locale not equal
|
||||
// the current organization language.
|
||||
if (localeCookie !== organization.metadata.language) {
|
||||
window.location.reload();
|
||||
}
|
||||
}, [localeCookie, organization]);
|
||||
|
||||
React.useEffect(() => {
|
||||
// Once the all requests complete change the app loading state.
|
||||
if (
|
||||
isAuthUserSuccess &&
|
||||
isCurrentOrganizationSuccess &&
|
||||
localeCookie === organization?.metadata?.language
|
||||
) {
|
||||
setAppIsLoading(false);
|
||||
isBooted.current = true;
|
||||
}
|
||||
}, [
|
||||
isAuthUserSuccess,
|
||||
isCurrentOrganizationSuccess,
|
||||
organization,
|
||||
setAppIsLoading,
|
||||
localeCookie,
|
||||
]);
|
||||
return null;
|
||||
}
|
||||
|
||||
export const DashboardBoot = R.compose(
|
||||
withAuthentication(({ authenticatedUserId }) => ({
|
||||
authenticatedUserId,
|
||||
})),
|
||||
withDashboardActions,
|
||||
)(DashboardBootJSX);
|
||||
@@ -1,13 +1,8 @@
|
||||
import React from 'react';
|
||||
import DashboardLoadingIndicator from './DashboardLoadingIndicator';
|
||||
|
||||
/**
|
||||
* Dashboard provider.
|
||||
*/
|
||||
export default function DashboardProvider({ children }) {
|
||||
return (
|
||||
<DashboardLoadingIndicator isLoading={false}>
|
||||
{ children }
|
||||
</DashboardLoadingIndicator>
|
||||
)
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import SetupWizardPage from 'containers/Setup/WizardSetupPage';
|
||||
import EnsureOrganizationIsReady from 'components/Guards/EnsureOrganizationIsReady';
|
||||
import EnsureOrganizationIsNotReady from 'components/Guards/EnsureOrganizationIsNotReady';
|
||||
import { PrivatePagesProvider } from './PrivatePagesProvider';
|
||||
import { DashboardBoot } from '../../components';
|
||||
|
||||
import 'style/pages/Dashboard/Dashboard.scss';
|
||||
|
||||
@@ -16,6 +17,8 @@ import 'style/pages/Dashboard/Dashboard.scss';
|
||||
export default function DashboardPrivatePages() {
|
||||
return (
|
||||
<PrivatePagesProvider>
|
||||
<DashboardBoot />
|
||||
|
||||
<Switch>
|
||||
<Route path={'/setup'}>
|
||||
<EnsureOrganizationIsNotReady>
|
||||
@@ -23,7 +26,7 @@ export default function DashboardPrivatePages() {
|
||||
</EnsureOrganizationIsNotReady>
|
||||
</Route>
|
||||
|
||||
<Route path='/'>
|
||||
<Route path="/">
|
||||
<EnsureOrganizationIsReady>
|
||||
<Dashboard />
|
||||
</EnsureOrganizationIsReady>
|
||||
@@ -31,4 +34,4 @@ export default function DashboardPrivatePages() {
|
||||
</Switch>
|
||||
</PrivatePagesProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
import React from 'react';
|
||||
import DashboardLoadingIndicator from 'components/Dashboard/DashboardLoadingIndicator';
|
||||
import { useCurrentOrganization } from '../../hooks/query/organization';
|
||||
import { AuthenticatedUser } from './AuthenticatedUser';
|
||||
|
||||
/**
|
||||
* Private pages provider.
|
||||
*/
|
||||
export function PrivatePagesProvider({ children }) {
|
||||
// Fetches the current user's organization.
|
||||
const { isLoading } = useCurrentOrganization();
|
||||
|
||||
return (
|
||||
<DashboardLoadingIndicator isLoading={isLoading}>
|
||||
{children}
|
||||
</DashboardLoadingIndicator>
|
||||
)
|
||||
}
|
||||
return <AuthenticatedUser>{children}</AuthenticatedUser>;
|
||||
}
|
||||
|
||||
15
client/src/components/Dashboard/SplashScreen.js
Normal file
15
client/src/components/Dashboard/SplashScreen.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
import BigcapitalLoading from './BigcapitalLoading';
|
||||
import withDashboard from '../../containers/Dashboard/withDashboard';
|
||||
|
||||
function SplashScreenComponent({ appIsLoading, appIntlIsLoading }) {
|
||||
return appIsLoading || appIntlIsLoading ? <BigcapitalLoading /> : null;
|
||||
}
|
||||
|
||||
export const SplashScreen = R.compose(
|
||||
withDashboard(({ appIsLoading, appIntlIsLoading }) => ({
|
||||
appIsLoading,
|
||||
appIntlIsLoading,
|
||||
})),
|
||||
)(SplashScreenComponent);
|
||||
@@ -11,11 +11,12 @@ import {
|
||||
import { If, FormattedMessage as T } from 'components';
|
||||
|
||||
import { firstLettersArgs } from 'utils';
|
||||
import { useAuthActions, useAuthUser } from 'hooks/state';
|
||||
import { useAuthActions } from 'hooks/state';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import { compose } from 'utils';
|
||||
import withSubscriptions from '../../containers/Subscriptions/withSubscriptions';
|
||||
import { useAuthenticatedUser } from './AuthenticatedUser';
|
||||
|
||||
function DashboardTopbarUser({
|
||||
openDialog,
|
||||
@@ -25,7 +26,9 @@ function DashboardTopbarUser({
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { setLogout } = useAuthActions();
|
||||
const user = useAuthUser();
|
||||
|
||||
// Retrieve authenticated user information.
|
||||
const { user } = useAuthenticatedUser();
|
||||
|
||||
const onClickLogout = () => {
|
||||
setLogout();
|
||||
|
||||
4
client/src/components/Dashboard/index.js
Normal file
4
client/src/components/Dashboard/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
|
||||
export * from './SplashScreen';
|
||||
export * from './DashboardBoot';
|
||||
@@ -1,26 +1,17 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
|
||||
import 'style/components/DataTable/DataTableEmptyStatus.scss';
|
||||
import Style from 'style/components/DataTable/DataTableEmptyStatus.module.scss';
|
||||
|
||||
/**
|
||||
* Datatable empty status.
|
||||
*/
|
||||
export default function EmptyStatuts({ title, description, action, children }) {
|
||||
export default function EmptyStatus({ title, description, action, children }) {
|
||||
return (
|
||||
<div className={classNames(CLASSES.DATATABLE_EMPTY_STATUS)}>
|
||||
<h1 className={classNames(CLASSES.DATATABLE_EMPTY_STATUS_TITLE)}>
|
||||
{title}
|
||||
</h1>
|
||||
|
||||
<div className={classNames(CLASSES.DATATABLE_EMPTY_STATUS_DESC)}>
|
||||
{description}
|
||||
</div>
|
||||
|
||||
<div className={classNames(CLASSES.DATATABLE_EMPTY_STATUS_ACTIONS)}>
|
||||
{action}
|
||||
</div>
|
||||
<div className={classNames(Style.root)}>
|
||||
<h1 className={classNames(Style.root_title)}>{title}</h1>
|
||||
<div className={classNames(Style.root_desc)}>{description}</div>
|
||||
<div className={classNames(Style.root_actions)}>{action}</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { Button, Popover, Menu, Position } from '@blueprintjs/core';
|
||||
import Icon from 'components/Icon';
|
||||
import { useAuthUser } from 'hooks/state';
|
||||
import { compose, firstLettersArgs } from 'utils';
|
||||
import withCurrentOrganization from '../../containers/Organization/withCurrentOrganization';
|
||||
import { useAuthenticatedUser } from '../Dashboard/AuthenticatedUser';
|
||||
|
||||
// Popover modifiers.
|
||||
const POPOVER_MODIFIERS = {
|
||||
@@ -17,7 +17,8 @@ function SidebarHead({
|
||||
// #withCurrentOrganization
|
||||
organization,
|
||||
}) {
|
||||
const user = useAuthUser();
|
||||
// Retrieve authenticated user information.
|
||||
const { user } = useAuthenticatedUser();
|
||||
|
||||
return (
|
||||
<div className="sidebar__head">
|
||||
|
||||
@@ -74,6 +74,7 @@ export * from './Drawer/DrawerMainTabs';
|
||||
export * from './TotalLines/index'
|
||||
export * from './Alert';
|
||||
export * from './Subscriptions';
|
||||
export * from './Dashboard';
|
||||
|
||||
const Hint = FieldHint;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
import { DataTable, DashboardContentTable } from 'components';
|
||||
|
||||
import ManualJournalsEmptyStatus from './ManualJournalsEmptyStatus';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
@@ -91,33 +91,35 @@ function ManualJournalsDataTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={manualJournals}
|
||||
initialState={manualJournalsTableState}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
expandable={true}
|
||||
sticky={true}
|
||||
loading={isManualJournalsLoading}
|
||||
headerLoading={isManualJournalsLoading}
|
||||
progressBarLoading={isManualJournalsFetching}
|
||||
pagesCount={pagination.pagesCount}
|
||||
pagination={true}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
onFetchData={handleFetchData}
|
||||
payload={{
|
||||
onDelete: handleDeleteJournal,
|
||||
onPublish: handlePublishJournal,
|
||||
onEdit: handleEditJournal,
|
||||
onViewDetails: handleViewDetailJournal,
|
||||
}}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={manualJournals}
|
||||
initialState={manualJournalsTableState}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
expandable={true}
|
||||
sticky={true}
|
||||
loading={isManualJournalsLoading}
|
||||
headerLoading={isManualJournalsLoading}
|
||||
progressBarLoading={isManualJournalsFetching}
|
||||
pagesCount={pagination.pagesCount}
|
||||
pagination={true}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
onFetchData={handleFetchData}
|
||||
payload={{
|
||||
onDelete: handleDeleteJournal,
|
||||
onPublish: handlePublishJournal,
|
||||
onEdit: handleEditJournal,
|
||||
onViewDetails: handleViewDetailJournal,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,20 +30,19 @@ function ManualJournalsTable({
|
||||
|
||||
<DashboardPageContent>
|
||||
<ManualJournalsViewTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<ManualJournalsDataTable />
|
||||
</DashboardContentTable>
|
||||
|
||||
<ManualJournalsAlerts />
|
||||
<ManualJournalsDataTable />
|
||||
</DashboardPageContent>
|
||||
|
||||
<ManualJournalsAlerts />
|
||||
</ManualJournalsListProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withManualJournals(({ manualJournalsTableState, manualJournalTableStateChanged }) => ({
|
||||
journalsTableState: manualJournalsTableState,
|
||||
journalsTableStateChanged: manualJournalTableStateChanged,
|
||||
})),
|
||||
withManualJournals(
|
||||
({ manualJournalsTableState, manualJournalTableStateChanged }) => ({
|
||||
journalsTableState: manualJournalsTableState,
|
||||
journalsTableStateChanged: manualJournalTableStateChanged,
|
||||
}),
|
||||
),
|
||||
)(ManualJournalsTable);
|
||||
|
||||
15
client/src/containers/Authentication/AuthenticationBoot.js
Normal file
15
client/src/containers/Authentication/AuthenticationBoot.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import * as R from 'ramda';
|
||||
|
||||
import withDashboardActions from '../../containers/Dashboard/withDashboardActions';
|
||||
|
||||
function AuthenticationBootJSX({ setAppIsLoading }) {
|
||||
React.useEffect(() => {
|
||||
setAppIsLoading(false);
|
||||
}, [setAppIsLoading]);
|
||||
|
||||
return null;
|
||||
}
|
||||
export const AuthenticationBoot = R.compose(withDashboardActions)(
|
||||
AuthenticationBootJSX,
|
||||
);
|
||||
@@ -20,18 +20,20 @@ export default function Login() {
|
||||
loginMutate({
|
||||
crediential: values.crediential,
|
||||
password: values.password,
|
||||
})
|
||||
.then(() => {
|
||||
setSubmitting(false);
|
||||
})
|
||||
.catch(({ response: { data: { errors } } }) => {
|
||||
}).catch(
|
||||
({
|
||||
response: {
|
||||
data: { errors },
|
||||
},
|
||||
}) => {
|
||||
const toastBuilders = transformLoginErrorsToToasts(errors);
|
||||
|
||||
toastBuilders.forEach((builder) => {
|
||||
Toaster.show(builder);
|
||||
});
|
||||
setSubmitting(false);
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -66,4 +68,4 @@ export default function Login() {
|
||||
</div>
|
||||
</AuthInsider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { Formik } from 'formik';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
import {
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
import { FormattedMessage as T } from 'components';
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import AuthInsider from 'containers/Authentication/AuthInsider';
|
||||
import { useAuthLogin, useAuthRegister } from '../../hooks/query/authentication';
|
||||
import {
|
||||
useAuthLogin,
|
||||
useAuthRegister,
|
||||
} from '../../hooks/query/authentication';
|
||||
|
||||
import RegisterForm from './RegisterForm';
|
||||
import { RegisterSchema, transformRegisterErrorsToForm } from './utils';
|
||||
@@ -18,11 +19,9 @@ import { RegisterSchema, transformRegisterErrorsToForm } from './utils';
|
||||
* Register form.
|
||||
*/
|
||||
export default function RegisterUserForm() {
|
||||
const history = useHistory();
|
||||
const { mutateAsync: authLoginMutate } = useAuthLogin();
|
||||
const { mutateAsync: authRegisterMutate } = useAuthRegister();
|
||||
|
||||
const { mutateAsync: authLoginMutate } = useAuthLogin();
|
||||
const { mutateAsync: authRegisterMutate } = useAuthRegister();
|
||||
|
||||
const initialValues = useMemo(
|
||||
() => ({
|
||||
first_name: '',
|
||||
@@ -41,26 +40,33 @@ export default function RegisterUserForm() {
|
||||
authLoginMutate({
|
||||
crediential: values.email,
|
||||
password: values.password,
|
||||
})
|
||||
.then(() => {
|
||||
history.push('/register/subscription');
|
||||
setSubmitting(false);
|
||||
})
|
||||
.catch(({ response: { data: { errors } } }) => {
|
||||
}).catch(
|
||||
({
|
||||
response: {
|
||||
data: { errors },
|
||||
},
|
||||
}) => {
|
||||
AppToaster.show({
|
||||
message: intl.get('something_wentwrong'),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
})
|
||||
.catch(({ response: { data: { errors } } }) => {
|
||||
const formErrors = transformRegisterErrorsToForm(errors);
|
||||
.catch(
|
||||
({
|
||||
response: {
|
||||
data: { errors },
|
||||
},
|
||||
}) => {
|
||||
const formErrors = transformRegisterErrorsToForm(errors);
|
||||
|
||||
setErrors(formErrors);
|
||||
setSubmitting(false);
|
||||
});
|
||||
setErrors(formErrors);
|
||||
setSubmitting(false);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<AuthInsider>
|
||||
<div className={'register-form'}>
|
||||
@@ -83,4 +89,4 @@ export default function RegisterUserForm() {
|
||||
</div>
|
||||
</AuthInsider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { isAuthenticated } from 'store/authentication/authentication.reducer'
|
||||
import { isAuthenticated } from 'store/authentication/authentication.reducer';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
export default (mapState) => {
|
||||
const mapStateToProps = (state, props) => {
|
||||
const mapped = {
|
||||
isAuthorized: isAuthenticated(state),
|
||||
user: state.authentication.user,
|
||||
authenticatedUserId: state.authentication.userId,
|
||||
currentOrganizationId: state.authentication?.organizationId,
|
||||
currentTenantId: state.authentication?.tenantId,
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
return connect(mapStateToProps);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -47,10 +47,7 @@ function CustomersList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<CustomersViewsTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<CustomersTable />
|
||||
</DashboardContentTable>
|
||||
<CustomersTable />
|
||||
</DashboardPageContent>
|
||||
<CustomersAlerts />
|
||||
</CustomersListProvider>
|
||||
|
||||
@@ -5,7 +5,7 @@ import CustomersEmptyStatus from './CustomersEmptyStatus';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
import { DataTable, DashboardContentTable } from 'components';
|
||||
|
||||
import withCustomers from './withCustomers';
|
||||
import withCustomersActions from './withCustomersActions';
|
||||
@@ -100,37 +100,39 @@ function CustomersTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={customers}
|
||||
initialState={customersTableState}
|
||||
loading={isCustomersLoading}
|
||||
headerLoading={isCustomersLoading}
|
||||
progressBarLoading={isCustomersFetching}
|
||||
onFetchData={handleFetchData}
|
||||
selectionColumn={true}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
spinnerProps={{ size: 30 }}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
payload={{
|
||||
onDelete: handleCustomerDelete,
|
||||
onEdit: handleCustomerEdit,
|
||||
onDuplicate: handleContactDuplicate,
|
||||
onInactivate: handleInactiveCustomer,
|
||||
onActivate: handleActivateCustomer,
|
||||
onViewDetails: handleViewDetailCustomer,
|
||||
}}
|
||||
ContextMenu={ActionsMenu}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={customers}
|
||||
initialState={customersTableState}
|
||||
loading={isCustomersLoading}
|
||||
headerLoading={isCustomersLoading}
|
||||
progressBarLoading={isCustomersFetching}
|
||||
onFetchData={handleFetchData}
|
||||
selectionColumn={true}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
spinnerProps={{ size: 30 }}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
payload={{
|
||||
onDelete: handleCustomerDelete,
|
||||
onEdit: handleCustomerEdit,
|
||||
onDuplicate: handleContactDuplicate,
|
||||
onInactivate: handleInactiveCustomer,
|
||||
onActivate: handleActivateCustomer,
|
||||
onViewDetails: handleViewDetailCustomer,
|
||||
}}
|
||||
ContextMenu={ActionsMenu}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ export default (mapState) => {
|
||||
sidebarExpended: state.dashboard.sidebarExpended,
|
||||
preferencesPageTitle: state.dashboard.preferencesPageTitle,
|
||||
dashboardBackLink: state.dashboard.backLink,
|
||||
appIsLoading: state.dashboard.appIsLoading,
|
||||
appIntlIsLoading: state.dashboard.appIntlIsLoading
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,8 @@ import { connect } from 'react-redux';
|
||||
import t from 'store/types';
|
||||
import {
|
||||
toggleExpendSidebar,
|
||||
appIsLoading,
|
||||
appIntlIsLoading
|
||||
} from 'store/dashboard/dashboard.actions';
|
||||
|
||||
const mapActionsToProps = (dispatch) => ({
|
||||
@@ -55,6 +57,8 @@ const mapActionsToProps = (dispatch) => ({
|
||||
type: t.SET_DASHBOARD_BACK_LINK,
|
||||
payload: { backLink },
|
||||
}),
|
||||
setAppIsLoading: (isLoading) => dispatch(appIsLoading(isLoading)),
|
||||
setAppIntlIsLoading: (isLoading) => dispatch(appIntlIsLoading(isLoading)),
|
||||
});
|
||||
|
||||
export default connect(null, mapActionsToProps);
|
||||
|
||||
@@ -35,8 +35,12 @@ function PaymentViaLicenseDialogContent({
|
||||
const handleSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
setSubmitting(true);
|
||||
|
||||
const mutateValues = {
|
||||
plan_slug: `${values.plan_slug}-${values.period}ly`,
|
||||
license_code: values.license_code,
|
||||
};
|
||||
// Payment via voucher mutate.
|
||||
paymentViaVoucherMutate({ ...values })
|
||||
paymentViaVoucherMutate({ ...mutateValues })
|
||||
.then(() => {
|
||||
Toaster.show({
|
||||
message: intl.get('payment_via_voucher.success_message'),
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useHistory } from 'react-router-dom';
|
||||
import { compose } from 'utils';
|
||||
import { useExpensesListContext } from './ExpensesListProvider';
|
||||
|
||||
import { DashboardContentTable } from 'components';
|
||||
import DataTable from 'components/DataTable';
|
||||
import ExpensesEmptyStatus from './ExpensesEmptyStatus';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
@@ -84,32 +85,34 @@ function ExpensesDataTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={expenses}
|
||||
loading={isExpensesLoading}
|
||||
headerLoading={isExpensesLoading}
|
||||
progressBarLoading={isExpensesFetching}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onFetchData={handleFetchData}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onPublish: handlePublishExpense,
|
||||
onDelete: handleDeleteExpense,
|
||||
onEdit: handleEditExpense,
|
||||
onViewDetails: handleViewDetailExpense,
|
||||
}}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={expenses}
|
||||
loading={isExpensesLoading}
|
||||
headerLoading={isExpensesLoading}
|
||||
progressBarLoading={isExpensesFetching}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
onFetchData={handleFetchData}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onPublish: handlePublishExpense,
|
||||
onDelete: handleDeleteExpense,
|
||||
onEdit: handleEditExpense,
|
||||
onViewDetails: handleViewDetailExpense,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,10 +47,7 @@ function ExpensesList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<ExpenseViewTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<ExpenseDataTable />
|
||||
</DashboardContentTable>
|
||||
<ExpenseDataTable />
|
||||
</DashboardPageContent>
|
||||
|
||||
<ExpensesAlerts />
|
||||
|
||||
@@ -12,8 +12,8 @@ import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import { APAgingSummaryProvider } from './APAgingSummaryProvider';
|
||||
import { APAgingSummarySheetLoadingBar } from './components';
|
||||
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withAPAgingSummaryActions from './withAPAgingSummaryActions'
|
||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||
import withAPAgingSummaryActions from './withAPAgingSummaryActions';
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
@@ -51,9 +51,12 @@ function APAgingSummary({
|
||||
};
|
||||
|
||||
// Hide the report filter drawer once the page unmount.
|
||||
useEffect(() => () => {
|
||||
toggleDisplayFilterDrawer(false);
|
||||
}, [toggleDisplayFilterDrawer])
|
||||
useEffect(
|
||||
() => () => {
|
||||
toggleDisplayFilterDrawer(false);
|
||||
},
|
||||
[toggleDisplayFilterDrawer],
|
||||
);
|
||||
|
||||
return (
|
||||
<APAgingSummaryProvider filter={filter}>
|
||||
@@ -79,8 +82,8 @@ function APAgingSummary({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings?.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization?.name,
|
||||
})),
|
||||
withAPAgingSummaryActions
|
||||
withAPAgingSummaryActions,
|
||||
)(APAgingSummary);
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ARAgingSummaryProvider } from './ARAgingSummaryProvider';
|
||||
import { ARAgingSummarySheetLoadingBar } from './components';
|
||||
|
||||
import withARAgingSummaryActions from './withARAgingSummaryActions'
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
@@ -77,8 +77,8 @@ function ReceivableAgingSummarySheet({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
withARAgingSummaryActions
|
||||
)(ReceivableAgingSummarySheet);
|
||||
|
||||
@@ -10,7 +10,7 @@ import { BalanceSheetAlerts, BalanceSheetLoadingBar } from './components';
|
||||
import { FinancialStatement } from 'components';
|
||||
|
||||
import withBalanceSheetActions from './withBalanceSheetActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||
import { BalanceSheetProvider } from './BalanceSheetProvider';
|
||||
|
||||
import { compose } from 'utils';
|
||||
@@ -23,7 +23,7 @@ function BalanceSheet({
|
||||
organizationName,
|
||||
|
||||
// #withBalanceSheetActions
|
||||
toggleBalanceSheetFilterDrawer
|
||||
toggleBalanceSheetFilterDrawer,
|
||||
}) {
|
||||
const [filter, setFilter] = useState({
|
||||
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
|
||||
@@ -52,9 +52,12 @@ function BalanceSheet({
|
||||
};
|
||||
|
||||
// Hides the balance sheet filter drawer once the page unmount.
|
||||
useEffect(() => () => {
|
||||
toggleBalanceSheetFilterDrawer(false);
|
||||
}, [toggleBalanceSheetFilterDrawer])
|
||||
useEffect(
|
||||
() => () => {
|
||||
toggleBalanceSheetFilterDrawer(false);
|
||||
},
|
||||
[toggleBalanceSheetFilterDrawer],
|
||||
);
|
||||
|
||||
return (
|
||||
<BalanceSheetProvider filter={filter}>
|
||||
@@ -81,8 +84,8 @@ function BalanceSheet({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
withBalanceSheetActions,
|
||||
)(BalanceSheet);
|
||||
|
||||
@@ -9,7 +9,7 @@ import CashFlowStatementHeader from './CashFlowStatementHeader';
|
||||
import CashFlowStatementTable from './CashFlowStatementTable';
|
||||
import CashFlowStatementActionsBar from './CashFlowStatementActionsBar';
|
||||
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||
import withCashFlowStatementActions from './withCashFlowStatementActions';
|
||||
import { CashFlowStatementProvider } from './CashFlowStatementProvider';
|
||||
import {
|
||||
@@ -85,8 +85,8 @@ function CashFlowStatement({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings?.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
withCashFlowStatementActions,
|
||||
)(CashFlowStatement);
|
||||
|
||||
@@ -13,8 +13,7 @@ import CustomersBalanceSummaryTable from './CustomersBalanceSummaryTable';
|
||||
import { CustomersBalanceLoadingBar } from './components';
|
||||
import { CustomersBalanceSummaryProvider } from './CustomersBalanceSummaryProvider';
|
||||
import withCustomersBalanceSummaryActions from './withCustomersBalanceSummaryActions';
|
||||
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||
|
||||
import { compose } from 'redux';
|
||||
|
||||
@@ -81,8 +80,8 @@ function CustomersBalanceSummary({
|
||||
);
|
||||
}
|
||||
export default compose(
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
withCustomersBalanceSummaryActions,
|
||||
)(CustomersBalanceSummary);
|
||||
|
||||
@@ -10,7 +10,7 @@ import CustomersTransactionsTable from './CustomersTransactionsTable';
|
||||
import CustomersTransactionsActionsBar from './CustomersTransactionsActionsBar';
|
||||
|
||||
import withCustomersTransactionsActions from './withCustomersTransactionsActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||
import { CustomersTransactionsLoadingBar } from './components';
|
||||
import { CustomersTransactionsProvider } from './CustomersTransactionsProvider';
|
||||
|
||||
@@ -81,8 +81,8 @@ function CustomersTransactions({
|
||||
);
|
||||
}
|
||||
export default compose(
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
withCustomersTransactionsActions,
|
||||
)(CustomersTransactions);
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from './components';
|
||||
|
||||
import withGeneralLedgerActions from './withGeneralLedgerActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||
|
||||
import { transformFilterFormToQuery } from 'containers/FinancialStatements/common';
|
||||
import { compose } from 'utils';
|
||||
@@ -85,7 +85,7 @@ function GeneralLedger({
|
||||
|
||||
export default compose(
|
||||
withGeneralLedgerActions,
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
)(GeneralLedger);
|
||||
|
||||
@@ -10,7 +10,7 @@ import InventoryItemDetailsHeader from './InventoryItemDetailsHeader';
|
||||
import InventoryItemDetailsTable from './InventoryItemDetailsTable';
|
||||
|
||||
import withInventoryItemDetailsActions from './withInventoryItemDetailsActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||
import { InventoryItemDetailsProvider } from './InventoryItemDetailsProvider';
|
||||
import {
|
||||
InventoryItemDetailsLoadingBar,
|
||||
@@ -84,8 +84,8 @@ function InventoryItemDetails({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings?.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
withInventoryItemDetailsActions,
|
||||
)(InventoryItemDetails);
|
||||
|
||||
@@ -11,7 +11,7 @@ import InventoryValuationTable from './InventoryValuationTable';
|
||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import { InventoryValuationLoadingBar } from './components';
|
||||
import withInventoryValuationActions from './withInventoryValuationActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
@@ -80,7 +80,7 @@ function InventoryValuation({
|
||||
|
||||
export default compose(
|
||||
withInventoryValuationActions,
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings?.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
)(InventoryValuation);
|
||||
|
||||
@@ -11,7 +11,7 @@ import JournalActionsBar from './JournalActionsBar';
|
||||
import { JournalSheetProvider } from './JournalProvider';
|
||||
import { JournalSheetLoadingBar, JournalSheetAlerts } from './components';
|
||||
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withJournalActions from './withJournalActions';
|
||||
|
||||
@@ -79,7 +79,7 @@ function Journal({
|
||||
export default compose(
|
||||
withDashboardActions,
|
||||
withJournalActions,
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
)(Journal);
|
||||
|
||||
@@ -10,7 +10,7 @@ import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withProfitLossActions from './withProfitLossActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||
|
||||
import 'style/pages/FinancialStatements/ProfitLossSheet.scss';
|
||||
import { ProfitLossSheetProvider } from './ProfitLossProvider';
|
||||
@@ -91,7 +91,7 @@ function ProfitLossSheet({
|
||||
export default compose(
|
||||
withDashboardActions,
|
||||
withProfitLossActions,
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
)(ProfitLossSheet);
|
||||
|
||||
@@ -11,7 +11,7 @@ import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import { PurchasesByItemsLoadingBar } from './components';
|
||||
|
||||
import withPurchasesByItemsActions from './withPurchasesByItemsActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
@@ -82,7 +82,7 @@ function PurchasesByItems({
|
||||
|
||||
export default compose(
|
||||
withPurchasesByItemsActions,
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
)(PurchasesByItems);
|
||||
|
||||
@@ -13,7 +13,7 @@ import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import { SalesByItemsLoadingBar } from './components';
|
||||
|
||||
import withSalesByItemsActions from './withSalesByItemsActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
@@ -84,7 +84,7 @@ function SalesByItems({
|
||||
|
||||
export default compose(
|
||||
withSalesByItemsActions,
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
)(SalesByItems);
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from './components';
|
||||
|
||||
import withTrialBalanceActions from './withTrialBalanceActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
@@ -91,7 +91,7 @@ function TrialBalanceSheet({
|
||||
|
||||
export default compose(
|
||||
withTrialBalanceActions,
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
)(TrialBalanceSheet);
|
||||
|
||||
@@ -14,7 +14,7 @@ import { VendorsBalanceSummaryProvider } from './VendorsBalanceSummaryProvider';
|
||||
import { VendorsSummarySheetLoadingBar } from './components';
|
||||
import withVendorsBalanceSummaryActions from './withVendorsBalanceSummaryActions';
|
||||
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
@@ -82,8 +82,8 @@ function VendorsBalanceSummary({
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings?.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
withVendorsBalanceSummaryActions,
|
||||
)(VendorsBalanceSummary);
|
||||
|
||||
@@ -10,7 +10,7 @@ import VendorsTransactionsActionsBar from './VendorsTransactionsActionsBar';
|
||||
import VendorsTransactionsTable from './VendorsTransactionsTable';
|
||||
|
||||
import withVendorsTransactionsActions from './withVendorsTransactionsActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||
|
||||
import { VendorsTransactionsProvider } from './VendorsTransactionsProvider';
|
||||
import { VendorsTransactionsLoadingBar } from './components';
|
||||
@@ -81,8 +81,8 @@ function VendorsTransactions({
|
||||
);
|
||||
}
|
||||
export default compose(
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationName: organizationSettings.name,
|
||||
withCurrentOrganization(({ organization }) => ({
|
||||
organizationName: organization.name,
|
||||
})),
|
||||
withVendorsTransactionsActions,
|
||||
)(VendorsTransactions);
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { FormattedMessage as T } from 'components';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
import { DashboardContentTable, DataTable } from 'components';
|
||||
|
||||
import ItemsEmptyStatus from './ItemsEmptyStatus';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
@@ -108,41 +108,43 @@ function ItemsDataTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={items}
|
||||
initialState={itemsTableState}
|
||||
loading={isItemsLoading}
|
||||
headerLoading={isItemsLoading}
|
||||
progressBarLoading={isItemsFetching}
|
||||
noInitialFetch={true}
|
||||
selectionColumn={true}
|
||||
spinnerProps={{ size: 30 }}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
rowClassNames={rowClassNames}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={true}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ItemsActionMenuList}
|
||||
onFetchData={handleFetchData}
|
||||
payload={{
|
||||
onDeleteItem: handleDeleteItem,
|
||||
onEditItem: handleEditItem,
|
||||
onInactivateItem: handleInactiveItem,
|
||||
onActivateItem: handleActivateItem,
|
||||
onMakeAdjustment: handleMakeAdjustment,
|
||||
onDuplicate: handleDuplicate,
|
||||
onViewDetails: handleViewDetailItem,
|
||||
}}
|
||||
noResults={<T id={'there_is_no_items_in_the_table_yet'} />}
|
||||
{...tableProps}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={items}
|
||||
initialState={itemsTableState}
|
||||
loading={isItemsLoading}
|
||||
headerLoading={isItemsLoading}
|
||||
progressBarLoading={isItemsFetching}
|
||||
noInitialFetch={true}
|
||||
selectionColumn={true}
|
||||
spinnerProps={{ size: 30 }}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
rowClassNames={rowClassNames}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={true}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ItemsActionMenuList}
|
||||
onFetchData={handleFetchData}
|
||||
payload={{
|
||||
onDeleteItem: handleDeleteItem,
|
||||
onEditItem: handleEditItem,
|
||||
onInactivateItem: handleInactiveItem,
|
||||
onActivateItem: handleActivateItem,
|
||||
onMakeAdjustment: handleMakeAdjustment,
|
||||
onDuplicate: handleDuplicate,
|
||||
onViewDetails: handleViewDetailItem,
|
||||
}}
|
||||
noResults={<T id={'there_is_no_items_in_the_table_yet'} />}
|
||||
{...tableProps}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function ItemsEmptyStatus() {
|
||||
</Button>
|
||||
|
||||
<Button intent={Intent.NONE} large={true}>
|
||||
<T id={'learn_more'}/>
|
||||
<T id={'learn_more'} />
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { compose } from 'utils';
|
||||
|
||||
import 'style/pages/Items/List.scss';
|
||||
|
||||
import { DashboardContentTable, DashboardPageContent } from 'components';
|
||||
import { DashboardPageContent } from 'components';
|
||||
|
||||
import ItemsActionsBar from './ItemsActionsBar';
|
||||
import ItemsAlerts from './ItemsAlerts';
|
||||
@@ -43,10 +43,7 @@ function ItemsList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<ItemsViewsTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<ItemsDataTable />
|
||||
</DashboardContentTable>
|
||||
<ItemsDataTable />
|
||||
</DashboardPageContent>
|
||||
|
||||
<ItemsAlerts />
|
||||
|
||||
@@ -51,6 +51,11 @@ function GeneralFormPage({
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
setSubmitting(false);
|
||||
|
||||
// Reboot the application if the application's language is mutated.
|
||||
if (organization.language !== values.language) {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
// Handle request error.
|
||||
const onError = (errors) => {
|
||||
|
||||
@@ -47,10 +47,7 @@ function BillsList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<BillsViewsTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<BillsTable />
|
||||
</DashboardContentTable>
|
||||
<BillsTable />
|
||||
</DashboardPageContent>
|
||||
|
||||
<BillsAlerts />
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useHistory } from 'react-router-dom';
|
||||
import { compose } from 'utils';
|
||||
|
||||
import DataTable from 'components/DataTable';
|
||||
import { DashboardContentTable } from 'components';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||
|
||||
@@ -92,6 +93,7 @@ function BillsDataTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={bills}
|
||||
@@ -118,6 +120,7 @@ function BillsDataTable({
|
||||
onViewDetails: handleViewDetailBill,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,10 +42,7 @@ function PaymentMadeList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<PaymentMadeViewTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<PaymentMadesTable />
|
||||
</DashboardContentTable>
|
||||
<PaymentMadesTable />
|
||||
</DashboardPageContent>
|
||||
|
||||
<PaymentMadesAlerts />
|
||||
|
||||
@@ -3,7 +3,8 @@ import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
import { DataTable, DashboardContentTable } from 'components';
|
||||
|
||||
import PaymentMadesEmptyStatus from './PaymentMadesEmptyStatus';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||
@@ -76,31 +77,33 @@ function PaymentMadesTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={paymentMades}
|
||||
initialState={paymentMadesTableState}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
loading={isPaymentsLoading}
|
||||
headerLoading={isPaymentsLoading}
|
||||
progressBarLoading={isPaymentsFetching}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onEdit: handleEditPaymentMade,
|
||||
onDelete: handleDeletePaymentMade,
|
||||
onViewDetails: handleViewDetailPaymentMade,
|
||||
}}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={paymentMades}
|
||||
initialState={paymentMadesTableState}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
loading={isPaymentsLoading}
|
||||
headerLoading={isPaymentsLoading}
|
||||
progressBarLoading={isPaymentsFetching}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onEdit: handleEditPaymentMade,
|
||||
onDelete: handleDeletePaymentMade,
|
||||
onViewDetails: handleViewDetailPaymentMade,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
import { DataTable, DashboardContentTable } from 'components';
|
||||
import EstimatesEmptyStatus from './EstimatesEmptyStatus';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||
@@ -109,35 +109,37 @@ function EstimatesDataTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={estimates}
|
||||
loading={isEstimatesLoading}
|
||||
headerLoading={isEstimatesLoading}
|
||||
progressBarLoading={isEstimatesFetching}
|
||||
onFetchData={handleFetchData}
|
||||
noInitialFetch={true}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onApprove: handleApproveEstimate,
|
||||
onEdit: handleEditEstimate,
|
||||
onReject: handleRejectEstimate,
|
||||
onDeliver: handleDeliverEstimate,
|
||||
onDelete: handleDeleteEstimate,
|
||||
onDrawer: handleDrawerEstimate,
|
||||
onConvert: handleConvertToInvoice,
|
||||
onViewDetails: handleViewDetailEstimate,
|
||||
onPrint: handlePrintEstimate,
|
||||
}}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={estimates}
|
||||
loading={isEstimatesLoading}
|
||||
headerLoading={isEstimatesLoading}
|
||||
progressBarLoading={isEstimatesFetching}
|
||||
onFetchData={handleFetchData}
|
||||
noInitialFetch={true}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onApprove: handleApproveEstimate,
|
||||
onEdit: handleEditEstimate,
|
||||
onReject: handleRejectEstimate,
|
||||
onDeliver: handleDeliverEstimate,
|
||||
onDelete: handleDeleteEstimate,
|
||||
onDrawer: handleDrawerEstimate,
|
||||
onConvert: handleConvertToInvoice,
|
||||
onViewDetails: handleViewDetailEstimate,
|
||||
onPrint: handlePrintEstimate,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,10 +42,7 @@ function EstimatesList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<EstimatesViewTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<EstimatesDataTable />
|
||||
</DashboardContentTable>
|
||||
<EstimatesDataTable />
|
||||
</DashboardPageContent>
|
||||
|
||||
<EstimatesAlerts />
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useHistory } from 'react-router-dom';
|
||||
import InvoicesEmptyStatus from './InvoicesEmptyStatus';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import { DataTable } from 'components';
|
||||
import { DataTable, DashboardContentTable } from 'components';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||
|
||||
@@ -108,37 +108,39 @@ function InvoicesDataTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={invoices}
|
||||
initialState={invoicesTableState}
|
||||
loading={isInvoicesLoading}
|
||||
headerLoading={isInvoicesLoading}
|
||||
progressBarLoading={isInvoicesFetching}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onDelete: handleDeleteInvoice,
|
||||
onDeliver: handleDeliverInvoice,
|
||||
onEdit: handleEditInvoice,
|
||||
onDrawer: handleDrawerInvoice,
|
||||
onQuick: handleQuickPaymentReceive,
|
||||
onViewDetails: handleViewDetailInvoice,
|
||||
onPrint: handlePrintInvoice,
|
||||
baseCurrency,
|
||||
}}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={invoices}
|
||||
initialState={invoicesTableState}
|
||||
loading={isInvoicesLoading}
|
||||
headerLoading={isInvoicesLoading}
|
||||
progressBarLoading={isInvoicesFetching}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
manualPagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onDelete: handleDeleteInvoice,
|
||||
onDeliver: handleDeliverInvoice,
|
||||
onEdit: handleEditInvoice,
|
||||
onDrawer: handleDrawerInvoice,
|
||||
onQuick: handleQuickPaymentReceive,
|
||||
onViewDetails: handleViewDetailInvoice,
|
||||
onPrint: handlePrintInvoice,
|
||||
baseCurrency,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,10 +44,7 @@ function InvoicesList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<InvoiceViewTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<InvoicesDataTable />
|
||||
</DashboardContentTable>
|
||||
<InvoicesDataTable />
|
||||
</DashboardPageContent>
|
||||
|
||||
<InvoicesAlerts />
|
||||
|
||||
@@ -42,10 +42,7 @@ function PaymentReceiveList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<PaymentReceiveViewTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<PaymentReceivesTable />
|
||||
</DashboardContentTable>
|
||||
<PaymentReceivesTable />
|
||||
</DashboardPageContent>
|
||||
|
||||
<PaymentReceiveAlerts />
|
||||
|
||||
@@ -3,8 +3,8 @@ import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
import { DataTable, DashboardContentTable } from 'components';
|
||||
import PaymentReceivesEmptyStatus from './PaymentReceivesEmptyStatus';
|
||||
import { DataTable } from 'components';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||
|
||||
@@ -85,32 +85,34 @@ function PaymentReceivesDataTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={paymentReceives}
|
||||
initialState={paymentReceivesTableState}
|
||||
loading={isPaymentReceivesLoading}
|
||||
headerLoading={isPaymentReceivesLoading}
|
||||
progressBarLoading={isPaymentReceivesFetching}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
pagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onDelete: handleDeletePaymentReceive,
|
||||
onEdit: handleEditPaymentReceive,
|
||||
onDrawer: handleDrawerPaymentReceive,
|
||||
onViewDetails: handleViewDetailPaymentReceive,
|
||||
}}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={paymentReceives}
|
||||
initialState={paymentReceivesTableState}
|
||||
loading={isPaymentReceivesLoading}
|
||||
headerLoading={isPaymentReceivesLoading}
|
||||
progressBarLoading={isPaymentReceivesFetching}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
pagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onDelete: handleDeletePaymentReceive,
|
||||
onEdit: handleEditPaymentReceive,
|
||||
onDrawer: handleDrawerPaymentReceive,
|
||||
onViewDetails: handleViewDetailPaymentReceive,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,10 +43,7 @@ function ReceiptsList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<ReceiptViewTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<ReceiptsTable />
|
||||
</DashboardContentTable>
|
||||
<ReceiptsTable />
|
||||
</DashboardPageContent>
|
||||
|
||||
<ReceiptsAlerts />
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useCallback } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import { DataTable } from 'components';
|
||||
import { DataTable, DashboardContentTable } from 'components';
|
||||
|
||||
import ReceiptsEmptyStatus from './ReceiptsEmptyStatus';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
@@ -101,36 +101,38 @@ function ReceiptsDataTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={receipts}
|
||||
initialState={receiptTableState}
|
||||
loading={isReceiptsLoading}
|
||||
headerLoading={isReceiptsLoading}
|
||||
progressBarLoading={isReceiptsFetching}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
manualPagination={true}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onEdit: handleEditReceipt,
|
||||
onDelete: handleDeleteReceipt,
|
||||
onClose: handleCloseReceipt,
|
||||
onDrawer: handleDrawerReceipt,
|
||||
onViewDetails: handleViewDetailReceipt,
|
||||
onPrint: handlePrintInvoice,
|
||||
baseCurrency,
|
||||
}}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={receipts}
|
||||
initialState={receiptTableState}
|
||||
loading={isReceiptsLoading}
|
||||
headerLoading={isReceiptsLoading}
|
||||
progressBarLoading={isReceiptsFetching}
|
||||
onFetchData={handleDataTableFetchData}
|
||||
manualSortBy={true}
|
||||
selectionColumn={true}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
manualPagination={true}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onEdit: handleEditReceipt,
|
||||
onDelete: handleDeleteReceipt,
|
||||
onClose: handleCloseReceipt,
|
||||
onDrawer: handleDrawerReceipt,
|
||||
onViewDetails: handleViewDetailReceipt,
|
||||
onPrint: handlePrintInvoice,
|
||||
baseCurrency,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React from 'react';
|
||||
import { Button, Intent } from '@blueprintjs/core';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import WorkflowIcon from './WorkflowIcon';
|
||||
import { FormattedMessage as T } from 'components';
|
||||
@@ -10,17 +9,16 @@ import { compose } from 'utils';
|
||||
|
||||
import 'style/pages/Setup/Congrats.scss';
|
||||
|
||||
|
||||
/**
|
||||
* Setup congrats page.
|
||||
*/
|
||||
function SetupCongratsPage({ setOrganizationSetupCompleted }) {
|
||||
const history = useHistory();
|
||||
const [isReloading, setIsReloading] = React.useState(false);
|
||||
|
||||
const handleBtnClick = useCallback(() => {
|
||||
setOrganizationSetupCompleted(false);
|
||||
history.push('/homepage');
|
||||
}, [setOrganizationSetupCompleted, history]);
|
||||
const handleBtnClick = () => {
|
||||
setIsReloading(true);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="setup-congrats">
|
||||
@@ -37,7 +35,12 @@ function SetupCongratsPage({ setOrganizationSetupCompleted }) {
|
||||
<T id={'setup.congrats.description'} />
|
||||
</p>
|
||||
|
||||
<Button intent={Intent.PRIMARY} type="submit" onClick={handleBtnClick}>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
loading={isReloading}
|
||||
onClick={handleBtnClick}
|
||||
>
|
||||
<T id={'setup.congrats.go_to_dashboard'} />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -20,10 +20,12 @@ function SetupInitializingForm({
|
||||
}) {
|
||||
const { refetch, isSuccess } = useCurrentOrganization({ enabled: false });
|
||||
|
||||
// Job done state.
|
||||
const [isJobDone, setIsJobDone] = React.useState(false);
|
||||
|
||||
const {
|
||||
data: { running, queued, failed, completed },
|
||||
isFetching: isJobFetching,
|
||||
} = useJob(organization?.build_job_id, {
|
||||
refetchInterval: 2000,
|
||||
enabled: !!organization?.build_job_id,
|
||||
@@ -45,17 +47,15 @@ function SetupInitializingForm({
|
||||
|
||||
return (
|
||||
<div class="setup-initializing-form">
|
||||
<ProgressBar intent={Intent.PRIMARY} value={null} />
|
||||
|
||||
<div className={'setup-initializing-form__title'}>
|
||||
{failed ? (
|
||||
<SetupInitializingFailed />
|
||||
) : running || queued ? (
|
||||
<SetupInitializingRunning />
|
||||
) : completed ? (
|
||||
<SetupInitializingCompleted />
|
||||
) : null}
|
||||
</div>
|
||||
{failed ? (
|
||||
<SetupInitializingFailed />
|
||||
) : running || queued || isJobFetching ? (
|
||||
<SetupInitializingRunning />
|
||||
) : completed ? (
|
||||
<SetupInitializingCompleted />
|
||||
) : (
|
||||
<SetupInitializingFailed />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -68,41 +68,60 @@ export default R.compose(
|
||||
withOrganization(({ organization }) => ({ organization })),
|
||||
)(SetupInitializingForm);
|
||||
|
||||
/**
|
||||
* State initializing failed state.
|
||||
*/
|
||||
function SetupInitializingFailed() {
|
||||
return (
|
||||
<div class="failed">
|
||||
<h1>
|
||||
<T id={'setup.initializing.something_went_wrong'} />
|
||||
</h1>
|
||||
<p class="paragraph">
|
||||
<T id={'setup.initializing.please_refresh_the_page'} />
|
||||
</p>
|
||||
<div class="setup-initializing__content">
|
||||
<div className={'setup-initializing-form__title'}>
|
||||
<h1>
|
||||
<T id={'setup.initializing.something_went_wrong'} />
|
||||
</h1>
|
||||
<p class="paragraph">
|
||||
<T id={'setup.initializing.please_refresh_the_page'} />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup initializing running state.
|
||||
*/
|
||||
function SetupInitializingRunning() {
|
||||
return (
|
||||
<div class="running">
|
||||
<h1>
|
||||
<T id={'setup.initializing.title'} />
|
||||
</h1>
|
||||
<p className={'paragraph'}>
|
||||
<T id={'setup.initializing.description'} />
|
||||
</p>
|
||||
<div class="setup-initializing__content">
|
||||
<ProgressBar intent={Intent.PRIMARY} value={null} />
|
||||
|
||||
<div className={'setup-initializing-form__title'}>
|
||||
<h1>
|
||||
<T id={'setup.initializing.title'} />
|
||||
</h1>
|
||||
<p className={'paragraph'}>
|
||||
<T id={'setup.initializing.description'} />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup initializing completed state.
|
||||
*/
|
||||
function SetupInitializingCompleted() {
|
||||
return (
|
||||
<div class="completed">
|
||||
<h1>
|
||||
<T id={'setup.initializing.waiting_to_redirect'} />
|
||||
</h1>
|
||||
<p class="paragraph">
|
||||
<T id={'setup.initializing.refresh_the_page_if_redirect_not_worked'} />
|
||||
</p>
|
||||
<div class="setup-initializing__content">
|
||||
<div className={'setup-initializing-form__title'}>
|
||||
<h1>
|
||||
<T id={'setup.initializing.waiting_to_redirect'} />
|
||||
</h1>
|
||||
<p class="paragraph">
|
||||
<T
|
||||
id={'setup.initializing.refresh_the_page_if_redirect_not_worked'}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import { TimezonePicker } from '@blueprintjs/timezone';
|
||||
import useAutofocus from 'hooks/useAutofocus'
|
||||
import { FormattedMessage as T } from 'components';
|
||||
import { getCountries } from 'common/countries';
|
||||
|
||||
@@ -29,6 +30,8 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
||||
const currencies = getAllCurrenciesOptions();
|
||||
const countries = getCountries();
|
||||
|
||||
const accountRef = useAutofocus();
|
||||
|
||||
return (
|
||||
<Form>
|
||||
<h3>
|
||||
@@ -44,7 +47,11 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'name'} />}
|
||||
>
|
||||
<InputGroup {...field} intent={inputIntent({ error, touched })} />
|
||||
<InputGroup
|
||||
{...field}
|
||||
intent={inputIntent({ error, touched })}
|
||||
inputRef={accountRef}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
@@ -9,7 +9,7 @@ import SetupOrganizationForm from './SetupOrganizationForm';
|
||||
import { useOrganizationSetup } from 'hooks/query';
|
||||
import withSettingsActions from 'containers/Settings/withSettingsActions';
|
||||
|
||||
import { compose, transfromToSnakeCase } from 'utils';
|
||||
import { setCookie, compose, transfromToSnakeCase } from 'utils';
|
||||
import { getSetupOrganizationValidation } from './SetupOrganization.schema';
|
||||
|
||||
// Initial values.
|
||||
@@ -41,6 +41,9 @@ function SetupOrganizationPage({ wizard }) {
|
||||
organizationSetupMutate({ ...transfromToSnakeCase(values) })
|
||||
.then((response) => {
|
||||
setSubmitting(false);
|
||||
|
||||
// Sets locale cookie to next boot cycle.
|
||||
setCookie('locale', values.language);
|
||||
wizard.next();
|
||||
})
|
||||
.catch((erros) => {
|
||||
|
||||
@@ -21,12 +21,12 @@ function SetupSubscription({
|
||||
|
||||
// Initial values.
|
||||
const initialValues = {
|
||||
plan_slug: 'starter',
|
||||
plan_slug: 'essentials',
|
||||
period: 'month',
|
||||
license_code: '',
|
||||
};
|
||||
// Handle form submit.
|
||||
const handleSubmit = () => {};
|
||||
const handleSubmit = (values) => {};
|
||||
|
||||
// Retrieve momerized subscription form schema.
|
||||
const SubscriptionFormSchema = React.useMemo(
|
||||
|
||||
@@ -9,6 +9,10 @@ import withPlan from '../../Subscriptions/withPlan';
|
||||
const SubscriptionPeriodsEnhanced = R.compose(
|
||||
withPlan(({ plan }) => ({ plan })),
|
||||
)(({ plan, ...restProps }) => {
|
||||
// Can't continue if the current plan of the form not selected.
|
||||
if (!plan) {
|
||||
return null;
|
||||
}
|
||||
return <SubscriptionPeriods periods={plan.periods} {...restProps} />;
|
||||
});
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ function BillingForm({
|
||||
|
||||
// Initial values.
|
||||
const initialValues = {
|
||||
plan_slug: 'free',
|
||||
plan_slug: 'essentials',
|
||||
period: 'month',
|
||||
license_code: '',
|
||||
};
|
||||
|
||||
@@ -12,6 +12,8 @@ import withPlan from './withPlan';
|
||||
const SubscriptionPeriodsEnhanced = R.compose(
|
||||
withPlan(({ plan }) => ({ plan })),
|
||||
)(({ plan, ...restProps }) => {
|
||||
if (!plan) return null;
|
||||
|
||||
return <SubscriptionPeriods periods={plan.periods} {...restProps} />;
|
||||
});
|
||||
|
||||
|
||||
@@ -47,13 +47,9 @@ function VendorsList({
|
||||
|
||||
<DashboardPageContent>
|
||||
<VendorViewsTabs />
|
||||
|
||||
<DashboardContentTable>
|
||||
<VendorsTable />
|
||||
</DashboardContentTable>
|
||||
|
||||
<VendorsAlerts />
|
||||
<VendorsTable />
|
||||
</DashboardPageContent>
|
||||
<VendorsAlerts />
|
||||
</VendorsListProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
|
||||
import { DataTable } from 'components';
|
||||
import { DataTable, DashboardContentTable } from 'components';
|
||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||
|
||||
@@ -85,7 +85,7 @@ function VendorsTable({
|
||||
const handleViewDetailVendor = ({ id }) => {
|
||||
openDrawer('contact-detail-drawer', { contactId: id });
|
||||
};
|
||||
|
||||
|
||||
// Handle fetch data once the page index, size or sort by of the table change.
|
||||
const handleFetchData = React.useCallback(
|
||||
({ pageSize, pageIndex, sortBy }) => {
|
||||
@@ -104,35 +104,37 @@ function VendorsTable({
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={vendors}
|
||||
initialState={vendorsTableState}
|
||||
loading={isVendorsLoading}
|
||||
headerLoading={isVendorsLoading}
|
||||
progressBarLoading={isVendorsFetching}
|
||||
onFetchData={handleFetchData}
|
||||
selectionColumn={true}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onEdit: handleEditVendor,
|
||||
onDelete: handleDeleteVendor,
|
||||
onDuplicate: handleContactDuplicate,
|
||||
onInactivate: handleInactiveVendor,
|
||||
onActivate: handleActivateVendor,
|
||||
onViewDetails: handleViewDetailVendor,
|
||||
}}
|
||||
/>
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
noInitialFetch={true}
|
||||
columns={columns}
|
||||
data={vendors}
|
||||
initialState={vendorsTableState}
|
||||
loading={isVendorsLoading}
|
||||
headerLoading={isVendorsLoading}
|
||||
progressBarLoading={isVendorsFetching}
|
||||
onFetchData={handleFetchData}
|
||||
selectionColumn={true}
|
||||
expandable={false}
|
||||
sticky={true}
|
||||
pagination={true}
|
||||
manualSortBy={true}
|
||||
pagesCount={pagination.pagesCount}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={ActionsMenu}
|
||||
payload={{
|
||||
onEdit: handleEditVendor,
|
||||
onDelete: handleDeleteVendor,
|
||||
onDuplicate: handleContactDuplicate,
|
||||
onInactivate: handleInactiveVendor,
|
||||
onActivate: handleActivateVendor,
|
||||
onViewDetails: handleViewDetailVendor,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,37 @@
|
||||
import { useMutation } from 'react-query';
|
||||
import useApiRequest from '../useRequest';
|
||||
import { useAuthActions } from '../state';
|
||||
import { persistor } from 'store/createStore';
|
||||
import { setCookie } from '../../utils';
|
||||
|
||||
/**
|
||||
* Saves the response data to cookies.
|
||||
*/
|
||||
function setAuthLoginCookies(data) {
|
||||
setCookie('token', data.token);
|
||||
setCookie('authenticated_user_id', data.user.id);
|
||||
setCookie('organization_id', data.tenant.organization_id);
|
||||
setCookie('tenant_id', data.tenant.id);
|
||||
|
||||
if (data?.tenant?.metadata?.language)
|
||||
setCookie('locale', data.tenant.metadata.language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication login.
|
||||
*/
|
||||
export const useAuthLogin = (props) => {
|
||||
const { setLogin } = useAuthActions();
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation(
|
||||
(values) => apiRequest.post('auth/login', values),
|
||||
{
|
||||
select: (res) => res.data,
|
||||
onSuccess: (data) => {
|
||||
setLogin(data.data);
|
||||
return useMutation((values) => apiRequest.post('auth/login', values), {
|
||||
select: (res) => res.data,
|
||||
onSuccess: (data) => {
|
||||
// Set authentication cookies.
|
||||
setAuthLoginCookies(data.data);
|
||||
|
||||
// Run the store persist.
|
||||
persistor.persist();
|
||||
},
|
||||
...props
|
||||
}
|
||||
);
|
||||
// Reboot the application.
|
||||
window.location.reload();
|
||||
},
|
||||
...props,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -34,7 +43,7 @@ export const useAuthRegister = (props) => {
|
||||
return useMutation(
|
||||
(values) => apiRequest.post('auth/register', values),
|
||||
props,
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -45,9 +54,9 @@ export const useAuthSendResetPassword = (props) => {
|
||||
|
||||
return useMutation(
|
||||
(email) => apiRequest.post('auth/send_reset_password', email),
|
||||
props
|
||||
props,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Authentication reset password.
|
||||
@@ -58,5 +67,5 @@ export const useAuthResetPassword = (props) => {
|
||||
return useMutation(
|
||||
([token, values]) => apiRequest.post(`auth/reset/${token}`, values),
|
||||
props,
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
9
client/src/hooks/query/base.js
Normal file
9
client/src/hooks/query/base.js
Normal file
@@ -0,0 +1,9 @@
|
||||
// Query client config.
|
||||
export const queryConfig = {
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
refetchOnWindowFocus: true,
|
||||
staleTime: 30000,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -112,11 +112,16 @@ export function useUsers(props) {
|
||||
* Retrieve details of the given user.
|
||||
*/
|
||||
export function useUser(id, props) {
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useQueryTenant(
|
||||
return useRequestQuery(
|
||||
[t.USER, id],
|
||||
() => apiRequest.get(`users/${id}`).then((response) => response.data.user),
|
||||
props,
|
||||
{
|
||||
method: 'get',
|
||||
url: `users/${id}`,
|
||||
},
|
||||
{
|
||||
select: (response) => response.data.user,
|
||||
defaultData: {},
|
||||
...props,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,15 @@ import {
|
||||
setStoreReset,
|
||||
} from 'store/authentication/authentication.actions';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { removeCookie } from '../../utils';
|
||||
|
||||
function removeAuthenticationCookies() {
|
||||
removeCookie('token');
|
||||
removeCookie('organization_id');
|
||||
removeCookie('tenant_id');
|
||||
removeCookie('authenticated_user_id');
|
||||
removeCookie('locale');
|
||||
}
|
||||
|
||||
export const useAuthActions = () => {
|
||||
const dispatch = useDispatch();
|
||||
@@ -15,11 +24,15 @@ export const useAuthActions = () => {
|
||||
setLogin: useCallback((login) => dispatch(setLogin(login)), [dispatch]),
|
||||
setLogout: useCallback(() => {
|
||||
// Resets store state.
|
||||
dispatch(setStoreReset());
|
||||
// dispatch(setStoreReset());
|
||||
|
||||
// Remove all cached queries.
|
||||
queryClient.removeQueries();
|
||||
}, [dispatch, queryClient]),
|
||||
|
||||
removeAuthenticationCookies();
|
||||
|
||||
window.location.reload();
|
||||
}, [queryClient]),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -41,12 +54,12 @@ export const useAuthToken = () => {
|
||||
* Retrieve the authentication user.
|
||||
*/
|
||||
export const useAuthUser = () => {
|
||||
return useSelector((state) => state.authentication.user);
|
||||
return useSelector((state) => ({}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the authenticated organization id.
|
||||
*/
|
||||
export const useAuthOrganizationId = () => {
|
||||
return useSelector((state) => state.authentication.organization);
|
||||
return useSelector((state) => state.authentication.organizationId);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import t from 'store/types';
|
||||
|
||||
export const setLogin = ({ user, token, tenant }) => ({
|
||||
type: t.LOGIN_SUCCESS,
|
||||
payload: { user, token, tenant, },
|
||||
});
|
||||
|
||||
export const setLogin = () => ({ type: t.LOGIN_SUCCESS });
|
||||
export const setLogout = () => ({ type: t.LOGOUT });
|
||||
export const setStoreReset = () => ({ type: t.RESET });
|
||||
@@ -2,36 +2,28 @@ import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import purgeStoredState from 'redux-persist/es/purgeStoredState';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import { getCookie, setCookie } from 'utils';
|
||||
import t from 'store/types';
|
||||
import { removeCookie } from '../../utils';
|
||||
|
||||
// Read stored data in cookies and merge it with the initial state.
|
||||
const initialState = {
|
||||
token: '',
|
||||
organization: '',
|
||||
organizationId: null,
|
||||
user: '',
|
||||
tenant: {},
|
||||
locale: '',
|
||||
token: getCookie('token'),
|
||||
organizationId: getCookie('organization_id'),
|
||||
tenantId: getCookie('tenant_id'),
|
||||
userId: getCookie('authenticated_user_id'),
|
||||
locale: getCookie('locale'),
|
||||
errors: [],
|
||||
};
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:authentication';
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
blacklist: ['errors'],
|
||||
whitelist: [],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
[t.LOGIN_SUCCESS]: (state, action) => {
|
||||
const { token, user, tenant } = action.payload;
|
||||
|
||||
state.token = token;
|
||||
state.user = user;
|
||||
state.organization = tenant.organization_id;
|
||||
state.organizationId = tenant.id;
|
||||
state.tenant = tenant;
|
||||
},
|
||||
|
||||
[t.LOGIN_FAILURE]: (state, action) => {
|
||||
state.errors = action.errors;
|
||||
},
|
||||
@@ -40,15 +32,12 @@ const reducerInstance = createReducer(initialState, {
|
||||
state.errors = [];
|
||||
},
|
||||
|
||||
[t.RESET]: () => {
|
||||
[t.RESET]: (state) => {
|
||||
purgeStoredState(CONFIG);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
CONFIG,
|
||||
reducerInstance,
|
||||
);
|
||||
export default persistReducer(CONFIG, reducerInstance);
|
||||
|
||||
export const isAuthenticated = (state) => !!state.authentication.token;
|
||||
export const hasErrorType = (state, errorType) => {
|
||||
@@ -59,4 +48,4 @@ export const isTenantSeeded = (state) => !!state.tenant.seeded_at;
|
||||
export const isTenantBuilt = (state) => !!state.tenant.initialized_at;
|
||||
|
||||
export const isTenantHasSubscription = () => false;
|
||||
export const isTenantSubscriptionExpired = () => false;
|
||||
export const isTenantSubscriptionExpired = () => false;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { defaultTo } from 'lodash';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
|
||||
const getCurrentOrganizationId = (state) => state.authentication.organization;
|
||||
const getCurrentTenantId = (state) => state.authentication.organizationId;
|
||||
const getCurrentOrganizationId = (state) => state.authentication.organizationId;
|
||||
const getCurrentTenantId = (state) => state.authentication.tenantId;
|
||||
const getOrganizationsMap = (state) => state.organizations.data;
|
||||
|
||||
// Retrieve organization tenant id.
|
||||
|
||||
@@ -10,13 +10,14 @@ import loggerMiddleware from 'middleware/logger';
|
||||
import rootReducer from 'store/reducers';
|
||||
import ResetMiddleware from './ResetMiddleware';
|
||||
|
||||
|
||||
const createStoreFactory = (initialState = {}) => {
|
||||
/**
|
||||
|--------------------------------------------------
|
||||
| Middleware Configuration
|
||||
|--------------------------------------------------
|
||||
*/
|
||||
const middleware = [thunkMiddleware, loggerMiddleware ];
|
||||
const middleware = [thunkMiddleware, loggerMiddleware];
|
||||
|
||||
/**
|
||||
|--------------------------------------------------
|
||||
@@ -41,8 +42,6 @@ const createStoreFactory = (initialState = {}) => {
|
||||
rootReducer,
|
||||
initialState,
|
||||
composeEnhancers(applyMiddleware(...middleware), ...enhancers),
|
||||
|
||||
|
||||
);
|
||||
store.asyncReducers = {};
|
||||
return store;
|
||||
|
||||
@@ -69,4 +69,19 @@ export function toggleExpendSidebar(toggle) {
|
||||
type: t.SIDEBAR_EXPEND_TOGGLE,
|
||||
payload: { toggle }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function appIsLoading(toggle) {
|
||||
return {
|
||||
type: t.APP_IS_LOADING,
|
||||
payload: { isLoading: toggle },
|
||||
};
|
||||
}
|
||||
|
||||
export function appIntlIsLoading(toggle) {
|
||||
return {
|
||||
type: t.APP_INTL_IS_LOADING,
|
||||
payload: { isLoading: toggle },
|
||||
};
|
||||
}
|
||||
@@ -16,6 +16,8 @@ const initialState = {
|
||||
topbarEditViewId: null,
|
||||
requestsLoading: 0,
|
||||
backLink: false,
|
||||
appIsLoading: true,
|
||||
appIntlIsLoading: true,
|
||||
};
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:dashboard';
|
||||
@@ -100,6 +102,16 @@ const reducerInstance = createReducer(initialState, {
|
||||
state.backLink = backLink;
|
||||
},
|
||||
|
||||
[t.APP_IS_LOADING]: (state, action) => {
|
||||
const { isLoading } = action.payload;
|
||||
state.appIsLoading = isLoading;
|
||||
},
|
||||
|
||||
[t.APP_INTL_IS_LOADING]: (state, action) => {
|
||||
const { isLoading } = action.payload;
|
||||
state.appIntlIsLoading = isLoading;
|
||||
},
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
|
||||
@@ -14,4 +14,6 @@ export default {
|
||||
SET_TOPBAR_EDIT_VIEW: 'SET_TOPBAR_EDIT_VIEW',
|
||||
SIDEBAR_EXPEND_TOGGLE: 'SIDEBAR_EXPEND_TOGGLE',
|
||||
SET_DASHBOARD_BACK_LINK: 'SET_DASHBOARD_BACK_LINK',
|
||||
APP_IS_LOADING: 'APP_IS_LOADING',
|
||||
APP_INTL_IS_LOADING: 'APP_INTL_IS_LOADING'
|
||||
};
|
||||
|
||||
@@ -29,12 +29,12 @@ export const fetchOrganizations = () => (dispatch) =>
|
||||
|
||||
export const setOrganizationSetupCompleted =
|
||||
(congrats) => (dispatch, getState) => {
|
||||
const organizationId = getState().authentication.organizationId;
|
||||
const tenantId = getState().authentication.tenantId;
|
||||
|
||||
dispatch({
|
||||
type: t.SET_ORGANIZATION_CONGRATS,
|
||||
payload: {
|
||||
organizationId,
|
||||
tenantId,
|
||||
congrats,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -27,10 +27,10 @@ const reducer = createReducer(initialState, {
|
||||
},
|
||||
|
||||
[t.SET_ORGANIZATION_CONGRATS]: (state, action) => {
|
||||
const { organizationId, congrats } = action.payload;
|
||||
const { tenantId, congrats } = action.payload;
|
||||
|
||||
state.data[organizationId] = {
|
||||
...(state.data[organizationId] || {}),
|
||||
state.data[tenantId] = {
|
||||
...(state.data[tenantId] || {}),
|
||||
is_congrats: !!congrats,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,50 +1,39 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
|
||||
const organizationSelector = (state, props) => state.organizations.data[props.organizationId];
|
||||
const organizationSelector = (state, props) => {
|
||||
const tenantId = state.organizations.byOrganizationId[props.organizationId];
|
||||
return state.organizations.data[tenantId];
|
||||
};
|
||||
|
||||
export const getOrganizationByIdFactory = () => createSelector(
|
||||
organizationSelector,
|
||||
(organization) => organization
|
||||
);
|
||||
export const getOrganizationByIdFactory = () =>
|
||||
createSelector(organizationSelector, (organization) => organization);
|
||||
|
||||
export const isOrganizationSeededFactory = () => createSelector(
|
||||
organizationSelector,
|
||||
(organization) => {
|
||||
export const isOrganizationSeededFactory = () =>
|
||||
createSelector(organizationSelector, (organization) => {
|
||||
return !!organization?.seeded_at;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
export const isOrganizationBuiltFactory = () => createSelector(
|
||||
organizationSelector,
|
||||
(organization) => {
|
||||
export const isOrganizationBuiltFactory = () =>
|
||||
createSelector(organizationSelector, (organization) => {
|
||||
return !!organization?.initialized_at;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
export const isOrganizationReadyFactory = () => createSelector(
|
||||
organizationSelector,
|
||||
(organization) => {
|
||||
export const isOrganizationReadyFactory = () =>
|
||||
createSelector(organizationSelector, (organization) => {
|
||||
return organization?.is_ready;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
export const isOrganizationSubscribedFactory = () => createSelector(
|
||||
organizationSelector,
|
||||
(organization) => {
|
||||
export const isOrganizationSubscribedFactory = () =>
|
||||
createSelector(organizationSelector, (organization) => {
|
||||
return organization?.subscriptions?.length > 0;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export const isOrganizationCongratsFactory = () => createSelector(
|
||||
organizationSelector,
|
||||
(organization) => {
|
||||
export const isOrganizationCongratsFactory = () =>
|
||||
createSelector(organizationSelector, (organization) => {
|
||||
return !!organization?.is_congrats;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export const isOrganizationBuildRunningFactory = () => createSelector(
|
||||
organizationSelector,
|
||||
(organization) => {
|
||||
export const isOrganizationBuildRunningFactory = () =>
|
||||
createSelector(organizationSelector, (organization) => {
|
||||
return !!organization?.is_build_running;
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
export default {
|
||||
ORGANIZATION_SET: 'ORGANIZATION_SET',
|
||||
ORGANIZATIONS_LIST_SET: 'ORGANIZATIONS_LIST_SET',
|
||||
SET_ORGANIZATION_CONGRATS: 'SET_ORGANIZATION_CONGRATS'
|
||||
};
|
||||
@@ -17,7 +17,7 @@ const getSubscriptionPeriods = () => [
|
||||
const getSubscriptionPlans = () => [
|
||||
{
|
||||
name: intl.get('plan.essential.title'),
|
||||
slug: 'free',
|
||||
slug: 'essentials',
|
||||
description: [
|
||||
intl.get('plan.feature.sale_purchase_invoice'),
|
||||
intl.get('plan.feature.receivable_payable_accounts'),
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
background: #fff;
|
||||
z-index: 999999;
|
||||
|
||||
.center {
|
||||
width: auto;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
.datatable-empty-status {
|
||||
max-width: 550px;
|
||||
.root {
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
margin: auto;
|
||||
padding-bottom: 40px;
|
||||
text-align: center;
|
||||
margin-top: 200px;
|
||||
|
||||
&__title {
|
||||
&_title {
|
||||
font-size: 20px;
|
||||
color: #2c3a5d;
|
||||
font-weight: 600;
|
||||
@@ -19,20 +19,16 @@
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
&__desc {
|
||||
&_desc {
|
||||
font-size: 16px;
|
||||
color: #1f3255;
|
||||
opacity: 0.8;
|
||||
line-height: 1.6;
|
||||
|
||||
html[lang='ar'] & {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
&__actions {
|
||||
&_actions {
|
||||
margin-top: 26px;
|
||||
|
||||
.bp3-button {
|
||||
:global .bp3-button {
|
||||
min-height: 36px;
|
||||
|
||||
& + .bp3-button {
|
||||
@@ -371,6 +371,18 @@ $dashboard-views-bar-height: 44px;
|
||||
}
|
||||
}
|
||||
|
||||
&__centered-empty-status{
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
flex-direction: column;
|
||||
margin: auto;
|
||||
|
||||
.datatable-empty-status{
|
||||
margin: auto;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
&__datatable {
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
|
||||
@@ -11,6 +11,19 @@ import deepMapKeys from 'deep-map-keys';
|
||||
import { createSelectorCreator, defaultMemoize } from 'reselect';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
import jsCookie from 'js-cookie';
|
||||
|
||||
export const getCookie = (name, defaultValue) => _.defaultTo(jsCookie.get(name), defaultValue);
|
||||
|
||||
export const setCookie = (name, value, expiry = 365, secure = false) => {
|
||||
jsCookie.set(name, value, { expires: expiry, path: '/', secure });
|
||||
};
|
||||
|
||||
export const removeCookie = (name) => {
|
||||
return jsCookie.remove(name, { path: '/' });
|
||||
}
|
||||
|
||||
|
||||
export function removeEmptyFromObject(obj) {
|
||||
obj = Object.assign({}, obj);
|
||||
var keys = Object.keys(obj);
|
||||
@@ -227,6 +240,7 @@ export const firstLettersArgs = (...args) => {
|
||||
return letters.join('').toUpperCase();
|
||||
};
|
||||
|
||||
|
||||
export const uniqueMultiProps = (items, props) => {
|
||||
return _.uniqBy(items, (item) => {
|
||||
return JSON.stringify(_.pick(item, props));
|
||||
|
||||
Reference in New Issue
Block a user