diff --git a/client/package.json b/client/package.json index e5e6ee159..e0152888e 100644 --- a/client/package.json +++ b/client/package.json @@ -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", diff --git a/client/src/common/languagesOptions.js b/client/src/common/languagesOptions.js index 3de03d718..b331d32ec 100644 --- a/client/src/common/languagesOptions.js +++ b/client/src/common/languagesOptions.js @@ -1,6 +1,6 @@ export default [ - { name: 'English', value: 'EN' }, - { name: 'Arabic', value: 'AR' }, + { name: 'English', value: 'en' }, + { name: 'Arabic', value: 'ar' }, ]; \ No newline at end of file diff --git a/client/src/components/Dashboard/BigcapitalLoading.js b/client/src/components/Dashboard/BigcapitalLoading.js index 56c821511..2c5e244c7 100644 --- a/client/src/components/Dashboard/BigcapitalLoading.js +++ b/client/src/components/Dashboard/BigcapitalLoading.js @@ -11,7 +11,7 @@ export default function BigcapitalLoading({ className }) { return (
- +
); diff --git a/client/src/containers/Dialogs/PaymentViaVoucherDialog/PaymentViaVoucherDialogContent.js b/client/src/containers/Dialogs/PaymentViaVoucherDialog/PaymentViaVoucherDialogContent.js index 49f415d16..cc36aa075 100644 --- a/client/src/containers/Dialogs/PaymentViaVoucherDialog/PaymentViaVoucherDialogContent.js +++ b/client/src/containers/Dialogs/PaymentViaVoucherDialog/PaymentViaVoucherDialogContent.js @@ -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); diff --git a/client/src/containers/Dialogs/PaymentViaVoucherDialog/PaymentViaVoucherForm.js b/client/src/containers/Dialogs/PaymentViaVoucherDialog/PaymentViaVoucherForm.js index 63179d1a4..5ce741460 100644 --- a/client/src/containers/Dialogs/PaymentViaVoucherDialog/PaymentViaVoucherForm.js +++ b/client/src/containers/Dialogs/PaymentViaVoucherDialog/PaymentViaVoucherForm.js @@ -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({

Please enter your preferred payment method below.

- + {({ field, meta: { error, touched } }) => ( } intent={inputIntent({ error, touched })} - helperText={} + helperText={} className={'form-group--voucher_number'} > (licenseNumberRef.current = ref)} /> diff --git a/client/src/containers/Dialogs/PaymentViaVoucherDialog/index.js b/client/src/containers/Dialogs/PaymentViaVoucherDialog/index.js index f3870fd97..7c77c3c45 100644 --- a/client/src/containers/Dialogs/PaymentViaVoucherDialog/index.js +++ b/client/src/containers/Dialogs/PaymentViaVoucherDialog/index.js @@ -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 ( - ) + ); } -export default compose( - withDialogRedux(), -)(PaymentViaLicenseDialog); \ No newline at end of file +export default compose(withDialogRedux())(PaymentViaLicenseDialog); diff --git a/client/src/containers/Organization/withOrganizationActions.js b/client/src/containers/Organization/withOrganizationActions.js index dcac4731a..ec173d264 100644 --- a/client/src/containers/Organization/withOrganizationActions.js +++ b/client/src/containers/Organization/withOrganizationActions.js @@ -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); \ No newline at end of file +export default connect(null, mapDispatchToProps); diff --git a/client/src/containers/Setup/SetupInitializingForm.js b/client/src/containers/Setup/SetupInitializingForm.js index 09569be1a..09fbe601b 100644 --- a/client/src/containers/Setup/SetupInitializingForm.js +++ b/client/src/containers/Setup/SetupInitializingForm.js @@ -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 (
- + {isLoading && }
-

- {/* You organization is initializin... */} - It's time to make your accounting really simple! -

-

- while we set up your account, please remember to verify your account by - clicking on the link we sent to yout registered email address -

+ {isLoading ? ( + <> +

It's time to make your accounting really simple!

+

+ while we set up your account, please remember to verify your + account by clicking on the link we sent to yout registered email + address +

+ + ) : isError ? ( + <> +

Something went wrong!

+

Please refresh the page

+ + ) : ( + <> +

Waiting to redirect

+

Refresh the page if redirect not worked.

+ + )}
); } - -export default compose( - withOrganizationActions, - withWizard, -)(SetupInitializingForm); \ No newline at end of file diff --git a/client/src/containers/Setup/SetupOrganizationForm.js b/client/src/containers/Setup/SetupOrganizationForm.js index c2fa5b14b..dddf52535 100644 --- a/client/src/containers/Setup/SetupOrganizationForm.js +++ b/client/src/containers/Setup/SetupOrganizationForm.js @@ -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 }) { {/* ---------- Organization name ---------- */} - + {({ form, field, meta: { error, touched } }) => ( } label={} className={'form-group--name'} intent={inputIntent({ error, touched })} @@ -55,6 +56,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) { {({ form: { setFieldValue }, field: { value }, meta: { error, touched } }) => ( } label={} intent={inputIntent({ error, touched })} helperText={} @@ -82,6 +84,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) { meta: { error, touched }, }) => ( } label={} className={classNames( 'form-group--base-currency', @@ -137,6 +140,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) { selectedItemProp={'value'} defaultText={} popoverProps={{ minimal: true }} + filterable={false} /> )} @@ -147,6 +151,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) { {({ form: { setFieldValue }, field: { value }, meta: { error, touched } }) => ( } label={} className={classNames( 'form-group--fiscal_year', @@ -167,6 +172,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) { onItemSelect={(item) => { setFieldValue('fiscalYear', item.value) }} + filterable={false} /> )} @@ -180,6 +186,7 @@ export default function SetupOrganizationForm({ isSubmitting, values }) { meta: { error, touched }, }) => ( } label={} className={classNames( 'form-group--time-zone', diff --git a/client/src/containers/Setup/SetupOrganizationPage.js b/client/src/containers/Setup/SetupOrganizationPage.js index 7aa562e75..240558f72 100644 --- a/client/src/containers/Setup/SetupOrganizationPage.js +++ b/client/src/containers/Setup/SetupOrganizationPage.js @@ -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); diff --git a/client/src/containers/Setup/SetupRightSection.js b/client/src/containers/Setup/SetupRightSection.js index e1d784419..96640f6db 100644 --- a/client/src/containers/Setup/SetupRightSection.js +++ b/client/src/containers/Setup/SetupRightSection.js @@ -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 (
-
@@ -84,17 +60,8 @@ export default compose( }), 'main', ), - withSetupWizard( - ({ - isCongratsStep, - isSubscriptionStep, - isInitializingStep, - isOrganizationStep, - }) => ({ - isCongratsStep, - isSubscriptionStep, - isInitializingStep, - isOrganizationStep, - }), - ), + withSetupWizard(({ setupStepId, setupStepIndex }) => ({ + setupStepId, + setupStepIndex, + })), )(SetupRightSection); diff --git a/client/src/containers/Setup/SetupSteps.js b/client/src/containers/Setup/SetupSteps.js new file mode 100644 index 000000000..15a5c0019 --- /dev/null +++ b/client/src/containers/Setup/SetupSteps.js @@ -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; +} diff --git a/client/src/containers/Setup/SetupSubscription.js b/client/src/containers/Setup/SetupSubscription.js index e13cd0f19..de4b4eda3 100644 --- a/client/src/containers/Setup/SetupSubscription.js +++ b/client/src/containers/Setup/SetupSubscription.js @@ -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({ />
); -} - -export default compose( - withWizard, -)(SetupSubscription); +} \ No newline at end of file diff --git a/client/src/containers/Setup/SetupWizardContent.js b/client/src/containers/Setup/SetupWizardContent.js index 1b14e9ddb..fbdb8368c 100644 --- a/client/src/containers/Setup/SetupWizardContent.js +++ b/client/src/containers/Setup/SetupWizardContent.js @@ -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 (
- + - - -
- - - - - - - - - - - - - - - - - -
-
-
+
+ + + + + + +
); } diff --git a/client/src/containers/Setup/WizardSetupSteps.js b/client/src/containers/Setup/WizardSetupSteps.js index d29cb4abe..ae4395c92 100644 --- a/client/src/containers/Setup/WizardSetupSteps.js +++ b/client/src/containers/Setup/WizardSetupSteps.js @@ -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 (
  • -

    +

    + +

  • ); } -function WizardSetupSteps({ - currentStep = 1, -}) { +export default function WizardSetupSteps({ currentStep = 1 }) { return (
    @@ -24,7 +21,7 @@ function WizardSetupSteps({ {registerWizardSteps.map((step, index) => ( ))} @@ -32,5 +29,3 @@ function WizardSetupSteps({
    ); } - -export default WizardSetupSteps; diff --git a/client/src/hooks/query/accounts.js b/client/src/hooks/query/accounts.js index 8acaebee1..2a2d54738 100644 --- a/client/src/hooks/query/accounts.js +++ b/client/src/hooks/query/accounts.js @@ -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, }, diff --git a/client/src/hooks/query/authentication.js b/client/src/hooks/query/authentication.js index 8a780b210..dc86ac5e8 100644 --- a/client/src/hooks/query/authentication.js +++ b/client/src/hooks/query/authentication.js @@ -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; }; /** diff --git a/client/src/hooks/query/index.js b/client/src/hooks/query/index.js index 268856ea1..1ce3eef49 100644 --- a/client/src/hooks/query/index.js +++ b/client/src/hooks/query/index.js @@ -21,3 +21,5 @@ export * from './users'; export * from './invite'; export * from './exchangeRates'; export * from './contacts'; +export * from './subscriptions'; +export * from './organization'; diff --git a/client/src/hooks/query/organization.js b/client/src/hooks/query/organization.js index 60fb83fed..2a70cda75 100644 --- a/client/src/hooks/query/organization.js +++ b/client/src/hooks/query/organization.js @@ -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); }, - } - ) -}; \ No newline at end of file + }, + ); +} diff --git a/client/src/hooks/query/subscriptions.js b/client/src/hooks/query/subscriptions.js new file mode 100644 index 000000000..ebab2893e --- /dev/null +++ b/client/src/hooks/query/subscriptions.js @@ -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]) +}; \ No newline at end of file diff --git a/client/src/hooks/query/types.js b/client/src/hooks/query/types.js index 8cc419f63..bfbb32c69 100644 --- a/client/src/hooks/query/types.js +++ b/client/src/hooks/query/types.js @@ -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 }; diff --git a/client/src/hooks/state/subscriptions.js b/client/src/hooks/state/subscriptions.js index 7da587908..95f2cdd4d 100644 --- a/client/src/hooks/state/subscriptions.js +++ b/client/src/hooks/state/subscriptions.js @@ -11,4 +11,4 @@ export const useSetSubscriptions = () => { return useCallback((subscriptions) => { dispatch(setSubscriptions(subscriptions)); }, [dispatch]); -} \ No newline at end of file +} diff --git a/client/src/store/Bills/bills.reducer.js b/client/src/store/Bills/bills.reducer.js index 1e2b9a302..0d58b54c5 100644 --- a/client/src/store/Bills/bills.reducer.js +++ b/client/src/store/Bills/bills.reducer.js @@ -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, ); \ No newline at end of file diff --git a/client/src/store/Estimate/estimates.reducer.js b/client/src/store/Estimate/estimates.reducer.js index bc26dea13..7ddcdba12 100644 --- a/client/src/store/Estimate/estimates.reducer.js +++ b/client/src/store/Estimate/estimates.reducer.js @@ -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, ); diff --git a/client/src/store/Invoice/invoices.reducer.js b/client/src/store/Invoice/invoices.reducer.js index da6fce26f..e6492a545 100644 --- a/client/src/store/Invoice/invoices.reducer.js +++ b/client/src/store/Invoice/invoices.reducer.js @@ -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, ); diff --git a/client/src/store/PaymentMades/paymentMades.reducer.js b/client/src/store/PaymentMades/paymentMades.reducer.js index 9dbd113b7..c1531fec0 100644 --- a/client/src/store/PaymentMades/paymentMades.reducer.js +++ b/client/src/store/PaymentMades/paymentMades.reducer.js @@ -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); diff --git a/client/src/store/PaymentReceives/paymentReceives.reducer.js b/client/src/store/PaymentReceives/paymentReceives.reducer.js index fc2be7e6b..2bddc3138 100644 --- a/client/src/store/PaymentReceives/paymentReceives.reducer.js +++ b/client/src/store/PaymentReceives/paymentReceives.reducer.js @@ -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, ); diff --git a/client/src/store/accounts/accounts.reducer.js b/client/src/store/accounts/accounts.reducer.js index 194b7719a..e486b131d 100644 --- a/client/src/store/accounts/accounts.reducer.js +++ b/client/src/store/accounts/accounts.reducer.js @@ -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); diff --git a/client/src/store/authentication/authentication.reducer.js b/client/src/store/authentication/authentication.reducer.js index abc814e47..0e5b9fde3 100644 --- a/client/src/store/authentication/authentication.reducer.js +++ b/client/src/store/authentication/authentication.reducer.js @@ -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, ); diff --git a/client/src/store/dashboard/dashboard.reducer.js b/client/src/store/dashboard/dashboard.reducer.js index 2f5bee3c3..c88704b54 100644 --- a/client/src/store/dashboard/dashboard.reducer.js +++ b/client/src/store/dashboard/dashboard.reducer.js @@ -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' diff --git a/client/src/store/expenses/expenses.reducer.js b/client/src/store/expenses/expenses.reducer.js index 7c9557ace..318360938 100644 --- a/client/src/store/expenses/expenses.reducer.js +++ b/client/src/store/expenses/expenses.reducer.js @@ -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); diff --git a/client/src/store/inventoryAdjustments/inventoryAdjustment.reducer.js b/client/src/store/inventoryAdjustments/inventoryAdjustment.reducer.js index 96a46b517..15e673224 100644 --- a/client/src/store/inventoryAdjustments/inventoryAdjustment.reducer.js +++ b/client/src/store/inventoryAdjustments/inventoryAdjustment.reducer.js @@ -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); diff --git a/client/src/store/itemCategories/itemsCategory.reducer.js b/client/src/store/itemCategories/itemsCategory.reducer.js index bb15a35dc..fb0d90b3a 100644 --- a/client/src/store/itemCategories/itemsCategory.reducer.js +++ b/client/src/store/itemCategories/itemsCategory.reducer.js @@ -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, ); diff --git a/client/src/store/items/items.reducer.js b/client/src/store/items/items.reducer.js index 0c60a7c43..c8d48cd02 100644 --- a/client/src/store/items/items.reducer.js +++ b/client/src/store/items/items.reducer.js @@ -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, ); \ No newline at end of file diff --git a/client/src/store/manualJournals/manualJournals.reducers.js b/client/src/store/manualJournals/manualJournals.reducers.js index 2cfd009e0..b041a63f4 100644 --- a/client/src/store/manualJournals/manualJournals.reducers.js +++ b/client/src/store/manualJournals/manualJournals.reducers.js @@ -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); diff --git a/client/src/store/organizations/organizations.reducers.js b/client/src/store/organizations/organizations.reducers.js index 6fa8a44e0..9dfa28f20 100644 --- a/client/src/store/organizations/organizations.reducers.js +++ b/client/src/store/organizations/organizations.reducers.js @@ -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; diff --git a/client/src/store/organizations/withSetupWizard.js b/client/src/store/organizations/withSetupWizard.js index 19a265244..d0121bd5c 100644 --- a/client/src/store/organizations/withSetupWizard.js +++ b/client/src/store/organizations/withSetupWizard.js @@ -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); diff --git a/client/src/store/receipts/receipts.reducer.js b/client/src/store/receipts/receipts.reducer.js index de3b218d3..5401eb97a 100644 --- a/client/src/store/receipts/receipts.reducer.js +++ b/client/src/store/receipts/receipts.reducer.js @@ -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, ); diff --git a/client/src/store/settings/settings.reducer.js b/client/src/store/settings/settings.reducer.js index d837ab1dd..3b25af410 100644 --- a/client/src/store/settings/settings.reducer.js +++ b/client/src/store/settings/settings.reducer.js @@ -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: {}, diff --git a/client/src/store/subscription/subscription.actions.js b/client/src/store/subscription/subscription.actions.js index bd765a782..161a2684e 100644 --- a/client/src/store/subscription/subscription.actions.js +++ b/client/src/store/subscription/subscription.actions.js @@ -21,4 +21,5 @@ export const setSubscriptions = (subscriptions) => { subscriptions, }, } -}; \ No newline at end of file +}; + diff --git a/client/src/store/vendors/vendors.reducer.js b/client/src/store/vendors/vendors.reducer.js index 74412377e..2db324950 100644 --- a/client/src/store/vendors/vendors.reducer.js +++ b/client/src/store/vendors/vendors.reducer.js @@ -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); diff --git a/client/src/style/pages/Setup/Organization.scss b/client/src/style/pages/Setup/Organization.scss index 67f43d203..82defab18 100644 --- a/client/src/style/pages/Setup/Organization.scss +++ b/client/src/style/pages/Setup/Organization.scss @@ -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; } diff --git a/client/src/style/pages/Subscription/PlanPeriodRadio.scss b/client/src/style/pages/Subscription/PlanPeriodRadio.scss index 186d11e85..2332f71a6 100644 --- a/client/src/style/pages/Subscription/PlanPeriodRadio.scss +++ b/client/src/style/pages/Subscription/PlanPeriodRadio.scss @@ -30,7 +30,7 @@ font-weight: 600; } &__period{ - color: #666; + color: #2f3863; font-size: 14px; font-weight: 500; diff --git a/client/src/style/pages/Subscription/PlanRadio.scss b/client/src/style/pages/Subscription/PlanRadio.scss index 5615bd53a..ba8c85d45 100644 --- a/client/src/style/pages/Subscription/PlanRadio.scss +++ b/client/src/style/pages/Subscription/PlanRadio.scss @@ -60,7 +60,7 @@ } &__period { font-weight: 400; - color: #666; + color: #2f3863; &::before { content: '/'; diff --git a/server/src/api/controllers/Subscription/PaymentViaLicense.ts b/server/src/api/controllers/Subscription/PaymentViaLicense.ts index 45b219c53..9e8e083c2 100644 --- a/server/src/api/controllers/Subscription/PaymentViaLicense.ts +++ b/server/src/api/controllers/Subscription/PaymentViaLicense.ts @@ -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', diff --git a/server/src/api/index.ts b/server/src/api/index.ts index 4d6cf32f4..5b4fd7d9d 100644 --- a/server/src/api/index.ts +++ b/server/src/api/index.ts @@ -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();