Compare commits
216 Commits
BIG-336-it
...
v0.7.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91ff3fdccb | ||
|
|
edd37fff78 | ||
|
|
679f7ce96c | ||
|
|
79b3ab9ec7 | ||
|
|
e7158b7ba7 | ||
|
|
569bc1c4a4 | ||
|
|
b880732087 | ||
|
|
b1e7720bd9 | ||
|
|
5eb9968095 | ||
|
|
b0cf8f723f | ||
|
|
b0a826e62a | ||
|
|
6daa9f09a5 | ||
|
|
f828d85880 | ||
|
|
46d895bef9 | ||
|
|
1fa26c7cb7 | ||
|
|
41d2fc63cb | ||
|
|
4814a40fa9 | ||
|
|
b903aa3eb2 | ||
|
|
872b98fb0d | ||
|
|
b849bfaa95 | ||
|
|
756af3c4d3 | ||
|
|
b935d13918 | ||
|
|
4aea9cb19b | ||
|
|
d22212e6e3 | ||
|
|
6a6ff16c48 | ||
|
|
d08894820d | ||
|
|
2db32b8ee8 | ||
|
|
86c6de361b | ||
|
|
9bd13b0d46 | ||
|
|
30b17d697f | ||
|
|
ce674466fe | ||
|
|
373a695c4c | ||
|
|
3f4ffdc995 | ||
|
|
a9c2a5c5f0 | ||
|
|
908d232cb9 | ||
|
|
10af33f1dc | ||
|
|
767d807490 | ||
|
|
ba1d945dca | ||
|
|
03ea8643e7 | ||
|
|
3d78e5d397 | ||
|
|
fffd255eb1 | ||
|
|
d0f09a0164 | ||
|
|
7774d9f5ab | ||
|
|
e5ab240dfd | ||
|
|
2b07917399 | ||
|
|
79099e1abc | ||
|
|
e87b22801b | ||
|
|
e0eaa56b5c | ||
|
|
d842722183 | ||
|
|
9c14f10edf | ||
|
|
6a8137729f | ||
|
|
5c601fcf2d | ||
|
|
df4c4a832b | ||
|
|
86cab7988c | ||
|
|
8404fee10a | ||
|
|
99a23889bc | ||
|
|
5e2000d252 | ||
|
|
73cb0ec32e | ||
|
|
8fc11b3237 | ||
|
|
eecb81e882 | ||
|
|
2e743f2232 | ||
|
|
3faa765a07 | ||
|
|
a6d93170df | ||
|
|
3d9b95cbcf | ||
|
|
4882afd63f | ||
|
|
8dac7e3d98 | ||
|
|
6e6b005fc9 | ||
|
|
68323486e2 | ||
|
|
fd357196a8 | ||
|
|
5a508dd789 | ||
|
|
bac6812d36 | ||
|
|
ba71679b55 | ||
|
|
bc0f4f4cd9 | ||
|
|
4e53b3a2d5 | ||
|
|
a913b84723 | ||
|
|
50f1979c9f | ||
|
|
3722afdc47 | ||
|
|
5711fb8366 | ||
|
|
09f4d0fbe0 | ||
|
|
918780bf4c | ||
|
|
8b78fbdb86 | ||
|
|
2c0291da84 | ||
|
|
a17fafbc90 | ||
|
|
701c32debd | ||
|
|
70e1e94a4a | ||
|
|
90c77d80eb | ||
|
|
932afddf11 | ||
|
|
a533c3cb76 | ||
|
|
2f36594459 | ||
|
|
a093c0d335 | ||
|
|
120f8d15ec | ||
|
|
65bb05d498 | ||
|
|
64d73fa7b9 | ||
|
|
928e903fe0 | ||
|
|
23261e975d | ||
|
|
e51f203ca8 | ||
|
|
35f40503f3 | ||
|
|
f86845ea91 | ||
|
|
29fbcf1f1c | ||
|
|
39a68f5c25 | ||
|
|
89b28903fa | ||
|
|
4f7e9caedb | ||
|
|
ef91afe041 | ||
|
|
dd5e10ef83 | ||
|
|
acdec70385 | ||
|
|
05126253db | ||
|
|
cc637471d9 | ||
|
|
321d206670 | ||
|
|
69c47aee4d | ||
|
|
ad149c1b18 | ||
|
|
7df4cbdf54 | ||
|
|
ca0672509b | ||
|
|
966d1100aa | ||
|
|
0e263437e1 | ||
|
|
e1977dbe07 | ||
|
|
e6d7d6aa1c | ||
|
|
8e7955bc7e | ||
|
|
379d033344 | ||
|
|
378110f6b3 | ||
|
|
888c3a11e0 | ||
|
|
b0407168a0 | ||
|
|
7f3a494c8d | ||
|
|
d85133b35e | ||
|
|
a360f8a62b | ||
|
|
a91f303111 | ||
|
|
f45d5ecf42 | ||
|
|
3d49ebd1e7 | ||
|
|
f84023f399 | ||
|
|
dd46180d87 | ||
|
|
3e91b01b61 | ||
|
|
bd3059ecd8 | ||
|
|
0bbd31dcce | ||
|
|
c5c490d7ce | ||
|
|
733f198dcb | ||
|
|
c17234f245 | ||
|
|
a2bf37d5cd | ||
|
|
a75451cee7 | ||
|
|
c1ad349f6b | ||
|
|
37f8662cc5 | ||
|
|
c5e360ffa2 | ||
|
|
098429d31a | ||
|
|
433b611188 | ||
|
|
6638accae6 | ||
|
|
2d34baa7a5 | ||
|
|
0f4176ae79 | ||
|
|
4f630d8365 | ||
|
|
e38b96c528 | ||
|
|
e03dee2a9f | ||
|
|
a8311f1798 | ||
|
|
b8b95c7929 | ||
|
|
2501626d70 | ||
|
|
87a56dcd95 | ||
|
|
b26b4c5491 | ||
|
|
d12e35f649 | ||
|
|
51c7a0fcd8 | ||
|
|
a639101e28 | ||
|
|
7467b63e54 | ||
|
|
5c52f80536 | ||
|
|
94c88a7003 | ||
|
|
7f4ee26979 | ||
|
|
e46609e3f1 | ||
|
|
f814374279 | ||
|
|
cfbc59280e | ||
|
|
0923c69c16 | ||
|
|
151e72a76d | ||
|
|
ff2c74344a | ||
|
|
eb340269c0 | ||
|
|
cb9c7fcdb6 | ||
|
|
31a5ee6dda | ||
|
|
01db5a2faa | ||
|
|
a3c79d98b0 | ||
|
|
deddbea752 | ||
|
|
e0126018b8 | ||
|
|
22eb7a1cc1 | ||
|
|
e6a7c7bc58 | ||
|
|
cf7d032aae | ||
|
|
faea111f46 | ||
|
|
836be59cbf | ||
|
|
ffd6629b80 | ||
|
|
9ff91e27e5 | ||
|
|
b15437c88e | ||
|
|
7c9ad8438c | ||
|
|
98a02396a9 | ||
|
|
c7673f57cd | ||
|
|
aa39aab93a | ||
|
|
8e6b0b496f | ||
|
|
914e1de79f | ||
|
|
f6f949bcbc | ||
|
|
f7790ef440 | ||
|
|
05b0f5caac | ||
|
|
f5983937b0 | ||
|
|
3a4c1adbd4 | ||
|
|
e9d379c623 | ||
|
|
b46c3f4843 | ||
|
|
96635ffa84 | ||
|
|
e874b89d2d | ||
|
|
60d37e3424 | ||
|
|
8ae39bf04c | ||
|
|
e3f2c82a38 | ||
|
|
68c0678dc3 | ||
|
|
030be9652c | ||
|
|
554527f17d | ||
|
|
79144ad4a5 | ||
|
|
e6fcbfeea6 | ||
|
|
7eacaa0660 | ||
|
|
673808cceb | ||
|
|
f27ef2c9b0 | ||
|
|
da699a766a | ||
|
|
f1899e1ce1 | ||
|
|
11851d114d | ||
|
|
21779007be | ||
|
|
4fc1ecdc2d | ||
|
|
c9b5cecf7a | ||
|
|
c31e9dcd29 | ||
|
|
430ab95dc3 | ||
|
|
8100a57195 |
67
CHANGELOG.md
@@ -2,6 +2,73 @@
|
|||||||
|
|
||||||
All notable changes to Bigcapital server-side will be in this file.
|
All notable changes to Bigcapital server-side will be in this file.
|
||||||
|
|
||||||
|
## [1.7.2-rc.2] - 04-04-2022
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Add the missing Arabic localization.
|
||||||
|
- Subscription plans modifications.
|
||||||
|
|
||||||
|
## [1.7.1-rc.2] - 30-03-2022
|
||||||
|
|
||||||
|
## Added
|
||||||
|
- `BIG-141` Add inactive status to item drawer details.
|
||||||
|
- `BIG-278` Add created at date on expense details.
|
||||||
|
- `BIG-350` Add empty status content of warehouse transfers service.
|
||||||
|
- `BIG-344` Add branch details to manual journal and expense details.
|
||||||
|
## Fixed
|
||||||
|
- `BIG-221` Remove Non-inventory radio choice on item form.
|
||||||
|
- `BIG-236` Validate estimate expiration date should be equal or bigger than estimate date.
|
||||||
|
- `BIG-237` Validate invoice due date should be equal or bigger than invoice date.
|
||||||
|
- `BIG-238` Validate bill due date should be equal or bigger than bill date.
|
||||||
|
- `BIG-280` Optimize style of multi-select accounts menu.
|
||||||
|
- `BIG-284` Cashflow statement loading bar.
|
||||||
|
- `BIG-296` Creating a new child account from accounts list.
|
||||||
|
- `BIG-301` Navigation bar divider on actions bar hide with permissions control.
|
||||||
|
- `BIG-304` Adding cash or bank account from cash flow service.
|
||||||
|
- `BIG-351` Invalid date in the inventory adjustment detail.
|
||||||
|
- `BIG-352` Fix terms and notes fields on footer of all services.
|
||||||
|
- `BIG-354` Validate the warehouse transfer quantity should be above zero.
|
||||||
|
|
||||||
|
## [1.7.0-rc.1] - 24-03-2022
|
||||||
|
|
||||||
|
## Added
|
||||||
|
- Multiply currencies with foreign currencies.
|
||||||
|
- Multiply warehouses to track inventory items.
|
||||||
|
- Multiply branches to track organization transactions.
|
||||||
|
- Transfer orders between warehouses.
|
||||||
|
- Integrate financial reports with multiply branches.
|
||||||
|
- Integrate inventory reports with multiply warehouses.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
- Optimize style of sale invoice form.
|
||||||
|
- Optimize style of sale receipt form.
|
||||||
|
- Optimize style of credit note form.
|
||||||
|
- Optimize style of payment receive form.
|
||||||
|
- Optimize style of bill form.
|
||||||
|
- Optimize style of payment made form.
|
||||||
|
- Optimize style of manual journal form.
|
||||||
|
- Optimize style of expense form.
|
||||||
|
|
||||||
|
## [1.6.3] - 21-02-2022
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `BIG-337` Display billing page once the organization subscription is inactive.
|
||||||
|
|
||||||
|
## [1.6.2] - 19-02-2022
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- fix syled components dependency with imported as default components.
|
||||||
|
|
||||||
|
## [1.6.0] - 18-02-2022
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Balance sheet comparison of previous period (PP).
|
||||||
|
- Balance sheet comparison of previous year (PY).
|
||||||
|
- Balance sheet percentage analysis columns and rows basis.
|
||||||
|
- Profit & loss sheet comparison of preivous period (PP).
|
||||||
|
- Profit & loss sheet comparison of previous year (PY).
|
||||||
|
- Profit & loss sheet percentage analysis columns, rows, income and expenses basis.
|
||||||
|
|
||||||
## [1.5.8] - 13-01-2022
|
## [1.5.8] - 13-01-2022
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ function getClientEnvironment(publicUrl) {
|
|||||||
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
|
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
|
||||||
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
|
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
|
||||||
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
|
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
|
||||||
|
|
||||||
|
// Application version.
|
||||||
|
VERSION: paths.appVersion
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// Stringify all values so we can feed into webpack DefinePlugin
|
// Stringify all values so we can feed into webpack DefinePlugin
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ const resolveModule = (resolveFn, filePath) => {
|
|||||||
return resolveFn(`${filePath}.js`);
|
return resolveFn(`${filePath}.js`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const appVersion = require(resolveApp('package.json')).version;
|
||||||
|
|
||||||
// config after eject: we're in ./config/
|
// config after eject: we're in ./config/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
dotenv: resolveApp('.env'),
|
dotenv: resolveApp('.env'),
|
||||||
@@ -65,6 +67,7 @@ module.exports = {
|
|||||||
proxySetup: resolveApp('src/setupProxy.js'),
|
proxySetup: resolveApp('src/setupProxy.js'),
|
||||||
appNodeModules: resolveApp('node_modules'),
|
appNodeModules: resolveApp('node_modules'),
|
||||||
publicUrlOrPath,
|
publicUrlOrPath,
|
||||||
|
appVersion
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "bigcapital-client",
|
"name": "bigcapital-client",
|
||||||
"version": "1.5.8",
|
"version": "1.7.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "7.8.4",
|
"@babel/core": "7.8.4",
|
||||||
"@blueprintjs-formik/core": "^0.1.5",
|
"@blueprintjs-formik/core": "^0.2.1",
|
||||||
"@blueprintjs-formik/select": "^0.1.4",
|
"@blueprintjs-formik/select": "^0.1.4",
|
||||||
"@blueprintjs/core": "^3.50.2",
|
"@blueprintjs/core": "^3.50.2",
|
||||||
"@blueprintjs/datetime": "^3.23.12",
|
"@blueprintjs/datetime": "^3.23.12",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -221,3 +221,5 @@ export const ACCOUNT_TYPES = [
|
|||||||
incomeSheet: true,
|
incomeSheet: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const FOREIGN_CURRENCY_ACCOUNTS = ['cash', 'bank'];
|
||||||
|
|||||||
7
src/common/cellTypes.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
export const CellType = {
|
||||||
|
Text: 'text',
|
||||||
|
Field: 'field',
|
||||||
|
Button: 'button'
|
||||||
|
}
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
|
|
||||||
export const Features = {
|
export const Features = {
|
||||||
Warehouses: 'warehouses',
|
Warehouses: 'warehouses',
|
||||||
Branches: 'branches'
|
Branches: 'branches',
|
||||||
|
ManualJournal: 'manualJournal',
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
|
export * from './accountTypes';
|
||||||
export * from './TableStyle';
|
export * from './TableStyle';
|
||||||
export * from './features';
|
export * from './features';
|
||||||
|
export * from './cellTypes';
|
||||||
|
|
||||||
export const Align = { Left: 'left', Right: 'right', Center: 'center' };
|
export const Align = { Left: 'left', Right: 'right', Center: 'center' };
|
||||||
|
|||||||
73
src/components/Accounts/AccountMultiSelect.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { MenuItem } from '@blueprintjs/core';
|
||||||
|
import { FMultiSelect } from '../Forms';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Classes } from '@blueprintjs/popover2';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} query
|
||||||
|
* @param {*} account
|
||||||
|
* @param {*} _index
|
||||||
|
* @param {*} exactMatch
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const accountItemPredicate = (query, account, _index, exactMatch) => {
|
||||||
|
const normalizedTitle = account.name.toLowerCase();
|
||||||
|
const normalizedQuery = query.toLowerCase();
|
||||||
|
|
||||||
|
if (exactMatch) {
|
||||||
|
return normalizedTitle === normalizedQuery;
|
||||||
|
} else {
|
||||||
|
return `${account.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} account
|
||||||
|
* @param {*} param1
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const accountItemRenderer = (
|
||||||
|
account,
|
||||||
|
{ handleClick, modifiers, query },
|
||||||
|
{ isSelected },
|
||||||
|
) => {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
icon={isSelected ? 'tick' : 'blank'}
|
||||||
|
text={account.name}
|
||||||
|
label={account.code}
|
||||||
|
key={account.id}
|
||||||
|
onClick={handleClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const accountSelectProps = {
|
||||||
|
itemPredicate: accountItemPredicate,
|
||||||
|
itemRenderer: accountItemRenderer,
|
||||||
|
valueAccessor: (item) => item.id,
|
||||||
|
labelAccessor: (item) => item.code,
|
||||||
|
tagRenderer: (item) => item.name,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* branches mulit select.
|
||||||
|
* @param {*} param0
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
*/
|
||||||
|
export function AccountMultiSelect({ accounts, ...rest }) {
|
||||||
|
return (
|
||||||
|
<FMultiSelect
|
||||||
|
items={accounts}
|
||||||
|
popoverProps={{
|
||||||
|
minimal: true,
|
||||||
|
}}
|
||||||
|
{...accountSelectProps}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
1
src/components/Accounts/index.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './AccountMultiSelect';
|
||||||
124
src/components/BranchSuggestField.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { MenuItem } from '@blueprintjs/core';
|
||||||
|
import { Suggest } from '@blueprintjs/select';
|
||||||
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { CLASSES } from 'common/classes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* branch suggest field.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function BranchSuggestField({
|
||||||
|
branches,
|
||||||
|
initialBranchId,
|
||||||
|
selectedBranchId,
|
||||||
|
defaultSelectText = intl.get('select_branch'),
|
||||||
|
popoverFill = false,
|
||||||
|
onBranchSelected,
|
||||||
|
...suggestProps
|
||||||
|
}) {
|
||||||
|
const initialBranch = React.useMemo(
|
||||||
|
() => branches.find((b) => b.id === initialBranchId),
|
||||||
|
[initialBranchId, branches],
|
||||||
|
);
|
||||||
|
|
||||||
|
const [selectedBranch, setSelectedBranch] = React.useState(
|
||||||
|
initialBranch || null,
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (typeof selectedBranchId !== 'undefined') {
|
||||||
|
const branch = selectedBranchId
|
||||||
|
? branches.find((a) => a.id === selectedBranchId)
|
||||||
|
: null;
|
||||||
|
setSelectedBranch(branch);
|
||||||
|
}
|
||||||
|
}, [selectedBranchId, branches, setSelectedBranch]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} branch
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const branchItemRenderer = (branch, { handleClick, modifiers, query }) => {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
// active={modifiers.active}
|
||||||
|
disabled={modifiers.disabled}
|
||||||
|
label={branch.code}
|
||||||
|
key={branch.id}
|
||||||
|
onClick={handleClick}
|
||||||
|
text={branch.name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} query
|
||||||
|
* @param {*} branch
|
||||||
|
* @param {*} _index
|
||||||
|
* @param {*} exactMatch
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const branchItemPredicate = (query, branch, _index, exactMatch) => {
|
||||||
|
const normalizedTitle = branch.name.toLowerCase();
|
||||||
|
const normalizedQuery = query.toLowerCase();
|
||||||
|
|
||||||
|
if (exactMatch) {
|
||||||
|
return normalizedTitle === normalizedQuery;
|
||||||
|
} else {
|
||||||
|
return `${branch.code}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} branch
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const brnachItemSelect = React.useCallback(
|
||||||
|
(branch) => {
|
||||||
|
if (branch.id) {
|
||||||
|
setSelectedBranch({ ...branch });
|
||||||
|
onBranchSelected && onBranchSelected(branch);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setSelectedBranch, onBranchSelected],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} inputVaue
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const branchInputValueRenderer = (inputValue) => {
|
||||||
|
if (inputValue) {
|
||||||
|
return inputValue.name.toString();
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suggest
|
||||||
|
items={branches}
|
||||||
|
noResults={<MenuItem disabled={true} text={<T id={'no_accounts'} />} />}
|
||||||
|
itemRenderer={branchItemRenderer}
|
||||||
|
itemPredicate={branchItemPredicate}
|
||||||
|
onItemSelect={brnachItemSelect}
|
||||||
|
selectedItem={selectedBranch}
|
||||||
|
inputProps={{ placeholder: defaultSelectText }}
|
||||||
|
resetOnClose={true}
|
||||||
|
fill={true}
|
||||||
|
popoverProps={{ minimal: true, boundary: 'window' }}
|
||||||
|
inputValueRenderer={branchInputValueRenderer}
|
||||||
|
className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
|
||||||
|
[CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
|
||||||
|
})}
|
||||||
|
{...suggestProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -38,8 +38,8 @@ const branchItemRenderer = (
|
|||||||
active={modifiers.active}
|
active={modifiers.active}
|
||||||
disabled={modifiers.disabled}
|
disabled={modifiers.disabled}
|
||||||
icon={isSelected ? 'tick' : 'blank'}
|
icon={isSelected ? 'tick' : 'blank'}
|
||||||
text={branch.name.toString()}
|
text={branch.name}
|
||||||
label={branch.code.toString()}
|
label={branch.code}
|
||||||
key={branch.id}
|
key={branch.id}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
/>
|
/>
|
||||||
@@ -50,14 +50,14 @@ const branchSelectProps = {
|
|||||||
itemPredicate: branchItemPredicate,
|
itemPredicate: branchItemPredicate,
|
||||||
itemRenderer: branchItemRenderer,
|
itemRenderer: branchItemRenderer,
|
||||||
valueAccessor: (item) => item.id,
|
valueAccessor: (item) => item.id,
|
||||||
labelAccessor: (item) => item.label,
|
labelAccessor: (item) => item.code,
|
||||||
tagRenderer: (item) => item.name,
|
tagRenderer: (item) => item.name,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* branches mulit select.
|
* branches mulit select.
|
||||||
* @param {*} param0
|
* @param {*} param0
|
||||||
* @returns
|
* @returns {JSX.Element}
|
||||||
*/
|
*/
|
||||||
export function BranchMultiSelect({ branches, ...rest }) {
|
export function BranchMultiSelect({ branches, ...rest }) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const branchItemRenderer = (branch, { handleClick, modifiers, query }) => {
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
active={modifiers.active}
|
active={modifiers.active}
|
||||||
disabled={modifiers.disabled}
|
disabled={modifiers.disabled}
|
||||||
label={branch.name.toString()}
|
label={branch.code}
|
||||||
key={branch.id}
|
key={branch.id}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
text={text}
|
text={text}
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
|
|
||||||
|
|
||||||
export * from './ButtonLink';
|
export * from './ButtonLink';
|
||||||
10
src/components/Currencies/BaseCurrency.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { CurrencyTag } from 'components';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base currecncy.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function BaseCurrency({ currency }) {
|
||||||
|
return <CurrencyTag>{currency}</CurrencyTag>;
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
export * from './CurrencySelect'
|
export * from './CurrencySelect';
|
||||||
|
export * from './BaseCurrency';
|
||||||
|
|||||||
@@ -1,23 +1,29 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import { ButtonLink } from 'components';
|
import { ButtonLink } from '../Button';
|
||||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||||
|
|
||||||
function CustomerDrawerLinkComponent({
|
function CustomerDrawerLinkComponent({
|
||||||
// #ownProps
|
// #ownProps
|
||||||
children,
|
children,
|
||||||
customerId,
|
customerId,
|
||||||
|
className,
|
||||||
|
|
||||||
// #withDrawerActions
|
// #withDrawerActions
|
||||||
openDrawer,
|
openDrawer,
|
||||||
}) {
|
}) {
|
||||||
// Handle view customer drawer.
|
// Handle view customer drawer.
|
||||||
const handleCustomerDrawer = () => {
|
const handleCustomerDrawer = (event) => {
|
||||||
openDrawer('customer-details-drawer', { customerId });
|
openDrawer('customer-details-drawer', { customerId });
|
||||||
|
event.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
return <ButtonLink onClick={handleCustomerDrawer}>{children}</ButtonLink>;
|
return (
|
||||||
|
<ButtonLink className={className} onClick={handleCustomerDrawer}>
|
||||||
|
{children}
|
||||||
|
</ButtonLink>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CustomerDrawerLink = R.compose(withDrawerActions)(
|
export const CustomerDrawerLink = R.compose(withDrawerActions)(
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Ability } from '@casl/ability';
|
import { Ability } from '@casl/ability';
|
||||||
import { createContextualCan } from '@casl/react';
|
import { createContextualCan } from '@casl/react';
|
||||||
import { useDashboardMeta } from '../../hooks/query';
|
|
||||||
|
import { useDashboardMetaBoot } from './DashboardBoot';
|
||||||
|
|
||||||
export const AbilityContext = React.createContext();
|
export const AbilityContext = React.createContext();
|
||||||
export const Can = createContextualCan(AbilityContext.Consumer);
|
export const Can = createContextualCan(AbilityContext.Consumer);
|
||||||
@@ -11,8 +12,8 @@ export const Can = createContextualCan(AbilityContext.Consumer);
|
|||||||
*/
|
*/
|
||||||
export function DashboardAbilityProvider({ children }) {
|
export function DashboardAbilityProvider({ children }) {
|
||||||
const {
|
const {
|
||||||
data: { abilities },
|
meta: { abilities },
|
||||||
} = useDashboardMeta();
|
} = useDashboardMetaBoot();
|
||||||
|
|
||||||
// Ability instance.
|
// Ability instance.
|
||||||
const ability = new Ability(abilities);
|
const ability = new Ability(abilities);
|
||||||
|
|||||||
@@ -6,18 +6,26 @@ import {
|
|||||||
} from '../../hooks/query';
|
} from '../../hooks/query';
|
||||||
import { useSplashLoading } from '../../hooks/state';
|
import { useSplashLoading } from '../../hooks/state';
|
||||||
import { useWatch, useWatchImmediate, useWhen } from '../../hooks';
|
import { useWatch, useWatchImmediate, useWhen } from '../../hooks';
|
||||||
|
import { useSubscription } from '../../hooks/state';
|
||||||
import { setCookie, getCookie } from '../../utils';
|
import { setCookie, getCookie } from '../../utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard meta async booting.
|
* Dashboard meta async booting.
|
||||||
|
* - Fetches the dashboard meta only if the organization subscribe is active.
|
||||||
|
* - Once the dashboard meta query is loading display dashboard splash screen.
|
||||||
*/
|
*/
|
||||||
export function useDashboardMetaBoot() {
|
export function useDashboardMetaBoot() {
|
||||||
|
const { isSubscriptionActive } = useSubscription();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: dashboardMeta,
|
data: dashboardMeta,
|
||||||
isLoading: isDashboardMetaLoading,
|
isLoading: isDashboardMetaLoading,
|
||||||
isSuccess: isDashboardMetaSuccess,
|
isSuccess: isDashboardMetaSuccess,
|
||||||
} = useDashboardMeta({
|
} = useDashboardMeta({
|
||||||
keepPreviousData: true,
|
keepPreviousData: true,
|
||||||
|
|
||||||
|
// Avoid run the query if the organization subscription is not active.
|
||||||
|
enabled: isSubscriptionActive,
|
||||||
});
|
});
|
||||||
const [startLoading, stopLoading] = useSplashLoading();
|
const [startLoading, stopLoading] = useSplashLoading();
|
||||||
|
|
||||||
@@ -30,20 +38,12 @@ export function useDashboardMetaBoot() {
|
|||||||
}, isDashboardMetaSuccess);
|
}, isDashboardMetaSuccess);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
meta: dashboardMeta,
|
||||||
isLoading: isDashboardMetaLoading,
|
isLoading: isDashboardMetaLoading,
|
||||||
|
isSuccess: isDashboardMetaSuccess
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Dashboard async booting.
|
|
||||||
* @returns {{ isLoading: boolean }}
|
|
||||||
*/
|
|
||||||
export function useDashboardBoot() {
|
|
||||||
const { isLoading } = useDashboardMetaBoot();
|
|
||||||
|
|
||||||
return { isLoading };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application async booting.
|
* Application async booting.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { DashboardAbilityProvider } from '../../components';
|
import { DashboardAbilityProvider } from '../../components';
|
||||||
import { useDashboardBoot } from './DashboardBoot';
|
import { useDashboardMetaBoot } from './DashboardBoot';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard provider.
|
* Dashboard provider.
|
||||||
*/
|
*/
|
||||||
export default function DashboardProvider({ children }) {
|
export default function DashboardProvider({ children }) {
|
||||||
const { isLoading } = useDashboardBoot();
|
const { isLoading } = useDashboardMetaBoot();
|
||||||
|
|
||||||
// Avoid display any dashboard component before complete booting.
|
// Avoid display any dashboard component before complete booting.
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import React, { useRef, useCallback, useMemo } from 'react';
|
import React, { useRef, useCallback, useMemo } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useCellAutoFocus } from 'hooks';
|
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
|
import { CellType } from 'common';
|
||||||
|
import { useCellAutoFocus } from 'hooks';
|
||||||
import AccountsSuggestField from 'components/AccountsSuggestField';
|
import AccountsSuggestField from 'components/AccountsSuggestField';
|
||||||
|
|
||||||
// import AccountsSelectList from 'components/AccountsSelectList';
|
|
||||||
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account cell renderer.
|
* Account cell renderer.
|
||||||
*/
|
*/
|
||||||
@@ -74,3 +73,4 @@ export default function AccountCellRenderer({
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
AccountCellRenderer.cellType = CellType.Field;
|
||||||
|
|||||||
44
src/components/DataTableCells/BranchesListFieldCell.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FormGroup, Intent, Classes } from '@blueprintjs/core';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { CellType } from 'common';
|
||||||
|
import BranchSuggestField from '../BranchSuggestField';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Branches list field cell.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function BranchesListFieldCell({
|
||||||
|
column: { id },
|
||||||
|
row: { index, original },
|
||||||
|
payload: { branches, updateData, errors },
|
||||||
|
}) {
|
||||||
|
const handleBranchSelected = React.useCallback(
|
||||||
|
(branch) => {
|
||||||
|
updateData(index, 'branch_id', branch.id);
|
||||||
|
},
|
||||||
|
[updateData, index],
|
||||||
|
);
|
||||||
|
|
||||||
|
const error = errors?.[index]?.[id];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormGroup
|
||||||
|
intent={error ? Intent.DANGER : null}
|
||||||
|
className={classNames(
|
||||||
|
'form-group--select-list',
|
||||||
|
'form-group--contacts-list',
|
||||||
|
Classes.FILL,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<BranchSuggestField
|
||||||
|
branches={branches}
|
||||||
|
onBranchSelected={handleBranchSelected}
|
||||||
|
selectedBranchId={original?.branch_id}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BranchesListFieldCell.cellType = CellType.Field;
|
||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { Classes, Checkbox, FormGroup, Intent } from '@blueprintjs/core';
|
import { Classes, Checkbox, FormGroup, Intent } from '@blueprintjs/core';
|
||||||
|
import { CellType } from 'common';
|
||||||
|
|
||||||
const CheckboxEditableCell = ({
|
const CheckboxEditableCell = ({
|
||||||
row: { index, original },
|
row: { index, original },
|
||||||
@@ -45,4 +46,6 @@ const CheckboxEditableCell = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CheckboxEditableCell.cellType = CellType.Field;
|
||||||
|
|
||||||
export default CheckboxEditableCell;
|
export default CheckboxEditableCell;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { FormGroup, Intent, Classes } from '@blueprintjs/core';
|
import { FormGroup, Intent, Classes } from '@blueprintjs/core';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { ContactSelecetList } from 'components';
|
|
||||||
import ContactsSuggestField from 'components/ContactsSuggestField';
|
|
||||||
|
|
||||||
|
import { CellType } from 'common';
|
||||||
|
import ContactsSuggestField from 'components/ContactsSuggestField';
|
||||||
export default function ContactsListCellRenderer({
|
export default function ContactsListCellRenderer({
|
||||||
column: { id },
|
column: { id },
|
||||||
row: { index, original },
|
row: { index, original },
|
||||||
@@ -37,3 +37,5 @@ export default function ContactsListCellRenderer({
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContactsListCellRenderer.cellType = CellType.Field;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Classes, InputGroup, FormGroup, Intent } from '@blueprintjs/core';
|
import { Classes, InputGroup, FormGroup, Intent } from '@blueprintjs/core';
|
||||||
|
import { CellType } from 'common';
|
||||||
|
|
||||||
const InputEditableCell = ({
|
const InputEditableCell = ({
|
||||||
row: { index },
|
row: { index },
|
||||||
@@ -37,4 +38,6 @@ const InputEditableCell = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
InputEditableCell.cellType = CellType.Field;
|
||||||
|
|
||||||
export default InputEditableCell;
|
export default InputEditableCell;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import classNames from 'classnames';
|
|||||||
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
|
import { CellType } from 'common';
|
||||||
import ItemsSuggestField from 'components/ItemsSuggestField';
|
import ItemsSuggestField from 'components/ItemsSuggestField';
|
||||||
|
|
||||||
import { useCellAutoFocus } from 'hooks';
|
import { useCellAutoFocus } from 'hooks';
|
||||||
@@ -54,3 +55,5 @@ export default function ItemsListCell({
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ItemsListCell.cellType = CellType.Field;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import React, { useCallback, useState, useEffect } from 'react';
|
import React, { useCallback, useState, useEffect } from 'react';
|
||||||
import { FormGroup, Intent } from '@blueprintjs/core';
|
import { FormGroup, Intent } from '@blueprintjs/core';
|
||||||
|
|
||||||
import { MoneyInputGroup } from 'components';
|
import { MoneyInputGroup } from 'components';
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
|
import { CellType } from 'common';
|
||||||
|
|
||||||
// Input form cell renderer.
|
// Input form cell renderer.
|
||||||
const MoneyFieldCellRenderer = ({
|
const MoneyFieldCellRenderer = ({
|
||||||
@@ -48,4 +50,6 @@ const MoneyFieldCellRenderer = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MoneyFieldCellRenderer.cellType = CellType.Field;
|
||||||
|
|
||||||
export default MoneyFieldCellRenderer;
|
export default MoneyFieldCellRenderer;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { FormGroup, NumericInput, Intent } from '@blueprintjs/core';
|
import { FormGroup, NumericInput, Intent } from '@blueprintjs/core';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { CellType } from 'common';
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,8 +38,10 @@ export default function NumericInputCell({
|
|||||||
onValueChange={handleValueChange}
|
onValueChange={handleValueChange}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
fill={true}
|
fill={true}
|
||||||
buttonPosition={"none"}
|
buttonPosition={'none'}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NumericInputCell.cellType = CellType.Field;
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import PaymentReceiveListField from 'components/PaymentReceiveListField';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
import { FormGroup, Classes, Intent } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
import PaymentReceiveListField from 'components/PaymentReceiveListField';
|
||||||
|
import { CellType } from 'common';
|
||||||
function PaymentReceiveListFieldCell({
|
function PaymentReceiveListFieldCell({
|
||||||
column: { id },
|
column: { id },
|
||||||
row: { index },
|
row: { index },
|
||||||
@@ -32,4 +33,6 @@ function PaymentReceiveListFieldCell({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PaymentReceiveListFieldCell.cellType = CellType.Field;
|
||||||
|
|
||||||
export default PaymentReceiveListFieldCell;
|
export default PaymentReceiveListFieldCell;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React, { useCallback, useState, useEffect } from 'react';
|
import React, { useCallback, useState, useEffect } from 'react';
|
||||||
import { FormGroup, Intent } from '@blueprintjs/core';
|
import { FormGroup, Intent } from '@blueprintjs/core';
|
||||||
|
|
||||||
import { MoneyInputGroup } from 'components';
|
import { MoneyInputGroup } from 'components';
|
||||||
|
import { CellType } from 'common';
|
||||||
|
|
||||||
const PercentFieldCell = ({
|
const PercentFieldCell = ({
|
||||||
cell: { value: initialValue },
|
cell: { value: initialValue },
|
||||||
@@ -38,4 +40,6 @@ const PercentFieldCell = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PercentFieldCell.cellType = CellType.Field;
|
||||||
|
|
||||||
export default PercentFieldCell;
|
export default PercentFieldCell;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Classes, Switch, FormGroup, Intent } from '@blueprintjs/core';
|
import { Classes, Switch, FormGroup, Intent } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
import { CellType } from 'common';
|
||||||
import { safeInvoke } from 'utils';
|
import { safeInvoke } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,4 +49,6 @@ const SwitchEditableCell = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SwitchEditableCell.cellType = CellType.Field;
|
||||||
|
|
||||||
export default SwitchEditableCell;
|
export default SwitchEditableCell;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Classes, TextArea, FormGroup, Intent } from '@blueprintjs/core';
|
import { Classes, TextArea, FormGroup, Intent } from '@blueprintjs/core';
|
||||||
|
import { CellType } from 'common';
|
||||||
|
|
||||||
const TextAreaEditableCell = ({
|
const TextAreaEditableCell = ({
|
||||||
row: { index },
|
row: { index },
|
||||||
@@ -39,4 +40,6 @@ const TextAreaEditableCell = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TextAreaEditableCell.cellType = CellType.Field;
|
||||||
|
|
||||||
export default TextAreaEditableCell;
|
export default TextAreaEditableCell;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import NumericInputCell from './NumericInputCell';
|
|||||||
import CheckBoxFieldCell from './CheckBoxFieldCell';
|
import CheckBoxFieldCell from './CheckBoxFieldCell';
|
||||||
import SwitchFieldCell from './SwitchFieldCell';
|
import SwitchFieldCell from './SwitchFieldCell';
|
||||||
import TextAreaCell from './TextAreaCell';
|
import TextAreaCell from './TextAreaCell';
|
||||||
|
import BranchesListFieldCell from './BranchesListFieldCell';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
AccountsListFieldCell,
|
AccountsListFieldCell,
|
||||||
@@ -23,4 +24,5 @@ export {
|
|||||||
CheckBoxFieldCell,
|
CheckBoxFieldCell,
|
||||||
SwitchFieldCell,
|
SwitchFieldCell,
|
||||||
TextAreaCell,
|
TextAreaCell,
|
||||||
|
BranchesListFieldCell,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import styled from 'styled-components';
|
||||||
import { CLASSES } from 'common/classes';
|
|
||||||
import { DataTable, If } from 'components';
|
import { DataTable } from 'components';
|
||||||
import 'style/components/DataTable/DataTableEditable.scss';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editable datatable.
|
* Editable datatable.
|
||||||
@@ -11,26 +10,106 @@ export default function DatatableEditable({
|
|||||||
totalRow = false,
|
totalRow = false,
|
||||||
actions,
|
actions,
|
||||||
name,
|
name,
|
||||||
className,
|
|
||||||
...tableProps
|
...tableProps
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<DatatableEditableRoot>
|
||||||
className={classNames(
|
|
||||||
CLASSES.DATATABLE_EDITOR,
|
|
||||||
{
|
|
||||||
[`${CLASSES.DATATABLE_EDITOR}--${name}`]: name,
|
|
||||||
},
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<DataTable {...tableProps} />
|
<DataTable {...tableProps} />
|
||||||
|
</DatatableEditableRoot>
|
||||||
<If condition={actions}>
|
|
||||||
<div className={classNames(CLASSES.DATATABLE_EDITOR_ACTIONS)}>
|
|
||||||
{actions}
|
|
||||||
</div>
|
|
||||||
</If>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DatatableEditableRoot = styled.div`
|
||||||
|
.bp3-form-group {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.table {
|
||||||
|
border: 1px solid #d2dce2;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
.th,
|
||||||
|
.td {
|
||||||
|
border-left: 1px solid #e2e2e2;
|
||||||
|
|
||||||
|
&:first-of-type{
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.thead {
|
||||||
|
.tr .th {
|
||||||
|
padding: 9px 14px;
|
||||||
|
background-color: #f2f3fb;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #415060;
|
||||||
|
border-bottom: 1px solid #d2dce2;
|
||||||
|
|
||||||
|
&,
|
||||||
|
.inner-resizer {
|
||||||
|
border-left-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tbody {
|
||||||
|
.tr .td {
|
||||||
|
border-bottom: 0;
|
||||||
|
border-bottom: 1px solid #d8d8d8;
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 4px 14px;
|
||||||
|
|
||||||
|
&.td-field-type,
|
||||||
|
&.td-button-type{
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tr:last-of-type .td {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
.tr {
|
||||||
|
&:hover .td,
|
||||||
|
.bp3-input {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.bp3-form-group:not(.bp3-intent-danger) .bp3-input,
|
||||||
|
.form-group--select-list .bp3-button {
|
||||||
|
border-color: #ffffff;
|
||||||
|
color: #222;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-align: inherit;
|
||||||
|
}
|
||||||
|
.bp3-form-group:not(.bp3-intent-danger) .bp3-input {
|
||||||
|
border-radius: 2px;
|
||||||
|
padding-left: 14px;
|
||||||
|
padding-right: 14px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 0 0 2px #116cd0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.form-group--select-list .bp3-button {
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-right: 6px;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.form-group--select-list,
|
||||||
|
.bp3-form-group {
|
||||||
|
&.bp3-intent-danger {
|
||||||
|
.bp3-button:not(.bp3-minimal),
|
||||||
|
.bp3-input {
|
||||||
|
border-color: #f7b6b6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.td.actions {
|
||||||
|
.bp3-button {
|
||||||
|
color: #80858f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { If } from 'components';
|
import { camelCase} from 'lodash';
|
||||||
import { Skeleton } from 'components';
|
|
||||||
|
import { If, Skeleton } from 'components';
|
||||||
import { useAppIntlContext } from 'components/AppIntlProvider';
|
import { useAppIntlContext } from 'components/AppIntlProvider';
|
||||||
import TableContext from './TableContext';
|
import TableContext from './TableContext';
|
||||||
import { saveInvoke, ignoreEventFromSelectors } from 'utils';
|
import { saveInvoke, ignoreEventFromSelectors } from 'utils';
|
||||||
@@ -57,6 +58,7 @@ export default function TableCell({ cell, row, index }) {
|
|||||||
}
|
}
|
||||||
saveInvoke(onCellClick, cell, event);
|
saveInvoke(onCellClick, cell, event);
|
||||||
};
|
};
|
||||||
|
const cellType = camelCase(cell.column.Cell.cellType) || 'text';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -65,6 +67,9 @@ export default function TableCell({ cell, row, index }) {
|
|||||||
'is-text-overview': cell.column.textOverview,
|
'is-text-overview': cell.column.textOverview,
|
||||||
clickable: cell.column.clickable,
|
clickable: cell.column.clickable,
|
||||||
'align-right': cell.column.align === 'right',
|
'align-right': cell.column.align === 'right',
|
||||||
|
'align-center': cell.column.align === 'center',
|
||||||
|
[`td-${cell.column.id}`]: cell.column.id,
|
||||||
|
[`td-${cellType}-type`]: !!cellType,
|
||||||
}),
|
}),
|
||||||
onClick: handleCellClick,
|
onClick: handleCellClick,
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Checkbox } from '@blueprintjs/core';
|
import { Checkbox } from '@blueprintjs/core';
|
||||||
|
import { CellType } from 'common';
|
||||||
export default function TableIndeterminateCheckboxRow({ row }) {
|
export default function TableIndeterminateCheckboxRow({ row }) {
|
||||||
return (
|
return (
|
||||||
<div class="selection-checkbox">
|
<div class="selection-checkbox">
|
||||||
@@ -8,3 +8,5 @@ export default function TableIndeterminateCheckboxRow({ row }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TableIndeterminateCheckboxRow.cellType = CellType.Field;
|
||||||
|
|||||||
34
src/components/DetailExchangeRate.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
import { DetailItem } from 'components';
|
||||||
|
import { isEqual } from 'lodash';
|
||||||
|
|
||||||
|
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detail exchange rate item.
|
||||||
|
* @param {*} param0
|
||||||
|
* @param {*} param1
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function DetailExchangeRate({
|
||||||
|
exchangeRate,
|
||||||
|
toCurrency,
|
||||||
|
// #withCurrentOrganization
|
||||||
|
organization: { base_currency },
|
||||||
|
}) {
|
||||||
|
if (isEqual(base_currency, toCurrency)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DetailItem label={intl.get('exchange_rate')}>
|
||||||
|
1 {base_currency} = {exchangeRate} {toCurrency}
|
||||||
|
</DetailItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ExchangeRateDetailItem = R.compose(withCurrentOrganization())(
|
||||||
|
DetailExchangeRate,
|
||||||
|
);
|
||||||
@@ -38,6 +38,8 @@ import WarehouseFormDialog from '../containers/Dialogs/WarehouseFormDialog';
|
|||||||
import BranchFormDialog from '../containers/Dialogs/BranchFormDialog';
|
import BranchFormDialog from '../containers/Dialogs/BranchFormDialog';
|
||||||
import BranchActivateDialog from '../containers/Dialogs/BranchActivateDialog';
|
import BranchActivateDialog from '../containers/Dialogs/BranchActivateDialog';
|
||||||
import WarehouseActivateDialog from '../containers/Dialogs/WarehouseActivateDialog';
|
import WarehouseActivateDialog from '../containers/Dialogs/WarehouseActivateDialog';
|
||||||
|
import CustomerOpeningBalanceDialog from '../containers/Dialogs/CustomerOpeningBalanceDialog';
|
||||||
|
import VendorOpeningBalanceDialog from '../containers/Dialogs/VendorOpeningBalanceDialog';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialogs container.
|
* Dialogs container.
|
||||||
@@ -86,6 +88,8 @@ export default function DialogsContainer() {
|
|||||||
<BranchFormDialog dialogName={'branch-form'} />
|
<BranchFormDialog dialogName={'branch-form'} />
|
||||||
<BranchActivateDialog dialogName={'branch-activate'} />
|
<BranchActivateDialog dialogName={'branch-activate'} />
|
||||||
<WarehouseActivateDialog dialogName={'warehouse-activate'} />
|
<WarehouseActivateDialog dialogName={'warehouse-activate'} />
|
||||||
|
<CustomerOpeningBalanceDialog dialogName={'customer-opening-balance'} />
|
||||||
|
<VendorOpeningBalanceDialog dialogName={'vendor-opening-balance'} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Classes, Icon, H4, Button } from '@blueprintjs/core';
|
|||||||
|
|
||||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||||
|
|
||||||
|
import styled from 'styled-components';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,6 +14,7 @@ function DrawerHeaderContent(props) {
|
|||||||
const {
|
const {
|
||||||
icon,
|
icon,
|
||||||
title = <T id={'view_paper'} />,
|
title = <T id={'view_paper'} />,
|
||||||
|
subTitle,
|
||||||
onClose,
|
onClose,
|
||||||
name,
|
name,
|
||||||
closeDrawer,
|
closeDrawer,
|
||||||
@@ -30,7 +32,10 @@ function DrawerHeaderContent(props) {
|
|||||||
return (
|
return (
|
||||||
<div className={Classes.DRAWER_HEADER}>
|
<div className={Classes.DRAWER_HEADER}>
|
||||||
<Icon icon={icon} iconSize={Icon.SIZE_LARGE} />
|
<Icon icon={icon} iconSize={Icon.SIZE_LARGE} />
|
||||||
<H4>{title}</H4>
|
<H4>
|
||||||
|
{title}
|
||||||
|
<SubTitle>{subTitle}</SubTitle>
|
||||||
|
</H4>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
@@ -44,3 +49,24 @@ function DrawerHeaderContent(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default compose(withDrawerActions)(DrawerHeaderContent);
|
export default compose(withDrawerActions)(DrawerHeaderContent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SubTitle Drawer header.
|
||||||
|
* @returns {React.JSX}
|
||||||
|
*/
|
||||||
|
function SubTitle({ children }) {
|
||||||
|
if (children == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <SubTitleHead>{children}</SubTitleHead>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SubTitleHead = styled.div`
|
||||||
|
color: #666;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 2px 0px;
|
||||||
|
margin: 2px 0px;
|
||||||
|
`;
|
||||||
|
|||||||
@@ -12,23 +12,20 @@ export function ExchangeRateInputGroup({
|
|||||||
formGroupProps,
|
formGroupProps,
|
||||||
name,
|
name,
|
||||||
}) {
|
}) {
|
||||||
const fromCountryCode = 'US';
|
|
||||||
const toCountryCode = 'LY';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FFormGroup inline={true} {...formGroupProps} name={name}>
|
<FFormGroup inline={true} {...formGroupProps} name={name}>
|
||||||
<ControlGroup>
|
<ControlGroup>
|
||||||
<ExchangeRatePrepend>
|
<ExchangeRatePrepend>
|
||||||
<ExchangeFlagIcon countryCode={fromCountryCode} /> 1 {fromCurrency} =
|
<ExchangeFlagIcon currencyCode={fromCurrency} /> 1 {fromCurrency} =
|
||||||
</ExchangeRatePrepend>
|
</ExchangeRatePrepend>
|
||||||
<ExchangeRateField
|
<ExchangeRateField
|
||||||
allowDecimals={false}
|
allowDecimals={true}
|
||||||
allowNegativeValue={true}
|
allowNegativeValue={true}
|
||||||
{...inputGroupProps}
|
{...inputGroupProps}
|
||||||
name={name}
|
name={name}
|
||||||
/>
|
/>
|
||||||
<ExchangeRateAppend>
|
<ExchangeRateAppend>
|
||||||
<ExchangeFlagIcon countryCode={toCountryCode} /> {toCurrency}
|
<ExchangeFlagIcon currencyCode={toCurrency} /> {toCurrency}
|
||||||
</ExchangeRateAppend>
|
</ExchangeRateAppend>
|
||||||
</ControlGroup>
|
</ControlGroup>
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
@@ -36,7 +33,7 @@ export function ExchangeRateInputGroup({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ExchangeRateField = styled(FMoneyInputGroup)`
|
const ExchangeRateField = styled(FMoneyInputGroup)`
|
||||||
max-width: 88px;
|
max-width: 75px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ExchangeRateSideIcon = styled.div`
|
const ExchangeRateSideIcon = styled.div`
|
||||||
|
|||||||
94
src/components/ExchangeRate/ExchangeRateMutedField.js
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Popover,
|
||||||
|
PopoverInteractionKind,
|
||||||
|
FormGroup,
|
||||||
|
Position,
|
||||||
|
Classes,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import { ExchangeRateInputGroup, Icon } from 'components';
|
||||||
|
|
||||||
|
export function ExchangeRateMutedField({
|
||||||
|
name,
|
||||||
|
toCurrency,
|
||||||
|
fromCurrency,
|
||||||
|
date,
|
||||||
|
exchangeRate,
|
||||||
|
exchangeRateFieldProps,
|
||||||
|
popoverProps,
|
||||||
|
}) {
|
||||||
|
const content = (
|
||||||
|
<ExchangeRateFormGroupContent>
|
||||||
|
<ExchangeRateInputGroup
|
||||||
|
name={name}
|
||||||
|
fromCurrency={fromCurrency}
|
||||||
|
toCurrency={toCurrency}
|
||||||
|
{...exchangeRateFieldProps}
|
||||||
|
/>
|
||||||
|
</ExchangeRateFormGroupContent>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ExchangeRateFormGroup label={`As on ${date},`}>
|
||||||
|
<Popover
|
||||||
|
content={content}
|
||||||
|
interactionKind={PopoverInteractionKind.CLICK}
|
||||||
|
position={Position.RIGHT_TOP}
|
||||||
|
modifiers={{
|
||||||
|
offset: { offset: '0, 4' },
|
||||||
|
}}
|
||||||
|
{...popoverProps}
|
||||||
|
minimal={true}
|
||||||
|
usePortal={false}
|
||||||
|
target={<div />}
|
||||||
|
>
|
||||||
|
<ExchangeRateButton>
|
||||||
|
1 {fromCurrency} = {exchangeRate} {toCurrency}
|
||||||
|
<Button
|
||||||
|
className={Classes.MINIMAL}
|
||||||
|
rightIcon={<Icon icon="pen-18" iconSize={14} />}
|
||||||
|
small={true}
|
||||||
|
/>
|
||||||
|
</ExchangeRateButton>
|
||||||
|
</Popover>
|
||||||
|
</ExchangeRateFormGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExchangeRateFormGroup = styled(FormGroup)`
|
||||||
|
&.bp3-form-group {
|
||||||
|
label.bp3-label {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.7;
|
||||||
|
line-height: 1;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ExchangeRateButton = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #0d244a;
|
||||||
|
position: relative;
|
||||||
|
padding-right: 28px;
|
||||||
|
|
||||||
|
.bp3-button {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ExchangeRateFormGroupContent = styled.div`
|
||||||
|
padding: 5px 0;
|
||||||
|
|
||||||
|
.bp3-form-group {
|
||||||
|
padding: 2px;
|
||||||
|
margin: 2px 4px !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -1 +1,2 @@
|
|||||||
export * from './ExchangeRateInput';
|
export * from './ExchangeRateInput';
|
||||||
|
export * from './ExchangeRateMutedField'
|
||||||
@@ -2,7 +2,8 @@ import React, { useMemo, useCallback } from 'react';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
import { If, FormattedMessage as T } from 'components';
|
import If from '../Utils/If';
|
||||||
|
import { FormattedMessage as T } from '../FormattedMessage';
|
||||||
import {
|
import {
|
||||||
FinancialSheetRoot,
|
FinancialSheetRoot,
|
||||||
FinancialSheetFooterCurrentTime,
|
FinancialSheetFooterCurrentTime,
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import React from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { Align } from 'common';
|
import { Align } from 'common';
|
||||||
import { SkeletonText, DataTable } from 'components';
|
import { SkeletonText } from 'components';
|
||||||
|
import DataTable from '../../components/DataTable'
|
||||||
|
|
||||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||||
|
|||||||
9
src/components/FinancialSheet/ReportDataTable.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import DataTable from '../DataTable';
|
||||||
|
|
||||||
|
export const ReportDataTable = styled(DataTable)`
|
||||||
|
.table .tbody .tr.no-results:last-of-type .td {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './FinancialSheet';
|
export * from './FinancialSheet';
|
||||||
export * from './FinancialSheetSkeleton';
|
export * from './FinancialSheetSkeleton';
|
||||||
|
export * from './ReportDataTable';
|
||||||
44
src/components/FormTopbar.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { Navbar } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form the topbar.
|
||||||
|
* @param {JSX.Element} children
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
*/
|
||||||
|
export function FormTopbar({ className, children }) {
|
||||||
|
return <FormTopBarRoot className={className}>{children}</FormTopBarRoot>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FormTopBarRoot = styled(Navbar)`
|
||||||
|
box-shadow: 0 0 0;
|
||||||
|
border-bottom: 1px solid #c7d5db;
|
||||||
|
height: 35px;
|
||||||
|
padding: 0 20px;
|
||||||
|
|
||||||
|
.bp3-navbar-group {
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
.bp3-navbar-divider {
|
||||||
|
border-left-color: #d2dce2;
|
||||||
|
}
|
||||||
|
.bp3-skeleton {
|
||||||
|
max-height: 10px;
|
||||||
|
}
|
||||||
|
.bp3-button {
|
||||||
|
&:hover {
|
||||||
|
background: rgba(167, 182, 194, 0.12);
|
||||||
|
color: #32304a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DetailsBarSkeletonBase = styled.div`
|
||||||
|
letter-spacing: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 8px;
|
||||||
|
width: 140px;
|
||||||
|
height: 10px;
|
||||||
|
`;
|
||||||
@@ -5,6 +5,8 @@ import {
|
|||||||
Checkbox,
|
Checkbox,
|
||||||
RadioGroup,
|
RadioGroup,
|
||||||
Switch,
|
Switch,
|
||||||
|
EditableText,
|
||||||
|
TextArea,
|
||||||
} from '@blueprintjs-formik/core';
|
} from '@blueprintjs-formik/core';
|
||||||
import { Select, MultiSelect } from '@blueprintjs-formik/select';
|
import { Select, MultiSelect } from '@blueprintjs-formik/select';
|
||||||
|
|
||||||
@@ -17,4 +19,6 @@ export {
|
|||||||
Switch as FSwitch,
|
Switch as FSwitch,
|
||||||
Select as FSelect,
|
Select as FSelect,
|
||||||
MultiSelect as FMultiSelect,
|
MultiSelect as FMultiSelect,
|
||||||
|
EditableText as FEditableText,
|
||||||
|
TextArea as FTextArea,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import { useFormikContext } from 'formik';
|
||||||
import { useDeepCompareEffect } from 'hooks/utils';
|
import { useDeepCompareEffect } from 'hooks/utils';
|
||||||
|
|
||||||
export function FormikObserver({ onChange, values }) {
|
export function FormikObserver({ onChange }) {
|
||||||
|
const { values } = useFormikContext();
|
||||||
|
|
||||||
useDeepCompareEffect(() => {
|
useDeepCompareEffect(() => {
|
||||||
onChange(values);
|
onChange(values);
|
||||||
}, [values]);
|
}, [values]);
|
||||||
|
|||||||
12
src/components/Paper/Paper.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export function Paper({ children, className }) {
|
||||||
|
return <PaperRoot className={className}>{children}</PaperRoot>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PaperRoot = styled.div`
|
||||||
|
border: 1px solid #d2dce2;
|
||||||
|
background: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
`;
|
||||||
1
src/components/Paper/index.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './Paper';
|
||||||
@@ -28,7 +28,7 @@ export default function Sidebar({ dashboardContentRef }) {
|
|||||||
* @returns {React.JSX}
|
* @returns {React.JSX}
|
||||||
*/
|
*/
|
||||||
function SidebarFooterVersion() {
|
function SidebarFooterVersion() {
|
||||||
const { REACT_APP_VERSION: VERSION } = process.env;
|
const { VERSION } = process.env;
|
||||||
|
|
||||||
if (!VERSION) {
|
if (!VERSION) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -9,3 +9,13 @@ export const CurrencyTag = styled.span`
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const BaseCurrencyRoot = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 10px;
|
||||||
|
margin-left: 4px;
|
||||||
|
> span {
|
||||||
|
background: #5c7080;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const FlagIcon = ({ countryCode, className }) => {
|
export const FlagIcon = ({ currencyCode, className }) => {
|
||||||
const source = `/icons/flags/${countryCode}.svg`;
|
const source = `/icons/flags/${currencyCode}.svg`;
|
||||||
|
|
||||||
return <img alt="flag" src={source} className={className} />;
|
return <img alt="flag" src={source} className={className} />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const TotalLineBorderStyle = {
|
export const TotalLineBorderStyle = {
|
||||||
|
None: 'None',
|
||||||
SingleDark: 'SingleDark',
|
SingleDark: 'SingleDark',
|
||||||
DoubleDark: 'DoubleDark',
|
DoubleDark: 'DoubleDark',
|
||||||
};
|
};
|
||||||
@@ -80,6 +81,11 @@ export const TotalLineRoot = styled.div`
|
|||||||
`
|
`
|
||||||
border-bottom: 1px double #000;
|
border-bottom: 1px double #000;
|
||||||
`}
|
`}
|
||||||
|
${(props) =>
|
||||||
|
props.borderStyle === TotalLineBorderStyle.None &&
|
||||||
|
`
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
`}
|
||||||
${(props) =>
|
${(props) =>
|
||||||
props.textStyle === TotalLineTextStyle.Bold &&
|
props.textStyle === TotalLineTextStyle.Bold &&
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import { ButtonLink } from 'components';
|
import { ButtonLink } from '../Button';
|
||||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||||
|
|
||||||
function VendorDrawerLinkComponent({
|
function VendorDrawerLinkComponent({
|
||||||
// #ownProps
|
// #ownProps
|
||||||
children,
|
children,
|
||||||
vendorId,
|
vendorId,
|
||||||
|
className,
|
||||||
|
|
||||||
// #withDrawerActions
|
// #withDrawerActions
|
||||||
openDrawer,
|
openDrawer,
|
||||||
}) {
|
}) {
|
||||||
// Handle view customer drawer.
|
// Handle view customer drawer.
|
||||||
const handleVendorDrawer = () => {
|
const handleVendorDrawer = (event) => {
|
||||||
openDrawer('vendor-details-drawer', { vendorId });
|
openDrawer('vendor-details-drawer', { vendorId });
|
||||||
|
event.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
return <ButtonLink onClick={handleVendorDrawer}>{children}</ButtonLink>;
|
return <ButtonLink className={className} onClick={handleVendorDrawer}>{children}</ButtonLink>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VendorDrawerLink = R.compose(withDrawerActions)(VendorDrawerLinkComponent);
|
export const VendorDrawerLink = R.compose(withDrawerActions)(VendorDrawerLinkComponent);
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ const warehouseItemRenderer = (
|
|||||||
active={modifiers.active}
|
active={modifiers.active}
|
||||||
disabled={modifiers.disabled}
|
disabled={modifiers.disabled}
|
||||||
icon={isSelected ? 'tick' : 'blank'}
|
icon={isSelected ? 'tick' : 'blank'}
|
||||||
text={warehouse.name.toString()}
|
text={warehouse.name}
|
||||||
label={warehouse.code.toString()}
|
label={warehouse.code}
|
||||||
key={warehouse.id}
|
key={warehouse.id}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
/>
|
/>
|
||||||
@@ -52,7 +52,7 @@ const warehouseSelectProps = {
|
|||||||
itemPredicate: warehouseItemPredicate,
|
itemPredicate: warehouseItemPredicate,
|
||||||
itemRenderer: warehouseItemRenderer,
|
itemRenderer: warehouseItemRenderer,
|
||||||
valueAccessor: (item) => item.id,
|
valueAccessor: (item) => item.id,
|
||||||
labelAccessor: (item) => item.label,
|
labelAccessor: (item) => item.code,
|
||||||
tagRenderer: (item) => item.name,
|
tagRenderer: (item) => item.name,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const warehouseItemRenderer = (
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
active={modifiers.active}
|
active={modifiers.active}
|
||||||
disabled={modifiers.disabled}
|
disabled={modifiers.disabled}
|
||||||
label={warehouse.name.toString()}
|
label={warehouse.code}
|
||||||
key={warehouse.id}
|
key={warehouse.id}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
text={text}
|
text={text}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ import AvaterCell from './AvaterCell';
|
|||||||
import { ItemsMultiSelect } from './Items';
|
import { ItemsMultiSelect } from './Items';
|
||||||
import MoreMenuItems from './MoreMenutItems';
|
import MoreMenuItems from './MoreMenutItems';
|
||||||
import CustomSelectList from './CustomSelectList';
|
import CustomSelectList from './CustomSelectList';
|
||||||
import BaseCurrency from './BaseCurrency';
|
import { ExchangeRateDetailItem } from './DetailExchangeRate';
|
||||||
|
|
||||||
export * from './Dialog';
|
export * from './Dialog';
|
||||||
export * from './Menu';
|
export * from './Menu';
|
||||||
@@ -102,6 +102,9 @@ export * from './ExchangeRate';
|
|||||||
export * from './Branches';
|
export * from './Branches';
|
||||||
export * from './Warehouses';
|
export * from './Warehouses';
|
||||||
export * from './Currencies';
|
export * from './Currencies';
|
||||||
|
export * from './FormTopbar'
|
||||||
|
export * from './Paper';
|
||||||
|
export * from './Accounts'
|
||||||
|
|
||||||
const Hint = FieldHint;
|
const Hint = FieldHint;
|
||||||
|
|
||||||
@@ -167,7 +170,7 @@ export {
|
|||||||
MoneyFieldCell,
|
MoneyFieldCell,
|
||||||
ItemsMultiSelect,
|
ItemsMultiSelect,
|
||||||
AvaterCell,
|
AvaterCell,
|
||||||
BaseCurrency,
|
|
||||||
MoreMenuItems,
|
MoreMenuItems,
|
||||||
CustomSelectList,
|
CustomSelectList,
|
||||||
|
ExchangeRateDetailItem,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -70,6 +70,20 @@ export const financialReportMenus = [
|
|||||||
subject: AbilitySubject.Report,
|
subject: AbilitySubject.Report,
|
||||||
ability: ReportsAction.READ_AP_AGING_SUMMARY,
|
ability: ReportsAction.READ_AP_AGING_SUMMARY,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: <T id={'report.balance_sheet_comparison.title'} />,
|
||||||
|
desc: <T id={'report.balance_sheet_comparison.desc'} />,
|
||||||
|
link: 'financial-reports/balance-sheet?previousYear=true&previousYearAmountChange=true&previousYearPercentageChange=true',
|
||||||
|
subject: AbilitySubject.Report,
|
||||||
|
ability: ReportsAction.READ_BALANCE_SHEET,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: <T id={'report.profit_loss_sheet_comparison.title'} />,
|
||||||
|
desc: <T id={'report.profit_loss_sheet_comparison.desc'} />,
|
||||||
|
link: '/financial-reports/profit-loss-sheet?previousYear=true&previousYearAmountChange=true&previousYearPercentageChange=true',
|
||||||
|
subject: AbilitySubject.Report,
|
||||||
|
ability: ReportsAction.READ_PROFIT_LOSS,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -641,14 +641,14 @@ export default [
|
|||||||
ability: ReportsAction.READ_AP_AGING_SUMMARY,
|
ability: ReportsAction.READ_AP_AGING_SUMMARY,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
text: <T id={'realized_gain_or_loss.label'} />,
|
// text: <T id={'realized_gain_or_loss.label'} />,
|
||||||
href: '/financial-reports/realized-gain-loss',
|
// href: '/financial-reports/realized-gain-loss',
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
text: <T id={'unrealized_gain_or_loss.label'} />,
|
// text: <T id={'unrealized_gain_or_loss.label'} />,
|
||||||
href: '/financial-reports/unrealized-gain-loss',
|
// href: '/financial-reports/unrealized-gain-loss',
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
text: <T id={'Sales/Purchases'} />,
|
text: <T id={'Sales/Purchases'} />,
|
||||||
label: true,
|
label: true,
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ const Schema = Yup.object().shape({
|
|||||||
.min(1)
|
.min(1)
|
||||||
.max(DATATYPES_LENGTH.STRING)
|
.max(DATATYPES_LENGTH.STRING)
|
||||||
.label(intl.get('journal_type')),
|
.label(intl.get('journal_type')),
|
||||||
date: Yup.date()
|
date: Yup.date().required().label(intl.get('date')),
|
||||||
.required()
|
|
||||||
.label(intl.get('date')),
|
|
||||||
currency_code: Yup.string().max(3),
|
currency_code: Yup.string().max(3),
|
||||||
publish: Yup.boolean(),
|
publish: Yup.boolean(),
|
||||||
|
branch_id: Yup.string(),
|
||||||
reference: Yup.string().nullable().min(1).max(DATATYPES_LENGTH.STRING),
|
reference: Yup.string().nullable().min(1).max(DATATYPES_LENGTH.STRING),
|
||||||
description: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(),
|
description: Yup.string().min(1).max(DATATYPES_LENGTH.STRING).nullable(),
|
||||||
|
exchange_rate: Yup.number(),
|
||||||
entries: Yup.array().of(
|
entries: Yup.array().of(
|
||||||
Yup.object().shape({
|
Yup.object().shape({
|
||||||
credit: Yup.number().nullable(),
|
credit: Yup.number().nullable(),
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { useMakeJournalFormContext } from './MakeJournalProvider';
|
|||||||
* Make journal entries field.
|
* Make journal entries field.
|
||||||
*/
|
*/
|
||||||
export default function MakeJournalEntriesField() {
|
export default function MakeJournalEntriesField() {
|
||||||
const { accounts, contacts } = useMakeJournalFormContext();
|
const { accounts, contacts ,branches } = useMakeJournalFormContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
|
<div className={classNames(CLASSES.PAGE_FORM_BODY)}>
|
||||||
@@ -18,6 +18,7 @@ export default function MakeJournalEntriesField() {
|
|||||||
name={'entries'}
|
name={'entries'}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
accounts={accounts}
|
accounts={accounts}
|
||||||
|
branches={branches}
|
||||||
shouldUpdate={entriesFieldShouldUpdate}
|
shouldUpdate={entriesFieldShouldUpdate}
|
||||||
>
|
>
|
||||||
{({
|
{({
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import MakeJournalFormFloatingActions from './MakeJournalFormFloatingActions';
|
|||||||
import MakeJournalEntriesField from './MakeJournalEntriesField';
|
import MakeJournalEntriesField from './MakeJournalEntriesField';
|
||||||
import MakeJournalFormFooter from './MakeJournalFormFooter';
|
import MakeJournalFormFooter from './MakeJournalFormFooter';
|
||||||
import MakeJournalFormDialogs from './MakeJournalFormDialogs';
|
import MakeJournalFormDialogs from './MakeJournalFormDialogs';
|
||||||
|
import MakeJournalFormTopBar from './MakeJournalFormTopBar';
|
||||||
|
|
||||||
import withSettings from 'containers/Settings/withSettings';
|
import withSettings from 'containers/Settings/withSettings';
|
||||||
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
|
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
|
||||||
@@ -58,6 +59,7 @@ function MakeJournalEntriesForm({
|
|||||||
journalNumberPrefix,
|
journalNumberPrefix,
|
||||||
journalNextNumber,
|
journalNextNumber,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Form initial values.
|
// Form initial values.
|
||||||
const initialValues = useMemo(
|
const initialValues = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -68,12 +70,12 @@ function MakeJournalEntriesForm({
|
|||||||
: {
|
: {
|
||||||
...defaultManualJournal,
|
...defaultManualJournal,
|
||||||
...(journalAutoIncrement && {
|
...(journalAutoIncrement && {
|
||||||
journal_number: defaultTo(journalNumber, ''),
|
journal_number: journalNumber,
|
||||||
}),
|
}),
|
||||||
currency_code: base_currency,
|
currency_code: base_currency,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
[manualJournal, base_currency, journalNumber],
|
[manualJournal, base_currency, journalNumber, journalAutoIncrement],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle the form submiting.
|
// Handle the form submiting.
|
||||||
@@ -107,7 +109,7 @@ function MakeJournalEntriesForm({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const form = {
|
const form = {
|
||||||
...omit(values, ['journal_number', 'journal_number_manually']),
|
...omit(values, ['journal_number_manually']),
|
||||||
...(values.journal_number_manually && {
|
...(values.journal_number_manually && {
|
||||||
journal_number: values.journal_number,
|
journal_number: values.journal_number,
|
||||||
}),
|
}),
|
||||||
@@ -169,6 +171,7 @@ function MakeJournalEntriesForm({
|
|||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
<Form>
|
<Form>
|
||||||
|
<MakeJournalFormTopBar />
|
||||||
<MakeJournalEntriesHeader />
|
<MakeJournalEntriesHeader />
|
||||||
<MakeJournalEntriesField />
|
<MakeJournalEntriesField />
|
||||||
<MakeJournalFormFooter />
|
<MakeJournalFormFooter />
|
||||||
@@ -185,7 +188,7 @@ function MakeJournalEntriesForm({
|
|||||||
export default compose(
|
export default compose(
|
||||||
withMediaActions,
|
withMediaActions,
|
||||||
withSettings(({ manualJournalsSettings }) => ({
|
withSettings(({ manualJournalsSettings }) => ({
|
||||||
journalNextNumber: parseInt(manualJournalsSettings?.nextNumber, 10),
|
journalNextNumber: manualJournalsSettings?.nextNumber,
|
||||||
journalNumberPrefix: manualJournalsSettings?.numberPrefix,
|
journalNumberPrefix: manualJournalsSettings?.numberPrefix,
|
||||||
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
|
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
|
||||||
})),
|
})),
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
} from 'components';
|
} from 'components';
|
||||||
import withSettings from 'containers/Settings/withSettings';
|
import withSettings from 'containers/Settings/withSettings';
|
||||||
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
||||||
|
import { JournalExchangeRateInputField } from './components';
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
import {
|
import {
|
||||||
currenciesFieldShouldUpdate,
|
currenciesFieldShouldUpdate,
|
||||||
@@ -52,14 +53,14 @@ function MakeJournalEntriesHeader({
|
|||||||
|
|
||||||
// Handle journal number change.
|
// Handle journal number change.
|
||||||
const handleJournalNumberChange = () => {
|
const handleJournalNumberChange = () => {
|
||||||
openDialog('journal-number-form', {});
|
openDialog('journal-number-form');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle journal number blur.
|
// Handle journal number blur.
|
||||||
const handleJournalNoBlur = (form, field) => (event) => {
|
const handleJournalNoBlur = (form, field) => (event) => {
|
||||||
const newValue = event.target.value;
|
const newValue = event.target.value;
|
||||||
|
|
||||||
if (field.value !== newValue) {
|
if (field.value !== newValue && journalAutoIncrement) {
|
||||||
openDialog('journal-number-form', {
|
openDialog('journal-number-form', {
|
||||||
initialFormValues: {
|
initialFormValues: {
|
||||||
manualTransactionNo: newValue,
|
manualTransactionNo: newValue,
|
||||||
@@ -201,13 +202,19 @@ function MakeJournalEntriesHeader({
|
|||||||
selectedCurrencyCode={value}
|
selectedCurrencyCode={value}
|
||||||
onCurrencySelected={(currencyItem) => {
|
onCurrencySelected={(currencyItem) => {
|
||||||
form.setFieldValue('currency_code', currencyItem.currency_code);
|
form.setFieldValue('currency_code', currencyItem.currency_code);
|
||||||
|
form.setFieldValue('exchange_rate', '');
|
||||||
}}
|
}}
|
||||||
defaultSelectText={value}
|
defaultSelectText={value}
|
||||||
disabled={true}
|
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
</FastField>
|
</FastField>
|
||||||
|
|
||||||
|
{/* ----------- Exchange rate ----------- */}
|
||||||
|
<JournalExchangeRateInputField
|
||||||
|
name={'exchange_rate'}
|
||||||
|
formGroupProps={{ label: ' ', inline: true }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,15 +21,16 @@ export default function MakeJournalEntriesTable({
|
|||||||
entries,
|
entries,
|
||||||
defaultEntry,
|
defaultEntry,
|
||||||
error,
|
error,
|
||||||
initialLinesNumber = 4,
|
initialLinesNumber = 1,
|
||||||
minLinesNumber = 4,
|
minLinesNumber = 1,
|
||||||
currencyCode,
|
currencyCode,
|
||||||
}) {
|
}) {
|
||||||
const { accounts, contacts } = useMakeJournalFormContext();
|
const { accounts, contacts, branches } = useMakeJournalFormContext();
|
||||||
|
|
||||||
// Memorized data table columns.
|
// Memorized data table columns.
|
||||||
const columns = useJournalTableEntriesColumns();
|
const columns = useJournalTableEntriesColumns();
|
||||||
|
|
||||||
|
|
||||||
// Handles update datatable data.
|
// Handles update datatable data.
|
||||||
const handleUpdateData = (rowIndex, columnId, value) => {
|
const handleUpdateData = (rowIndex, columnId, value) => {
|
||||||
const newRows = compose(
|
const newRows = compose(
|
||||||
@@ -62,13 +63,13 @@ export default function MakeJournalEntriesTable({
|
|||||||
data={entries}
|
data={entries}
|
||||||
sticky={true}
|
sticky={true}
|
||||||
totalRow={true}
|
totalRow={true}
|
||||||
footer={true}
|
|
||||||
payload={{
|
payload={{
|
||||||
accounts,
|
accounts,
|
||||||
errors: error,
|
errors: error,
|
||||||
updateData: handleUpdateData,
|
updateData: handleUpdateData,
|
||||||
removeRow: handleRemoveRow,
|
removeRow: handleRemoveRow,
|
||||||
contacts,
|
contacts,
|
||||||
|
branches,
|
||||||
autoFocus: ['account_id', 0],
|
autoFocus: ['account_id', 0],
|
||||||
currencyCode,
|
currencyCode,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,44 +1,29 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FastField } from 'formik';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
import { FormGroup, TextArea } from '@blueprintjs/core';
|
import { Row, Col, Paper } from 'components';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { MakeJournalFormFooterLeft } from './MakeJournalFormFooterLeft';
|
||||||
import { Postbox, ErrorMessage, Row, Col } from 'components';
|
import { MakeJournalFormFooterRight } from './MakeJournalFormFooterRight';
|
||||||
import Dragzone from 'components/Dragzone';
|
|
||||||
import { inputIntent } from 'utils';
|
|
||||||
|
|
||||||
export default function MakeJournalFormFooter() {
|
export default function MakeJournalFormFooter() {
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_FOOTER)}>
|
<div className={classNames(CLASSES.PAGE_FORM_FOOTER)}>
|
||||||
<Postbox title={<T id={'journal_details'} />} defaultOpen={false}>
|
<MakeJournalFooterPaper>
|
||||||
<Row>
|
<Row>
|
||||||
<Col md={8}>
|
<Col md={8}>
|
||||||
<FastField name={'description'}>
|
<MakeJournalFormFooterLeft />
|
||||||
{({ field, meta: { error, touched } }) => (
|
|
||||||
<FormGroup
|
|
||||||
label={<T id={'description'} />}
|
|
||||||
className={'form-group--description'}
|
|
||||||
intent={inputIntent({ error, touched })}
|
|
||||||
helperText={<ErrorMessage name="description" />}
|
|
||||||
fill={true}
|
|
||||||
>
|
|
||||||
<TextArea fill={true} {...field} />
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
</FastField>
|
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col md={4}>
|
<Col md={4}>
|
||||||
<Dragzone
|
<MakeJournalFormFooterRight />
|
||||||
initialFiles={[]}
|
|
||||||
// onDrop={handleDropFiles}
|
|
||||||
// onDeleteFile={handleDeleteFile}
|
|
||||||
hint={<T id={'attachments_maximum'} />}
|
|
||||||
/>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Postbox>
|
</MakeJournalFooterPaper>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const MakeJournalFooterPaper = styled(Paper)`
|
||||||
|
padding: 20px;
|
||||||
|
`;
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { FFormGroup, FEditableText, FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
|
export function MakeJournalFormFooterLeft() {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{/* --------- Description --------- */}
|
||||||
|
<DescriptionFormGroup
|
||||||
|
label={<T id={'description'} />}
|
||||||
|
name={'description'}
|
||||||
|
>
|
||||||
|
<FEditableText
|
||||||
|
name={'description'}
|
||||||
|
placeholder={<T id={'make_jorunal.decscrption.placeholder'} />}
|
||||||
|
/>
|
||||||
|
</DescriptionFormGroup>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DescriptionFormGroup = styled(FFormGroup)`
|
||||||
|
&.bp3-form-group {
|
||||||
|
.bp3-label {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.bp3-form-content {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import {
|
||||||
|
T,
|
||||||
|
TotalLines,
|
||||||
|
TotalLine,
|
||||||
|
TotalLineBorderStyle,
|
||||||
|
TotalLineTextStyle,
|
||||||
|
} from 'components';
|
||||||
|
import { useJournalTotals } from './utils';
|
||||||
|
|
||||||
|
export function MakeJournalFormFooterRight() {
|
||||||
|
const { formattedSubtotal, formattedTotal } = useJournalTotals();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MakeJouranlTotalLines>
|
||||||
|
<TotalLine
|
||||||
|
title={<T id={'make_journal.label.subtotal'} />}
|
||||||
|
value={formattedSubtotal}
|
||||||
|
borderStyle={TotalLineBorderStyle.None}
|
||||||
|
/>
|
||||||
|
<TotalLine
|
||||||
|
title={<T id={'make_journal.label.total'} />}
|
||||||
|
value={formattedTotal}
|
||||||
|
textStyle={TotalLineTextStyle.Bold}
|
||||||
|
/>
|
||||||
|
</MakeJouranlTotalLines>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MakeJouranlTotalLines = styled(TotalLines)`
|
||||||
|
width: 100%;
|
||||||
|
color: #555555;
|
||||||
|
`;
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { Button, Alignment, NavbarGroup, Classes } from '@blueprintjs/core';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { useSetPrimaryBranchToForm } from './utils';
|
||||||
|
import { useFeatureCan } from 'hooks/state';
|
||||||
|
import {
|
||||||
|
Icon,
|
||||||
|
BranchSelect,
|
||||||
|
FeatureCan,
|
||||||
|
FormTopbar,
|
||||||
|
DetailsBarSkeletonBase,
|
||||||
|
} from 'components';
|
||||||
|
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
||||||
|
import { Features } from 'common';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make journal form topbar.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function MakeJournalFormTopBar() {
|
||||||
|
// Features guard.
|
||||||
|
const { featureCan } = useFeatureCan();
|
||||||
|
|
||||||
|
// Sets the primary branch to form.
|
||||||
|
useSetPrimaryBranchToForm();
|
||||||
|
|
||||||
|
// Can't display the navigation bar if branches feature is not enabled.
|
||||||
|
if (!featureCan(Features.Branches)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormTopbar>
|
||||||
|
<NavbarGroup align={Alignment.LEFT}>
|
||||||
|
<FeatureCan feature={Features.Branches}>
|
||||||
|
<MakeJournalFormSelectBranch />
|
||||||
|
</FeatureCan>
|
||||||
|
</NavbarGroup>
|
||||||
|
</FormTopbar>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MakeJournalFormSelectBranch() {
|
||||||
|
// Invoice form context.
|
||||||
|
const { branches, isBranchesLoading } = useMakeJournalFormContext();
|
||||||
|
|
||||||
|
return isBranchesLoading ? (
|
||||||
|
<DetailsBarSkeletonBase className={Classes.SKELETON} />
|
||||||
|
) : (
|
||||||
|
<BranchSelect
|
||||||
|
name={'branch_id'}
|
||||||
|
branches={branches}
|
||||||
|
input={MakeJournalBranchSelectButton}
|
||||||
|
popoverProps={{ minimal: true }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function MakeJournalBranchSelectButton({ label }) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
text={intl.get('make_journal.branch_button.label', { label })}
|
||||||
|
minimal={true}
|
||||||
|
small={true}
|
||||||
|
icon={<Icon icon={'branch-16'} iconSize={16} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
import React, { createContext, useState } from 'react';
|
import React, { createContext, useState } from 'react';
|
||||||
|
import { isEqual, isUndefined } from 'lodash';
|
||||||
|
import { Features } from 'common';
|
||||||
|
import { useFeatureCan } from 'hooks/state';
|
||||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||||
import {
|
import {
|
||||||
useAccounts,
|
useAccounts,
|
||||||
@@ -8,7 +11,8 @@ import {
|
|||||||
useCreateJournal,
|
useCreateJournal,
|
||||||
useEditJournal,
|
useEditJournal,
|
||||||
useSettings,
|
useSettings,
|
||||||
useSettingsManualJournals
|
useBranches,
|
||||||
|
useSettingsManualJournals,
|
||||||
} from 'hooks/query';
|
} from 'hooks/query';
|
||||||
|
|
||||||
const MakeJournalFormContext = createContext();
|
const MakeJournalFormContext = createContext();
|
||||||
@@ -16,15 +20,17 @@ const MakeJournalFormContext = createContext();
|
|||||||
/**
|
/**
|
||||||
* Make journal form provider.
|
* Make journal form provider.
|
||||||
*/
|
*/
|
||||||
function MakeJournalProvider({ journalId, ...props }) {
|
function MakeJournalProvider({ journalId, query, ...props }) {
|
||||||
|
// Features guard.
|
||||||
|
const { featureCan } = useFeatureCan();
|
||||||
|
const isBranchFeatureCan = featureCan(Features.Branches);
|
||||||
|
|
||||||
// Load the accounts list.
|
// Load the accounts list.
|
||||||
const { data: accounts, isLoading: isAccountsLoading } = useAccounts();
|
const { data: accounts, isLoading: isAccountsLoading } = useAccounts();
|
||||||
|
|
||||||
// Load the customers list.
|
// Load the customers list.
|
||||||
const {
|
const { data: contacts, isLoading: isContactsLoading } =
|
||||||
data: contacts,
|
useAutoCompleteContacts();
|
||||||
isLoading: isContactsLoading,
|
|
||||||
} = useAutoCompleteContacts();
|
|
||||||
|
|
||||||
// Load the currencies list.
|
// Load the currencies list.
|
||||||
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
|
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
|
||||||
@@ -43,15 +49,27 @@ function MakeJournalProvider({ journalId, ...props }) {
|
|||||||
// Loading the journal settings.
|
// Loading the journal settings.
|
||||||
const { isLoading: isSettingsLoading } = useSettingsManualJournals();
|
const { isLoading: isSettingsLoading } = useSettingsManualJournals();
|
||||||
|
|
||||||
|
// Fetches the branches list.
|
||||||
|
const {
|
||||||
|
data: branches,
|
||||||
|
isLoading: isBranchesLoading,
|
||||||
|
isSuccess: isBranchesSuccess,
|
||||||
|
} = useBranches(query, { enabled: isBranchFeatureCan });
|
||||||
|
|
||||||
// Submit form payload.
|
// Submit form payload.
|
||||||
const [submitPayload, setSubmitPayload] = useState({});
|
const [submitPayload, setSubmitPayload] = useState({});
|
||||||
|
|
||||||
|
// Determines whether the warehouse and branches are loading.
|
||||||
|
const isFeatureLoading = isBranchesLoading;
|
||||||
|
|
||||||
const provider = {
|
const provider = {
|
||||||
accounts,
|
accounts,
|
||||||
contacts,
|
contacts,
|
||||||
currencies,
|
currencies,
|
||||||
manualJournal,
|
manualJournal,
|
||||||
|
|
||||||
|
branches,
|
||||||
|
|
||||||
createJournalMutate,
|
createJournalMutate,
|
||||||
editJournalMutate,
|
editJournalMutate,
|
||||||
|
|
||||||
@@ -59,12 +77,13 @@ function MakeJournalProvider({ journalId, ...props }) {
|
|||||||
isContactsLoading,
|
isContactsLoading,
|
||||||
isCurrenciesLoading,
|
isCurrenciesLoading,
|
||||||
isJournalLoading,
|
isJournalLoading,
|
||||||
|
isFeatureLoading,
|
||||||
isSettingsLoading,
|
isSettingsLoading,
|
||||||
|
isBranchesSuccess,
|
||||||
isNewMode: !journalId,
|
isNewMode: !journalId,
|
||||||
|
|
||||||
submitPayload,
|
submitPayload,
|
||||||
setSubmitPayload
|
setSubmitPayload,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,15 +1,28 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Intent, Position, Button, Tooltip } from '@blueprintjs/core';
|
import { Menu, MenuItem, Position, Button } from '@blueprintjs/core';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { Popover2 } from '@blueprintjs/popover2';
|
||||||
import { Icon, Money, Hint } from 'components';
|
import { useFormikContext } from 'formik';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ExchangeRateInputGroup,
|
||||||
|
Icon,
|
||||||
|
Hint,
|
||||||
|
FormattedMessage as T,
|
||||||
|
} from 'components';
|
||||||
import {
|
import {
|
||||||
AccountsListFieldCell,
|
AccountsListFieldCell,
|
||||||
MoneyFieldCell,
|
MoneyFieldCell,
|
||||||
InputGroupCell,
|
InputGroupCell,
|
||||||
ContactsListFieldCell,
|
ContactsListFieldCell,
|
||||||
|
BranchesListFieldCell,
|
||||||
} from 'components/DataTableCells';
|
} from 'components/DataTableCells';
|
||||||
import { safeSumBy } from 'utils';
|
|
||||||
|
import { CellType, Features, Align } from 'common';
|
||||||
|
|
||||||
|
import { useFeatureCan } from 'hooks/state';
|
||||||
|
import { useCurrentOrganization } from 'hooks/state';
|
||||||
|
import { useJournalIsForeign } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contact header cell.
|
* Contact header cell.
|
||||||
@@ -40,42 +53,6 @@ export function DebitHeaderCell({ payload: { currencyCode } }) {
|
|||||||
return intl.get('debit_currency', { currency: currencyCode });
|
return intl.get('debit_currency', { currency: currencyCode });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Account footer cell.
|
|
||||||
*/
|
|
||||||
function AccountFooterCell({ payload: { currencyCode } }) {
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
{intl.get('total_currency', { currency: currencyCode })}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total credit table footer cell.
|
|
||||||
*/
|
|
||||||
function TotalCreditFooterCell({ payload: { currencyCode }, rows }) {
|
|
||||||
const credit = safeSumBy(rows, 'original.credit');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
<Money amount={credit} currency={currencyCode} />
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total debit table footer cell.
|
|
||||||
*/
|
|
||||||
function TotalDebitFooterCell({ payload: { currencyCode }, rows }) {
|
|
||||||
const debit = safeSumBy(rows, 'original.debit');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
<Money amount={debit} currency={currencyCode} />
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Actions cell renderer.
|
* Actions cell renderer.
|
||||||
*/
|
*/
|
||||||
@@ -86,95 +63,123 @@ export const ActionsCellRenderer = ({
|
|||||||
data,
|
data,
|
||||||
payload,
|
payload,
|
||||||
}) => {
|
}) => {
|
||||||
const onClickRemoveRole = () => {
|
const handleClickRemoveRole = () => {
|
||||||
payload.removeRow(index);
|
payload.removeRow(index);
|
||||||
};
|
};
|
||||||
return (
|
const exampleMenu = (
|
||||||
<Tooltip content={<T id={'remove_the_line'} />} position={Position.LEFT}>
|
<Menu>
|
||||||
<Button
|
<MenuItem
|
||||||
icon={<Icon icon="times-circle" iconSize={14} />}
|
onClick={handleClickRemoveRole}
|
||||||
iconSize={14}
|
text={intl.get('make_journal.entries.remove_row')}
|
||||||
className="ml2"
|
|
||||||
minimal={true}
|
|
||||||
intent={Intent.DANGER}
|
|
||||||
onClick={onClickRemoveRole}
|
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Menu>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<Popover2 content={exampleMenu} placement="left-start">
|
||||||
|
<Button
|
||||||
|
icon={<Icon icon={'more-13'} iconSize={13} />}
|
||||||
|
iconSize={14}
|
||||||
|
className="m12"
|
||||||
|
minimal={true}
|
||||||
|
/>
|
||||||
|
</Popover2>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
ActionsCellRenderer.cellType = CellType.Button;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve columns of make journal entries table.
|
* Retrieve columns of make journal entries table.
|
||||||
*/
|
*/
|
||||||
export const useJournalTableEntriesColumns = () => {
|
export const useJournalTableEntriesColumns = () => {
|
||||||
|
const { featureCan } = useFeatureCan();
|
||||||
|
|
||||||
return React.useMemo(
|
return React.useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
|
||||||
Header: '#',
|
|
||||||
accessor: 'index',
|
|
||||||
Cell: ({ row: { index } }) => <span>{index + 1}</span>,
|
|
||||||
className: 'index',
|
|
||||||
width: 40,
|
|
||||||
disableResizing: true,
|
|
||||||
disableSortBy: true,
|
|
||||||
sticky: 'left',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Header: intl.get('account'),
|
Header: intl.get('account'),
|
||||||
id: 'account_id',
|
id: 'account_id',
|
||||||
accessor: 'account_id',
|
accessor: 'account_id',
|
||||||
Cell: AccountsListFieldCell,
|
Cell: AccountsListFieldCell,
|
||||||
Footer: AccountFooterCell,
|
|
||||||
className: 'account',
|
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
width: 160,
|
width: 160,
|
||||||
fieldProps: { allowCreate: true }
|
fieldProps: { allowCreate: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: CreditHeaderCell,
|
Header: CreditHeaderCell,
|
||||||
accessor: 'credit',
|
accessor: 'credit',
|
||||||
Cell: MoneyFieldCell,
|
Cell: MoneyFieldCell,
|
||||||
Footer: TotalCreditFooterCell,
|
|
||||||
className: 'credit',
|
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
|
align: Align.Right,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: DebitHeaderCell,
|
Header: DebitHeaderCell,
|
||||||
accessor: 'debit',
|
accessor: 'debit',
|
||||||
Cell: MoneyFieldCell,
|
Cell: MoneyFieldCell,
|
||||||
Footer: TotalDebitFooterCell,
|
|
||||||
className: 'debit',
|
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
|
align: Align.Right,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: ContactHeaderCell,
|
Header: ContactHeaderCell,
|
||||||
id: 'contact_id',
|
id: 'contact_id',
|
||||||
accessor: 'contact_id',
|
accessor: 'contact_id',
|
||||||
Cell: ContactsListFieldCell,
|
Cell: ContactsListFieldCell,
|
||||||
className: 'contact',
|
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
|
...(featureCan(Features.Branches)
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
Header: intl.get('branch'),
|
||||||
|
id: 'branch_id',
|
||||||
|
accessor: 'branch_id',
|
||||||
|
Cell: BranchesListFieldCell,
|
||||||
|
disableSortBy: true,
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
{
|
{
|
||||||
Header: intl.get('note'),
|
Header: intl.get('note'),
|
||||||
accessor: 'note',
|
accessor: 'note',
|
||||||
Cell: InputGroupCell,
|
Cell: InputGroupCell,
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
className: 'note',
|
|
||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: '',
|
Header: '',
|
||||||
accessor: 'action',
|
accessor: 'action',
|
||||||
Cell: ActionsCellRenderer,
|
Cell: ActionsCellRenderer,
|
||||||
className: 'actions',
|
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
disableResizing: true,
|
disableResizing: true,
|
||||||
width: 45,
|
width: 45,
|
||||||
|
align: Align.Center,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Journal exchange rate input field.
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
*/
|
||||||
|
export function JournalExchangeRateInputField({ ...props }) {
|
||||||
|
const currentOrganization = useCurrentOrganization();
|
||||||
|
const { values } = useFormikContext();
|
||||||
|
|
||||||
|
const isForeignJouranl = useJournalIsForeign();
|
||||||
|
|
||||||
|
// Can't continue if the customer is not foreign.
|
||||||
|
if (!isForeignJouranl) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<ExchangeRateInputGroup
|
||||||
|
fromCurrency={values.currency_code}
|
||||||
|
toCurrency={currentOrganization.base_currency}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Intent } from '@blueprintjs/core';
|
import { Intent } from '@blueprintjs/core';
|
||||||
import { sumBy, setWith, toSafeInteger, get } from 'lodash';
|
import { sumBy, setWith, toSafeInteger, get, first } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import {
|
import {
|
||||||
@@ -9,11 +9,15 @@ import {
|
|||||||
repeatValue,
|
repeatValue,
|
||||||
transformToForm,
|
transformToForm,
|
||||||
defaultFastFieldShouldUpdate,
|
defaultFastFieldShouldUpdate,
|
||||||
ensureEntriesHasEmptyLine
|
ensureEntriesHasEmptyLine,
|
||||||
|
formattedAmount,
|
||||||
|
safeSumBy,
|
||||||
} from 'utils';
|
} from 'utils';
|
||||||
import { AppToaster } from 'components';
|
import { AppToaster } from 'components';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
|
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
||||||
|
import { useCurrentOrganization } from 'hooks/state';
|
||||||
|
|
||||||
const ERROR = {
|
const ERROR = {
|
||||||
JOURNAL_NUMBER_ALREADY_EXISTS: 'JOURNAL.NUMBER.ALREADY.EXISTS',
|
JOURNAL_NUMBER_ALREADY_EXISTS: 'JOURNAL.NUMBER.ALREADY.EXISTS',
|
||||||
@@ -26,25 +30,30 @@ const ERROR = {
|
|||||||
ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
|
ENTRIES_SHOULD_ASSIGN_WITH_CONTACT: 'ENTRIES_SHOULD_ASSIGN_WITH_CONTACT',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MIN_LINES_NUMBER = 4;
|
export const MIN_LINES_NUMBER = 1;
|
||||||
|
export const DEFAULT_LINES_NUMBER = 1;
|
||||||
|
|
||||||
export const defaultEntry = {
|
export const defaultEntry = {
|
||||||
account_id: '',
|
account_id: '',
|
||||||
credit: '',
|
credit: '',
|
||||||
debit: '',
|
debit: '',
|
||||||
contact_id: '',
|
contact_id: '',
|
||||||
|
branch_id: '',
|
||||||
note: '',
|
note: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultManualJournal = {
|
export const defaultManualJournal = {
|
||||||
journal_number: '',
|
journal_number: '',
|
||||||
|
journal_number_manually: false,
|
||||||
journal_type: 'Journal',
|
journal_type: 'Journal',
|
||||||
date: moment(new Date()).format('YYYY-MM-DD'),
|
date: moment(new Date()).format('YYYY-MM-DD'),
|
||||||
description: '',
|
description: '',
|
||||||
reference: '',
|
reference: '',
|
||||||
currency_code: '',
|
currency_code: '',
|
||||||
publish: '',
|
publish: '',
|
||||||
entries: [...repeatValue(defaultEntry, 4)],
|
branch_id: '',
|
||||||
|
exchange_rate: 1,
|
||||||
|
entries: [...repeatValue(defaultEntry, DEFAULT_LINES_NUMBER)],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Transform to edit form.
|
// Transform to edit form.
|
||||||
@@ -179,6 +188,7 @@ export const entriesFieldShouldUpdate = (newProps, oldProps) => {
|
|||||||
return (
|
return (
|
||||||
newProps.accounts !== oldProps.accounts ||
|
newProps.accounts !== oldProps.accounts ||
|
||||||
newProps.contacts !== oldProps.contacts ||
|
newProps.contacts !== oldProps.contacts ||
|
||||||
|
newProps.branches !== oldProps.branches ||
|
||||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -192,3 +202,63 @@ export const currenciesFieldShouldUpdate = (newProps, oldProps) => {
|
|||||||
defaultFastFieldShouldUpdate(newProps, oldProps)
|
defaultFastFieldShouldUpdate(newProps, oldProps)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSetPrimaryBranchToForm = () => {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
const { branches, isBranchesSuccess } = useMakeJournalFormContext();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (isBranchesSuccess) {
|
||||||
|
const primaryBranch = branches.find((b) => b.primary) || first(branches);
|
||||||
|
|
||||||
|
if (primaryBranch) {
|
||||||
|
setFieldValue('branch_id', primaryBranch.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isBranchesSuccess, setFieldValue, branches]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retreives the Journal totals.
|
||||||
|
*/
|
||||||
|
export const useJournalTotals = () => {
|
||||||
|
const {
|
||||||
|
values: { entries, currency_code: currencyCode },
|
||||||
|
} = useFormikContext();
|
||||||
|
|
||||||
|
// Retrieves the invoice entries total.
|
||||||
|
const totalCredit = safeSumBy(entries, 'credit');
|
||||||
|
const totalDebit = safeSumBy(entries, 'debit');
|
||||||
|
|
||||||
|
const total = Math.max(totalCredit, totalDebit);
|
||||||
|
// Retrieves the formatted total money.
|
||||||
|
const formattedTotal = React.useMemo(
|
||||||
|
() => formattedAmount(total, currencyCode),
|
||||||
|
[total, currencyCode],
|
||||||
|
);
|
||||||
|
// Retrieves the formatted subtotal.
|
||||||
|
const formattedSubtotal = React.useMemo(
|
||||||
|
() => formattedAmount(total, currencyCode, { money: false }),
|
||||||
|
[total, currencyCode],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
formattedTotal,
|
||||||
|
formattedSubtotal,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detarmines whether the expenses has foreign .
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export const useJournalIsForeign = () => {
|
||||||
|
const { values } = useFormikContext();
|
||||||
|
const currentOrganization = useCurrentOrganization();
|
||||||
|
|
||||||
|
const isForeignJournal = React.useMemo(
|
||||||
|
() => values.currency_code !== currentOrganization.base_currency,
|
||||||
|
[values.currency_code, currentOrganization.base_currency],
|
||||||
|
);
|
||||||
|
return isForeignJournal;
|
||||||
|
};
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import withSettings from '../Settings/withSettings';
|
|||||||
import { useAccountsChartContext } from './AccountsChartProvider';
|
import { useAccountsChartContext } from './AccountsChartProvider';
|
||||||
import { useMemorizedColumnsWidths } from '../../hooks';
|
import { useMemorizedColumnsWidths } from '../../hooks';
|
||||||
|
|
||||||
|
import { AccountDialogAction } from '../Dialogs/AccountDialog/utils';
|
||||||
|
|
||||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||||
@@ -58,7 +60,10 @@ function AccountsDataTable({
|
|||||||
|
|
||||||
// Handle edit account action.
|
// Handle edit account action.
|
||||||
const handleEditAccount = (account) => {
|
const handleEditAccount = (account) => {
|
||||||
openDialog('account-form', { action: 'edit', id: account.id });
|
openDialog('account-form', {
|
||||||
|
action: AccountDialogAction.Edit,
|
||||||
|
id: account.id,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle view detail account.
|
// Handle view detail account.
|
||||||
@@ -69,7 +74,7 @@ function AccountsDataTable({
|
|||||||
// Handle new child button click.
|
// Handle new child button click.
|
||||||
const handleNewChildAccount = (account) => {
|
const handleNewChildAccount = (account) => {
|
||||||
openDialog('account-form', {
|
openDialog('account-form', {
|
||||||
action: 'new_child',
|
action: AccountDialogAction.NewChild,
|
||||||
parentAccountId: account.id,
|
parentAccountId: account.id,
|
||||||
accountType: account.account_type,
|
accountType: account.account_type,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -57,9 +57,7 @@ function BillTransactionDeleteAlert({
|
|||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
<T
|
<T id={`landed_cost.once_your_delete_this_located_landed_cost`} />
|
||||||
id={`Once your delete this located landed cost, you won't be able to restore it later, Are your sure you want to delete this transaction?`}
|
|
||||||
/>
|
|
||||||
</p>
|
</p>
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Intent, Alert } from '@blueprintjs/core';
|
|||||||
import { AppToaster } from 'components';
|
import { AppToaster } from 'components';
|
||||||
|
|
||||||
import { useDeleteBranch } from 'hooks/query';
|
import { useDeleteBranch } from 'hooks/query';
|
||||||
|
import { handleDeleteErrors } from '../../Preferences/Branches/utils';
|
||||||
|
|
||||||
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
@@ -24,7 +25,6 @@ function BranchDeleteAlert({
|
|||||||
// #withAlertActions
|
// #withAlertActions
|
||||||
closeAlert,
|
closeAlert,
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
const { mutateAsync: deleteBranch, isLoading } = useDeleteBranch();
|
const { mutateAsync: deleteBranch, isLoading } = useDeleteBranch();
|
||||||
|
|
||||||
// Handle cancel delete alert.
|
// Handle cancel delete alert.
|
||||||
@@ -46,7 +46,9 @@ function BranchDeleteAlert({
|
|||||||
response: {
|
response: {
|
||||||
data: { errors },
|
data: { errors },
|
||||||
},
|
},
|
||||||
}) => {},
|
}) => {
|
||||||
|
handleDeleteErrors(errors);
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
closeAlert(name);
|
closeAlert(name);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import intl from 'react-intl-universal';
|
|||||||
import { Intent, Alert } from '@blueprintjs/core';
|
import { Intent, Alert } from '@blueprintjs/core';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import { useMarkPrimaryBranches } from 'hooks/query';
|
import { useMarkBranchAsPrimary } from 'hooks/query';
|
||||||
import { AppToaster } from 'components';
|
import { AppToaster } from 'components';
|
||||||
|
|
||||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
@@ -25,7 +25,7 @@ function BranchMarkPrimaryAlert({
|
|||||||
closeAlert,
|
closeAlert,
|
||||||
}) {
|
}) {
|
||||||
const { mutateAsync: markPrimaryBranchMutate, isLoading } =
|
const { mutateAsync: markPrimaryBranchMutate, isLoading } =
|
||||||
useMarkPrimaryBranches();
|
useMarkBranchAsPrimary();
|
||||||
|
|
||||||
// Handle cancel mark primary alert.
|
// Handle cancel mark primary alert.
|
||||||
const handleCancelMarkPrimaryAlert = () => {
|
const handleCancelMarkPrimaryAlert = () => {
|
||||||
@@ -49,8 +49,8 @@ function BranchMarkPrimaryAlert({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Alert
|
<Alert
|
||||||
cancelButtonText={<T id={'cancel'} />}
|
// cancelButtonText={<T id={'cancel'} />}
|
||||||
confirmButtonText={<T id={'make_primary'} />}
|
// confirmButtonText={<T id={'make_primary'} />}
|
||||||
intent={Intent.WARNING}
|
intent={Intent.WARNING}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onCancel={handleCancelMarkPrimaryAlert}
|
onCancel={handleCancelMarkPrimaryAlert}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { FormattedMessage as T, FormattedHTMLMessage } from 'components';
|
|||||||
import { Intent, Alert } from '@blueprintjs/core';
|
import { Intent, Alert } from '@blueprintjs/core';
|
||||||
import { AppToaster } from 'components';
|
import { AppToaster } from 'components';
|
||||||
import { useDeleteWarehouse } from 'hooks/query';
|
import { useDeleteWarehouse } from 'hooks/query';
|
||||||
|
import { handleDeleteErrors } from '../../Preferences/Warehouses/utils';
|
||||||
|
|
||||||
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
@@ -46,7 +47,9 @@ function WarehouseDeleteAlert({
|
|||||||
response: {
|
response: {
|
||||||
data: { errors },
|
data: { errors },
|
||||||
},
|
},
|
||||||
}) => {},
|
}) => {
|
||||||
|
handleDeleteErrors(errors);
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
closeAlert(name);
|
closeAlert(name);
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage as T } from 'components';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { Intent, Alert } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
import { useTransferredWarehouseTransfer } from 'hooks/query';
|
||||||
|
import { AppToaster } from 'components';
|
||||||
|
|
||||||
|
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||||
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* warehouse transfer transferred alert.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function TransferredWarehouseTransferAlert({
|
||||||
|
name,
|
||||||
|
|
||||||
|
// #withAlertStoreConnect
|
||||||
|
isOpen,
|
||||||
|
payload: { warehouseTransferId },
|
||||||
|
|
||||||
|
// #withAlertActions
|
||||||
|
closeAlert,
|
||||||
|
}) {
|
||||||
|
const { mutateAsync: transferredWarehouseTransferMutate, isLoading } =
|
||||||
|
useTransferredWarehouseTransfer();
|
||||||
|
|
||||||
|
// handle cancel alert.
|
||||||
|
const handleCancelAlert = () => {
|
||||||
|
closeAlert(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle confirm alert.
|
||||||
|
const handleConfirmTransferred = () => {
|
||||||
|
transferredWarehouseTransferMutate(warehouseTransferId)
|
||||||
|
.then(() => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: intl.get('warehouse_transfer.alert.transferred_warehouse'),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {})
|
||||||
|
.finally(() => {
|
||||||
|
closeAlert(name);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
cancelButtonText={<T id={'cancel'} />}
|
||||||
|
confirmButtonText={<T id={'deliver'} />}
|
||||||
|
intent={Intent.WARNING}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onCancel={handleCancelAlert}
|
||||||
|
onConfirm={handleConfirmTransferred}
|
||||||
|
loading={isLoading}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
<T id={'warehouse_transfer.alert.are_you_sure_you_want_to_deliver'} />
|
||||||
|
</p>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withAlertStoreConnect(),
|
||||||
|
withAlertActions,
|
||||||
|
)(TransferredWarehouseTransferAlert);
|
||||||
@@ -3,7 +3,7 @@ import intl from 'react-intl-universal';
|
|||||||
import { Intent, Alert } from '@blueprintjs/core';
|
import { Intent, Alert } from '@blueprintjs/core';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import { useMarkPrimaryWarehouse } from 'hooks/query';
|
import { useMarkWarehouseAsPrimary } from 'hooks/query';
|
||||||
import { AppToaster } from 'components';
|
import { AppToaster } from 'components';
|
||||||
|
|
||||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
@@ -24,14 +24,14 @@ function WarehouseMarkPrimaryAlert({
|
|||||||
// #withAlertActions
|
// #withAlertActions
|
||||||
closeAlert,
|
closeAlert,
|
||||||
}) {
|
}) {
|
||||||
const { mutateAsync: markPrimaryWarehouseMutate, isLoading } =
|
// const { mutateAsync: markPrimaryWarehouseMutate, isLoading } =
|
||||||
useMarkPrimaryWarehouse();
|
// useMarkWarehouseAsPrimary();
|
||||||
|
|
||||||
// Handle cancel mark primary alert.
|
// Handle cancel mark primary alert.
|
||||||
const handleCancelMarkPrimaryAlert = () => {
|
const handleCancelMarkPrimaryAlert = () => {
|
||||||
closeAlert(name);
|
closeAlert(name);
|
||||||
};
|
};
|
||||||
console.log(warehouseId, 'XX');
|
|
||||||
// andle cancel mark primary confirm.
|
// andle cancel mark primary confirm.
|
||||||
const handleConfirmMarkPrimaryWarehouse = () => {
|
const handleConfirmMarkPrimaryWarehouse = () => {
|
||||||
markPrimaryWarehouseMutate(warehouseId)
|
markPrimaryWarehouseMutate(warehouseId)
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage as T } from 'components';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { Intent, Alert } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
import { useInitiateWarehouseTransfer } from 'hooks/query';
|
||||||
|
import { AppToaster } from 'components';
|
||||||
|
|
||||||
|
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||||
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* warehouse transfer initiate alert.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function WarehouseTransferInitiateAlert({
|
||||||
|
name,
|
||||||
|
|
||||||
|
// #withAlertStoreConnect
|
||||||
|
isOpen,
|
||||||
|
payload: { warehouseTransferId },
|
||||||
|
|
||||||
|
// #withAlertActions
|
||||||
|
closeAlert,
|
||||||
|
}) {
|
||||||
|
const { mutateAsync: initialWarehouseTransferMutate, isLoading } =
|
||||||
|
useInitiateWarehouseTransfer();
|
||||||
|
|
||||||
|
// handle cancel alert.
|
||||||
|
const handleCancelAlert = () => {
|
||||||
|
closeAlert(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle confirm alert.
|
||||||
|
const handleConfirmInitiated = () => {
|
||||||
|
initialWarehouseTransferMutate(warehouseTransferId)
|
||||||
|
.then(() => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: intl.get('warehouse_transfer.alert.initiate_warehouse'),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {})
|
||||||
|
.finally(() => {
|
||||||
|
closeAlert(name);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
cancelButtonText={<T id={'cancel'} />}
|
||||||
|
confirmButtonText={<T id={'warehouse_transfer.label.initiate'} />}
|
||||||
|
intent={Intent.WARNING}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onCancel={handleCancelAlert}
|
||||||
|
onConfirm={handleConfirmInitiated}
|
||||||
|
loading={isLoading}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
<T id={'warehouse_transfer.alert.are_you_sure_you_want_to_initate'} />
|
||||||
|
</p>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withAlertStoreConnect(),
|
||||||
|
withAlertActions,
|
||||||
|
)(WarehouseTransferInitiateAlert);
|
||||||
@@ -79,6 +79,10 @@ export const handleCashFlowTransactionType = (reference, openDrawer) => {
|
|||||||
return openDrawer('refund-vendor-detail-drawer', {
|
return openDrawer('refund-vendor-detail-drawer', {
|
||||||
refundTransactionId: reference.reference_id,
|
refundTransactionId: reference.reference_id,
|
||||||
});
|
});
|
||||||
|
case 'InventoryAdjustment':
|
||||||
|
return openDrawer('inventory-adjustment-drawer', {
|
||||||
|
inventoryId: reference.reference_id,
|
||||||
|
});
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return openDrawer('cashflow-transaction-drawer', {
|
return openDrawer('cashflow-transaction-drawer', {
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
|||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
import withCashflowAccountsTableActions from '../AccountTransactions/withCashflowAccountsTableActions';
|
import withCashflowAccountsTableActions from '../AccountTransactions/withCashflowAccountsTableActions';
|
||||||
|
|
||||||
|
import { AccountDialogAction } from '../../Dialogs/AccountDialog/utils';
|
||||||
|
import { ACCOUNT_TYPE } from '../../../common';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,15 +40,15 @@ function CashFlowAccountsActionsBar({
|
|||||||
// Handle add bank account.
|
// Handle add bank account.
|
||||||
const handleAddBankAccount = () => {
|
const handleAddBankAccount = () => {
|
||||||
openDialog('account-form', {
|
openDialog('account-form', {
|
||||||
action: 'NEW_ACCOUNT_DEFINED_TYPE',
|
action: AccountDialogAction.NewDefinedType,
|
||||||
accountType: 'cash',
|
accountType: ACCOUNT_TYPE.CASH,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// Handle add cash account.
|
// Handle add cash account.
|
||||||
const handleAddCashAccount = () => {
|
const handleAddCashAccount = () => {
|
||||||
openDialog('account-form', {
|
openDialog('account-form', {
|
||||||
action: 'NEW_ACCOUNT_DEFINED_TYPE',
|
action: AccountDialogAction.NewDefinedType,
|
||||||
accountType: 'bank',
|
accountType: ACCOUNT_TYPE.BANK,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// Handle inactive switch changing.
|
// Handle inactive switch changing.
|
||||||
|
|||||||
@@ -3,32 +3,33 @@ import classNames from 'classnames';
|
|||||||
import { FormGroup, Position, Classes, ControlGroup } from '@blueprintjs/core';
|
import { FormGroup, Position, Classes, ControlGroup } from '@blueprintjs/core';
|
||||||
import { DateInput } from '@blueprintjs/datetime';
|
import { DateInput } from '@blueprintjs/datetime';
|
||||||
import { FastField, ErrorMessage } from 'formik';
|
import { FastField, ErrorMessage } from 'formik';
|
||||||
|
import { FFormGroup } from '../../../components/Forms';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { Features } from 'common';
|
||||||
import {
|
import {
|
||||||
MoneyInputGroup,
|
MoneyInputGroup,
|
||||||
InputPrependText,
|
InputPrependText,
|
||||||
CurrencySelectList,
|
CurrencySelectList,
|
||||||
|
BranchSelect,
|
||||||
|
BranchSelectButton,
|
||||||
|
FeatureCan,
|
||||||
Row,
|
Row,
|
||||||
Col,
|
Col,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import { useCustomerFormContext } from './CustomerFormProvider';
|
import { useCustomerFormContext } from './CustomerFormProvider';
|
||||||
|
import { useSetPrimaryBranchToForm } from './utils';
|
||||||
import {
|
import { momentFormatter, tansformDateValue, inputIntent } from 'utils';
|
||||||
momentFormatter,
|
|
||||||
tansformDateValue,
|
|
||||||
inputIntent,
|
|
||||||
} from 'utils';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customer financial panel.
|
* Customer financial panel.
|
||||||
*/
|
*/
|
||||||
export default function CustomerFinancialPanel() {
|
export default function CustomerFinancialPanel() {
|
||||||
const {
|
const { currencies, customerId, branches } = useCustomerFormContext();
|
||||||
currencies,
|
|
||||||
customerId
|
// Sets the primary branch to form.
|
||||||
} = useCustomerFormContext();
|
useSetPrimaryBranchToForm();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'tab-panel--financial'}>
|
<div className={'tab-panel--financial'}>
|
||||||
@@ -62,12 +63,7 @@ export default function CustomerFinancialPanel() {
|
|||||||
|
|
||||||
{/*------------ Opening balance -----------*/}
|
{/*------------ Opening balance -----------*/}
|
||||||
<FastField name={'opening_balance'}>
|
<FastField name={'opening_balance'}>
|
||||||
{({
|
{({ form, field, field: { value }, meta: { error, touched } }) => (
|
||||||
form,
|
|
||||||
field,
|
|
||||||
field: { value },
|
|
||||||
meta: { error, touched },
|
|
||||||
}) => (
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'opening_balance'} />}
|
label={<T id={'opening_balance'} />}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
@@ -92,6 +88,23 @@ export default function CustomerFinancialPanel() {
|
|||||||
)}
|
)}
|
||||||
</FastField>
|
</FastField>
|
||||||
|
|
||||||
|
{/*------------ Opening branch -----------*/}
|
||||||
|
<FeatureCan feature={Features.Branches}>
|
||||||
|
<FFormGroup
|
||||||
|
label={<T id={'customer.label.opening_branch'} />}
|
||||||
|
name={'opening_balance_branch_id'}
|
||||||
|
inline={true}
|
||||||
|
className={classNames('form-group--select-list', Classes.FILL)}
|
||||||
|
>
|
||||||
|
<BranchSelect
|
||||||
|
name={'opening_balance_branch_id'}
|
||||||
|
branches={branches}
|
||||||
|
input={BranchSelectButton}
|
||||||
|
popoverProps={{ minimal: true }}
|
||||||
|
/>
|
||||||
|
</FFormGroup>
|
||||||
|
</FeatureCan>
|
||||||
|
|
||||||
{/*------------ Currency -----------*/}
|
{/*------------ Currency -----------*/}
|
||||||
<FastField name={'currency_code'}>
|
<FastField name={'currency_code'}>
|
||||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ const Schema = Yup.object().shape({
|
|||||||
opening_balance: Yup.number().nullable(),
|
opening_balance: Yup.number().nullable(),
|
||||||
currency_code: Yup.string(),
|
currency_code: Yup.string(),
|
||||||
opening_balance_at: Yup.date(),
|
opening_balance_at: Yup.date(),
|
||||||
|
opening_balance_branch_id: Yup.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const CreateCustomerForm = Schema;
|
export const CreateCustomerForm = Schema;
|
||||||
|
|||||||
@@ -6,15 +6,21 @@ import {
|
|||||||
useCreateCustomer,
|
useCreateCustomer,
|
||||||
useEditCustomer,
|
useEditCustomer,
|
||||||
useContact,
|
useContact,
|
||||||
|
useBranches,
|
||||||
} from 'hooks/query';
|
} from 'hooks/query';
|
||||||
|
import { Features } from 'common';
|
||||||
|
import { useFeatureCan } from 'hooks/state';
|
||||||
|
|
||||||
const CustomerFormContext = createContext();
|
const CustomerFormContext = createContext();
|
||||||
|
|
||||||
function CustomerFormProvider({ customerId, ...props }) {
|
function CustomerFormProvider({ query, customerId, ...props }) {
|
||||||
const { state } = useLocation();
|
const { state } = useLocation();
|
||||||
|
|
||||||
const contactId = state?.action;
|
const contactId = state?.action;
|
||||||
|
|
||||||
|
// Features guard.
|
||||||
|
const { featureCan } = useFeatureCan();
|
||||||
|
const isBranchFeatureCan = featureCan(Features.Branches);
|
||||||
|
|
||||||
// Handle fetch customer details.
|
// Handle fetch customer details.
|
||||||
const { data: customer, isLoading: isCustomerLoading } = useCustomer(
|
const { data: customer, isLoading: isCustomerLoading } = useCustomer(
|
||||||
customerId,
|
customerId,
|
||||||
@@ -28,6 +34,13 @@ function CustomerFormProvider({ customerId, ...props }) {
|
|||||||
// Handle fetch Currencies data table
|
// Handle fetch Currencies data table
|
||||||
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
|
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
|
||||||
|
|
||||||
|
// Fetches the branches list.
|
||||||
|
const {
|
||||||
|
data: branches,
|
||||||
|
isLoading: isBranchesLoading,
|
||||||
|
isSuccess: isBranchesSuccess,
|
||||||
|
} = useBranches(query, { enabled: isBranchFeatureCan });
|
||||||
|
|
||||||
// Form submit payload.
|
// Form submit payload.
|
||||||
const [submitPayload, setSubmitPayload] = useState({});
|
const [submitPayload, setSubmitPayload] = useState({});
|
||||||
|
|
||||||
@@ -38,18 +51,20 @@ function CustomerFormProvider({ customerId, ...props }) {
|
|||||||
const isNewMode = contactId || !customerId;
|
const isNewMode = contactId || !customerId;
|
||||||
|
|
||||||
const isFormLoading =
|
const isFormLoading =
|
||||||
isCustomerLoading || isCurrenciesLoading || isContactLoading;
|
isCustomerLoading || isCurrenciesLoading || isBranchesLoading;
|
||||||
|
|
||||||
const provider = {
|
const provider = {
|
||||||
customerId,
|
customerId,
|
||||||
customer,
|
customer,
|
||||||
currencies,
|
currencies,
|
||||||
|
branches,
|
||||||
contactDuplicate,
|
contactDuplicate,
|
||||||
submitPayload,
|
submitPayload,
|
||||||
isNewMode,
|
isNewMode,
|
||||||
|
|
||||||
isCustomerLoading,
|
isCustomerLoading,
|
||||||
isCurrenciesLoading,
|
isCurrenciesLoading,
|
||||||
|
isBranchesSuccess,
|
||||||
isFormLoading,
|
isFormLoading,
|
||||||
|
|
||||||
setSubmitPayload,
|
setSubmitPayload,
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import { first } from 'lodash';
|
||||||
|
|
||||||
|
import { useCustomerFormContext } from './CustomerFormProvider';
|
||||||
|
|
||||||
export const defaultInitialValues = {
|
export const defaultInitialValues = {
|
||||||
customer_type: 'business',
|
customer_type: 'business',
|
||||||
@@ -35,4 +39,20 @@ export const defaultInitialValues = {
|
|||||||
opening_balance: '',
|
opening_balance: '',
|
||||||
currency_code: '',
|
currency_code: '',
|
||||||
opening_balance_at: moment(new Date()).format('YYYY-MM-DD'),
|
opening_balance_at: moment(new Date()).format('YYYY-MM-DD'),
|
||||||
|
opening_balance_branch_id: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSetPrimaryBranchToForm = () => {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
const { branches, isBranchesSuccess } = useCustomerFormContext();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (isBranchesSuccess) {
|
||||||
|
const primaryBranch = branches.find((b) => b.primary) || first(branches);
|
||||||
|
|
||||||
|
if (primaryBranch) {
|
||||||
|
setFieldValue('opening_balance_branch_id', primaryBranch.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isBranchesSuccess, setFieldValue, branches]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,21 +5,9 @@ import AccountDialogForm from './AccountDialogForm';
|
|||||||
/**
|
/**
|
||||||
* Account dialog content.
|
* Account dialog content.
|
||||||
*/
|
*/
|
||||||
export default function AccountDialogContent({
|
export default function AccountDialogContent({ dialogName, payload }) {
|
||||||
dialogName,
|
|
||||||
accountId,
|
|
||||||
action,
|
|
||||||
parentAccountId,
|
|
||||||
accountType,
|
|
||||||
}) {
|
|
||||||
return (
|
return (
|
||||||
<AccountDialogProvider
|
<AccountDialogProvider dialogName={dialogName} payload={payload}>
|
||||||
dialogName={dialogName}
|
|
||||||
accountId={accountId}
|
|
||||||
action={action}
|
|
||||||
parentAccountId={parentAccountId}
|
|
||||||
accountType={accountType}
|
|
||||||
>
|
|
||||||
<AccountDialogForm />
|
<AccountDialogForm />
|
||||||
</AccountDialogProvider>
|
</AccountDialogProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const defaultInitialValues = {
|
|||||||
name: '',
|
name: '',
|
||||||
code: '',
|
code: '',
|
||||||
description: '',
|
description: '',
|
||||||
|
currency_code:'',
|
||||||
subaccount: false,
|
subaccount: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,9 +43,7 @@ function AccountFormDialogContent({
|
|||||||
account,
|
account,
|
||||||
|
|
||||||
accountId,
|
accountId,
|
||||||
action,
|
payload,
|
||||||
parentAccountId,
|
|
||||||
accountType,
|
|
||||||
isNewMode,
|
isNewMode,
|
||||||
dialogName,
|
dialogName,
|
||||||
} = useAccountDialogContext();
|
} = useAccountDialogContext();
|
||||||
@@ -100,7 +99,6 @@ function AccountFormDialogContent({
|
|||||||
.catch(handleError);
|
.catch(handleError);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Form initial values in create and edit mode.
|
// Form initial values in create and edit mode.
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
...defaultInitialValues,
|
...defaultInitialValues,
|
||||||
@@ -110,11 +108,7 @@ function AccountFormDialogContent({
|
|||||||
* as well.
|
* as well.
|
||||||
*/
|
*/
|
||||||
...transformToForm(
|
...transformToForm(
|
||||||
transformAccountToForm(account, {
|
transformAccountToForm(account, payload),
|
||||||
action,
|
|
||||||
parentAccountId,
|
|
||||||
accountType,
|
|
||||||
}),
|
|
||||||
defaultInitialValues,
|
defaultInitialValues,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
@@ -132,7 +126,7 @@ function AccountFormDialogContent({
|
|||||||
>
|
>
|
||||||
<AccountDialogFormContent
|
<AccountDialogFormContent
|
||||||
dialogName={dialogName}
|
dialogName={dialogName}
|
||||||
action={action}
|
action={payload?.action}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
/>
|
/>
|
||||||
</Formik>
|
</Formik>
|
||||||
|
|||||||
@@ -17,12 +17,14 @@ import {
|
|||||||
Hint,
|
Hint,
|
||||||
AccountsSelectList,
|
AccountsSelectList,
|
||||||
AccountsTypesSelect,
|
AccountsTypesSelect,
|
||||||
|
CurrencySelect,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import withAccounts from 'containers/Accounts/withAccounts';
|
import withAccounts from 'containers/Accounts/withAccounts';
|
||||||
|
|
||||||
import { inputIntent } from 'utils';
|
import { inputIntent } from 'utils';
|
||||||
import { compose } from 'redux';
|
import { compose } from 'redux';
|
||||||
import { useAutofocus } from 'hooks';
|
import { useAutofocus } from 'hooks';
|
||||||
|
import { FOREIGN_CURRENCY_ACCOUNTS } from '../../../common/accountTypes';
|
||||||
import { useAccountDialogContext } from './AccountDialogProvider';
|
import { useAccountDialogContext } from './AccountDialogProvider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +39,8 @@ function AccountFormDialogFields({
|
|||||||
const accountNameFieldRef = useAutofocus();
|
const accountNameFieldRef = useAutofocus();
|
||||||
|
|
||||||
// Account form context.
|
// Account form context.
|
||||||
const { accounts, accountsTypes } = useAccountDialogContext();
|
const { fieldsDisabled, accounts, accountsTypes, currencies } =
|
||||||
|
useAccountDialogContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form>
|
<Form>
|
||||||
@@ -58,12 +61,9 @@ function AccountFormDialogFields({
|
|||||||
defaultSelectText={<T id={'select_account_type'} />}
|
defaultSelectText={<T id={'select_account_type'} />}
|
||||||
onTypeSelected={(accountType) => {
|
onTypeSelected={(accountType) => {
|
||||||
form.setFieldValue('account_type', accountType.key);
|
form.setFieldValue('account_type', accountType.key);
|
||||||
|
form.setFieldValue('currency_code', '');
|
||||||
}}
|
}}
|
||||||
disabled={
|
disabled={fieldsDisabled.accountType}
|
||||||
action === 'edit' ||
|
|
||||||
action === 'new_child' ||
|
|
||||||
action === 'NEW_ACCOUNT_DEFINED_TYPE'
|
|
||||||
}
|
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
popoverFill={true}
|
popoverFill={true}
|
||||||
/>
|
/>
|
||||||
@@ -143,6 +143,7 @@ function AccountFormDialogFields({
|
|||||||
)}
|
)}
|
||||||
inline={true}
|
inline={true}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
|
helperText={<ErrorMessage name="parent_account_id" />}
|
||||||
>
|
>
|
||||||
<AccountsSelectList
|
<AccountsSelectList
|
||||||
accounts={accounts}
|
accounts={accounts}
|
||||||
@@ -159,6 +160,24 @@ function AccountFormDialogFields({
|
|||||||
</FastField>
|
</FastField>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
|
<If condition={FOREIGN_CURRENCY_ACCOUNTS.includes(values.account_type)}>
|
||||||
|
{/*------------ Currency -----------*/}
|
||||||
|
<FastField name={'currency_code'}>
|
||||||
|
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||||
|
<FormGroup
|
||||||
|
label={<T id={'currency'} />}
|
||||||
|
className={classNames('form-group--select-list', Classes.FILL)}
|
||||||
|
inline={true}
|
||||||
|
>
|
||||||
|
<CurrencySelect
|
||||||
|
name={'currency_code'}
|
||||||
|
currencies={currencies}
|
||||||
|
popoverProps={{ minimal: true }}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
</If>
|
||||||
<FastField name={'description'}>
|
<FastField name={'description'}>
|
||||||
{({ field, meta: { error, touched } }) => (
|
{({ field, meta: { error, touched } }) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
@@ -187,7 +206,7 @@ function AccountFormDialogFields({
|
|||||||
<Button
|
<Button
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
loading={isSubmitting}
|
loading={isSubmitting}
|
||||||
style={{ minWidth: '75px' }}
|
style={{ minWidth: '95px' }}
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
{action === 'edit' ? <T id={'edit'} /> : <T id={'submit'} />}
|
{action === 'edit' ? <T id={'edit'} /> : <T id={'submit'} />}
|
||||||
|
|||||||
@@ -3,25 +3,19 @@ import { DialogContent } from 'components';
|
|||||||
import {
|
import {
|
||||||
useCreateAccount,
|
useCreateAccount,
|
||||||
useAccountsTypes,
|
useAccountsTypes,
|
||||||
|
useCurrencies,
|
||||||
useAccount,
|
useAccount,
|
||||||
useAccounts,
|
useAccounts,
|
||||||
useEditAccount,
|
useEditAccount,
|
||||||
} from 'hooks/query';
|
} from 'hooks/query';
|
||||||
|
import { AccountDialogAction, getDisabledFormFields } from './utils';
|
||||||
|
|
||||||
const AccountDialogContext = createContext();
|
const AccountDialogContext = createContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account form provider.
|
* Account form provider.
|
||||||
*/
|
*/
|
||||||
function AccountDialogProvider({
|
function AccountDialogProvider({ dialogName, payload, ...props }) {
|
||||||
accountId,
|
|
||||||
parentAccountId,
|
|
||||||
action,
|
|
||||||
accountType,
|
|
||||||
|
|
||||||
dialogName,
|
|
||||||
...props
|
|
||||||
}) {
|
|
||||||
// Create and edit account mutations.
|
// Create and edit account mutations.
|
||||||
const { mutateAsync: createAccountMutate } = useCreateAccount();
|
const { mutateAsync: createAccountMutate } = useCreateAccount();
|
||||||
const { mutateAsync: editAccountMutate } = useEditAccount();
|
const { mutateAsync: editAccountMutate } = useEditAccount();
|
||||||
@@ -30,25 +24,36 @@ function AccountDialogProvider({
|
|||||||
const { data: accounts, isLoading: isAccountsLoading } = useAccounts();
|
const { data: accounts, isLoading: isAccountsLoading } = useAccounts();
|
||||||
|
|
||||||
// Fetches accounts types.
|
// Fetches accounts types.
|
||||||
const {
|
const { data: accountsTypes, isLoading: isAccountsTypesLoading } =
|
||||||
data: accountsTypes,
|
useAccountsTypes();
|
||||||
isLoading: isAccountsTypesLoading,
|
|
||||||
} = useAccountsTypes();
|
|
||||||
|
|
||||||
// Fetches the specific account details.
|
// Fetches the specific account details.
|
||||||
const { data: account, isLoading: isAccountLoading } = useAccount(accountId, {
|
const { data: account, isLoading: isAccountLoading } = useAccount(
|
||||||
enabled: !!accountId,
|
payload.accountId,
|
||||||
});
|
{
|
||||||
|
enabled:
|
||||||
|
!!payload.accountId && payload.action === AccountDialogAction.Edit,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const isNewMode = !accountId;
|
// Handle fetch Currencies data table
|
||||||
|
const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies();
|
||||||
|
|
||||||
|
const isNewMode = !payload?.action;
|
||||||
|
|
||||||
|
// Retrieves the disabled fields of the form.
|
||||||
|
const fieldsDisabled = React.useMemo(
|
||||||
|
() => getDisabledFormFields(account, payload),
|
||||||
|
[account, payload],
|
||||||
|
);
|
||||||
|
|
||||||
// Provider payload.
|
// Provider payload.
|
||||||
const provider = {
|
const provider = {
|
||||||
dialogName,
|
dialogName,
|
||||||
accountId,
|
payload,
|
||||||
parentAccountId,
|
fieldsDisabled,
|
||||||
action,
|
|
||||||
accountType,
|
currencies,
|
||||||
|
|
||||||
createAccountMutate,
|
createAccountMutate,
|
||||||
editAccountMutate,
|
editAccountMutate,
|
||||||
@@ -57,11 +62,15 @@ function AccountDialogProvider({
|
|||||||
account,
|
account,
|
||||||
|
|
||||||
isAccountsLoading,
|
isAccountsLoading,
|
||||||
isNewMode
|
isCurrenciesLoading,
|
||||||
|
isNewMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
const isLoading =
|
const isLoading =
|
||||||
isAccountsLoading || isAccountsTypesLoading || isAccountLoading;
|
isAccountsLoading ||
|
||||||
|
isAccountsTypesLoading ||
|
||||||
|
isAccountLoading ||
|
||||||
|
isCurrenciesLoading;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogContent isLoading={isLoading}>
|
<DialogContent isLoading={isLoading}>
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ function AccountFormDialog({
|
|||||||
<Dialog
|
<Dialog
|
||||||
name={dialogName}
|
name={dialogName}
|
||||||
title={
|
title={
|
||||||
(payload.action === 'edit') ?
|
payload.action === 'edit' ? (
|
||||||
(<T id={'edit_account'} />) :
|
<T id={'edit_account'} />
|
||||||
(<T id={'new_account'} />)
|
) : (
|
||||||
|
<T id={'new_account'} />
|
||||||
|
)
|
||||||
}
|
}
|
||||||
className={'dialog--account-form'}
|
className={'dialog--account-form'}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
@@ -28,18 +30,10 @@ function AccountFormDialog({
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
>
|
>
|
||||||
<DialogSuspense>
|
<DialogSuspense>
|
||||||
<AccountDialogContent
|
<AccountDialogContent dialogName={dialogName} payload={payload} />
|
||||||
dialogName={dialogName}
|
|
||||||
accountId={payload.id}
|
|
||||||
action={payload.action}
|
|
||||||
parentAccountId={payload.parentAccountId}
|
|
||||||
accountType={payload.accountType}
|
|
||||||
/>
|
|
||||||
</DialogSuspense>
|
</DialogSuspense>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(withDialogRedux())(AccountFormDialog);
|
||||||
withDialogRedux(),
|
|
||||||
)(AccountFormDialog);
|
|
||||||
|
|||||||