mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
feat: Transactions locking.
This commit is contained in:
@@ -23,8 +23,9 @@ import BadDebtDialog from '../containers/Dialogs/BadDebtDialog';
|
||||
import NotifyInvoiceViaSMSDialog from '../containers/Dialogs/NotifyInvoiceViaSMSDialog';
|
||||
import NotifyReceiptViaSMSDialog from '../containers/Dialogs/NotifyReceiptViaSMSDialog';
|
||||
import NotifyEstimateViaSMSDialog from '../containers/Dialogs/NotifyEstimateViaSMSDialog';
|
||||
import NotifyPaymentReceiveViaSMSDialog from '../containers/Dialogs/NotifyPaymentReceiveViaSMSDialog'
|
||||
import NotifyPaymentReceiveViaSMSDialog from '../containers/Dialogs/NotifyPaymentReceiveViaSMSDialog';
|
||||
import SMSMessageDialog from '../containers/Dialogs/SMSMessageDialog';
|
||||
import TransactionsLockingDialog from '../containers/Dialogs/TransactionsLockingDialog';
|
||||
|
||||
/**
|
||||
* Dialogs container.
|
||||
@@ -58,6 +59,7 @@ export default function DialogsContainer() {
|
||||
|
||||
<BadDebtDialog dialogName={'write-off-bad-debt'} />
|
||||
<SMSMessageDialog dialogName={'sms-message-form'} />
|
||||
<TransactionsLockingDialog dialogName={'transactions-locking'} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -172,6 +172,10 @@ export default [
|
||||
text: <T id={'manual_journals'} />,
|
||||
href: '/manual-journals',
|
||||
},
|
||||
{
|
||||
text: <T id={'sidebar.transactions_locaking'} />,
|
||||
href: '/transactions-locking',
|
||||
},
|
||||
{
|
||||
text: <T id={'exchange_rate'} />,
|
||||
href: '/exchange-rates',
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { TransactionsLockingFormProvider } from './TransactionsLockingFormProvider';
|
||||
import TransactionsLockingForm from './TransactionsLockingForm';
|
||||
|
||||
export default function TransactionsLockingDialogContent({
|
||||
// #ownProps
|
||||
dialogName,
|
||||
}) {
|
||||
return (
|
||||
<TransactionsLockingFormProvider dialogName={dialogName}>
|
||||
<TransactionsLockingForm />
|
||||
</TransactionsLockingFormProvider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import { Intent, Button, Classes } from '@blueprintjs/core';
|
||||
import { useFormikContext } from 'formik';
|
||||
import { FormattedMessage as T } from 'components';
|
||||
|
||||
import { useTransactionLockingContext } from './TransactionsLockingFormProvider';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Transactions locking floating actions.
|
||||
*/
|
||||
function TransactionsLockingFloatingActions({
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
}) {
|
||||
// Formik context.
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
const { dialogName } = useTransactionLockingContext();
|
||||
|
||||
// Handle cancel button click.
|
||||
const handleCancelBtnClick = (event) => {
|
||||
closeDialog(dialogName);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={Classes.DIALOG_FOOTER}>
|
||||
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
onClick={handleCancelBtnClick}
|
||||
style={{ minWidth: '75px' }}
|
||||
>
|
||||
<T id={'cancel'} />
|
||||
</Button>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
loading={isSubmitting}
|
||||
style={{ minWidth: '75px' }}
|
||||
type="submit"
|
||||
>
|
||||
{<T id={'submit'} />}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withDialogActions)(TransactionsLockingFloatingActions);
|
||||
@@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { Formik } from 'formik';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
import '../../../style/pages/TransactionsLocking/TransactionsLockingDialog.scss'
|
||||
|
||||
import { AppToaster } from 'components';
|
||||
import { CreateTransactionsLockingFormSchema } from './TransactionsLockingForm.schema';
|
||||
|
||||
import { useTransactionLockingContext } from './TransactionsLockingFormProvider';
|
||||
import TransactionsLockingFormContent from './TransactionsLockingFormContent';
|
||||
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import { compose } from 'utils';
|
||||
|
||||
const defaultInitialValues = {
|
||||
date: moment(new Date()).format('YYYY-MM-DD'),
|
||||
reason: '',
|
||||
};
|
||||
|
||||
/**
|
||||
* Transactions Locking From.
|
||||
*/
|
||||
function TransactionsLockingForm({
|
||||
// #withDialogActions
|
||||
closeDialog,
|
||||
}) {
|
||||
const { dialogName } = useTransactionLockingContext();
|
||||
// Initial form values.
|
||||
const initialValues = {
|
||||
...defaultInitialValues,
|
||||
};
|
||||
|
||||
// Handles the form submit.
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {};
|
||||
|
||||
return (
|
||||
<Formik
|
||||
validationSchema={CreateTransactionsLockingFormSchema}
|
||||
initialValues={initialValues}
|
||||
onSubmit={handleFormSubmit}
|
||||
component={TransactionsLockingFormContent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
export default compose(withDialogActions)(TransactionsLockingForm);
|
||||
@@ -0,0 +1,13 @@
|
||||
import * as Yup from 'yup';
|
||||
import intl from 'react-intl-universal';
|
||||
import { DATATYPES_LENGTH } from 'common/dataTypes';
|
||||
|
||||
const Schema = Yup.object().shape({
|
||||
date: Yup.date().required().label(intl.get('date')),
|
||||
reason: Yup.string()
|
||||
.required()
|
||||
.min(3)
|
||||
.max(DATATYPES_LENGTH.TEXT)
|
||||
.label(intl.get('reason')),
|
||||
});
|
||||
export const CreateTransactionsLockingFormSchema = Schema;
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import { Form } from 'formik';
|
||||
|
||||
import TransactionsLockingFormFields from './TransactionsLockingFormFields';
|
||||
import TransactionsLockingFloatingActions from './TransactionsLockingFloatingActions';
|
||||
|
||||
/**
|
||||
* Transactions locking form content.
|
||||
*/
|
||||
export default function TransactionsLockingFormContent() {
|
||||
return (
|
||||
<Form>
|
||||
<TransactionsLockingFormFields />
|
||||
<TransactionsLockingFloatingActions />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
import { FastField, ErrorMessage } from 'formik';
|
||||
import { Classes, FormGroup, TextArea, Position } from '@blueprintjs/core';
|
||||
import { DateInput } from '@blueprintjs/datetime';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { FieldRequiredHint, FormattedMessage as T } from 'components';
|
||||
import { useAutofocus } from 'hooks';
|
||||
import {
|
||||
inputIntent,
|
||||
momentFormatter,
|
||||
tansformDateValue,
|
||||
handleDateChange,
|
||||
} from 'utils';
|
||||
|
||||
/**
|
||||
* Transactions locking form fields.
|
||||
*/
|
||||
export default function TransactionsLockingFormFields() {
|
||||
const dateFieldRef = useAutofocus();
|
||||
|
||||
return (
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
{/*------------ Date -----------*/}
|
||||
<FastField name={'date'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'date'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name="date" />}
|
||||
minimal={true}
|
||||
className={classNames(CLASSES.FILL, 'form-group--date')}
|
||||
>
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
onChange={handleDateChange((formattedDate) => {
|
||||
form.setFieldValue('date', formattedDate);
|
||||
})}
|
||||
value={tansformDateValue(value)}
|
||||
popoverProps={{
|
||||
position: Position.BOTTOM,
|
||||
minimal: true,
|
||||
}}
|
||||
intent={inputIntent({ error, touched })}
|
||||
inputRef={(ref) => (dateFieldRef.current = ref)}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
{/*------------ reasons -----------*/}
|
||||
<FastField name={'reason'}>
|
||||
{({ field, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'reason'} />}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
className={'form-group--reason'}
|
||||
intent={inputIntent({ error, touched })}
|
||||
helperText={<ErrorMessage name={'reason'} />}
|
||||
>
|
||||
<TextArea
|
||||
growVertically={true}
|
||||
large={true}
|
||||
intent={inputIntent({ error, touched })}
|
||||
{...field}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import { DialogContent } from 'components';
|
||||
|
||||
const TransactionsLockingContext = React.createContext();
|
||||
|
||||
function TransactionsLockingFormProvider({ dialogName, ...props }) {
|
||||
// State provider.
|
||||
const provider = {
|
||||
dialogName,
|
||||
};
|
||||
return (
|
||||
<DialogContent>
|
||||
<TransactionsLockingContext.Provider value={provider} {...props} />
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
const useTransactionLockingContext = () =>
|
||||
React.useContext(TransactionsLockingContext);
|
||||
|
||||
export { TransactionsLockingFormProvider, useTransactionLockingContext };
|
||||
30
src/containers/Dialogs/TransactionsLockingDialog/index.js
Normal file
30
src/containers/Dialogs/TransactionsLockingDialog/index.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import { Dialog, DialogSuspense, FormattedMessage as T } from 'components';
|
||||
import withDialogRedux from 'components/DialogReduxConnect';
|
||||
import { compose } from 'utils';
|
||||
|
||||
const TransactionsLockingContent = React.lazy(() =>
|
||||
import('./TransactionsLockingDialogContent'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Transaction Locking dialog
|
||||
*/
|
||||
function TransactionsLockingDialog({ dialogName, payload = {}, isOpen }) {
|
||||
return (
|
||||
<Dialog
|
||||
name={dialogName}
|
||||
autoFocus={true}
|
||||
title={<T id={'transactions_locking.dialog.label'} />}
|
||||
canEscapeKeyClose={true}
|
||||
isOpen={isOpen}
|
||||
className={'dialog--transaction--locking'}
|
||||
>
|
||||
<DialogSuspense>
|
||||
<TransactionsLockingContent dialogName={dialogName} />
|
||||
</DialogSuspense>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withDialogRedux())(TransactionsLockingDialog);
|
||||
@@ -0,0 +1,79 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { TransactionsLockingProvider } from './TransactionsLockingProvider';
|
||||
import { TransactionLockingContent } from './components';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Transactions locking list.
|
||||
*/
|
||||
function TransactionsLockingList({
|
||||
// #withDialogActions
|
||||
openDialog,
|
||||
}) {
|
||||
// Handle switch transactions locking.
|
||||
const handleSwitchTransactionsLocking = () => {
|
||||
openDialog('transactions-locking', {});
|
||||
};
|
||||
|
||||
const DataTest = [
|
||||
{
|
||||
name: 'sales',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do',
|
||||
},
|
||||
{
|
||||
name: 'purchases',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do',
|
||||
},
|
||||
{
|
||||
name: 'financial',
|
||||
description:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<TransactionsLockingProvider>
|
||||
<TransactionsLocking>
|
||||
<TransactionsLockingParagraph>
|
||||
<h2>Transaction Locking</h2>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, <br />
|
||||
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
</p>
|
||||
Lock All Transactions At Once.
|
||||
<Link to={'/'}> {''}Lock All Transactions At Once. </Link>
|
||||
</TransactionsLockingParagraph>
|
||||
|
||||
{DataTest.map(({ name, description }) => (
|
||||
<TransactionLockingContent
|
||||
name={name}
|
||||
description={description}
|
||||
onSwitch={handleSwitchTransactionsLocking}
|
||||
/>
|
||||
))}
|
||||
</TransactionsLocking>
|
||||
</TransactionsLockingProvider>
|
||||
);
|
||||
}
|
||||
export default compose(withDialogActions)(TransactionsLockingList);
|
||||
|
||||
const TransactionsLocking = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 22px 32px;
|
||||
`;
|
||||
|
||||
const TransactionsLockingParagraph = styled.div`
|
||||
line-height: 1.5rem;
|
||||
font-size: 16px;
|
||||
h2 {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
|
||||
const TransactionsLockingContext = React.createContext();
|
||||
|
||||
/**
|
||||
* Transactions locking data provider.
|
||||
*/
|
||||
function TransactionsLockingProvider({ ...props }) {
|
||||
// Provider
|
||||
const provider = {};
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
// loading={}
|
||||
>
|
||||
<TransactionsLockingContext.Provider value={provider} {...props} />
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
const useTransactionsLockingContext = () =>
|
||||
React.useContext(TransactionsLockingContext);
|
||||
|
||||
export { TransactionsLockingProvider, useTransactionsLockingContext };
|
||||
51
src/containers/TransactionsLocking/components.js
Normal file
51
src/containers/TransactionsLocking/components.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Switch, FormGroup, Intent } from '@blueprintjs/core';
|
||||
import { Icon, FormattedMessage as T } from 'components';
|
||||
|
||||
export const TransactionLockingContent = ({ name, description, onSwitch }) => (
|
||||
<TransactionLockingWrapp>
|
||||
<TransactionsLockingcontent>
|
||||
<Icon icon="info-circle" iconSize={22} />
|
||||
|
||||
<div className="block">
|
||||
<h3>
|
||||
<T id={name} />
|
||||
</h3>
|
||||
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
<FormGroup>
|
||||
<Switch
|
||||
large={true}
|
||||
defaultChecked={false}
|
||||
minimal={true}
|
||||
className="ml2"
|
||||
onChange={onSwitch}
|
||||
/>
|
||||
</FormGroup>
|
||||
</TransactionsLockingcontent>
|
||||
</TransactionLockingWrapp>
|
||||
);
|
||||
|
||||
const TransactionLockingWrapp = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #d2dce2;
|
||||
max-width: 610px;
|
||||
padding: 22px 15px;
|
||||
margin-top: 25px;
|
||||
|
||||
div.block {
|
||||
flex: 1 1 0;
|
||||
margin-left: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const TransactionsLockingcontent = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1 1 0;
|
||||
`;
|
||||
@@ -1467,5 +1467,12 @@
|
||||
"sms_notification.payment_details.type": "Payment receive thank you.",
|
||||
"sms_notification.receipt_details.type": "Sale receipt details",
|
||||
"personal": "Personal",
|
||||
"list.create":"Create {value}"
|
||||
"list.create":"Create {value}",
|
||||
"roles.label":"Roles",
|
||||
"roles.column.name":"Name",
|
||||
"roles.column.description":"description",
|
||||
"roles.edit_roles":"Edit Roles",
|
||||
"roles.delete_roles":"Delete Roles",
|
||||
"sidebar.transactions_locaking":"Transactions Locaking",
|
||||
"transactions_locking.dialog.label":"Transactions locking"
|
||||
}
|
||||
@@ -785,6 +785,13 @@ export const getDashboardRoutes = () => [
|
||||
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||
defaultSearchResource: RESOURCES_TYPES.ACCOUNT,
|
||||
},
|
||||
{
|
||||
path: `/transactions-locking`,
|
||||
component: lazy(() =>
|
||||
import('../containers/TransactionsLocking/TransactionsLockingList'),
|
||||
),
|
||||
pageTitle: intl.get('sidebar.transactions_locaking'),
|
||||
},
|
||||
// Homepage
|
||||
{
|
||||
path: `/`,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
.dialog--transaction--locking {
|
||||
max-width: 400px;
|
||||
.bp3-form-group {
|
||||
margin-bottom: 15px;
|
||||
margin-top: 15px;
|
||||
|
||||
label.bp3-label {
|
||||
font-size: 13px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-group {
|
||||
&--reason {
|
||||
.bp3-form-content {
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bp3-dialog-footer {
|
||||
padding-top: 10px;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user