mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
fix(Setup): fix organization setup.
This commit is contained in:
@@ -63,7 +63,6 @@
|
||||
"postcss-preset-env": "6.7.0",
|
||||
"postcss-safe-parser": "4.0.1",
|
||||
"react": "^16.12.0",
|
||||
"react-albus": "^2.0.0",
|
||||
"react-app-polyfill": "^1.0.6",
|
||||
"react-body-classname": "^1.3.1",
|
||||
"react-content-loader": "^6.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
export default [
|
||||
{ name: 'English', value: 'EN' },
|
||||
{ name: 'Arabic', value: 'AR' },
|
||||
{ name: 'English', value: 'en' },
|
||||
{ name: 'Arabic', value: 'ar' },
|
||||
];
|
||||
@@ -11,7 +11,7 @@ export default function BigcapitalLoading({ className }) {
|
||||
return (
|
||||
<div className={classNames('bigcapital-loading', className)}>
|
||||
<div class="center">
|
||||
<Icon icon="bigcapital" height={37} width={214} />
|
||||
<Icon icon="bigcapital" height={37} width={228} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,18 +4,17 @@ import { Formik } from 'formik';
|
||||
import { useIntl } from 'react-intl';
|
||||
import * as Yup from 'yup';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import Toaster from 'components/AppToaster';
|
||||
|
||||
import 'style/pages/Setup/PaymentViaVoucherDialog.scss';
|
||||
|
||||
|
||||
import { usePaymentByVoucher } from 'hooks/query';
|
||||
import { DialogContent } from 'components';
|
||||
import PaymentViaLicenseForm from './PaymentViaVoucherForm';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withBillingActions from 'containers/Subscriptions/withBillingActions';
|
||||
import withSubscriptionsActions from 'containers/Subscriptions/withSubscriptionsActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
|
||||
/**
|
||||
* Payment via license dialog content.
|
||||
@@ -26,30 +25,43 @@ function PaymentViaLicenseDialogContent({
|
||||
|
||||
// #withDialog
|
||||
closeDialog,
|
||||
|
||||
// #withBillingActions
|
||||
requestSubmitBilling,
|
||||
|
||||
// #withSubscriptionsActions
|
||||
requestFetchSubscriptions,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const history = useHistory();
|
||||
|
||||
// Payment via voucher
|
||||
const {
|
||||
mutateAsync: paymentViaVoucherMutate,
|
||||
} = usePaymentByVoucher();
|
||||
|
||||
// Handle submit.
|
||||
const handleSubmit = (values, { setSubmitting }) => {
|
||||
const handleSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
setSubmitting(true);
|
||||
|
||||
requestSubmitBilling({ ...values, ...subscriptionForm })
|
||||
.then(() => {
|
||||
return requestFetchSubscriptions();
|
||||
})
|
||||
paymentViaVoucherMutate({ ...values })
|
||||
.then(() => {
|
||||
Toaster.show({
|
||||
message: 'Payment has been done successfully.',
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
return closeDialog('payment-via-voucher');
|
||||
})
|
||||
.then(() => {
|
||||
history.push('initializing');
|
||||
})
|
||||
.catch(
|
||||
({
|
||||
response: {
|
||||
data: { errors },
|
||||
},
|
||||
}) => {
|
||||
if (errors.find((e) => e.type === 'LICENSE.CODE.IS.INVALID')) {
|
||||
setErrors({
|
||||
license_code: 'The license code is not valid, please try agin.',
|
||||
});
|
||||
}
|
||||
},
|
||||
)
|
||||
.finally((errors) => {
|
||||
setSubmitting(false);
|
||||
});
|
||||
@@ -57,17 +69,18 @@ function PaymentViaLicenseDialogContent({
|
||||
|
||||
// Initial values.
|
||||
const initialValues = {
|
||||
license_number: '',
|
||||
license_code: '',
|
||||
plan_slug: '',
|
||||
period: '',
|
||||
...subscriptionForm,
|
||||
};
|
||||
// Validation schema.
|
||||
const validationSchema = Yup.object().shape({
|
||||
license_number: Yup.string()
|
||||
license_code: Yup.string()
|
||||
.required()
|
||||
.min(10)
|
||||
.max(10)
|
||||
.label(formatMessage({ id: 'license_number' })),
|
||||
.label(formatMessage({ id: 'license_code' })),
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -82,8 +95,4 @@ function PaymentViaLicenseDialogContent({
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogActions,
|
||||
withBillingActions,
|
||||
withSubscriptionsActions,
|
||||
)(PaymentViaLicenseDialogContent);
|
||||
export default compose(withDialogActions)(PaymentViaLicenseDialogContent);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Button, FormGroup, InputGroup, Intent } from '@blueprintjs/core';
|
||||
import { Form, FastField, ErrorMessage } from 'formik';
|
||||
import { Form, FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { compose } from 'redux';
|
||||
|
||||
@@ -15,12 +15,12 @@ import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
* Payment via license form.
|
||||
*/
|
||||
function PaymentViaLicenseForm({
|
||||
// #ownProps
|
||||
isSubmitting,
|
||||
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
}) {
|
||||
// Formik context.
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
const licenseNumberRef = useAutofocus();
|
||||
|
||||
// Handle close button click.
|
||||
@@ -33,15 +33,17 @@ function PaymentViaLicenseForm({
|
||||
<div className={CLASSES.DIALOG_BODY}>
|
||||
<p>Please enter your preferred payment method below.</p>
|
||||
|
||||
<FastField name="license_number">
|
||||
<FastField name="license_code">
|
||||
{({ field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'voucher_number'} />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="voucher_number" />}
|
||||
helperText={<ErrorMessage name="license_code" />}
|
||||
className={'form-group--voucher_number'}
|
||||
>
|
||||
<InputGroup
|
||||
large={true}
|
||||
intent={inputIntent({ error, touched })}
|
||||
{...field}
|
||||
inputRef={(ref) => (licenseNumberRef.current = ref)}
|
||||
/>
|
||||
|
||||
@@ -7,16 +7,14 @@ import withDialogRedux from 'components/DialogReduxConnect';
|
||||
import { compose } from 'utils';
|
||||
|
||||
// Lazy loading the content.
|
||||
const PaymentViaLicenseDialogContent = lazy(() => import('./PaymentViaVoucherDialogContent'));
|
||||
const PaymentViaLicenseDialogContent = lazy(() =>
|
||||
import('./PaymentViaVoucherDialogContent'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Payment via license dialog.
|
||||
*/
|
||||
function PaymentViaLicenseDialog({
|
||||
dialogName,
|
||||
payload,
|
||||
isOpen
|
||||
}) {
|
||||
function PaymentViaLicenseDialog({ dialogName, payload, isOpen }) {
|
||||
return (
|
||||
<Dialog
|
||||
name={dialogName}
|
||||
@@ -33,9 +31,7 @@ function PaymentViaLicenseDialog({
|
||||
/>
|
||||
</DialogSuspense>
|
||||
</Dialog>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withDialogRedux(),
|
||||
)(PaymentViaLicenseDialog);
|
||||
export default compose(withDialogRedux())(PaymentViaLicenseDialog);
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
fetchOrganizations,
|
||||
buildTenant,
|
||||
seedTenant,
|
||||
setOrganizationSetupCompleted,
|
||||
} from 'store/organizations/organizations.actions';
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
requestOrganizationBuild: () => dispatch(buildTenant()),
|
||||
requestOrganizationSeed: () => dispatch(seedTenant()),
|
||||
requestAllOrganizations: () => dispatch(fetchOrganizations()),
|
||||
|
||||
setOrganizationSetupCompleted: (congrats) => dispatch(setOrganizationSetupCompleted(congrats)),
|
||||
setOrganizationSetupCompleted: (congrats) =>
|
||||
dispatch(setOrganizationSetupCompleted(congrats)),
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps);
|
||||
export default connect(null, mapDispatchToProps);
|
||||
|
||||
@@ -1,53 +1,49 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { withWizard } from 'react-albus'
|
||||
import { ProgressBar, Intent } from '@blueprintjs/core';
|
||||
import { useBuildTenant } from 'hooks/query';
|
||||
|
||||
import 'style/pages/Setup/Initializing.scss';
|
||||
|
||||
import withOrganizationActions from 'containers/Organization/withOrganizationActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Setup initializing step form.
|
||||
*/
|
||||
function SetupInitializingForm({
|
||||
|
||||
// #withOrganizationActions
|
||||
requestOrganizationBuild,
|
||||
|
||||
wizard: { next },
|
||||
}) {
|
||||
const { isSuccess } = useQuery(
|
||||
['build-tenant'], () => requestOrganizationBuild(),
|
||||
);
|
||||
export default function SetupInitializingForm() {
|
||||
const {
|
||||
mutateAsync: buildTenantMutate,
|
||||
isLoading,
|
||||
isError,
|
||||
} = useBuildTenant();
|
||||
|
||||
useEffect(() => {
|
||||
if (isSuccess) {
|
||||
next();
|
||||
}
|
||||
}, [isSuccess, next]);
|
||||
buildTenantMutate();
|
||||
}, [buildTenantMutate]);
|
||||
|
||||
return (
|
||||
<div class="setup-initializing-form">
|
||||
<ProgressBar intent={Intent.PRIMARY} value={null} />
|
||||
{isLoading && <ProgressBar intent={Intent.PRIMARY} value={null} />}
|
||||
|
||||
<div className={'setup-initializing-form__title'}>
|
||||
<h1>
|
||||
{/* You organization is initializin... */}
|
||||
It's time to make your accounting really simple!
|
||||
</h1>
|
||||
<p className={'paragraph'}>
|
||||
while we set up your account, please remember to verify your account by
|
||||
clicking on the link we sent to yout registered email address
|
||||
</p>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<h1>It's time to make your accounting really simple!</h1>
|
||||
<p className={'paragraph'}>
|
||||
while we set up your account, please remember to verify your
|
||||
account by clicking on the link we sent to yout registered email
|
||||
address
|
||||
</p>
|
||||
</>
|
||||
) : isError ? (
|
||||
<>
|
||||
<h1>Something went wrong!</h1>
|
||||
<p class="paragraph">Please refresh the page</p>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h1>Waiting to redirect</h1>
|
||||
<p class="paragraph">Refresh the page if redirect not worked.</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withOrganizationActions,
|
||||
withWizard,
|
||||
)(SetupInitializingForm);
|
||||
@@ -14,7 +14,7 @@ import classNames from 'classnames';
|
||||
import { TimezonePicker } from '@blueprintjs/timezone';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
|
||||
import { Col, Row, ListSelect } from 'components';
|
||||
import { FieldRequiredHint, Col, Row, ListSelect } from 'components';
|
||||
import {
|
||||
momentFormatter,
|
||||
tansformDateValue,
|
||||
@@ -38,9 +38,10 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
||||
</h3>
|
||||
|
||||
{/* ---------- Organization name ---------- */}
|
||||
<FastField name={'name'}>
|
||||
<FastField name={'organization_name'}>
|
||||
{({ form, field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
label={<T id={'legal_organization_name'} />}
|
||||
className={'form-group--name'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
@@ -55,6 +56,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
||||
<FastField name={'financialDateStart'}>
|
||||
{({ form: { setFieldValue }, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
label={<T id={'financial_starting_date'} />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="financialDateStart" />}
|
||||
@@ -82,6 +84,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
label={<T id={'base_currency'} />}
|
||||
className={classNames(
|
||||
'form-group--base-currency',
|
||||
@@ -137,6 +140,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
||||
selectedItemProp={'value'}
|
||||
defaultText={<T id={'select_language'} />}
|
||||
popoverProps={{ minimal: true }}
|
||||
filterable={false}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
@@ -147,6 +151,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
||||
<FastField name={'fiscalYear'}>
|
||||
{({ form: { setFieldValue }, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
label={<T id={'fiscal_year'} />}
|
||||
className={classNames(
|
||||
'form-group--fiscal_year',
|
||||
@@ -167,6 +172,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
||||
onItemSelect={(item) => {
|
||||
setFieldValue('fiscalYear', item.value)
|
||||
}}
|
||||
filterable={false}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
@@ -180,6 +186,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) {
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
label={<T id={'time_zone'} />}
|
||||
className={classNames(
|
||||
'form-group--time-zone',
|
||||
|
||||
@@ -3,49 +3,33 @@ import * as Yup from 'yup';
|
||||
import { Formik } from 'formik';
|
||||
import moment from 'moment';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import { snakeCase } from 'lodash';
|
||||
|
||||
import { withWizard } from 'react-albus';
|
||||
import { useQuery } from 'react-query';
|
||||
|
||||
import 'style/pages/Setup/Organization.scss';
|
||||
|
||||
import SetupOrganizationForm from './SetupOrganizationForm';
|
||||
|
||||
import { useOrganizationSetup } from 'hooks/query';
|
||||
import withSettingsActions from 'containers/Settings/withSettingsActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import withOrganizationActions from 'containers/Organization/withOrganizationActions';
|
||||
|
||||
import {
|
||||
compose,
|
||||
transformToForm,
|
||||
optionsMapToArray,
|
||||
transfromToSnakeCase,
|
||||
} from 'utils';
|
||||
|
||||
/**
|
||||
* Setup organization form.
|
||||
*/
|
||||
function SetupOrganizationPage({
|
||||
// #withSettingsActions
|
||||
requestSubmitOptions,
|
||||
requestFetchOptions,
|
||||
|
||||
// #withOrganizationActions
|
||||
requestOrganizationSeed,
|
||||
|
||||
// #withSettings
|
||||
organizationSettings,
|
||||
|
||||
wizard,
|
||||
setOrganizationSetupCompleted,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({}));
|
||||
const { mutateAsync: organizationSetupMutate } = useOrganizationSetup();
|
||||
|
||||
// Validation schema.
|
||||
const validationSchema = Yup.object().shape({
|
||||
name: Yup.string()
|
||||
organization_name: Yup.string()
|
||||
.required()
|
||||
.label(formatMessage({ id: 'organization_name_' })),
|
||||
financialDateStart: Yup.date()
|
||||
@@ -67,35 +51,21 @@ function SetupOrganizationPage({
|
||||
|
||||
// Initial values.
|
||||
const defaultValues = {
|
||||
name: '',
|
||||
organization_name: '',
|
||||
financialDateStart: moment(new Date()).format('YYYY-MM-DD'),
|
||||
baseCurrency: '',
|
||||
language: '',
|
||||
language: 'en',
|
||||
fiscalYear: '',
|
||||
timeZone: '',
|
||||
...organizationSettings,
|
||||
};
|
||||
|
||||
const initialValues = {
|
||||
...defaultValues,
|
||||
|
||||
/**
|
||||
* We only care about the fields in the form. Previously unfilled optional
|
||||
* values such as `notes` come back from the API as null, so remove those
|
||||
* as well.
|
||||
*/
|
||||
...transformToForm(organizationSettings, defaultValues),
|
||||
};
|
||||
|
||||
// Handle the form submit.
|
||||
const handleSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
const options = optionsMapToArray(values).map((option) => {
|
||||
return { ...option, key: snakeCase(option.key), group: 'organization' };
|
||||
});
|
||||
requestSubmitOptions({ options })
|
||||
.then(() => {
|
||||
return requestOrganizationSeed();
|
||||
})
|
||||
organizationSetupMutate({ ...transfromToSnakeCase(values) })
|
||||
.then(() => {
|
||||
return setOrganizationSetupCompleted(true);
|
||||
})
|
||||
@@ -132,8 +102,4 @@ function SetupOrganizationPage({
|
||||
export default compose(
|
||||
withSettingsActions,
|
||||
withOrganizationActions,
|
||||
withWizard,
|
||||
withSettings(({ organizationSettings }) => ({
|
||||
organizationSettings,
|
||||
})),
|
||||
)(SetupOrganizationPage);
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Wizard } from 'react-albus';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import withSubscriptions from 'containers/Subscriptions/withSubscriptions';
|
||||
|
||||
import SetupDialogs from './SetupDialogs';
|
||||
import SetupWizardContent from './SetupWizardContent';
|
||||
|
||||
import withSubscriptions from 'containers/Subscriptions/withSubscriptions';
|
||||
import withOrganization from 'containers/Organization/withOrganization';
|
||||
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
|
||||
import withSetupWizard from '../../store/organizations/withSetupWizard';
|
||||
@@ -24,37 +20,17 @@ function SetupRightSection({
|
||||
isOrganizationSetupCompleted,
|
||||
|
||||
// #withSetupWizard
|
||||
isCongratsStep,
|
||||
isSubscriptionStep,
|
||||
isInitializingStep,
|
||||
isOrganizationStep,
|
||||
setupStepId,
|
||||
setupStepIndex,
|
||||
|
||||
// #withSubscriptions
|
||||
isSubscriptionActive,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
|
||||
const handleSkip = ({ step, push }) => {
|
||||
const scenarios = [
|
||||
{ condition: isCongratsStep, redirectTo: 'congrats' },
|
||||
{ condition: isSubscriptionStep, redirectTo: 'subscription' },
|
||||
{ condition: isInitializingStep, redirectTo: 'initializing' },
|
||||
{ condition: isOrganizationStep, redirectTo: 'organization' },
|
||||
];
|
||||
const scenario = scenarios.find((scenario) => scenario.condition);
|
||||
|
||||
if (scenario) {
|
||||
push(scenario.redirectTo);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={'setup-page__right-section'}>
|
||||
<Wizard
|
||||
onNext={handleSkip}
|
||||
basename={'/setup'}
|
||||
history={history}
|
||||
render={SetupWizardContent}
|
||||
<SetupWizardContent
|
||||
setupStepId={setupStepId}
|
||||
setupStepIndex={setupStepIndex}
|
||||
/>
|
||||
<SetupDialogs />
|
||||
</section>
|
||||
@@ -84,17 +60,8 @@ export default compose(
|
||||
}),
|
||||
'main',
|
||||
),
|
||||
withSetupWizard(
|
||||
({
|
||||
isCongratsStep,
|
||||
isSubscriptionStep,
|
||||
isInitializingStep,
|
||||
isOrganizationStep,
|
||||
}) => ({
|
||||
isCongratsStep,
|
||||
isSubscriptionStep,
|
||||
isInitializingStep,
|
||||
isOrganizationStep,
|
||||
}),
|
||||
),
|
||||
withSetupWizard(({ setupStepId, setupStepIndex }) => ({
|
||||
setupStepId,
|
||||
setupStepIndex,
|
||||
})),
|
||||
)(SetupRightSection);
|
||||
|
||||
8
client/src/containers/Setup/SetupSteps.js
Normal file
8
client/src/containers/Setup/SetupSteps.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function SetupSteps({ step, children }) {
|
||||
const activeStep = React.Children.toArray(children).filter(
|
||||
(child) => child.props.id === step.id,
|
||||
);
|
||||
return activeStep;
|
||||
}
|
||||
@@ -1,21 +1,15 @@
|
||||
import React from 'react';
|
||||
import { Formik } from 'formik';
|
||||
import { withWizard } from 'react-albus';
|
||||
|
||||
import 'style/pages/Setup/Subscription.scss';
|
||||
|
||||
import SetupSubscriptionForm from './SetupSubscriptionForm';
|
||||
import { SubscriptionFormSchema } from './SubscriptionForm.schema';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Subscription step of wizard setup.
|
||||
*/
|
||||
function SetupSubscription({
|
||||
// #withWizard
|
||||
wizard,
|
||||
}) {
|
||||
export default function SetupSubscription() {
|
||||
// Initial values.
|
||||
const initialValues = {
|
||||
plan_slug: 'free',
|
||||
@@ -23,6 +17,7 @@ function SetupSubscription({
|
||||
license_code: '',
|
||||
};
|
||||
|
||||
// Handle form submit.
|
||||
const handleSubmit = () => {};
|
||||
|
||||
return (
|
||||
@@ -35,8 +30,4 @@ function SetupSubscription({
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withWizard,
|
||||
)(SetupSubscription);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Steps, Step } from 'react-albus';
|
||||
import { TransitionGroup, CSSTransition } from 'react-transition-group';
|
||||
|
||||
import SetupSteps from './SetupSteps';
|
||||
import WizardSetupSteps from './WizardSetupSteps';
|
||||
|
||||
import SetupSubscription from './SetupSubscription';
|
||||
@@ -12,37 +11,19 @@ import SetupCongratsPage from './SetupCongratsPage';
|
||||
/**
|
||||
* Setup wizard content.
|
||||
*/
|
||||
export default function SetupWizardContent({
|
||||
step,
|
||||
steps
|
||||
}) {
|
||||
export default function SetupWizardContent({ setupStepIndex, setupStepId }) {
|
||||
return (
|
||||
<div class="setup-page__content">
|
||||
<WizardSetupSteps currentStep={steps.indexOf(step) + 1} />
|
||||
<WizardSetupSteps currentStep={setupStepIndex} />
|
||||
|
||||
<TransitionGroup>
|
||||
<CSSTransition key={step.id} timeout={{ enter: 500, exit: 500 }}>
|
||||
<div class="setup-page-form">
|
||||
<Steps key={step.id} step={step}>
|
||||
<Step id="subscription">
|
||||
<SetupSubscription />
|
||||
</Step>
|
||||
|
||||
<Step id={'initializing'}>
|
||||
<SetupInitializingForm />
|
||||
</Step>
|
||||
|
||||
<Step id="organization">
|
||||
<SetupOrganizationPage />
|
||||
</Step>
|
||||
|
||||
<Step id="congrats">
|
||||
<SetupCongratsPage />
|
||||
</Step>
|
||||
</Steps>
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</TransitionGroup>
|
||||
<div class="setup-page-form">
|
||||
<SetupSteps step={{ id: setupStepId }}>
|
||||
<SetupSubscription id="subscription" />
|
||||
<SetupInitializingForm id={'initializing'} />
|
||||
<SetupOrganizationPage id="organization" />
|
||||
<SetupCongratsPage id="congrats" />
|
||||
</SetupSteps>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { FormattedMessage as T } from 'react-intl';
|
||||
import { registerWizardSteps } from 'common/registerWizard'
|
||||
import { registerWizardSteps } from 'common/registerWizard';
|
||||
|
||||
function WizardSetupStep({
|
||||
label,
|
||||
isActive = false
|
||||
}) {
|
||||
function WizardSetupStep({ label, isActive = false }) {
|
||||
return (
|
||||
<li className={classNames({ 'is-active': isActive })}>
|
||||
<p className={'wizard-info'}><T id={label} /></p>
|
||||
<p className={'wizard-info'}>
|
||||
<T id={label} />
|
||||
</p>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
function WizardSetupSteps({
|
||||
currentStep = 1,
|
||||
}) {
|
||||
export default function WizardSetupSteps({ currentStep = 1 }) {
|
||||
return (
|
||||
<div className={'setup-page-steps-container'}>
|
||||
<div className={'setup-page-steps'}>
|
||||
@@ -24,7 +21,7 @@ function WizardSetupSteps({
|
||||
{registerWizardSteps.map((step, index) => (
|
||||
<WizardSetupStep
|
||||
label={step.label}
|
||||
isActive={(index + 1) == currentStep}
|
||||
isActive={index + 1 === currentStep}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
@@ -32,5 +29,3 @@ function WizardSetupSteps({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default WizardSetupSteps;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import { useQueryTenant, useRequestQuery } from '../useQueryRequest';
|
||||
import { useRequestQuery } from '../useQueryRequest';
|
||||
import useApiRequest from '../useRequest';
|
||||
import t from './types';
|
||||
|
||||
@@ -24,9 +24,7 @@ export function useAccounts(query, props) {
|
||||
[t.ACCOUNTS, query],
|
||||
{ method: 'get', url: 'accounts', params: query },
|
||||
{
|
||||
select: (response) => {
|
||||
return response.data.accounts;
|
||||
},
|
||||
select: (res) => res.data.accounts,
|
||||
defaultData: [],
|
||||
...props,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useMutation } from 'react-query';
|
||||
import useApiRequest from '../useRequest';
|
||||
import { useAuthActions } from '../state';
|
||||
@@ -10,20 +9,16 @@ export const useAuthLogin = (props) => {
|
||||
const { setLogin } = useAuthActions();
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
const states = useMutation(
|
||||
return useMutation(
|
||||
(values) => apiRequest.post('auth/login', values),
|
||||
{
|
||||
select: (res) => res.data,
|
||||
onSuccess: (data) => {
|
||||
setLogin(data.data);
|
||||
},
|
||||
...props
|
||||
}
|
||||
);
|
||||
const { isSuccess, data: response } = states;
|
||||
|
||||
useEffect(() => {
|
||||
if (isSuccess) { setLogin(response.data); }
|
||||
}, [isSuccess, response, setLogin]);
|
||||
|
||||
return states;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,3 +21,5 @@ export * from './users';
|
||||
export * from './invite';
|
||||
export * from './exchangeRates';
|
||||
export * from './contacts';
|
||||
export * from './subscriptions';
|
||||
export * from './organization';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useMutation } from 'react-query';
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
import { batch } from 'react-redux';
|
||||
import t from './types';
|
||||
import useApiRequest from '../useRequest';
|
||||
import { useRequestQuery } from '../useQueryRequest';
|
||||
import { useEffect } from 'react';
|
||||
import { useSetOrganizations, useSetSubscriptions } from '../state';
|
||||
import { omit } from 'lodash';
|
||||
|
||||
@@ -33,29 +33,26 @@ export function useCurrentOrganization(props) {
|
||||
const setOrganizations = useSetOrganizations();
|
||||
const setSubscriptions = useSetSubscriptions();
|
||||
|
||||
const query = useRequestQuery(
|
||||
return useRequestQuery(
|
||||
[t.ORGANIZATION_CURRENT],
|
||||
{ method: 'get', url: `organization/current` },
|
||||
{
|
||||
select: (res) => res.data.organization,
|
||||
defaultData: {},
|
||||
onSuccess: (data) => {
|
||||
const organization = omit(data, ['subscriptions']);
|
||||
|
||||
batch(() => {
|
||||
// Sets subscriptions.
|
||||
setSubscriptions(data.subscriptions);
|
||||
|
||||
// Sets organizations.
|
||||
setOrganizations([organization]);
|
||||
});
|
||||
},
|
||||
...props,
|
||||
},
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (query.isSuccess) {
|
||||
const organization = omit(query.data, ['subscriptions']);
|
||||
|
||||
// Sets organizations.
|
||||
setOrganizations([organization]);
|
||||
|
||||
// Sets subscriptions.
|
||||
setSubscriptions(query.data.subscriptions);
|
||||
}
|
||||
}, [query.data, query.isSuccess, setOrganizations, setSubscriptions]);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,30 +60,46 @@ export function useCurrentOrganization(props) {
|
||||
*/
|
||||
export function useBuildTenant(props) {
|
||||
const apiRequest = useApiRequest();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
(values) => apiRequest.post('organization/build'),
|
||||
{
|
||||
onSuccess: (res, values) => {
|
||||
|
||||
},
|
||||
...props,
|
||||
return useMutation((values) => apiRequest.post('organization/build'), {
|
||||
onSuccess: (res, values) => {
|
||||
queryClient.invalidateQueries(t.ORGANIZATION_CURRENT);
|
||||
queryClient.invalidateQueries(t.ORGANIZATIONS);
|
||||
},
|
||||
);
|
||||
};
|
||||
...props,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeds the current tenant
|
||||
*/
|
||||
export function useSeedTenant() {
|
||||
const apiRequest = useApiRequest();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation((values) => apiRequest.post('organization/seed'), {
|
||||
onSuccess: (res) => {
|
||||
queryClient.invalidateQueries(t.ORGANIZATION_CURRENT);
|
||||
queryClient.invalidateQueries(t.ORGANIZATIONS);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Organization setup.
|
||||
*/
|
||||
export function useOrganizationSetup() {
|
||||
const apiRequest = useApiRequest();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
(values) => apiRequest.post('organization/seed'),
|
||||
(values) => apiRequest.post(`setup/organization`, values),
|
||||
{
|
||||
onSuccess: (res) => {
|
||||
|
||||
queryClient.invalidateQueries(t.ORGANIZATION_CURRENT);
|
||||
queryClient.invalidateQueries(t.ORGANIZATIONS);
|
||||
},
|
||||
}
|
||||
)
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
44
client/src/hooks/query/subscriptions.js
Normal file
44
client/src/hooks/query/subscriptions.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import { useEffect } from "react"
|
||||
import { useMutation, useQueryClient } from "react-query";
|
||||
import { useRequestQuery } from "../useQueryRequest";
|
||||
import useApiRequest from "../useRequest";
|
||||
import { useSetSubscriptions } from '../state/subscriptions';
|
||||
import T from './types';
|
||||
|
||||
/**
|
||||
* Subscription payment via voucher.
|
||||
*/
|
||||
export const usePaymentByVoucher = (props) => {
|
||||
const apiRequest = useApiRequest();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
(values) => apiRequest.post('subscription/license/payment', values),
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(T.SUBSCRIPTIONS);
|
||||
queryClient.invalidateQueries(T.ORGANIZATION_CURRENT);
|
||||
queryClient.invalidateQueries(T.ORGANIZATIONS);
|
||||
},
|
||||
...props,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the organization subscriptions.
|
||||
*/
|
||||
export const useOrganizationSubscriptions = (props) => {
|
||||
const setSubscriptions = useSetSubscriptions();
|
||||
|
||||
const state = useRequestQuery(
|
||||
[T.SUBSCRIPTIONS],
|
||||
{ method: 'get', url: 'subscriptions' },
|
||||
{ ...props },
|
||||
);
|
||||
useEffect(() => {
|
||||
if (state.isSuccess) {
|
||||
setSubscriptions(state.data);
|
||||
}
|
||||
}, [state.isSuccess, state.data, setSubscriptions])
|
||||
};
|
||||
@@ -94,6 +94,10 @@ const ORGANIZATIONS = {
|
||||
ORGANIZATION_CURRENT: 'ORGANIZATION_CURRENT',
|
||||
};
|
||||
|
||||
const SUBSCRIPTIONS = {
|
||||
SUBSCRIPTIONS: 'SUBSCRIPTIONS',
|
||||
}
|
||||
|
||||
export default {
|
||||
...ACCOUNTS,
|
||||
...BILLS,
|
||||
@@ -111,4 +115,5 @@ export default {
|
||||
...USERS,
|
||||
...SETTING,
|
||||
...ORGANIZATIONS,
|
||||
...SUBSCRIPTIONS
|
||||
};
|
||||
|
||||
@@ -11,4 +11,4 @@ export const useSetSubscriptions = () => {
|
||||
return useCallback((subscriptions) => {
|
||||
dispatch(setSubscriptions(subscriptions));
|
||||
}, [dispatch]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import { createTableStateReducers } from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -12,15 +13,21 @@ const initialState = {
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:bills';
|
||||
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('BILLS'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
}
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
},
|
||||
CONFIG,
|
||||
reducerInstance,
|
||||
);
|
||||
@@ -1,9 +1,10 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import {
|
||||
createTableStateReducers,
|
||||
} from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -12,17 +13,23 @@ const initialState = {
|
||||
},
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('ESTIMATES'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:estimates';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('ESTIMATES'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
CONFIG,
|
||||
reducerInstance,
|
||||
);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import {
|
||||
createTableStateReducers,
|
||||
} from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -12,17 +13,23 @@ const initialState = {
|
||||
},
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('INVOICES'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:invoices';
|
||||
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('INVOICES'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
}
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
},
|
||||
CONFIG,
|
||||
reducerInstance,
|
||||
);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import {
|
||||
createTableStateReducers,
|
||||
} from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -13,17 +14,20 @@ const initialState = {
|
||||
},
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('PAYMENT_MADES'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:paymentMades';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
}
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('PAYMENT_MADES'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
reducerInstance,
|
||||
);
|
||||
});
|
||||
|
||||
export default persistReducer(CONFIG, reducerInstance);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import {
|
||||
createTableStateReducers,
|
||||
} from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -12,17 +13,23 @@ const initialState = {
|
||||
},
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('PAYMENT_RECEIVES'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:paymentReceives';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('PAYMENT_RECEIVES'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
CONFIG,
|
||||
reducerInstance,
|
||||
);
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
import { createReducer} from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import {
|
||||
createTableStateReducers,
|
||||
} from 'store/tableState.reducer';
|
||||
import { createTableStateReducers } from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {},
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('ACCOUNTS'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:accounts';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
},
|
||||
reducerInstance,
|
||||
);
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('ACCOUNTS'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
}
|
||||
});
|
||||
|
||||
export default persistReducer(CONFIG, reducerInstance);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import purgeStoredState from 'redux-persist/es/purgeStoredState';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import t from 'store/types';
|
||||
|
||||
@@ -14,10 +15,16 @@ const initialState = {
|
||||
};
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:authentication';
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
blacklist: ['errors'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
[t.LOGIN_SUCCESS]: (state, action) => {
|
||||
const { token, user, tenant } = action.payload;
|
||||
|
||||
state.token = token;
|
||||
state.user = user;
|
||||
state.organization = tenant.organization_id;
|
||||
@@ -32,14 +39,14 @@ const reducerInstance = createReducer(initialState, {
|
||||
[t.LOGIN_CLEAR_ERRORS]: (state) => {
|
||||
state.errors = [];
|
||||
},
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
}
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
blacklist: ['errors'],
|
||||
storage,
|
||||
},
|
||||
CONFIG,
|
||||
reducerInstance,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import t from 'store/types';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
|
||||
const initialState = {
|
||||
@@ -20,6 +20,12 @@ const initialState = {
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:dashboard';
|
||||
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['sidebarExpended', 'previousSidebarExpended'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
[t.CHANGE_DASHBOARD_PAGE_TITLE]: (state, action) => {
|
||||
state.pageTitle = action.pageTitle;
|
||||
@@ -115,19 +121,13 @@ const reducerInstance = createReducer(initialState, {
|
||||
const { backLink } = action.payload;
|
||||
state.backLink = backLink;
|
||||
},
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: [
|
||||
'sidebarExpended',
|
||||
'previousSidebarExpended',
|
||||
],
|
||||
storage,
|
||||
},
|
||||
reducerInstance,
|
||||
);
|
||||
export default persistReducer(CONFIG, reducerInstance);
|
||||
|
||||
export const getDialogPayload = (state, dialogName) => {
|
||||
return typeof state.dashboard.dialogs[dialogName] !== 'undefined'
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import { createTableStateReducers } from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -10,17 +11,20 @@ const initialState = {
|
||||
},
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('EXPENSES'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:expenses';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
},
|
||||
reducerInstance,
|
||||
);
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('EXPENSES'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
}
|
||||
});
|
||||
|
||||
export default persistReducer(CONFIG, reducerInstance);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import { createTableStateReducers } from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -12,17 +13,20 @@ const initialState = {
|
||||
selectedRows: [],
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('INVENTORY_ADJUSTMENTS'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:inventoryAdjustments';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('INVENTORY_ADJUSTMENTS'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
reducerInstance,
|
||||
);
|
||||
});
|
||||
|
||||
export default persistReducer(CONFIG, reducerInstance);
|
||||
|
||||
@@ -1,27 +1,33 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import {
|
||||
createTableStateReducers,
|
||||
} from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
// Initial state.
|
||||
const initialState = {
|
||||
tableState: {},
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('ITEMS_CATEGORIES'),
|
||||
});
|
||||
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:itemCategories';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('ITEMS_CATEGORIES'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
CONFIG,
|
||||
reducerInstance,
|
||||
);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import { createTableStateReducers } from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -12,17 +13,23 @@ const initialState = {
|
||||
selectedRows: [],
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('ITEMS'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:items';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('ITEMS'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
CONFIG,
|
||||
reducerInstance,
|
||||
);
|
||||
@@ -1,7 +1,8 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import { createTableStateReducers } from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -10,17 +11,20 @@ const initialState = {
|
||||
},
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('MANUAL_JOURNALS'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:manualJournals';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('MANUAL_JOURNALS'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
reducerInstance,
|
||||
);
|
||||
});
|
||||
|
||||
export default persistReducer(CONFIG, reducerInstance);
|
||||
|
||||
@@ -14,7 +14,10 @@ const reducer = createReducer(initialState, {
|
||||
const _dataByOrganizationId = {};
|
||||
|
||||
organizations.forEach((organization) => {
|
||||
_data[organization.id] = organization;
|
||||
_data[organization.id] = {
|
||||
...state.data[organization.id],
|
||||
...organization,
|
||||
};
|
||||
_dataByOrganizationId[organization.organization_id] = organization.id;
|
||||
});
|
||||
state.data = _data;
|
||||
|
||||
@@ -6,16 +6,28 @@ export default (mapState) => {
|
||||
isOrganizationSetupCompleted,
|
||||
isOrganizationInitialized,
|
||||
isOrganizationSeeded,
|
||||
|
||||
isSubscriptionActive
|
||||
} = props;
|
||||
|
||||
const mapped = {
|
||||
const condits = {
|
||||
isCongratsStep: isOrganizationSetupCompleted,
|
||||
isSubscriptionStep: !isSubscriptionActive,
|
||||
isInitializingStep: isSubscriptionActive && !isOrganizationInitialized,
|
||||
isOrganizationStep: isOrganizationInitialized && !isOrganizationSeeded,
|
||||
};
|
||||
|
||||
const scenarios = [
|
||||
{ condition: condits.isCongratsStep, step: 'congrats' },
|
||||
{ condition: condits.isSubscriptionStep, step: 'subscription' },
|
||||
{ condition: condits.isInitializingStep, step: 'initializing' },
|
||||
{ condition: condits.isOrganizationStep, step: 'organization' },
|
||||
];
|
||||
const setupStep = scenarios.find((scenario) => scenario.condition);
|
||||
const mapped = {
|
||||
...condits,
|
||||
setupStepId: setupStep?.step,
|
||||
setupStepIndex: scenarios.indexOf(setupStep) ,
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
return connect(mapStateToProps);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import {
|
||||
createTableStateReducers,
|
||||
} from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -11,18 +12,24 @@ const initialState = {
|
||||
pageIndex: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('RECEIPTS'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:receipts';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('RECEIPTS'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
},
|
||||
});
|
||||
|
||||
export default persistReducer(
|
||||
CONFIG,
|
||||
reducerInstance,
|
||||
);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { camelCase } from 'lodash';
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import t from 'store/types';
|
||||
import { optionsArrayToMap } from 'utils';
|
||||
|
||||
const initialState = {
|
||||
data: {
|
||||
organization: {
|
||||
name: 'Bigcapital, Limited Liabilities',
|
||||
name: 'Bigcapital, LLC',
|
||||
},
|
||||
manualJournals: {},
|
||||
bills: {},
|
||||
|
||||
@@ -21,4 +21,5 @@ export const setSubscriptions = (subscriptions) => {
|
||||
subscriptions,
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
33
client/src/store/vendors/vendors.reducer.js
vendored
33
client/src/store/vendors/vendors.reducer.js
vendored
@@ -1,9 +1,8 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import { persistReducer } from 'redux-persist';
|
||||
import { persistReducer, purgeStoredState } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
import {
|
||||
createTableStateReducers,
|
||||
} from 'store/tableState.reducer';
|
||||
import { createTableStateReducers } from 'store/tableState.reducer';
|
||||
import t from 'store/types';
|
||||
|
||||
const initialState = {
|
||||
tableState: {
|
||||
@@ -11,17 +10,21 @@ const initialState = {
|
||||
pageIndex: 0,
|
||||
},
|
||||
};
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('VENDORS'),
|
||||
});
|
||||
|
||||
const STORAGE_KEY = 'bigcapital:vendors';
|
||||
|
||||
export default persistReducer(
|
||||
{
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
},
|
||||
reducerInstance,
|
||||
);
|
||||
const CONFIG = {
|
||||
key: STORAGE_KEY,
|
||||
whitelist: ['tableState'],
|
||||
storage,
|
||||
};
|
||||
|
||||
const reducerInstance = createReducer(initialState, {
|
||||
...createTableStateReducers('VENDORS'),
|
||||
|
||||
[t.RESET]: () => {
|
||||
purgeStoredState(CONFIG);
|
||||
}
|
||||
});
|
||||
|
||||
export default persistReducer(CONFIG, reducerInstance);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
color: #565e6c;
|
||||
}
|
||||
.paragraph {
|
||||
opacity: 0.75;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
label.bp3-label{
|
||||
color: #313744;
|
||||
}
|
||||
|
||||
.form-group--language {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
&__period{
|
||||
color: #666;
|
||||
color: #2f3863;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
}
|
||||
&__period {
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
color: #2f3863;
|
||||
|
||||
&::before {
|
||||
content: '/';
|
||||
|
||||
@@ -8,8 +8,10 @@ import {
|
||||
NoPaymentModelWithPricedPlan,
|
||||
PaymentAmountInvalidWithPlan,
|
||||
PaymentInputInvalid,
|
||||
VoucherCodeRequired
|
||||
} from 'exceptions';
|
||||
import { ILicensePaymentModel } from 'interfaces';
|
||||
import instance from 'tsyringe/dist/typings/dependency-container';
|
||||
|
||||
@Service()
|
||||
export default class PaymentViaLicenseController extends PaymentMethodController {
|
||||
@@ -67,6 +69,11 @@ export default class PaymentViaLicenseController extends PaymentMethodController
|
||||
} catch (exception) {
|
||||
const errorReasons = [];
|
||||
|
||||
if (exception instanceof VoucherCodeRequired) {
|
||||
errorReasons.push({
|
||||
type: 'VOUCHER_CODE_REQUIRED', code: 100,
|
||||
});
|
||||
}
|
||||
if (exception instanceof NoPaymentModelWithPricedPlan) {
|
||||
errorReasons.push({
|
||||
type: 'NO_PAYMENT_WITH_PRICED_PLAN',
|
||||
|
||||
@@ -56,6 +56,7 @@ export default () => {
|
||||
app.use('/organization', Container.get(Organization).router());
|
||||
app.use('/ping', Container.get(Ping).router());
|
||||
app.use('/setup', Container.get(Setup).router());
|
||||
|
||||
// - Dashboard routes.
|
||||
// ---------------------------
|
||||
const dashboard = Router();
|
||||
|
||||
Reference in New Issue
Block a user