mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 22:30:31 +00:00
feat: ensure to access dashboard user's subscription is active.
This commit is contained in:
@@ -2,15 +2,15 @@ import intl from 'react-intl-universal';
|
|||||||
|
|
||||||
export const getSetupWizardSteps = () => [
|
export const getSetupWizardSteps = () => [
|
||||||
{
|
{
|
||||||
label: intl.get('Plans & Payment'),
|
label: intl.get('setup.plan.plans'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: intl.get('Initializing'),
|
label: intl.get('setup.plan.initializing'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: intl.get('Getting started'),
|
label: intl.get('setup.plan.getting_started'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: intl.get('Congratulations'),
|
label: intl.get('setup.plan.congrats'),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
17
client/src/components/Alert/index.js
Normal file
17
client/src/components/Alert/index.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import clsx from 'classnames';
|
||||||
|
|
||||||
|
import Style from './style.module.scss';
|
||||||
|
|
||||||
|
export function Alert({ title, description, intent }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(Style.root, {
|
||||||
|
[`${Style['root_' + intent]}`]: intent,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{title && <h3 className={clsx(Style.title)}>{title}</h3>}
|
||||||
|
{description && <p class={clsx(Style.description)}>{description}</p>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
32
client/src/components/Alert/style.module.scss
Normal file
32
client/src/components/Alert/style.module.scss
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
.root {
|
||||||
|
border: 1px solid rgb(223, 227, 230);
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&_danger {
|
||||||
|
border-color: rgb(249, 198, 198);
|
||||||
|
background: rgb(255, 248, 248);
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: #d95759;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: rgb(205, 43, 49);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: rgb(17, 24, 28);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: rgb(104, 112, 118);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
@@ -12,6 +12,33 @@ import DashboardSplitPane from 'components/Dashboard/DashboardSplitePane';
|
|||||||
import GlobalHotkeys from './GlobalHotkeys';
|
import GlobalHotkeys from './GlobalHotkeys';
|
||||||
import DashboardProvider from './DashboardProvider';
|
import DashboardProvider from './DashboardProvider';
|
||||||
import DrawersContainer from 'components/DrawersContainer';
|
import DrawersContainer from 'components/DrawersContainer';
|
||||||
|
import EnsureSubscriptionIsActive from '../Guards/EnsureSubscriptionIsActive';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dashboard preferences.
|
||||||
|
*/
|
||||||
|
function DashboardPreferences() {
|
||||||
|
return (
|
||||||
|
<EnsureSubscriptionIsActive>
|
||||||
|
<DashboardSplitPane>
|
||||||
|
<Sidebar />
|
||||||
|
<PreferencesPage />
|
||||||
|
</DashboardSplitPane>
|
||||||
|
</EnsureSubscriptionIsActive>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dashboard other routes.
|
||||||
|
*/
|
||||||
|
function DashboardAnyPage() {
|
||||||
|
return (
|
||||||
|
<DashboardSplitPane>
|
||||||
|
<Sidebar />
|
||||||
|
<DashboardContent />
|
||||||
|
</DashboardSplitPane>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard page.
|
* Dashboard page.
|
||||||
@@ -20,19 +47,8 @@ export default function Dashboard() {
|
|||||||
return (
|
return (
|
||||||
<DashboardProvider>
|
<DashboardProvider>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/preferences">
|
<Route path="/preferences" component={DashboardPreferences} />
|
||||||
<DashboardSplitPane>
|
<Route path="/" component={DashboardAnyPage} />
|
||||||
<Sidebar />
|
|
||||||
<PreferencesPage />
|
|
||||||
</DashboardSplitPane>
|
|
||||||
</Route>
|
|
||||||
|
|
||||||
<Route path="/">
|
|
||||||
<DashboardSplitPane>
|
|
||||||
<Sidebar />
|
|
||||||
<DashboardContent />
|
|
||||||
</DashboardSplitPane>
|
|
||||||
</Route>
|
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
||||||
<DashboardUniversalSearch />
|
<DashboardUniversalSearch />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ErrorBoundary } from 'react-error-boundary';
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
import DashboardTopbar from 'components/Dashboard/DashboardTopbar';
|
import DashboardTopbar from 'components/Dashboard/DashboardTopbar';
|
||||||
import DashboardContentRoute from 'components/Dashboard/DashboardContentRoute';
|
import DashboardContentRoutes from 'components/Dashboard/DashboardContentRoute';
|
||||||
import DashboardFooter from 'components/Dashboard/DashboardFooter';
|
import DashboardFooter from 'components/Dashboard/DashboardFooter';
|
||||||
import DashboardErrorBoundary from './DashboardErrorBoundary';
|
import DashboardErrorBoundary from './DashboardErrorBoundary';
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ export default React.forwardRef(({}, ref) => {
|
|||||||
<ErrorBoundary FallbackComponent={DashboardErrorBoundary}>
|
<ErrorBoundary FallbackComponent={DashboardErrorBoundary}>
|
||||||
<div className="dashboard-content" id="dashboard" ref={ref}>
|
<div className="dashboard-content" id="dashboard" ref={ref}>
|
||||||
<DashboardTopbar />
|
<DashboardTopbar />
|
||||||
<DashboardContentRoute />
|
<DashboardContentRoutes />
|
||||||
<DashboardFooter />
|
<DashboardFooter />
|
||||||
</div>
|
</div>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
|||||||
@@ -2,8 +2,43 @@ import React from 'react';
|
|||||||
import { Route, Switch } from 'react-router-dom';
|
import { Route, Switch } from 'react-router-dom';
|
||||||
|
|
||||||
import { getDashboardRoutes } from 'routes/dashboard';
|
import { getDashboardRoutes } from 'routes/dashboard';
|
||||||
|
import EnsureSubscriptionsIsActive from '../Guards/EnsureSubscriptionsIsActive';
|
||||||
|
import EnsureSubscriptionsIsInactive from '../Guards/EnsureSubscriptionsIsInactive';
|
||||||
import DashboardPage from './DashboardPage';
|
import DashboardPage from './DashboardPage';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dashboard inner route content.
|
||||||
|
*/
|
||||||
|
function DashboardContentRouteContent({ route }) {
|
||||||
|
const content = (
|
||||||
|
<DashboardPage
|
||||||
|
name={route.name}
|
||||||
|
Component={route.component}
|
||||||
|
pageTitle={route.pageTitle}
|
||||||
|
backLink={route.backLink}
|
||||||
|
hint={route.hint}
|
||||||
|
sidebarExpand={route.sidebarExpand}
|
||||||
|
pageType={route.pageType}
|
||||||
|
defaultSearchResource={route.defaultSearchResource}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
return route.subscriptionActive ? (
|
||||||
|
<EnsureSubscriptionsIsInactive
|
||||||
|
subscriptionTypes={route.subscriptionActive}
|
||||||
|
children={content}
|
||||||
|
redirectTo={'/billing'}
|
||||||
|
/>
|
||||||
|
) : route.subscriptionInactive ? (
|
||||||
|
<EnsureSubscriptionsIsActive
|
||||||
|
subscriptionTypes={route.subscriptionInactive}
|
||||||
|
children={content}
|
||||||
|
redirectTo={'/'}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard content route.
|
* Dashboard content route.
|
||||||
*/
|
*/
|
||||||
@@ -14,21 +49,8 @@ export default function DashboardContentRoute() {
|
|||||||
<Route pathname="/">
|
<Route pathname="/">
|
||||||
<Switch>
|
<Switch>
|
||||||
{routes.map((route, index) => (
|
{routes.map((route, index) => (
|
||||||
<Route
|
<Route exact={route.exact} key={index} path={`${route.path}`}>
|
||||||
exact={route.exact}
|
<DashboardContentRouteContent route={route} />
|
||||||
key={index}
|
|
||||||
path={`${route.path}`}
|
|
||||||
>
|
|
||||||
<DashboardPage
|
|
||||||
name={route.name}
|
|
||||||
Component={route.component}
|
|
||||||
pageTitle={route.pageTitle}
|
|
||||||
backLink={route.backLink}
|
|
||||||
hint={route.hint}
|
|
||||||
sidebarExpand={route.sidebarExpand}
|
|
||||||
pageType={route.pageType}
|
|
||||||
defaultSearchResource={route.defaultSearchResource}
|
|
||||||
/>
|
|
||||||
</Route>
|
</Route>
|
||||||
))}
|
))}
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import DashboardLoadingIndicator from './DashboardLoadingIndicator';
|
import DashboardLoadingIndicator from './DashboardLoadingIndicator';
|
||||||
import { useSettings } from 'hooks/query';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard provider.
|
* Dashboard provider.
|
||||||
*/
|
*/
|
||||||
export default function DashboardProvider({ children }) {
|
export default function DashboardProvider({ children }) {
|
||||||
const { isLoading } = useSettings();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardLoadingIndicator isLoading={isLoading}>
|
<DashboardLoadingIndicator isLoading={false}>
|
||||||
{ children }
|
{ children }
|
||||||
</DashboardLoadingIndicator>
|
</DashboardLoadingIndicator>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,6 +23,43 @@ import withSettings from 'containers/Settings/withSettings';
|
|||||||
|
|
||||||
import QuickNewDropdown from 'containers/QuickNewDropdown/QuickNewDropdown';
|
import QuickNewDropdown from 'containers/QuickNewDropdown/QuickNewDropdown';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
import withSubscriptions from '../../containers/Subscriptions/withSubscriptions';
|
||||||
|
|
||||||
|
function DashboardTopbarSubscriptionMessage() {
|
||||||
|
return (
|
||||||
|
<div class="dashboard__topbar-subscription-msg">
|
||||||
|
<span>
|
||||||
|
<T id={'dashboard.subscription_msg.period_over'} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DashboardHamburgerButton({ ...props }) {
|
||||||
|
return (
|
||||||
|
<Button minimal={true} {...props}>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
role="img"
|
||||||
|
focusable="false"
|
||||||
|
>
|
||||||
|
<title>
|
||||||
|
<T id={'menu'} />
|
||||||
|
</title>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-miterlimit="5"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M4 7h15M4 12h15M4 17h15"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard topbar.
|
* Dashboard topbar.
|
||||||
@@ -44,6 +81,10 @@ function DashboardTopbar({
|
|||||||
|
|
||||||
// #withGlobalSearch
|
// #withGlobalSearch
|
||||||
openGlobalSearch,
|
openGlobalSearch,
|
||||||
|
|
||||||
|
// #withSubscriptions
|
||||||
|
isSubscriptionActive,
|
||||||
|
isSubscriptionInactive,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
@@ -69,27 +110,7 @@ function DashboardTopbar({
|
|||||||
}
|
}
|
||||||
position={Position.RIGHT}
|
position={Position.RIGHT}
|
||||||
>
|
>
|
||||||
<Button minimal={true} onClick={handleSidebarToggleBtn}>
|
<DashboardHamburgerButton onClick={handleSidebarToggleBtn} />
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
role="img"
|
|
||||||
focusable="false"
|
|
||||||
>
|
|
||||||
<title>
|
|
||||||
<T id={'menu'} />
|
|
||||||
</title>
|
|
||||||
<path
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-miterlimit="5"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M4 7h15M4 12h15M4 17h15"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -114,29 +135,36 @@ function DashboardTopbar({
|
|||||||
<div class="dashboard__breadcrumbs">
|
<div class="dashboard__breadcrumbs">
|
||||||
<DashboardBreadcrumbs />
|
<DashboardBreadcrumbs />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DashboardBackLink />
|
<DashboardBackLink />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dashboard__topbar-right">
|
<div class="dashboard__topbar-right">
|
||||||
|
<If condition={isSubscriptionInactive}>
|
||||||
|
<DashboardTopbarSubscriptionMessage />
|
||||||
|
</If>
|
||||||
|
|
||||||
<Navbar class="dashboard__topbar-navbar">
|
<Navbar class="dashboard__topbar-navbar">
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
<Button
|
<If condition={isSubscriptionActive}>
|
||||||
onClick={() => openGlobalSearch(true)}
|
|
||||||
className={Classes.MINIMAL}
|
|
||||||
icon={<Icon icon={'search-24'} iconSize={20} />}
|
|
||||||
text={<T id={'quick_find'} />}
|
|
||||||
/>
|
|
||||||
<QuickNewDropdown />
|
|
||||||
<Tooltip
|
|
||||||
content={<T id={'notifications'} />}
|
|
||||||
position={Position.BOTTOM}
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
|
onClick={() => openGlobalSearch(true)}
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
icon={<Icon icon={'notification-24'} iconSize={20} />}
|
icon={<Icon icon={'search-24'} iconSize={20} />}
|
||||||
|
text={<T id={'quick_find'} />}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
<QuickNewDropdown />
|
||||||
|
|
||||||
|
<Tooltip
|
||||||
|
content={<T id={'notifications'} />}
|
||||||
|
position={Position.BOTTOM}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
className={Classes.MINIMAL}
|
||||||
|
icon={<Icon icon={'notification-24'} iconSize={20} />}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</If>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
icon={<Icon icon={'help-24'} iconSize={20} />}
|
icon={<Icon icon={'help-24'} iconSize={20} />}
|
||||||
@@ -166,4 +194,11 @@ export default compose(
|
|||||||
organizationName: organizationSettings.name,
|
organizationName: organizationSettings.name,
|
||||||
})),
|
})),
|
||||||
withDashboardActions,
|
withDashboardActions,
|
||||||
|
withSubscriptions(
|
||||||
|
({ isSubscriptionActive, isSubscriptionInactive }) => ({
|
||||||
|
isSubscriptionActive,
|
||||||
|
isSubscriptionInactive,
|
||||||
|
}),
|
||||||
|
'main',
|
||||||
|
),
|
||||||
)(DashboardTopbar);
|
)(DashboardTopbar);
|
||||||
|
|||||||
@@ -8,15 +8,21 @@ import {
|
|||||||
Popover,
|
Popover,
|
||||||
Position,
|
Position,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { If, FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import { firstLettersArgs } from 'utils';
|
import { firstLettersArgs } from 'utils';
|
||||||
import { useAuthActions, useAuthUser } from 'hooks/state';
|
import { useAuthActions, useAuthUser } from 'hooks/state';
|
||||||
|
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
import withSubscriptions from '../../containers/Subscriptions/withSubscriptions';
|
||||||
|
|
||||||
function DashboardTopbarUser({ openDialog }) {
|
function DashboardTopbarUser({
|
||||||
|
openDialog,
|
||||||
|
|
||||||
|
// #withSubscriptions
|
||||||
|
isSubscriptionActive
|
||||||
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { setLogout } = useAuthActions();
|
const { setLogout } = useAuthActions();
|
||||||
const user = useAuthUser();
|
const user = useAuthUser();
|
||||||
@@ -48,14 +54,16 @@ function DashboardTopbarUser({ openDialog }) {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<MenuDivider />
|
<MenuDivider />
|
||||||
<MenuItem
|
<If condition={isSubscriptionActive}>
|
||||||
text={<T id={'keyboard_shortcuts'} />}
|
<MenuItem
|
||||||
onClick={onKeyboardShortcut}
|
text={<T id={'keyboard_shortcuts'} />}
|
||||||
/>
|
onClick={onKeyboardShortcut}
|
||||||
<MenuItem
|
/>
|
||||||
text={<T id={'preferences'} />}
|
<MenuItem
|
||||||
onClick={() => history.push('/preferences')}
|
text={<T id={'preferences'} />}
|
||||||
/>
|
onClick={() => history.push('/preferences')}
|
||||||
|
/>
|
||||||
|
</If>
|
||||||
<MenuItem text={<T id={'logout'} />} onClick={onClickLogout} />
|
<MenuItem text={<T id={'logout'} />} onClick={onClickLogout} />
|
||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
@@ -69,4 +77,10 @@ function DashboardTopbarUser({ openDialog }) {
|
|||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default compose(withDialogActions)(DashboardTopbarUser);
|
export default compose(
|
||||||
|
withDialogActions,
|
||||||
|
withSubscriptions(
|
||||||
|
({ isSubscriptionActive }) => ({ isSubscriptionActive }),
|
||||||
|
'main',
|
||||||
|
),
|
||||||
|
)(DashboardTopbarUser);
|
||||||
|
|||||||
31
client/src/components/Guards/EnsureSubscriptionIsActive.js
Normal file
31
client/src/components/Guards/EnsureSubscriptionIsActive.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { includes } from 'lodash';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
import { Redirect } from 'react-router-dom';
|
||||||
|
import withSubscriptions from '../../containers/Subscriptions/withSubscriptions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the given subscription type is active or redirect to the given route.
|
||||||
|
*/
|
||||||
|
function EnsureSubscriptionIsActive({
|
||||||
|
children,
|
||||||
|
subscriptionType = 'main',
|
||||||
|
redirectTo = '/billing',
|
||||||
|
routePath,
|
||||||
|
exclude,
|
||||||
|
isSubscriptionActive,
|
||||||
|
}) {
|
||||||
|
return isSubscriptionActive || includes(exclude, routePath) ? (
|
||||||
|
children
|
||||||
|
) : (
|
||||||
|
<Redirect to={{ pathname: redirectTo }} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withSubscriptions(
|
||||||
|
({ isSubscriptionActive }) => ({ isSubscriptionActive }),
|
||||||
|
'main',
|
||||||
|
),
|
||||||
|
)(EnsureSubscriptionIsActive);
|
||||||
31
client/src/components/Guards/EnsureSubscriptionsIsActive.js
Normal file
31
client/src/components/Guards/EnsureSubscriptionsIsActive.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { includes } from 'lodash';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
import { Redirect } from 'react-router-dom';
|
||||||
|
import withSubscriptions from '../../containers/Subscriptions/withSubscriptionss';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the given subscription type is active or redirect to the given route.
|
||||||
|
*/
|
||||||
|
function EnsureSubscriptionsIsActive({
|
||||||
|
children,
|
||||||
|
subscriptionType = 'main',
|
||||||
|
redirectTo = '/billing',
|
||||||
|
routePath,
|
||||||
|
exclude,
|
||||||
|
isSubscriptionsActive,
|
||||||
|
}) {
|
||||||
|
return !isSubscriptionsActive || includes(exclude, routePath) ? (
|
||||||
|
children
|
||||||
|
) : (
|
||||||
|
<Redirect to={{ pathname: redirectTo }} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withSubscriptions(
|
||||||
|
({ isSubscriptionsActive }) => ({ isSubscriptionsActive }),
|
||||||
|
'main',
|
||||||
|
),
|
||||||
|
)(EnsureSubscriptionsIsActive);
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { includes } from 'lodash';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
import { Redirect } from 'react-router-dom';
|
||||||
|
import withSubscriptions from '../../containers/Subscriptions/withSubscriptionss';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the given subscription type is active or redirect to the given route.
|
||||||
|
*/
|
||||||
|
function EnsureSubscriptionsIsInactive({
|
||||||
|
children,
|
||||||
|
subscriptionType = 'main',
|
||||||
|
redirectTo = '/billing',
|
||||||
|
routePath,
|
||||||
|
exclude,
|
||||||
|
isSubscriptionsInactive,
|
||||||
|
}) {
|
||||||
|
return !isSubscriptionsInactive || includes(exclude, routePath) ? (
|
||||||
|
children
|
||||||
|
) : (
|
||||||
|
<Redirect to={{ pathname: redirectTo }} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withSubscriptions(
|
||||||
|
({ isSubscriptionsInactive }) => ({ isSubscriptionsInactive }),
|
||||||
|
'main',
|
||||||
|
),
|
||||||
|
)(EnsureSubscriptionsIsInactive);
|
||||||
@@ -1,22 +1,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Route, Switch, Redirect } from 'react-router-dom';
|
import { Route, Switch } from 'react-router-dom';
|
||||||
import preferencesRoutes from 'routes/preferences'
|
import preferencesRoutes from 'routes/preferences';
|
||||||
|
|
||||||
|
|
||||||
export default function DashboardContentRoute() {
|
export default function DashboardContentRoute() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Route pathname="/preferences">
|
<Route pathname="/preferences">
|
||||||
<Switch>
|
<Switch>
|
||||||
{ preferencesRoutes.map((route, index) => (
|
{preferencesRoutes.map((route, index) => (
|
||||||
<Route
|
<Route
|
||||||
key={index}
|
key={index}
|
||||||
path={`${route.path}`}
|
path={`${route.path}`}
|
||||||
exact={route.exact}
|
exact={route.exact}
|
||||||
component={route.component}
|
component={route.component}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Switch>
|
</Switch>
|
||||||
</Route>
|
</Route>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
|||||||
import withDashboard from 'containers/Dashboard/withDashboard';
|
import withDashboard from 'containers/Dashboard/withDashboard';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
import withSubscriptions from '../../containers/Subscriptions/withSubscriptions';
|
||||||
|
|
||||||
function SidebarContainer({
|
function SidebarContainer({
|
||||||
// #ownProps
|
// #ownProps
|
||||||
@@ -15,6 +16,9 @@ function SidebarContainer({
|
|||||||
|
|
||||||
// #withDashboard
|
// #withDashboard
|
||||||
sidebarExpended,
|
sidebarExpended,
|
||||||
|
|
||||||
|
// #withSubscription
|
||||||
|
isSubscriptionActive,
|
||||||
}) {
|
}) {
|
||||||
const sidebarScrollerRef = React.useRef();
|
const sidebarScrollerRef = React.useRef();
|
||||||
|
|
||||||
@@ -30,8 +34,8 @@ function SidebarContainer({
|
|||||||
}, [sidebarExpended]);
|
}, [sidebarExpended]);
|
||||||
|
|
||||||
const handleSidebarMouseLeave = () => {
|
const handleSidebarMouseLeave = () => {
|
||||||
if (!sidebarExpended && sidebarScrollerRef.current) {
|
if (!sidebarExpended && sidebarScrollerRef.current) {
|
||||||
sidebarScrollerRef.current.scrollTo({ top: 0, left: 0, });
|
sidebarScrollerRef.current.scrollTo({ top: 0, left: 0 });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,6 +47,7 @@ function SidebarContainer({
|
|||||||
<div
|
<div
|
||||||
className={classNames('sidebar', {
|
className={classNames('sidebar', {
|
||||||
'sidebar--mini-sidebar': !sidebarExpended,
|
'sidebar--mini-sidebar': !sidebarExpended,
|
||||||
|
'is-subscription-inactive': !isSubscriptionActive,
|
||||||
})}
|
})}
|
||||||
id="sidebar"
|
id="sidebar"
|
||||||
onMouseLeave={handleSidebarMouseLeave}
|
onMouseLeave={handleSidebarMouseLeave}
|
||||||
@@ -64,4 +69,8 @@ export default compose(
|
|||||||
withDashboard(({ sidebarExpended }) => ({
|
withDashboard(({ sidebarExpended }) => ({
|
||||||
sidebarExpended,
|
sidebarExpended,
|
||||||
})),
|
})),
|
||||||
|
withSubscriptions(
|
||||||
|
({ isSubscriptionActive }) => ({ isSubscriptionActive }),
|
||||||
|
'main',
|
||||||
|
),
|
||||||
)(SidebarContainer);
|
)(SidebarContainer);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import MenuItem from 'components/MenuItem';
|
|||||||
import { MenuItemLabel } from 'components';
|
import { MenuItemLabel } from 'components';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import SidebarOverlay from 'components/SidebarOverlay';
|
import SidebarOverlay from 'components/SidebarOverlay';
|
||||||
|
import { compose } from 'redux';
|
||||||
|
import withSubscriptions from '../../containers/Subscriptions/withSubscriptions';
|
||||||
|
|
||||||
const DEFAULT_ITEM = {
|
const DEFAULT_ITEM = {
|
||||||
text: '',
|
text: '',
|
||||||
@@ -19,12 +21,10 @@ function matchPath(pathname, path, matchExact) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SidebarMenuItemSpace({ space }) {
|
function SidebarMenuItemSpace({ space }) {
|
||||||
return (
|
return <div class="bp3-menu-spacer" style={{ height: `${space}px` }} />;
|
||||||
<div class="bp3-menu-spacer" style={{ height: `${space}px` }} />
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SidebarMenu() {
|
function SidebarMenu({ isSubscriptionActive }) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
@@ -92,7 +92,11 @@ export default function SidebarMenu() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const items = menuItemsMapper(sidebarMenuList);
|
|
||||||
|
const filterItems = sidebarMenuList.filter(
|
||||||
|
(item) => isSubscriptionActive || item.enableBilling,
|
||||||
|
);
|
||||||
|
const items = menuItemsMapper(filterItems);
|
||||||
|
|
||||||
const handleSidebarOverlayClose = () => {
|
const handleSidebarOverlayClose = () => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
@@ -110,3 +114,10 @@ export default function SidebarMenu() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withSubscriptions(
|
||||||
|
({ isSubscriptionActive }) => ({ isSubscriptionActive }),
|
||||||
|
'main',
|
||||||
|
),
|
||||||
|
)(SidebarMenu);
|
||||||
|
|||||||
135
client/src/components/Subscriptions/index.js
Normal file
135
client/src/components/Subscriptions/index.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { T } from 'components';
|
||||||
|
import { saveInvoke } from 'utils';
|
||||||
|
|
||||||
|
import 'style/pages/Subscription/PlanRadio.scss';
|
||||||
|
import 'style/pages/Subscription/PlanPeriodRadio.scss';
|
||||||
|
|
||||||
|
export function SubscriptionPlans({ value, plans, onSelect }) {
|
||||||
|
const handleSelect = (value) => {
|
||||||
|
onSelect && onSelect(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'plan-radios'}>
|
||||||
|
{plans.map((plan) => (
|
||||||
|
<SubscriptionPlan
|
||||||
|
name={plan.name}
|
||||||
|
description={plan.description}
|
||||||
|
slug={plan.slug}
|
||||||
|
price={plan.price}
|
||||||
|
currencyCode={plan.currencyCode}
|
||||||
|
value={plan.slug}
|
||||||
|
onSelected={handleSelect}
|
||||||
|
selectedOption={value}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SubscriptionPlan({
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
price,
|
||||||
|
currencyCode,
|
||||||
|
|
||||||
|
value,
|
||||||
|
selectedOption,
|
||||||
|
onSelected,
|
||||||
|
}) {
|
||||||
|
const handlePlanClick = () => {
|
||||||
|
saveInvoke(onSelected, value);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id={'basic-plan'}
|
||||||
|
className={classNames('plan-radio', {
|
||||||
|
'is-selected': selectedOption === value,
|
||||||
|
})}
|
||||||
|
onClick={handlePlanClick}
|
||||||
|
>
|
||||||
|
<div className={'plan-radio__header'}>
|
||||||
|
<div className={'plan-radio__name'}>{name}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'plan-radio__description'}>
|
||||||
|
<ul>
|
||||||
|
{description.map((line) => (
|
||||||
|
<li>{line}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'plan-radio__price'}>
|
||||||
|
<span className={'plan-radio__amount'}>
|
||||||
|
{price} {currencyCode}
|
||||||
|
</span>
|
||||||
|
<span className={'plan-radio__period'}>
|
||||||
|
<T id={'monthly'} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscription periods.
|
||||||
|
*/
|
||||||
|
export function SubscriptionPeriods({ periods, selectedPeriod, onPeriodSelect }) {
|
||||||
|
const handleSelected = (value) => {
|
||||||
|
saveInvoke(onPeriodSelect, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'plan-periods'}>
|
||||||
|
{periods.map((period) => (
|
||||||
|
<SubscriptionPeriod
|
||||||
|
period={period.slug}
|
||||||
|
label={period.label}
|
||||||
|
onSelected={handleSelected}
|
||||||
|
price={period.price}
|
||||||
|
selectedPeriod={selectedPeriod}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Billing period.
|
||||||
|
*/
|
||||||
|
export function SubscriptionPeriod({
|
||||||
|
// #ownProps
|
||||||
|
label,
|
||||||
|
selectedPeriod,
|
||||||
|
onSelected,
|
||||||
|
period,
|
||||||
|
price,
|
||||||
|
currencyCode,
|
||||||
|
}) {
|
||||||
|
const handlePeriodClick = () => {
|
||||||
|
saveInvoke(onSelected, period);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id={`plan-period-${period}`}
|
||||||
|
className={classNames(
|
||||||
|
{ 'is-selected': period === selectedPeriod },
|
||||||
|
'period-radio',
|
||||||
|
)}
|
||||||
|
onClick={handlePeriodClick}
|
||||||
|
>
|
||||||
|
<span className={'period-radio__label'}>{label}</span>
|
||||||
|
|
||||||
|
<div className={'period-radio__price'}>
|
||||||
|
<span className={'period-radio__amount'}>
|
||||||
|
{price} {currencyCode}
|
||||||
|
</span>
|
||||||
|
<span className={'period-radio__period'}>{label}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -72,6 +72,8 @@ export * from './Details';
|
|||||||
export * from './Drawer/DrawerInsider';
|
export * from './Drawer/DrawerInsider';
|
||||||
export * from './Drawer/DrawerMainTabs';
|
export * from './Drawer/DrawerMainTabs';
|
||||||
export * from './TotalLines/index'
|
export * from './TotalLines/index'
|
||||||
|
export * from './Alert';
|
||||||
|
export * from './Subscriptions';
|
||||||
|
|
||||||
const Hint = FieldHint;
|
const Hint = FieldHint;
|
||||||
|
|
||||||
|
|||||||
@@ -298,6 +298,7 @@ export default [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: <T id={'system'} />,
|
text: <T id={'system'} />,
|
||||||
|
enableBilling: true,
|
||||||
label: true,
|
label: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -307,5 +308,6 @@ export default [
|
|||||||
{
|
{
|
||||||
text: <T id={'billing'} />,
|
text: <T id={'billing'} />,
|
||||||
href: '/billing',
|
href: '/billing',
|
||||||
|
enableBilling: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
|
import { Intent } from '@blueprintjs/core';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import Toaster from 'components/AppToaster';
|
import Toaster from 'components/AppToaster';
|
||||||
|
|
||||||
import 'style/pages/Setup/PaymentViaVoucherDialog.scss';
|
import 'style/pages/Setup/PaymentViaVoucherDialog.scss';
|
||||||
@@ -14,7 +15,6 @@ import PaymentViaLicenseForm from './PaymentViaVoucherForm';
|
|||||||
|
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
import { Intent } from '@blueprintjs/core';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payment via license dialog content.
|
* Payment via license dialog content.
|
||||||
@@ -35,10 +35,11 @@ function PaymentViaLicenseDialogContent({
|
|||||||
const handleSubmit = (values, { setSubmitting, setErrors }) => {
|
const handleSubmit = (values, { setSubmitting, setErrors }) => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
|
// Payment via voucher mutate.
|
||||||
paymentViaVoucherMutate({ ...values })
|
paymentViaVoucherMutate({ ...values })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
Toaster.show({
|
Toaster.show({
|
||||||
message: intl.get('payment_has_been_done_successfully'),
|
message: intl.get('payment_via_voucher.success_message'),
|
||||||
intent: Intent.SUCCESS,
|
intent: Intent.SUCCESS,
|
||||||
});
|
});
|
||||||
return closeDialog('payment-via-voucher');
|
return closeDialog('payment-via-voucher');
|
||||||
@@ -54,7 +55,7 @@ function PaymentViaLicenseDialogContent({
|
|||||||
}) => {
|
}) => {
|
||||||
if (errors.find((e) => e.type === 'LICENSE.CODE.IS.INVALID')) {
|
if (errors.find((e) => e.type === 'LICENSE.CODE.IS.INVALID')) {
|
||||||
setErrors({
|
setErrors({
|
||||||
license_code: 'The license code is not valid, please try agin.',
|
license_code: 'payment_via_voucher.license_code_not_valid',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ function PaymentViaLicenseForm({
|
|||||||
<Form>
|
<Form>
|
||||||
<div className={CLASSES.DIALOG_BODY}>
|
<div className={CLASSES.DIALOG_BODY}>
|
||||||
<p>
|
<p>
|
||||||
<T id={'Pleasse enter your voucher number that you received from reseller.'} />
|
<T id={'payment_via_voucher.dialog.description'} />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<FastField name="license_code">
|
<FastField name="license_code">
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import React from 'react';
|
||||||
import { Intent } from '@blueprintjs/core';
|
import { Intent } from '@blueprintjs/core';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
import AppToaster from 'components/AppToaster';
|
import AppToaster from 'components/AppToaster';
|
||||||
|
|
||||||
import withGlobalErrors from './withGlobalErrors';
|
import withGlobalErrors from './withGlobalErrors';
|
||||||
@@ -17,29 +19,31 @@ function GlobalErrors({
|
|||||||
globalErrorsSet,
|
globalErrorsSet,
|
||||||
}) {
|
}) {
|
||||||
if (globalErrors.something_wrong) {
|
if (globalErrors.something_wrong) {
|
||||||
toastKeySessionExpired = AppToaster.show({
|
toastKeySessionExpired = AppToaster.show(
|
||||||
message: intl.get('ops_something_went_wrong'),
|
{
|
||||||
intent: Intent.DANGER,
|
message: intl.get('ops_something_went_wrong'),
|
||||||
onDismiss: () => {
|
intent: Intent.DANGER,
|
||||||
globalErrorsSet({ something_wrong: false });
|
onDismiss: () => {
|
||||||
}
|
globalErrorsSet({ something_wrong: false });
|
||||||
}, toastKeySessionExpired);
|
},
|
||||||
|
},
|
||||||
|
toastKeySessionExpired,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalErrors.session_expired) {
|
if (globalErrors.session_expired) {
|
||||||
toastKeySomethingWrong = AppToaster.show({
|
toastKeySomethingWrong = AppToaster.show(
|
||||||
message: intl.get('session_expired'),
|
{
|
||||||
intent: Intent.DANGER,
|
message: intl.get('session_expired'),
|
||||||
onDismiss: () => {
|
intent: Intent.DANGER,
|
||||||
globalErrorsSet({ session_expired: false });
|
onDismiss: () => {
|
||||||
}
|
globalErrorsSet({ session_expired: false });
|
||||||
}, toastKeySomethingWrong);
|
},
|
||||||
|
},
|
||||||
|
toastKeySomethingWrong,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(withGlobalErrors, withGlobalErrorsActions)(GlobalErrors);
|
||||||
withGlobalErrors,
|
|
||||||
withGlobalErrorsActions,
|
|
||||||
)(GlobalErrors);
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { Button, Intent } from '@blueprintjs/core';
|
import { Button, Intent } from '@blueprintjs/core';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import WorkflowIcon from './WorkflowIcon';
|
import WorkflowIcon from './WorkflowIcon';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import withOrganizationActions from 'containers/Organization/withOrganizationActions';
|
import withOrganizationActions from 'containers/Organization/withOrganizationActions';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
import 'style/pages/Setup/Congrats.scss';
|
import 'style/pages/Setup/Congrats.scss';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup congrats page.
|
* Setup congrats page.
|
||||||
@@ -28,15 +30,15 @@ function SetupCongratsPage({ setOrganizationSetupCompleted }) {
|
|||||||
|
|
||||||
<div class="setup-congrats__text">
|
<div class="setup-congrats__text">
|
||||||
<h1>
|
<h1>
|
||||||
<T id={'congrats_you_are_ready_to_go'} />
|
<T id={'setup.congrats.title'} />
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p class="paragraph">
|
<p class="paragraph">
|
||||||
<T id={'it_is_a_long_established_fact_that_a_reader'} />
|
<T id={'setup.congrats.description'} />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Button intent={Intent.PRIMARY} type="submit" onClick={handleBtnClick}>
|
<Button intent={Intent.PRIMARY} type="submit" onClick={handleBtnClick}>
|
||||||
<T id={'go_to_dashboard'} />
|
<T id={'setup.congrats.go_to_dashboard'} />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function SetupInitializingForm() {
|
|||||||
isError,
|
isError,
|
||||||
} = useBuildTenant();
|
} = useBuildTenant();
|
||||||
|
|
||||||
useEffect(() => {
|
React.useEffect(() => {
|
||||||
buildTenantMutate();
|
buildTenantMutate();
|
||||||
}, [buildTenantMutate]);
|
}, [buildTenantMutate]);
|
||||||
|
|
||||||
@@ -27,32 +27,32 @@ export default function SetupInitializingForm() {
|
|||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<>
|
<>
|
||||||
<h1>
|
<h1>
|
||||||
<T id={'it_s_time_to_make_your_accounting_really_simple'} />
|
<T id={'setup.initializing.title'} />
|
||||||
</h1>
|
</h1>
|
||||||
<p className={'paragraph'}>
|
<p className={'paragraph'}>
|
||||||
<T
|
<T id={'setup.initializing.description'} />
|
||||||
id={
|
|
||||||
'while_we_set_up_your_account_please_remember_to_verify_your_account'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
) : isError ? (
|
) : isError ? (
|
||||||
<>
|
<>
|
||||||
<h1>
|
<h1>
|
||||||
<T id={'something_went_wrong'} />
|
<T id={'setup.initializing.something_went_wrong'} />
|
||||||
</h1>
|
</h1>
|
||||||
<p class="paragraph">
|
<p class="paragraph">
|
||||||
<T id={'please_refresh_the_page'} />
|
<T id={'setup.initializing.please_refresh_the_page'} />
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<h1>
|
<h1>
|
||||||
<T id={'waiting_to_redirect'} />
|
<T id={'setup.initializing.waiting_to_redirect'} />
|
||||||
</h1>
|
</h1>
|
||||||
<p class="paragraph">
|
<p class="paragraph">
|
||||||
<T id={'refresh_the_page_if_redirect_not_worked'} />
|
<T
|
||||||
|
id={
|
||||||
|
'setup.initializing.refresh_the_page_if_redirect_not_worked'
|
||||||
|
}
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ import { Icon, For } from 'components';
|
|||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import { getFooterLinks } from 'config/footerLinks';
|
import { getFooterLinks } from 'config/footerLinks';
|
||||||
import { useAuthActions, useAuthOrganizationId } from 'hooks/state';
|
import { useAuthActions } from 'hooks/state';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Footer item link.
|
||||||
|
*/
|
||||||
function FooterLinkItem({ title, link }) {
|
function FooterLinkItem({ title, link }) {
|
||||||
return (
|
return (
|
||||||
<div class="">
|
<div class="content__links-item">
|
||||||
<a href={link} target="_blank">
|
<a href={link} target="_blank">
|
||||||
{title}
|
{title}
|
||||||
</a>
|
</a>
|
||||||
@@ -16,20 +19,65 @@ function FooterLinkItem({ title, link }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wizard setup left section.
|
* Setup left section footer.
|
||||||
*/
|
*/
|
||||||
export default function SetupLeftSection() {
|
function SetupLeftSectionFooter() {
|
||||||
const { setLogout } = useAuthActions();
|
|
||||||
const organizationId = useAuthOrganizationId();
|
|
||||||
|
|
||||||
// Retrieve the footer links.
|
// Retrieve the footer links.
|
||||||
const footerLinks = getFooterLinks();
|
const footerLinks = getFooterLinks();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'content__footer'}>
|
||||||
|
<div className={'content__contact-info'}>
|
||||||
|
<p>
|
||||||
|
<T id={'setup.left_side.footer_help'} />{' '}
|
||||||
|
<span>{'+21892-738-1987'}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'content__links'}>
|
||||||
|
<For render={FooterLinkItem} of={footerLinks} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup left section header.
|
||||||
|
*/
|
||||||
|
function SetupLeftSectionHeader() {
|
||||||
|
const { setLogout } = useAuthActions();
|
||||||
|
|
||||||
// Handle logout link click.
|
// Handle logout link click.
|
||||||
const onClickLogout = () => {
|
const onClickLogout = () => {
|
||||||
setLogout();
|
setLogout();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'content__header'}>
|
||||||
|
<h1 className={'content__title'}>
|
||||||
|
<T id={'setup.left_side.title'} />
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p className={'content__text'}>
|
||||||
|
<T id={'setup.left_side.description'} />
|
||||||
|
</p>
|
||||||
|
<div class="content__divider"></div>
|
||||||
|
|
||||||
|
<div className={'content__organization'}>
|
||||||
|
<span class="signout">
|
||||||
|
<a onClick={onClickLogout} href="#">
|
||||||
|
<T id={'sign_out'} />
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wizard setup left section.
|
||||||
|
*/
|
||||||
|
export default function SetupLeftSection() {
|
||||||
return (
|
return (
|
||||||
<section className={'setup-page__left-section'}>
|
<section className={'setup-page__left-section'}>
|
||||||
<div className={'content'}>
|
<div className={'content'}>
|
||||||
@@ -41,40 +89,8 @@ export default function SetupLeftSection() {
|
|||||||
width={190}
|
width={190}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<SetupLeftSectionHeader />
|
||||||
<h1 className={'content__title'}>
|
<SetupLeftSectionFooter />
|
||||||
<T id={'register_a_new_organization_now'} />
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p className={'content__text'}>
|
|
||||||
<T id={'you_have_a_bigcapital_account'} />
|
|
||||||
</p>
|
|
||||||
<span class="content__divider"></span>
|
|
||||||
|
|
||||||
<div className={'content__organization'}>
|
|
||||||
<span class="organization-id">
|
|
||||||
<T id={'organization_id'} />:{' '}
|
|
||||||
<span class="id">{organizationId}</span>,
|
|
||||||
</span>
|
|
||||||
<br />
|
|
||||||
<span class="signout">
|
|
||||||
<a onClick={onClickLogout} href="#">
|
|
||||||
<T id={'sign_out'} />
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={'content__footer'}>
|
|
||||||
<div className={'content__contact-info'}>
|
|
||||||
<p>
|
|
||||||
<T id={'we_re_here_to_help'} /> <span>{'+21892-738-1987'}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={'content__links'}>
|
|
||||||
<For render={FooterLinkItem} of={footerLinks} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
15
client/src/containers/Setup/SetupOrganization.schema.js
Normal file
15
client/src/containers/Setup/SetupOrganization.schema.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import * as Yup from 'yup';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
|
// Retrieve the setup organization form validation.
|
||||||
|
export const getSetupOrganizationValidation = () =>
|
||||||
|
Yup.object().shape({
|
||||||
|
organization_name: Yup.string()
|
||||||
|
.required()
|
||||||
|
.label(intl.get('organization_name_')),
|
||||||
|
financialDateStart: Yup.date().required().label(intl.get('date_start_')),
|
||||||
|
baseCurrency: Yup.string().required().label(intl.get('base_currency_')),
|
||||||
|
language: Yup.string().required().label(intl.get('language')),
|
||||||
|
fiscalYear: Yup.string().required().label(intl.get('fiscal_year_')),
|
||||||
|
timeZone: Yup.string().required().label(intl.get('time_zone_')),
|
||||||
|
});
|
||||||
@@ -14,20 +14,18 @@ import classNames from 'classnames';
|
|||||||
import { TimezonePicker } from '@blueprintjs/timezone';
|
import { TimezonePicker } from '@blueprintjs/timezone';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import { FieldRequiredHint, Col, Row, ListSelect } from 'components';
|
import { Col, Row, ListSelect } from 'components';
|
||||||
import {
|
import {
|
||||||
momentFormatter,
|
momentFormatter,
|
||||||
tansformDateValue,
|
tansformDateValue,
|
||||||
inputIntent,
|
inputIntent,
|
||||||
handleDateChange
|
handleDateChange,
|
||||||
} from 'utils';
|
} from 'utils';
|
||||||
|
|
||||||
import { getFiscalYear } from 'common/fiscalYearOptions';
|
import { getFiscalYear } from 'common/fiscalYearOptions';
|
||||||
import { getLanguages } from 'common/languagesOptions';
|
import { getLanguages } from 'common/languagesOptions';
|
||||||
import { getCurrencies } from 'common/currencies';
|
import { getCurrencies } from 'common/currencies';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup organization form.
|
* Setup organization form.
|
||||||
*/
|
*/
|
||||||
@@ -46,22 +44,24 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
<FastField name={'organization_name'}>
|
<FastField name={'organization_name'}>
|
||||||
{({ form, field, meta: { error, touched } }) => (
|
{({ form, field, meta: { error, touched } }) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelInfo={<FieldRequiredHint />}
|
|
||||||
label={<T id={'legal_organization_name'} />}
|
label={<T id={'legal_organization_name'} />}
|
||||||
className={'form-group--name'}
|
className={'form-group--name'}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
helperText={<ErrorMessage name={'organization_name'} />}
|
helperText={<ErrorMessage name={'organization_name'} />}
|
||||||
>
|
>
|
||||||
<InputGroup {...field} />
|
<InputGroup {...field} intent={inputIntent({ error, touched })} />
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
</FastField>
|
</FastField>
|
||||||
|
|
||||||
{/* ---------- Financial starting date ---------- */}
|
{/* ---------- Financial starting date ---------- */}
|
||||||
<FastField name={'financialDateStart'}>
|
<FastField name={'financialDateStart'}>
|
||||||
{({ form: { setFieldValue }, field: { value }, meta: { error, touched } }) => (
|
{({
|
||||||
|
form: { setFieldValue },
|
||||||
|
field: { value },
|
||||||
|
meta: { error, touched },
|
||||||
|
}) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelInfo={<FieldRequiredHint />}
|
|
||||||
label={<T id={'financial_starting_date'} />}
|
label={<T id={'financial_starting_date'} />}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
helperText={<ErrorMessage name="financialDateStart" />}
|
helperText={<ErrorMessage name="financialDateStart" />}
|
||||||
@@ -74,6 +74,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
onChange={handleDateChange((formattedDate) => {
|
onChange={handleDateChange((formattedDate) => {
|
||||||
setFieldValue('financialDateStart', formattedDate);
|
setFieldValue('financialDateStart', formattedDate);
|
||||||
})}
|
})}
|
||||||
|
intent={inputIntent({ error, touched })}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
@@ -89,7 +90,6 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
meta: { error, touched },
|
meta: { error, touched },
|
||||||
}) => (
|
}) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelInfo={<FieldRequiredHint />}
|
|
||||||
label={<T id={'base_currency'} />}
|
label={<T id={'base_currency'} />}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'form-group--base-currency',
|
'form-group--base-currency',
|
||||||
@@ -101,7 +101,9 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
>
|
>
|
||||||
<ListSelect
|
<ListSelect
|
||||||
items={Currencies}
|
items={Currencies}
|
||||||
noResults={<MenuItem disabled={true} text={<T id={'no_results'} />} />}
|
noResults={
|
||||||
|
<MenuItem disabled={true} text={<T id={'no_results'} />} />
|
||||||
|
}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
onItemSelect={(item) => {
|
onItemSelect={(item) => {
|
||||||
setFieldValue('baseCurrency', item.code);
|
setFieldValue('baseCurrency', item.code);
|
||||||
@@ -110,6 +112,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
textProp={'name'}
|
textProp={'name'}
|
||||||
defaultText={<T id={'select_base_currency'} />}
|
defaultText={<T id={'select_base_currency'} />}
|
||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
|
intent={inputIntent({ error, touched })}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
@@ -136,7 +139,9 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
>
|
>
|
||||||
<ListSelect
|
<ListSelect
|
||||||
items={Languages}
|
items={Languages}
|
||||||
noResults={<MenuItem disabled={true} text={<T id={'no_results'} />} />}
|
noResults={
|
||||||
|
<MenuItem disabled={true} text={<T id={'no_results'} />} />
|
||||||
|
}
|
||||||
onItemSelect={(item) => {
|
onItemSelect={(item) => {
|
||||||
setFieldValue('language', item.value);
|
setFieldValue('language', item.value);
|
||||||
}}
|
}}
|
||||||
@@ -146,6 +151,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
defaultText={<T id={'select_language'} />}
|
defaultText={<T id={'select_language'} />}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
filterable={false}
|
filterable={false}
|
||||||
|
intent={inputIntent({ error, touched })}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
@@ -154,9 +160,12 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
</Row>
|
</Row>
|
||||||
{/* --------- Fiscal Year ----------- */}
|
{/* --------- Fiscal Year ----------- */}
|
||||||
<FastField name={'fiscalYear'}>
|
<FastField name={'fiscalYear'}>
|
||||||
{({ form: { setFieldValue }, field: { value }, meta: { error, touched } }) => (
|
{({
|
||||||
|
form: { setFieldValue },
|
||||||
|
field: { value },
|
||||||
|
meta: { error, touched },
|
||||||
|
}) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelInfo={<FieldRequiredHint />}
|
|
||||||
label={<T id={'fiscal_year'} />}
|
label={<T id={'fiscal_year'} />}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'form-group--fiscal_year',
|
'form-group--fiscal_year',
|
||||||
@@ -168,14 +177,16 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
>
|
>
|
||||||
<ListSelect
|
<ListSelect
|
||||||
items={FiscalYear}
|
items={FiscalYear}
|
||||||
noResults={<MenuItem disabled={true} text={<T id={'no_results'} />} />}
|
noResults={
|
||||||
|
<MenuItem disabled={true} text={<T id={'no_results'} />} />
|
||||||
|
}
|
||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
selectedItemProp={'value'}
|
selectedItemProp={'value'}
|
||||||
textProp={'name'}
|
textProp={'name'}
|
||||||
defaultText={<T id={'select_fiscal_year'} />}
|
defaultText={<T id={'select_fiscal_year'} />}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
onItemSelect={(item) => {
|
onItemSelect={(item) => {
|
||||||
setFieldValue('fiscalYear', item.value)
|
setFieldValue('fiscalYear', item.value);
|
||||||
}}
|
}}
|
||||||
filterable={false}
|
filterable={false}
|
||||||
/>
|
/>
|
||||||
@@ -191,7 +202,6 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
meta: { error, touched },
|
meta: { error, touched },
|
||||||
}) => (
|
}) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelInfo={<FieldRequiredHint />}
|
|
||||||
label={<T id={'time_zone'} />}
|
label={<T id={'time_zone'} />}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'form-group--time-zone',
|
'form-group--time-zone',
|
||||||
@@ -216,20 +226,11 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
|||||||
</FastField>
|
</FastField>
|
||||||
|
|
||||||
<p className={'register-org-note'}>
|
<p className={'register-org-note'}>
|
||||||
<T
|
<T id={'setup.organization.note_you_can_change_your_preferences'} />
|
||||||
id={
|
|
||||||
'note_you_can_change_your_preferences_later_in_dashboard_if_needed'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className={'register-org-button'}>
|
<div className={'register-org-button'}>
|
||||||
<Button
|
<Button intent={Intent.PRIMARY} loading={isSubmitting} type="submit">
|
||||||
intent={Intent.PRIMARY}
|
|
||||||
disabled={isSubmitting}
|
|
||||||
loading={isSubmitting}
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
<T id={'save_continue'} />
|
<T id={'save_continue'} />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as Yup from 'yup';
|
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
import intl from 'react-intl-universal';
|
|
||||||
|
|
||||||
import 'style/pages/Setup/Organization.scss';
|
import 'style/pages/Setup/Organization.scss';
|
||||||
|
|
||||||
@@ -13,53 +12,30 @@ import { useOrganizationSetup } from 'hooks/query';
|
|||||||
import withSettingsActions from 'containers/Settings/withSettingsActions';
|
import withSettingsActions from 'containers/Settings/withSettingsActions';
|
||||||
import withOrganizationActions from 'containers/Organization/withOrganizationActions';
|
import withOrganizationActions from 'containers/Organization/withOrganizationActions';
|
||||||
|
|
||||||
import {
|
import { compose, transfromToSnakeCase } from 'utils';
|
||||||
compose,
|
import { getSetupOrganizationValidation } from './SetupOrganization.schema';
|
||||||
transfromToSnakeCase,
|
|
||||||
} from 'utils';
|
|
||||||
|
// Initial values.
|
||||||
|
const defaultValues = {
|
||||||
|
organization_name: '',
|
||||||
|
financialDateStart: moment(new Date()).format('YYYY-MM-DD'),
|
||||||
|
baseCurrency: '',
|
||||||
|
language: 'en',
|
||||||
|
fiscalYear: '',
|
||||||
|
timeZone: '',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup organization form.
|
* Setup organization form.
|
||||||
*/
|
*/
|
||||||
function SetupOrganizationPage({
|
function SetupOrganizationPage({ wizard, setOrganizationSetupCompleted }) {
|
||||||
wizard,
|
|
||||||
setOrganizationSetupCompleted,
|
|
||||||
}) {
|
|
||||||
|
|
||||||
const { mutateAsync: organizationSetupMutate } = useOrganizationSetup();
|
const { mutateAsync: organizationSetupMutate } = useOrganizationSetup();
|
||||||
|
|
||||||
// Validation schema.
|
// Validation schema.
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = getSetupOrganizationValidation();
|
||||||
organization_name: Yup.string()
|
|
||||||
.required()
|
|
||||||
.label(intl.get('organization_name_')),
|
|
||||||
financialDateStart: Yup.date()
|
|
||||||
.required()
|
|
||||||
.label(intl.get('date_start_')),
|
|
||||||
baseCurrency: Yup.string()
|
|
||||||
.required()
|
|
||||||
.label(intl.get('base_currency_')),
|
|
||||||
language: Yup.string()
|
|
||||||
.required()
|
|
||||||
.label(intl.get('language')),
|
|
||||||
fiscalYear: Yup.string()
|
|
||||||
.required()
|
|
||||||
.label(intl.get('fiscal_year_')),
|
|
||||||
timeZone: Yup.string()
|
|
||||||
.required()
|
|
||||||
.label(intl.get('time_zone_')),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initial values.
|
|
||||||
const defaultValues = {
|
|
||||||
organization_name: '',
|
|
||||||
financialDateStart: moment(new Date()).format('YYYY-MM-DD'),
|
|
||||||
baseCurrency: '',
|
|
||||||
language: 'en',
|
|
||||||
fiscalYear: '',
|
|
||||||
timeZone: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// Initialize values.
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
...defaultValues,
|
...defaultValues,
|
||||||
};
|
};
|
||||||
@@ -83,10 +59,10 @@ function SetupOrganizationPage({
|
|||||||
<div className={'setup-organization'}>
|
<div className={'setup-organization'}>
|
||||||
<div className={'setup-organization__title-wrap'}>
|
<div className={'setup-organization__title-wrap'}>
|
||||||
<h1>
|
<h1>
|
||||||
<T id={'let_s_get_started'} />
|
<T id={'setup.organization.title'} />
|
||||||
</h1>
|
</h1>
|
||||||
<p class="paragraph">
|
<p class="paragraph">
|
||||||
<T id={'tell_the_system_a_little_bit_about_your_organization'} />
|
<T id={'setup.organization.description'} />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import * as R from 'ramda';
|
|||||||
|
|
||||||
import 'style/pages/Setup/Subscription.scss';
|
import 'style/pages/Setup/Subscription.scss';
|
||||||
|
|
||||||
import SetupSubscriptionForm from './SetupSubscriptionForm';
|
import SetupSubscriptionForm from './SetupSubscription/SetupSubscriptionForm';
|
||||||
import { getSubscriptionFormSchema } from './SubscriptionForm.schema';
|
import { getSubscriptionFormSchema } from './SubscriptionForm.schema';
|
||||||
import withSubscriptionPlansActions from '../Subscriptions/withSubscriptionPlansActions';
|
import withSubscriptionPlansActions from '../Subscriptions/withSubscriptionPlansActions';
|
||||||
|
|
||||||
@@ -13,13 +13,11 @@ import withSubscriptionPlansActions from '../Subscriptions/withSubscriptionPlans
|
|||||||
*/
|
*/
|
||||||
function SetupSubscription({
|
function SetupSubscription({
|
||||||
// #withSubscriptionPlansActions
|
// #withSubscriptionPlansActions
|
||||||
initSubscriptionPlans
|
initSubscriptionPlans,
|
||||||
}) {
|
}) {
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
initSubscriptionPlans();
|
initSubscriptionPlans();
|
||||||
}, [
|
}, [initSubscriptionPlans]);
|
||||||
initSubscriptionPlans
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Initial values.
|
// Initial values.
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
@@ -30,10 +28,14 @@ function SetupSubscription({
|
|||||||
// Handle form submit.
|
// Handle form submit.
|
||||||
const handleSubmit = () => {};
|
const handleSubmit = () => {};
|
||||||
|
|
||||||
const SubscriptionFormSchema = getSubscriptionFormSchema();
|
// Retrieve momerized subscription form schema.
|
||||||
|
const SubscriptionFormSchema = React.useMemo(
|
||||||
|
() => getSubscriptionFormSchema(),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'setup-subscription-form'}>
|
<div className={'setup-subscription-form'}>
|
||||||
<Formik
|
<Formik
|
||||||
validationSchema={SubscriptionFormSchema}
|
validationSchema={SubscriptionFormSchema}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
@@ -44,6 +46,4 @@ function SetupSubscription({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default R.compose(
|
export default R.compose(withSubscriptionPlansActions)(SetupSubscription);
|
||||||
withSubscriptionPlansActions,
|
|
||||||
)(SetupSubscription);
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import SubscriptionPlansSection from './SubscriptionPlansSection';
|
||||||
|
import SubscriptionPeriodsSection from './SubscriptionPeriodsSection';
|
||||||
|
import SubscriptionPaymentMethodsSection from './SubscriptionPaymentsMethodsSection';
|
||||||
|
|
||||||
|
|
||||||
|
export default function SetupSubscriptionForm() {
|
||||||
|
return (
|
||||||
|
<div class="billing-plans">
|
||||||
|
<SubscriptionPlansSection />
|
||||||
|
<SubscriptionPeriodsSection />
|
||||||
|
<SubscriptionPaymentMethodsSection />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { T } from 'components';
|
||||||
|
|
||||||
|
import { PaymentMethodTabs } from '../../Subscriptions/SubscriptionTabs';
|
||||||
|
|
||||||
|
export default ({ formik, title, description }) => {
|
||||||
|
return (
|
||||||
|
<section class="billing-plans__section">
|
||||||
|
<h1 className="title">
|
||||||
|
<T id={'setup.plans.payment_methods.title'} />
|
||||||
|
</h1>
|
||||||
|
<p className="paragraph">
|
||||||
|
<T id={'setup.plans.payment_methods.description'} />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<PaymentMethodTabs formik={formik} />
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Field } from 'formik';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
|
import { T, SubscriptionPeriods } from 'components';
|
||||||
|
|
||||||
|
import withPlan from '../../Subscriptions/withPlan';
|
||||||
|
|
||||||
|
const SubscriptionPeriodsEnhanced = R.compose(
|
||||||
|
withPlan(({ plan }) => ({ plan })),
|
||||||
|
)(({ plan, ...restProps }) => {
|
||||||
|
return <SubscriptionPeriods periods={plan.periods} {...restProps} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Billing periods.
|
||||||
|
*/
|
||||||
|
export default function SubscriptionPeriodsSection() {
|
||||||
|
return (
|
||||||
|
<section class="billing-plans__section">
|
||||||
|
<h1 class="title">
|
||||||
|
<T id={'setup.plans.select_period.title'} />
|
||||||
|
</h1>
|
||||||
|
<div class="description">
|
||||||
|
<p className="paragraph">
|
||||||
|
<T id={'setup.plans.select_period.description'} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Field name={'period'}>
|
||||||
|
{({ form: { setFieldValue, values }, field: { value } }) => (
|
||||||
|
<SubscriptionPeriodsEnhanced
|
||||||
|
planSlug={values.plan_slug}
|
||||||
|
selectedPeriod={value}
|
||||||
|
onPeriodSelect={(period) => {
|
||||||
|
setFieldValue('period', period);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Field } from 'formik';
|
||||||
|
|
||||||
|
import { T, SubscriptionPlans } from 'components';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
import withPlans from '../../Subscriptions/withPlans';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Billing plans.
|
||||||
|
*/
|
||||||
|
function SubscriptionPlansSection({ plans }) {
|
||||||
|
return (
|
||||||
|
<section class="billing-plans__section">
|
||||||
|
<h1 class="title">
|
||||||
|
<T id={'setup.plans.select_plan.title'} />
|
||||||
|
</h1>
|
||||||
|
<div class="description">
|
||||||
|
<p className="paragraph">
|
||||||
|
<T id={'setup.plans.select_plan.description'} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Field name={'plan_slug'}>
|
||||||
|
{({ form: { setFieldValue }, field: { value } }) => (
|
||||||
|
<SubscriptionPlans
|
||||||
|
value={value}
|
||||||
|
plans={plans}
|
||||||
|
onSelect={(value) => {
|
||||||
|
setFieldValue('plan_slug', value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(withPlans(({ plans }) => ({ plans })))(
|
||||||
|
SubscriptionPlansSection,
|
||||||
|
);
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Form } from 'formik';
|
|
||||||
|
|
||||||
import BillingPlansForm from 'containers/Subscriptions/BillingPlansForm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscription step of wizard setup.
|
|
||||||
*/
|
|
||||||
export default function SetupSubscriptionForm() {
|
|
||||||
return (
|
|
||||||
<Form>
|
|
||||||
<BillingPlansForm />
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,7 @@ import { getSetupWizardSteps } from 'common/registerWizard';
|
|||||||
function WizardSetupStep({ label, isActive = false }) {
|
function WizardSetupStep({ label, isActive = false }) {
|
||||||
return (
|
return (
|
||||||
<li className={classNames({ 'is-active': isActive })}>
|
<li className={classNames({ 'is-active': isActive })}>
|
||||||
<p className={'wizard-info'}>
|
<p className={'wizard-info'}>{label}</p>
|
||||||
{ label }
|
|
||||||
</p>
|
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import * as Yup from 'yup';
|
|
||||||
import { Formik, Form } from 'formik';
|
import { Formik, Form } from 'formik';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
import { If, Alert, T } from 'components';
|
||||||
|
|
||||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||||
|
|
||||||
import 'style/pages/Billing/BillingPage.scss';
|
import 'style/pages/Billing/BillingPage.scss';
|
||||||
@@ -10,8 +11,11 @@ import { MasterBillingTabs } from './SubscriptionTabs';
|
|||||||
|
|
||||||
import withBillingActions from './withBillingActions';
|
import withBillingActions from './withBillingActions';
|
||||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||||
|
import withSubscriptionPlansActions from './withSubscriptionPlansActions';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
import { getBillingFormValidationSchema } from './utils';
|
||||||
|
import withSubscriptions from './withSubscriptions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Billing form.
|
* Billing form.
|
||||||
@@ -20,26 +24,30 @@ function BillingForm({
|
|||||||
// #withDashboardActions
|
// #withDashboardActions
|
||||||
changePageTitle,
|
changePageTitle,
|
||||||
|
|
||||||
//#withBillingActions
|
// #withBillingActions
|
||||||
requestSubmitBilling,
|
requestSubmitBilling,
|
||||||
|
|
||||||
|
initSubscriptionPlans,
|
||||||
|
|
||||||
|
// #withSubscriptions
|
||||||
|
isSubscriptionInactive,
|
||||||
}) {
|
}) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
changePageTitle(intl.get('billing'));
|
changePageTitle(intl.get('billing'));
|
||||||
}, [changePageTitle]);
|
}, [changePageTitle]);
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
React.useEffect(() => {
|
||||||
plan_slug: Yup.string()
|
initSubscriptionPlans();
|
||||||
.required(),
|
}, [initSubscriptionPlans]);
|
||||||
period: Yup.string().required(),
|
|
||||||
license_code: Yup.string().trim(),
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Initial values.
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
plan_slug: 'free',
|
plan_slug: 'free',
|
||||||
period: 'month',
|
period: 'month',
|
||||||
license_code: '',
|
license_code: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle form submitting.
|
||||||
const handleSubmit = (values, { setSubmitting }) => {
|
const handleSubmit = (values, { setSubmitting }) => {
|
||||||
requestSubmitBilling(values)
|
requestSubmitBilling(values)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@@ -53,20 +61,34 @@ function BillingForm({
|
|||||||
return (
|
return (
|
||||||
<DashboardInsider name={'billing-page'}>
|
<DashboardInsider name={'billing-page'}>
|
||||||
<div className={'billing-page'}>
|
<div className={'billing-page'}>
|
||||||
|
<If condition={isSubscriptionInactive}>
|
||||||
|
<Alert
|
||||||
|
intent={'danger'}
|
||||||
|
title={<T id={'billing.suspend_message.title'} />}
|
||||||
|
description={<T id={'billing.suspend_message.description'} />}
|
||||||
|
/>
|
||||||
|
</If>
|
||||||
|
|
||||||
<Formik
|
<Formik
|
||||||
validationSchema={validationSchema}
|
validationSchema={getBillingFormValidationSchema()}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
>
|
>
|
||||||
{({ isSubmitting, handleSubmit }) => (
|
<Form>
|
||||||
<Form>
|
<MasterBillingTabs />
|
||||||
<MasterBillingTabs />
|
</Form>
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
</DashboardInsider>
|
</DashboardInsider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(withDashboardActions, withBillingActions)(BillingForm);
|
export default compose(
|
||||||
|
withDashboardActions,
|
||||||
|
withBillingActions,
|
||||||
|
withSubscriptionPlansActions,
|
||||||
|
withSubscriptions(
|
||||||
|
({ isSubscriptionInactive }) => ({ isSubscriptionInactive }),
|
||||||
|
'main',
|
||||||
|
),
|
||||||
|
)(BillingForm);
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ import { saveInvoke } from 'utils';
|
|||||||
function BillingPeriod({
|
function BillingPeriod({
|
||||||
// #ownProps
|
// #ownProps
|
||||||
label,
|
label,
|
||||||
currencyCode,
|
|
||||||
value,
|
value,
|
||||||
selectedOption,
|
selectedOption,
|
||||||
onSelected,
|
onSelected,
|
||||||
period,
|
period,
|
||||||
|
|
||||||
|
// #withPlan
|
||||||
price,
|
price,
|
||||||
|
currencyCode,
|
||||||
}) {
|
}) {
|
||||||
const handlePeriodClick = () => {
|
const handlePeriodClick = () => {
|
||||||
saveInvoke(onSelected, value);
|
saveInvoke(onSelected, value);
|
||||||
|
|||||||
@@ -1,42 +1,46 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Field } from 'formik';
|
import { Field } from 'formik';
|
||||||
import BillingPeriod from './BillingPeriod';
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import withPlans from './withPlans';
|
import { T, SubscriptionPeriods } from 'components';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import withPlan from './withPlan';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sunscription periods enhanced.
|
||||||
|
*/
|
||||||
|
const SubscriptionPeriodsEnhanced = R.compose(
|
||||||
|
withPlan(({ plan }) => ({ plan })),
|
||||||
|
)(({ plan, ...restProps }) => {
|
||||||
|
return <SubscriptionPeriods periods={plan.periods} {...restProps} />;
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Billing periods.
|
* Billing periods.
|
||||||
*/
|
*/
|
||||||
function BillingPeriods({ title, description, plansPeriods }) {
|
export default function BillingPeriods() {
|
||||||
return (
|
return (
|
||||||
<section class="billing-plans__section">
|
<section class="billing-plans__section">
|
||||||
<h1 class="title">{title}</h1>
|
<h1 class="title">
|
||||||
|
<T id={'setup.plans.select_period.title'} />
|
||||||
|
</h1>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<p className="paragraph">{description}</p>
|
<p className="paragraph">
|
||||||
|
<T id={'setup.plans.select_period.description'} />
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Field name={'period'}>
|
<Field name={'period'}>
|
||||||
{({ form: { setFieldValue, values } }) => (
|
{({ field: { value }, form: { values, setFieldValue } }) => (
|
||||||
<div className={'plan-periods'}>
|
<SubscriptionPeriodsEnhanced
|
||||||
{plansPeriods.map((period) => (
|
selectedPeriod={value}
|
||||||
<BillingPeriod
|
planSlug={values.plan_slug}
|
||||||
planSlug={values.plan_slug}
|
onPeriodSelect={(period) => {
|
||||||
period={period.slug}
|
setFieldValue('period', period);
|
||||||
label={period.label}
|
}}
|
||||||
value={period.slug}
|
/>
|
||||||
onSelected={(value) => setFieldValue('period', value)}
|
|
||||||
selectedOption={values.period}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(withPlans(({ plansPeriods }) => ({ plansPeriods })))(
|
|
||||||
BillingPeriods,
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import classNames from 'classnames';
|
|||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
import 'style/pages/Subscription/PlanRadio.scss';
|
|
||||||
|
|
||||||
import { saveInvoke } from 'utils';
|
import { saveInvoke } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,9 +30,7 @@ export default function BillingPlan({
|
|||||||
onClick={handlePlanClick}
|
onClick={handlePlanClick}
|
||||||
>
|
>
|
||||||
<div className={'plan-radio__header'}>
|
<div className={'plan-radio__header'}>
|
||||||
<div className={'plan-radio__name'}>
|
<div className={'plan-radio__name'}>{name}</div>
|
||||||
{intl.get('plan_radio_name', { name: name })}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={'plan-radio__description'}>
|
<div className={'plan-radio__description'}>
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage as T } from 'components';
|
|
||||||
import intl from 'react-intl-universal';
|
|
||||||
|
|
||||||
import 'style/pages/Subscription/BillingPlans.scss';
|
import 'style/pages/Subscription/BillingPlans.scss';
|
||||||
|
|
||||||
import BillingPlansInput from 'containers/Subscriptions/BillingPlansInput';
|
import BillingPlansInput from './BillingPlansInput';
|
||||||
import BillingPeriodsInput from 'containers/Subscriptions/BillingPeriodsInput';
|
import BillingPeriodsInput from './BillingPeriodsInput';
|
||||||
import BillingPaymentMethod from 'containers/Subscriptions/BillingPaymentMethod';
|
import BillingPaymentMethod from './BillingPaymentMethod';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Billing plans form.
|
* Billing plans form.
|
||||||
@@ -14,18 +12,9 @@ import BillingPaymentMethod from 'containers/Subscriptions/BillingPaymentMethod'
|
|||||||
export default function BillingPlansForm() {
|
export default function BillingPlansForm() {
|
||||||
return (
|
return (
|
||||||
<div class="billing-plans">
|
<div class="billing-plans">
|
||||||
<BillingPlansInput
|
<BillingPlansInput />
|
||||||
title={intl.get('select_a_plan')}
|
<BillingPeriodsInput />
|
||||||
description={<T id={'please_enter_your_preferred_payment_method'} />}
|
<BillingPaymentMethod />
|
||||||
/>
|
|
||||||
<BillingPeriodsInput
|
|
||||||
title={intl.get('choose_your_billing')}
|
|
||||||
description={<T id={'please_enter_your_preferred_payment_method'} />}
|
|
||||||
/>
|
|
||||||
<BillingPaymentMethod
|
|
||||||
title={intl.get('payment_methods')}
|
|
||||||
description={<T id={'please_enter_your_preferred_payment_method'} />}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FastField, Field } from 'formik';
|
import { Field } from 'formik';
|
||||||
import BillingPlan from './BillingPlan';
|
import { T, SubscriptionPlans } from 'components';
|
||||||
|
|
||||||
import withPlans from './withPlans';
|
import withPlans from './withPlans';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
@@ -11,27 +11,24 @@ import { compose } from 'utils';
|
|||||||
function BillingPlans({ plans, title, description, selectedOption }) {
|
function BillingPlans({ plans, title, description, selectedOption }) {
|
||||||
return (
|
return (
|
||||||
<section class="billing-plans__section">
|
<section class="billing-plans__section">
|
||||||
<h1 class="title">{title}</h1>
|
<h1 class="title">
|
||||||
|
<T id={'setup.plans.select_plan.title'} />
|
||||||
|
</h1>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<p className="paragraph">{description}</p>
|
<p className="paragraph">
|
||||||
|
<T id={'setup.plans.select_plan.description'} />
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Field name={'plan_slug'}>
|
<Field name={'plan_slug'}>
|
||||||
{({ form: { setFieldValue }, field: { value } }) => (
|
{({ form: { setFieldValue }, field: { value } }) => (
|
||||||
<div className={'plan-radios'}>
|
<SubscriptionPlans
|
||||||
{plans.map((plan) => (
|
plans={plans}
|
||||||
<BillingPlan
|
value={value}
|
||||||
name={plan.name}
|
onSelect={(value) => {
|
||||||
description={plan.description}
|
setFieldValue('plan_slug', value);
|
||||||
slug={plan.slug}
|
}}
|
||||||
price={plan.price.month}
|
/>
|
||||||
currencyCode={plan.currencyCode}
|
|
||||||
value={plan.slug}
|
|
||||||
onSelected={(value) => setFieldValue('plan_slug', value)}
|
|
||||||
selectedOption={value}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import BillingPlansForm from 'containers/Subscriptions/BillingPlansForm';
|
import BillingPlansForm from './BillingPlansForm';
|
||||||
|
|
||||||
export default function BillingTab() {
|
export default function BillingTab() {
|
||||||
return (
|
return (<BillingPlansForm />);
|
||||||
<div>
|
|
||||||
<BillingPlansForm />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
@@ -16,11 +16,7 @@ export const MasterBillingTabs = ({ formik }) => {
|
|||||||
id={'billing'}
|
id={'billing'}
|
||||||
panel={<BillingTab formik={formik} />}
|
panel={<BillingTab formik={formik} />}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab title={intl.get('usage')} id={'usage'} disabled={true} />
|
||||||
title={intl.get('usage')}
|
|
||||||
id={'usage'}
|
|
||||||
disabled={true}
|
|
||||||
/>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -43,11 +39,7 @@ export const PaymentMethodTabs = ({ formik }) => {
|
|||||||
id={'credit_card'}
|
id={'credit_card'}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab title={intl.get('paypal')} id={'paypal'} disabled={true} />
|
||||||
title={intl.get('paypal')}
|
|
||||||
id={'paypal'}
|
|
||||||
disabled={true}
|
|
||||||
/>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { T } from 'components';
|
||||||
import { PaymentMethodTabs } from './SubscriptionTabs';
|
import { PaymentMethodTabs } from './SubscriptionTabs';
|
||||||
|
|
||||||
export default ({ formik, title, description }) => {
|
export default ({ formik, title, description }) => {
|
||||||
return (
|
return (
|
||||||
<section class="billing-plans__section">
|
<section class="billing-plans__section">
|
||||||
<h1 className="title">{ title }</h1>
|
<h1 className="title"><T id={'setup.plans.payment_methods.title'} /></h1>
|
||||||
<p className="paragraph">{ description }</p>
|
<p className="paragraph"><T id={'setup.plans.payment_methods.description' } /></p>
|
||||||
|
|
||||||
<PaymentMethodTabs formik={formik} />
|
<PaymentMethodTabs formik={formik} />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
8
client/src/containers/Subscriptions/utils.js
Normal file
8
client/src/containers/Subscriptions/utils.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
|
export const getBillingFormValidationSchema = () =>
|
||||||
|
Yup.object().shape({
|
||||||
|
plan_slug: Yup.string().required(),
|
||||||
|
period: Yup.string().required(),
|
||||||
|
license_code: Yup.string().trim(),
|
||||||
|
});
|
||||||
@@ -1,17 +1,14 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
getPlansSelector,
|
getPlansSelector,
|
||||||
getPlansPeriodsSelector,
|
|
||||||
} from 'store/plans/plans.selectors';
|
} from 'store/plans/plans.selectors';
|
||||||
|
|
||||||
export default (mapState) => {
|
export default (mapState) => {
|
||||||
const mapStateToProps = (state, props) => {
|
const mapStateToProps = (state, props) => {
|
||||||
const getPlans = getPlansSelector();
|
const getPlans = getPlansSelector();
|
||||||
const getPlansPeriods = getPlansPeriodsSelector();
|
|
||||||
|
|
||||||
const mapped = {
|
const mapped = {
|
||||||
plans: getPlans(state, props),
|
plans: getPlans(state, props),
|
||||||
plansPeriods: getPlansPeriods(state, props),
|
|
||||||
};
|
};
|
||||||
return mapState ? mapState(mapped, state, props) : mapped;
|
return mapState ? mapState(mapped, state, props) : mapped;
|
||||||
};
|
};
|
||||||
|
|||||||
19
client/src/containers/Subscriptions/withSubscriptionss.js
Normal file
19
client/src/containers/Subscriptions/withSubscriptionss.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
isSubscriptionsInactiveFactory,
|
||||||
|
isSubscriptionsActiveFactory
|
||||||
|
} from 'store/subscription/subscription.selectors';
|
||||||
|
|
||||||
|
export default (mapState) => {
|
||||||
|
const isSubscriptionsInactive = isSubscriptionsInactiveFactory();
|
||||||
|
const isSubscriptionsActive = isSubscriptionsActiveFactory();
|
||||||
|
|
||||||
|
const mapStateToProps = (state, props) => {
|
||||||
|
const mapped = {
|
||||||
|
isSubscriptionsInactive: isSubscriptionsInactive(state, props),
|
||||||
|
isSubscriptionsActive: isSubscriptionsActive(state, props),
|
||||||
|
};
|
||||||
|
return (mapState) ? mapState(mapped, state, props) : mapped;
|
||||||
|
};
|
||||||
|
return connect(mapStateToProps);
|
||||||
|
};
|
||||||
@@ -23,23 +23,18 @@ export function useSaveSettings(props) {
|
|||||||
function useSettingsQuery(key, query, props) {
|
function useSettingsQuery(key, query, props) {
|
||||||
const setSettings = useSetSettings();
|
const setSettings = useSetSettings();
|
||||||
|
|
||||||
const state = useRequestQuery(
|
return useRequestQuery(
|
||||||
key,
|
key,
|
||||||
{ method: 'get', url: 'settings', params: query },
|
{ method: 'get', url: 'settings', params: query },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.settings,
|
select: (res) => res.data.settings,
|
||||||
defaultData: [],
|
defaultData: [],
|
||||||
|
onSuccess: (settings) => {
|
||||||
|
setSettings(settings);
|
||||||
|
},
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (state.isSuccess) {
|
|
||||||
setSettings(state.data);
|
|
||||||
}
|
|
||||||
}, [state.data, state.isSuccess, setSettings]);
|
|
||||||
|
|
||||||
return state.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -584,7 +584,7 @@
|
|||||||
"payment_mades": "سندات الموردين",
|
"payment_mades": "سندات الموردين",
|
||||||
"subscription": "الاشتراك",
|
"subscription": "الاشتراك",
|
||||||
"plan_slug": "سبيكة خطة",
|
"plan_slug": "سبيكة خطة",
|
||||||
"billing": "الفواتير",
|
"billing": "الاشتراك",
|
||||||
"the_billing_has_been_created_successfully": "تم إنشاء الفواتير بنجاح.",
|
"the_billing_has_been_created_successfully": "تم إنشاء الفواتير بنجاح.",
|
||||||
"select_a_plan": "حدد الباقة",
|
"select_a_plan": "حدد الباقة",
|
||||||
"choose_your_billing": "اختر مدة الدفع",
|
"choose_your_billing": "اختر مدة الدفع",
|
||||||
@@ -1114,12 +1114,10 @@
|
|||||||
"filter_": "البحث...",
|
"filter_": "البحث...",
|
||||||
"all_rights_reserved": "© {pre}-{current} كل الحقوق محفوظة.",
|
"all_rights_reserved": "© {pre}-{current} كل الحقوق محفوظة.",
|
||||||
"congrats_your_account_has_been_created_and_invited": "مبروك! تم إنشاء حسابك ودعوتك إلى <strong>{organization_name} </strong> بنجاح.",
|
"congrats_your_account_has_been_created_and_invited": "مبروك! تم إنشاء حسابك ودعوتك إلى <strong>{organization_name} </strong> بنجاح.",
|
||||||
"it_s_time_to_make_your_accounting_really_simple": "حان الوقت لجعل عملية المحاسبة الخاصة بك بسيطة واكتر دقة!",
|
|
||||||
"while_we_set_up_your_account_please_remember_to_verify_your_account": "أثناء قيامنا بإعداد حسابك ، يرجى تذكر التحقق من حسابك بالنقر فوق الارتباط الذي أرسلناه إلى عنوان بريدك الإلكتروني المسجل",
|
"while_we_set_up_your_account_please_remember_to_verify_your_account": "أثناء قيامنا بإعداد حسابك ، يرجى تذكر التحقق من حسابك بالنقر فوق الارتباط الذي أرسلناه إلى عنوان بريدك الإلكتروني المسجل",
|
||||||
"something_went_wrong": "هناك خطأ ما!",
|
|
||||||
"please_refresh_the_page": "يرجى تحديث الصفحة",
|
|
||||||
"waiting_to_redirect": "في انتظار إعادة التوجيه",
|
|
||||||
"refresh_the_page_if_redirect_not_worked": "قم بتحديث الصفحة إذا لم تنجح إعادة التوجيه.",
|
|
||||||
"blog": "المدونة",
|
"blog": "المدونة",
|
||||||
"support": "الدعم النفي",
|
"support": "الدعم النفي",
|
||||||
"service_status": "حالة الخدمة",
|
"service_status": "حالة الخدمة",
|
||||||
@@ -1220,6 +1218,67 @@
|
|||||||
"pdf_preview.preview.button": "معاينة",
|
"pdf_preview.preview.button": "معاينة",
|
||||||
"invoice_preview.dialog.title": "معاينة فاتورة PDF",
|
"invoice_preview.dialog.title": "معاينة فاتورة PDF",
|
||||||
"estimate_preview.dialog.title": "معاينة عرض PDF",
|
"estimate_preview.dialog.title": "معاينة عرض PDF",
|
||||||
"receipt_preview.dialog.title":"معاينة إيصال PDF"
|
"receipt_preview.dialog.title":"معاينة إيصال PDF",
|
||||||
|
"edit_contact": "Edit {name}",
|
||||||
|
"item.sell_description": "Sell description",
|
||||||
|
"item.purchase_description": "Purchase description",
|
||||||
|
"closed_date": "Closed date",
|
||||||
|
"payment_made.details.payment_number": "Payment #",
|
||||||
|
"payment_receive.details.payment_number": "Payment #",
|
||||||
|
"estimate.details.estimate_number": "Estimate #",
|
||||||
|
"receipt.details.receipt_number": "Receipt #",
|
||||||
|
"bill.details.bill_number": "Bill #",
|
||||||
|
"setup.left_side.title": "سجل منشأة جديدة الأن.",
|
||||||
|
"setup.left_side.description": "حسابك علي Bigcapital",
|
||||||
|
"setup.left_side.footer_help": "نحن هنا للمساعدة!",
|
||||||
|
"setup.plan.plans": "الخطط والدفع",
|
||||||
|
"setup.plan.initializing": "التهيئة",
|
||||||
|
"setup.plan.getting_started": "البدء",
|
||||||
|
"setup.plan.congrats": "تهانينا",
|
||||||
|
"setup.plans.select_plan.description": "الرجاء إدخال طريقة الدفع المفضلة لديك أدناه. يمكنك استخدام بطاقة الائتمان / الخصم أو الدفع المسبق من خلال PayPal. ",
|
||||||
|
"setup.plans.select_plan.title": "اختر الخطة",
|
||||||
|
"setup.plans.select_period.title": "اختر الفترة",
|
||||||
|
"setup.plans.select_period.description": "يمكن تسديد الخطة شهرياً او سنوياً.",
|
||||||
|
"setup.plans.payment_methods.title": "طرق الدفع",
|
||||||
|
"setup.plans.payment_methods.description": "",
|
||||||
|
"setup.initializing.title": "حان الوقت لجعل عملية المحاسبة الخاصة بك بسيطة واكتر دقة!",
|
||||||
|
"setup.initializing.description": "أثناء قيامنا بإعداد حسابك ، يرجى تذكر التحقق من حسابك بالنقر فوق الارتباط الذي أرسلناه إلى عنوان بريدك الإلكتروني المسجل",
|
||||||
|
"setup.initializing.waiting_to_redirect": "في انتظار إعادة التوجيه",
|
||||||
|
"setup.initializing.refresh_the_page_if_redirect_not_worked": "قم بتحديث الصفحة إذا لم تنجح إعادة التوجيه.",
|
||||||
|
"setup.initializing.something_went_wrong": "هناك خطأ ما!",
|
||||||
|
"setup.initializing.please_refresh_the_page": "يرجى تحديث الصفحة",
|
||||||
|
"setup.organization.title": "دعنا نبدأ",
|
||||||
|
"setup.organization.description": "أخبر النظام قليلاً عن مؤسستك.",
|
||||||
|
"plan.essential.title": "الاساسية",
|
||||||
|
"plan.plus.title": "الاضافية",
|
||||||
|
"plan.professional.title": "الاحترافية",
|
||||||
|
"plan.feature.sale_purchase_invoice": "فواتير البيع والشراء.",
|
||||||
|
"plan.feature.receivable_payable_accounts": "حسابات العملاء والموردين.",
|
||||||
|
"plan.feature.expenses_tracking": "تتبع المصروفات",
|
||||||
|
"plan.feature.manual_journal": "القيود اليدوية",
|
||||||
|
"plan.feature.financial_reports": "القوائم المالية",
|
||||||
|
"plan.feature.one_user_with_accountant": "لمستخدم واحد والمحاسب",
|
||||||
|
"plan.feature.all_capital_essential": "جميع مميزات الباقة الاساسية",
|
||||||
|
"plan.feature.multi_currency": "تعدد العملات",
|
||||||
|
"plan.feature.purchase_sell_orders": "أوامر الشراء والبيع.",
|
||||||
|
"plan.feature.multi_inventory_managment": "تعدد المخازن.",
|
||||||
|
"plan.feature.three_users": "ثلاثة مستخدمين مع المحاسب",
|
||||||
|
"plan.feature.advanced_financial_reports": "تقارير المالية المتقدمة",
|
||||||
|
"plan.feature.tracking_multi_locations": "تتبع الفروع والمواقع",
|
||||||
|
"plan.feture.all_capital_professional_features": "جميع مميزات الباقة الاحترافية",
|
||||||
|
"plan.feature.projects_accounting": "محاسبة المشاريع والجداول الزمنية",
|
||||||
|
"plan.feature.accounting_dimensions": "محاسبة ثلاثية الابعاد",
|
||||||
|
"plan.monthly": "شهريا",
|
||||||
|
"plan.yearly": "سنوياً",
|
||||||
|
"payment_via_voucher.success_message": "تم الدفع وتجديد واشتراكك بنجاح.",
|
||||||
|
"payment_via_voucher.license_code_not_valid": "رقم الرخصة غير صالح ، يرجي المحاولة مرة أخرى",
|
||||||
|
"payment_via_voucher.dialog.description": "الرجاء إدخال رقم الرخصة التي استلمتها عند تجديد او طلب الاشتراك .",
|
||||||
|
"setup.organization.note_you_can_change_your_preferences": "ملاحظة: يمكنك تغيير تفضيلاتك لاحقًا في لوحة التحكم ، إذا لزم الأمر.",
|
||||||
|
"setup.congrats.title": "تهانينا! حسابك جاهز للعمل",
|
||||||
|
"setup.congrats.description": "تهانينا ، تم إعداد مؤسستك بنجاح. يمكنك البدء في العمل بمجرد الانتقال إلى لوحة التحكم.",
|
||||||
|
"setup.congrats.go_to_dashboard": "اذهب إلي لوحة التحكم",
|
||||||
|
"billing.suspend_message.title": "حسابك معلق :(",
|
||||||
|
"billing.suspend_message.description": "تم تعليق حسابك بسبب انتهاء فترة الاشتراك. الرجاء تجديد الاشتراك لتفعيل الحساب.",
|
||||||
|
"dashboard.subscription_msg.period_over": "انتهت فترة الاشتراك"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -578,7 +578,6 @@
|
|||||||
"plan_slug": "Plan slug",
|
"plan_slug": "Plan slug",
|
||||||
"billing": "Billing",
|
"billing": "Billing",
|
||||||
"the_billing_has_been_created_successfully": "The billing has been created successfully.",
|
"the_billing_has_been_created_successfully": "The billing has been created successfully.",
|
||||||
"select_a_plan": "Select a plan",
|
|
||||||
"choose_your_billing": "Choose your billing",
|
"choose_your_billing": "Choose your billing",
|
||||||
"payment_methods": "Payment methods",
|
"payment_methods": "Payment methods",
|
||||||
"usage": "Usage",
|
"usage": "Usage",
|
||||||
@@ -591,7 +590,6 @@
|
|||||||
"yearly": "Yearly",
|
"yearly": "Yearly",
|
||||||
"license_code": "License Code",
|
"license_code": "License Code",
|
||||||
"year": "Year",
|
"year": "Year",
|
||||||
"please_enter_your_preferred_payment_method": "Please enter your preferred payment method below. You can use a credit / debit card or prepay through PayPal. ",
|
|
||||||
"cards_will_be_charged": "Cards will be charged either at the end of the month or whenever your balance exceeds the usage threshold. All major credit / debit cards accepted.",
|
"cards_will_be_charged": "Cards will be charged either at the end of the month or whenever your balance exceeds the usage threshold. All major credit / debit cards accepted.",
|
||||||
"license_number": "License number",
|
"license_number": "License number",
|
||||||
"subscribe": "Subscribe",
|
"subscribe": "Subscribe",
|
||||||
@@ -616,20 +614,15 @@
|
|||||||
"purchasable": "Purchasable",
|
"purchasable": "Purchasable",
|
||||||
"sell_account": "Sell Account",
|
"sell_account": "Sell Account",
|
||||||
"cost_account": "Cost Account",
|
"cost_account": "Cost Account",
|
||||||
"register_a_new_organization_now": "Register a New Organization now!.",
|
|
||||||
"you_have_a_bigcapital_account": "You have a Bigcapital account ",
|
|
||||||
"contact_us_technical_support": "Contact us - Technical Support",
|
"contact_us_technical_support": "Contact us - Technical Support",
|
||||||
"let_s_get_started": "Let’s Get Started",
|
|
||||||
"tell_the_system_a_little_bit_about_your_organization": "Tell the system a little bit about your organization.",
|
|
||||||
"organization_details": "Organization details",
|
"organization_details": "Organization details",
|
||||||
"financial_starting_date": "Financial starting date ",
|
"financial_starting_date": "Financial starting date ",
|
||||||
"note_you_can_change_your_preferences_later_in_dashboard_if_needed": "Note: You can change your preferences later in dashboard, if needed.",
|
|
||||||
"save_continue": "Save & Continue",
|
"save_continue": "Save & Continue",
|
||||||
"organization_register": "Organization Register",
|
"organization_register": "Organization Register",
|
||||||
"fiscal_year_": "Fiscal year",
|
"fiscal_year_": "Fiscal year",
|
||||||
"welcome": "Welcome ",
|
"welcome": "Welcome ",
|
||||||
"sign_out": "Sign out",
|
"sign_out": "Sign out",
|
||||||
"we_re_here_to_help": "We’re Here to Help!",
|
|
||||||
"date_start_": "Date start",
|
"date_start_": "Date start",
|
||||||
"something_wentwrong": "Something went wrong.",
|
"something_wentwrong": "Something went wrong.",
|
||||||
"license_code_": "License code",
|
"license_code_": "License code",
|
||||||
@@ -906,7 +899,6 @@
|
|||||||
"accounting": "Accounting",
|
"accounting": "Accounting",
|
||||||
"system": "SYSTEM",
|
"system": "SYSTEM",
|
||||||
"it_s_time_to_send_estimates_to_your_customers": "It's time to send estimates to your customers",
|
"it_s_time_to_send_estimates_to_your_customers": "It's time to send estimates to your customers",
|
||||||
"it_is_a_long_established_fact_that_a_reader": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.",
|
|
||||||
"new_sale_estimate": "New sale estimate",
|
"new_sale_estimate": "New sale estimate",
|
||||||
"learn_more": "Learn more",
|
"learn_more": "Learn more",
|
||||||
"back_to_list": "Back to list.",
|
"back_to_list": "Back to list.",
|
||||||
@@ -1068,8 +1060,7 @@
|
|||||||
"products_you_buy_and_or_sell": "<strong> Inventory :</strong> Products you buy and/or sell and that you track quantities of.",
|
"products_you_buy_and_or_sell": "<strong> Inventory :</strong> Products you buy and/or sell and that you track quantities of.",
|
||||||
"products_you_buy_and_or_sell_but_don_t_need": "<strong> Non-Inventory:</strong> Products you buy and/or sell but don’t need to (or can’t) track quantities of, for example, nuts and bolts used in an installation.",
|
"products_you_buy_and_or_sell_but_don_t_need": "<strong> Non-Inventory:</strong> Products you buy and/or sell but don’t need to (or can’t) track quantities of, for example, nuts and bolts used in an installation.",
|
||||||
"there_is_no_items_in_the_table_yet": "There is no items in the table yet.",
|
"there_is_no_items_in_the_table_yet": "There is no items in the table yet.",
|
||||||
"congrats_you_are_ready_to_go": "Congrats! You are ready to go",
|
|
||||||
"go_to_dashboard": "Go to dashboard",
|
|
||||||
"mr": "Mr.",
|
"mr": "Mr.",
|
||||||
"mrs": "Mrs.",
|
"mrs": "Mrs.",
|
||||||
"ms": "Ms.",
|
"ms": "Ms.",
|
||||||
@@ -1101,25 +1092,13 @@
|
|||||||
"filter_": "Filter...",
|
"filter_": "Filter...",
|
||||||
"all_rights_reserved": "© {pre}-{current} All Rights Reserved.",
|
"all_rights_reserved": "© {pre}-{current} All Rights Reserved.",
|
||||||
"congrats_your_account_has_been_created_and_invited": "Congrats! Your account has been created and invited to <strong>{organization_name} </strong> organization successfully.",
|
"congrats_your_account_has_been_created_and_invited": "Congrats! Your account has been created and invited to <strong>{organization_name} </strong> organization successfully.",
|
||||||
"it_s_time_to_make_your_accounting_really_simple": "It's time to make your accounting really simple!",
|
|
||||||
"while_we_set_up_your_account_please_remember_to_verify_your_account": "while we set up your account, please remember to verify your account by clicking on the link we sent to your registered email address",
|
|
||||||
"something_went_wrong": "Something went wrong!",
|
"something_went_wrong": "Something went wrong!",
|
||||||
"please_refresh_the_page": "Please refresh the page",
|
|
||||||
"waiting_to_redirect": "Waiting to redirect",
|
|
||||||
"refresh_the_page_if_redirect_not_worked": "Refresh the page if redirect not worked.",
|
|
||||||
"blog": "Blog",
|
"blog": "Blog",
|
||||||
"support": "Support",
|
"support": "Support",
|
||||||
"service_status": "Service Status",
|
"service_status": "Service Status",
|
||||||
"pricing": "Pricing",
|
"pricing": "Pricing",
|
||||||
"reseller_partner": "Reseller Partner",
|
"reseller_partner": "Reseller Partner",
|
||||||
"docs": "Docs",
|
"docs": "Docs",
|
||||||
"Pleasse enter your voucher number that you received from reseller.": "Pleasse enter your voucher number that you received from reseller.",
|
|
||||||
"Sale and purchase invoices.": "Sale and purchase invoices.",
|
|
||||||
"Customers/vendors accounts.": "Customers/vendors accounts.",
|
|
||||||
"Expenses tracking.": "Expenses tracking.",
|
|
||||||
"Manual journals.": "Manual journals.",
|
|
||||||
"Financial reports.": "Financial reports.",
|
|
||||||
"All Capital Starter features.": "All Capital Starter features.",
|
|
||||||
"Multi-currency.": "Multi-currency.",
|
"Multi-currency.": "Multi-currency.",
|
||||||
"Purchase and sell orders.": "Purchase and sell orders.",
|
"Purchase and sell orders.": "Purchase and sell orders.",
|
||||||
"Inventory management.": "Inventory management.",
|
"Inventory management.": "Inventory management.",
|
||||||
@@ -1129,14 +1108,13 @@
|
|||||||
"Track multi-branches and locations.": "Track multi-branches and locations.",
|
"Track multi-branches and locations.": "Track multi-branches and locations.",
|
||||||
"Projects accounting and timesheets.": "Projects accounting and timesheets.",
|
"Projects accounting and timesheets.": "Projects accounting and timesheets.",
|
||||||
"Accounting dimensions.": "Accounting dimensions.",
|
"Accounting dimensions.": "Accounting dimensions.",
|
||||||
"For one user and accountant.": "For one user and accountant.",
|
|
||||||
"Monthly": "Monthly",
|
"Monthly": "Monthly",
|
||||||
"Yearly": "Yearly",
|
"Yearly": "Yearly",
|
||||||
"Plans & Payment": "Plans & Payment",
|
"Plans & Payment": "Plans & Payment",
|
||||||
"Initializing": "Initializing",
|
"Initializing": "Initializing",
|
||||||
"Getting started": "Getting started",
|
"Getting started": "Getting started",
|
||||||
"Congratulations": "Congratulations",
|
"Congratulations": "Congratulations",
|
||||||
"payment_has_been_done_successfully": "Payment has been done successfully.",
|
|
||||||
"manual_journal_number": "Manual journal {number}",
|
"manual_journal_number": "Manual journal {number}",
|
||||||
"conditions_and_terms": "Conditions and terms",
|
"conditions_and_terms": "Conditions and terms",
|
||||||
"allocate_landed_coast": "Allocate landed cost",
|
"allocate_landed_coast": "Allocate landed cost",
|
||||||
@@ -1167,12 +1145,12 @@
|
|||||||
"Landed": "Landed",
|
"Landed": "Landed",
|
||||||
"This options allows you to be able to add additional cost eg. freight then allocate cost to the items in your bills.": "This options allows you to be able to add additional cost eg. freight then allocate cost to the items in your bills.",
|
"This options allows you to be able to add additional cost eg. freight then allocate cost to the items in your bills.": "This options allows you to be able to add additional cost eg. freight then allocate cost to the items in your bills.",
|
||||||
"Once your delete this located landed cost, you won't be able to restore it later, Are your sure you want to delete this transaction?": "Once your delete this located landed cost, you won't be able to restore it later, Are your sure you want to delete this transaction?",
|
"Once your delete this located landed cost, you won't be able to restore it later, Are your sure you want to delete this transaction?": "Once your delete this located landed cost, you won't be able to restore it later, Are your sure you want to delete this transaction?",
|
||||||
"journal_entries":"Journal entries",
|
"journal_entries": "Journal entries",
|
||||||
"contact":"Contact",
|
"contact": "Contact",
|
||||||
"invoice_details":"Invoice details",
|
"invoice_details": "Invoice details",
|
||||||
"receipt_details":"Receipt details",
|
"receipt_details": "Receipt details",
|
||||||
"payment_receive_details":"Payment receive details",
|
"payment_receive_details": "Payment receive details",
|
||||||
"payment_made_details":"Payment made details",
|
"payment_made_details": "Payment made details",
|
||||||
"New item category": "New item category",
|
"New item category": "New item category",
|
||||||
"New service": "New service",
|
"New service": "New service",
|
||||||
"New inventory item": "New inventory item",
|
"New inventory item": "New inventory item",
|
||||||
@@ -1182,10 +1160,10 @@
|
|||||||
"New tasks": "New tasks",
|
"New tasks": "New tasks",
|
||||||
"sorry_about_that_something_went_wrong": "Sorry about that! Something went wrong",
|
"sorry_about_that_something_went_wrong": "Sorry about that! Something went wrong",
|
||||||
"if_the_problem_stuck_please_contact_us_as_soon_as_possible": "If the problem stuck, please contact us as soon as possible.",
|
"if_the_problem_stuck_please_contact_us_as_soon_as_possible": "If the problem stuck, please contact us as soon as possible.",
|
||||||
"non-inventory":"Non-Inventory",
|
"non-inventory": "Non-Inventory",
|
||||||
"terms_conditions":"Terms conditions",
|
"terms_conditions": "Terms conditions",
|
||||||
"your_invoice_numbers_are_set_on_auto_increment_mod_are_you_sure_changing_this_setting":"Your invoice numbers are set on auto-increment mod. Are you sure changing this setting?",
|
"your_invoice_numbers_are_set_on_auto_increment_mod_are_you_sure_changing_this_setting": "Your invoice numbers are set on auto-increment mod. Are you sure changing this setting?",
|
||||||
"auto_incrementing_number":"Auto-incrementing number",
|
"auto_incrementing_number": "Auto-incrementing number",
|
||||||
"inventory_adjustment.publish.success_message": "The inventory adjustment has been published successfully.",
|
"inventory_adjustment.publish.success_message": "The inventory adjustment has been published successfully.",
|
||||||
"inventory_adjustment.publish.alert_message": "Are you sure you want to publish this inventory adjustment?",
|
"inventory_adjustment.publish.alert_message": "Are you sure you want to publish this inventory adjustment?",
|
||||||
"the_contact_has_been_activated_successfully": "The contact has been inactivated successfully.",
|
"the_contact_has_been_activated_successfully": "The contact has been inactivated successfully.",
|
||||||
@@ -1207,15 +1185,67 @@
|
|||||||
"pdf_preview.download.button": "Download",
|
"pdf_preview.download.button": "Download",
|
||||||
"pdf_preview.preview.button": "Preview",
|
"pdf_preview.preview.button": "Preview",
|
||||||
"invoice_preview.dialog.title": "Invoice PDF Preview",
|
"invoice_preview.dialog.title": "Invoice PDF Preview",
|
||||||
"estimate_preview.dialog.title":"Estimate PDF Preview",
|
"estimate_preview.dialog.title": "Estimate PDF Preview",
|
||||||
"receipt_preview.dialog.title":"Receipt PDF Preview",
|
"receipt_preview.dialog.title": "Receipt PDF Preview",
|
||||||
"edit_contact":"Edit {name}",
|
"edit_contact": "Edit {name}",
|
||||||
"item.sell_description": "Sell description",
|
"item.sell_description": "Sell description",
|
||||||
"item.purchase_description": "Purchase description",
|
"item.purchase_description": "Purchase description",
|
||||||
"closed_date":"Closed date",
|
"closed_date": "Closed date",
|
||||||
"payment_made.details.payment_number": "Payment #",
|
"payment_made.details.payment_number": "Payment #",
|
||||||
"payment_receive.details.payment_number": "Payment #",
|
"payment_receive.details.payment_number": "Payment #",
|
||||||
"estimate.details.estimate_number": "Estimate #",
|
"estimate.details.estimate_number": "Estimate #",
|
||||||
"receipt.details.receipt_number": "Receipt #",
|
"receipt.details.receipt_number": "Receipt #",
|
||||||
"bill.details.bill_number": "Bill #"
|
"bill.details.bill_number": "Bill #",
|
||||||
|
"setup.left_side.title": "Register a New Organization now!.",
|
||||||
|
"setup.left_side.description": "You have a Bigcapital account",
|
||||||
|
"setup.left_side.footer_help": "We’re Here to Help!",
|
||||||
|
"setup.plan.plans": "Plans & Payment",
|
||||||
|
"setup.plan.initializing": "Initializing",
|
||||||
|
"setup.plan.getting_started": "Getting started",
|
||||||
|
"setup.plan.congrats": "Congratulations",
|
||||||
|
"setup.plans.select_plan.description": "Please enter your preferred payment method below. You can use a credit / debit card or prepay through PayPal. ",
|
||||||
|
"setup.plans.select_plan.title": "Select a plan",
|
||||||
|
"setup.plans.select_period.title": "Plan period",
|
||||||
|
"setup.plans.select_period.description": "The plan could be billed monthly or annually.",
|
||||||
|
"setup.plans.payment_methods.title": "Payment methods",
|
||||||
|
"setup.plans.payment_methods.description": "",
|
||||||
|
"setup.initializing.title": "It's time to make your accounting really simple!",
|
||||||
|
"setup.initializing.description": "while we set up your account, please remember to verify your account by clicking on the link we sent to your registered email address",
|
||||||
|
"setup.initializing.waiting_to_redirect": "Waiting to redirect",
|
||||||
|
"setup.initializing.refresh_the_page_if_redirect_not_worked": "Refresh the page if redirect not worked.",
|
||||||
|
"setup.initializing.something_went_wrong": "Something went wrong!",
|
||||||
|
"setup.initializing.please_refresh_the_page": "Please refresh the page",
|
||||||
|
"setup.organization.title": "Let’s Get Started",
|
||||||
|
"setup.organization.description": "Tell the system a little bit about your organization.",
|
||||||
|
"plan.professional.title": "Pro",
|
||||||
|
"plan.essential.title": "Essential",
|
||||||
|
"plan.plus.title": "Plus+",
|
||||||
|
"plan.feature.sale_purchase_invoice": "Sale and purchase invoices.",
|
||||||
|
"plan.feature.receivable_payable_accounts": "Customers/vendors accounts.",
|
||||||
|
"plan.feature.expenses_tracking": "Expenses tracking",
|
||||||
|
"plan.feature.manual_journal": "Manual journals.",
|
||||||
|
"plan.feature.financial_reports": "Financial reports.",
|
||||||
|
"plan.feature.one_user_with_accountant": "For one user and accountant",
|
||||||
|
"plan.feture.all_capital_professional_features": "All Capital Pro features.",
|
||||||
|
"plan.feature.multi_currency": "Multi-currency.",
|
||||||
|
"plan.feature.purchase_sell_orders": "Purchase and sell orders.",
|
||||||
|
"plan.feature.multi_inventory_managment": "Mutli-inventory managment.",
|
||||||
|
"plan.feature.three_users": "Three users with your accountant",
|
||||||
|
"plan.feature.advanced_financial_reports": "Advanced financial reports",
|
||||||
|
"plan.feature.tracking_multi_locations": "Track multi-branches and locations",
|
||||||
|
"plan.feature.all_capital_essential": "All Capital Essential features.",
|
||||||
|
"plan.feature.projects_accounting": "Projects accounting and timesheets",
|
||||||
|
"plan.feature.accounting_dimensions": "Accounting dimensions.",
|
||||||
|
"plan.monthly": "Monthly",
|
||||||
|
"plan.yearly": "Yearly",
|
||||||
|
"payment_via_voucher.success_message": "Payment has been done successfully.",
|
||||||
|
"payment_via_voucher.license_code_not_valid": "The license code is not valid, please try agin.",
|
||||||
|
"payment_via_voucher.dialog.description": "Pleasse enter your voucher number that you received from reseller.",
|
||||||
|
"setup.organization.note_you_can_change_your_preferences": "Note: You can change your preferences later in dashboard, if needed.",
|
||||||
|
"setup.congrats.title": "Congrats! You are ready to go",
|
||||||
|
"setup.congrats.description": "Congrats, Your organization is set up successfully. you can start working once go to dashboard.",
|
||||||
|
"setup.congrats.go_to_dashboard": "Go to dashboard",
|
||||||
|
"billing.suspend_message.title": "Your account is suspended :(",
|
||||||
|
"billing.suspend_message.description": "Your account has been suspended due to the expiration of the subscription period. Please renew the subscription to activate the account.",
|
||||||
|
"dashboard.subscription_msg.period_over": "Subscription period is over"
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,14 @@ import { lazy } from 'react';
|
|||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { RESOURCES_TYPES } from '../common/resourcesTypes';
|
import { RESOURCES_TYPES } from '../common/resourcesTypes';
|
||||||
|
|
||||||
|
|
||||||
|
const SUBSCRIPTION_TYPE = {
|
||||||
|
MAIN: 'main',
|
||||||
|
}
|
||||||
// const BASE_URL = '/dashboard';
|
// const BASE_URL = '/dashboard';
|
||||||
|
|
||||||
export const getDashboardRoutes = () => [
|
export const getDashboardRoutes = () => [
|
||||||
// // Accounts.
|
// Accounts.
|
||||||
{
|
{
|
||||||
path: `/accounts`,
|
path: `/accounts`,
|
||||||
component: lazy(() => import('containers/Accounts/AccountsChart')),
|
component: lazy(() => import('containers/Accounts/AccountsChart')),
|
||||||
@@ -14,6 +18,7 @@ export const getDashboardRoutes = () => [
|
|||||||
hotkey: 'shift+a',
|
hotkey: 'shift+a',
|
||||||
pageTitle: intl.get('accounts_chart'),
|
pageTitle: intl.get('accounts_chart'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.ACCOUNT,
|
defaultSearchResource: RESOURCES_TYPES.ACCOUNT,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
// Accounting.
|
// Accounting.
|
||||||
{
|
{
|
||||||
@@ -27,6 +32,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.MANUAL_JOURNAL,
|
defaultSearchResource: RESOURCES_TYPES.MANUAL_JOURNAL,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/manual-journals/:id/edit`,
|
path: `/manual-journals/:id/edit`,
|
||||||
@@ -38,6 +44,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.MANUAL_JOURNAL,
|
defaultSearchResource: RESOURCES_TYPES.MANUAL_JOURNAL,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/manual-journals`,
|
path: `/manual-journals`,
|
||||||
@@ -48,6 +55,7 @@ export const getDashboardRoutes = () => [
|
|||||||
hotkey: 'shift+m',
|
hotkey: 'shift+m',
|
||||||
pageTitle: intl.get('manual_journals'),
|
pageTitle: intl.get('manual_journals'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.MANUAL_JOURNAL,
|
defaultSearchResource: RESOURCES_TYPES.MANUAL_JOURNAL,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/items/categories`,
|
path: `/items/categories`,
|
||||||
@@ -57,6 +65,7 @@ export const getDashboardRoutes = () => [
|
|||||||
breadcrumb: intl.get('categories'),
|
breadcrumb: intl.get('categories'),
|
||||||
pageTitle: intl.get('category_list'),
|
pageTitle: intl.get('category_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
// Items.
|
// Items.
|
||||||
{
|
{
|
||||||
@@ -67,6 +76,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('edit_item'),
|
pageTitle: intl.get('edit_item'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/items/new?duplicate=/:id`,
|
path: `/items/new?duplicate=/:id`,
|
||||||
@@ -75,6 +85,7 @@ export const getDashboardRoutes = () => [
|
|||||||
}),
|
}),
|
||||||
breadcrumb: intl.get('duplicate_item'),
|
breadcrumb: intl.get('duplicate_item'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/items/new`,
|
path: `/items/new`,
|
||||||
@@ -85,6 +96,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('new_item'),
|
pageTitle: intl.get('new_item'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/items`,
|
path: `/items`,
|
||||||
@@ -93,6 +105,7 @@ export const getDashboardRoutes = () => [
|
|||||||
hotkey: 'shift+w',
|
hotkey: 'shift+w',
|
||||||
pageTitle: intl.get('items_list'),
|
pageTitle: intl.get('items_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Inventory adjustments.
|
// Inventory adjustments.
|
||||||
@@ -104,6 +117,7 @@ export const getDashboardRoutes = () => [
|
|||||||
breadcrumb: intl.get('inventory_adjustments'),
|
breadcrumb: intl.get('inventory_adjustments'),
|
||||||
pageTitle: intl.get('inventory_adjustment_list'),
|
pageTitle: intl.get('inventory_adjustment_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
defaultSearchResource: RESOURCES_TYPES.ITEM,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Financial Reports.
|
// Financial Reports.
|
||||||
@@ -119,6 +133,7 @@ export const getDashboardRoutes = () => [
|
|||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
defaultSearchResource: RESOURCES_TYPES.INVENTORY_ADJUSTMENT,
|
defaultSearchResource: RESOURCES_TYPES.INVENTORY_ADJUSTMENT,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/balance-sheet`,
|
path: `/financial-reports/balance-sheet`,
|
||||||
@@ -131,6 +146,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('balance_sheet'),
|
pageTitle: intl.get('balance_sheet'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/trial-balance-sheet`,
|
path: `/financial-reports/trial-balance-sheet`,
|
||||||
@@ -145,6 +161,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('trial_balance_sheet'),
|
pageTitle: intl.get('trial_balance_sheet'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/profit-loss-sheet`,
|
path: `/financial-reports/profit-loss-sheet`,
|
||||||
@@ -157,6 +174,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('profit_loss_sheet'),
|
pageTitle: intl.get('profit_loss_sheet'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/financial-reports/receivable-aging-summary',
|
path: '/financial-reports/receivable-aging-summary',
|
||||||
@@ -168,6 +186,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('receivable_aging_summary'),
|
pageTitle: intl.get('receivable_aging_summary'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/financial-reports/payable-aging-summary',
|
path: '/financial-reports/payable-aging-summary',
|
||||||
@@ -179,6 +198,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('payable_aging_summary'),
|
pageTitle: intl.get('payable_aging_summary'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/journal-sheet`,
|
path: `/financial-reports/journal-sheet`,
|
||||||
@@ -191,6 +211,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('journal_sheet'),
|
pageTitle: intl.get('journal_sheet'),
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/purchases-by-items`,
|
path: `/financial-reports/purchases-by-items`,
|
||||||
@@ -204,6 +225,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('purchases_by_items'),
|
pageTitle: intl.get('purchases_by_items'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/sales-by-items`,
|
path: `/financial-reports/sales-by-items`,
|
||||||
@@ -217,6 +239,7 @@ export const getDashboardRoutes = () => [
|
|||||||
),
|
),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/inventory-valuation`,
|
path: `/financial-reports/inventory-valuation`,
|
||||||
@@ -230,6 +253,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('inventory_valuation'),
|
pageTitle: intl.get('inventory_valuation'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/customers-balance-summary`,
|
path: `/financial-reports/customers-balance-summary`,
|
||||||
@@ -243,6 +267,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('customers_balance_summary'),
|
pageTitle: intl.get('customers_balance_summary'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/vendors-balance-summary`,
|
path: `/financial-reports/vendors-balance-summary`,
|
||||||
@@ -256,6 +281,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('vendors_balance_summary'),
|
pageTitle: intl.get('vendors_balance_summary'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/transactions-by-customers`,
|
path: `/financial-reports/transactions-by-customers`,
|
||||||
@@ -269,6 +295,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('customers_transactions'),
|
pageTitle: intl.get('customers_transactions'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/transactions-by-vendors`,
|
path: `/financial-reports/transactions-by-vendors`,
|
||||||
@@ -282,6 +309,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('vendors_transactions'),
|
pageTitle: intl.get('vendors_transactions'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/cash-flow`,
|
path: `/financial-reports/cash-flow`,
|
||||||
@@ -295,6 +323,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('cash_flow_statement'),
|
pageTitle: intl.get('cash_flow_statement'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/financial-reports/inventory-item-details`,
|
path: `/financial-reports/inventory-item-details`,
|
||||||
@@ -308,6 +337,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('inventory_item_details'),
|
pageTitle: intl.get('inventory_item_details'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/financial-reports',
|
path: '/financial-reports',
|
||||||
@@ -316,6 +346,7 @@ export const getDashboardRoutes = () => [
|
|||||||
),
|
),
|
||||||
breadcrumb: intl.get('financial_reports'),
|
breadcrumb: intl.get('financial_reports'),
|
||||||
pageTitle: intl.get('all_financial_reports'),
|
pageTitle: intl.get('all_financial_reports'),
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
// Exchange Rates
|
// Exchange Rates
|
||||||
{
|
{
|
||||||
@@ -323,6 +354,7 @@ export const getDashboardRoutes = () => [
|
|||||||
component: lazy(() => import('containers/ExchangeRates/ExchangeRatesList')),
|
component: lazy(() => import('containers/ExchangeRates/ExchangeRatesList')),
|
||||||
breadcrumb: intl.get('exchange_rates_list'),
|
breadcrumb: intl.get('exchange_rates_list'),
|
||||||
pageTitle: intl.get('exchange_rates_list'),
|
pageTitle: intl.get('exchange_rates_list'),
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
// Expenses.
|
// Expenses.
|
||||||
{
|
{
|
||||||
@@ -336,6 +368,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.EXPENSE,
|
defaultSearchResource: RESOURCES_TYPES.EXPENSE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/expenses/:id/edit`,
|
path: `/expenses/:id/edit`,
|
||||||
@@ -347,6 +380,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.EXPENSE,
|
defaultSearchResource: RESOURCES_TYPES.EXPENSE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/expenses`,
|
path: `/expenses`,
|
||||||
@@ -357,6 +391,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('expenses_list'),
|
pageTitle: intl.get('expenses_list'),
|
||||||
hotkey: 'shift+x',
|
hotkey: 'shift+x',
|
||||||
defaultSearchResource: RESOURCES_TYPES.EXPENSE,
|
defaultSearchResource: RESOURCES_TYPES.EXPENSE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Customers
|
// Customers
|
||||||
@@ -370,6 +405,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('edit_customer'),
|
pageTitle: intl.get('edit_customer'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.CUSTOMER,
|
defaultSearchResource: RESOURCES_TYPES.CUSTOMER,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/customers/new`,
|
path: `/customers/new`,
|
||||||
@@ -382,6 +418,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('new_customer'),
|
pageTitle: intl.get('new_customer'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.CUSTOMER,
|
defaultSearchResource: RESOURCES_TYPES.CUSTOMER,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/customers`,
|
path: `/customers`,
|
||||||
@@ -392,6 +429,7 @@ export const getDashboardRoutes = () => [
|
|||||||
hotkey: 'shift+c',
|
hotkey: 'shift+c',
|
||||||
pageTitle: intl.get('customers_list'),
|
pageTitle: intl.get('customers_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.CUSTOMER,
|
defaultSearchResource: RESOURCES_TYPES.CUSTOMER,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/customers/contact_duplicate=/:id`,
|
path: `/customers/contact_duplicate=/:id`,
|
||||||
@@ -403,6 +441,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('new_customer'),
|
pageTitle: intl.get('new_customer'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.CUSTOMER,
|
defaultSearchResource: RESOURCES_TYPES.CUSTOMER,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Vendors
|
// Vendors
|
||||||
@@ -416,6 +455,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('edit_vendor'),
|
pageTitle: intl.get('edit_vendor'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.VENDOR,
|
defaultSearchResource: RESOURCES_TYPES.VENDOR,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/vendors/new`,
|
path: `/vendors/new`,
|
||||||
@@ -428,6 +468,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('new_vendor'),
|
pageTitle: intl.get('new_vendor'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.VENDOR,
|
defaultSearchResource: RESOURCES_TYPES.VENDOR,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/vendors`,
|
path: `/vendors`,
|
||||||
@@ -438,6 +479,7 @@ export const getDashboardRoutes = () => [
|
|||||||
hotkey: 'shift+v',
|
hotkey: 'shift+v',
|
||||||
pageTitle: intl.get('vendors_list'),
|
pageTitle: intl.get('vendors_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.VENDOR,
|
defaultSearchResource: RESOURCES_TYPES.VENDOR,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/vendors/contact_duplicate=/:id`,
|
path: `/vendors/contact_duplicate=/:id`,
|
||||||
@@ -449,6 +491,7 @@ export const getDashboardRoutes = () => [
|
|||||||
pageTitle: intl.get('new_vendor'),
|
pageTitle: intl.get('new_vendor'),
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.VENDOR,
|
defaultSearchResource: RESOURCES_TYPES.VENDOR,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Estimates
|
// Estimates
|
||||||
@@ -463,6 +506,7 @@ export const getDashboardRoutes = () => [
|
|||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
defaultSearchResource: RESOURCES_TYPES.ESTIMATE,
|
defaultSearchResource: RESOURCES_TYPES.ESTIMATE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/invoices/new?from_estimate_id=/:id`,
|
path: `/invoices/new?from_estimate_id=/:id`,
|
||||||
@@ -475,6 +519,7 @@ export const getDashboardRoutes = () => [
|
|||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
defaultSearchResource: RESOURCES_TYPES.INVOICE,
|
defaultSearchResource: RESOURCES_TYPES.INVOICE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/estimates/new`,
|
path: `/estimates/new`,
|
||||||
@@ -488,6 +533,7 @@ export const getDashboardRoutes = () => [
|
|||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
defaultSearchResource: RESOURCES_TYPES.ESTIMATE,
|
defaultSearchResource: RESOURCES_TYPES.ESTIMATE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/estimates`,
|
path: `/estimates`,
|
||||||
@@ -499,6 +545,7 @@ export const getDashboardRoutes = () => [
|
|||||||
hotkey: 'shift+e',
|
hotkey: 'shift+e',
|
||||||
pageTitle: intl.get('estimates_list'),
|
pageTitle: intl.get('estimates_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.ESTIMATE,
|
defaultSearchResource: RESOURCES_TYPES.ESTIMATE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Invoices.
|
// Invoices.
|
||||||
@@ -513,6 +560,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.INVOICE,
|
defaultSearchResource: RESOURCES_TYPES.INVOICE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/invoices/new`,
|
path: `/invoices/new`,
|
||||||
@@ -526,6 +574,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.INVOICE,
|
defaultSearchResource: RESOURCES_TYPES.INVOICE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/invoices`,
|
path: `/invoices`,
|
||||||
@@ -536,6 +585,7 @@ export const getDashboardRoutes = () => [
|
|||||||
hotkey: 'shift+i',
|
hotkey: 'shift+i',
|
||||||
pageTitle: intl.get('invoices_list'),
|
pageTitle: intl.get('invoices_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.INVOICE,
|
defaultSearchResource: RESOURCES_TYPES.INVOICE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Sales Receipts.
|
// Sales Receipts.
|
||||||
@@ -550,6 +600,7 @@ export const getDashboardRoutes = () => [
|
|||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
defaultSearchResource: RESOURCES_TYPES.RECEIPT,
|
defaultSearchResource: RESOURCES_TYPES.RECEIPT,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/receipts/new`,
|
path: `/receipts/new`,
|
||||||
@@ -563,6 +614,7 @@ export const getDashboardRoutes = () => [
|
|||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
defaultSearchResource: RESOURCES_TYPES.RECEIPT,
|
defaultSearchResource: RESOURCES_TYPES.RECEIPT,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/receipts`,
|
path: `/receipts`,
|
||||||
@@ -573,6 +625,7 @@ export const getDashboardRoutes = () => [
|
|||||||
hotkey: 'shift+r',
|
hotkey: 'shift+r',
|
||||||
pageTitle: intl.get('receipts_list'),
|
pageTitle: intl.get('receipts_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.RECEIPT,
|
defaultSearchResource: RESOURCES_TYPES.RECEIPT,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Payment receives
|
// Payment receives
|
||||||
@@ -589,6 +642,7 @@ export const getDashboardRoutes = () => [
|
|||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
defaultSearchResource: RESOURCES_TYPES.PAYMENT_RECEIVE,
|
defaultSearchResource: RESOURCES_TYPES.PAYMENT_RECEIVE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/payment-receives/new`,
|
path: `/payment-receives/new`,
|
||||||
@@ -603,6 +657,7 @@ export const getDashboardRoutes = () => [
|
|||||||
backLink: true,
|
backLink: true,
|
||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
defaultSearchResource: RESOURCES_TYPES.PAYMENT_RECEIVE,
|
defaultSearchResource: RESOURCES_TYPES.PAYMENT_RECEIVE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/payment-receives`,
|
path: `/payment-receives`,
|
||||||
@@ -614,6 +669,7 @@ export const getDashboardRoutes = () => [
|
|||||||
breadcrumb: intl.get('payment_receives_list'),
|
breadcrumb: intl.get('payment_receives_list'),
|
||||||
pageTitle: intl.get('payment_receives_list'),
|
pageTitle: intl.get('payment_receives_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.PAYMENT_RECEIVE,
|
defaultSearchResource: RESOURCES_TYPES.PAYMENT_RECEIVE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Bills
|
// Bills
|
||||||
@@ -628,6 +684,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.BILL,
|
defaultSearchResource: RESOURCES_TYPES.BILL,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/bills/new`,
|
path: `/bills/new`,
|
||||||
@@ -641,6 +698,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.BILL,
|
defaultSearchResource: RESOURCES_TYPES.BILL,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/bills`,
|
path: `/bills`,
|
||||||
@@ -651,6 +709,7 @@ export const getDashboardRoutes = () => [
|
|||||||
hotkey: 'shift+b',
|
hotkey: 'shift+b',
|
||||||
pageTitle: intl.get('bills_list'),
|
pageTitle: intl.get('bills_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.BILL,
|
defaultSearchResource: RESOURCES_TYPES.BILL,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Subscription billing.
|
// Subscription billing.
|
||||||
@@ -658,6 +717,7 @@ export const getDashboardRoutes = () => [
|
|||||||
path: `/billing`,
|
path: `/billing`,
|
||||||
component: lazy(() => import('containers/Subscriptions/BillingForm')),
|
component: lazy(() => import('containers/Subscriptions/BillingForm')),
|
||||||
breadcrumb: intl.get('new_billing'),
|
breadcrumb: intl.get('new_billing'),
|
||||||
|
subscriptionInactive: [SUBSCRIPTION_TYPE.MAIN]
|
||||||
},
|
},
|
||||||
// Payment modes.
|
// Payment modes.
|
||||||
{
|
{
|
||||||
@@ -673,6 +733,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.PAYMENT_MADE,
|
defaultSearchResource: RESOURCES_TYPES.PAYMENT_MADE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/payment-mades/new`,
|
path: `/payment-mades/new`,
|
||||||
@@ -687,6 +748,7 @@ export const getDashboardRoutes = () => [
|
|||||||
sidebarExpand: false,
|
sidebarExpand: false,
|
||||||
backLink: true,
|
backLink: true,
|
||||||
defaultSearchResource: RESOURCES_TYPES.PAYMENT_MADE,
|
defaultSearchResource: RESOURCES_TYPES.PAYMENT_MADE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/payment-mades`,
|
path: `/payment-mades`,
|
||||||
@@ -698,11 +760,13 @@ export const getDashboardRoutes = () => [
|
|||||||
breadcrumb: intl.get('payment_made_list'),
|
breadcrumb: intl.get('payment_made_list'),
|
||||||
pageTitle: intl.get('payment_made_list'),
|
pageTitle: intl.get('payment_made_list'),
|
||||||
defaultSearchResource: RESOURCES_TYPES.PAYMENT_MADE,
|
defaultSearchResource: RESOURCES_TYPES.PAYMENT_MADE,
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
// Homepage
|
// Homepage
|
||||||
{
|
{
|
||||||
path: `/`,
|
path: `/`,
|
||||||
component: lazy(() => import('containers/Homepage/Homepage')),
|
component: lazy(() => import('containers/Homepage/Homepage')),
|
||||||
breadcrumb: intl.get('homepage'),
|
breadcrumb: intl.get('homepage'),
|
||||||
|
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,69 +1,95 @@
|
|||||||
import React from 'react';
|
|
||||||
import { createReducer } from '@reduxjs/toolkit';
|
import { createReducer } from '@reduxjs/toolkit';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import t from 'store/types';
|
import t from 'store/types';
|
||||||
|
|
||||||
const getSubscriptionPlans = () => [
|
|
||||||
{
|
|
||||||
name: intl.get('Starter'),
|
|
||||||
slug: 'free',
|
|
||||||
// slug: 'starter',
|
|
||||||
description: [
|
|
||||||
intl.get('Sale and purchase invoices.'),
|
|
||||||
intl.get('Customers/vendors accounts.'),
|
|
||||||
intl.get('Expenses tracking'),
|
|
||||||
intl.get('Manual journals.'),
|
|
||||||
intl.get('Financial reports.'),
|
|
||||||
intl.get('For one user and accountant.'),
|
|
||||||
],
|
|
||||||
price: {
|
|
||||||
month: '100',
|
|
||||||
year: '1,200',
|
|
||||||
},
|
|
||||||
currencyCode: 'LYD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: intl.get('Essential'),
|
|
||||||
slug: 'plus',
|
|
||||||
description: [
|
|
||||||
intl.get('All Capital Starter features.'),
|
|
||||||
intl.get('Multi-currency.'),
|
|
||||||
intl.get('Purchase and sell orders.'),
|
|
||||||
intl.get('Inventory management.'),
|
|
||||||
intl.get('Three users with your accountant.'),
|
|
||||||
intl.get('Advanced financial reports.'),
|
|
||||||
],
|
|
||||||
price: {
|
|
||||||
month: '200',
|
|
||||||
year: '2,400',
|
|
||||||
},
|
|
||||||
currencyCode: 'LYD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: intl.get('Enterprise'),
|
|
||||||
slug: 'enterprise',
|
|
||||||
description: [
|
|
||||||
intl.get('All Capital Essential features.'),
|
|
||||||
intl.get('Track multi-branches and locations.'),
|
|
||||||
intl.get('Projects accounting and timesheets.'),
|
|
||||||
intl.get('Accounting dimensions.'),
|
|
||||||
],
|
|
||||||
price: {
|
|
||||||
month: '300',
|
|
||||||
year: '3,400',
|
|
||||||
},
|
|
||||||
currencyCode: 'LYD',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const getSubscriptionPeriods = () => [
|
const getSubscriptionPeriods = () => [
|
||||||
{
|
{
|
||||||
slug: 'month',
|
slug: 'month',
|
||||||
label: intl.get('Monthly'),
|
label: intl.get('plan.monthly'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
slug: 'year',
|
slug: 'year',
|
||||||
label: intl.get('Yearly'),
|
label: intl.get('plan.yearly'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const getSubscriptionPlans = () => [
|
||||||
|
{
|
||||||
|
name: intl.get('plan.essential.title'),
|
||||||
|
slug: 'free',
|
||||||
|
description: [
|
||||||
|
intl.get('plan.feature.sale_purchase_invoice'),
|
||||||
|
intl.get('plan.feature.receivable_payable_accounts'),
|
||||||
|
intl.get('plan.feature.expenses_tracking'),
|
||||||
|
intl.get('plan.feature.manual_journal'),
|
||||||
|
intl.get('plan.feature.financial_reports'),
|
||||||
|
intl.get('plan.feature.one_user_with_accountant'),
|
||||||
|
],
|
||||||
|
price: '100',
|
||||||
|
periods: [
|
||||||
|
{
|
||||||
|
slug: 'month',
|
||||||
|
label: intl.get('plan.monthly'),
|
||||||
|
price: '100'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: 'year',
|
||||||
|
label: intl.get('plan.yearly'),
|
||||||
|
price: '1,200',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
currencyCode: 'LYD',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: intl.get('plan.professional.title'),
|
||||||
|
slug: 'plus',
|
||||||
|
description: [
|
||||||
|
intl.get('plan.feature.all_capital_essential'),
|
||||||
|
intl.get('plan.feature.multi_currency'),
|
||||||
|
intl.get('plan.feature.purchase_sell_orders'),
|
||||||
|
intl.get('plan.feature.multi_inventory_managment'),
|
||||||
|
intl.get('plan.feature.three_users'),
|
||||||
|
intl.get('plan.feature.advanced_financial_reports'),
|
||||||
|
],
|
||||||
|
price: '200',
|
||||||
|
currencyCode: 'LYD',
|
||||||
|
periods: [
|
||||||
|
{
|
||||||
|
slug: 'month',
|
||||||
|
label: intl.get('plan.monthly'),
|
||||||
|
price: '200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: 'year',
|
||||||
|
label: intl.get('plan.yearly'),
|
||||||
|
price: '1,200',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: intl.get('plan.plus.title'),
|
||||||
|
slug: 'enterprise',
|
||||||
|
description: [
|
||||||
|
intl.get('plan.feture.all_capital_professional_features'),
|
||||||
|
intl.get('plan.feature.tracking_multi_locations'),
|
||||||
|
intl.get('plan.feature.projects_accounting'),
|
||||||
|
intl.get('plan.feature.accounting_dimensions'),
|
||||||
|
],
|
||||||
|
price: '300',
|
||||||
|
currencyCode: 'LYD',
|
||||||
|
periods: [
|
||||||
|
{
|
||||||
|
slug: 'month',
|
||||||
|
label: intl.get('plan.monthly'),
|
||||||
|
price: '300'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: 'year',
|
||||||
|
label: intl.get('plan.yearly'),
|
||||||
|
price: '1,200',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ const plansSelector = (state) => state.plans.plans;
|
|||||||
const planSelector = (state, props) => state.plans.plans
|
const planSelector = (state, props) => state.plans.plans
|
||||||
.find((plan) => plan.slug === props.planSlug);
|
.find((plan) => plan.slug === props.planSlug);
|
||||||
|
|
||||||
const plansPeriodsSelector = (state) => state.plans.periods;
|
|
||||||
|
|
||||||
// Retrieve manual jounral current page results.
|
// Retrieve manual jounral current page results.
|
||||||
export const getPlansSelector = () => createSelector(
|
export const getPlansSelector = () => createSelector(
|
||||||
plansSelector,
|
plansSelector,
|
||||||
@@ -14,14 +12,6 @@ export const getPlansSelector = () => createSelector(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Retrieve manual jounral current page results.
|
|
||||||
export const getPlansPeriodsSelector = () => createSelector(
|
|
||||||
plansPeriodsSelector,
|
|
||||||
(periods) => {
|
|
||||||
return periods;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Retrieve plan details.
|
// Retrieve plan details.
|
||||||
export const getPlanSelector = () => createSelector(
|
export const getPlanSelector = () => createSelector(
|
||||||
planSelector,
|
planSelector,
|
||||||
|
|||||||
@@ -1,23 +1,45 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { includes } from 'lodash';
|
||||||
|
|
||||||
const subscriptionSelector = (slug) => (state, props) => {
|
const subscriptionSelector = (slug) => (state, props) => {
|
||||||
const subscriptions = Object.values(state.subscriptions.data);
|
const subscriptions = Object.values(state.subscriptions.data);
|
||||||
return subscriptions.find((subscription) => subscription.slug === slug);
|
return subscriptions.find(
|
||||||
|
(subscription) => subscription.slug === (slug || props.subscriptionType),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isSubscriptionOnTrialFactory = (slug) => createSelector(
|
const subscriptionsSelector = (state, props) => {
|
||||||
subscriptionSelector(slug),
|
const subscriptions = Object.values(state.subscriptions.data);
|
||||||
(subscription) => !!subscription?.on_trial,
|
return subscriptions.filter(
|
||||||
);
|
(subscription) =>
|
||||||
|
includes(props.subscriptionTypes, subscription.slug) ||
|
||||||
|
!props.subscriptionTypes,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const isSubscriptionActiveFactory = (slug) => createSelector(
|
export const isSubscriptionOnTrialFactory = (slug) =>
|
||||||
subscriptionSelector(slug),
|
createSelector(
|
||||||
(subscription) => {
|
subscriptionSelector(slug),
|
||||||
|
(subscription) => !!subscription?.on_trial,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const isSubscriptionActiveFactory = (slug) =>
|
||||||
|
createSelector(subscriptionSelector(slug), (subscription) => {
|
||||||
return !!subscription?.active;
|
return !!subscription?.active;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
export const isSubscriptionInactiveFactory = (slug) => createSelector(
|
export const isSubscriptionInactiveFactory = (slug) =>
|
||||||
subscriptionSelector(slug),
|
createSelector(
|
||||||
(subscription) => !!subscription?.inactive,
|
subscriptionSelector(slug),
|
||||||
);
|
(subscription) => !!subscription?.inactive,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const isSubscriptionsInactiveFactory = () =>
|
||||||
|
createSelector(subscriptionsSelector, (subscriptions) =>
|
||||||
|
subscriptions.some((subscription) => subscription?.inactive),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const isSubscriptionsActiveFactory = () =>
|
||||||
|
createSelector(subscriptionsSelector, (subscriptions) =>
|
||||||
|
subscriptions.some((subscription) => subscription?.active),
|
||||||
|
);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ScrollbarsCustom-Content{
|
.ScrollbarsCustom-Content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
|
||||||
svg{
|
svg {
|
||||||
opacity: $sidebar-logo-opacity;
|
opacity: $sidebar-logo-opacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,12 +69,14 @@
|
|||||||
&:not([class*="bp3-intent-"]):not(.bp3-minimal) {
|
&:not([class*="bp3-intent-"]):not(.bp3-minimal) {
|
||||||
color: rgb(255, 255, 255);
|
color: rgb(255, 255, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:active,
|
&:active,
|
||||||
&.bp3-active {
|
&.bp3-active {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp3-button-text {
|
.bp3-button-text {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -82,13 +84,14 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
fill: rgba(255, 255, 255, 0.3);
|
fill: rgba(255, 255, 255, 0.3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp3-popover-wrapper,
|
.bp3-popover-wrapper,
|
||||||
.bp3-popover-target{
|
.bp3-popover-target {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
@@ -104,20 +107,24 @@
|
|||||||
.sidebar__head-logo {
|
.sidebar__head-logo {
|
||||||
transition: transform 0.05s ease-in-out;
|
transition: transform 0.05s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.is-subscription-inactive:not(.sidebar--mini-sidebar) & {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__scroll-wrapper {
|
&__scroll-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__version{
|
&__version {
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
padding: 0 20px 20px;
|
padding: 0 20px 20px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: rgba(255, 255, 255, 0.6);
|
color: rgba(255, 255, 255, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
&__inner{
|
&__inner {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -170,7 +177,7 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
|
|
||||||
html[lang^="ar"] &{
|
html[lang^="ar"] & {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
letter-spacing: 0;
|
letter-spacing: 0;
|
||||||
}
|
}
|
||||||
@@ -188,6 +195,7 @@
|
|||||||
padding-bottom: 6px;
|
padding-bottom: 6px;
|
||||||
padding-top: 6px;
|
padding-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.#{$ns}-menu-item {
|
.#{$ns}-menu-item {
|
||||||
padding: 8px 20px;
|
padding: 8px 20px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
@@ -242,11 +250,11 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
// Hide text of bigcapital logo.
|
|
||||||
&-logo {
|
|
||||||
|
|
||||||
}
|
// Hide text of bigcapital logo.
|
||||||
&-organization{
|
&-logo {}
|
||||||
|
|
||||||
|
&-organization {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.3s ease-in-out;
|
transition: opacity 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
@@ -263,7 +271,7 @@
|
|||||||
transition: min-width 0.15s ease-in-out;
|
transition: min-width 0.15s ease-in-out;
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
|
|
||||||
.ScrollbarsCustom-Scroller{
|
.ScrollbarsCustom-Scroller {
|
||||||
overflow: hidden !important;
|
overflow: hidden !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,14 +282,14 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition-delay: 0s;
|
transition-delay: 0s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar__head-organization,
|
.sidebar__head-organization,
|
||||||
.sidebar__menu,
|
.sidebar__menu,
|
||||||
.sidebar__version {
|
.sidebar__version {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ScrollbarsCustom-Scroller{
|
.ScrollbarsCustom-Scroller {
|
||||||
overflow: scroll !important;
|
overflow: scroll !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,12 +334,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.menu--dashboard-organization{
|
|
||||||
|
.menu--dashboard-organization {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
.org-item {
|
.org-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__logo {
|
&__logo {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
@@ -343,16 +353,16 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__name {
|
&__name {
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__divider{
|
&__divider {
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background: #ebebeb;
|
background: #ebebeb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
.billing-page{
|
.billing-page{
|
||||||
padding: 0 60px;
|
padding: 0 60px;
|
||||||
margin-top: 20px;
|
margin-top: 40px;
|
||||||
max-width: 820px;
|
max-width: 820px;
|
||||||
|
|
||||||
.bp3-tab-list{
|
.bp3-tab-list{
|
||||||
|
|||||||
@@ -95,6 +95,17 @@ $dashboard-views-bar-height: 44px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-subscription-msg{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding-right: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
span{
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__breadcrumbs {
|
&__breadcrumbs {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.setup-congrats {
|
.setup-congrats {
|
||||||
width: 600px;
|
width: 500px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-top: 80px;
|
padding-top: 80px;
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
.paragraph {
|
.paragraph {
|
||||||
font-size: 15px;
|
font-size: 16px;
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,9 @@
|
|||||||
|
|
||||||
form {
|
form {
|
||||||
h3 {
|
h3 {
|
||||||
margin-bottom: 1rem;
|
color: #4e5764;
|
||||||
|
margin-bottom: 1.2rem;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@import "../../Base.scss";
|
||||||
|
|
||||||
.setup-page {
|
.setup-page {
|
||||||
max-width: 1600px;
|
max-width: 1600px;
|
||||||
|
|
||||||
@@ -9,15 +11,21 @@
|
|||||||
&:before {
|
&:before {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
width: 30%;
|
width: 100%;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
min-width: 300px;
|
|
||||||
max-width: 350px;
|
max-width: 350px;
|
||||||
|
min-width: 350px;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1200px) {
|
||||||
|
min-width: 300px;
|
||||||
|
max-width: 350px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h3 {
|
h3 {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -36,11 +44,14 @@
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 30%;
|
width: 100%;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
max-width: 350px;
|
width: 350px;
|
||||||
min-width: 300px;
|
|
||||||
|
@media only screen and (max-width: 1200px) {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -76,7 +87,7 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
|
|
||||||
span > a {
|
span>a {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
@@ -101,7 +112,8 @@
|
|||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
p > span {
|
|
||||||
|
p>span {
|
||||||
unicode-bidi: plaintext;
|
unicode-bidi: plaintext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +122,7 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
opacity: 0.55;
|
opacity: 0.55;
|
||||||
|
|
||||||
> div {
|
>div {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
display: inline;
|
display: inline;
|
||||||
@@ -133,9 +145,11 @@
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 50px 0 0;
|
padding: 50px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
position: relative;
|
position: relative;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
@@ -155,6 +169,7 @@
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: #75859c;
|
background-color: #75859c;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
@@ -165,24 +180,29 @@
|
|||||||
left: -50%;
|
left: -50%;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:first-child::after {
|
&:first-child::after {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-active {
|
&.is-active {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
background-color: #75859c;
|
background-color: #75859c;
|
||||||
}
|
}
|
||||||
~ li {
|
|
||||||
|
~li {
|
||||||
|
|
||||||
&:before,
|
&:before,
|
||||||
&:after {
|
&:after {
|
||||||
background: #e0e0e0;
|
background: #e0e0e0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.wizard-info {
|
p.wizard-info {
|
||||||
color: #004dd0;
|
color: #004dd0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user